NẾU… HOẶC NẾU… trong một tệp loạt cửa sổ


95

Có cách nào để viết câu lệnh điều kiện IF HOẶC IF trong một tệp lô cửa sổ không?

Ví dụ:

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

7
Số gì có thể là viết trực tiếp AND: IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE. Tôi sử dụng để xác định SET AND=IFvà sau đó viết: IF cond1 %AND% cond2 ECHO BOTH ARE TRUE.
Aacini

Câu trả lời:


95

Giải pháp zmbq là tốt, nhưng không thể được sử dụng trong mọi trường hợp, chẳng hạn như bên trong một khối mã như vòng lặp FOR DO (...).

Một giải pháp thay thế là sử dụng một biến chỉ số. Khởi tạo nó thành không xác định, và sau đó xác định nó chỉ khi bất kỳ một trong các điều kiện OR là đúng. Sau đó sử dụng IF DEFINED như một thử nghiệm cuối cùng - không cần sử dụng mở rộng bị trì hoãn.

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

Bạn có thể thêm logic ELSE IF mà arasmussen sử dụng với lý do rằng nó có thể hoạt động nhanh hơn một chút nếu điều kiện đầu tiên là đúng, nhưng tôi không bao giờ bận tâm.

Phụ lục - Đây là một câu hỏi trùng lặp với các câu trả lời gần giống nhau cho Sử dụng OR trong câu lệnh IF WinXP Batch Script

Phụ lục cuối cùng - Tôi gần như đã quên kỹ thuật yêu thích của mình để kiểm tra xem một biến có phải là bất kỳ một trong danh sách các giá trị không phân biệt chữ hoa chữ thường hay không. Khởi tạo một biến thử nghiệm có chứa danh sách được phân tách bằng các giá trị được chấp nhận, sau đó sử dụng tìm kiếm và thay thế để kiểm tra xem biến của bạn có nằm trong danh sách hay không. Điều này rất nhanh và sử dụng mã tối thiểu cho một danh sách dài tùy ý. Nó yêu cầu mở rộng bị trì hoãn (hoặc nếu không, thủ thuật CALL %% VAR %%). Ngoài ra, bài kiểm tra là CASE INSENSITIVE.

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

Ở trên có thể không thành công nếu VAR có chứa =, vì vậy thử nghiệm không phải là thử nghiệm đánh lừa.

Nếu thực hiện kiểm tra trong một khối nơi cần mở rộng trễ để truy cập giá trị hiện tại của VAR thì

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

Các tùy chọn FOR như "delims =" có thể cần thiết tùy thuộc vào các giá trị mong đợi trong VAR

Chiến lược trên có thể được thực hiện đáng tin cậy ngay cả với =VAR bằng cách thêm một chút mã.

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

Nhưng bây giờ chúng tôi đã mất khả năng cung cấp một mệnh đề ELSE trừ khi chúng tôi thêm một biến chỉ số. Mã đã bắt đầu trông hơi "xấu", nhưng tôi nghĩ rằng đó là phương pháp đáng tin cậy hoạt động tốt nhất để kiểm tra nếu VAR là bất kỳ một trong số các tùy chọn phân biệt chữ hoa chữ thường tùy ý.

Cuối cùng, có một phiên bản đơn giản hơn mà tôi nghĩ là hơi chậm hơn vì nó phải thực hiện một IF cho mỗi giá trị. Aacini đã cung cấp giải pháp này trong một bình luận cho câu trả lời được chấp nhận trong liên kết được đề cập trước đó

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

Danh sách các giá trị không được bao gồm dấu * hoặc? ký tự và các giá trị và %VAR%không được chứa dấu ngoặc kép. Dấu ngoặc kép dẫn đến sự cố nếu %VAR%dấu ngoặc kép cũng chứa khoảng trắng hoặc các ký tự đặc biệt như ^, &v.v. Một hạn chế khác với giải pháp này là nó không cung cấp tùy chọn cho mệnh đề ELSE trừ khi bạn thêm một biến chỉ số. Ưu điểm là nó có thể phân biệt chữ hoa chữ thường hoặc không phân biệt tùy thuộc vào sự hiện diện hoặc không có /Itùy chọn IF .


Rất tiếc là for sẽ không hoạt động với các giá trị bao gồm dấu chấm hỏi như FOR %% A IN (-? -H -help) do ngữ nghĩa đối sánh tệp.
Killroy

