Чому $ RANDOM не включений у висновок 'env'?


23

Я знаю env, що це команда оболонки, її можна використовувати для друку списку змінних поточного середовища. Наскільки я розумію, RANDOMце також змінна середовище.

То чому, при запуску envна Linux, вихід не включає RANDOM?


4
envне є командою оболонки, оскільки вона зазвичай не вбудована в оболонку.
шилі

@schily BTW для Bash declare -x- еквівалент в оболонці.
wjandrea

Відповіді:


42

RANDOMне є змінною середовища. Це змінна оболонка, яка підтримується деякими оболонками. Зазвичай не експортується за замовчуванням. Ось чому це не відображається у результатах env.

Після того, як він був використаний принаймні один раз, він буде відображатися у висновку set, що, сам по собі, перераховує змінні оболонки (і функція) і їх значення в поточній сесії оболонки. Така поведінка залежить від оболонки та використання pdkshв OpenBSD, RANDOMперераховується, setнавіть якщо раніше не використовувалося.


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

Експорт з ним export RANDOMзробив би його змінною середовища, але його використання було б сильно обмеженим, оскільки його значення в дочірньому процесі було б "випадковим, але статичним" (це означає, що це буде незмінне випадкове число). Точна поведінка відрізняється між оболонками.

Я використовую pdkshOpenBSD у наведеному нижче прикладі, і я отримую нове випадкове значення в кожному awkзапуску (але одне і те ж значення кожного разу в межах одного і того ж awkекземпляра). Використовуючи bash, я отримав би абсолютно однакове випадкове значення у всіх викликах awk.

$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
25444 25444

$ awk 'BEGIN { print ENVIRON["RANDOM"], ENVIRON["RANDOM"] }'
30906 30906

У bash, експортне значення RANDOMзалишатиметься статичним незалежно від використання RANDOMв оболонці (де кожне використання $RANDOMвсе ще дасть нове значення).

Це пояснюється тим, що кожна посилання на змінну оболонки RANDOM у bashзмушує оболонку отримувати доступ до її внутрішньої get_random()функції, щоб надати змінній нове випадкове значення, але оболонка не оновлює змінну середовища RANDOM . Це схоже на поведінку , як і інших динамічних bashзмінних, таких , як LINENO, SECONDS, і BASHPIDт.д.

Щоб оновити змінну середовища RANDOMв bash, вам доведеться призначити їй значення змінної оболонки RANDOM та повторно експортувати її:

export RANDOM="$RANDOM"

Мені незрозуміло, чи це призвело б до додаткового побічного ефекту від повторного висівання генератора випадкових чисел у bashчи ні (але добре зрозуміла здогадка - це не так).


1
Чи має RANDOMнавіть значення, перш ніж використовувати його? Я завжди припускав, що він заселений лише тоді, коли телефонував.
тердон

1
Це не так.
тердон

1
Хоча якщо ви це зробите рівномірно export RANDOMабо declare -p RANDOM, виявляється, тож я не впевнений, чи є якась користь, якої вона не існує, перш ніж звертатися до неї ...
ilkkachu

1
"Його значення в дочірньому процесі було б випадковим, але статичним". Якщо він статичний, це не випадково , будь то три байти чи шістнадцять.
l0b0

3
@ l0b0 Це було б випадково в тому сенсі, що ви не зможете цього передбачити. Очевидно, що після того, як ви його прочитали, він більше не є випадковим, оскільки він не зміниться (якщо не повторний експорт, як я показав, в цьому випадку змінна середовища отримає нове випадкове значення). Ось чому я сказав, що це випадково, але статично. Я дещо уточнив це в тексті зараз.
Кусалаланда

16

Не всі змінні, встановлені у вашому сеансі оболонки, є змінними середовища. "Змінні середовища" стосуються лише тих змінних, які були експортовані в навколишнє середовище за допомогою exportвбудованого. envКоманда виводить тільки такі середовища змінної. Наприклад:

$ foo="bar"
$ env | grep foo ## returns nothing
$ export foo
$ env | grep foo ## now, env will print it
foo=bar

Якщо ви хочете побачити всі змінні, встановлені у вашому сеансі, незалежно від того, були вони експортовані, ви можете використовувати set:

$ set | grep foo=
foo=bar

setВбудований також повертає функцію, так , щоб бачити тільки змінні, ви можете використовувати:

set | grep  '^[^[:space:]]*='

Нарешті, RANDOMзмінна особлива тим, що їй присвоюється значення лише тоді, коли ви посилаєтесь на неї. Про це йдеться в bash (1) :

