4

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

command1 | command2 | command3

Команда command2 и 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. Я попробовал тройник, но это заставляет команду выполняться, как только труба построена. Есть идеи?

Спасибо!

3 ответа3

4

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

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

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

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

myscript.sh | command2 | command3

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

4

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

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

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

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     
2

Самая простая конструкция будет:

(command1 ; command1.1) | command2 | command3

Есть две потенциальные проблемы с этим. Если command1.1 какой-либо вывод на стандартный вывод, он будет отправлен через канал. Кроме того, command2 не увидит EOF на стандартном вводе, пока command1.1 не будет выполнена.

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

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

Это приведет к тому, что стандартный вывод command1.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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .