WENN… ODER WENN… in einer Windows-Batchdatei

95

Gibt es eine Möglichkeit, eine bedingte IF- oder IF-Anweisung in eine Windows-Batchdatei zu schreiben?

Beispielsweise:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE
Mechaflash
quelle
7
Nein. Es ist möglich, direkt ein UND zu schreiben : IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE. Ich habe immer definiert SET AND=IFund dann geschrieben : IF cond1 %AND% cond2 ECHO BOTH ARE TRUE.
Aacini

Antworten:

95

Die zmbq-Lösung ist gut, kann jedoch nicht in allen Situationen verwendet werden, z. B. in einem Codeblock wie einer FOR DO (...) - Schleife.

Eine Alternative ist die Verwendung einer Indikatorvariablen. Initialisieren Sie es so, dass es nicht definiert ist, und definieren Sie es dann nur, wenn eine der ODER-Bedingungen erfüllt ist. Verwenden Sie dann IF DEFINED als letzten Test - Sie müssen keine verzögerte Erweiterung verwenden.

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

Sie könnten die ELSE IF-Logik hinzufügen, die arasmussen verwendet, weil sie möglicherweise etwas schneller ausgeführt wird, wenn die erste Bedingung erfüllt ist, aber ich kümmere mich nie darum.

Nachtrag - Dies ist eine doppelte Frage mit nahezu identischen Antworten auf die Verwendung eines ODER in einem WinXP-Batch-Skript mit IF-Anweisung

Letzter Nachtrag - Ich habe fast meine Lieblingstechnik vergessen, um zu testen, ob eine Variable zu einer Liste von Werten gehört, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird. Initialisieren Sie eine Testvariable, die eine begrenzte Liste akzeptabler Werte enthält, und testen Sie dann mithilfe von Suchen und Ersetzen, ob sich Ihre Variable in der Liste befindet. Dies ist sehr schnell und verwendet minimalen Code für eine beliebig lange Liste. Es erfordert eine verzögerte Erweiterung (oder den Trick CALL %% VAR %%). Auch der Test ist CASE INSENSITIVE.

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

Das Obige kann fehlschlagen, wenn VAR enthält =, sodass der Test nicht narrensicher ist.

Wenn Sie den Test innerhalb eines Blocks durchführen, in dem eine verzögerte Erweiterung erforderlich ist, um auf den aktuellen Wert von VAR zuzugreifen, dann

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

Abhängig von den erwarteten Werten in VAR sind möglicherweise FOR-Optionen wie "delims =" erforderlich

Die obige Strategie kann auch =in VAR durch Hinzufügen von etwas mehr Code zuverlässig gemacht werden.

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

Jetzt haben wir jedoch die Möglichkeit verloren, eine ELSE-Klausel bereitzustellen, sofern wir keine Indikatorvariable hinzufügen. Der Code hat begonnen, ein bisschen "hässlich" auszusehen, aber ich denke, er ist die zuverlässigste Methode zum Testen, ob VAR eine beliebige Anzahl von Optionen ist, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird.

Schließlich gibt es eine einfachere Version, die meiner Meinung nach etwas langsamer ist, da für jeden Wert eine IF ausgeführt werden muss. Aacini hat diese Lösung in einem Kommentar zur akzeptierten Antwort im zuvor genannten Link bereitgestellt

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

Die Werteliste darf nicht das * oder? Enthalten. Zeichen und die Werte und %VAR%sollte keine Anführungszeichen enthalten. Zitate führen zu Problemen , wenn die %VAR%auch Leer- oder Sonderzeichen enthalten wie ^, &usw. Eine andere Einschränkung bei dieser Lösung ist es nicht die Möglichkeit , für eine ELSE - Klausel zur Verfügung stellen , wenn Sie eine Indikatorvariable hinzufügen. Vorteile sind, dass je nach Vorhandensein oder Fehlen einer IF- /IOption zwischen Groß- und Kleinschreibung unterschieden werden kann .

