Створення підшивки Bash з фігурними дужками


31

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

Використовуючи, psщоб побачити це в дії

Це ієрархія процесу для конвеєра процесу, який виконується безпосередньо в командному рядку. 4398 - PID для оболонки для входу:

sleep 2 | ps -H;
  PID TTY          TIME CMD
   4398 pts/23   00:00:00 bash
   29696 pts/23   00:00:00   sleep
   29697 pts/23   00:00:00   ps

Тепер слід ієрархія процесу для конвеєра процесу між фігурними дужками, виконаними безпосередньо в командному рядку. 4398 - PID для оболонки входу. Це схоже на ієрархію вище, що доводить, що все виконується в поточному контексті оболонки :

{ sleep 2 | ps -H; }
   PID TTY          TIME CMD
    4398 pts/23   00:00:00 bash
    29588 pts/23   00:00:00   sleep
    29589 pts/23   00:00:00   ps

Тепер це ієрархія процесу, коли сам sleepтрубопровід розміщується всередині фігурних дужок (тому два рівні дужки у всіх)

{ { sleep 2; } | ps -H; }
  PID TTY          TIME CMD
   4398 pts/23   00:00:00 bash
   29869 pts/23   00:00:00   bash
   29871 pts/23   00:00:00     sleep
   29870 pts/23   00:00:00   ps

Чому bashдоводиться створювати підзарядку для запуску sleepв третьому випадку, коли в документації зазначено, що команди між фігурними дужками виконуються в поточному контексті оболонки?


Цікаво, я б припустив, що це в тому, що в третьому випадку внутрішня група є частиною конвеєра, і, отже, вона виконується в підколонці, наприклад, як і будь-який інший виклик функції, який є частиною конвеєра. Чи має сенс?
Мирослав Кошкар

2
Я б не сказав "Оболонка повинна" тільки тому, що це робить ... Трубопроводи не виконуються в контексті оболонки. Якщо трубопровід складається з нічого, крім зовнішніх команд, то створення підпроцесів достатньо. { sleep 2 | command ps -H; }
Hauke ​​Laging

Відповіді:


26

