Чи є такі змінні, як $ 0 та $ 1 змінної оболонки / середовища?


17

Є змінні в оболонці , як $0, $1, $2, $?і т.д.

Я спробував надрукувати змінні оболонки та середовища за допомогою наступної команди:

set

Але цих змінних у списку не було.

Отже, в основному ці змінні не вважаються змінними оболонки / середовища, правда? (незважаючи на те, щоб вивести їх, вам доведеться передувати їм $, як це робиться зі змінними оболонки / середовища)


3
Позиційні параметри не є змінними. Ви не export 3можете перетворитись $3в змінну середовища. Ви не можете unset 3; і ви не можете призначити $3нове значення за допомогою 3=val.
Каз

Відповіді:


25

Змінні - це один із трьох різних різновидів параметрів оболонки.

  1. Мінлива є параметром , чиє ім'я є допустимим ідентифікатором оболонки; починається з _або літери, після чого - нуль або більше літер, цифр або _.
  2. У позиційних параметрах пронумерованих параметри $1, $2...
  3. Усі спеціальні параметри мають одноіменні імена, окрім $0них - всі різні знаки пунктуації.

set відображає лише змінні оболонки.

Підмножина змінних оболонки - це змінні середовища, значення яких або успадковуються від середовища при запуску оболонки, або створюються шляхом встановлення exportатрибута на дійсне ім'я.


1
Зауважте, що setвідображаються всі параметри в zsh(не $ 1, $ 2 ..., але $ *, $ @) і функції в bash і bosh. Деякі оболонки, такі як ksh93 та старіші версії тире, виводять env vars, які не були відображені у змінні оболонки. ( env 1=foo ksh -c setнадрукував 1=foo)
Стефан Шазелас

11

Змінні середовища та позиційні параметри

Перш ніж ми розпочнемо обговорення $INTEGERтипу змінних, нам потрібно зрозуміти, що вони насправді є, і чим вони відрізняються від змінних оточуючих середовищ. Такі змінні, як $INTEGERназивають позиційні параметри. Це описано в стандарті POSIX (Портативний інтерфейс операційної системи), розділ 2.1 (моє наголос):

  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перегляньте фактичну змінну середовища, з якою працює команда. Дивіться також це .


"У інтерактивній оболонці ви не можете посилатися на $ 1, $ 2 тощо". Чи є пряма посилання на це? Я зіткнувся з дивними випадками, коли вони встановлені в інтерактивному середовищі оболонки, і я не впевнений, чи це буде вважатися "нестандартним" чи ні.
користувач5359531

@ user5359531 Чесно кажучи, я не зовсім впевнений, звідки я це взяв. Можливо, тому, що тоді, коли я розмістив відповідь у 2017 році, я, мабуть, посилався, що ви не можете зробити щось на кшталт, 1="foo"але пізніше я з'ясував, що за визначенням POSIX слово "(тобто назва об'єкта, такого як змінна чи функція) не може запуститися з цифрою (див. запитання, яке я розмістив у темі ). Позиційні параметри, мабуть, є винятком із цього правила.
Сергій Колодяжний

@ user5359531 Я видалив частину відповіді, оскільки це не особливо точно. Ви можете посилатися $1, $2і так далі в інтерактивній оболонці, і в тому , що це робиться з setкомандою, часто , щоб обійти /bin/shобмеження , які не мають масиви. Дякуємо, що довели до цього мою увагу. Я також збираюсь відредагувати відповідь протягом наступних кількох днів, оскільки їй потрібно трохи зайвої польської та оновлення.
Сергій Колодяжний

Дякуємо за роз’яснення. Проблема, яка у мене виникає, полягає в тому conda, що при запуску source conda/bin/activateвін перевіряє, чи встановлені $1і $2т. Д., Щоб визначити, він був запущений як сценарій з аргументами чи ні. Це закінчується порушенням систем, які з певних причин встановлені в інтерактивному середовищі. Я сподіваюся розібратися, чи є ця нестандартна поведінка вадою в системі встановлення цих змінних в інтерактивному середовищі, або в програмі для їх використання, щоб визначити, чи він був запущений як сценарій.
user5359531

@ user5359531 Я б запропонував вам подати звіт про помилку condaрозробникам або тому, хто є оригінальним автором такого сценарію, оскільки перевірка ${N}параметрів, безумовно, є неправильним шляхом. Є питання по тій же темі тут і тут , і більш-менш стерпний спосіб, щоб перевірити , якщо ${0}це так само , як ім'я сценарію, в той час як на bashсамому справі має змінні оточення для цієї мети
Сергій Kolodyazhnyy

4

Ці $1, $2, $3, ..., ${10}, ${11}змінні називаються позиційними параметрами і розглянуті в Баш розділі керівництва3.4.1

3.4.1 Позиційні параметри

Позиційний параметр - це параметр, позначений однією або декількома цифрами, відмінними від одноцифрової 0. Позиційні параметри призначаються з аргументів оболонки, коли вона викликається, і можуть бути перепризначені за допомогою команди setinin. Позиційний параметр N може посилатися як $ {N} або як $ N, коли N складається з однієї цифри. Позиційні параметри можуть не призначатися операторам призначення. Вбудовані множини та зсуви використовуються для їх встановлення та зняття (див. Команди Shell Builtin Commands). Позиційні параметри тимчасово замінюються, коли виконується функція оболонки (див. Функції оболонки).

