Які команди ми виконуємо, або команда which

Створення персональних версій програм, подібних cal, створює неко торие труднощі Найбільш явна з них формулюється таким чином: якщо ви працюєте разом з Мері і вводите cal, будучи зареєстрованим як mary, відпрацює стандартна, а не нова версія команди (якщо тільки в каталозі / bin, що належить Мері, немає посилання на відповідний файл) Це не дуже зручно (згадайте, наприклад, що повідомлення про помилки, що видаються вихідною програмою cal, не дуже-то корисні), але це всього лише один з проявів однієї великої проблеми Оскільки оболонка шукає команди в каталогах, ука занних у змінній PATH, завжди є шанс отримати не ту версію команди, яка очікується Наприклад, якщо ввести команду echo, то шляхом до файлу, який виповниться, може бути / Echo або / bin / echo, або

/ Usr / bin / echo, або щось ще, залежно від компонентів змінної PATH та місця розташування файлів І якщо виконуваний файл з пра Вільнев імям, але робить не те, чого очікує користувач, зустрінеться на шляху пошуку раніше, то виникне плутанина Напевно, найяскравішим прикладом є команда test (про неї буде розказано пізніше): це імя очевидним чином підходить для тимчасових версій програми, які і викликаються (набагато частіше, ніж хотілося б) при зверненні до справжньої test1 Корисною може виявитися програма, яка інформує про те, яка версія програми буде виконуватися

1 Далі буде показано, як уникнути подібних проблем у командних файлах, де звичайно використовується test

Одна з можливих реалізацій полягає в застосуванні циклу для перегляду всіх каталогів, перерахованих в PATH, в пошуку виконуваних файлів із заданим імям У розділі 3 для перебору імен файлів і аргументів використовувався оператор for У даному випадку потрібен опера тор такого виду:

for  i  in  кожен компонентPATH do

done

якщо файл із заданим імям є в каталозі i, вивести його повне колійне імя

Оскільки будь-яка команда може бути запущена з-під зворотних ка вичек `..`, то очевидно наступне рішення – застосувати команду sed до $ PATH, замінюючи двокрапки пробілами Протестуємо за допомогою нашого старого друга echo:

$ echo $PATH

:/usr/you/bin:/bin:/usr/bin         4 компоненти

$ echo $PATH  | sed  s/:/ /g

/usr/you/bin /bin  /usr/bin           Виведено тільки 3

$ echo `echo  $PATH  | sed  s/:/ /g`

/usr/you/bin  /bin /usr/bin          Також тільки 3

$

Чітко видно проблема: порожній рядок в PATH є синонімом точки «», І в результаті перетворення двокрапок в прогалини інформація про нульові компонентах буде втрачена Для того щоб підлозі чить коректний список каталогів, слід перетворити нульову компоненту PATH в точку Нульовий компонент може знаходитися як в середині рядка, так і з будь-якого кінця, необхідно передбачити всі ці варіанти:

$ echo $PATH  | sed  s/^:/:/

&gt                                   s/::/::/g

&gt                                   s/:$/:/

&gt                                                   s/:/ /g

. /usr/you/bin /bin /usr/bin

$

Можна було б записати це як чотири окремі команди sed, але так як sed здійснює заміни по порядку, достатньо одного виклику ва програми

Як тільки стало відомо, які каталоги є компонентами PATH, команда test (1), яка вже згадувалася, може визначити, чи присутній файл в кожному з каталогів Треба сказати, що test є однією з найбільш незграбних програм UNIX Наприклад, test-r file перевіряє, чи існує файл і доступний він для читання, а test-w file перевіряє, чи існує файл і чи дозволено в нього запис У сьомій версії немає команди test-x (вона існувала в

System V та інших версіях), яка б цілком підійшла для нашого завдання Будемо використовувати test-f, вона перевіряє, чи існує файл і чи не є він каталогом (тобто, іншими словами, чи є він звичайним файлом) Зараз в обігу знаходиться кілька версій програми test, так що зверніться до керівництва для отримання інформації про вашу систему

