Você pode usar coprocessos. Invólucro simples que alimenta as duas saídas de um determinado comando para duas sed
instances (uma para stderr
a outra para stdout
), que faz a marcação.
#!/bin/bash
exec 3>&1
coproc SEDo ( sed "s/^/STDOUT: /" >&3 )
exec 4>&2-
coproc SEDe ( sed "s/^/STDERR: /" >&4 )
eval $@ 2>&${SEDe[1]} 1>&${SEDo[1]}
eval exec "${SEDo[1]}>&-"
eval exec "${SEDe[1]}>&-"
Observe várias coisas:
-
É um encantamento mágico para muitas pessoas (incluindo eu) - por uma razão (veja a resposta abaixo).
-
Não há garantia de que não irá ocasionalmente trocar algumas linhas - tudo depende do agendamento dos coprocessos. Na verdade, é quase garantido que em algum momento isso acontecerá. Dito isso, se a ordem for estritamente a mesma, você terá que processar os dados de
stderr
estdin
no mesmo processo, caso contrário, o agendador do kernel pode (e vai) fazer uma bagunça.Se eu entendi o problema corretamente, isso significa que você precisaria instruir o shell a redirecionar ambos os fluxos para um processo (o que pode ser feito pelo AFAIK). O problema começa quando esse processo começa a decidir sobre o que atuar primeiro - ele teria que pesquisar as duas fontes de dados e, em algum momento, chegar ao estado em que estaria processando um fluxo e os dados chegariam aos dois fluxos antes de terminar. E é exatamente aí que ele se desfaz. Isso também significa que agrupar os syscalls de saída como
stderred
é provavelmente a única maneira de alcançar o resultado desejado (e, mesmo assim, você pode ter um problema quando algo se torna multissegmentado em um sistema multiprocessador).
No que diz respeito aos coprocessos, leia a excelente resposta de Stéphane em Como você usa o comando coproc no Bash? para uma visão mais aprofundada.