Czy istnieje sposób zapisania instrukcji warunkowej IF OR IF w pliku wsadowym systemu Windows?
Na przykład:
IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE
Czy istnieje sposób zapisania instrukcji warunkowej IF OR IF w pliku wsadowym systemu Windows?
Na przykład:
IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE
Odpowiedzi:
Rozwiązanie zmbq jest dobre, ale nie może być używane we wszystkich sytuacjach, takich jak wewnątrz bloku kodu, takiego jak pętla FOR DO (...).
Alternatywą jest użycie zmiennej wskaźnikowej. Zainicjuj go, aby był niezdefiniowany, a następnie zdefiniuj go tylko wtedy, gdy jeden z warunków LUB jest prawdziwy. Następnie użyj funkcji IF DEFINED jako ostatecznego testu - nie ma potrzeby używania opóźnionego rozszerzania.
FOR ..... DO (
set "TRUE="
IF cond1 set TRUE=1
IF cond2 set TRUE=1
IF defined TRUE (
...
) else (
...
)
)
Możesz dodać logikę ELSE IF, której używa arasmussen na tej podstawie, że może działać trochę szybciej, jeśli pierwszy warunek jest prawdziwy, ale nigdy się nie przejmuję.
Dodatek - jest to zduplikowane pytanie z prawie identycznymi odpowiedziami na temat używania OR w instrukcji IF WinXP Batch Script
Dodatek końcowy - prawie zapomniałem o mojej ulubionej technice sprawdzania, czy zmienna jest jedną z listy wartości niewrażliwych na wielkość liter. Zainicjuj zmienną testową zawierającą rozdzielaną listę dopuszczalnych wartości, a następnie użyj funkcji wyszukiwania i zamieniania, aby sprawdzić, czy zmienna znajduje się na liście. Jest to bardzo szybkie i wykorzystuje minimalny kod dla dowolnie długiej listy. Wymaga opóźnionej ekspansji (lub sztuczki CALL %% VAR %%). Test jest również niewrażliwy na wielkość liter.
set "TEST=;val1;val2;val3;val4;val5;"
if "!TEST:;%VAR%;=!" neq "!TEST!" (echo true) else (echo false)
Powyższe może się nie powieść, jeśli VAR zawiera =
, więc test nie jest niezawodny .
Jeśli wykonujesz test w bloku, w którym potrzebne jest opóźnione rozwinięcie, aby uzyskać dostęp do bieżącej wartości VAR, to
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)
)
W zależności od oczekiwanych wartości w VAR mogą być potrzebne opcje FOR, takie jak „delims =”
Powyższą strategię można uczynić niezawodną nawet =
w przypadku VAR, dodając nieco więcej kodu.
set "TEST=;val1;val2;val3;val4;val5;"
if "!TEST:;%VAR%;=!" neq "!TEST!" if "!TEST:;%VAR%;=;%VAR%;"=="!TEST!" echo true
Ale teraz straciliśmy możliwość dostarczania klauzuli ELSE, chyba że dodamy zmienną wskaźnikową. Kod zaczął wyglądać trochę "brzydko", ale myślę, że jest to najlepsza niezawodna metoda testowania, jeśli VAR jest jedną z dowolnej liczby opcji bez rozróżniania wielkości liter.
Wreszcie jest prostsza wersja, która moim zdaniem jest nieco wolniejsza, ponieważ musi wykonywać jedną IF dla każdej wartości. Aacini podał to rozwiązanie w komentarzu do zaakceptowanej odpowiedzi w powyższym linku
for %%A in ("val1" "val2" "val3" "val4" "val5") do if "%VAR%"==%%A echo true
Lista wartości nie może zawierać znaku * ani? znaków oraz wartości i %VAR%
nie powinny zawierać cudzysłowów. Cytaty prowadzić do problemów, jeśli %VAR%
zawiera spacje lub znaki specjalne, takie jak ^
, &
itd jednego innego ograniczenia ze jest to nie przewiduje opcję dla ELSE klauzuli chyba dodać zmienną wskaźnikową tego rozwiązania. Zaletą jest to, że może być uwzględniana wielkość liter lub niewrażliwa, w zależności od obecności lub braku /I
opcji IF .
Nie sądzę. Po prostu użyj dwóch IF i GOTO tej samej etykiety:
IF cond1 GOTO foundit
IF cond2 GOTO foundit
ECHO Didn't found it
GOTO end
:foundit
ECHO Found it!
:end
ECHO Didn't find it
nawet, gdyby go znalazł.
Dzięki za ten post, bardzo mi pomógł.
Nie wiem, czy to może pomóc, ale miałem problem i dzięki tobie znalazłem inny sposób rozwiązania go w oparciu o tę logiczną równoważność:
„A lub B” to to samo, co „nie (nie A i nie B)”
A zatem:
IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE
Staje się:
IF not [%var%] == [1] IF not [%var%] == [2] ECHO FALSE
Aby użyć warunku „lub”, można użyć prostego „FOR” w pojedynczym wierszu:
FOR %%a in (item1 item2 ...) DO IF {condition_involving_%%a} {execute_command}
Dotyczy twojego przypadku:
FOR %%a in (1 2) DO IF %var%==%%a ECHO TRUE
Nawet jeśli to pytanie jest trochę starsze:
Jeśli chcesz używać if cond1 or cond 2
- nie powinieneś używać skomplikowanych pętli lub podobnych rzeczy.
Proste dostarczanie obu ifs
po sobie w połączeniu z goto
- to niejawne lub.
//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
Bez działania goto, ale „inplace”, możesz wykonać akcję 3 razy, jeśli WSZYSTKIE warunki są zgodne.
Nie ma IF <arg> OR
ani ELIF
czy ELSE IF
w trybie wsadowym, jednak ...
Spróbuj zagnieździć inne IF wewnątrz ELSE poprzedniego IF.
IF <arg> (
....
) ELSE (
IF <arg> (
......
) ELSE (
IF <arg> (
....
) ELSE (
)
)
Możliwe jest użycie funkcji, która ocenia logikę OR i zwraca pojedynczą wartość.
@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
)
&& ... || ...
składni bezpośrednio zamiast dodatkowej IF ... ELSE ...
instrukcji.
Cel można osiągnąć poprzez pośrednie wykorzystanie FI.
Poniżej znajduje się przykład złożonego wyrażenia, które można zapisać dość zwięźle i logicznie w partii CMD, bez niespójnych etykiet i GOTO.
Bloki kodu w nawiasach () są traktowane przez CMD jako (żałosny) rodzaj podpowłoki. Cokolwiek kod wyjścia wychodzi z bloku, zostanie użyty do określenia wartości prawda / fałsz, którą blok odtwarza w większym wyrażeniu logicznym. Z tych bloków kodu można zbudować dowolnie duże wyrażenia logiczne.
Prosty przykład
Każdy blok jest przetwarzany na prawdę (tj. ERRORLEVEL = 0 po wykonaniu ostatniej instrukcji w bloku) / fałsz, dopóki wartość całego wyrażenia nie zostanie określona lub sterowanie wyskoczy (np. Przez GOTO):
((DIR c:\xsgdde /w) || (DIR c:\ /w)) && (ECHO -=BINGO=-)
Złożony przykład
To rozwiązuje problem podniesiony na początku. W każdym bloku jest możliwych wiele instrukcji, ale w || || || wyrażenie lepiej jest być zwięzłe, aby było jak najbardziej czytelne. ^ jest znakiem ucieczki w paczkach CMD i po umieszczeniu na końcu wiersza będzie oznaczał wyjście z EOL i poinstruowanie CMD, aby kontynuował czytanie bieżącej serii instrukcji w następnym wierszu.
@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
If %x%==1 (
If %y%==1 (
:: both are equal to 1.
)
)
Służy do sprawdzania, czy wiele zmiennych ma taką samą wartość. Tutaj jest dla każdej zmiennej.
If %x%==1 (
:: true
)
If %x%==0 (
If %y%==1 (
:: true
)
)
If %x%==0 (
If %y%==0 (
:: False
)
)
Po prostu pomyślałem o tym z góry, jeśli moja głowa. Mógłbym to bardziej zagęścić.
Zdaję sobie sprawę, że to pytanie jest stare, ale chciałem opublikować alternatywne rozwiązanie na wypadek, gdyby ktoś inny (taki jak ja) znalazł ten wątek, mając to samo pytanie. Byłem w stanie obejść brak operatora OR, wywołując echo zmiennej i używając findstr do walidacji.
for /f %%v in ('echo %var% ^| findstr /x /c:"1" /c:"2"') do (
if %errorlevel% equ 0 echo true
)
Chociaż odpowiedź dbenham jest całkiem dobra, poleganie na niej IF DEFINED
może przysporzyć Ci wielu kłopotów, jeśli sprawdzana zmienna nie jest zmienną środowiskową . Zmienne skryptowe nie są traktowane w ten specjalny sposób.
Chociaż może się to wydawać absurdalnym, nieudokumentowanym BS, wykonanie prostego zapytania w powłoce za IF
pomocą IF /?
ujawnia, że:
Warunek DEFINED działa tak samo jak EXIST, z tą różnicą, że przyjmuje nazwę zmiennej środowiskowej i zwraca wartość true, jeśli zmienna środowiskowa jest zdefiniowana.
Jeśli chodzi o odpowiedź na to pytanie, czy istnieje powód, aby nie używać prostej flagi po serii ocen? Wydaje OR
mi się, że jest to najbardziej elastyczne sprawdzenie, zarówno pod względem logiki, jak i czytelności. Na przykład:
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)
Oczywiście mogą to być dowolne oceny warunkowe, ale podam tylko kilka przykładów.
Jeśli chcesz mieć to wszystko w jednej linii, pod względem pisma, możesz po prostu połączyć je razem za pomocą &&
:
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)
Nigdy nie przyszedłem do pracy.
Używam jeśli nie istnieje g: xyz / what goto h: Else xcopy c: current / files g: bu / current Istnieją modyfikatory / a itp. Nie wiem, które z nich. Laptop w sklepie. I komputer w biurze. Mnie tam nie ma.
Pliki wsadowe nigdy nie działały w systemie Windows XP
O wiele szybsza alternatywa, której zwykle używam, jest następująca, ponieważ mogę "lub" dowolna liczba warunków, które mogą zmieścić się w zmiennej przestrzeni
@(
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.
)
Zdając sobie sprawę, że jest to trochę stare pytanie, odpowiedzi pomogły mi wymyślić rozwiązanie testowania argumentów wiersza poleceń w pliku wsadowym; dlatego też chciałem zamieścić moje rozwiązanie na wypadek, gdyby ktoś inny szukał podobnego rozwiązania.
Pierwszą rzeczą, na którą powinienem zwrócić uwagę, jest to, że miałem problem z uzyskaniem działania instrukcji IF ... ELSE wewnątrz klauzuli FOR ... DO. Okazuje się (dzięki dbenhamowi za nieumyślne wskazanie tego w swoich przykładach), że instrukcja ELSE nie może znajdować się w oddzielnym wierszu od zamykających par.
Więc zamiast tego:
FOR ... DO (
IF ... (
)
ELSE (
)
)
Które preferuję ze względu na czytelność i estetykę, musisz to zrobić:
FOR ... DO (
IF ... (
) ELSE (
)
)
Teraz instrukcja ELSE nie zwraca jako nierozpoznane polecenie.
Wreszcie, oto co próbowałem zrobić - chciałem móc przekazać kilka argumentów do pliku wsadowego w dowolnej kolejności, ignorując wielkość liter i zgłaszając / niepowodzenie w przekazywaniu niezdefiniowanych argumentów. Oto moje rozwiązanie ...
@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
Uwaga, to zgłosi tylko pierwszy nieudany argument. Jeśli więc użytkownik poda więcej niż jeden niedopuszczalny argument, zostanie mu poinformowany tylko o pierwszym, dopóki nie zostanie poprawiony, potem o drugim itd.
IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE
. Użyłem do zdefiniowaniaSET AND=IF
, a następnie napisać:IF cond1 %AND% cond2 ECHO BOTH ARE TRUE
.