Будь-яка команда повертає код завершення – Число, за значенням якого оболонка визначає, що сталося Код завершення – це ціле число, прийнято угоду про те, що 0 означає «істина» (команда виконалася успішно), а ненульова величина означає «брехня» (команда не виконала успішно) Зверніть увагу на що, що в мові Сі значення істини і брехні прямо протилежні щойно описаним

Оскільки «брехня» може здаватися різними ненульовими вели чинами, то в цьому коді завершення часто зашифрована причина невдачі Наприклад, команда grep повертає 0, якщо знайдено відповідність, 1 – Якщо відповідність не знайдено, і 2 – якщо в імені файлу або шаблоні є помилка Код завершення повертається будь-якою програмою, незважаючи на те, що його значення часто буває не цікаво поль зователя Команда test – це незвичайна команда, її єдине призначення полягає в поверненні коду завершення Вона нічого не виводить і не змінює файли

Оболонка зберігає код завершення останньої програми у змінній

$:

$ cmp  /usr/you/profile /usr/you/profile

$                                                                    Ні виводу вони однакові

$ echo $

0                          Нуль означає успішне виконання: файли ідентичні

$ cmp  /usr/you/profile /usr/mary/profile

/usr/you/profile /usr/mary/profile differ:  char  6,  line 3

$ echo $

1                    Ненульова величина означає, що файли були різними

$

У деяких команд, наприклад cmp і grep, є параметр-s, і якщо він заданий, то команда повертає відповідний код завершення, але нічого не виводить

Оператор оболонки if виконує команди залежно від коду завершення команди:

if команда

then

else fi

команди, якщо умова істинно команди, якщо умова помилкова

Положення роздільників рядків має важливе значення: fi, then і else розпізнаються, тільки якщо знаходяться на початку рядка або слідують за крапкою з комою Частина else може бути відсутнім

Оператор if завжди запускає команду, яка є умовою, тоді як оператор case здійснює порівняння з шаблоном безпосередньо в оболонці У деяких версіях UNIX (у тому числі в System V) test є вбудованою функцією оболонки, тому if і test будуть виконані так само швидко, як і case Якщо ж test не є вбудованою, то оператори case більш продуктивні, ніж оператори if, і саме їх слід застосовувати для будь-якого зіставлення з шаблоном:

case  &quot&quot  in hello)    команда esac

виконається швидше, ніж

if test &quot&quot  = hello      Повільніше, якщо test не вбудована в оболонку

then

команда

fi

Саме з цієї причини оператори case іноді застосовуються в оболонці для тестування того, що в більшості мов програмування тестували б за допомогою оператора if З іншого боку, в операторі case немає простого способу, що дозволяє визначити, чи є права на читання файлу, це краще зробити, використовуючи test і if

Тепер все готово для написання першої версії команди which, кото раю буде повідомляти, який файл відповідає команді:

$ cat  which

# Which cmd: яка з наявних в $ PATH команд виконується, версія 1

case  $# in

0)    echo Usage:  which command  1&gt&amp2 exit 2 esac

for  i in  `echo  $PATH  |  sed  s/^:/:/ s/::/::/g s/:$/:/ s/:/  /g`

do

if test-f $ i / $ 1 # якщо можна, використовуйте test-x then

echo $i/

exit 0 # знайдено

fi done

exit 1 # не знайдено

$

Давайте випробуємо її:

$ cx which Робимо команду виконуваної

$ which  which

./which

$ which  ed

/bin/ed

$ mv  which /usr/you/bin

$ which  which

/usr/you/bin/which

$

