Estou tentando descobrir como esperar a conclusão de um comando e, em seguida, canalizar stdin para stdout. Estou em um mac, mas acho que minha pergunta é mais sobre como esperar a conclusão de um processo e canalizar a saída do que qualquer coisa a ver com um mac.
Percebi que no mac consigo rodar alguns say
comandos juntos, e eles esperam que cada frase seja totalmente falada antes de iniciar a próxima, se eu usar o &&
operador para juntá-los.
$ say "stage 1" && say "stage 2"
Aqui é onde está o caso de uso real - eu tenho um script bash que gostaria que apenas passasse stdin para stdout, depois que terminasse de dizer algo.
$ cat /etc/passwd | say_and_pass "stage 1" | grep -v test | say_and_pass "stage 2"
Então, conceitualmente, isso diria em voz alta, "estágio 1", imediatamente diria "estágio 2" e, em seguida, despejaria o conteúdo grep de /etc/password
para stdout.
Minha rachadura inicial no say_and_pass
script é esta:
diga_e_passe
#!/usr/bin/env bash
OUT="$*"
say "$OUT" && cat
Mas não parece funcionar ;-)
EDIT: alterei o exemplo acima para usar say_and_pass "stage2"
como comando final, que é necessário para que minha solução funcione...
O problema com o que você está tentando fazer aqui é que você parece ter dois fluxos de dados - um para
say
e outro para processamento de texto (ou seja,cat
egrep
).Você não pode usar um único pipeline para isso, pois isso apenas misturará os dados.
cat /etc/passwd | say
fará com que seu computador tente falar todo o conteúdo do arquivo. Além disso,say
não grava nada na saída padrão, portanto, nada iria mais longe no pipeline.Se você deseja "interromper" seu fluxo de processamento de dados para lidar com a saída separada para outros utilitários como
say
, você precisa configurar um FIFO (ou seja, um "pipe nomeado") para um ou outro de seus fluxos de dados ou usar arquivos temporários gravados em disco.Seu caso de uso demonstrativo não é muito útil para um exemplo, pois, apesar dos
say
s, você está apenasgrep
executando ping em um arquivo, o que pode ser feito em uma etapa comgrep -v test /etc/passwd
(cat file | grep pattern
é um uso inútil decat
).Dito isso, um exemplo usando um arquivo de rascunho:
E um usou um pipe nomeado para
say
:Acontece que tudo o que tive que fazer foi consumir todo o stdin no início do meu script ... Não quero que ele processe o stdin quando for recebido, mas quando todo o comando anterior na cadeia de pipes for concluído.
Portanto, meu
say_and_pass
script é simplesmente este, que funciona para o meu caso de uso!Tentar:
Na verdade, não tenho
say
no meu sistema, mas isso funciona:H!
Sugiro, com base em sua própria resposta, apenas despejar stdin em stdout, removendo a parte que o armazena em uma variável. Isso deve reduzir o consumo de memória e fazer com que a cadeia de pipes funcione como os pipes deveriam (uma linha é processada e o resultado enviado para o próximo processo).
Esta versão
say_and_pass
faz o que o OP pede:Ele usa um arquivo temporário, como @DopeGhoti sugere, mas mantém qualquer outra lógica (o
grep
, por exemplo) fora do script. Isso o tornasay_and_pass
mais geral e reutilizável.Minha interpretação do objetivo/propósito é que queremos uma forma audível de monitorar o progresso de um pipeline potencialmente longo.
Então, ao executar:
Como usuário, você pode saber de forma audível que
cmd1
concluiu totalmente sua execução; a desvantagem é quecmd2
não pode começar a processar seu stdin até quecmd1
esteja completo. Mas parece que o OP está ciente dessa troca e disposto a fazê-la.Isso é semelhante à resposta de @BradParks, mas não é limitado pela memória disponível para bash (como @agc aponta) e é um pouco mais cuidadoso para evitar a poluição acidental de stdout.
Observe também que não há necessidade de capturar a mensagem em uma variável própria, então simplesmente encaminhamos
"$@"
parasay
.Se você usar &&, seu significado, faça o primeiro comando após o segundo comando, mas o resultado do primeiro comando não é importante para o segundo comando. Quer dizer, você tem 2 comandos diferentes, porque usa &&. Se você usar |, isso significa que o primeiro comando faz algo e dá algo para o segundo comando. No final, você deve fornecer um atributo para o comando cat. desculpe meu ingles a propósito