У конвеєрі всі команди виконуються одночасно (при цьому їх stdout / stdin з'єднані трубами), тому в різних процесах.

В

cmd1 | cmd2 | cmd3

Усі три команди виконуються в різних процесах, тому щонайменше дві з них повинні виконуватись у дочірньому процесі. Деякі оболонки запускають один із них у поточному процесі оболонки (якщо вбудований подібний readабо якщо конвеєр є останньою командою сценарію), але bashзапускає їх у своєму окремому процесі (за винятком lastpipeопції в останніх bashверсіях та за певних конкретних умов ).

{...}групи команд. Якщо ця група є частиною конвеєра, вона повинна запускатися в окремому процесі так само, як і проста команда.

В:

{ a; b "$?"; } | c

Нам потрібна оболонка, щоб оцінити, що a; b "$?"це окремий процес, тому нам потрібна нижня оболонка . Оболонку можна оптимізувати, не запитуючи, bоскільки це остання команда, яку слід виконати в цій групі. Деякі снаряди це роблять, але, мабуть, ні bash.


" Усі три команди виконуються в різних процесах, тому щонайменше дві з них повинні запускатись в нижній частині ". Чому в цьому випадку необхідна підпачка? Чи може батьківська оболонка не породити процеси дерев? Або, коли ви говорите " доведеться запускати в нижній частині ", ти маєш на увазі, що оболонка буде розщедритися, а потім виконати для кожного cmd1 cmd2 та cmd3? Якщо я виконую це, bash -c "sleep 112345 | cat | cat "я бачу лише один створений bash, а потім 3 дітей до нього, без будь-яких інших перемежувальних підпунктів.
Хакан Баба

" Нам потрібна оболонка для того, щоб оцінити, що a; b" $? "- це окремий процес, тому нам потрібна додаткова оболонка. " Чи можете ви також розширити міркування? Для чого нам потрібен нижній шар, щоб зрозуміти це? Що потрібно, щоб зрозуміти це? Я припускаю, що розбір необхідний, але що ще? . Чи може батьківська оболонка не розібратися a; b "$?"? Чи дійсно є фундаментальна потреба в підкладці, чи, можливо, це проектне рішення / реалізація на bash?
Хакан Баба

@HakanBaba, я змінив це на "дитячий процес", щоб уникнути потенційної плутанини.
Стефан Шазелас

1
@HakanBaba, синтаксичний аналіз виконується в батьківському (процес, який читає код, той, який виконував інтерпретатор, якщо цей код не був переданий eval), але оцінка (запустіть першу команду, почекайте її, запустіть другу) робиться у дитини, той, у якого штик з'єднаний з трубою.
Стефан Шазелас

у { sleep 2 | ps -H; }батьківському bash бачить, sleep 2що потрібен fork / exec. Але в { { sleep 2; } | ps -H; }батьківському баші бачить { sleep 2; }іншими словами, якийсь баш-код. Схоже, батько може обробляти fork / exec для, sleep 2але породжує новий bash рекурсивно для обробки зіткнутого bash-коду. Це моє розуміння, чи є сенс?
Хакан Баба

19

Введення фігурних брекетів, схоже, позначає, що ви створюєте додатковий рівень масштабування, для якого потрібно викликати нову підрозділ. Цей ефект ви можете побачити у другій копії Bash у вашому ps -Hвисновку.

Тільки процеси, передбачені на першому рівні фігурних брекетів, виконуються в межах оригінальної оболонки Bash. Будь-які вкладені фігурні фігурні дужки запускатимуться у власній оболонці Bash.

Приклад

$ { { { sleep 20; } | sleep 20; } | ps -H; }
  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5012 pts/1    00:00:00   bash
 5014 pts/1    00:00:00     bash
 5016 pts/1    00:00:00       sleep
 5015 pts/1    00:00:00     sleep
 5013 pts/1    00:00:00   ps

Виймаючи | ps -Hсуміш просто так, щоб ми могли побачити вкладені фігурні дужки, ми можемо запустити ps auxf | lessв іншу оболонку.

saml     29190  0.0  0.0 117056  3004 pts/1    Ss   13:39   0:00  \_ bash
saml      5191  0.0  0.0 117056  2336 pts/1    S+   14:42   0:00  |   \_ bash
saml      5193  0.0  0.0 107892   512 pts/1    S+   14:42   0:00  |   |   \_ sleep 20
saml      5192  0.0  0.0 107892   508 pts/1    S+   14:42   0:00  |   \_ sleep 20
saml      5068  0.2  0.0 116824  3416 pts/6    Ss   14:42   0:00  \_ bash
saml      5195  0.0  0.0 115020  1272 pts/6    R+   14:42   0:00      \_ ps auxf
saml      5196  0.0  0.0 110244   880 pts/6    S+   14:42   0:00      \_ less

Але зачекайте, що є більше!

Якщо ви виймаєте труби, хоча і використовуєте цю форму команди, ми бачимо, чого ви насправді очікуєте:

$ { { { sleep 10; } ; { sleep 10; } ; sleep 10; } } | watch "ps -H"

Тепер у отриманому вікні перегляду ми отримуємо оновлення кожні 2 секунди того, що відбувається:

Ось перший sleep 10:

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5678 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5681 pts/1    00:00:00     watch
 5682 pts/1    00:00:00       ps

Ось друге sleep 10:

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5691 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5694 pts/1    00:00:00     watch
 5695 pts/1    00:00:00       ps

Ось третій sleep 10:

  PID TTY          TIME CMD
29190 pts/1    00:00:00 bash
 5676 pts/1    00:00:00   bash
 5704 pts/1    00:00:00     sleep
 5677 pts/1    00:00:00   watch
 5710 pts/1    00:00:00     watch
 5711 pts/1    00:00:00       ps

Зауважте, що всі три сну, хоча вони викликаються на різних рівнях гніздування фігурних брекетів, залишаються незмінними в межах PID 5676 Bash. Тому я вважаю, що ваше питання завдано самокористування | ps -H.

Висновки

Використання | ps -H(тобто труба) спричиняє додаткову підрозділ, тому не використовуйте цей метод, намагаючись допитати те, що відбувається.


так, "Тільки процеси, передбачені на першому рівні фігурних брекетів, виконуються в межах первісної оболонки Баша".
xealits

@xealits - це запитання, про яке ви мене запитуєте?
slm

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

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

@xealits - це правильно.
slm

7

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

$ { A=1; { A=2; sleep 2; } ; echo $A; }
2

$ { A=1; { A=2; sleep 2; } | sleep 1; echo $A; }
1

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