rd завершает работу с уровнем ошибки, установленным на 0, при ошибке, когда удаление не удается, и т. д.

Я пишу пакетный (.bat) скрипт, и мне нужно обработать случай, когда удаление папки не удается. Я использую %errorlevel% для перехвата кода выхода, но в случае с командой rd это не работает:

C:\Users\edo\Desktop>rd testdir
Directory is not empty

C:\Users\edo\Desktop>echo %errorlevel%
0

Почему? Что ты посоветуешь?


person etuardu    schedule 21.06.2012    source источник


Ответы (2)


Вау, это второй случай, когда я видел, что ERRORLEVEL не установлен должным образом! См. перенаправление файлов в Windows и %errorlevel%.

Решение такое же, как и при обнаружении сбоя перенаправления. Используйте оператор || для принятия мер в случае сбоя.

rd testdir || echo The command failed!

Странно то, что когда вы используете оператор ||, ERRORLEVEL затем правильно устанавливается на 145, если папка не пуста, или на 2, если папка не существует. Так что вам даже не нужно ничего делать. Вы можете условно «выполнить» замечание, и тогда уровень ошибки будет установлен правильно.

rd testdir || rem
echo %errorlevel%

Я думал, что вышеизложенное дало полную картину. Но затем серия комментариев ниже продемонстрировала, что при использовании /RD /S все еще существуют потенциальные проблемы. Если файл или подпапка в родительской папке заблокированы (на любом уровне родительской папки), то RD /S /Q PARENT && echo removed || echo failed выведет сообщение об ошибке, но сработает ветвь && вместо ветки ||. Очень жаль. Если команда не удалась из-за того, что сама родительская папка заблокирована, тогда || правильно сработает и установит ERRORLEVEL.

Во всех случаях можно обнаружить сбой, заменив stderr на stdout и передав результат в FINDSTR "^". Если совпадение найдено, значит, произошла ошибка.

3>&2 2>&1 1>&3 rd /s test | findstr "^" && echo FAILED

Обмен stderr и stdout важен, когда /q отсутствует, потому что он позволяет задать вопрос «Вы уверены (да/нет)?» подсказка для отображения на стандартном выводе отдельно от сообщения об ошибке на стандартном выходе.

person dbenham    schedule 21.06.2012
comment
Что ж, это просто сработало. Я предполагаю, что проблема связана с %errorlevel% и не имеет ничего общего с rd. Я думаю, что мне следует переписать обработку ошибок, используя эту структуру для более детерминированного поведения. Спасибо! - person etuardu; 21.06.2012
comment
Это отлично работает для кодов 2 и 145, но в случае Отказано в доступе или Процесс не может получить доступ к файлу, потому что он используется другим процессом, тогда он просто оставляет ERRORLEVEL без изменений. :( - person Andreas Vergison; 07.04.2015
comment
@AndreasVergison - Спасибо! Я обновил свой ответ вашей информацией. - person dbenham; 07.04.2015
comment
выручил меня! Спасибо... itados.blogspot.co.at/2015 /04/dos-error-levels.html - person Daniel Kienböck; 21.04.2015
comment
Я только что попробовал это на Windows 10. У меня та же проблема, что и у @AndreasVergison. Я не получаю уровень ошибки (или, точнее, я получаю OK), хотя мне не удается удалить, потому что файл используется другим процессом. Я получаю сообщение об ошибке в консоли, но оно не имеет ErrorLevel - person Mark; 14.03.2017
comment
@Mark - Хммм, я только что перепроверил на своем компьютере с Win 10, и решение || отлично работает для меня с ожидаемым ERRORLEVEL 32. Самый простой синтаксис для получения правильного результата - rd "yourFolder" || rem, а затем на следующей строке echo %errorlevel%. Но если этот код находится внутри блока в скобках, вы должны включить отложенное расширение и вместо этого использовать echo !errorlevel!. - person dbenham; 22.03.2017
comment
Это не работает с параметром /s для меня. Кто-нибудь может это подтвердить? - person Stefan; 27.06.2017
comment
@Stefan Я только что попробовал Windows 7, и это сработало для меня: (call ) & rd /s aaaa && echo. || rem Я получил как сообщение «Используется», так и правильно установленный уровень ошибок. Не могли бы вы уточнить, какой именно синтаксис не работает и какую ОС вы используете? - person Barniferous; 28.06.2017
comment
@Barniferous, это зависит от ошибки. Я могу подтвердить выводы @Stefan. То есть rd /q /s tmp && echo OK || echo ERROR !errorlevel! напечатает Процесс не может получить доступ к файлу, поскольку он используется другим процессом, а затем OK (уровень ошибки отсутствует). Однако о других ошибках, таких как ERROR 2 из сообщения dbenham, сообщается правильно. Воспроизведение: откройте командную строку и cd в каталог. В другой командной строке попробуйте удалить этот каталог с помощью решения dbenham. Уровень ошибки отсутствует, но ошибка печатается... :S. Проверено на Windows 7. - person Abel; 29.10.2017
comment
Условное выполнение || вообще не работает, если внутренняя папка заблокирована для доступа Access is denied. У RD просто есть 0 код выхода. - person it3xl; 16.09.2018
comment
Я думаю, что вышеупомянутый пример от @dbenham работал для случая отказа в доступе только потому, что это было нерекурсивное удаление. Это был отказ в доступе к самому каталогу нежелательной почты, а не к его внутренностям. Если отказ в доступе вызван каким-либо файлом внутри каталога, тогда ERRORLEVEL равен 0. Я думаю, это может быть из-за ошибочной функции из del (stackoverflow.com/questions/22953027/). Возможно, во время рекурсивного удаления Windows пытается использовать del для каждого файла внутри каталога и, к сожалению, всегда возвращает 0. - person Alexander Samoylov; 16.11.2018
comment
@AlexanderSamoylov - Отличный анализ. Я сделал еще несколько тестов, и вы абсолютно правы. Я обновлю свой ответ, когда у меня будет шанс. - person dbenham; 16.11.2018

rd не устанавливает errorlevel в ноль - он оставляет errorlevel нетронутым: f.e. если предыдущая операция заканчивается положительным errorlevel и rd завершается успешно, errorlevel остается без изменений. Пример: уровни ошибок robocopy ниже 4 являются предупреждениями, а не ошибками, и их можно игнорировать, поэтому следующий код может закончиться ошибкой, даже если каталог был успешно удален:

robocopy ...
if errorlevel 4 goto :error
rd somedir
if errorlevel 1 goto :error

Решение: проигнорируйте ошибку и проверьте, существует ли каталог после rd:

rd somedir
if exist somedir goto :error
person rychu    schedule 10.04.2015
comment
Также о robocopy: не забудьте не сбросить уровень ошибки с помощью set errorlevel=0 после того, как вы проверите, что он не ›= 4, потому что эта команда создает переменную среды, которая навсегда перезаписывает внутренний уровень ошибки. Прочитайте здесь - person rychu; 10.04.2015
comment
Это лучшее решение ИМО. Вместо того, чтобы пытаться делать запутанные обходные пути, обмениваться выводами и прочей ерундой, пытаясь обнаружить все странные случаи... просто посмотрите, существует ли еще каталог; если это так, у вас была проблема. - person Doktor J; 31.05.2019