IF… OR IF… bir Windows toplu iş dosyasında


97

Windows toplu iş dosyasına bir EĞER VEYA EĞER koşullu ifade yazmanın bir yolu var mı?

Örneğin:

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

7
Hayır. Mümkün olan, doğrudan bir VE: yazmaktır IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE. Ben tanımlamak için kullanılan SET AND=IFve sonra yazın: IF cond1 %AND% cond2 ECHO BOTH ARE TRUE.
Aacini

Yanıtlar:


95

Zmbq çözümü iyidir, ancak FOR DO (...) döngüsü gibi bir kod bloğunun içinde olduğu gibi tüm durumlarda kullanılamaz.

Bir alternatif, bir gösterge değişkeni kullanmaktır. Tanımlanmamış olacak şekilde başlatın ve ardından yalnızca VEYA koşullarından herhangi biri doğruysa tanımlayın. Ardından son test olarak IF DEFINED'i kullanın - gecikmeli genişletme kullanmaya gerek yoktur.

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

1. koşul doğruysa biraz daha hızlı çalışabileceği gerekçesiyle arasmussen'in kullandığı ELSE EĞER mantığını ekleyebilirsiniz, ancak ben asla rahatsız etmem.

Ek - Bu, WinXP Batch Script IF deyiminde OR kullanma ile neredeyse aynı yanıtlara sahip yinelenen bir sorudur

Son ek - Bir değişkenin büyük / küçük harfe duyarsız değerler listesinden herhangi biri olup olmadığını test etmek için en sevdiğim tekniği neredeyse unutuyordum. Sınırlandırılmış kabul edilebilir değerler listesi içeren bir test değişkenini başlatın ve ardından değişkeninizin listede olup olmadığını test etmek için ara ve değiştir seçeneğini kullanın. Bu çok hızlıdır ve rastgele uzun bir liste için minimum kod kullanır. Gecikmeli genişletme gerektirir (ya da CALL %% VAR %% numarası). Ayrıca test CASE INSENSITIVE'dır.

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

VAR içeriyorsa yukarıdakiler başarısız olabilir =, bu nedenle test kusursuz değildir.

Testi, VAR'ın mevcut değerine erişmek için gecikmeli genişlemenin gerekli olduğu bir blok içinde yapıyorsanız,

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 içindeki beklenen değerlere bağlı olarak "delims =" gibi seçenekler gerekli olabilir

Yukarıdaki strateji, =biraz daha fazla kod ekleyerek VAR'da bile güvenilir hale getirilebilir .

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

Ancak şimdi bir gösterge değişkeni eklemediğimiz sürece bir ELSE cümlesini sağlama yeteneğimizi kaybettik. Kod biraz "çirkin" görünmeye başladı, ancak VAR'ın rastgele sayıdaki büyük / küçük harf duyarlı olmayan seçeneklerden biri olup olmadığını test etmek için en iyi performans gösteren güvenilir yöntem olduğunu düşünüyorum.

Son olarak biraz daha yavaş olduğunu düşündüğüm daha basit bir sürüm var çünkü her değer için bir IF gerçekleştirmesi gerekiyor. Aacini, bu çözümü, daha önce belirtilen bağlantıda kabul edilen yanıta bir yorumda sundu.

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

Değerler listesi * veya? karakterler ve değerler ve %VAR%tırnak işareti içermemelidir. Eğer Alıntılar problemlere yol %VAR%da boşluk veya benzeri özel karakterler içeriyor ^, &bu çözümün bir gösterge değişkeni eklemek sürece bir BAŞKA maddede seçeneği sunmaz ise vb bir diğer sınırlama. Avantajları, IF /Iseçeneğinin varlığına veya yokluğuna bağlı olarak büyük / küçük harfe duyarlı veya duyarsız olabilir .


Maalesef, dosya eşleşmesi anlambiliminden dolayı FOR %% A IN (-? -H -help) gibi soru işaretleri içeren değerlerle çalışmaz.
Killroy

