Executa o comando entre uma linha do pipe do bash…?

4

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

command1 | command2 | command3

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

Agora eu 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 idéia?

Obrigado!

    
por cunei 18.01.2015 / 18:27

3 respostas

4

Você pode redirecioná-lo para um subnível.

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

Outra maneira é criar um fifo com pipe nomeado.
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     
    
por 18.01.2015 / 19:17
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 após o primeiro comando iniciado , não depois que o ist terminou .

Então, o que você precisa fazer é usar um script de shell - algo que tenha 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á redirecionada para STDERR do script, por isso não é enviada para o pipe, mas para o terminal

    
por 18.01.2015 / 19:05
2

A construção mais simples seria:

(command1 ; command1.1) | command2 | command3

Existem dois problemas potenciais com isso. Se command1.1 produzir qualquer saída no stdout, ela será enviada pelo pipe. Além disso, command2 não verá EOF no stdin até que command1.1 seja concluído.

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, então 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 de descritor de arquivo. Então, a menos que você realmente precise manter o stdout e o stderr de command1.1 separados, 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
    
por 18.01.2015 / 21:01