Questão Executar o comando entre uma linha de tubulação bash ...?


Eu quero executar uma série de comandos canalizados que fazem muito audioprocessamento. Parece o seguinte no pseudocódigo:

command1 | command2 | command3

Dos comandos2 e command3, ambos tomam a saída do comando anterior como entrada (comportamento regular stdin / stdout).

Agora gostaria de executar outro comando1.1 logo após o comando1, que não está de forma alguma conectado ao canal de execução entre o comando1 e o comando2, exceto que ele não deve ser executado antes que o comando1 tenha terminado completamente.

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

No entanto, não tenho ideia de como fazer isso no bash. Eu tentei tee, mas isso faz com que o comando seja executado assim que o pipe é construído. Alguma ideia?

Obrigado!


4


origem




Respostas:


Você pode redirecioná-lo para um subshell.

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

Outra maneira é criar um pipe nomeado fifo.
Um script deve ser semelhante a

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





A parte importante sobre isso é "depois disso" - o único conceito que os pipes UNIX têm de "after that" é que eles geralmente fecham, mas eles serão executados depois que o primeiro comando tiver começado, não depois de ist terminou.

Então, o que você precisa fazer é usar um script de shell - algo que tem o conceito de "um após o outro":

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

(Claro que você pode usar o seu editor favorito para achá-lo), então corra

myscript.sh | command2 | command3

O que acontece agora é que a saída de command1 será a saída do script de shell, assim o seu pipe funciona. Dentro do seu script, a saída de command1.1 será redirecionado para STDERR do script, por isso não é enviado para o pipe, mas para o terminal


4



Eugen, o segundo eco deve ser echo 'command1.1 >&2' >> myscript.sh - Romeo Ninov
Talvez melhor ./myscript.sh do que myscript.sh; geralmente o diretório atual não está incluído no caminho por motivos de segurança ... - Hastur
@RomeoNinov Obrigado - corrigido! - Eugen Rieck
@Hastur eu deixei de fora todos os pathes - do OQ eu assumo, o cartaz sabe o caminho - Eugen Rieck
@EugenRieck Eu concordo, não foi para você ou cunei. Nós todos esperamos que a resposta possa ser útil para outros leitores também :-) e, talvez, um deles possa perder à primeira vista a diferença entre um comando que está em algum lugar no PATHe um script que, mesmo se executável (chmod 755) está no diretório atual, por padrão, fora do PATH. - Hastur


A construção mais simples seria:

(command1 ; command1.1) | command2 | command3

Existem dois problemas potenciais com isso. E se command1.1 produzir qualquer saída no stdout, ele será enviado através do pipe. Além disso command2 não verá EOF em stdin até command1.1 Completou.

Se o pipeline for invocado inicialmente em um contexto onde os descritores de arquivo stdout e stderr estão apontando para a mesma estrutura de arquivo, existe uma maneira simples de corrigir os dois problemas:

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

Isso fará com que o stdout do comando1.1 aponte para stderr, que não foi redirecionado pelo pipeline.

Se inicialmente stdout e stderr podem ser dois descritores de arquivo diferentes, a abordagem acima pode ser usada temporariamente armazenando o stdout inicial em outro número do descritor de arquivo. Então, a menos que você realmente precise manter stdout e stderr de command1.1 separar, eu não usaria essa abordagem.

Para completar, se você quisesse fazer isso, poderia ser assim:

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

2