Windowsバッチファイル内のIF ...またはIF ...


96

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 (
    ...
  )
)

1番目の条件がtrueの場合、少し高速に実行される可能性があるという理由でarasmussenが使用するELSE IFロ​​ジックを追加できますが、私は気にしません。

補遺 -これは、IFステートメントでのORの使用WinXPバッチスクリプトとほぼ同じ回答の重複した質問です

最終補遺 -変数が大文字と小文字を区別しない値のリストのいずれかであるかどうかをテストするためのお気に入りのテクニックをほとんど忘れていました。許容値の送信済みリストを含むテスト変数を初期化し、検索と置換を使用して、変数がリスト内にあるかどうかをテストします。これは非常に高速で、任意の長いリストに対して最小限のコードを使用します。拡張の遅延が必要です(または、CALL %% VAR %%のトリック)。また、テストはCASE INSENSITIVEです。

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が大文字と小文字を区別しない任意の数のオプションのいずれかであるかどうかをテストするための、信頼性の高い最適な方法です。

最後に、値ごとに1つのIFを実行する必要があるため、少し遅いと思う単純なバージョンがあります。Aaciniは、前述のリンクで受け入れられた回答に対するコメントでこのソリューションを提供しました

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

値のリストに*または?を含めることはできません。文字、値、および%VAR%引用符を含めることはできません。場合は、引用符は問題につながる%VAR%も、スペースなどの特殊文字が含まれている^&この解決策の一つの他の制限は、あなたがインジケータ変数を追加しない限り、それはELSE句のオプションを提供していないですなど。利点は、IF /Iオプションの有無に応じて、大文字と小文字を区別する場合と区別しない場合があります。


ファイル一致のセマンティクスのため、残念ながらforは、FOR %% A IN(-?-h -help)などの疑問符を含む値では機能しません。
Killroy 2013

@キルロイ-はい、私はすでにその制限を回答で指摘していました。しかし、あなたのコメントにより、私は答えを見て、FORソリューションには追加の制限があることに気づきました。回答の最後を少し更新しました。
dbenham 2013

findstrへのエコーはオプションではありませんか?
スカッシュマン2018年

@Squashman-うーん、そうです。FINDSTRのすべてのバグや癖をナビゲートしたい場合は。
dbenham 2018年

答えは間違っています。Aaciniに起因するコマンドは引用どおり失敗しますが、次のように編集すると機能します。%% A in( "val1" "val2" "val3")do if if "%VAR%" == %% A echo true
Ed999

54

私はそうは思いません。2つのIFとGOTOに同じラベルを使用するだけです。

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end

ええ、私が知る限り、これら2つが唯一の選択肢です。
Mechaflash 2011

1
= D私は実際にpowershellを学習し、すべてのスクリプトを適応させています。しかし、バッチスクリプトに小さなバグ修正を行う必要があるだけで、これが可能かどうかを知りたいと思っていました。クリーンなコードに関しては私はうるさいですlol
Mechaflash

1
ELSE句が必要ない場合にのみ機能しますが、多くの場合、GOTOよりもCALLの方が適しています。
ハリージョンストン

@HarryJohnstonは、それが単なるトップダウンのプログラム/スクリプトであるか、または関数がバッチスクリプト= /に存在するかのように実行するように構造化されているかどうかに依存します。彼の例では、GOTOは正しいでしょうECHO Didn't find it
Mechaflash 2011

バットにor演算子をサポートさせるのはどれほど難しいですか?2019
Joke Huang

8

この投稿をお寄せいただきありがとうございます。

役に立てない場合はDunnoに問題があり、あなたのおかげで、このブール等価に基づいてそれを解決する別の方法だと思います:

「A or B」は「not(not A and not B)」と同じ

したがって:

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

になる:

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

ただし、どちらもtrueでない場合は、FALSE(ELSE)ブランチのみが提供されます。OPは、いずれかが真の場合にTRUE分岐を必要とします。
dbenham 2014年

8

単純な "FOR"を1行で使用して、 "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 '19

ありがとう。よくわかりませんが、一般的に賛成投票は非常に奇妙なプロセスです(そして疑わしいですか?)。stackoverflowだけでなく、他のフォーラムでも同様です。しかし、この場合、それはタイミングだと思います。質問はかなり古く、私の回答は最近です。我々は見つけることができたときにとにかく、私たちは幸せでなければならないすべての作品の答えを。:)
Apostolos 2018

一つの可能なこの技術の欠点(のような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を使用せずに「インプレース」アクションを実行すると、すべての条件が一致する場合、アクションが3回実行される可能性があります。


この答えはすでに提供されていることに気づきました。ムストはそれを監督しました。
ドノーズ2014

2

何もありませんIF <arg> ORELIFもしくは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によって(哀れな)種類のサブシェルとして処理されます。ブロックから出てくる終了コードはすべて、ブロックがより大きなブール式で再生するtrue / false値を決定するために使用されます。これらのコードブロックを使用して、任意の大きなブール式を作成できます。

簡単な例

各ブロックは、式全体の値が決定されるか、制御がジャンプするまで(たとえば、GOTOを介して)、true(つまり、ブロックの最後のステートメントが実行された後はERRORLEVEL = 0)に解決されます。

 ((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のように見えるかもしれませんが、IFwithの簡単なシェルクエリを実行すると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)

明らかに、それらはあらゆる種類の条件付き評価になる可能性がありますが、私はいくつかの例を共有しています。

すべてを1行で記述したい場合は、次のようにチェーンします&&

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でバッチファイルが機能しない


あなたの例で書かれているように、「存在しない場合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

これは、失敗した最初の引数についてのみ報告することに注意してください。したがって、ユーザーが複数の許容できない引数を渡した場合、修正されるまで最初の引数のみが通知され、次に2番目の引数などが通知されます。


-1この質問は、「FORループのIF構文」や引数を適切に渡す方法とは関係ありませんが、バッチファイル内のIf .. Or .. Ifステートメントを複製する方法を見つけることと関係がありました。
Mechaflash

1
けっこうだ。OPの元の質問に慎重に答えるのではなく、自分自身の質問に答えていたと思います。将来はもっと注意していきます。メカフラッシュありがとう!-R
RMWChaos 2012

1
本質的に類似した質問があり、その質問を自分で解決し、同じ質問がstackoverflowに投稿されていない場合は、それを質問として提起し、ボックスにチェックを入れて自分で回答できます。そうすればサイトに表示され、人々もそれに応答することができます。
Mechaflash 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.