JIKA… ATAU JIKA… dalam file batch windows

97

Apakah ada cara untuk menulis pernyataan bersyarat JIKA ATAU JIKA di file batch windows?

Sebagai contoh:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE
Mechaflash
sumber
7
No Apa yang mungkin adalah dengan langsung menulis DAN: IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE. Aku digunakan untuk mendefinisikan SET AND=IFdan kemudian menulis: IF cond1 %AND% cond2 ECHO BOTH ARE TRUE.
Aacini

Jawaban:

95

Solusi zmbq bagus, tetapi tidak dapat digunakan dalam semua situasi, seperti di dalam blok kode seperti loop FOR DO (...).

Alternatifnya adalah dengan menggunakan variabel indikator. Lakukan inisialisasi agar tidak ditentukan, lalu tentukan hanya jika salah satu kondisi ATAU benar. Kemudian gunakan IF DEFINED sebagai pengujian akhir - tidak perlu menggunakan ekspansi tertunda.

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

Anda dapat menambahkan logika ELSE IF yang digunakan arasmussen dengan alasan bahwa ia mungkin bekerja sedikit lebih cepat jika kondisi 1 benar, tetapi saya tidak pernah repot.

Tambahan - Ini adalah pertanyaan duplikat dengan jawaban yang hampir identik dengan Menggunakan ATAU dalam pernyataan IF WinXP Batch Script

Adendum terakhir - Saya hampir lupa teknik favorit saya untuk menguji apakah variabel adalah salah satu dari daftar nilai tidak peka huruf besar / kecil. Inisialisasi variabel uji yang berisi daftar nilai yang dapat diterima yang dipisahkan, lalu gunakan cari dan ganti untuk menguji apakah variabel Anda ada dalam daftar. Ini sangat cepat dan menggunakan kode minimal untuk daftar yang sangat panjang. Itu memang membutuhkan perluasan yang tertunda (atau trik CALL %% VAR %%). Juga tes ini tidak sensitif terhadap kasus.

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

Di atas bisa gagal jika VAR berisi = , jadi pengujian ini bukan bukti yang bodoh.

Jika melakukan pengujian dalam blok di mana ekspansi tertunda diperlukan untuk mengakses nilai VAR saat ini

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

UNTUK opsi seperti "delims =" mungkin diperlukan bergantung pada nilai yang diharapkan dalam VAR

Strategi di atas dapat dibuat dapat diandalkan bahkan =dalam VAR dengan menambahkan lebih banyak kode.

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

Tapi sekarang kami kehilangan kemampuan untuk menyediakan klausa ELSE kecuali kami menambahkan variabel indikator. Kode mulai terlihat sedikit "jelek", tetapi saya pikir ini adalah metode yang dapat diandalkan dengan kinerja terbaik untuk pengujian jika VAR adalah salah satu dari sejumlah pilihan yang tidak peka huruf besar / kecil.

Akhirnya ada versi yang lebih sederhana yang menurut saya sedikit lebih lambat karena harus melakukan satu IF untuk setiap nilai. Aacini memberikan solusi ini dalam komentar ke jawaban yang diterima di tautan yang disebutkan sebelumnya

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

Daftar nilai tidak boleh menyertakan * atau? karakter, dan nilai dan %VAR%tidak boleh mengandung tanda kutip. Kutipan menyebabkan masalah jika %VAR%juga berisi spasi atau karakter khusus seperti ^, &dll. Satu batasan lain dengan solusi ini adalah tidak menyediakan opsi untuk klausa ELSE kecuali Anda menambahkan variabel indikator. Keuntungannya bisa peka huruf besar kecil atau tidak peka tergantung pada ada atau tidaknya /Iopsi IF .

dbenham
sumber
Sayangnya for tidak berfungsi dengan nilai yang menyertakan tanda tanya seperti FOR %% A IN (-? -H -help) karena semantik kecocokan file.
Killroy
@Kroy - ya, saya sudah mencatat batasan itu dalam jawabannya. Tetapi komentar Anda memaksa saya untuk melihat jawabannya dan menyadari ada batasan tambahan dengan solusi FOR. Saya telah memperbarui sedikit akhir jawaban.
dbenham
Bukankah echo untuk findstr menjadi pilihan?
Squashman
@Squashman - Ugh, ya, jika Anda ingin menelusuri semua bug dan kebiasaan FINDSTR.
dbenham
Jawabannya salah. Perintah yang dikaitkan dengan Aacini gagal seperti yang dikutip, tetapi berfungsi jika diedit sebagai berikut: untuk %% A di ("val1" "val2" "val3") lakukan jika "% VAR%" == %% A echo true
Ed999
54

