Пакетный файл и DEL ошибка уровня 0 выпуск
Пакет должен удалить файлы и каталоги из определенных мест и вывести сообщения об успехе или stdout/stderr в новый файл.txt. Я создал большую часть сценария, и он работает точно так, как должен, за исключением того, что при успешном удалении он переходит к следующей строке, а не выводит "успешное" сообщение в журнал.
echo Basic Deletion Batch Script > results.txt
@echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 0 echo succesful
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
По какой-то причине я не могу найти синтаксис, если del успешно завершается эхо "успешно". В приведенном выше примере, если я удаляю строку
if errorlevel 0 echo successful
Все работает нормально, но сообщения об успехе нет. С этой строкой, оставленной в ней, повторяется успех для каждой строки.
7 ответов
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
если появляется пустая строка и 1
иначе:
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 =)
При использовании этого синтаксиса вместо этого
if errorlevel 0 echo successful
Вы можете использовать это - потому что errorlevel 0 всегда true.
if not errorlevel 1 echo successful
Просто используйте команду "rm" из инструментов UnxUtils (или gow) для окон. Он правильно устанавливает уровень ошибки в случае каких-либо ошибок при удалении файла.
Код:
Код ошибки: (Что вы сделали)
if errorlevel 0 echo succesful
Проблема здесь в том, что вы не вызываете errorlevel как переменную и, кроме того, не добавляете оператор в оператор.
Правильный код: (Вот каким он должен быть на самом деле.)
if %ERRORLEVEL% EQU 0 echo succesful
Определения:
EQU: EQU означает равный. Этот вид оператора также называется оператором отношения. Вот ссылка на документацию по операторам, если вы хотите узнать больше, есть и другие, но это мне помогло.
ERRORLEVEL: объявляется как переменная и обычно получает уровень ошибки последней выполненной команды. Переменные обычно вызываются, когда они находятся между такими знаками процента
%foo%
Для получения дополнительной справки по переменным перейдите в cmd (к которому вы можете перейти, выполнив поиск в Windows 10) и введите "set /?" Без кавычек. команда set - это команда, которую вы используете для установки переменных
Это было добавлено в качестве правки исходным запросчиком, я преобразовал его в ответ сообщества вики, потому что это должен быть ответ, а не правка.
Я узнал, как это сделать... в любом случае.
echo Startup > results.txt
@echo off
call :filelog >> results.txt 2>&1
notepad results.txt
exit /b
:filelog
call :delete new.txt
call :delete newer.txt
call :delete newest.txt
call :remove c:\NoSuchDirectory
GOTO :EOF
:delete
echo deleting %1
dir c:\users\newuser\Desktop\%1 >NUL 2>&1
SET existed=%ERRORLEVEL%
del /f /q c:\Users\newuser\Desktop\%1
dir c:\users\newuser\Desktop\%1 2>NUL >NUL
if %existed% == 0 (if %ERRORLEVEL% == 1 echo "successful" )
GOTO :EOF
:remove
echo deleting directory %1
rmdir /q /s %1
GOTO :EOF
IF ERRORLEVEL 0 [cmd] будет выполняться каждый раз, потому что IF ERRORLEVEL # проверяет, является ли значение ERRORLEVEL больше или равно #. Поэтому каждый код ошибки будет вызывать выполнение [cmd].
Отличная ссылка для этого: http://www.robvanderwoude.com/errorlevel.php
>IF /?
Performs conditional processing in batch programs.
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT Specifies that Windows should carry out
the command only if the condition is false.
ERRORLEVEL number Specifies a true condition if the last program run
returned an exit code equal to or greater than the number
specified.
Я бы порекомендовал изменить ваш код так:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 1 (
rem This block executes if ERRORLEVEL is a non-zero
echo failed
) else (
echo succesful
)
GOTO :EOF
Если вам нужно что-то, что обрабатывает более одного ERRORLEVEL, вы можете сделать что-то вроде этого:
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
if errorlevel 3 echo Cannot find path& GOTO :delete_errorcheck_done
if errorlevel 2 echo Cannot find file& GOTO :delete_errorcheck_done
if errorlevel 1 echo Unknown error& GOTO :delete_errorcheck_done
echo succesful
:delete_errorcheck_done
GOTO :EOF
ИЛИ ЖЕ
:delete
echo deleting %1
del /f /q c:\Users\newuser\Desktop\%1
goto :delete_error%ERRORLEVEL% || goto :delete_errorOTHER
:delete_errorOTHER
echo Unknown error: %ERRORLEVEL%
GOTO :delete_errorcheck_done
:delete_error3
echo Cannot find path
GOTO :delete_errorcheck_done
:delete_error2
echo Cannot find file
GOTO :delete_errorcheck_done
:delete_error0
echo succesful
:delete_errorcheck_done
GOTO :EOF
Ответ aschipfl великолепен (спасибо, мне очень помог!), Используя код в Presetting ErrorLevel, вы получаете хорошую стандартную функцию:
Будьте осторожны, чтобы использовать %~1
вместо %1
в del
заявление, или вы получите ошибки, если вы используете цитируемое имя файла.
::######################################################################
::call :DELETE "file.txt"
::call :DELETE "file.txt" "error message"
:DELETE
>nul ver && for /F "tokens=*" %%# in ('del /F /Q "%~1" 2^>^&1 1^> nul') do (2>nul set =) || (
if NOT .%2==. echo %~2
)
goto :EOF
КСТАТИ 1: Вы можете дать изящное сообщение об ошибке в качестве второго параметра
КСТАТИ 2: Использование ::
вместо REM
для комментариев делает код еще более читабельным.
Насколько я помню, правильный синтаксис:
if %errorlevel% == 0 echo succesful
Эти знаки процента являются подсказкой для проверки переменных среды.