Os comandos em um pipeline são executados ao mesmo tempo, esse é o ponto inteiro dos canais e do mecanismo de comunicação entre processos.
Em:
cmd1 | cmd2
cmd1
e cmd2
são iniciados ao mesmo tempo, cmd2
processa os dados que cmd1
grava conforme aparecem.
Se você quisesse que cmd2
fosse iniciado somente se cmd1
tivesse falhado, você teria que iniciar cmd2
após cmd1
ter terminado e reportado seu status de saída, então você não poderia usar um canal, você teria que usar um arquivo temporário que armazena todos os dados que o cmd1
produziu:
cmd1 > file || cmd2 < file; rm -f file
Ou armazene na memória como no seu exemplo, mas tem vários outros problemas (como $(...)
removendo todos os caracteres de nova linha à direita, e a maioria dos shells não consegue lidar com bytes NUL lá, sem mencionar os problemas de dimensionamento de grandes saídas).
No Linux e com shells como zsh
ou bash
que armazenam aqui-documents e here-strings em arquivos temporários, você poderia fazer:
{ cmd1 > /dev/fd/3 || cmd2 <&3 3<&-; } 3<<< ignored
Para permitir que o shell lide com a criação e limpeza do arquivo temporário.
manualmente, POSIXly:
tmpfile=$(
echo 'mkstemp(template)' |
m4 -D template="${TMPDIR:-/tmp}/XXXXXX"
) && [ -n "$tmpfile" ] && (
rm -f -- "$tmpfile" || exit
cmd1 >&3 3>&- 4<&- ||
cmd2 <&4 4<&- 3>&-) 3> "$tmpfile" 4< "$tmpfile"
Alguns sistemas possuem um comando mktemp
não padrão (embora com uma interface que varia entre sistemas) que facilita um pouco a criação do arquivo temporário ( tmpfile=$(mktemp)
deve ser suficiente com a maioria da implementação, embora alguns não criem o arquivo então você pode precisar ajustar o umask
). O [ -n "$tmpfile" ]
não deve ser necessário com m4
de implementações compatíveis, mas pelo menos o GNU m4
não é compatível, pois não retorna um status de saída diferente de zero quando a chamada mkstemp()
falha.
Observe também que não há nada que o impeça de executar qualquer código no console . Seu "script" pode ser inserido da mesma forma no prompt de um shell interativo (exceto pela parte return
que assume que o código está em uma função), embora seja possível simplificá-lo para:
output=$(cmd) || grep foo <<< "$output"