Saya rasa tidak. Cukup gunakan dua IF dan GOTO dengan label yang sama:

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end
zmbq
sumber
Ya sejauh yang saya tahu, dua itu adalah satu-satunya pilihan.
Mechaflash
1
= D Saya sebenarnya dalam proses mempelajari PowerShell dan mengadaptasi semua skrip saya. Tetapi hanya perlu melakukan perbaikan bug kecil pada skrip batch dan ingin tahu apakah ini mungkin. Saya pilih-pilih dalam hal membersihkan kode lol
Mechaflash
1
Dalam banyak situasi, CALL mungkin lebih disukai daripada GOTO, meskipun ini hanya berfungsi jika Anda tidak membutuhkan klausa ELSE.
Harry Johnston
@HarryJohnston itu tergantung pada apakah itu hanya program / skrip top-down atau jika terstruktur untuk berjalan seolah-olah fungsi ada di batch-scripting = /. Dalam contoh ini, GOTO akan benar atau Anda akan menekan ECHO Didn't find itbahkan jika memang menemukannya.
Mechaflash
Seberapa sulit membiarkan kelelawar mendukung operator atau? Ini belum diterapkan pada 2019.
Joke Huang
8

Terima kasih untuk posting ini, itu sangat membantu saya.

Entah apakah itu dapat membantu tetapi saya memiliki masalah dan terima kasih kepada Anda, saya menemukan apa yang menurut saya adalah cara lain untuk menyelesaikannya berdasarkan persamaan boolean ini:

"A atau B" sama dengan "bukan (bukan A dan bukan B)"

Jadi:

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

Menjadi:

IF not [%var%] == [1] IF not [%var%] == [2] ECHO FALSE
Kaktus
sumber
Tetapi ini hanya menyediakan cabang FALSE (ELSE) jika tidak ada yang benar. OP menginginkan cabang TRUE jika salah satunya benar.
dbenham
8

"FOR" sederhana dapat digunakan dalam satu baris untuk menggunakan kondisi "atau":

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

Diterapkan ke kasus Anda:

FOR %%a in (1 2) DO IF %var%==%%a ECHO TRUE
Apostolos
sumber
Saya menemukan ini sebagai kasus yang paling lurus ke depan dan mudah digunakan dalam skrip batch saya. Kenapa ini tidak pernah menjadikannya sebagai jawaban yang direkomendasikan?
myusrn
Terima kasih. Entahlah, upvoting secara umum adalah proses yang sangat aneh (dan meragukan?), Tidak hanya di stackoverflow tetapi juga di forum lain. Tapi dalam kasus ini, saya rasa ini waktunya. Pertanyaannya sudah cukup lama dan jawaban saya sangat baru. Bagaimanapun, kita harus senang ketika kita dapat menemukan jawaban apa pun yang berhasil. :)
Apostolos
Salah satu kemungkinan kelemahan dengan teknik ini (meskipun saya seperti out-of-the-boxness pendekatan!) Adalah bahwa tergantung pada kondisi , itu mungkin mungkin untuk mengeksekusi perintah dua kali, yang mungkin tidak ingin.
TripeHound
Secara teoritis, ya. Tapi saya telah membuat ratusan file batch, saya menggunakan lusinan setiap hari dan saya tidak pernah menemui kasus seperti itu. Jadi mari tetap berlatih! :)
Apostolos
6

Meskipun pertanyaan ini sedikit lebih tua:

Jika Anda ingin menggunakan if cond1 or cond 2- Anda tidak boleh menggunakan loop rumit atau hal-hal seperti itu.

Sederhana menyediakan keduanya ifssetelah satu sama lain digabungkan dengan goto- itu implisit atau.

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

