Làm thế nào để kiểm tra tham số dòng lệnh trong tệp “.bat”?


103

Hệ điều hành của tôi là Windows Vista. Tôi cần có tệp ".bat" để kiểm tra xem người dùng có nhập bất kỳ tham số dòng lệnh nào hay không. Nếu có thì nếu tham số bằng -bthì tôi sẽ làm gì đó nếu không tôi sẽ gắn cờ "Đầu vào không hợp lệ". Nếu người dùng không nhập bất kỳ tham số dòng lệnh nào thì tôi sẽ làm gì đó. Tôi đã tạo tệp .bat sau. Nó hoạt động cho -bvà không bình đẳng với -bcác trường hợp - nhưng nó không thành công khi người dùng không chuyển bất kỳ tham số dòng lệnh nào.

Tôi luôn gặp lỗi:

GOTO was unexpected at this time.

Bất cứ ai có thể cho tôi biết tôi đang làm gì sai ở đây?


ECHO OFF
CLS
ECHO.

IF [%1]==[/?] GOTO BLANK

IF %1=="-b" GOTO SPECIFIC

IF NOT %1=="-b" GOTO UNKNOWN

:SPECIFIC

ECHO SPECIFIC

GOTO DONE

:BLANK

ECHO No Parameter

GOTO DONE

:UNKNOWN

ECHO Unknown Option

GOTO DONE

:DONE

ECHO Done!

Nếu bạn thêm dấu ngoặc (như trong GOTO BLANKdòng) vào hai IFcâu lệnh còn lại, điều đó có khắc phục được sự cố không?
Jeremiah Willcock

Câu trả lời:


141

Bạn cần kiểm tra xem tham số có trống không: if "%~1"=="" goto blank

Khi bạn đã hoàn thành việc đó, hãy thực hiện chuyển đổi if / else trên -b: if "%~1"=="-b" (goto specific) else goto unknown

Bao quanh các tham số bằng dấu ngoặc kép giúp kiểm tra những thứ như tham số trống / trống / thiếu dễ dàng hơn. "~" đảm bảo dấu ngoặc kép được loại bỏ nếu chúng nằm trên đối số dòng lệnh.


Những công việc này!! Chỉ "khác" là không được chấp nhận. Tôi gặp lỗi: 'else' không được nhận dạng là lệnh nội bộ hoặc lệnh bên ngoài, chương trình có thể hoạt động hoặc tệp hàng loạt. Vì vậy, tôi đã thêm một IF khác cho trường hợp "không bằng -b". Cảm ơn vì sớm phản hồi.
javauser71

7
ELSE phải nằm trên cùng một dòng với IF hoặc nó phải nằm ngay sau một dấu ngoặc
jeb

4
Điều này dường như không hiệu quả với tôi nếu% 1 chứa khoảng trắng, có thể xảy ra trường hợp này nếu nó là đường dẫn đầy đủ đến tệp thực thi. Xem câu trả lời của Jeremiah Willcock để biết giải pháp hoạt động ngay cả với các tham số có khoảng trắng trong giá trị của chúng.
Mark A. Fitzgerald

nó sẽ không được chấp nhận nếu đối số của bạn là a File, trong trường hợp đó bạn chỉ nên kiểm tra existhoặc not exist. Đây là lý do tại sao lập luận của bạn phải được xác định rõ ràng, hoặc đơn giản là sử dụng PowerShell hoặc VBScript (nếu bạn đang ở 80 của ..)

1
Điều này không thành công cho run.bat "a b". "%1"==""sụp đổ nếu đối số có khoảng trắng. Xem stackoverflow.com/a/46942471
Wisbucky

27

Hãy xem http://ss64.com/nt/if.html để biết câu trả lời; lệnh này IF [%1]==[] GOTO NO_ARGUMENThoặc tương tự.


1
Không chỉ điều này CŨNG hoạt động! Nó chỉ hoạt động, trái ngược với "%1"=="". Tôi phải nói rõ hơn về điều đó trong câu trả lời của riêng tôi.
Tomasz Gandor,

1
điều này sẽ bị phá vỡ khi% 1 được trích dẫn, ví dụ foo.bat "1st parameter" 2nd_param. Xem stackoverflow.com/questions/2541767/…
matt wilkie

Việc sử dụng [%1]==[-b]sẽ không phù hợp nếu arg được trích dẫn. Ví dụ run.bat "-b". Xem stackoverflow.com/a/46942471
Wisbucky

