Вопрос: Выполнить команду между строк строки bash ...?


Я хочу запустить ряд команд с каналами, которые выполняют много процессов обработки. В псевдокоде он выглядит следующим образом:

command1 | command2 | command3

Из команды 2 и command3 оба берут вывод предыдущей команды как входной (регулярное поведение stdin / stdout).

Теперь я хотел бы выполнить еще одну команду1.1 сразу после команды 1, которая никак не связана с работающим каналом между командами 1 и командой2, за исключением того, что она не должна запускаться до того, как команда 1 полностью завершила.

command1 [; after that run command1.1, even if command2 and command3 are still busy] command2 command3

Однако я понятия не имею, как это сделать в bash. Я попробовал tee, но это заставляет команду запускаться, как только будет построен канал. Есть идеи?

Благодаря!


4
2018-01-18 17:27


Источник




Ответы:


Вы можете перенаправить его на подоболочку.

command1 & > >(command2 | command3) &
wait $!      # Wait end of process $! (actually the pid of command1)
command_1.1     

Другой способ - создать именованный канал ФИФО,
Сценарий должен быть похож на

MYFIFO=/tmp/myfifo.$$
rm -f $MYFIFO
mkfifo $MYFIFO
command1 > $MYFIFO &
MYPROGRAM_PID=$!
cat $MYFIFO  | command2 | command3 &
wait $MYPROGRAM_PID   # Wait end of process $MYPROGRAM_PID
command_1.1     

4
2018-01-18 18:17





Важной частью этого является «после этого» - единственная концепция UNIX-труб имеет «после этого», что они обычно закрываются, но они будут выполняться после того, как первая команда будет начал, а не после того, закончился,

Итак, что вам нужно сделать, используется сценарий оболочки - то, что имеет понятие «один за другим»:

echo 'command1' > myscript.sh
echo 'command1.1 >&2' >> myscript.sh
chmod 755 myscript.sh

(Конечно, вы можете использовать свой любимый редактор для достижения этого), затем запустите

myscript.sh | command2 | command3

Что происходит, так это то, что выход command1 будет выходом скрипта оболочки, поэтому ваш труба работает. Внутри вашего скрипта вывод command1.1 будет перенаправлен на STDERR скрипта, поэтому он не отправляется на канал, а на терминал


4
2018-01-18 18:05



Eugen, второе эхо должно быть echo 'command1.1 >&2' >> myscript.sh - Romeo Ninov
Может быть лучше ./myscript.sh чем myscript.sh; обычно текущий каталог не включен в путь по соображениям безопасности ... - Hastur
@RomeoNinov Спасибо - исправлено! - Eugen Rieck
@Hastur Я упустил все исправления - из OQ я предполагаю, плакат знает свой путь - Eugen Rieck
@EugenRieck Я согласен, это было не для вас и для cunei. Мы все надеемся, что ответ может быть полезен и для других читателей :-), и, возможно, один из них может пропустить на первый взгляд разницу между командой, которая находится где-то в PATHи сценарий, который, даже если исполнимый (chmod 755) находится в текущем каталоге, по умолчанию отключен от PATH, - Hastur


Простейшая конструкция:

(command1 ; command1.1) | command2 | command3

С этим связаны две потенциальные проблемы. Если command1.1 производят любой вывод на stdout, он будет отправлен через трубу. Дополнительно command2 не будет видеть EOF на stdin, пока command1.1 завершено.

Если конвейер изначально вызывается в контексте, где дескрипторы файла stdout и stderr оба указывают на одну и ту же файловую структуру, тогда есть простой способ исправить обе проблемы:

(command1 ; exec 1>&2 command1.1) | command2 | command3

Это приведет к тому, что stdout команды1.1 укажет на stderr, который не был перенаправлен конвейером.

Если изначально stdout и stderr могут быть двумя разными файловыми дескрипторами, вышеупомянутый подход может быть использован путем временного удаления начального stdout в другом номере дескриптора файла. Поэтому, если вам абсолютно не нужно сохранять stdout и stderr из command1.1 Раздельный, я бы не принял такой подход.

Для полноты, если вы хотите сделать это, это может выглядеть так:

(((exec 9>&- command1) ; exec 1>&9 9>&- command1.1) | exec 9>&- command2 | exec 9>&- command3) 9>&1

2
2018-01-18 20:01