ЕСЛИ ... ИЛИ ЕСЛИ ... в командном файле Windows - PullRequest
76 голосов
/ 09 декабря 2011

Есть ли способ написать условный оператор IF ИЛИ IF в пакетном файле Windows?

Например:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE

Ответы [ 13 ]

84 голосов
/ 09 декабря 2011

Решение zmbq хорошо, но его нельзя использовать во всех ситуациях, например, внутри блока кода, такого как цикл FOR DO (...).

Альтернативой является использование индикаторной переменной.Инициализируйте его как неопределенное, а затем определяйте его, только если выполняется одно из условий ИЛИ.Затем используйте IF DEFINED в качестве финального теста - нет необходимости использовать отложенное расширение.

FOR ..... DO (
  set "TRUE="
  IF cond1 set TRUE=1
  IF cond2 set TRUE=1
  IF defined TRUE (
    ...
  ) else (
    ...
  )
)

Вы можете добавить логику ELSE IF, которую использует arasmussen, на том основании, что она может выполнить крошечное быстрее, если выполнено 1-е условиеэто правда, но я никогда не беспокоюсь.

Приложение - Это дублирующий вопрос с почти идентичными ответами на Использование ИЛИ в операторе IF WinXP BatchСценарий

Заключительное приложение - Я почти забыл свой любимый метод проверки, является ли переменная одним из списка значений.Инициализируйте тестовую переменную, содержащую список допустимых значений с разделителями, а затем используйте поиск и замену, чтобы проверить, находится ли ваша переменная в списке.Это очень быстро и использует минимальный код для произвольно длинного списка.Требуется отложенное расширение (или трюк CALL %% VAR %%).Кроме того, тест НЕ УКАЗАН.

set "TEST=;val1;val2;val3;val4;val5;"
if "!TEST:;%VAR%;=!" neq "!TEST!" (echo true) else (echo false)

Выше может произойти сбой, если VAR содержит =, поэтому тест не защищен от ошибок.

Если выполняется тест в блоке, гдеотложенное расширение необходимо для доступа к текущему значению VAR, тогда

for ... do (
  set "TEST=;val1;val2;val3;val4;val5;"
  for /f %%A in (";!VAR!;") do if "!TEST:%%A=!" neq "!TEST!" (echo true) else (echo false)
)

FOR могут потребоваться такие параметры, как "delims =", в зависимости от ожидаемых значений в VAR

. Приведенную выше стратегию можно сделать надежной дажес = в VAR, добавив немного больше кода.

set "TEST=;val1;val2;val3;val4;val5;"
if "!TEST:;%VAR%;=!" neq "!TEST!" if "!TEST:;%VAR%;=;%VAR%;"=="!TEST!" echo true

Но теперь мы потеряли возможность предоставлять предложение ELSE, если мы не добавим переменную-индикатор.Код начал выглядеть немного «некрасиво», но я думаю, что это самый эффективный и надежный метод для тестирования, если VAR является любым из произвольного числа вариантов без учета регистра.

Наконец, есть более простойВерсия, которую я считаю, немного медленнее, потому что она должна выполнять один IF для каждого значения.Aacini предоставил это решение в комментарии к принятому ответу в вышеупомянутой ссылке

for %%A in ("val1" "val2" "val3" "val4" "val5") do if "%VAR%"==%%A do echo true

Список значений не может включать * или?символы, а значения и %VAR% не должны содержать кавычек.Кавычки приводят к проблемам, если %VAR% также содержит пробелы или специальные символы, такие как ^, & и т. Д. Еще одно ограничение этого решения состоит в том, что он не предоставляет опцию для предложения ELSE, если вы не добавите переменную-индикатор.Преимущества в том, что он может быть чувствительным к регистру или нечувствительным в зависимости от наличия или отсутствия опции IF /I.

45 голосов
/ 09 декабря 2011

Я так не думаю. Просто используйте два IF и GOTO одного ярлыка:

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end
6 голосов
/ 25 июня 2014

Спасибо за этот пост, он мне очень помог.

Не знаю, может ли это помочь, но у меня возникла проблема, и благодаря вам я нашел, как мне кажется, еще один способ ее решения на основе этой логической эквивалентности:

«А или В» - это то же самое, что «не (не А и не В)»

Таким образом:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE

Становится:

IF not [%var%] == [1] IF not [%var%] == [2] ECHO FALSE
5 голосов
/ 10 апреля 2014

Даже если этот вопрос немного старше:

Если вы хотите использовать if cond1 or cond 2 - вы не должны использовать сложные циклы или тому подобное.