20

Câu trả lời ngắn gọn - sử dụng dấu ngoặc vuông:

if [%1]==[] goto :blank

hoặc (khi bạn cần xử lý các args được trích dẫn, hãy xem Chỉnh sửa bên dưới):

if [%~1]==[] goto :blank

Tại sao? bạn có thể hỏi. Vâng, đúng như Jeremiah Willcock đã đề cập: http://ss64.com/nt/if.html - họ sử dụng điều đó! OK, nhưng có gì sai với dấu ngoặc kép?

Một lần nữa, câu trả lời ngắn gọn: chúng rất "kỳ diệu" - đôi khi dấu ngoặc kép (kép) được chuyển đổi thành báo giá đơn (kép). Và họ cần phải phù hợp để bắt đầu.

Hãy xem xét kịch bản nhỏ này:

@rem argq.bat
@echo off

:loop 
if "%1"=="" goto :done
echo %1
shift
goto :loop

:done
echo Done.

Hãy kiểm tra nó:

C:\> argq bla bla
bla
bla
Done.

Có vẻ hiệu quả. Nhưng bây giờ, hãy chuyển sang thiết bị thứ hai:

C:\> argq "bla bla"
bla""=="" was unexpected at this time.

Boom Điều này không đánh giá đúng, cũng không đánh giá sai. Kịch bản ĐÃ CHẾT. Nếu bạn được cho là phải tắt lò phản ứng ở đâu đó dưới dây, thì - thật may mắn. Bây giờ bạn sẽ chết như Harry Daghlian.

Bạn có thể nghĩ - OK, các đối số không được chứa dấu ngoặc kép. Nếu họ làm vậy, điều này sẽ xảy ra. Sai Đây là một số an ủi:

C:\> argq ""bla bla""
""bla
bla""
Done.

Ồ vâng. Đừng lo lắng - đôi khi điều này sẽ hiệu quả.

Hãy thử một tập lệnh khác:

@rem args.bat
@echo off

:loop 
if [%1]==[] goto :done
echo %1
shift
goto :loop

:done
echo Done.

Bạn có thể tự kiểm tra xem nó hoạt động tốt cho các trường hợp trên. Điều này là hợp lý - dấu ngoặc kép không liên quan gì đến dấu ngoặc, vì vậy không có phép thuật nào ở đây. Nhưng những gì về spicing args lên với dấu ngoặc?