@Killroy - evet, yanıtta bu sınırlamayı zaten not etmiştim. Ancak yorumunuz beni cevaba bakmaya ve FOR çözümüyle ilgili ek sınırlamalar olduğunu fark etmeye zorladı. Cevabın sonunu biraz güncelledim.
dbenham

Findstr için bir eko bir seçenek olmaz mıydı?
Squashman

@Squashman - Ugh, evet, tüm FINDSTR hatalarını ve tuhaflıkları gezinmek istiyorsanız.
dbenham

Cevap yanlış. Aacini'ye atfedilen komut, alıntılandığı gibi başarısız olur, ancak şu şekilde düzenlenirse çalışır: ("val1" "val2" "val3") içindeki %% A için, "% VAR%" == %% A yankı doğru ise
Ed999

54

Ben öyle düşünmüyorum. Sadece iki IF kullanın ve aynı etiketi GOTO:

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end

Evet, bildiğim kadarıyla bu ikisi tek seçenek.
Mechaflash

1
= D Aslında powershell öğrenme ve tüm senaryolarımı uyarlama sürecindeyim. Ancak bir toplu komut dosyasında küçük bir hata düzeltmesi yapması gerekiyordu ve bunun mümkün olup olmadığını bilmek istiyordu. Temiz kod söz konusu olduğunda seçici
davranıyorum

1
Çoğu durumda CALL, GOTO'ya tercih edilebilir, ancak bu yalnızca ELSE cümlesine ihtiyacınız yoksa çalışır.
Harry Johnston

@HarryJohnston Bu, sadece yukarıdan aşağıya bir program / komut dosyası olup olmadığına veya toplu komut dosyası oluşturma = / 'de işlevler varmış gibi çalışacak şekilde yapılandırılmış olup olmadığına bağlıdır. Onun örneğinde, GOTO doğru olurdu, yoksa bulsa bile vururdunuz ECHO Didn't find it.
Mechaflash

Yarasanın veya operatörü desteklemesine izin vermek ne kadar zor? 2019'da uygulanmadı.
Joke Huang

8

Bu yazı için teşekkürler, bana çok yardımcı oldu.

Dunno yardımcı olabilirse ama sorun bende vardı ve senin sayende bu boole denkliğine dayanarak sorunu çözmenin başka bir yolu olduğunu düşündüğüm şeyi buldum:

"A veya B", "değil (A ve B değil)" ile aynıdır

Böylece:

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

Oluyor:

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

Ancak bu, ikisi de doğru değilse yalnızca YANLIŞ (ELSE) dalını sağlar. OP, eğer doğruysa, DOĞRU şubesini ister.
dbenham

8

Basit bir "FOR", bir "veya" koşulunu kullanmak için tek bir satırda kullanılabilir:

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

Davanıza uygulandı:

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

Bunu, toplu komut dosyalarımda en basit ve kullanımı kolay durum olarak buldum. Bu neden bunu asla önerilen cevap haline getirmedi?
myusrn

Teşekkürler. Bilmiyorum, genel olarak yukarı oy vermek çok garip (ve şüpheli mi?), Sadece stackoverflow'da değil, diğer forumlarda da. Ama bu durumda, sanırım zamanlama. Soru oldukça eski ve cevabım yeni geldi. Her neyse, işe yarayan herhangi bir cevabı bulduğumuzda mutlu olmalıyız . :)
Apostolos

Bir olası bu teknikle dezavantajı (gibi her ne kadar dışarı-of-the-boxness yaklaşımının!) Olmasıdır durumuna bağlı , olabilir istenmek değil olabilir iki kez komutunu çalıştırmak mümkün.
TripeHound

Teorik olarak evet. Ama yüzlerce toplu iş dosyası oluşturdum, her gün düzinelerce kullanıyorum ve böyle bir vakayla hiç karşılaşmadım. Öyleyse pratikte kalalım! :)
Apostolos

6

Bu soru biraz daha eski olsa bile:

Kullanmak istiyorsanız if cond1 or cond 2- karmaşık döngüler veya bunun gibi şeyler kullanmamalısınız.

Basit bir şekilde ifsbirbiri ardına her ikisini de sağlayın goto- bu örtük veya.

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