RANDOM

    Щоразу, коли цей параметр посилається, генерується випадкове ціле число між 0 і 32767. Послідовність випадкових чисел може бути ініціалізована шляхом присвоєння значення RANDOM. Якщо його RANDOMне встановлено, він втрачає свої особливі властивості, навіть якщо згодом його скидає.

Тож навіть якби це була змінна середовище, як ви думали, вона не відображалася б, envоскільки вона не буде встановлена ​​до першого виклику. Ось чому він не відображається в set:

$ set | grep RAN   ## returns nothing, RANDOM is unset
$ echo "$RANDOM"   ## this will assign a value to RANDOM
1234
$ set | grep RAN   ## so now it will also appear in the output of set 
RANDOM=1234

Це цікаве відкриття щодо set | grep RAN. Я б цього не очікував. FWIW, я вважаю, що це неможливо передбачити в документації.
G-Man каже: "Відновіть Моніку"

1
PS Вітаємо з досягненням 120 000. (Напевно, я щойно поставив вас.)
G-Man каже: "Відновіть Моніку"

4

Більшість оболонок матимуть ряд інших змінних, встановлених або використовуваних оболонкою, які не експортуються в дочірні процеси за замовчуванням.

У Bash є, очевидно, специфічні для Баша:

$ echo "${!BASH*}"
BASH BASHOPTS BASHPID BASH_ALIASES BASH_ARGC BASH_ARGV BASH_CMDS BASH_COMMAND BASH_LINENO BASH_SOURCE BASH_SUBSHELL BASH_VERSINFO BASH_VERSION
$ echo $BASH_VERSION
4.4.12(1)-release
$ env|grep -c BASH
0

Потім є більш стандартні, такі як ( OPTINDі OPTERRвикористовуються getopts), і PS2,PS3 (вторинні підказки) і навіть інша "магічна" змінна: SECONDS(показує час у секундах з моменту запуску оболонки)

У Bash ви можете побачити всі змінні та їх експортний статус declare -p. Ті, що позначені -xзначком, експортуються, а без них x- ні. (Деякі матимуть інші прапори, такі як iцілі чи rдля читання.)

У Zsh або ksh93, ви можете використовувати typeset -p, хоча знаки ЗШ експортовані змінні, змінюючи typesetдо exportна виході, замість того , щоб використовувати прапори. exportсам по собі також показав би всі експортовані змінні, але це приблизно той самий результат, який ви отримуєте, запустивши env.


2

Якщо ви користуєтеся Google для цього, у документах зазначено наступне:

$RANDOMце внутрішня функція Bash (не константа), яка повертає псевдовипадкове [1] ціле число в діапазоні 0 - 32767. Його не слід використовувати для створення ключа шифрування.

Якщо ви використовуєте, straceви можете бачити, що $RANDOM"змінна" передається безпосередньо командам так, ніби це була звичайна змінна оболонки або змінна середовища, але це лише внутрішня функція, вбудована в оболонку, Bash, що робить розширення.

$ strace -t echo "random value: $RANDOM"
04:37:58 execve("/bin/echo", ["echo", "random value: 30795"], [/* 27 vars */]) = 0
04:37:58 brk(NULL)                      = 0x19c1000
04:37:58 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9841351000
...

порівняно з цією звичайною змінною:

$ strace -t echo "random value: $SOMEVAR"
04:40:19 execve("/bin/echo", ["echo", "random value: helloworld"], [/* 27 vars */]) = 0
04:40:19 brk(NULL)                      = 0x154b000
04:40:19 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f659d2eb000
...

Змінна не передається як посилання.

Список літератури


1
ну, не те, що відбувається розширене значення з $RANDOMабо $SOMEVARчерез лінію аргументу команди, а не в якості змінного оточення? Вам потрібно буде exportобом пропустити їх через навколишнє середовище.
ilkkachu

Ні, це не мало б значення. Оболонка розширює їх незалежно. Те, як я це показав, в основному підкреслює той факт, що оболонка робить розширення.
slm

2
Схоже, straceвихід не вловлює внутрішню функцію, яку виконує оболонка. В обох випадках змінна вже розширена в першому рядку strace. Я не розумію, на яку різницю ти вказуєш. Що я пропускаю?
тердон

Показано, що $RANDOMрозширення робиться всередині оболонки. Це в основному підтвердження, що оболонка визначає значення, а не передача посилання на змінну. Оболонка, коли вона розширює командний рядок для виконання синтаксичного аналізу $RANDOMта передає розгорнуту форму в echo.
slm

2
Отже, нічого подібного до змінної середовища .
Toby Speight
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.