После неудачного перенаправления (из-за несуществующего файла или недостаточного доступа к файлу) значение ErrorLevel, похоже, не установлено (в следующих примерах файл test.tmp защищен от записи и файл test.nil не существует):
>>> (call ) & rem // (reset `ErrorLevel`)
>>> > "test.tmp" echo Text
Access is denied.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
>>> (call ) & rem // (reset `ErrorLevel`)
>>> < "test.nil" set /P DUMMY=""
The system cannot find the file specified.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
Однако, как только неудачное перенаправление сопровождается оператором условной конкатенации ||, который запрашивает код выхода, ErrorLevel устанавливается на 1, неожиданно:
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) || echo Fail
Access is denied.
Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") || echo Fail
The system cannot find the file specified.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
Интересно, что ErrorLevel остается 0, когда используется оператор &&:
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) && echo Pass
Access is denied.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") && echo Pass
The system cannot find the file specified.
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
ErrorLevel остается также 0 с помощью оператора &:
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) & echo Pass or Fail
Access is denied.
Pass or Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") & echo Pass or Fail
The system cannot find the file specified.
Pass or Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=0
В случае появления операторов условной конкатенации && и ||, ErrorLevel также устанавливается на 1 (если || встречается до &&, обе ветки выполняются как в последнем примере, но Я думаю, это просто потому, что && оценивает код выхода предыдущей команды echo):
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (> "test.tmp" echo Text) && echo Pass || echo Fail
Access is denied.
Fail
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
>>> (call ) & rem // (reset `ErrorLevel`)
>>> (< "test.nil" set /P DUMMY="") || echo Fail && echo Pass
The system cannot find the file specified.
Fail
Pass
>>> echo ErrorLevel=%ErrorLevel%
ErrorLevel=1
Итак, какова связь между значением ErrorLevel и оператором ||, почему ErrorLevel влияет на ||? Является ли || копирование кода выхода на ErrorLevel? Возможно ли это только при перенаправлении (неудачных), поскольку они обрабатываются до того, как будут выполнены какие-либо команды?
Еще более странно, я не мог наблюдать обратное поведение - ErrorLevel 0 && - при правильном возврате тестовой настройки (то есть замене (call ) на (call) (сначала установить ErrorLevel в 1), очищая атрибут только для чтения файла test.tmp, создавая файл test.nil (первая строка не пуста, чтобы избежать set /P, чтобы установить ErrorLevel в 1) и используя расширение файла .bat, а не .cmd для тестирования (чтобы избежать set /P до reset ErrorLevel до 0)).
Я наблюдал описанное поведение в Windows 7 и Windows 10.