ฉันสามารถมี IF block ในไฟล์แบตช์ DOS ได้หรือไม่


98

ในไฟล์แบตช์ DOS เราสามารถมีได้เพียง 1 บรรทัดเท่านั้น if statement body? ฉันคิดว่าฉันพบที่ไหนสักแห่งที่ฉันสามารถใช้()สำหรับ if block ได้เหมือนกับที่{}ใช้ในภาษาโปรแกรมคล้าย C แต่มันไม่ได้เรียกใช้งานคำสั่งเมื่อฉันลองทำเช่นนี้ ไม่มีข้อความแสดงข้อผิดพลาดเช่นกัน นี่คือรหัสของฉัน:

if %GPMANAGER_FOUND%==true(echo GP Manager is up
goto Continue7
)
echo GP Manager is down
:Continue7

ไม่แปลกที่ทั้ง "GP Manager is up" หรือ "GP Manager is down" ไม่ได้รับการพิมพ์ออกมาเมื่อฉันเรียกใช้ไฟล์แบตช์


บางทีนี่อาจช่วยได้: commandwindows.com/batchfiles-branching.htm
esaj

ยาที่ช่วย DOS ห่วย ถ้าฉันต้องการใช้หลายคำสั่งใน if หรืออื่น ๆ ฉันต้องใช้ && ระหว่างคำสั่ง? หรือมีวิธีที่หรูหรากว่านี้?
Hugh Darling

คำตอบ:


143

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

if <statement> (
    do something
) else (
    do something else
)

อย่างไรก็ตามฉันไม่เชื่อว่ามีไวยากรณ์ในตัวสำหรับelse-ifคำสั่ง คุณต้องสร้างกลุ่มifคำสั่งที่ซ้อนกันเพื่อจัดการกับสิ่งนั้น


ประการที่สอง%GPMANAGER_FOUND% == trueการทดสอบนั้นดูน่าสงสัยสำหรับฉัน ฉันไม่รู้ว่าตัวแปรสภาพแวดล้อมถูกตั้งค่าเป็นอะไรหรือคุณตั้งค่าอย่างไร แต่ฉันสงสัยมากว่าโค้ดที่คุณแสดงจะให้ผลลัพธ์ที่คุณกำลังมองหา


โค้ดตัวอย่างต่อไปนี้ใช้ได้ดีสำหรับฉัน:

@echo off

if ERRORLEVEL == 0 (
    echo GP Manager is up
    goto Continue7
)
echo GP Manager is down
:Continue7

โปรดสังเกตรายละเอียดบางประการเกี่ยวกับโค้ดตัวอย่างของฉัน:

  • ช่องว่างที่เพิ่มระหว่างส่วนท้ายของคำสั่งเงื่อนไขและวงเล็บเปิด
  • ฉันกำลังตั้งค่า@echo offเพื่อไม่ให้เห็นข้อความทั้งหมดที่พิมพ์ไปยังคอนโซลขณะดำเนินการและดูผลลัพธ์ของข้อความที่ขึ้นต้นโดยเฉพาะechoแทน
  • ฉันใช้ERRORLEVELตัวแปรบิวท์อินเพื่อทดสอบ อ่านเพิ่มเติมที่นี่

1
ใช้ได้ดีกว่าถ้า% ERRORLEVEL% == 0 เนื่องจากตัวแปรอื่นเป็นจริงเสมอเนื่องจาก IF ERRORLEVEL <N> เป็นจริงหากระดับข้อผิดพลาดเท่ากับหรือมากกว่า <N> "==" จะถูกละเว้นในกรณีนี้
jeb

@jeb: ฉันคิดว่าคุณอาจพลาดจุดนี้ การใช้ERRORLEVELไม่ใช่คำตอบสำหรับปัญหาของเขา ฉันแค่โพสต์ตัวอย่างของไวยากรณ์ที่เหมาะสม ทั้งสองรูปแบบเป็นที่ยอมรับในกรณีนี้เช่นเดียวกับที่จะเป็นif 0 == 0หรือการแสดงออกที่ไม่สำคัญอื่น ๆ แต่ต้องแน่ใจว่าคุณเข้าใจความแตกต่างระหว่างตัวแปรสภาพแวดล้อม%ERRORLEVEL%และภายในERRORLEVELของตัวประมวลผลคำสั่ง Raymond Chen อธิบายไว้อย่างดีในบล็อกนี้
Cody Grey

คุณมี ELSE IF ได้ไหม
xagyg

1
การเพิ่มความคิดเห็นของ @ Mythofechelon แม้แต่วงเล็บปิดที่ดูเหมือนไม่มีพิษมีภัยในคำสั่ง REM ก็จะยุติการบล็อก เช่นโยนREM This is a comment (or so I thought)เข้าไปในIFบล็อกจะทำให้คุณยุ่ง
rkagerer

2
ทั้ง @mythofechelon และ @rkagerer กำลังชี้ให้เห็นปัญหาเฉพาะของกฎทั่วไปที่ต้องมีการอ้างอิงสตริง คุณไม่ควรเขียนโค้ด IF %somevar%==example_string2 มันควรจะเป็นโค้ดเสมอดังนั้นตัวถูกดำเนินการจะแก้ไขเป็น IF "value_of_somevar"=="example_string2"เพื่อหลีกเลี่ยงอักขระพิเศษในตัวถูกดำเนินการสตริงใด ๆ ที่ทำให้เกิดข้อผิดพลาดทางไวยากรณ์ในIFคำสั่งค่าที่คุณตั้งไว้ควรทำเสมอเนื่องจาก set "somevar=value_of_somevar" ไวยากรณ์นั้นช่วยให้คุณสามารถหลีกเลี่ยงอักขระพิเศษในค่าตัวแปรได้หมายเหตุ ที่ฉันไม่ได้หมายถึง set somevar="value_of_somevar"
ข้าม R