D:\>args ]bla bla[
]bla
bla[
Done.

D:\>args [bla bla]
[bla
bla]
Done.

Không có may mắn ở đó. Dấu ngoặc đơn không thể nghẹt thởcmd.exe trình phân tích cú pháp.

Chúng ta hãy quay trở lại những câu trích dẫn độc ác một chút. Vấn đề là ở đó, khi cuộc tranh luận kết thúc bằng một câu trích dẫn:

D:\>argq "bla1 bla2"
bla2""=="" was unexpected at this time.

Điều gì sẽ xảy ra nếu tôi chỉ vượt qua:

D:\>argq bla2"
The syntax of the command is incorrect.

Tập lệnh hoàn toàn không chạy. Tương tự cho args.bat:

D:\>args bla2"
The syntax of the command is incorrect.

Nhưng tôi nhận được gì, khi số "ký tự-ký tự "khớp" (tức là - là số chẵn), trong trường hợp như vậy:

D:\>args bla2" "bla3
bla2" "bla3
Done.

ĐẸP - Tôi hy vọng bạn đã học được điều gì đó về cách .batcác tệp phân chia các đối số dòng lệnh của chúng (GỢI Ý: * Nó không chính xác như trong bash). Đối số trên chứa một khoảng trắng. Nhưng các dấu ngoặc kép không tự động bị loại bỏ.

Và argq? Làm thế nào nó phản ứng với điều đó? Có thể đoán trước:

D:\>argq bla2" "bla3
"bla3"=="" was unexpected at this time.

Vì vậy - hãy suy nghĩ trước khi bạn nói: "Biết gì không? Chỉ cần sử dụng dấu ngoặc kép. [Bởi vì, với tôi, điều này trông đẹp hơn]".

Biên tập

Gần đây, đã có những nhận xét về câu trả lời này - tốt, dấu ngoặc vuông "không thể xử lý" chuyển các đối số được trích dẫn và xử lý chúng như thể chúng không được trích dẫn.

Cú pháp:

if "%~1"=="" (...)

Không phải là một số tính năng mới được tìm thấy của dấu ngoặc kép, mà là sự thể hiện một tính năng gọn gàng của việc loại bỏ dấu ngoặc kép khỏi biến đối số, nếu ký tự đầu tiên và cuối cùng là dấu ngoặc kép.

"Công nghệ" này hoạt động tốt với dấu ngoặc vuông:

if [%~1]==[] (...)

Đó là một điều hữu ích khi chỉ ra điều này, vì vậy tôi cũng ủng hộ câu trả lời mới.

Cuối cùng, những người hâm mộ dấu ngoặc kép, một đối số dạng này ""có tồn tại trong sách của bạn không, hay nó trống? Chỉ là hỏi thế thôi' ;)


1
Dấu ngoặc vuông [%1]==[-b]sẽ không khớp nếu đối số được trích dẫn như run.bat "-b". Xem stackoverflow.com/a/46942471
Wisbucky

Lưu ý về lịch sử: [%1]==[-b]"%1"=="-b"tập lệnh lô hệ thống MS / PC-DOS của win 98 trở về trước cũng vậy. Kể từ khi win 2000 / NT giới thiệu cú pháp if "%~1"=="-b"trong đó dấu ngoặc kép có ý nghĩa đặc biệt, đó là cách bạn nên viết mã script vì nó cung cấp khả năng bảo vệ mạnh mẽ hơn. Dấu ngoặc kép thoát khỏi ý nghĩa của các ký tự đặc biệt (ký tự thử & | và% trong dòng lệnh của bạn). 99,9% các ví dụ hoạt động với cú pháp dấu ngoặc kép - ví dụ của bạn argq bla2" "bla3là trường hợp duy nhất để căn các dấu ngoặc vuông. Dấu ngoặc kép được nhúng là một công thức cho thảm họa - chỉ cần sayin '
Bỏ qua R

@SkipR - đó là lý do tại sao trong hệ thống tệp của Windows, bạn không thể có các ký tự đặc biệt này trong tên. Tôi không có bằng chứng toán học, nhưng tôi nghĩ rằng KHÔNG đơn giản là mọi thứ đều có thể được trích dẫn (theo nghĩa - được thực hiện nguyên văn thông qua một chuỗi thoát nào đó, v.v.) trong cmdshell. Trong các hệ thống khác, đôi khi bạn có thể trích dẫn mọi thứ, bao gồm cả ký tự NUL. ( stackoverflow.com/questions/2730732/… ) - câu hỏi này chỉ cho thấy, bạn cần sử dụng một số chương trình bên ngoài.
Tomasz Gandor

8

Ngoài các câu trả lời khác mà tôi đăng ký, bạn có thể xem xét sử dụng công /Itắc của IFlệnh.

... công tắc / I, nếu được chỉ định, nói để thực hiện so sánh chuỗi phân biệt chữ hoa chữ thường.

nó có thể hữu ích nếu bạn muốn cung cấp sự linh hoạt không phân biệt chữ hoa chữ thường cho người dùng của mình để chỉ định các tham số.

IF /I "%1"=="-b" GOTO SPECIFIC

5

Bạn đang so sánh các chuỗi. Nếu một đối số bị bỏ qua, %1mở rộng thành một khoảng trống để các lệnh trở thành IF =="-b" GOTO SPECIFICví dụ (đó là một lỗi cú pháp). Đặt chuỗi của bạn trong dấu ngoặc kép (hoặc dấu ngoặc vuông).

REM this is ok
IF [%1]==[/?] GOTO BLANK

REM I'd recommend using quotes exclusively
IF "%1"=="-b" GOTO SPECIFIC

IF NOT "%1"=="-b" GOTO UNKNOWN

IF [% 1] == [/?] Không hoạt động nhưng của tôi IF [% 1] == [] hoặc "% 1" == "", thì nó hoạt động. Dù sao bây giờ tôi có thể bắt đầu. Cảm ơn cho phản ứng nhanh chóng của bạn.
javauser71

5

Trên thực tế, tất cả các câu trả lời khác đều có sai sót. Cách đáng tin cậy nhất là:

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

Giải thích chi tiết:

Việc sử dụng "%1"=="-b"sẽ không xảy ra sự cố nếu truyền đối số có dấu cách và dấu ngoặc kép. Đây là phương pháp kém tin cậy nhất.

IF "%1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "a b"

b""=="-b" was unexpected at this time.

Sử dụng [%1]==[-b]sẽ tốt hơn vì nó sẽ không bị lỗi với dấu cách và dấu ngoặc kép, nhưng nó sẽ không khớp nếu đối số được bao quanh bởi dấu ngoặc kép.

IF [%1]==[-b] (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "-b"

(does not match, and jumps to UNKNOWN instead of SPECIFIC)

Sử dụng "%~1"=="-b"là đáng tin cậy nhất. %~1sẽ loại bỏ các dấu ngoặc kép xung quanh nếu chúng tồn tại. Vì vậy, nó hoạt động có và không có dấu ngoặc kép, và cũng không có args.

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat
C:\> run.bat -b
C:\> run.bat "-b"
C:\> run.bat "a b"

(all of the above tests work correctly)

1
Đây không phải là phần cuối của dấu ngoặc vuông, bạn thấy: IF [%~1]==[]- điều này hoạt động, và nó thậm chí còn xử lý được "-b". Bạn chỉ cần có thể suy nghĩ bên trong hộp, ờm, hình vuông [dấu ngoặc vuông].
Tomasz Gandor

3

Gần đây, tôi đã phải vật lộn với việc triển khai các công tắc tham số phức tạp trong một tệp loạt, vì vậy đây là kết quả nghiên cứu của tôi. Không có câu trả lời nào được cung cấp là hoàn toàn an toàn, ví dụ:

"%1"=="-?" sẽ không khớp nếu tham số được đặt trong dấu ngoặc kép (cần cho tên tệp, v.v.) hoặc sẽ bị lỗi nếu tham số nằm trong dấu ngoặc kép và có khoảng trắng (một lần nữa thường thấy trong tên tệp)

@ECHO OFF
SETLOCAL
echo.
echo starting parameter test...
echo.
rem echo First parameter is %1
if "%1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)
C:\>test.bat -?

starting parameter test...

Condition is true, param=-?

C:\>test.bat "-?"

starting parameter test...

Condition is false, param="-?"

Bất kỳ kết hợp nào có dấu ngoặc vuông [%1]==[-?]hoặc [%~1]==[-?]sẽ không thành công trong trường hợp tham số có khoảng trắng trong dấu ngoặc kép:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if [%~1]==[-?] (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat "long file name"

starting parameter test...

First parameter is "long file name"
file was unexpected at this time.

Giải pháp an toàn nhất được đề xuất "%~1"=="-?"sẽ gặp sự cố với một tham số phức tạp bao gồm văn bản bên ngoài dấu ngoặc kép và văn bản có dấu cách trong dấu ngoặc kép:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if "%~1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat -source:"long file name"

starting parameter test...

First parameter is -source:"long file name"
file was unexpected at this time.

Cách duy nhất để đảm bảo tất cả các trường hợp trên được bao phủ là sử dụng EnableDelayedExpansion và chuyển các tham số theo tham chiếu (không phải theo giá trị) bằng cách sử dụng các biến. Sau đó, ngay cả kịch bản phức tạp nhất cũng sẽ hoạt động tốt:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
echo.
echo starting parameter test...
echo.
echo First parameter is %1
:: we assign the parameter to a variable to pass by reference with delayed expansion
set "var1=%~1"
echo var1 is !var1!
:: we assign the value to compare with to a second variable to pass by reference with delayed expansion
set "var2=-source:"c:\app images"\image.png"
echo var2 is !var2!
if "!var1!"=="!var2!" (echo Condition is true, param=!var1!) else (echo Condition is false, param=!var1!)
C:\>test.bat -source:"c:\app images"\image.png

starting parameter test...

First parameter is -source:"c:\app images"\image.png
var1 is -source:"c:\app images"\image.png
var2 is -source:"c:\app images"\image.png
Condition is true, param=-source:"c:\app images"\image.png

C:\>test.bat -source:"c:\app images"\image1.png

starting parameter test...

First parameter is -source:"c:\app images"\image1.png
var1 is -source:"c:\app images"\image1.png
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images"\image1.png

C:\>test.bat -source:"c:\app images\image.png"

starting parameter test...

First parameter is -source:"c:\app images\image.png"
var1 is -source:"c:\app images\image.png"
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images\image.png"

0

Lô Windows có từ khóa DEFINED để thực hiện việc này.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar

Cảm ơn bạn David. Tôi không biết tại sao không có dấu xuống dòng và dòng mới giữa IF và IF NOT. Tôi thậm chí còn không nhận thấy.
Charles
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.