วิธีตรวจสอบพารามิเตอร์บรรทัดคำสั่งในไฟล์“ .bat”


104

ระบบปฏิบัติการของฉันคือ Windows Vista ฉันต้องมีไฟล์ ".bat" ซึ่งฉันต้องตรวจสอบว่าผู้ใช้ป้อนพารามิเตอร์บรรทัดคำสั่งหรือไม่ หากเป็นเช่นนั้นหากพารามิเตอร์เท่ากับ-bฉันจะทำบางอย่างไม่เช่นนั้นฉันจะตั้งค่าสถานะ "อินพุตไม่ถูกต้อง" หากผู้ใช้ไม่ได้ป้อนพารามิเตอร์บรรทัดคำสั่งฉันจะทำบางอย่าง ฉันได้สร้างไฟล์. bat ต่อไปนี้ มันใช้งาน-bได้และไม่เท่ากับ-bเคส - แต่จะล้มเหลวเมื่อผู้ใช้ไม่ส่งผ่านพารามิเตอร์บรรทัดคำสั่งใด ๆ

ฉันมักจะได้รับข้อผิดพลาด:

GOTO was unexpected at this time.

ใครช่วยบอกทีว่าฉันทำอะไรผิดที่นี่?


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!

หากคุณเพิ่มวงเล็บ (เช่นในGOTO BLANKบรรทัด) ให้กับอีกสองIFคำสั่งนั้นจะช่วยแก้ปัญหาได้หรือไม่
Jeremiah Willcock

คำตอบ:


141

คุณต้องตรวจสอบว่าพารามิเตอร์ว่างเปล่า: if "%~1"=="" goto blank

เมื่อคุณทำเสร็จแล้วให้เปิด if / else -b: if "%~1"=="-b" (goto specific) else goto unknown

การล้อมรอบพารามิเตอร์ด้วยเครื่องหมายคำพูดทำให้การตรวจสอบสิ่งต่างๆเช่นพารามิเตอร์ว่าง / ว่าง / ขาดหายได้ง่ายขึ้น "~" ช่วยให้มั่นใจว่าเครื่องหมายคำพูดคู่จะถูกตัดออกหากอยู่ในอาร์กิวเมนต์บรรทัดคำสั่ง


งานนี้ !! ไม่ยอมรับเฉพาะ "else" เท่านั้น ฉันได้รับข้อผิดพลาด: ไม่รู้จัก 'else' เป็นคำสั่งภายในหรือภายนอกโปรแกรมที่ใช้งานได้หรือไฟล์แบตช์ ดังนั้นฉันจึงเพิ่ม IF อื่นสำหรับกรณี "ไม่เท่ากับ -b" ขอบคุณสำหรับคำตอบด่วน
javauser71

7
ELSE จะต้องอยู่ในบรรทัดเดียวกับ IF หรือต้องอยู่หลังวงเล็บโดยตรง
jeb

4
ดูเหมือนจะไม่ได้ผลสำหรับฉันถ้า% 1 มีช่องว่างซึ่งอาจเป็นเช่นนั้นหากเป็นเส้นทางแบบเต็มไปยังไฟล์ปฏิบัติการ ดูคำตอบของ Jeremiah Willcockสำหรับโซลูชันที่ใช้ได้แม้กระทั่งกับพารามิเตอร์ที่มีช่องว่างในค่า
Mark A. Fitzgerald

มันจะไม่ได้รับการยอมรับถ้าอาร์กิวเมนต์ของคุณเป็นFileในกรณีที่คุณควรจะได้รับการตรวจสอบเท่านั้นหรือexist not existนี่คือเหตุผลที่อาร์กิวเมนต์ของคุณควรได้รับการกำหนดไว้อย่างชัดเจนหรือใช้ powershell หรือ vbScript (ถ้าคุณอยู่ในยุค 80 ... )

1
สิ่งนี้ล้มเหลวสำหรับrun.bat "a b". "%1"==""ขัดข้องหากอาร์กิวเมนต์มีช่องว่าง ดูstackoverflow.com/a/46942471
wisbucky

27

ดูคำตอบที่http://ss64.com/nt/if.html คำสั่งIF [%1]==[] GOTO NO_ARGUMENTเหมือนหรือคล้ายกัน