Оператор case використаний просто для контролю помилок Зверніть увагу на перенаправлення 1> & 2 в команді echo – повідомлення про помилку не пропадуть в каналі Вбудована в оболонку функція exit може бути використана для повернення коду завершення Якщо команда не працює, то повертається код помилки – exit 2, якщо файл не знайдено – exit 1, якщо ж знайдено – exit 0 Якщо оператор exit явно не присутній, то код завершення для командного файлу – це статус останньої виконаної команди

Що відбудеться, якщо в поточному каталозі є програма під назвою test (Діємо в припущенні, що test не є вбудованою функцією оболонки)

$ echo echo hello> test Створимо підроблену test

$ cx test Зробимо її виконуваної

$ which which Тепер спробуємо which hello                                                     Невдача

./which

$

Требуется приділити більше уваги контролю за помилками Можна запустити which (якщо в поточному каталозі не було команди test), Знайти повне колійне імя test і вказати його явно Але це поганий спосіб: в різних системах програма test може перебувати в різних каталогах, а команда which також залежить від sed і echo, так що доведеться вказувати і їх шляхові імена Існує більш просте рішення: перевизначити PATH в командному файлі так, щоб виконувалися тільки команди з каталогів / bin та / usr / bin Старе значення PATH, безсумнівно, має бути збережено (тільки для команди which, щоб визна лити послідовність каталогів для перегляду)

$ cat  which

# Which cmd: яка команда виконується, остаточна версія

opath=$PATH PATH=/bin:/usr/bin

case  $# in

0)    echo Usage:  which command  1&gt&amp2 exit 2 esac

for  i in  `echo  $opath  |  sed  s/^:/:/ s/::/::/g s/:$/:/ s/:/  /g`

do

if test-f $ i / $ 1 # це тільки / bin / test then # або / usr / bin / test

echo $i/

exit 0 # знайдено

fi done

exit 1 # не знайдено

$

Команда which тепер працює навіть у разі наявності на шляху пошуку фальшивої test (або sed, або echo)

$ ls -l test

–rwxrwxrwx  1 you              11 Oct   1 06:55  test        Все ще тут

$ which  which

/usr/you/bin/which

$ which  test

./test

$ rm test

$ which  test

/bin/test

$

В оболонці є два оператора для комбінування команд: | | і &&, вони більш компактні, і часто працювати з ними зручніше, ніж з оператором if Так, | | може замінити деякі оператори if:

test –f  імя5файла || echo file імя5файлаdoes  not  exist

еквівалентно

if test –f  імя5файла Символ  інвертує умова

then

echo file  імя5файлаdoes  not  exist fi

Незважаючи на його зовнішній вигляд оператор | | не має нічого спільного з каналами це умовний оператор, логічне АБО Виконується команда, яка перебуває зліва від | | Якщо код завершення дорівнює нулю (виконано успішно), то команда праворуч від | | ігнорується Якщо ж ліва частина повертає ненулевую величину (неуспішно), то виконується права частина, і значення всього виразу одно коду завершення правій частині Іншими словами, | | – це оператор логічного АБО, який не виконує команду правій частині, якщо ліва виконалася успішно Аналогічно && відповідає логічному І він виконує команду своєї правій частині, тільки якщо успішно виконали ліва

Вправа 54Чому перед виходом команда which не встановлює PATH в opath ~

Вправа 55 Якщо в оболонці завершення case реалізується посред ством esac, а завершення if – за допомогою fi, то чому для завершення do використовується done ~

Вправа 56Додайте параметр-a для which, щоб вона друкувала всі файли в PATH, а не виходила після першого знайденого Підказка: match = exit0. ~

Вправа 57Змініть which так, щоб вона знала про вбудовані в оболонку функціях типу exit ~

Вправа 58Змініть which так, щоб вона перевіряла права на виконання файлів Нехай вона друкує повідомлення про помилку у випадку, якщо файл не знайдений ~

Джерело: Керниган Б, Пайк Р, UNIX Програмне оточення – Пер з англ – СПб: Символ-Плюс, 2003 – 416 с, Мул

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*