No Linux e com shells que implementam here-documents com arquivos temporários graváveis (como bash
), você pode fazer:
{
out=$(ls /dev/null /x 2> /dev/fd/3)
err=$(cat<&3)
} 3<<EOF
EOF
printf '%s=<%s>\n' out "$out" err "$err"
(onde ls /dev/null /x
é um exemplo de comando que gera algo em stdout e stderr).
Com zsh
, você também pode fazer:
(){ out=$(ls /dev/null /x 2> $1) err=$(<$1);} =(:)
(onde =(cmd)
é uma forma de substituição de processo que usa arquivos temporários e (){ code; } args
funções anônimas).
Em qualquer caso, você desejaria usar arquivos temporários. Qualquer solução que usasse pipes estaria sujeita a deadlocks no caso de grandes saídas. Você pode ler stdout e stderr através de dois canais separados e usar select()
/ poll()
e algumas leituras em um loop para ler dados, pois eles vêm dos dois canais sem causar travamentos, mas isso seria bastante complicado e AFAIK, somente zsh
tem select()
suporte embutido e apenas yash
uma interface bruta para pipe()
(mais sobre isso em Lido / escreva para o mesmo descritor de arquivo com redirecionamento de shell ).
Outra abordagem poderia ser armazenar um dos fluxos na memória temporária em vez de um arquivo temporário. Como ( zsh
ou bash
sintaxe):
{
IFS= read -rd '' err
IFS= read -rd '' out
} < <({ out=$(ls /dev/null /x); } 2>&1; printf 'out= err=
while IFS= read -r line; do
case $line in
(out:*) out=$out${line#out:}$'\n';;
(err:*) err=$err${line#err:}$'\n';;
esac
done < <(
{ { ls /dev/null /x | grep --label=out --line-buffered -H '^' >&3; } 2>&1 |
grep --label=err --line-buffered -H '^'; } 3>&1
)
%s' "$out")
(assumindo que o comando não produz qualquer NUL)
Observe que $err
incluirá o caractere de nova linha à direita.
Outras abordagens podem ser para decorar a stdout e stderr de forma diferente e remover a decoração ao ler:
{
out=$(ls /dev/null /x 2> /dev/fd/3)
err=$(cat<&3)
} 3<<EOF
EOF
printf '%s=<%s>\n' out "$out" err "$err"
Isso pressupõe o% GNUgrep
e as linhas são curtas o suficiente. Com linhas maiores que o PIPEBUF (4K no Linux), as linhas da saída dos dois grep
s podem acabar sendo mutiladas em partes.