1
สิ่งนี้ไม่เพียง แต่ใช้งานได้! มันใช้งานได้ตรงกันข้ามกับ"%1"=="". ฉันต้องอธิบายอย่างละเอียดในคำตอบของตัวเอง
Tomasz Gandor

1
นี้จะทำลายเมื่อ% 1 foo.bat "1st parameter" 2nd_paramจะยกมาเช่น ดูstackoverflow.com/questions/2541767/…
matt wilkie

การใช้[%1]==[-b]จะไม่ตรงกันหากอ้างอาร์กิวเมนต์ ตัวอย่างrun.bat "-b". ดูstackoverflow.com/a/46942471
wisbucky

20

คำตอบสั้น ๆ - ใช้วงเล็บเหลี่ยม:

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

หรือ (เมื่อคุณต้องการจัดการอาร์กิวเมนต์ให้ดูแก้ไขด้านล่าง):

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

ทำไม? คุณอาจถาม ก็อย่างที่ Jeremiah Willcock กล่าวไว้: http://ss64.com/nt/if.html - พวกเขาใช้สิ่งนั้น! ตกลง แต่มีอะไรผิดปกติกับเครื่องหมายคำพูด?

อีกครั้งคำตอบสั้น ๆ : พวกเขา "มีมนต์ขลัง" - บางครั้งเครื่องหมายคำพูดคู่ (คู่) จะถูกแปลงเป็นเครื่องหมายคำพูดเดี่ยว (คู่) และพวกเขาต้องจับคู่เพื่อเริ่มต้น

พิจารณาสคริปต์เล็ก ๆ นี้:

@rem argq.bat
@echo off

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

:done
echo Done.

มาทดสอบกัน:

C:\> argq bla bla
bla
bla
Done.

ดูเหมือนจะได้ผล แต่ตอนนี้ให้เปลี่ยนไปใช้เกียร์สอง:

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

Boomสิ่งนี้ไม่ได้ประเมินว่าเป็นจริงและไม่ได้ประเมินว่าเป็นเท็จ สคริปต์ตาย ถ้าคุณควรจะปิดเครื่องปฏิกรณ์ตรงไหนสักแห่งก็โชคดี ตอนนี้คุณจะตายเหมือน Harry Daghlian

คุณอาจคิดว่า - โอเคอาร์กิวเมนต์ต้องไม่มีเครื่องหมายคำพูด หากเป็นเช่นนั้นสิ่งนี้จะเกิดขึ้น ผิดนี่คือคำปลอบใจ:

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

โอ้ใช่. ไม่ต้องกังวล - บางครั้งนี้ประสงค์การทำงาน

ลองใช้สคริปต์อื่น:

@rem args.bat
@echo off

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

:done
echo Done.

คุณสามารถทดสอบตัวเองได้ว่าใช้งานได้ดีสำหรับกรณีข้างต้น นี่เป็นตรรกะ - คำพูดไม่มีส่วนเกี่ยวข้องกับวงเล็บดังนั้นจึงไม่มีเวทมนตร์ที่นี่ แต่สิ่งที่เกี่ยวกับการพ่นอาร์กอนด้วยวงเล็บ?

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

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

ไม่มีโชคที่นั่น วงเล็บไม่สามารถทำให้หายใจไม่ออกcmd.exeของตัวแยกวิเคราะห์

ขอกลับไปที่คำพูดชั่วร้ายสักครู่ ปัญหาอยู่ที่นั่นเมื่ออาร์กิวเมนต์จบลงด้วยการอ้าง:

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

จะเกิดอะไรขึ้นถ้าฉันผ่านเพียง:

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

สคริปต์จะไม่ทำงานเลย เหมือนกันสำหรับargs.bat:

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

แต่ฉันจะได้อะไรเมื่อจำนวน - ตัวอักษร""ตรงกัน" (เช่น - เท่ากัน) ในกรณีเช่นนี้:

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

ดี - ฉันหวังว่าคุณจะได้เรียนรู้บางอย่างเกี่ยวกับวิธีที่.batไฟล์แยกอาร์กิวเมนต์บรรทัดคำสั่ง (คำแนะนำ: * มันไม่เหมือนกับใน bash) อาร์กิวเมนต์ด้านบนมีช่องว่าง แต่คำพูดจะไม่ถูกตัดออกโดยอัตโนมัติ

และ argq? มันมีปฏิกิริยาอย่างไร? คาดเดาได้:

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

