Могу ли я иметь блок IF в командном файле DOS?

97

В пакетном файле DOS у нас может быть только 1 строка тела оператора if? Я думаю, что нашел где-то, что можно было бы использовать ()для блока if точно так же, как {}в C-подобных языках программирования, но он не выполняет инструкции, когда я пытаюсь это сделать. Сообщения об ошибке тоже нет. Это мой код:

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

Как ни странно, ни «GP Manager is up», ни «GP Manager is down» не печатаются, когда я запускаю командный файл.

Хью Дарлинг
источник
Возможно, это может помочь: commandwindows.com/batchfiles-branching.htm
esaj
Да, это помогает. DOS - отстой. Если я хочу использовать несколько операторов в if или иначе, я должен использовать && между операторами? или есть способ более элегантный?
Хью Дарлинг,

Ответы:

141

Вы действительно можете создать блок операторов для выполнения после условного. Но у вас неправильный синтаксис. Скобки необходимо использовать точно так, как показано:

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частью командного процессора. Раймонд Чен прекрасно объясняет это здесь, в этом блоге .
Коди Грей
Можно ли получить ELSE IF?
xagyg
1
Добавляя к комментарию @mithofechelon, даже кажущаяся безобидной закрывающая скобка в операторе REM завершит блок. например, бросок REM This is a comment (or so I thought)в IFблок вас испортит.
rkagerer 09
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
Использование отложенного расширения должно работать: используйте:set var3=!var1!_!var2!
Dracorat
4

Вместо этого беспорядка goto попробуйте использовать амперсанд & или двойной амперсанд && (условно для уровня ошибки 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
Винниджонсон
источник