Подтвердить что ты не робот

Как получить уровень ошибок команд в трубе в пакетном программировании Windows?

Пакетные файлы по умолчанию возвращают код ошибки последней команды.

Как-то можно вернуть код ошибки прежней команды. В частности, возможно ли вернуть код ошибки команды в трубе?

Например, эта однострочная партия script

foo.exe

возвращает код ошибки foo. Но этот:

foo.exe | tee output.txt

всегда возвращает код выхода tee, который равен нулю.

4b9b3361

Ответ 1

У меня была аналогичная проблема и я решил следующее решение, так как мне не нужно было точно определять код ошибки только с успехом или неудачей.

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
)

Ответ 2

Один способ обхода - сделать косвенную передачу через файл.

Подобно этому

foo.exe > tmp.txt
set FOOERR=%ERRORLEVEL%
cat tmp.txt
exit %FOOERR%

Ответ 3

Переменная% ERRORLEVEL% не обновляется до запуска команды pipe; вы должны использовать обертку, как указано в других ответах.

Однако вы можете использовать "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% кажется непоследовательным.

Изменить: Изменен пример, который должен быть запущен как есть.

Ответ 4

Сценарий

foo.exe && set dummy= | tee output.txt

вернет код ошибки foo.exe. Добавление некоторой фиктивной команды за && сохраняет код завершения команды до && Код выхода фиктивной команды не имеет значения. Команда-пустышка не должна ничего выводить и, предпочтительно, вообще не иметь никакого эффекта. Задание переменной среды в качестве фиктивной команды не имеет никакого эффекта, поскольку конвейерные команды выполняются в собственной оболочке cmd.

Если команда является частью более длинного сценария, тогда полезна следующая строка, поскольку она останавливает выполнение сценария и возвращает правильный код выхода:

foo.exe && set dummy= | tee output.txt || exit /b !errorlevel! 

Я проверял это в Windows 7 и Windows 10. Однако я не нашел никакой документации, объясняющей поведение комбинации && и | Кто-нибудь может объяснить или сослаться на такую документацию?

Ответ 5

Примерно через один день копания я нашел способ сделать это:

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, чтобы понять, что она делает:-)). Я не нашел хороший способ извлечь фактический уровень ошибок. Самое лучшее, что я получил, это заменить команду "эхо" на некоторый пакетный вызов script call rc.bat, который выглядит так:

@echo %errorlevel%

а затем замените "set error_ = 1" на "set error _ = %% i".

Но проблема в том, что этот вызов также может завершиться неудачей, и обнаружить это непросто. Тем не менее, это намного лучше, чем ничего - я не нашел для этого решения в Интернете.

Ответ 6

Чтобы вызвать tee для ввода bat файла, а не для одной команды, и свободно использовать уровень ошибок, я использую трюк следующим образом:

if "%1" == "body" goto :body
call %0 body | tee log.txt
goto :eof
:body

set nls_lang=american_america
set HomePath=%~dp0

sqlplus "usr/[email protected]" "@%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 от вызова любых команд внутри пакета.

Ответ 7

Вы можете решить проблему, создав оболочку вокруг файла команды:

rem wrapper for command file, wrapper.cmd

call foo.exe

echo %errorlevel%

if errorlevel 1 goto...

Затем добавьте tee к обертке:

wrapper.cmd | tee result.log

Конечно, это не совсем то же самое, например. если вы хотите зарегистрировать несколько файлов в завернутом файле, это невозможно, но в моем случае он решил проблему.