Como posso enviar saída para outro processo, mas manter o estado de erro do primeiro processo? [duplicado]

11

Estou usando a seguinte linha de comando (em um makefile) para canalizar as mensagens de erro detalhadas do meu compilador por meio de um script perl que as simplifica em algo legível:

g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl

Infelizmente, essa abordagem "mascara" o valor de erro retornado pelo comando g++ . make não tem idéia de que o comando g++ falhou, porque tudo o que recebe é o resultado do erro do comando perl .

Existe uma maneira de canalizar a saída e ainda manter a condição de erro original?

Caso isso faça diferença: Estou usando o GNU Make 3.81 e g ++ (GCC) 3.4.5 (mingw-vista especial r3) em um console MSYS executando o bash do GNU, versão 2.04.0 (1) -release (i686 -pc-msys) no Windows XP.

    
por e.James 02.12.2011 / 00:04

3 respostas

12

Não tenho certeza do que o shell sh.exe fornece (já que há vários shells que usam esse nome para seus executáveis do Windows), mas se for bash ou similar, você pode usar o array $PIPESTATUS . Para o seu exemplo, você faria:

g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl
echo "${PIPESTATUS[0]}"
    
por 02.12.2011 / 00:09
9

Bash tem uma opção pipefail :

The return status of a pipeline is the exit status of the last command,
unless  the  pipefail  option  is enabled.  If pipefail is enabled, the
pipeline's return status is the value of the last  (rightmost)  command
to  exit  with a non-zero status, or zero if all commands exit success-
fully.

Então:

set -o pipefail && $GCC_COMMAND | $PERL_COMMAND

Make executa cada linha em um subshell para cada linha , então você precisa adicioná-lo ao início da sua linha do gcc. Pode haver uma maneira de fazer o make para executar apenas aquele comando com pipefail set já, mas eu não sei.

Tente adicionar SHELL=/bin/bash no Makefile ( Make deve usar este )

Ou tente:

bash -o pipefail -c "$GCC_COMMAND | $PERL_COMMAND"
    
por 02.12.2011 / 00:20
6

Em shells tradicionais, o status do primeiro comando em um pipeline não é relatado ao script. Apenas o status do último comando está disponível, em $? .

No bash ≥3.0, quando você quiser fazer é parar se ocorrer um erro em qualquer lugar do pipeline, use o pipefail opção .

g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl

Mais geralmente, no bash, a matriz PIPESTATUS generaliza $? para cobrir todos os comandos no último pipeline.

$ (exit 1) | (exit 2) | (exit 3); echo ${PIPESTATUS[@]}
1 2 3

Zsh tem o mesmo recurso, apenas o array é chamado pipestatus .

% zsh -c '(exit 1) | (exit 2) | (exit 3); echo $pipestatus'    
1 2 3

Se você estiver disposto a assumir o bash (que IIRC é o shell fornecido por msys como sh ), então você pode usar PIPESTATUS . Se não estiver, você pode organizar passar o status de saída para o shell de nível superior por meio do pipe e fazer com que o programa de filtro saia com o status que ele lê na última linha de entrada, em vez de usá-lo como entrada normal. É desajeitado, mas pode ser útil.

Em makefiles, é relativamente comum usar arquivos temporários, tratando as mensagens do compilador como mais um arquivo intermediário.

%.otmp %.g++-log: %.cpp
        g++ -c $< -o $@tmp 2>&1 >$*.g++-log
%.o: %.otmp %.g++-log
        perl /bin/gSTLFilt.pl <$*.g++-log
        mv $*.otmp $@
    
por 02.12.2011 / 01:57