Змінні середовища та позиційні параметри
Перш ніж ми розпочнемо обговорення $INTEGERтипу змінних, нам потрібно зрозуміти, що вони насправді є, і чим вони відрізняються від змінних оточуючих середовищ. Такі змінні, як $INTEGERназивають позиційні параметри. Це описано в стандарті POSIX (Портативний інтерфейс операційної системи), розділ 2.1 (моє наголос):
- Оболонка виконує функцію (див. Команда визначення функції), вбудований (див. Спеціальні вбудовані утиліти), виконуваний файл або сценарій, надаючи імена аргументів як позиційних параметрів, пронумерованих від 1 до n, та ім'я команди (або у випадку функції в межах сценарію, назва сценарію) як позиційного параметра, що має нуль 0 (див. Пошук і виконання команд).
Навпаки, такі змінні, як $HOMEі $PATHє змінними середовища. Їх визначення описано в розділі 8 стандарту :
Змінні середовища, визначені в цій главі, впливають на роботу декількох утиліт, функцій та додатків. Є й інші змінні середовища, які цікавлять лише конкретні утиліти. Змінні середовища, які застосовуються лише до однієї утиліти, визначаються як частина опису утиліти.
Зауважте їх опис. Позиційні параметри мають на увазі відображатися перед командою, тобто command positional_arg_1 positional_arg_2.... Вони повинні бути надані користувачем, щоб сказати команді, що конкретно робити. Коли ви це зробите echo 'Hello' 'World', він буде роздруковувати Helloі Worldрядки, тому що це позиційні параметри echo- для речей, над якими ви хочете echoпрацювати. І echoпобудований таким чином, що він розуміє позиційні параметри як рядки для друку (якщо вони не є одним із необов'язкових прапорів на зразок -n). Якщо ви робите це за допомогою іншої команди, вона може не зрозуміти, що HelloіWorldце тому, що, можливо, вона очікує числа. Зауважте, що позиційні параметри не «успадковуються» - дочірній процес не знає про позиційні параметри батьків, якщо явно не передано дочірньому процесу. Часто ви бачите позиційні параметри, що передаються із скриптами обгортки - тими, які, можливо, перевіряють наявний екземпляр команди або додають додаткові параметри позиції до реальної команди, яка буде викликана.
Навпаки, змінні середовища повинні впливати на кілька програм. Вони є змінними середовища , оскільки вони встановлені поза самою програмою (докладніше про це нижче). Деякі змінні середовища, такі як HOMEабо PATHмають певний формат, конкретне значення, і вони означатимуть однакове для кожної програми. HOMEзмінна буде означати те саме для зовнішньої утиліти, як, наприклад, /usr/bin/findвашої оболонки (і, отже, для сценарію) - це домашній каталог імені користувача, під яким запускається процес. Зауважте, що змінні середовища можуть використовуватися, наприклад, для обліку конкретної поведінки командиUIDзмінна середовище може використовуватися для перевірки того, чи працює сценарій з кореневими привілеями чи ні, і відповідно до конкретних дій. Змінні середовища є спадковими - дочірні процеси отримують копію батьківського середовища. Див. Також Якщо процеси успадковують батьківське середовище, навіщо нам потрібен експорт?
Коротше кажучи, головне відмінність полягає в тому, що змінні середовища встановлюються поза командою і не мають змінюватися (як правило), тоді як позиційні параметри - це речі, які повинні бути оброблені командою, і вони змінюються.
Не лише поняття оболонки
Що я помітив із коментарів, це те, що ви змішуєте термінал і оболонку, і я б дуже рекомендував вам прочитати про справжні термінали, які колись були фізичними пристроями. Сьогодні "термінал", про який ми зазвичай маємо на увазі, це вікно з чорним фоном та зеленим текстом - це фактично програмне забезпечення. Термінал - це програма, яка запускає оболонку, в той час як оболонка - це також програма, але така, яка читає те, що ви вводите для виконання (тобто, якщо це інтерактивна оболонка; неінтерактивні оболонки - це сценарії та sh -c 'echo foo'типи викликів). Більше про мушлі тут .
Це важлива відмінність, але також важливо визнати, що термінал є програмою і тому дотримується одних і тих же правил середовища та позиційних параметрів. Ви gnome-terminalколи почали буде виглядати на вашому SHELLзмінному оточення, і нерест відповідної оболонки по замовчуванням для вас, якщо ви не вказали яку - або інша команди з -e. Скажімо, я змінив свою оболонку за замовчуванням на ksh - gnome-terminal потім нерестується kshзамість bash. Це також приклад того, як програми використовують середовище. Якщо я явно вказати gnome-terminalз -eдля запуску конкретної оболонки - він буде робити це, але це не буде постійним. Навпаки, навколишнє середовище мається на увазі незмінним (про це пізніше).
Отже, як ви бачите, змінні середовища та позиції - це властивості процесу / команди, а не просто оболонки. Що стосується скриптів оболонки, вони також слідують моделі, встановленій мовою програмування на C. Візьмемо для прикладу функцію C, mainяка зазвичай виглядає так
int main(int argc, char **argv)
, де argcє кількість аргументів командного рядка, і argvце фактично масив параметрів командного рядка, а потім є environфункція (в Linux, це man -e 7 environ) для доступу до таких речей, як шлях до домашнього каталогу користувача, список каталогів, PATHде ми можемо шукати виконувані файли тощо. Сценарії оболонки також моделюються аналогічно. У оболочечной термінології, ми маємо позиційні параметри $1, $2і так далі, в той час як $#ця кількість позиційних параметрів. Про що $0? Це ім'я самого виконуваного файлу, яке також моделюється з мови програмування на C - це argv[0]було б ім'я вашого C "виконуваного файлу". І це справедливо для більшості мов програмування та сценаріїв .
Інтерактивні проти неінтерактивні оболонки
Одне з речей, на яке я вже натякав, - це відмінність інтерактивних та неінтерактивних оболонок . Підказка, де ви вводите команди - це інтерактивна, вона взаємодіє з користувачем. На противагу цьому, коли у вас є сценарій оболонки або ви працюєте bash -c'', це неінтерактивний.
І саме тут розрізнення стає важливим. Оболонка, яку ви вже запустите, - це процес, породжений позиційними параметрами (для bashоболонки входу один "... перший символ аргументу нуля - -, або той, що розпочався з опції --login." ( Посилання ) )
На відміну від цього, сценарії та оболонки, запущені з -cопцією, можуть скористатися $1і $2аргументами. Наприклад,
$ bash -c 'echo $1; stat $2' sh 'Hello World' /etc/passwd
Hello World
File: '/etc/passwd'
Size: 2913 Blocks: 8 IO Block: 4096 regular file
Device: 801h/2049d Inode: 6035604 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2017-08-12 14:48:37.125879962 -0600
Modify: 2017-08-12 14:48:37.125879962 -0600
Change: 2017-08-12 14:48:37.137879811 -0600
Birth: -
Зауважте, що я також використовував shтам, тому що невелика химерність -cваріанту полягає в тому, щоб взяти перший позиційний параметр і призначити його $0, на відміну, як правило, це ім'я програми.
Ще одне, що важливо помітити, - це те, що позиційні параметри - це те, що я називаю "framable". Зверніть увагу, ми спочатку запустили bashсвої власні позиційні параметри, але ці позиційні параметри стали параметрами до echoта stat. І кожна програма розуміє це по-своєму. Якби ми надали statрядок Hello Worldі немає файлу, Hello Worldце призведе до помилки; bashтрактує його як простий рядок, але statочікує, що ця рядок буде наявним іменем файлу. Навпаки, всі програми погоджуються, що змінна середовища HOMEє каталогом (якщо програміст не кодував її необгрунтовано).
Чи можемо ми заплутатися зі змінними середовища та позиційними параметрами?
Технічно ми можемо возитися з обома, але ми не повинні возитися зі змінними середовища, хоча нам часто доводиться надавати позиційні параметри. Ми можемо запускати команди в оболонці з попередньою зміною, наприклад:
$ hello=world bash -c 'echo $hello'
world
Ми також можемо розміщувати змінні в середовищі, просто використовуючи export variable=valueз оболонки чи сценарію. Або ми можемо запустити команду з повністю порожнім середовищем за допомогою env -c command arg1 arg2. Однак, як правило, не рекомендується возитися з оточенням, особливо використовуючи великі регістри чи перезаписи вже існуючих змінних середовища. Зверніть увагу, що рекомендується, хоча не є стандартом.
Для позиційних параметрів спосіб їх встановлення очевидний, просто додайте їх до команди, але також є способи встановити їх інші мудрі , а також змінити список цих параметрів за допомогою shiftкоманди.
На закінчення ціль цих двох різна, і вони існують чомусь. Я сподіваюся, що люди отримали деяке розуміння з цієї відповіді, і мені було цікаво читати її так само, як мені було писати цю відповідь.
Примітка до команди set
setКоманда, в відповідно до інструкції , як веде себе так (від Баш керівництва, підкреслення додано):
Без параметрів ім'я та значення кожної змінної оболонки відображаються у форматі, який можна повторно використовувати як вхід для встановлення або скидання встановлених в даний час змінних.
Іншими словами, setрозглядаються змінні, характерні для оболонки, деякі з яких трапляються, наприклад, у середовищі HOME. На відміну від таких команд, як envі printenvперегляньте фактичну змінну середовища, з якою працює команда. Дивіться також це .
export 3можете перетворитись$3в змінну середовища. Ви не можетеunset 3; і ви не можете призначити$3нове значення за допомогою3=val.