@Killroy - vâng, tôi đã ghi nhận hạn chế đó trong câu trả lời. Nhưng nhận xét của bạn buộc tôi phải xem câu trả lời và nhận ra rằng có những hạn chế bổ sung với giải pháp CHO. Tôi đã cập nhật phần cuối của câu trả lời một chút.
dbenham

Một tiếng vọng để tìm kiếm không phải là một lựa chọn?
Squashman

@Squashman - Ugh, vâng, nếu bạn muốn điều hướng tất cả các lỗi và điều kỳ quặc của FINDSTR.
dbenham

Câu trả lời là sai. Lệnh được gán cho Aacini không thành công như được trích dẫn, nhưng hoạt động nếu được chỉnh sửa như sau: for %% A in ("val1" "val2" "val3") do if "% VAR%" == %% A echo true
Ed999

53

Tôi không nghĩ vậy. Chỉ cần sử dụng hai IF và GOTO cùng một nhãn:

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end

Vâng, theo như tôi có thể nói hai người đó là lựa chọn duy nhất.
Mechaflash

1
= D Tôi thực sự đang trong quá trình học powershell và điều chỉnh tất cả các tập lệnh của mình. Nhưng bạn chỉ cần thực hiện một sửa lỗi nhỏ đối với tập lệnh hàng loạt và muốn biết liệu điều này có thể thực hiện được hay không. Tôi kén chọn khi nói đến lol mã sạch
Mechaflash

1
Trong nhiều trường hợp, CALL có thể thích hợp hơn GOTO, mặc dù điều này chỉ hoạt động nếu bạn không cần mệnh đề ELSE.
Harry Johnston

@HarryJohnston nó phụ thuộc vào việc nó chỉ là một chương trình / tập lệnh từ trên xuống hay nếu nó được cấu trúc để chạy như thể các chức năng tồn tại trong tập lệnh hàng loạt = /. Trong ví dụ của anh ấy, GOTO sẽ đúng nếu không bạn sẽ đánh ECHO Didn't find itngay cả khi nó tìm thấy.
Mechaflash

Khó như thế nào để dơi hỗ trợ người điều hành hoặc người vận hành? Nó vẫn chưa được triển khai vào năm 2019.
Joke Huang

8

Cảm ơn cho bài viết này, nó đã giúp tôi rất nhiều.

Dunno nếu nó có thể giúp nhưng tôi đã gặp vấn đề và nhờ bạn, tôi đã tìm thấy những gì tôi nghĩ là một cách khác để giải quyết nó dựa trên sự tương đương boolean này:

"A hoặc B" giống với "not (không phải A và không phải B)"

Như vậy:

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

Trở thành:

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

Nhưng điều này chỉ cung cấp nhánh FALSE (ELSE) nếu cả hai đều không đúng. OP muốn nhánh TRUE nếu một trong hai là true.
dbenham

8

Một "FOR" đơn giản có thể được sử dụng trong một dòng để sử dụng điều kiện "hoặc":

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

Áp dụng cho trường hợp của bạn:

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

Tôi thấy đây là trường hợp đơn giản và dễ sử dụng nhất trong các tập lệnh hàng loạt của tôi. Tại sao điều này không bao giờ khiến nó trở thành câu trả lời được khuyến nghị?
myusrn 19/09/18

Cảm ơn. Tôi không biết, ủng hộ nói chung là một quá trình rất kỳ lạ (và đáng ngờ?), Không chỉ trong stackoverflow mà còn trong các diễn đàn khác. Nhưng trong trường hợp này, tôi đoán đã đến lúc. Câu hỏi khá cũ và câu trả lời của tôi mới xuất hiện. Dù sao, chúng ta phải hạnh phúc khi chúng ta có thể tìm thấy bất kỳ câu trả lời mà làm việc. :)
Apostolos

Một nhược điểm có thể xảy ra với kỹ thuật này (mặc dù tôi thích sự khác biệt của cách tiếp cận!) Là tùy thuộc vào điều kiện , thể thực hiện lệnh hai lần, điều này có thể không được mong muốn.
TripeHound

Về mặt lý thuyết, có. Nhưng tôi đã tạo hàng trăm tệp hàng loạt, tôi sử dụng hàng chục tệp hàng ngày và tôi chưa bao giờ gặp trường hợp như vậy. Vì vậy, chúng ta hãy tiếp tục thực hành! :)
Apostolos

6

Ngay cả khi câu hỏi này cũ hơn một chút:

