デフォルトでは、バッチ ファイルは最後のコマンドのエラー コードを返します。
以前のコマンドのエラーコードを返すことは何とか可能ですか? 最も注目すべきは、パイプ内のコマンドのエラー コードを返すことは可能ですか?
たとえば、この 1 行のバッチ スクリプト
foo.exe
fooのエラーコードを返します。しかし、これは:
foo.exe | tee output.txt
常にゼロであるteeの終了コードを返します。
デフォルトでは、バッチ ファイルは最後のコマンドのエラー コードを返します。
以前のコマンドのエラーコードを返すことは何とか可能ですか? 最も注目すべきは、パイプ内のコマンドのエラー コードを返すことは可能ですか?
たとえば、この 1 行のバッチ スクリプト
foo.exe
fooのエラーコードを返します。しかし、これは:
foo.exe | tee output.txt
常にゼロであるteeの終了コードを返します。
同様の問題があり、成功または失敗だけで正確なエラーコードを検出する必要がなかったため、次の解決策に落ち着きました。
echo > .failed.tmp
( foo.exe && del .failed.tmp ) | tee foo.log
if exist .failed.tmp (
del .failed.tmp
exit /b 1
) else (
exit /b 0
)
%ERRORLEVEL%変数は、パイプコマンドが実行される前に更新されません。他の回答でアドバイスされているように、ラッパーを使用する必要があります。
ただし、「IF ERRORLEVEL#」は使用できます。例えば:
(
type filename
@REM Use an existing (or not) filename to test each branch
IF ERRORLEVEL 1 (echo ERROR) ELSE (echo OKAY)
) > logfile.txt
ECHOは、エラーが返された場合にのみ実行されます。ただし、%ERRORLEVEL%は一貫していないようです。
編集:サンプルをそのまま実行できるように変更しました。
単一のコマンドではなく、エントリのバットファイルに対してティーを呼び出し、エラーレベルを自由に使用するには、次のようなトリックを使用します。
if "%1" == "body" goto :body
call %0 body | tee log.txt
goto :eof
:body
set nls_lang=american_america
set HomePath=%~dp0
sqlplus "usr/pwd@tnsname" "@%HomePath%script.sql"
if errorlevel 1 goto dberror
rem Here I can do something which is dependent on correct finish of script.sql
:dberror
echo script.sqlerror failed
これにより、tee の使用とバッチ内のコマンドの呼び出しが分離されます。
約1日掘り下げた後、私はそれを行う方法を見つけました:
set error_=0
9>&1 1>&2 2>&9 (for /f "delims=" %%i in ('9^>^&1 1^>^&2 2^>^&9 ^(^(^(2^>^&1 call "%homeDir%%1"^) ^|^| ^(1^>^&2 2^>nul echo FAILED^)^) ^| 2^>nul "%homeDir%mtee" /T /+ "%homeDir%logs\%date_%_%1.log"^)') do (set error_=1))
exit /b %error_%
上記の例では、「%homeDir%%1」が実行されており、その出力は「%homeDir%mtee」にパイプされています。この行は失敗を検出します (バッチ コンテキストとその stdin/stdout/stderr 割り当ての図を描いて、その動作を理解することをお勧めします :-) )。実際のエラーレベルを抽出する良い方法が見つかりませんでした。私が得た最良のことは、「echo」コマンドを、次のようなバッチスクリプト呼び出し「call rc.bat」に置き換えることでした。
@echo %errorlevel%
次に、「set error_=1」を「set error_=%%i」に置き換えます。
しかし問題は、この呼び出しも失敗する可能性があり、それを検出するのは容易ではないということです。それでも、何もないよりはましです。インターネット上で解決策が見つかりませんでした。
この問題は、コマンド ファイルのラッパーを作成することで解決できます。
rem wrapper for command file, wrapper.cmd
call foo.exe
echo %errorlevel%
if errorlevel 1 goto...
次に、tee をラッパーに追加します。
wrapper.cmd | tee result.log
もちろん、これはまったく同じではありません。たとえば、ラップされたファイルに複数のファイルをログインしたい場合、それは不可能ですが、私の場合は問題を解決しました。