web-dev-qa-db-ja.com

出力を別のプロセスにパイプして、最初のプロセスのエラー状態を保持するにはどうすればよいですか?

重複の可能性:
別のプロセスにパイプされているプロセスの終了コードを取得します

次のコマンドライン(メイクファイル内)を使用して、コンパイラからの詳細なエラーメッセージをPerlスクリプトを介してパイプし、人間が読める形式に簡略化します。

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

残念ながら、このアプローチは、g++コマンドによって返されるエラー値を「マスク」します。 makeは、g++コマンドが失敗したことを認識していません。これは、Perlコマンドからのエラー結果だけが返されるためです。

出力をパイプし、元のエラー状態を保持する方法はありますか?

違いがある場合:GNU bash、バージョン2.04を実行しているMSYSコンソールでGNU Make 3.81およびg ++(GCC)3.4.5(mingw-Vista special r3)を使用しています。 Windows XPの.0(1)-release(i686-pc-msys)。

11
e.James

Shell sh.exeが何を提供するかはわかりませんが(Windows実行可能ファイルにその名前を使用するシェルが複数あるため)、bashなどの場合は、$PIPESTATUSを使用できます。アレイ。あなたの例では、あなたはそうするでしょう:

g++ -c source.cpp -o source.o 2>&1 | Perl /bin/gSTLFilt.pl
echo "${PIPESTATUS[0]}"
12
Chris Down

Bashにはオプション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.

そう:

set -o pipefail && $GCC_COMMAND | $Perl_COMMAND

Makeは各行のサブシェル内のすべての行を実行します なので、gcc行の先頭に追加する必要があります。 makeにpipefailが設定されたその1つのコマンドだけを実行させる方法はあるかもしれませんが、私にはわかりません。

追加Shell=/bin/bash Makefile内( Makeはこれを使用する必要があります

または試してください:

bash -o pipefail -c "$GCC_COMMAND | $Perl_COMMAND"
9
Kevin

従来のシェルでは、パイプラインの最初のコマンドのステータスはスクリプトにまったく報告されません。 $?では、最後のコマンドのステータスのみが使用可能です。

Bash≥3.0では、 パイプラインのどこかでエラーが発生した場合に停止する場合は、pipefailオプションを使用します

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

より一般的には、bashでは、PIPESTATUS配列は$?を一般化して、最後のパイプラインのすべてのコマンドをカバーします。

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

Zshにも同じ機能があり、配列のみがpipestatusと呼ばれます。

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

Bash(IIRCはmsysによってshとして提供されるシェル)を想定する場合は、PIPESTATUSを使用できます。そうでない場合は、パイプを介して終了ステータスをトップレベルシェルに渡すように調整し、通常の入力として使用する代わりに、入力の最後の行で読み取ったステータスでフィルタープログラムを終了させることができます。不器用ですが、便利な場合があります。

Makefileでは、一時ファイルを使用するのが比較的一般的です。ここでは、コンパイラメッセージをもう1つの中間ファイルとして扱います。

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