Bir "yerinde" eylem olmadan, TÜM koşullar eşleşiyorsa, eylemi 3 kez yürütebilirsiniz.


sadece bu cevabın verildiğini fark ettim. musst bunu denetledi.
dognose

2

Hiçbir yoktur IF <arg> ORya ELIFya ELSE IFAncak Toplu İş ...

Diğer EĞER’leri önceki EĞER’in ELSE’nin içine yerleştirmeyi deneyin.

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

3
Bu, VEYA'nın iyi bir uygulaması değildir, çünkü çalıştırılacak koşullu kod her bir ELSE EĞER için çoğaltılmalıdır. (şartlı kod bir GOTO değilse, bu durumda zmbq çözümünün daha ayrıntılı bir biçimine sahip olursunuz.)
dbenham

2

VEYA mantığını değerlendiren ve tek bir değer döndüren bir işlev kullanmak mümkündür.

@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, Bu işlev, sonucu ERRORLEVEL dönüş kodunda döndürmek için iyi bir adaydır. Daha sonra çağrı && ... || ..., ekstra IF ... ELSE ...ifade yerine doğrudan uygun sözdizimini kullanabilir .
dbenham

2

Hedef, IF'leri dolaylı olarak kullanarak başarılabilir.

Aşağıda, tutarlı olmayan etiketler ve GOTO'lar olmadan bir CMD partisinde oldukça kısa ve mantıklı bir şekilde yazılabilen karmaşık bir ifade örneği bulunmaktadır.

Parantez () arasındaki kod blokları CMD tarafından (acıklı) bir alt kabuk türü olarak ele alınır. Bir bloktan çıkan çıkış kodu ne olursa olsun, bloğun daha büyük bir boole ifadesinde oynadığı doğru / yanlış değeri belirlemek için kullanılacaktır. Bu kod blokları ile rastgele büyük boole ifadeleri oluşturulabilir.

Basit örnek

Her blok, tüm ifadenin değeri belirlenene veya kontrol atlayana kadar (örn. GOTO aracılığıyla) doğru (yani, bloktaki son ifade çalıştırıldıktan sonra ERRORLEVEL = 0) / yanlış olarak çözümlenir:

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

Karmaşık örnek

Bu, başlangıçta ortaya çıkan sorunu çözer. Her blokta birden fazla ifade mümkündür, ancak || || || ifade mümkün olduğunca okunabilir olması için kısa ve öz olması tercih edilir. ^, CMD toplu işlerinde bir kaçış karakteridir ve bir satırın sonuna yerleştirildiğinde EOL'den kaçar ve CMD'ye bir sonraki satırdaki geçerli deyim grubunu okumaya devam etmesini söyler.

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

Bu, birden çok değişkenin eşit değer olup olmadığını kontrol etmek içindir. Her iki değişken için burada.

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

Sadece kafamın üstünden düşündüm. Daha fazla sıkıştırabilirim.


1

Bu sorunun eski olduğunun farkındayım, ancak başka birinin (benim gibi) aynı soruyu sorarken bu konuyu bulması durumunda alternatif bir çözüm göndermek istedim. Değişkeni yankılayarak ve doğrulamak için findstr kullanarak bir OR operatörü eksikliğinden kaçınabildim.

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

1

Dbenham'ın cevabı oldukça iyi IF DEFINEDolsa da, kontrol ettiğiniz değişken bir ortam değişkeni değilse , güvenmek sizi bir sürü belaya sokabilir . Komut dosyası değişkenleri bu özel muameleyi görmez.

Bu bazı saçma belgelenmemiş BS gibi görünse de, IFile basit bir kabuk sorgusu yapmak şunu IF /?ortaya çıkarır:

DEFINED koşulu, bir ortam değişkeni adı alması ve ortam değişkeni tanımlanmışsa true döndürmesi dışında, tıpkı EXIST gibi çalışır .

Bu soruyu cevaplamakla ilgili olarak, bir dizi değerlendirmeden sonra sadece basit bir bayrak kullanmamak için bir neden var mı? Bu OR, hem mantık hem de okunabilirlik açısından bana en esnek kontrol gibi görünüyor . Örneğin:

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)

