У термінології 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запуск виконується в середовищі нижньої оболонки.