У термінології POSIX середовище додаткової оболонки пов'язане з поняттям середовище виконання оболонки .
Навколишнє середовище додаткової оболонки - це окреме середовище виконання оболонки, створене як дублікат батьківського середовища. Це середовище виконання включає такі речі, як відкриті файли, umask, робочий каталог, змінні оболонки / функції / псевдоніми ...
Зміни в цьому середовищі додаткової оболонки не впливають на батьківське середовище.
Традиційно в оболонці Bourne або ksh88, на якій базується специфікація POSIX, це робилося шляхом розпалювання дочірнього процесу.
Області, де POSIX вимагає або дозволяє команді запускатись у середовищі підклітини, це ті області, де ksh88 традиційно розщеплює процес дочірньої оболонки.
Однак це не змушує реалізацію використовувати для цього дочірній процес.
Оболонка може замість цього реалізувати окреме середовище виконання будь-яким способом.
Наприклад, ksh93 робить це, зберігаючи атрибути батьківського середовища виконання та відновлюючи їх після завершення оточення підпрограми в контекстах, де розхитування можна уникнути (як оптимізація, оскільки розгортання є досить дорогим для більшості систем).
Наприклад, у:
cd /foo; pwd
(cd /bar; pwd)
pwd
POSIX вимагає cd /foo
запуску в окремому середовищі і для виведення чогось типу:
/foo
/bar
/foo
Це не вимагає його запуску в окремому процесі. Наприклад, якщо stdout стає зламаною трубою, pwd
запуск у середовищі підпалубки може дуже добре відправити SIGPIPE до єдиного процесу оболонки.
Більшість оболонок в тому числі bash
буде реалізовувати його, оцінюючи код всередині (...)
в дочірньому процесі (поки батьківський процес чекає його завершення), але замість ksh93 при запуску коду всередині (...)
цього ж процесу:
- пам’ятайте, що це знаходиться в нижній частині середовища.
- після цього
cd
збережіть попередню робочу директорію (як правило, у дескрипторі файлу, відкритому за допомогою O_CLOEXEC), збережіть значення змінних OLDPWD, PWD та будь-що, що cd
може змінити, а потім зробітьchdir("/bar")
- після повернення з допоміжної частини поточний робочий каталог відновлюється (з а
fchdir()
на цьому збереженому fd), а все інше, що можливо, допоміжна зміна.
Існують контексти, коли дочірнього процесу неможливо уникнути. ksh93 не роздвоюється:
var=$(subshell)
(subshell)
Але робить у
{ subshell; } &
{ subshell; } | other command
Тобто випадки, коли речі мають працювати в окремих процесах, щоб вони могли працювати одночасно.
ksh93 оптимізації йдуть далі. Наприклад, перебуваючи в
var=$(pwd)
більшість оболонок розщедрить процес, дозволить дитині запустити pwd
команду з її stdout, перенаправлену на трубу, pwd
записати поточну робочу директорію в цю трубу, а батьківський процес зчитує результат на іншому кінці труби, ksh93
віртуалізує все, що ні не вимагаючи ані вилки, ані труби. Вилка та труба використовуються лише для невбудованих команд.
Зауважте, що існують інші контексти, які підрозділи, для яких оболонки розщеплюють дочірній процес. Наприклад, щоб запустити команду, яка зберігається в окремому виконуваному файлі (а це не скрипт, призначений для того ж інтерпретатора оболонки), оболонка повинна розпалювати процес для запуску цієї команди в ній, інакше не було б зможе запустити більше команд після того, як ця команда повернеться.
В:
/bin/echo "$((n += 1))"
Це не додаткова оболонка, команда буде оцінюватися в поточному середовищі виконання оболонки, n
змінна поточного середовища виконання оболонки буде нарощена, але оболонка буде форсувати дочірній процес для виконання цієї /bin/echo
команди в ньому з розширенням $((n += 1))
як аргумент .
Багато оболонок реалізують оптимізацію, оскільки вони не примушують дочірнього процесу виконувати цю зовнішню команду, якщо це остання команда скрипту або підпакет (для тих допоміжних оболонок, які реалізовані як дочірні процеси). ( bash
однак це робиться лише в тому випадку, якщо ця команда є єдиною командою підпакеті).
Це означає, що з цими оболонками, якщо остання команда в допоміжній оболонці - це зовнішня команда, підшалл не викликає породження додаткового процесу. Якщо порівнювати:
a=1; /bin/echo "$a"; a=2; /bin/echo "$a"
з
a=1; /bin/echo "$a"; (a=2; /bin/echo "$a")
буде створено однакову кількість процесів, лише у другому випадку, друга вилка робиться раніше, так що a=2
запуск виконується в середовищі нижньої оболонки.