Пакетный файл и 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

Эти знаки процента являются подсказкой для проверки переменных среды.

Другие вопросы по тегам