del
и ErrorLevel
?
Команда del
не устанавливает ErrorLevel
до тех пор, пока допустимы заданные аргументы, в таких случаях она даже сбрасывает ErrorLevel
на 0
(по крайней мере, для Windows 7).
del
изменяет ErrorLevel
только в том случае, если указан недопустимый переключатель (del /X
устанавливает ErrorLevel
в 1
), аргументы вообще не указаны (del
также устанавливает ErrorLevel
в 1
) или указан неверный путь к файлу (del :
устанавливает ErrorLevel
в 123
), по крайней мере для Windows 7.
Возможный обходной путь
Возможный обходной путь — захватить вывод STDERR
del
, потому что в случае ошибок удаления соответствующие сообщения (Could Not Find [...]
, Access is denied.
, The process cannot access the file because it is being used by another process.
) записываются туда. Так может выглядеть:
for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
Чтобы использовать код непосредственно в командной строке, а не в пакетном файле, напишите %#
вместо %%#
.
Если вы не хотите удалять файлы только для чтения, удалите /F
из командной строки del
;
если вам нужны подсказки (если в пути к файлу присутствуют подстановочные знаки ?
и/или *
), удалите /Q
.
Объяснение кода
Это выполняет командную строку del /F /Q "\path\to\the\file_s.txt"
. По части 2>&1 1> nul
вывод команды на STDOUT
будет отклонен, а его вывод STDERR
будет перенаправлен так, чтобы for /F
принял его.
Если удаление прошло успешно, del
не генерирует вывод STDERR
, следовательно, цикл for /F
не повторяется, поскольку анализировать нечего. Обратите внимание, что ErrorLevel
в этом случае не сбрасывается, его значение остается неизменным.
Если for /F
получает любой вывод STDERR
из командной строки del
, выполняется команда в теле цикла, то есть set =
; это недопустимый синтаксис, поэтому set
устанавливает ErrorLevel
в 1
. Часть 2> nul
позволяет избежать отображения сообщения The syntax of the command is incorrect.
.
Чтобы установить ErrorLevel
явно, вы также можете использовать cmd /C exit /B 1
. Возможно, эта строка более разборчива. Конечно, это более гибко, потому что вы можете указать любое (со знаком 32-битное) число, включая 0
, чтобы очистить его (опуск числа также очищает его). Хотя с точки зрения производительности он может быть немного хуже.
Пример применения
Следующий пакетный файл демонстрирует, как можно применить описанный выше обходной путь:
:DELETE
echo Deleting "%~1"...
rem this line resets ErrorLevel initially:
cmd /C exit /B
rem this line constitutes the work-around:
for /F "tokens=*" %%# in ('del /F /Q "C:\Users\newuser\Desktop\%~1" 2^>^&1 1^> nul') do (2> nul set =)
rem this is the corrected ErrorLevel query:
if not ErrorLevel 1 echo Deleted "%~1" succesfully.
goto :EOF
Предустановка ErrorLevel
Помимо вышеупомянутой команды cmd /C exit /B
, вы также можете использовать > nul ver
для сброса ErrorLevel
. Это можно комбинировать с обходным решением цикла for /F
следующим образом:
> nul ver & for /F "tokens=*" %%# in ('del /F /Q "\path\to\the\file_s.txt" 2^>^&1 1^> nul') do (2> nul set =)
Альтернативный метод без for /F
Вместо использования for /F
для захвата STDERR
вывода del
команду find
можно также использовать как find /V ""
, которая возвращает ErrorLevel
из 1
, если приходит пустая строка, и 0
в противном случае:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1
Однако это вернет ErrorLevel
из 1
в случае успешного удаления и 0
в противном случае. Чтобы изменить это поведение, можно добавить предложение if
/else
следующим образом:
del "\path\to\the\file_s.ext" 2>&1 1> nul | find /V "" 1> nul 2>&1 & if ErrorLevel 1 (1> nul ver) else (2> nul set =)
Другой подход: проверка файла на существование после del
Совершенно другой подход заключается в проверке существования файла после попытки его удаления (спасибо пользователю Sasha за подсказку!), например, так :
del /F /Q "\path\to\the\file_s.txt" 1> nul 2>&1
if exist "\path\to\the\file_s.txt" (2> nul set =) else (1> nul ver)
person
aschipfl
schedule
28.10.2015