15

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

if %ERRORLEVEL%==0 (
set var1=blue
set var2=cheese
set var3=%var1%_%var2%
)

สิ่งนี้ควรระบุ var3 ด้วยค่าต่อไปนี้:

blue_cheese

แต่ให้ผลตอบแทน:

_

เนื่องจากคำสั่งทั้ง 3 ถูกแคชและดำเนินการพร้อมกันเมื่อออกจากบล็อกโค้ด

ฉันสามารถเอาชนะปัญหานี้ได้โดยการเขียน if block ใหม่เพื่อดำเนินการคำสั่งเดียว - goto - และเพิ่มป้ายกำกับสองสาม มันรกและฉันไม่ชอบมันมากนัก แต่อย่างน้อยมันก็ใช้งานได้

if %ERRORLEVEL%==0 goto :error0
goto :endif

:error0
set var1=blue
set var2=cheese
set var3=%var1%_%var2%

:endif

8
การใช้การขยายที่ล่าช้าควรใช้งานได้: ใช้:set var3=!var1!_!var2!
Dracorat

4

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

ฉันแก้ไขข้อมูลโค้ดสคริปต์ด้วยเคล็ดลับนี้เพื่อสรุปว่าฉันมีไฟล์แบตช์สามไฟล์ไฟล์หนึ่งเรียกอีกสองไฟล์หลังจากพบว่าตัวอักษรใดที่ไดรฟ์สำรองข้อมูลภายนอกได้รับมอบหมาย ฉันทิ้งไฟล์แรกไว้ในไดรฟ์ภายนอกหลักดังนั้นการโทรไปยังรูทีนการสำรองข้อมูลจึงทำงานได้ดี แต่การโทรไปยังไฟล์ที่สองจำเป็นต้องมีการเปลี่ยนไดรฟ์ที่ใช้งานอยู่ โค้ดด้านล่างแสดงวิธีแก้ไข:

for %%b in (d e f g h i j k l m n o p q r s t u v w x y z) DO (
if exist "%%b:\Backup.cmd" %%b: & CALL "%%b:\Backup.cmd"
)

ทำไมสิ่งนี้จึงถูกลดลงบนโลกนี้? นี่คือสิ่งที่ฉันต้องการ
ggb667

1
@ GCB667 - เพื่อชี้แจง @Louis "ได้เขียน" คำตอบ "ที่ไม่เกี่ยวข้องกับปัญหาว่าเหตุใดคำสั่ง IF จึงใช้ไม่ได้กับผู้โพสต์ต้นฉบับมันเกี่ยวข้องกับคำตอบของ" vinniejohnson "(ซึ่งพลาดปัญหาของผู้โพสต์ต้นฉบับด้วย) .
ข้าม R

1

ฉันอ่านบทความนี้ในผลลัพธ์ที่ได้จากการค้นหาที่เกี่ยวข้องกับคำสั่ง IF ในไฟล์แบตช์และฉันไม่สามารถต้านทานโอกาสในการแก้ไขความเข้าใจผิดที่ว่าบล็อก IF ถูก จำกัด ไว้ที่คำสั่งเดียว ต่อไปนี้เป็นส่วนหนึ่งของสคริปต์คำสั่ง Windows NT ที่ใช้งานจริงซึ่งทำงานทุกวันบนเครื่องที่ฉันเขียนคำตอบนี้

    if "%COPYTOOL%" equ "R" (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using RoboCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    %TOOLPATH% %SRCEPATH% %DESTPATH% /copyall %RCLOGSTR% /m /np /r:0 /tee
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Robocopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
) else (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using XCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    call %TOOLPATH%  "%USERPROFILE%\My Documents\Outlook Files\*" "%USERPROFILE%\My Documents\Outlook Files\_backups" /f /m /v /y
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Xcopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
)

บางทีบล็อกที่มีสองบรรทัดขึ้นไปจะใช้เฉพาะกับสคริปต์คำสั่งของ Windows NT (ไฟล์. CMD) เนื่องจากการค้นหาไดเร็กทอรีสคริปต์การผลิตของแอปพลิเคชันที่ จำกัด ไว้ที่ไฟล์แบตช์ (.BAT) ของโรงเรียนเก่าซึ่งเปิดเผยเพียงบล็อกคำสั่งเดียว . เนื่องจากแอปพลิเคชันได้เข้าสู่การบำรุงรักษาเป็นระยะเวลานาน (หมายความว่าฉันไม่ได้มีส่วนร่วมอย่างจริงจังในการสนับสนุน) ฉันจึงไม่สามารถพูดได้ว่านั่นเป็นเพราะฉันไม่ต้องการมากกว่าหนึ่งบรรทัดหรือฉันไม่สามารถทำให้มันใช้งานได้

ไม่ว่ากรณีหลังจะเป็นจริงมีวิธีแก้ปัญหาง่ายๆ ย้ายหลายบรรทัดลงในไฟล์แบตช์แยกต่างหากหรือรูทีนย่อยไฟล์แบตช์ ฉันรู้ว่างานหลังใช้สคริปต์ทั้งสองแบบ


0

อาจจะช้าไปหน่อย แต่หวังว่ามันจะแย่:

@echo off 

if %ERRORLEVEL% == 0 (
msg * 1st line WORKS FINE rem You can relpace msg * with any othe operation...
goto Continue1
)
:Continue1
If exist "C:\Python31" (
msg * 2nd line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue2
)
:Continue2
If exist "C:\Python31\Lib\site-packages\PyQt4" (  
msg * 3th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue3
)
:Continue3
msg * 4th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue4
)
:Continue4
msg * "Tutto a posto" rem You can relpace msg * with any othe operation...
pause
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.