ดังนั้น - คิดก่อนที่จะพูดว่า: "รู้อะไรไหมเพียงแค่ใช้เครื่องหมายคำพูด [เพราะสำหรับฉันสิ่งนี้ดูดีกว่า]"

แก้ไข

เมื่อเร็ว ๆ นี้มีความคิดเห็นเกี่ยวกับคำตอบนี้เช่นกันวงเล็บเหลี่ยม "ไม่สามารถจัดการได้" โดยส่งข้อโต้แย้งที่ยกมาและปฏิบัติกับพวกเขาราวกับว่าพวกเขาไม่ได้ยกมา

ไวยากรณ์:

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

ไม่ใช่คุณสมบัติที่พบใหม่ของเครื่องหมายคำพูดคู่ แต่เป็นการแสดงคุณสมบัติที่เป็นระเบียบของการตัดเครื่องหมายคำพูดจากตัวแปรอาร์กิวเมนต์หากอักขระตัวแรกและตัวสุดท้ายเป็นเครื่องหมายคำพูดคู่

"เทคโนโลยี" นี้ใช้ได้ดีกับวงเล็บเหลี่ยม:

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

มันเป็นสิ่งที่มีประโยชน์ที่จะชี้ให้เห็นดังนั้นฉันจึงเพิ่มคะแนนคำตอบใหม่ด้วย

ในที่สุดแฟน ๆ ที่อ้างถึงสองครั้งมีข้อโต้แย้งของแบบฟอร์ม""อยู่ในหนังสือของคุณหรือไม่หรือว่างเปล่า? แค่ถาม;)


1
วงเล็บจะไม่ตรงถ้าหาเรื่องจะยกมาเช่น[%1]==[-b] run.bat "-b"ดูstackoverflow.com/a/46942471
wisbucky

หมายเหตุในอดีต: [%1]==[-b]และ"%1"=="-b"เหมือนกันสำหรับ win 98 และสคริปต์ชุดระบบ MS / PC-DOS รุ่นก่อนหน้า เนื่องจาก win 2000 / NT ได้เปิดตัวไวยากรณ์if "%~1"=="-b"ที่เครื่องหมายคำพูดคู่มีความหมายพิเศษซึ่งเป็นวิธีที่คุณควรเขียนโค้ดเนื่องจากให้การป้องกันที่แข็งแกร่งยิ่งขึ้น เครื่องหมายคำพูดคู่จะหลีกหนีความหมายของอักขระพิเศษ (ลอง & | และ% ตัวอักษรในบรรทัดคำสั่งของคุณ) 99.9% ของตัวอย่างใช้ได้กับไวยากรณ์คำพูดคู่ - ตัวอย่างของคุณargq bla2" "bla3เป็นเพียงกรณีเดียวที่จะจัดวงเล็บเหลี่ยมเท่านั้น คำพูดคู่ที่ฝังไว้เป็นสูตรสำหรับภัยพิบัติ - เพียงแค่พูด
ข้าม R

@SkipR - นั่นคือเหตุผลที่ในระบบไฟล์ของ Windows คุณไม่สามารถมีอักขระพิเศษเหล่านี้ในชื่อได้ ฉันไม่มีหลักฐานทางคณิตศาสตร์ แต่ฉันคิดว่าทุกอย่างไม่สามารถยกมาได้ (ในแง่ของ - ทำคำต่อคำผ่านลำดับการหลีกเลี่ยง ฯลฯ ) ในcmdเชลล์ ในระบบอื่นบางครั้งคุณสามารถอ้างทุกอย่างรวมอักขระ NUL ( stackoverflow.com/questions/2730732/… ) - คำถามนี้แสดงให้เห็นว่าคุณต้องใช้โปรแกรมภายนอก
Tomasz Gandor

8

นอกเหนือจากคำตอบอื่น ๆ ที่ฉันสมัครคุณอาจพิจารณาใช้/Iสวิตช์ของIFคำสั่ง

... สวิตช์ / I หากระบุบอกว่าให้ทำการเปรียบเทียบสตริงที่ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่

อาจช่วยได้หากคุณต้องการให้ความยืดหยุ่นแบบไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่แก่ผู้ใช้ในการระบุพารามิเตอร์

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

5

