Яка різниця у використанні між змінними оболонки та змінними середовища?


16

Я фактично не знав, що є два різних типу змінних, до яких я можу отримати доступ з командного рядка. Все, що я знав, це те, що я можу оголосити змінні типу:

foo="my dear friends"
bar[0]="one"
bar[1]="two"
bar[2]="three"

або отримати доступ до них зі знаком $, наприклад:

echo $foo
echo ${bar[1]}

або з використанням вбудованих змінних, таких як:

echo $PWD
PATH=$PATH:"/usr/bin/myProg"

Тепер я чую, що існує два (принаймні?) Типи змінних: змінні оболонки та змінні середовища.

  • Яка мета наявності двох різних типів?
  • Як я можу дізнатися, який тип змінної?
  • Які типові звички для кожного з них?


Відповіді:


14

Змінні середовища - це список name=valueпар, які існують незалежно від програми (оболонка, програма, демон ...). Зазвичай вони успадковуються дочірніми процесами (створюються за допомогою послідовності fork/ exec): дочірні процеси отримують власну копію батьківських змінних.

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

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

Масив та інші змінні типу складного типу неможливо експортувати, якщо їх ім’я та значення не можуть бути перетворені у name=valueшаблон або коли встановлений специфічний механізм для оболонки (наприклад: bashфункції експорту в навколишнє середовище та деякі екзотичні, не-POSIX-оболонки, такі як rcі esможуть експортувати масиви ).

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

Зауважимо також, що сучасні оболонки (принаймні kshта bash) підтримують область змінних третіх оболонок. Змінні, створені у функціях із typesetключовим словом, є локальними для цієї функції (Спосіб оголошення функції вмикає / відключає цю функцію ksh, а постійна поведінка відрізняється між bashта ksh). Дивіться /unix//a/28349/2594

1 Це відноситься і до сучасної шкаралупі подобається ksh, dash, bashі подібна. Спадкова оболонка Борна та оболонки синтаксису, які не є Bourne, cshмають різну поведінку.


1
Все успадковується дітьми процесами, оскільки діти створюються як виделка (точна копія) свого батька. Суть із змінними середовища полягає в тому, що вони передаються до execve()системного виклику, тому вони (як правило) використовуються для збереження даних під час виконання інших команд (у тому ж процесі).
Стефан Шазелас

Не всі змінні середовища переведені на змінні оболонки. Тільки ті, які дійсні як ім'я змінної оболонки (і за кількома винятками, як IFSу деяких оболонках).
Стефан Шазелас

Оболонки, як rc, esможуть експортувати масиви, використовуючи adhoc-кодування. bashа rcтакож може експортувати функції, використовуючи змінні середовища (знову ж таки, використовуючи спеціальне кодування).
Стефан Шазелас

В ksh93, typesetобмежує сферу дії лише у функціях, оголошених function foo { ...; }синтаксисом, а не з синтаксисом Bourne ( foo() cmd) (і статичний діапазон не динамічний, як в інших оболонках).
Стефан Шазелас

@ StéphaneChazelas Дякуємо за відгук! Відповідь оновлено, щоб врахувати ваші зауваження.
jlliagre

17

Змінні оболонки

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

Ви можете створити змінну оболонки, призначивши значення невикористаному імені:

var="hello"

Використання змінних оболонок - це відстеження даних у поточному сеансі. Змінні оболонки зазвичай мають назви з малої літери.

Змінні середовища

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

VAR="hello"  # shell variable created
export VAR   # variable now part of the environment

або

export VAR="hello"

Після того, як змінна оболонки експортується, він залишається на експорт , поки не буде знята з охорони, або до його «експорт властивість» не видаляється (з export -nв bash), так що зазвичай немає необхідності повторно експортувати його. Видалення змінної з unsetїї видаленням (незалежно від того, чи є це змінна середовище чи ні).

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

Використання змінних оточуючих середовищ полягає в тому, щоб відслідковувати дані в поточному сеансі оболонки, а також дозволяти будь-якому запущеному процесу брати частину цих даних. Типовим випадком цього є PATHзмінна середовище, яка може бути встановлена ​​в оболонці і пізніше використана будь-якою програмою, яка хоче запускати програми, не вказуючи повний шлях до них.

Збір змінних середовища в процесі часто називають "середовищем процесу". У кожного процесу є своє середовище.

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

Змінні середовища можуть бути перелічені env(без жодних аргументів). Крім цього, вони виявляються такими ж, як неекспортовані змінні оболонки в сеансі оболонки. Це трохи особливо для оболонки, оскільки більшість інших мов програмування зазвичай не змішують "звичайні" змінні зі змінними середовища (див. Нижче).

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

env CC=clang CXX=clang++ make

Це починається makeзі змінної середовища, CCвстановленої на значення clangта CXXвстановленої на clang++.

Він також може бути використаний для очищення середовища для процесу:

env -i bash

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

Приклад різниці

$ var="hello"   # create shell variable "var"
$ bash          # start _new_ bash session
$ echo "$var"   # no output
$ exit          # back to original shell session
$ echo "$var"   # "hello" is outputted
$ unset var     # remove variable

$ export VAR="hello"  # create environment variable "VAR"
$ bash
$ echo "$VAR"         # "hello" is outputted since it's exported
$ exit                # back to original shell session
$ unset VAR           # remove variable

