Чи можу я отримати блок IF у пакетному файлі DOS?


97

У командному файлі DOS ми можемо мати лише 1 рядок, якщо тіло оператора? Думаю, я десь знайшов, що міг би використовувати ()для блоку if, як і {}в мовах програмування, подібних на C, але він не виконує оператори, коли я намагаюся це зробити. Повідомлення про помилку також відсутнє. Це мій код:

if %GPMANAGER_FOUND%==true(echo GP Manager is up
goto Continue7
)
echo GP Manager is down
:Continue7

Як не дивно, ні "GP Manager не працює", ні "GP Manager не працює", коли я запускаю пакетний файл, не надрукується.


Можливо, це може допомогти: commandwindows.com/batchfiles-branching.htm
esaj

Так, це допомагає. DOS відстій. Якщо я хочу використовувати декілька висловлювань, якщо чи інше, я повинен використовувати && між висловлюваннями? чи є більш елегантний спосіб?
Х'ю Дарлінг

Відповіді:


140

Ви дійсно можете помістити створення блоку операторів для виконання після умовного. Але у вас неправильний синтаксис. Дужки слід використовувати точно так, як показано:

if <statement> (
    do something
) else (
    do something else
)

Однак я не вірю, що існує якийсь вбудований синтаксис для else-ifтверджень. На жаль, вам доведеться створити вкладені блоки ifоператорів, щоб це обробити.


По-друге, цей %GPMANAGER_FOUND% == trueтест здається мені надзвичайно підозрілим. Я не знаю, для чого встановлена ​​змінна середовища і як ви її встановлюєте, але я дуже сумніваюся, що код, який ви показали, дасть результат, який ви шукаєте.


Наступний зразок коду добре працює для мене:

@echo off

if ERRORLEVEL == 0 (
    echo GP Manager is up
    goto Continue7
)
echo GP Manager is down
:Continue7

Зверніть увагу на кілька конкретних деталей про мій зразок коду:

  • Пробіл, доданий між кінцем умовного оператора та початковою дужкою.
  • Я налаштований, @echo offщоб не бачити всіх виразів, надрукованих на консолі, під час їх виконання, а натомість просто бачити результати тих, які конкретно починаються з echo.
  • Я використовую вбудовану ERRORLEVELзмінну просто як тест. Детальніше читайте тут

1
Краще використовувати, якщо% ERRORLEVEL% == 0, оскільки інший варіант завжди є істинним, оскільки, якщо ERRORLEVEL <N> відповідає істині, якщо рівень помилки дорівнює або більший <N>, "==" у цьому випадку ігнорується
jeb

@jeb: Я думаю, ви могли пропустити суть. Використання ERRORLEVEL- це не відповідь на його проблему. Я просто публікував приклад правильного синтаксису. У цьому випадку прийнятна будь-яка форма, як if 0 == 0і будь-який інший тривіальний вираз. Але справді, переконайтеся, що ви розумієте різницю між змінною середовища %ERRORLEVEL%та внутрішньою ERRORLEVELчастиною командного процесора. Раймонд Чен прекрасно це пояснює тут, у цьому блозі .
Коді Грей

Чи можете ви отримати ІНШЕ ЯКЩО?
xagyg

1
Додаючи коментар @ mythofechelon, навіть, здавалося б, нешкідлива закриваюча дужка в операторі REM закінчить блок. наприклад, кидання REM This is a comment (or so I thought)в IFблок заплутує вас.
rkagerer

2
Як @mythofechelon, так і @rkagerer вказують на конкретні проблеми загального правила, згідно з яким рядки потрібно цитувати. Ви ніколи не повинні кодувати, IF %somevar%==example_string2 це завжди повинен бути код, тому операнд вирішує IF "value_of_somevar"=="example_string2", щоб уникнути спеціальних символів у будь-якому рядковому операнді, що спричиняє синтаксичні помилки в IFоператорі. Значення, які ви встановлюєте, слід завжди робити, оскільки set "somevar=value_of_somevar" Цей синтаксис дозволяє вам уникати спеціальних символів у значеннях змінних, Примітка що я не маю на увазі set somevar="value_of_somevar"
Skip R

15