Tanpa pergi tetapi tindakan "di tempat", Anda dapat menjalankan tindakan 3 kali, jika SEMUA kondisi cocok.

dognose
sumber
hanya melihat jawaban ini sudah disediakan. musst telah mengawasi itu.
kenalkan
2

Tidak ada IF <arg> ORatau ELIFatauELSE IF dalam Batch, namun ...

Cobalah menumpuk IF lainnya di dalam IF sebelumnya.

IF <arg> (
    ....
) ELSE (
    IF <arg> (
        ......
    ) ELSE (
        IF <arg> (
            ....
        ) ELSE (
    )
)
Andrew Rasmussen
sumber
3
Ini bukan implementasi yang baik dari OR karena kode kondisional yang akan dieksekusi harus direplikasi untuk setiap ELSE IF. (kecuali tentu saja kode kondisionalnya adalah GOTO, dalam hal ini Anda memiliki bentuk solusi zmbq yang lebih bertele-tele.)
dbenham
2

Dimungkinkan untuk menggunakan fungsi, yang mengevaluasi logika OR dan mengembalikan satu nilai.

@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
sumber
+1, Fungsi ini adalah kandidat yang baik untuk mengembalikan hasil dalam kode pengembalian ERRORLEVEL. Kemudian panggilan tersebut dapat menggunakan && ... || ...sintaksis yang nyaman secara langsung sebagai ganti IF ... ELSE ...pernyataan tambahan .
dbenham
2

Tujuannya bisa dicapai dengan menggunakan IF secara tidak langsung.

Di bawah ini adalah contoh ekspresi kompleks yang dapat ditulis dengan cukup ringkas dan logis dalam batch CMD, tanpa label dan GOTO yang tidak koheren.

Blok kode di antara tanda kurung () ditangani oleh CMD sebagai jenis subkulit (menyedihkan). Kode keluar apa pun yang keluar dari sebuah blok akan digunakan untuk menentukan nilai benar / salah yang dimainkan blok dalam ekspresi boolean yang lebih besar. Ekspresi boolean yang sangat besar dapat dibangun dengan blok kode ini.

Contoh sederhana

Setiap blok diselesaikan menjadi benar (yaitu ERRORLEVEL = 0 setelah pernyataan terakhir dalam blok telah dieksekusi) / salah, sampai nilai seluruh ekspresi telah ditentukan atau kontrol melompat keluar (misalnya melalui GOTO):

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

Contoh yang kompleks

Ini memecahkan masalah yang awalnya diangkat. Beberapa pernyataan mungkin dilakukan di setiap blok tetapi di || || || ekspresi lebih disukai singkat sehingga dapat dibaca semaksimal mungkin. ^ adalah karakter escape dalam batch CMD dan ketika ditempatkan di akhir baris, ia akan keluar dari EOL dan menginstruksikan CMD untuk terus membaca kumpulan pernyataan saat ini di baris berikutnya.

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

Itu untuk memeriksa apakah beberapa variabel bernilai sama. Ini untuk salah satu variabel.

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

Saya hanya memikirkan itu di luar kepala saya. Saya bisa lebih memadatkannya.

titik dua
sumber
1

Saya menyadari pertanyaan ini sudah lama, tetapi saya ingin memposting solusi alternatif jika ada orang lain (seperti saya) yang menemukan utas ini saat memiliki pertanyaan yang sama. Saya dapat mengatasi kekurangan operator OR dengan menggemakan variabel dan menggunakan findstr untuk memvalidasi.

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

Meskipun jawaban dbenham cukup bagus, mengandalkan IF DEFINEDdapat membuat Anda mendapat banyak masalah jika variabel yang Anda periksa bukan variabel lingkungan . Variabel skrip tidak mendapatkan perlakuan khusus ini.

Meskipun ini mungkin tampak seperti beberapa BS tidak berdokumen yang menggelikan, melakukan kueri shell sederhana IFdengan IF /?mengungkapkan bahwa,

Kondisional DEFINED bekerja seperti ADA kecuali ia mengambil nama variabel lingkungan dan mengembalikan nilai true jika variabel lingkungan didefinisikan.

Berkenaan dengan menjawab pertanyaan ini, adakah alasan untuk tidak hanya menggunakan bendera sederhana setelah serangkaian evaluasi? Itu sepertinya pemeriksaan paling fleksibel ORbagi saya, baik dalam hal logika dan keterbacaan yang mendasarinya. Sebagai contoh:

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)

