IF… 또는 IF… Windows 배치 파일에서


97

Windows 배치 파일에 IF OR IF 조건문을 작성하는 방법이 있습니까?

예를 들면 :

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

7
아니요. 가능한 것은 AND :를 직접 작성하는 것 IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE입니다. 나는 정의 SET AND=IF하고 다음과 같이 작성했습니다 IF cond1 %AND% cond2 ECHO BOTH ARE TRUE.
Aacini 2011

답변:


95

zmbq 솔루션은 좋지만 FOR DO (...) 루프와 같은 코드 블록 내부와 같은 모든 상황에서 사용할 수는 없습니다.

대안은 인디케이터 변수를 사용하는 것입니다. 정의되지 않도록 초기화 한 다음 OR 조건 중 하나가 참인 경우에만 정의하십시오. 그런 다음 IF DEFINED를 최종 테스트로 사용합니다. 지연된 확장을 사용할 필요가 없습니다.

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

arasmussen이 첫 번째 조건이 참이면 조금 더 빨리 수행 할 수 있다는 이유로 사용하는 ELSE IF 논리를 추가 할 수 있지만, 저는 결코 신경 쓰지 않습니다.

부록 -IF 문에서 OR 사용 WinXP 배치 스크립트 와 거의 동일한 답변이있는 중복 질문입니다.

최종 부록 -변수가 대소 문자를 구분하지 않는 값 목록 중 하나인지 테스트하는 데 가장 좋아하는 기술을 거의 잊었습니다. 구분 된 허용 값 목록을 포함하는 테스트 변수를 초기화 한 다음 검색 및 바꾸기를 사용하여 변수가 목록 내에 있는지 테스트합니다. 이것은 매우 빠르고 임의로 긴 목록에 최소한의 코드를 사용합니다. 지연된 확장이 필요합니다 (또는 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)
)

VAR 내의 예상 값에 따라 "delims ="와 같은 FOR 옵션이 필요할 수 있습니다.

위의 전략은 =코드를 조금 더 추가하여 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 echo true

값 목록에는 * 또는? 문자 및 값과 %VAR%따옴표를 포함해서는 안됩니다. (가) 경우 따옴표 문제가 발생할 %VAR%또한 공백이나 같은 특수 문자가 포함되어 ^, &이 솔루션은 표시기 변수를 추가하지 않는 한이 ELSE 절에 대한 옵션을 제공하지 않습니다이다와 등 또 다른 한계를. 장점은 IF /I옵션의 유무에 따라 대소 문자를 구분하거나 구분하지 않을 수 있다는 것입니다.


불행히도 파일 일치 의미 체계로 인해 FOR %% A IN (-? -h -help)과 같은 물음표가 포함 된 값에는은 작동하지 않습니다.
Killroy

@Killroy-예, 나는 이미 대답에서 그 제한을 지적했습니다. 그러나 귀하의 의견은 대답을보고 FOR 솔루션에 추가 제한 사항이 있음을 깨닫도록 강요했습니다. 답변의 끝 부분을 약간 업데이트했습니다.
dbenham 2013

findstr에 대한 에코가 옵션이 아닐까요?
Squashman

@Squashman-네, 모든 FINDSTR 버그와 단점을 탐색하고 싶다면.
dbenham

대답은 틀 렸습니다. Aacini에 귀속 된 명령은 인용 된대로 실패하지만 다음과 같이 편집하면 작동합니다. ( "val1" "val2" "val3")의 %% A에 대해 "% VAR %"== %% A echo true
Ed999

54

나는 그렇게 생각하지 않는다. 두 개의 IF 및 GOTO를 동일한 레이블로 사용하십시오.

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end

네, 제가 말할 수있는 한 그 두 가지가 유일한 옵션입니다.
Mechaflash 2011

1
= D 저는 실제로 powershell을 배우고 모든 스크립트를 수정하는 과정에 있습니다. 그러나 배치 스크립트에 대한 작은 버그 수정을 수행하고 이것이 가능한지 알고 싶었습니다. 나는 클린 코드 롤에 관해서 까다
롭습니다