Логічно, що відповідь Коді повинна спрацювати. Однак я не думаю, що командний рядок обробляє блок коду логічно. За своє життя я не можу змусити це працювати належним чином за допомогою жодної команди в блоці. У моєму випадку розширене тестування показало, що всі команди всередині блоку кешуються і виконуються одночасно в кінці блоку. Звичайно, це не дає очікуваних результатів. Ось спрощений приклад:

if %ERRORLEVEL%==0 (
set var1=blue
set var2=cheese
set var3=%var1%_%var2%
)

Це має надати var3 таке значення:

blue_cheese

але натомість дає:

_

оскільки всі 3 команди кешуються та виконуються одночасно після виходу з кодового блоку.

Я зміг подолати цю проблему, переписавши блок if, щоб виконати лише одну команду - goto - і додавши кілька міток. Це незграбно, і мені це не дуже подобається, але принаймні це працює.

if %ERRORLEVEL%==0 goto :error0
goto :endif

:error0
set var1=blue
set var2=cheese
set var3=%var1%_%var2%

:endif

8
Використання відкладеного розширення повинно спрацювати: use:set var3=!var1!_!var2!
Dracorat

4

Замість цього goto mess, спробуйте використовувати амперсанд & або подвійний амперсанд && (умовно до рівня помилок 0) як роздільники команд.

Я виправив фрагмент сценарію цим трюком, підсумовуючи, у мене є три пакетні файли, один з яких викликає два інших після того, як знайшов, які літери призначені зовнішнім накопичувачам. Я залишаю перший файл на первинному зовнішньому диску, тому дзвінки до його процедури резервного копіювання працювали нормально, але дзвінки до другого вимагали активної зміни диска. У наведеному нижче коді показано, як я це виправив:

for %%b in (d e f g h i j k l m n o p q r s t u v w x y z) DO (
if exist "%%b:\Backup.cmd" %%b: & CALL "%%b:\Backup.cmd"
)

Чому це за голос проти? Це саме те, що мені потрібно було.
ggb667

1
@ GCB667 - Для роз'яснення @Louis "написав" відповідь ", яка не стосується проблеми, чому твердження IF не працює для оригінального плаката. Це стосується відповіді" vinniejohnson "(яка також пропустила проблему оригінальних плакатів) .
Пропустити R

1

Я натрапив на цю статтю в результатах пошуку, пов’язаних із командою IF у пакетному файлі, і я не зміг встояти перед можливістю виправити хибну думку, що блоки IF обмежуються одними командами. Далі йде частина виробничого сценарію команди Windows NT, що працює щодня на машині, на якій я складаю цю відповідь.

    if "%COPYTOOL%" equ "R" (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using RoboCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    %TOOLPATH% %SRCEPATH% %DESTPATH% /copyall %RCLOGSTR% /m /np /r:0 /tee
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Robocopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
) else (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using XCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    call %TOOLPATH%  "%USERPROFILE%\My Documents\Outlook Files\*" "%USERPROFILE%\My Documents\Outlook Files\_backups" /f /m /v /y
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Xcopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
)

Можливо, блоки з двох або більше рядків стосуються виключно сценаріїв команд Windows NT (файли .CMD), оскільки пошук у каталозі виробничих скриптів програми, обмеженої файлами старої школи (.BAT), виявив лише блоки з однією командою . Оскільки додаток перейшло на тривале технічне обслуговування (це означає, що я не беру участь у його підтримці), я не можу сказати, чи це тому, що мені не потрібно було більше одного рядка, чи що я не міг змусити їх працювати.

Незалежно від того, якщо останнє відповідає дійсності, існує просте обхідне рішення; перемістити кілька рядків або в окремий пакетний файл, або в підпрограму пакетного файлу. Я знаю, що останній працює в обох видах сценаріїв.


0

Можливо, трохи пізно, але сподіваюся, що це пекло:

@echo off 

if %ERRORLEVEL% == 0 (
msg * 1st line WORKS FINE rem You can relpace msg * with any othe operation...
goto Continue1
)
:Continue1
If exist "C:\Python31" (
msg * 2nd line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue2
)
:Continue2
If exist "C:\Python31\Lib\site-packages\PyQt4" (  
msg * 3th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue3
)
:Continue3
msg * 4th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue4
)
:Continue4
msg * "Tutto a posto" rem You can relpace msg * with any othe operation...
pause
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.