Nếu bạn muốn sử dụng if cond1 or cond 2- bạn không nên sử dụng các vòng lặp phức tạp hoặc những thứ như vậy.

Đơn giản cung cấp cả hai ifssau khi nhau kết hợp với goto- đó là một ẩn hoặc.

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

Không có goto mà là một hành động "tại chỗ", bạn có thể thực hiện hành động 3 lần, nếu TẤT CẢ các điều kiện đều phù hợp.


chỉ cần trích dẫn câu trả lời này đã được cung cấp. musst đã giám sát điều đó.
dognose

2

Tuy nhiên, không có IF <arg> ORhoặc ELIFhoặc ELSE IFtheo lô ...

Thử lồng IF khác bên trong ELSE của IF trước đó.

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

3
Đây không phải là một triển khai tốt của OR vì mã điều kiện được thực thi phải được sao chép cho mỗi ELSE IF. (tất nhiên trừ khi các mã có điều kiện là một GOTO, trong trường hợp bạn có một nhiều tiết hình thức giải pháp zmbq của.)
dbenham

2

Có thể sử dụng một hàm đánh giá logic OR và trả về một giá trị duy nhất.

@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, Hàm này là một ứng cử viên tốt để trả về kết quả trong mã trả về ERRORLEVEL. Sau đó, cuộc gọi có thể sử dụng && ... || ...cú pháp thuận tiện trực tiếp thay vì IF ... ELSE ...câu lệnh phụ .
dbenham

2

Mục tiêu có thể đạt được bằng cách sử dụng các IF gián tiếp.

Dưới đây là ví dụ về một biểu thức phức tạp có thể được viết khá ngắn gọn và logic trong một lô CMD, không có nhãn và GOTO không mạch lạc.

Các khối mã giữa () ngoặc được CMD xử lý như một loại vỏ con (thảm hại). Bất kỳ mã thoát nào xuất phát từ một khối sẽ được sử dụng để xác định giá trị true / false mà khối đóng trong một biểu thức boolean lớn hơn. Các biểu thức boolean lớn tùy ý có thể được xây dựng bằng các khối mã này.

Ví dụ đơn giản

Mỗi khối được giải quyết thành true (tức là ERRORLEVEL = 0 sau khi câu lệnh cuối cùng trong khối được thực thi) / false, cho đến khi giá trị của toàn bộ biểu thức đã được xác định hoặc điều khiển nhảy ra (ví dụ: thông qua GOTO):

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

Ví dụ phức tạp

Điều này giải quyết vấn đề được nêu ra ban đầu. Có thể có nhiều câu lệnh trong mỗi khối nhưng trong dấu || || || diễn đạt tốt hơn nên ngắn gọn để dễ đọc nhất có thể. ^ là một ký tự thoát trong lô CMD và khi được đặt ở cuối dòng, nó sẽ thoát khỏi EOL và hướng dẫn CMD tiếp tục đọc lô câu lệnh hiện tại ở dòng tiếp theo.

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

Đó là để kiểm tra xem nhiều biến có giá trị bằng nhau hay không. Đây là cho một trong hai biến.

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

Tôi chỉ nghĩ về điều đó khỏi đầu nếu đầu của tôi. Tôi có thể thu gọn nó nhiều hơn.


1

Tôi nhận ra câu hỏi này đã cũ, nhưng tôi muốn đăng một giải pháp thay thế trong trường hợp bất kỳ ai khác (như tôi) tìm thấy chủ đề này trong khi có cùng câu hỏi. Tôi đã có thể khắc phục việc thiếu toán tử OR bằng cách lặp lại biến và sử dụng findstr để xác thực.

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

1

Mặc dù câu trả lời của dbenham khá hay, nhưng việc dựa vào IF DEFINEDcó thể khiến bạn gặp vô số rắc rối nếu biến bạn đang kiểm tra không phải là biến môi trường . Các biến tập lệnh không được xử lý đặc biệt này.

Mặc dù điều này có vẻ giống như một số BS không có giấy tờ lố bịch, nhưng thực hiện một truy vấn shell đơn giản IFvới with IF /?cho thấy rằng,

Điều kiện DEFINED hoạt động giống như EXIST ngoại trừ nó nhận một tên biến môi trường và trả về true nếu biến môi trường được xác định.