Dbenham
quelle
Leider funktioniert for aufgrund der Semantik der Dateimatching nicht mit Werten, die Fragezeichen wie FOR %% A IN (-? -H -help) enthalten.
Killroy
@ Killroy - ja, ich hatte diese Einschränkung bereits in der Antwort bemerkt. Ihr Kommentar hat mich jedoch gezwungen, die Antwort zu prüfen und festzustellen, dass die FOR-Lösung zusätzliche Einschränkungen aufweist. Ich habe das Ende der Antwort etwas aktualisiert.
Dbenham
Wäre ein Echo zu findstr nicht eine Option?
Squashman
@Squashman - Ugh, ja, wenn Sie durch alle FINDSTR-Fehler und Macken navigieren möchten.
Dbenham
Die Antwort ist falsch. Der Aacini zugewiesene Befehl schlägt wie angegeben fehl, funktioniert jedoch, wenn er wie folgt bearbeitet wird: Für %% A in ("val1" "val2" "val3") tun, wenn "% VAR%" == %% A echo true
Ed999
53

Das glaube ich nicht. Verwenden Sie einfach zwei IFs und GOTO das gleiche Label:

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end
zmbq
quelle
Ja, soweit ich das beurteilen kann, sind diese beiden die einzige Option.
Mechaflash
1
= D Ich bin gerade dabei, Powershell zu lernen und alle meine Skripte anzupassen. Aber ich musste nur eine kleine Fehlerbehebung für ein Batch-Skript durchführen und wollte wissen, ob dies möglich war. Ich bin wählerisch, wenn es um sauberen Code geht lol
Mechaflash
1
In vielen Situationen ist CALL GOTO vorzuziehen, obwohl dies nur funktioniert, wenn Sie die ELSE-Klausel nicht benötigen.
Harry Johnston
@HarryJohnston es hängt davon ab, ob es sich nur um ein Top-Down-Programm / Skript handelt oder ob es so strukturiert ist, dass es so ausgeführt wird, als ob Funktionen im Batch-Scripting vorhanden wären = /. In seinem Beispiel wäre GOTO korrekt, oder Sie würden das treffen, ECHO Didn't find itselbst wenn es es finden würde.
Mechaflash
Wie schwierig ist es, die Fledermaus den oder den Bediener unterstützen zu lassen? Es wurde im Jahr 2019 nicht implementiert.
Witz Huang
8

Danke für diesen Beitrag, er hat mir sehr geholfen.

Keine Ahnung, ob es helfen kann, aber ich hatte das Problem und dank Ihnen habe ich herausgefunden, was meiner Meinung nach ein anderer Weg ist, es basierend auf dieser booleschen Äquivalenz zu lösen:

"A oder B" ist dasselbe wie "nicht (nicht A und nicht B)"

So:

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

Wird:

IF not [%var%] == [1] IF not [%var%] == [2] ECHO FALSE
Kaktus
quelle
Dies liefert jedoch nur dann den Zweig FALSE (ELSE), wenn keiner von beiden wahr ist. Das OP möchte den TRUE-Zweig, wenn einer von beiden wahr ist.
Dbenham
8

Ein einfaches "FOR" kann in einer einzelnen Zeile verwendet werden, um eine "oder" Bedingung zu verwenden:

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

Auf Ihren Fall angewendet:

FOR %%a in (1 2) DO IF %var%==%%a ECHO TRUE
Apostolos
quelle
Ich fand, dass dies der einfachste und am einfachsten zu verwendende Fall in meinen Batch-Skripten ist. Wie kommt es, dass dies nie die empfohlene Antwort war?
Myusrn
Vielen Dank. Ich weiß nicht, Upvoting ist im Allgemeinen ein sehr seltsamer Prozess (und zweifelhaft?), Nicht nur im Stackoverflow, sondern auch in anderen Foren. Aber in diesem Fall ist es wohl das Timing. Die Frage ist ziemlich alt und meine Antwort wurde kürzlich beantwortet. Wie auch immer, wir müssen glücklich sein, wenn wir eine Antwort finden, die funktioniert. :)
Apostolos
Ein möglicher Nachteil dieser Technik (obwohl ich wie die out-of-the-boxness des Ansatzes!) Ist , dass je nach Zustand , es kann möglich sein , den Befehl zweimal ausführen, die nicht gesucht werden könnten.
TripeHound
Theoretisch ja. Aber ich habe Hunderte von Batch-Dateien erstellt, ich verwende jeden Tag Dutzende davon und bin einem solchen Fall nie begegnet. Bleiben wir also in der Praxis! :)
Apostolos
6

Auch wenn diese Frage etwas älter ist:

Wenn Sie verwenden möchten, if cond1 or cond 2sollten Sie keine komplizierten Schleifen oder ähnliches verwenden.

Einfach beides ifsnacheinander in Kombination mit goto- das ist ein implizites oder.

//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

