Так, bashяк і в ksh(звідки походить ця функція), процеси всередині заміни процесу не чекають (перед запуском наступної команди в скрипті).
для <(...)одного, це зазвичай добре, як у:
cmd1 <(cmd2)
оболонка буде чекати cmd1і cmd1, як правило, чекає cmd2в силу її зчитування до кінця файлу на трубі, що підміняється, і цей кінець файлу зазвичай відбувається, коли cmd2гине. Це та ж причина , кілька снарядів (НЕ bash) не турбувати чекають cmd2в cmd2 | cmd1.
Бо cmd1 >(cmd2), однак, це взагалі не так, оскільки, як cmd2правило , більше cmd1там чекає, і, як правило, вийде після.
Це зафіксовано в zshтому, що cmd2там чекає (але не, якщо ви пишете це як cmd1 > >(cmd2)і cmd1не вбудовано, використовуйте {cmd1} > >(cmd2)натомість як документально ).
kshне чекає за замовчуванням, але дозволяє зачекати його за допомогою waitвбудованого (він також робить pid доступним у $!, хоча це не допомагає, якщо це зробити cmd1 >(cmd2) >(cmd3))
rc(із cmd1 >{cmd2}синтаксисом), так само, як kshви можете отримати підказки всіх фонових процесів $apids.
es(також з cmd1 >{cmd2}) чекає, cmd2як у zsh, а також чекає cmd2в <{cmd2}перенаправленнях процесів.
bashробить pid cmd2(або точніше підкабелі, оскільки він працює cmd2в дочірньому процесі цієї підпакеті, хоча це остання команда там) доступний $!, але не дозволяє вам чекати на нього.
Якщо вам доведеться використовувати bash, ви можете вирішити проблему, скориставшись командою, яка буде чекати обох команд із:
{ { cmd1 >(cmd2); } 3>&1 >&4 4>&- | cat; } 4>&1
Це робить і те, cmd1і cmd2їх fd 3 відкрито до труби. catбуде чекати закінчення файлу на іншому кінці, тому, як правило, вийде лише тоді, коли вони обидва cmd1та cmd2мертві. І оболонка буде чекати цієї catкоманди. Ви можете бачити, що це як мережа, щоб зафіксувати завершення всіх фонових процесів (ви можете використовувати це для інших речей, розпочатих у фоновому режимі, як, наприклад &, для копроків або навіть команд цього фону за умови, що вони не закривають усі дескриптори файлів, як, наприклад, демони ).
Зауважте, що завдяки тому, що був згаданий вище підзарядний процес, він працює, навіть якщо cmd2закриває свій fd 3 (команди зазвичай цього не роблять, але деякі люблять sudoабо sshроблять). Майбутні версії з bashчасом можуть зробити оптимізацію, як і в інших оболонках. Тоді вам знадобиться щось на кшталт:
{ { cmd1 >(sudo cmd2; exit); } 3>&1 >&4 4>&- | cat; } 4>&1
Щоб переконатися, що ще існує додатковий процес оболонки з тим відкритим fd 3, що чекає цієї sudoкоманди.
Зауважте, що catнічого не буде прочитано (оскільки процеси не записують на їх fd 3). Це просто для синхронізації. Він здійснить лише один read()системний виклик, який повернеться без нічого в кінці.
Насправді ви можете уникнути запуску cat, використовуючи заміну команди для синхронізації труби:
{ unused=$( { cmd1 >(cmd2); } 3>&1 >&4 4>&-); } 4>&1
Цього разу оболонка замість catцього зчитується з труби, інший кінець якої відкритий на fd 3 cmd1та cmd2. Ми використовуємо присвоєння змінної, щоб статус виходу cmd1був доступний у $?.
Або ви можете зробити заміну процесу вручну, і тоді ви можете навіть використовувати систему вашої системи, shоскільки це стане стандартним синтаксисом оболонки:
{ cmd1 /dev/fd/3 3>&1 >&4 4>&- | cmd2 4>&-; } 4>&1
хоча зауважте, як зазначалося раніше, що не всі shреалізації будуть чекати cmd1після cmd2закінчення (хоча це краще, ніж навпаки). Цей час $?містить статус виходу cmd2; хоча bashі zshзробіть cmd1статус виходу доступним відповідно ${PIPESTATUS[0]}і $pipestatus[1]відповідно (див. також pipefailопцію в декількох оболонках, щоб $?можна було повідомити про вихід інших трубних компонентів, ніж останній)
Зауважте, що у yashнього є аналогічні проблеми з функцією перенаправлення процесу . cmd1 >(cmd2)писали б cmd1 /dev/fd/3 3>(cmd2)там. Але cmd2його не чекають, і ви також не можете waitйого чекати, і його pid також не доступний у $!змінній. Ви б використовували ті самі роботи, що і для bash.