Простые предоставляют оба ifs друг за другом в сочетании с goto - это неявное или.

//thats an implicit IF cond1 OR cond2 OR cond3
if cond1 GOTO doit
if cond2 GOTO doit
if cond3 GOTO doit

//thats our else.
GOTO end

:doit
  echo "doing it"

:end

Без перехода, кроме действия «на месте», вы можете выполнить действие 3 раза, если ВСЕ условия совпадают.

2 голосов
/ 22 июля 2018

Простое «FOR» может использоваться в одной строке для использования условия «или»:

FOR %%a in (item1 item2 ...) DO IF {condition_involving_%%a} {execute_command}  

Применительно к вашему случаю:

FOR %%a in (1 2) DO IF %var%==%%a ECHO TRUE
2 голосов
/ 12 сентября 2014

Цель может быть достигнута косвенным использованием IF.

Ниже приведен пример сложного выражения, которое может быть написано достаточно кратко и логически в пакете CMD, без несвязных меток и GOTO.

Блоки кода между () скобками обрабатываются CMD как (жалкий) вид подоболочки. Независимо от того, какой код выхода выходит из блока, будет использоваться для определения истинного / ложного значения, которое блок воспроизводит в большем логическом выражении. С помощью этих блоков кода можно построить произвольно большие логические выражения.

Простой пример

Каждый блок разрешается в true (т.е. ERRORLEVEL = 0 после выполнения последнего оператора в блоке) / false, пока не будет определено значение всего выражения или пока не выпадет управление (например, через GOTO):

 ((DIR c:\xsgdde /w) || (DIR c:\ /w)) && (ECHO -=BINGO=-)

Сложный пример

Это решает проблему, поднятую изначально. В каждом блоке возможно несколько операторов, но в || || || Выражение предпочтительнее, чтобы быть кратким, чтобы он был максимально читабельным. ^ является escape-символом в пакетах CMD, и, будучи помещенным в конец строки, он покинет EOL и даст CMD команду продолжить чтение текущего пакета операторов на следующей строке.

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION

(
    (CALL :ProcedureType1 a b) ^
        || (CALL :ProcedureType2 sgd) ^
            || (CALL :ProcedureType1 c c)
) ^
    && (
        ECHO -=BINGO=-
        GOTO :EOF
    )
ECHO -=no bingo for you=-
GOTO :EOF

:ProcedureType1
    IF "%~1" == "%~2" (EXIT /B 0) ELSE (EXIT /B 1)
GOTO :EOF (this line is decorative as it's never reached)

:ProcedureType2
    ECHO :ax:xa:xx:aa:|FINDSTR /I /L /C:":%~1:">nul
GOTO :EOF
2 голосов
/ 09 декабря 2011

В пакетном режиме IF <arg> OR или ELIF или ELSE IF нет, однако ...

Попробуйте вложить другие IF внутри ELSE предыдущего IF.

1 голос
/ 12 августа 2014

Я понимаю, что этот вопрос старый, но я хотел опубликовать альтернативное решение на тот случай, если кто-то еще (например, я) найдет эту ветку, имея тот же вопрос.Мне удалось обойти отсутствие оператора OR, повторив переменную и используя findstr для проверки.

for /f %%v in ('echo %var% ^| findstr /x /c:"1" /c:"2"') do (
    if %errorlevel% equ 0 echo true
)
1 голос
/ 20 июля 2014
If %x%==1 (
If %y%==1 (
:: both are equal to 1.
)
)

Это для проверки, равны ли значения нескольких переменных. Вот для любой переменной.

If %x%==1 (
:: true
)
If %x%==0 (
If %y%==1 (
:: true
)
)
If %x%==0 (
If %y%==0 (
:: False
)
)

Я просто подумал об этом с головы до головы. Я мог бы сжать это больше.

1 голос
/ 29 апреля 2013

Можно использовать функцию, которая оценивает логику ИЛИ и возвращает одно значение.

@echo off
set var1=3
set var2=5
call :logic_or orResult "'%var1%'=='4'" "'%var2%'=='5'"
if %orResult%==1 ( 
    echo At least one expression is true
) ELSE echo All expressions are false
exit /b

:logic_or <resultVar> expression1 [[expr2] ... expr-n] 
SETLOCAL
set "logic_or.result=0"
set "logic_or.resultVar=%~1"

:logic_or_loop 
if "%~2"=="" goto :logic_or_end 
if %~2 set "logic_or.result=1"
SHIFT 
goto :logic_or_loop 

:logic_or_end 
( 
  ENDLOCAL 
  set "%logic_or.resultVar%=%logic_or.result%"
  exit /b
) 
...