Açıkçası, herhangi bir koşullu değerlendirme olabilirler, ancak ben sadece birkaç örnek paylaşıyorum.

Her şeyin yazılı olarak tek bir satırda olmasını istiyorsanız, bunları aşağıdaki &&gibi zincirleyebilirsiniz :

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

Asla çalışmak için var olmadı.

Yok ise kullanıyorum g: xyz / what goto h: Else xcopy c: current / files g: bu / current Değiştiriciler var / a vb. Hangileri olduğundan emin değilim. Dükkanda laptop. Ve ofiste bilgisayar. Orada değilim.

Windows XP üzerinde çalışacak toplu iş dosyaları hiç olmadı


Örneğinizde yazıldığı gibi, "yoksa g: xyz / what", xyz / g: sürücüsünün geçerli dizinine göre ne olduğu, g'nin kök klasörü olmayabilir. Burada "g: \ xyz \ ne" ye ihtiyacınız var mı? C: current / files ve g: bu / current ile aynı. Her sürücünün farklı bir geçerli klasörü olduğunu ve bu sürücü sizin geçerli çalışma dizininiz olmasa bile "hatırlandığını" unutmayın.
John Elion

0

Genelde kullandığım çok daha hızlı bir alternatif, değişken alana sığabilecek keyfi sayıda koşul "veya" yapabildiğim için aşağıdaki gibidir

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

Bunun biraz eski bir soru olduğunun farkına varmak, yanıtlar bir toplu iş dosyasında komut satırı argümanlarını test etmek için bir çözüm bulmama yardımcı oldu; Bu nedenle, başka birinin benzer bir çözüm araması durumunda çözümümü de yayınlamak istedim.

İlk belirtmem gereken şey, IF ... ELSE ifadelerinin bir FOR ... DO cümlesinin içinde çalışmasını sağlamakta sorun yaşadığımdır. ELSE ifadesinin, kapanış parantezlerinden ayrı bir satırda olamayacağı ortaya çıktı (örneklerinde istemeden bunu gösterdiği için dbenham sayesinde).

Yani bunun yerine:

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

Okunabilirlik ve estetik nedenlerle tercihim budur, bunu yapmanız gerekir:

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

Artık ELSE ifadesi tanınmayan bir komut olarak geri dönmüyor.

Son olarak, yapmaya çalıştığım şey şudur - bir toplu iş dosyasına birkaç argümanı herhangi bir sırayla iletebilmek, vakayı görmezden gelerek ve aktarılan tanımsız argümanları bildirmek / başarısız olmak istedim. İşte benim çözümüm ...

@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

Unutmayın, bu sadece ilk başarısız argümanı rapor edecektir. Dolayısıyla, eğer kullanıcı birden fazla kabul edilemez argümandan geçerse, ona sadece birincisi düzeltilene kadar, sonra ikincisi vb. Anlatılacaktır.


-1 Bu sorunun 'bir FOR döngüsünde IF sözdizimi' ile ya da bağımsız değişkenlerin düzgün bir şekilde nasıl iletileceği ile ilgisi yoktu, ancak bir toplu iş dosyasında bir If .. Veya .. If ifadesini çoğaltmanın bir yolunu bulmakla ilgisi vardı.
Mechaflash

1
Yeterince adil. Sanırım OP'nin orijinal sorusunu cevaplarken dikkatli olmak yerine bu cevapların bana yardımcı olduğu kendi sorumu cevaplıyordum. İleride daha dikkatli olacak. Teşekkürler Mechaflash! -R
RMWChaos

1
Doğası gereği benzer bir sorunuz varsa, bu soruyu kendi başınıza çözdüyseniz ve stackoverflow'da kendinizinkiyle aynı olan bir soru yoksa, bunu bir soru olarak sorabilir ve kendiniz yanıtlamak için kutuyu işaretleyebilirsiniz. Bu şekilde sitede olacak ve insanlar da buna cevap verebilir.
Mechaflash
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.