Коли розгорнутий позиційний параметр, що складається з більш ніж однієї цифри, він повинен бути укладений у дужки.

Щодо $?та $0, ці особливі параметри висвітлюються в наступному розділі3.4.2

3.4.2 Спеціальні параметри

Оболонка спеціально обробляє кілька параметрів. На ці параметри можна посилатися лише; присвоєння їм не допускається.

...

?

($?) Розширюється до статусу виходу останнього виконаного переднього плану трубопроводу.

0

($ 0) Розширюється на ім'я оболонки або сценарію оболонки. Це встановлюється при ініціалізації оболонки. Якщо Bash викликається файлом команд (див. Сценарії оболонки), на ім'я цього файла встановлюється $ 0. Якщо Bash запускається з опції -c (див. Invoking Bash), тоді $ 0 встановлюється першим аргументом після виконання рядка, якщо такий присутній. В іншому випадку воно встановлено на ім'я файлу, яке використовується для виклику Bash, як задано нульовим аргументом.


4

$1, $2... є позиційними параметрами , вони не є змінними, не кажучи вже про змінні середовища.

В Bourne, як оболонки термінології, $somethingназивається параметром розкладання (також охоплює ${something#pattern}і більш в деяких оболонках , як ${array[x]}, ${param:offset}, ${x:|y}і багато операторів розширення більше).

Існують різні види параметрів:

  • такі змінні$foo ,$PATH
  • позиційні параметри ( $1, $2... аргументи, які отримав ваш скрипт)
  • інші спеціальні параметри , такі як $0, $-, $#, $*, $@, $$, $!, $?...

Імена змінних в оболонках Борна повинні починатися з одного алфавітного символу (будь-якого розпізнаваного за місцевістю або обмеженого a-zA-Z залежно від оболонки) та підкреслення, а потім нуля або більше буквено-цифрових символів або підкреслення.

Залежно від оболонки, змінні можуть мати різні типи (скалярний, масив, хеш) або задані певні атрибути (лише для читання, експортовані, малі регістри ...).

Деякі з цих змінних створюються оболонки або мають особливе значення для оболонки (наприклад $OPTIND, $IFS, $_...)

Змінні оболонки, які мають атрибут експорту , автоматично експортуються як змінні середовища до команд, які виконує оболонка.

Змінна середовища - це поняття, окреме від змінних оболонок. Експорт змінної оболонки - не єдиний спосіб передачі змінної середовища виконанню команди.

VAR=foo
export VAR
printenv VAR

передасть команду VARзмінної середовища printenv(яку ми повідомляємо надрукувати її вміст), але ви також можете зробити:

env VAR=foo printenv VAR

або:

perl -e '$ENV{VAR}="foo"; exec "printenv", "VAR"'

наприклад.

Змінні середовища можуть мати будь-яке ім’я (можуть містити будь-який символ, але =можуть бути навіть порожніми). Недоцільно вказувати ім’я, яке не сумісне з ім'ям змінної оболонки Борна, змінної середовища, але можливо:

$ env '#+%=whatever' printenv '#+%'
whatever

Оболонки будуть відображати змінні середовища, які вони отримують для змінних оболонок, лише для тих змінних середовищ, чиє ім'я є дійсними змінними оболонок (а в деяких оболонках ігноруються деякі спеціальні, такі як $IFS).

Отже, поки ви зможете передати 1змінну середовища команді:

$ env '1=whatever' printenv 1
whatever

Це не означає, що виклик оболонки із цією змінною середовища встановив би значення $1параметра:

$ env '1=whatever' sh -c 'echo "$1"' script-name foo bar
foo

3

Ні, це параметри сценарію. Наприклад, якщо ви називаєте свій сценарій так:

mynicescript.sh one two three

то всередині скрипту будуть ці параметри доступні як

$1 = one
$2 = two
$3 = three

а $ 0 - назва самого сценарію.

Тож, коли ви знаходитесь поза сценарієм, ці змінні недоступні (крім 0 доларів, де відображається / bin / bash - сама оболонка).


"Отже, коли ви знаходитесь поза сценарієм, ці змінні недоступні" Що ви маєте на увазі під "поза скриптом" , тому що я можу бачити значення цих змінних у своєму терміналі.
користувач7681202

2
@ user7681202: Які з них можна побачити у своєму терміналі? $0буде вказувати на ваш поточний термінальний процес (швидше за все, bash) і $?просто код виходу останнього процесу.
Jesse_b

Я спробував запустити gnome-terminalаргументи ( gnome-terminal Hello World). Я міг бачити $0, але я не міг бачити $1і $2.
користувач7681202

@Jesse_b Дякую, я додав вміст у відповідь 0 доларів.
Ярослав Кучера

1
@ user7681202 gnome-термінал не оболонка, це емулятор терміналу (як xterm, konsole тощо). Оболонка працює всередині терміналу, і це може бути bash / sh / zsh / tcsh та багато іншого. Сценарій - це виконавчий файл із належним заголовком (наприклад, #! / Bin / bash) та вмістом, інтерпретованим оболонкою, вказаною в масці. Зазвичай він використовує суфікс .sh
Ярослав Кучера
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.