Ohne goto, aber eine "Inplace" -Aktion, können Sie die Aktion dreimal ausführen, wenn ALLE Bedingungen übereinstimmen.

dognose
quelle
Gerade entdeckt, ist diese Antwort bereits gegeben. muss das beaufsichtigt haben.
Dognose
2

Es gibt jedoch kein IF <arg> ORoder ELIFoder ELSE IFin Batch ...

Versuchen Sie, die anderen IFs im ELSE der vorherigen IF zu verschachteln.

IF <arg> (
    ....
) ELSE (
    IF <arg> (
        ......
    ) ELSE (
        IF <arg> (
            ....
        ) ELSE (
    )
)
Andrew Rasmussen
quelle
3
Dies ist keine gute Implementierung von OR, da der auszuführende bedingte Code für jede ELSE-IF repliziert werden muss. (es sei denn natürlich, der bedingte Code ist ein GOTO. In diesem Fall haben Sie eine ausführlichere Form der Lösung von zmbq.)
dbenham
2

Es ist möglich, eine Funktion zu verwenden, die die ODER-Logik auswertet und einen einzelnen Wert zurückgibt.

@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
) 
jeb
quelle
+1, Diese Funktion ist ein guter Kandidat für die Rückgabe des Ergebnisses im ERRORLEVEL-Rückkehrcode. Dann kann der Aufruf die bequeme && ... || ...Syntax direkt anstelle der zusätzlichen IF ... ELSE ...Anweisung verwenden.
Dbenham
2

Das Ziel kann durch indirekte Verwendung von IFs erreicht werden.

Im Folgenden finden Sie ein Beispiel für einen komplexen Ausdruck, der in einem CMD-Stapel ohne inkohärente Beschriftungen und GOTOs sehr präzise und logisch geschrieben werden kann.

Codeblöcke zwischen () Klammern werden von CMD als (pathetische) Art von Unterschale behandelt. Welcher Exit-Code aus einem Block kommt, wird verwendet, um den True / False-Wert zu bestimmen, den der Block in einem größeren booleschen Ausdruck spielt. Mit diesen Codeblöcken können beliebig große boolesche Ausdrücke erstellt werden.

Einfaches Beispiel

Jeder Block wird in true aufgelöst (dh ERRORLEVEL = 0, nachdem die letzte Anweisung im Block ausgeführt wurde) / false, bis der Wert des gesamten Ausdrucks bestimmt wurde oder die Steuerung herausspringt (z. B. über GOTO):

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

Komplexes Beispiel

Dies löst das ursprünglich aufgeworfene Problem. In jedem Block sind mehrere Anweisungen möglich, jedoch im || || || Ausdruck Es ist vorzuziehen, präzise zu sein, damit es so lesbar wie möglich ist. ^ ist ein Escape-Zeichen in CMD-Stapeln. Wenn es am Ende einer Zeile platziert wird, wird es der EOL entkommen und CMD anweisen, den aktuellen Stapel von Anweisungen in der nächsten Zeile weiterzulesen.

@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
Bogdan
quelle
1
If %x%==1 (
If %y%==1 (
:: both are equal to 1.
)
)

Hiermit wird überprüft, ob mehrere Variablen den gleichen Wert haben. Hier ist für jede Variable.

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

Ich habe nur von oben an das gedacht, wenn mein Kopf. Ich könnte es mehr verdichten.

Coltonon
quelle
1

Mir ist klar, dass diese Frage alt ist, aber ich wollte eine alternative Lösung veröffentlichen, falls jemand anderes (wie ich) diesen Thread gefunden hat, während er dieselbe Frage hat. Ich konnte das Fehlen eines OR-Operators umgehen, indem ich die Variable wiederholte und findstr zur Validierung verwendete.

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

Während die Antwort von dbenham ziemlich gut ist, IF DEFINEDkann das Verlassen auf Sie in große Schwierigkeiten geraten, wenn die Variable, die Sie überprüfen, keine Umgebungsvariable ist. Skriptvariablen erhalten diese spezielle Behandlung nicht.

Während dies wie eine lächerliche undokumentierte BS erscheinen mag, zeigt eine einfache Shell-Abfrage IFmit IF /?, dass

Die Bedingung DEFINED funktioniert genau wie EXIST, außer dass sie einen Umgebungsvariablennamen verwendet und true zurückgibt, wenn die Umgebungsvariable definiert ist.