Jelas, mereka dapat berupa evaluasi bersyarat apa pun, tetapi saya hanya membagikan beberapa contoh.

Jika Anda ingin memiliki semuanya dalam satu baris, secara tertulis, Anda dapat menggabungkannya dengan &&seperti:

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
sumber
0

Tidak pernah ada untuk bekerja.

Saya menggunakan jika tidak ada g: xyz / what goto h: Lain xcopy c: current / files g: bu / current Ada pengubah / a dll. Tidak yakin yang mana. Laptop di toko. Dan komputer di kantor. Aku tidak di sana.

Tidak pernah mendapat file batch untuk bekerja di atas Windows XP

pengguna8865291
sumber
Seperti yang tertulis dalam contoh Anda, "jika tidak ada g: xyz / what", xyz / what relatif terhadap direktori saat ini dari drive g:, yang mungkin bukan folder root g. Apakah Anda membutuhkan "g: \ xyz \ what" di sini? Sama dengan c: current / files dan g: bu / current. Perhatikan bahwa setiap drive memiliki folder saat ini yang berbeda, dan "diingat" bahkan jika drive tersebut bukan direktori kerja Anda saat ini.
John Elion
0

Alternatif yang jauh lebih cepat yang biasanya saya gunakan adalah sebagai berikut, yang saya bisa "atau" sejumlah kondisi acak yang dapat muat dalam ruang variabel

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

Menyadari ini adalah pertanyaan lama, tanggapan membantu saya menemukan solusi untuk menguji argumen baris perintah ke file batch; jadi saya ingin memposting solusi saya juga jika ada orang lain yang mencari solusi serupa.

Hal pertama yang harus saya tunjukkan adalah bahwa saya mengalami masalah dalam mendapatkan pernyataan IF ... ELSE untuk bekerja di dalam klausa FOR ... DO. Ternyata (terima kasih kepada dbenham karena secara tidak sengaja menunjukkan hal ini dalam contoh-contohnya) pernyataan ELSE tidak dapat dipisahkan dari baris penutup.

Jadi, alih-alih ini:

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

Yang mana preferensi saya untuk alasan keterbacaan dan estetika, Anda harus melakukan ini:

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

Sekarang pernyataan ELSE tidak kembali sebagai perintah yang tidak dikenali.

Akhirnya, inilah yang saya coba lakukan - saya ingin menyampaikan beberapa argumen ke file batch dalam urutan apa pun, mengabaikan kasus, dan melaporkan / gagal pada argumen yang tidak ditentukan yang diteruskan. Jadi, inilah solusi saya ...

@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

Catatan, ini hanya akan melaporkan argumen pertama yang gagal. Jadi jika pengguna memberikan lebih dari satu argumen yang tidak dapat diterima, mereka hanya akan diberi tahu tentang yang pertama sampai argumen itu diperbaiki, lalu yang kedua, dll.

RMWChaos
sumber
-1 Pertanyaan ini tidak ada hubungannya dengan 'sintaks IF dalam loop FOR' atau bagaimana menyampaikan argumen dengan benar, tetapi harus dilakukan dengan menemukan cara untuk mereplikasi pernyataan If .. Atau .. If dalam file batch.
Mechaflash
1
Cukup adil. Sepertinya saya menjawab pertanyaan saya sendiri bahwa jawaban ini membantu saya daripada berhati-hati menjawab pertanyaan asli OP. Akan lebih berhati-hati di masa depan. Terima kasih Mechaflash! -R
RMWChaos
1
Jika Anda memiliki pertanyaan yang sifatnya serupa, telah memecahkan pertanyaan itu sendiri, dan tidak ada pertanyaan yang diposting di stackoverflow yang sama dengan pertanyaan Anda, Anda dapat mengajukannya sebagai pertanyaan dan mencentang kotak untuk menjawabnya sendiri. Dengan begitu, iklan akan ada di situs dan orang-orang juga dapat menanggapinya.
Mechaflash