$ ( export VAR="hello"; echo "$VAR" )  # set env. var "VAR" to "hello" in subshell and echo it
$ echo "$VAR"         # no output since a subshell has its own environment

Інші мови

У більшості мов програмування є функції бібліотеки, що дозволяє отримувати та встановлювати змінні середовища. Зауважте, що оскільки змінні середовища зберігаються як просте співвідношення ключ-значення, вони зазвичай не є "змінними" мови. Програма може отримати значення (яке завжди є символьним рядком), що відповідає ключу (назва змінної середовища), але потім доведеться перетворити його в ціле число або будь-який тип даних, на який мова очікує, що це значення має.

У C, змінні оточення можуть бути доступні з допомогою getenv(), setenv(), putenv()і unsetenv(). Змінні, створені за допомогою цих процедур, успадковуються так само, як і будь-який процес, який запускається програма C.

Інші мови можуть мати спеціальні структури даних для виконання того ж самого, як %ENVхеш в Perl, або ENVIRONасоціативний масив у більшості реалізацій awk.


THX, блискуче зрозуміле пояснення. Таким чином, середовище - це як велике поле, в якому інші програми можуть жити і бачити кожну зі змінних середовища. Деякі програми мають свої приватні змінні, лише вони самі можуть бачити їх, як оболонку. але існує механізм, щоб приватні змінні бачили всі, які називаються "експорт". Якщо це нормально зрозуміло, то єдине, в чому я не впевнений, - чи може існувати більше одного середовища одночасно?
акулант

@sharkant У кожного запущеного процесу є своє середовище. Це середовище успадковується від процесу, який його запустив. Між середовищами різних процесів ніколи не існує «перехресних розмов». Єдиний спосіб зміни змінної середовища в процесі - це сам процес її зміни.
Кусалаланда

THX для уточнення мого розуміння. Кожна риба всередині своєї миски з рибою. Як щодо процесів, які породжують інші процеси? Чи є процеси та їхні дочірні процеси всередині одного середовища чи кожен має своє?
акулант

1
@sharkant У більшості мов є бібліотечні функції, що дозволяють отримати та встановити змінні середовища. У C, це робиться з getenv(), setenv(), putenv()і unsetenv(). Змінні, створені за допомогою цих процедур, успадковуються так само, як і будь-який процес, який запускається програма C. Інші мови можуть мати спеціальні структури даних для тієї ж речі, як %ENVу Perl.
Кусалаланда

1
FWIW: exec*()сімейство функцій також може задавати середовище для виконуваного процесу.
Satō Katsura

5

Змінні оболонки важко дублювати.

$ FOO=bar
$ FOO=zot
$ echo $FOO
zot
$ 

Однак змінні середовища можуть дублюватися; вони є лише списком, і список може мати повторювані записи. Ось envdup.cзробити саме це.

#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

extern char **environ;

int main(int argc, char *argv[]) {
    char **newenv;
    int envcount = 0;

    if (argc < 2) errx(64, "Usage: envdup command [args ..]");

    newenv = environ;
    while (*newenv++ != NULL) envcount++;

    newenv = malloc(sizeof(char *) * (envcount + 3));
    if (newenv == NULL) err(1, "malloc failed");
    memcpy(newenv, environ, sizeof(char *) * envcount);
    newenv[envcount]   = "FOO=bar";
    newenv[envcount+1] = "FOO=zot";
    newenv[envcount+2] = NULL;

    environ = newenv;
    argv++;
    execvp(*argv, argv);
    err(1, "exec failed '%s'", *argv);
}

Який ми можемо компілювати та запустити розповісти, envdupа потім запустити, envщоб показати нам, які змінні середовища встановлені ...

$ make envdup
cc     envdup.c   -o envdup
$ unset FOO
$ ./envdup env | grep FOO
FOO=bar
FOO=zot
$ 

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

$ unset FOO
$ ./envdup perl -e 'exec "env"' | grep FOO
FOO=bar
$ ./envdup python3 -c 'import os;os.execvp("env",["env"])' | grep FOO
FOO=bar
FOO=zot
$ 

Схоже, Python 3.6 тут наосліп проходить уздовж дублікатів (нещільна абстракція), тоді як Perl 5.24 цього не робить. Як щодо снарядів?

$ ./envdup bash -c 'echo $FOO; exec env' | egrep 'bar|zot'
zot
FOO=zot
$ ./envdup zsh -c 'echo $FOO; exec env' | egrep 'bar|zot' 
bar
FOO=bar
$ 

Боже, що станеться, якщо sudoтільки дезінфікує перший запис середовища, а потім bashпрацює з другим? Привіт PATHабо LD_RUN_PATHексплуатувати. Твій sudoвсе інше ?) Закріплений за цю дірку ? Подвиги безпеки - це ні "анекдотична різниця", ні просто "помилка" в програмі, що викликає.


1
Це правда, але анекдотична різниця і, можливо, помилка програми, що встановлює дублюючу змінну.
jlliagre


0

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

env –Команда дозволяє запускати іншу програму у користувальницькому середовищі без зміни поточної. При використанні без аргументу він надрукує список змінних поточних середовищ. printenv –Команда друкує всі або вказані змінні середовища. set –Команда встановлює або знімає змінні оболонки. При використанні без аргументу він надрукує список всіх змінних, включаючи змінні середовища і оболонки, і функції оболонки. unset –Команда видаляє змінні оболонки та середовища. export –Команда встановлює змінні середовища

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