Gibt es bei der Beantwortung dieser Frage einen Grund, nach einer Reihe von Bewertungen nicht einfach ein einfaches Flag zu verwenden? Dies scheint ORmir die flexibelste Prüfung zu sein, sowohl hinsichtlich der zugrunde liegenden Logik als auch der Lesbarkeit. Beispielsweise:

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)

Natürlich können sie jede Art von bedingter Bewertung sein, aber ich teile nur einige Beispiele.

Wenn Sie alles schriftlich in einer Zeile haben möchten, können Sie sie einfach mit folgenden Elementen verketten &&:

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)
kayleeFrye_onDeck
quelle
0

Nie existiert, um zu arbeiten.

Ich benutze wenn nicht vorhanden g: xyz / was gehe zu h: Sonst xcopy c: aktuell / Dateien g: bu / aktuell Es gibt Modifikatoren / a usw. Ich bin mir nicht sicher, welche. Laptop im Laden. Und Computer im Büro. Ich bin nicht da.

Batch-Dateien funktionieren nie über Windows XP

user8865291
quelle
Wie in Ihrem Beispiel geschrieben, "falls nicht vorhanden, g: xyz / what", xyz / what ist relativ zum aktuellen Verzeichnis des g: -Laufwerks, das möglicherweise nicht der Stammordner von g ist. Benötigen Sie hier "g: \ xyz \ what"? Gleiches gilt für c: current / files und g: bu / current. Beachten Sie, dass jedes Laufwerk einen anderen aktuellen Ordner hat und "gespeichert" wird, auch wenn dieses Laufwerk nicht Ihr aktuelles Arbeitsverzeichnis ist.
John Elion
0

Eine viel schnellere Alternative, die ich normalerweise verwende, ist die folgende, da ich eine beliebige Anzahl von Bedingungen "oder" kann, die in einen variablen Raum passen können

@(
  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.
)
Ben Personick
quelle
-3

Als mir klar wurde, dass dies eine alte Frage ist, haben mir die Antworten geholfen, eine Lösung zum Testen von Befehlszeilenargumenten für eine Batchdatei zu finden. Daher wollte ich meine Lösung auch veröffentlichen, falls jemand anderes nach einer ähnlichen Lösung suchte.

Als erstes sollte ich darauf hinweisen, dass ich Probleme hatte, IF ... ELSE-Anweisungen innerhalb einer FOR ... DO-Klausel zum Laufen zu bringen. Es stellt sich heraus (danke an dbenham, dass er in seinen Beispielen versehentlich darauf hingewiesen hat), dass die ELSE-Anweisung nicht in einer separaten Zeile von den schließenden Parens stehen darf.

Also stattdessen:

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

Was meine Präferenz für Lesbarkeit und ästhetische Gründe ist, müssen Sie dies tun:

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

Jetzt wird die ELSE-Anweisung nicht als nicht erkannter Befehl zurückgegeben.

Schließlich habe ich Folgendes versucht: Ich wollte in der Lage sein, mehrere Argumente in beliebiger Reihenfolge an eine Batchdatei zu übergeben, Groß- und Kleinschreibung zu ignorieren und undefinierte Argumente zu melden / fehlzuschlagen. Hier ist meine Lösung ...

@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

Beachten Sie, dass dies nur über das erste fehlgeschlagene Argument berichtet. Wenn der Benutzer also mehr als ein inakzeptables Argument eingibt, wird er nur über das erste informiert, bis es korrigiert ist, dann über das zweite usw.

RMWChaos
quelle
-1 Diese Frage hatte nichts mit der 'IF-Syntax in einer FOR-Schleife' oder der richtigen Übergabe von Argumenten zu tun, sondern mit der Suche nach einer Möglichkeit zur Replikation einer If .. Or .. If-Anweisung in einer Batchdatei.
Mechaflash
1
Meinetwegen. Ich schätze, ich habe meine eigene Frage beantwortet, bei der mir diese Antworten geholfen haben, anstatt darauf zu achten, die ursprüngliche Frage des OP zu beantworten. Wird in Zukunft vorsichtiger sein. Danke Mechaflash! -R
RMWChaos
1
Wenn Sie eine ähnliche Frage haben, diese Frage selbst gelöst haben und im Stackoverflow keine Frage veröffentlicht wird, die mit Ihrer eigenen identisch ist, können Sie sie als Frage stellen und das Kontrollkästchen aktivieren, um sie selbst zu beantworten. Auf diese Weise wird es auf der Website sein und die Leute können auch darauf reagieren.
Mechaflash