Liên quan đến việc trả lời câu hỏi này, có lý do gì để không chỉ sử dụng một lá cờ đơn giản sau một loạt các đánh giá? Đó dường như là cách ORkiểm tra linh hoạt nhất đối với tôi, cả về logic cơ bản và khả năng đọc. Ví dụ:

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)

Rõ ràng, chúng có thể là bất kỳ loại đánh giá có điều kiện nào, nhưng tôi chỉ chia sẻ một vài ví dụ.

Nếu bạn muốn có tất cả trên một dòng, thông minh bằng văn bản, bạn có thể chuỗi chúng lại với nhau bằng cách &&như:

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

Không bao giờ tồn tại để làm việc.

Tôi sử dụng nếu không tồn tại g: xyz / what goto h: Khác xcopy c: current / files g: bu / current Có bổ ngữ / a, v.v. Không chắc cái nào. Máy tính xách tay tại cửa hàng. Và máy tính trong văn phòng. Tôi không có ở đó.

Không bao giờ có tệp hàng loạt hoạt động trên Windows XP


Như đã viết trong ví dụ của bạn, "nếu không tồn tại g: xyz / what", xyz / là gì liên quan đến thư mục hiện tại của ổ g:, có thể không phải là thư mục gốc của g. Bạn có cần "g: \ xyz \ what" ở đây không? Tương tự với c: current / files và g: bu / current. Lưu ý rằng mỗi ổ có một thư mục hiện tại khác nhau và nó được "ghi nhớ" ngay cả khi ổ đó không phải là thư mục làm việc hiện tại của bạn.
John Elion

0

Một giải pháp thay thế nhanh hơn nhiều mà tôi thường sử dụng như sau, vì tôi có thể "hoặc" một số điều kiện tùy ý có thể phù hợp với không gian biến đổi

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

Nhận thấy đây là một câu hỏi hơi cũ, các câu trả lời đã giúp tôi đưa ra giải pháp để kiểm tra các đối số dòng lệnh cho một tệp loạt; vì vậy tôi cũng muốn đăng giải pháp của mình trong trường hợp có ai khác đang tìm kiếm giải pháp tương tự.

Điều đầu tiên mà tôi nên chỉ ra là tôi đã gặp khó khăn khi đưa các câu lệnh IF ... ELSE hoạt động bên trong mệnh đề FOR ​​... DO. Hóa ra (cảm ơn dbenham đã vô tình chỉ ra điều này trong các ví dụ của anh ấy) câu lệnh ELSE không thể nằm trên một dòng riêng biệt với các parens đóng.

Vì vậy, thay vì điều này:

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

Sở thích của tôi vì lý do dễ đọc và thẩm mỹ, bạn phải làm điều này:

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

Bây giờ câu lệnh ELSE không trả về như một lệnh không được công nhận.

Cuối cùng, đây là những gì tôi đang cố gắng thực hiện - tôi muốn có thể chuyển một số đối số vào một tệp hàng loạt theo bất kỳ thứ tự nào, bỏ qua chữ hoa chữ thường và báo cáo / không thành công trên các đối số không xác định được truyền vào. Vì vậy, đây là giải pháp của tôi ...

@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

Lưu ý, điều này sẽ chỉ báo cáo về đối số không thành công đầu tiên. Vì vậy, nếu người dùng chuyển nhiều hơn một đối số không được chấp nhận, họ sẽ chỉ được thông báo về đối số đầu tiên cho đến khi nó được sửa, sau đó là đối số thứ hai, v.v.


-1 Câu hỏi này không liên quan gì đến 'cú pháp IF trong vòng lặp FOR' cũng như cách chuyển đối số đúng cách, nhưng liên quan đến việc khám phá cách sao chép câu lệnh If .. Hoặc .. If trong một tệp loạt.
Mechaflash

1
Đủ công bằng. Đoán rằng tôi đang trả lời câu hỏi của chính mình mà những câu trả lời này giúp ích cho tôi thay vì cẩn thận trả lời câu hỏi ban đầu của OP. Sẽ cẩn thận hơn trong tương lai. Cảm ơn Mechaflash! -R
RMWChaos

1
Nếu bạn có một câu hỏi có tính chất tương tự, đã tự mình giải quyết câu hỏi đó và không có câu hỏi nào được đăng trên stackoverflow giống với câu hỏi của bạn, bạn có thể đặt nó như một câu hỏi và chọn hộp để tự trả lời. Bằng cách đó, nó sẽ có trên trang web và mọi người cũng có thể phản hồi nó.
Mechaflash
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.