1
ELSE 절이 필요하지 않은 경우에만 작동하지만 많은 상황에서 CALL이 GOTO보다 선호 될 수 있습니다.
Harry Johnston 2011

@HarryJohnston은 그것이 단지 하향식 프로그램 / 스크립트인지 아니면 마치 함수가 배치 스크립팅 = /에 존재하는 것처럼 실행되도록 구조화되었는지에 달려 있습니다. 그의 예에서 GOTO는 정확하거나 그렇지 않으면 ECHO Didn't find it발견하더라도 타격을 입을 것입니다.
Mechaflash 2011

박쥐가 or 연산자를 지원하게하는 것이 얼마나 어렵습니까? 그것은 2019 년에 구현되지 않았습니다
농담 황을

8

이 게시물에 감사드립니다. 많은 도움이되었습니다.

도움이 될 수 있다면 Dunno는 문제가 있었으며 덕분 에이 부울 등가를 기반으로 해결하는 또 다른 방법이라고 생각하는 것을 발견했습니다.

"A 또는 B"는 "not (A 아님 B 아님)"과 동일합니다.

그러므로:

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

된다 :

IF not [%var%] == [1] IF not [%var%] == [2] ECHO FALSE

그러나 이는 둘 다 사실이 아닌 경우에만 FALSE (ELSE) 분기를 제공합니다. OP는 둘 중 하나가 참이면 TRUE 분기를 원합니다.
dbenham 2014-06-30

8

간단한 "FOR"을 한 줄에 사용하여 "or"조건을 사용할 수 있습니다.

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

귀하의 사례에 적용 :

FOR %%a in (1 2) DO IF %var%==%%a ECHO TRUE

나는 이것이 내 배치 스크립트에서 가장 간단하고 사용하기 쉬운 사례라는 것을 알았습니다. 왜 이것이 권장 답변이되지 않았습니까?
myusrn

감사. 잘 모르겠습니다. 일반적으로 upvoting은 stackoverflow뿐만 아니라 다른 포럼에서도 매우 이상한 프로세스 (그리고 모호한가요?)입니다. 하지만이 경우에는 타이밍이라고 생각합니다. 질문은 꽤 오래되었고 내 대답은 최근에 있습니다. 어쨌든 우리는 효과가 있는 답을 찾을 수있을 때 행복해야 합니다. :)
Apostolos

한 가지 가능한 이 기술의 단점 (등 I 있지만 아웃 오브 boxness 접근 방식의은!)이다 상태에 따라 ,이 원되지 않을 수있는, 두 번 명령을 실행하는 것이 가능합니다.
TripeHound

이론적으로는 그렇습니다. 하지만 저는 수백 개의 배치 파일을 만들었고 매일 수십 개의 파일을 사용하며 그러한 경우를 만나 본 적이 없습니다. 그러니 계속 연습합시다! :)
Apostolos

6

이 질문이 조금 더 오래된 경우에도 :

사용하고 싶다면 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

goto없이 "inplace"작업이 없으면 모든 조건이 일치하면 작업을 3 번 실행할 수 있습니다.


이 답변은 이미 제공되었습니다. musst가 그것을 감독했습니다.
dognose 2014.04.11

2

더 없다 IF <arg> OR거나 ELIF또는 ELSE IF그러나, 배치에 ...

이전 IF의 ELSE 안에 다른 IF를 중첩 해보십시오.

IF <arg> (
    ....
) ELSE (
    IF <arg> (
        ......
    ) ELSE (
        IF <arg> (
            ....
        ) ELSE (
    )
)

3
실행될 조건부 코드가 각 ELSE IF에 대해 복제되어야하므로 OR의 좋은 구현이 아닙니다. (물론 조건부 코드가 GOTO가 아니라면 zmbq의 해법이 더 장황한 경우입니다.)
dbenham

2

OR 논리를 평가하고 단일 값을 반환하는 함수를 사용할 수 있습니다.

@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
) 

+1,이 함수는 ERRORLEVEL 리턴 코드에서 결과를 리턴하기에 좋은 후보입니다. 그러면 호출은 && ... || ...추가 IF ... ELSE ...문 대신 편리한 구문을 직접 사용할 수 있습니다 .
dbenham 2014 년

2

IF를 간접적으로 사용하여 목표를 달성 할 수 있습니다.

다음은 일관성없는 레이블 및 GOTO없이 CMD 배치에서 매우 간결하고 논리적으로 작성할 수있는 복잡한 표현식의 예입니다.

() 괄호 사이의 코드 블록은 CMD에서 (심각한) 종류의 서브 쉘로 처리됩니다. 블록에서 나오는 모든 종료 코드는 더 큰 부울 표현식에서 블록이 재생하는 참 / 거짓 값을 결정하는 데 사용됩니다. 이러한 코드 블록을 사용하여 임의로 큰 부울 식을 작성할 수 있습니다.

간단한 예

각 블록은 전체 표현식의 값이 결정되거나 제어가 점프 할 때까지 (예 : GOTO를 통해) true (예 : 블록의 마지막 문이 실행 된 후 ERRORLEVEL = 0) / false로 확인됩니다.

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

복잡한 예

이것은 처음에 제기 된 문제를 해결합니다. 각 블록에서 여러 문장이 가능하지만 || || || 가능한 한 읽을 수 있도록 간결하게하는 것이 좋습니다. ^는 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

1
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

나는이 질문이 오래되었다는 것을 알고 있지만 다른 사람 (나와 같은)이 같은 질문을 하면서이 스레드를 찾은 경우를 대비하여 대체 솔루션을 게시하고 싶었습니다. 변수를 에코하고 findstr을 사용하여 유효성을 검사함으로써 OR 연산자가없는 문제를 해결할 수있었습니다.

for /f %%v in ('echo %var% ^| findstr /x /c:"1" /c:"2"') do (
    if %errorlevel% equ 0 echo true
)

1

dbenham의 대답은 꽤 좋지만 IF DEFINED확인하는 변수가 환경 변수 가 아닌 경우 의존 하면 많은 문제가 발생할 수 있습니다 . 스크립트 변수는이 특별한 취급을받지 않습니다.

이것은 우스꽝스럽고 문서화되지 않은 BS처럼 보일 수 있지만 간단한 쉘 쿼리를 수행하면 다음 IF과 같은 IF /?사실이 드러납니다.

DEFINED 조건은 환경 변수 이름을 취하고 환경 변수가 정의 된 경우 true를 반환 한다는 점을 제외하면 EXIST와 동일하게 작동합니다 .

이 질문에 대한 답변과 관련하여 일련의 평가 후에 단순한 플래그를 사용하지 않는 이유가 있습니까? 그것은 OR기본 논리와 가독성 측면에서 나에게 가장 유연한 검사 처럼 보입니다 . 예를 들면 :

Set Evaluated_True=false

IF %condition_1%==true (Set Evaluated_True=true)
IF %some_string%=="desired result" (Set Evaluated_True=true)
IF %set_numerical_variable% EQ %desired_numerical_value% (Set Evaluated_True=true)

IF %Evaluated_True%==true (echo This is where you do your passing logic) ELSE (echo This is where you do your failing logic)

분명히 그들은 어떤 종류의 조건부 평가가 될 수 있지만 몇 가지 예를 공유하고 있습니다.

모든 것을 한 줄에 서면으로 작성하고 &&싶다면 다음 과 같이 연결하면됩니다 .

Set Evaluated_True=false

IF %condition_1%==true (Set Evaluated_True=true) && IF %some_string%=="desired result" (Set Evaluated_True=true) && IF %set_numerical_variable% EQ %desired_numerical_value% (Set Evaluated_True=true)

IF %Evaluated_True%==true (echo This is where you do your passing logic) ELSE (echo This is where you do your failing logic)

0

일하기 위해 존재하지 않았습니다.

존재하지 않는 경우 g : xyz / what goto h를 사용합니다. Else xcopy c : current / files g : bu / current 수정 자 / a 등이 있습니다. 어떤 것이 있는지 확실하지 않습니다. 상점에서 노트북. 그리고 사무실의 컴퓨터. 나는 거기에 없다.

Windows XP 이상에서 작동 할 배치 파일이 없습니다.