คุณกำลังเปรียบเทียบสตริง หากไม่มีอาร์กิวเมนต์ให้%1ขยายเป็นค่าว่างเพื่อให้คำสั่งกลายเป็นIF =="-b" GOTO SPECIFICตัวอย่าง (ซึ่งเป็นข้อผิดพลาดทางไวยากรณ์) รวมสตริงของคุณด้วยเครื่องหมายคำพูด (หรือวงเล็บเหลี่ยม)

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] == [/?] ไม่ทำงาน แต่ฉันทำ IF [% 1] == [] หรือ "% 1" == "" แล้วก็ใช้ได้ ตอนนี้ฉันไปได้แล้ว ขอบคุณสำหรับการตอบกลับอย่างรวดเร็ว
javauser71

5

อันที่จริงคำตอบอื่น ๆ ทั้งหมดมีข้อบกพร่อง วิธีที่น่าเชื่อถือที่สุดคือ:

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

คำอธิบายโดยละเอียด:

การใช้"%1"=="-b"จะแบนความผิดพลาดหากส่งอาร์กิวเมนต์ด้วยช่องว่างและเครื่องหมายคำพูด นี่เป็นวิธีที่น่าเชื่อถือน้อยที่สุด

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

C:\> run.bat "a b"

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

การใช้[%1]==[-b]จะดีกว่าเพราะจะไม่ผิดพลาดกับช่องว่างและเครื่องหมายคำพูด แต่จะไม่ตรงกันหากอาร์กิวเมนต์ล้อมรอบด้วยเครื่องหมายคำพูด

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

C:\> run.bat "-b"

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

การใช้งาน"%~1"=="-b"มีความน่าเชื่อถือที่สุด %~1จะตัดคำพูดโดยรอบออกหากมีอยู่ ดังนั้นจึงใช้งานได้โดยมีและไม่มีเครื่องหมายคำพูดและไม่มีอาร์กิวเมนต์

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
นี่ไม่ใช่จุดสิ้นสุดของวงเล็บเหลี่ยมคุณจะเห็น: IF [%~1]==[]- ใช้งานได้และจัดการ"-b"ได้ด้วย คุณเพียงแค่ต้องสามารถคิดในกรอบเอ่อสี่เหลี่ยม [วงเล็บ]
Tomasz Gandor

3

เมื่อเร็ว ๆ นี้ฉันกำลังดิ้นรนกับการใช้สวิตช์พารามิเตอร์ที่ซับซ้อนในไฟล์แบตช์ดังนั้นนี่คือผลการวิจัยของฉัน ไม่มีคำตอบใดที่ปลอดภัยอย่างสมบูรณ์ตัวอย่าง:

"%1"=="-?" จะไม่ตรงกันหากพารามิเตอร์อยู่ในเครื่องหมายคำพูด (จำเป็นสำหรับชื่อไฟล์เป็นต้น) หรือจะหยุดทำงานหากพารามิเตอร์อยู่ในเครื่องหมายคำพูดและมีช่องว่าง (มักจะเห็นอีกครั้งในชื่อไฟล์)

@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="-?"

การใช้ร่วมกับวงเล็บเหลี่ยม[%1]==[-?]หรือ[%~1]==[-?]จะล้มเหลวในกรณีที่พารามิเตอร์มีช่องว่างภายในเครื่องหมายคำพูด:

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

โซลูชันที่ปลอดภัยที่สุดที่เสนอ"%~1"=="-?"จะขัดข้องด้วยพารามิเตอร์ที่ซับซ้อนซึ่งรวมถึงข้อความภายนอกเครื่องหมายคำพูดและข้อความที่มีช่องว่างภายในเครื่องหมายคำพูด:

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

วิธีเดียวที่จะทำให้แน่ใจว่าสถานการณ์ข้างต้นทั้งหมดได้รับการครอบคลุมคือการใช้EnableDelayedExpansionและส่งผ่านพารามิเตอร์โดยการอ้างอิง (ไม่ใช่ตามค่า) โดยใช้ตัวแปร จากนั้นแม้แต่สถานการณ์ที่ซับซ้อนที่สุดก็ยังใช้ได้ดี:

@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

Windows batch มีคีย์เวิร์ด DEFINED สำหรับทำสิ่งนี้

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

ขอบคุณเดวิด ฉันไม่รู้ว่าเหตุใดจึงล้มเหลวในการกลับรถและขึ้นบรรทัดใหม่ระหว่าง IF และ IF NOT ฉันไม่ได้สังเกตเห็น
Charles
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.