"if not exist g : xyz / what"의 예에서와 같이 xyz / what은 g의 루트 폴더가 아닌 g : 드라이브의 현재 디렉토리에 상대적입니다. 여기에 "g : \ xyz \ what"이 필요합니까? c : current / files 및 g : bu / current와 동일합니다. 각 드라이브에는 다른 현재 폴더가 있으며 해당 드라이브가 현재 작업 디렉터리가 아닌 경우에도 "기억"됩니다.
John Elion

0

내가 일반적으로 사용하는 훨씬 빠른 대안은 다음과 같습니다. 가변 공간에 들어갈 수있는 임의의 수의 조건을 "또는"

@(
  Echo off
  Set "_Match= 1 2 3 "
)

Set /a "var=3"

Echo:%_Match%|Find " %var% ">nul || (
  REM Code for a false condition goes here
) && (
  REM code for a true condition goes here.
)

-3

이것이 약간 오래된 질문이라는 것을 깨달은 응답은 배치 파일에 대한 명령 줄 인수를 테스트하는 솔루션을 찾는 데 도움이되었습니다. 그래서 다른 사람이 비슷한 솔루션을 찾고있는 경우를 대비하여 내 솔루션도 게시하고 싶었습니다.

가장 먼저 지적해야 할 점은 FOR ... DO 절 내에서 IF ... ELSE 문이 작동하도록하는 데 문제가 있다는 것입니다. (부주의하게 그의 예에서 이것을 지적한 dbenham에게 감사합니다) ELSE 문은 닫는 괄호와 별도의 줄에있을 수 없습니다.

그래서이 대신 :

FOR ... DO (
    IF ... (
    )
    ELSE (
    )
)

가독성과 미적 이유로 내가 선호하는 것은 다음과 같습니다.

FOR ... DO (
    IF ... (
    ) ELSE (
    )
)

이제 ELSE 문은 인식 할 수없는 명령으로 반환되지 않습니다.

마지막으로, 제가하려는 작업은 다음과 같습니다. 순서에 상관없이 배치 파일에 여러 인수를 전달하고, 케이스를 무시하고, 전달 된 정의되지 않은 인수에 대해보고 / 실패 할 수 있기를 원했습니다. 그래서 여기에 제 해결책이 있습니다.

@ECHO OFF
SET ARG1=FALSE
SET ARG2=FALSE
SET ARG3=FALSE
SET ARG4=FALSE
SET ARGS=(arg1 Arg1 ARG1 arg2 Arg2 ARG2 arg3 Arg3 ARG3)
SET ARG=

FOR %%A IN (%*) DO (
    SET TRUE=
    FOR %%B in %ARGS% DO (
        IF [%%A] == [%%B] SET TRUE=1
        )
    IF DEFINED TRUE (
        SET %%A=TRUE
        ) ELSE (
        SET ARG=%%A
        GOTO UNDEFINED
        )
    )

ECHO %ARG1%
ECHO %ARG2%
ECHO %ARG3%
ECHO %ARG4%
GOTO END

:UNDEFINED
ECHO "%ARG%" is not an acceptable argument.
GOTO END

:END

이것은 첫 번째 실패한 인수에 대해서만보고합니다. 따라서 사용자가 허용되지 않는 인수를 두 개 이상 전달하면 수정 될 때까지 첫 번째 인수에 대한 정보 만 전달되고 두 번째 인수에 대한 정보 만 전달됩니다.


-1이 질문은 'FOR 루프의 IF 구문'이나 인수를 올바르게 전달하는 방법과 관련이 없지만 배치 파일에서 If .. 또는 .. If 문을 복제하는 방법을 찾는 것과 관련이 있습니다.
Mechaflash

1
그럴 수 있지. OP의 원래 질문에 신중하게 대답하기보다는이 답변이 도움이되었다고 생각합니다. 앞으로 더 조심할 것입니다. 감사합니다 Mechaflash! -R
RMWChaos

1
본질적으로 비슷한 질문이 있고 그 질문을 스스로 해결했으며 자신과 동일한 질문이 stackoverflow에 게시되지 않은 경우 질문으로 위장하고 확인란을 선택하여 직접 대답 할 수 있습니다. 이렇게하면 사이트에 게시되고 사람들도 이에 응답 할 수 있습니다.
Mechaflash
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.