การใช้พารามิเตอร์ในแบตช์ไฟล์ที่บรรทัดรับคำสั่งของ Windows


161

ใน Windows คุณเข้าถึงอาร์กิวเมนต์ที่ส่งผ่านเมื่อเรียกใช้ไฟล์แบตช์ได้อย่างไร

hello.batตัวอย่างเช่นสมมติว่าผมมีโปรแกรมที่ชื่อว่า เมื่อฉันป้อนhello -aที่บรรทัดคำสั่งของ Windows ฉันจะให้โปรแกรมของฉันรู้ว่า-aมันถูกส่งเป็นอาร์กิวเมนต์ได้อย่างไร


วิธีการส่งผ่านพารามิเตอร์บรรทัดคำสั่งไปยังไฟล์แบตช์: stackoverflow.com/questions/26551/…
Eric Leschinski

3
เขากล่าวถึง "บรรทัดคำสั่ง DOS"
David R Tribble

คำตอบ:


287

เป็นคนอื่นได้แล้วกล่าวว่าพารามิเตอร์ผ่านบรรทัดคำสั่งที่สามารถเข้าถึงได้ในไฟล์ชุดที่มีสัญกรณ์ไป%1 %9นอกจากนี้ยังมีโทเค็นอื่นอีกสองตัวที่คุณสามารถใช้ได้:

  • %0เป็นปฏิบัติการ (ไฟล์ batch) ชื่อตามที่ระบุไว้ในบรรทัดคำสั่ง
  • %*เป็นพารามิเตอร์ทั้งหมดที่ระบุในบรรทัดคำสั่ง - ซึ่งมีประโยชน์มากหากคุณต้องการส่งต่อพารามิเตอร์ไปยังโปรแกรมอื่น

นอกจากนี้ยังมีเทคนิคที่สำคัญมากมายที่ต้องระวังนอกเหนือจากวิธีการเข้าถึงพารามิเตอร์

การตรวจสอบว่าพารามิเตอร์ถูกส่งผ่าน

สิ่งนี้ทำกับโครงสร้างอย่างเช่นIF "%~1"==""ซึ่งเป็นจริงถ้าหากไม่มีการโต้แย้งใด ๆ เลย หมายเหตุตัวละครตัวหนอนซึ่งทำให้คำพูดโดยรอบใด ๆ ที่จะถูกลบออกจากค่าของ%1; หากไม่มีเครื่องหมายตัวหนอนคุณจะได้รับผลลัพธ์ที่ไม่คาดคิดหากค่านั้นมีเครื่องหมายคำพูดคู่รวมถึงความเป็นไปได้ของข้อผิดพลาดทางไวยากรณ์

จัดการข้อโต้แย้งมากกว่า 9 ข้อ (หรือทำให้ชีวิตง่ายขึ้น)

หากคุณจำเป็นต้องเข้าถึงมากกว่า 9 SHIFTข้อโต้แย้งที่คุณต้องใช้คำสั่ง คำสั่งนี้จะเปลี่ยนแปลงค่าของการขัดแย้งทุกสถานที่หนึ่งเพื่อที่%0จะใช้เวลาค่าของ%1, %1ใช้เวลาค่าของ%2ฯลฯ%9ใช้เวลาคุ้มค่าของการโต้แย้งที่สิบ (ถ้าเป็นปัจจุบัน) ซึ่งไม่สามารถใช้ได้ผ่านตัวแปรใด ๆ ก่อนที่จะเรียกSHIFT(ป้อน คำสั่งSHIFT /?สำหรับตัวเลือกเพิ่มเติม)

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

:parse
IF "%~1"=="" GOTO endparse
IF "%~1"=="-a" REM do something
IF "%~1"=="-b" REM do something else
SHIFT
GOTO parse
:endparse
REM ready for action!

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

การทดแทนพารามิเตอร์แบทช์

สำหรับพารามิเตอร์ที่แสดงชื่อไฟล์เชลล์มีฟังก์ชันที่เกี่ยวข้องกับการทำงานกับไฟล์ที่ไม่สามารถเข้าถึงได้ในวิธีอื่น %~ฟังก์ชั่นนี้จะเข้าถึงได้ด้วยโครงสร้างที่ขึ้นต้นด้วย

ตัวอย่างเช่นในการรับขนาดของไฟล์ที่ส่งผ่านเป็นการใช้อาร์กิวเมนต์

ECHO %~z1

ในการรับพา ธ ของไดเรกทอรีที่เปิดไฟล์แบตช์ (มีประโยชน์มาก!) คุณสามารถใช้ได้

ECHO %~dp0

คุณสามารถดูความสามารถทั้งหมดได้โดยการพิมพ์CALL /?ที่ command prompt


4
The: parse,: endparse build คือความงามแม้กระทั่งกับ GOTO ขอบคุณ! (ฉันหมายถึง DOS-BASIC บังคับ GOTO)
mmrtnt

1
เทคนิคนี้อาจล้มเหลวเมื่อโทร BAT จาก PowerShell อาร์กิวเมนต์ที่ยกมาเช่น"name=John"จะกลายเป็นname Johnในช่วง exe วิธีหลีกเลี่ยงปัญหาคือล้อมรอบด้วยเครื่องหมายคำพูดเดี่ยว'"name=John"'
cmcginty

1
ฉันหายไปนานCALL /?แค่ไหนแล้ว! ที่นี่ฉันชนกับ Google ตลอดเวลา
bigtlb

@ จอนฉันเขียนไฟล์ bat ซึ่งมีเพียงหนึ่งรหัส echo% 1 ถ้าฉันเรียกมันผ่านทาง cmd เช่น xx.bat & พารามิเตอร์> "C: \ yy.txt" เรียกไฟล์ bat พร้อมพารามิเตอร์และเขียนไปยังไฟล์ txt แต่ถ้าฉันให้ & ในพารามิเตอร์ที่จุดเริ่มต้นหรือจุดสิ้นสุดมันไม่ทำงาน ข้อความอื่นใดทำงานได้ดี
อเล็กซ์แม็ตธิว

56

การใช้พารามิเตอร์ในแบตช์ไฟล์:% 0 และ% 9

ไฟล์ batch สามารถอ้างถึงคำพูดที่ส่งผ่านเป็นพารามิเตอร์ที่มีสัญญาณ: ไป%0%9

%0 is the program name as it was called.
%1 is the first command line parameter
%2 is the second command line parameter
and so on till %9.

พารามิเตอร์ที่ส่งเข้ามาใน commandline จะต้องเป็นตัวอักษรและตัวเลขและคั่นด้วยช่องว่าง เนื่องจาก%0เป็นชื่อโปรแกรมตามที่ถูกเรียกใน DOS %0จะว่างเปล่าสำหรับ AUTOEXEC.BAT หากเริ่มต้นในเวลาบูต

ตัวอย่าง:

วางคำสั่งต่อไปนี้ในไฟล์แบทช์ชื่อmybatch.bat:

@echo off
@echo hello %1 %2
pause

เรียกใช้ไฟล์แบตช์ดังนี้: mybatch john billyจะแสดงผล:

hello john billy

รับพารามิเตอร์มากกว่า 9 รายการสำหรับไฟล์แบตช์ใช้:% *

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

http://www.robvanderwoude.com/parameters.php

หมายเหตุเกี่ยวกับตัวคั่นสำหรับพารามิเตอร์แบตช์

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

commas (",") are replaced by spaces, unless they are part of a string in 
double quotes

semicolons (";") are replaced by spaces, unless they are part of a string in 
double quotes

"=" characters are sometimes replaced by spaces, not if they are part of a 
string in double quotes

the first forward slash ("/") is replaced by a space only if it immediately 
follows the command, without a leading space

multiple spaces are replaced by a single space, unless they are part of a 
string in double quotes

tabs are replaced by a single space

leading spaces before the first command line argument are ignored

5

ไฟล์แบทช์ส่งข้อความโดยอัตโนมัติหลังจากโปรแกรมตราบใดที่พวกเขาเป็นตัวแปรในการกำหนดให้ พวกเขาจะถูกส่งผ่านตามลำดับพวกเขาจะถูกส่ง; เช่น% 1 จะเป็นสตริงแรกที่ส่งหลังจากเรียกใช้โปรแกรมเป็นต้น

หากคุณมี Hello.bat และเนื้อหาคือ:

@echo off
echo.Hello, %1 thanks for running this batch file (%2)
pause

และคุณเรียกใช้แบทช์ในคำสั่งผ่าน

hello.bat APerson241% วันที่%

คุณควรได้รับข้อความนี้กลับมา:

สวัสดี APerson241 ขอบคุณที่ใช้งานไฟล์แบตช์นี้ (01/11/2013)


4

@ Jon's :parse/ :endparseแบบแผนเป็นการเริ่มต้นที่ยอดเยี่ยมและเขามีความกตัญญูต่อการเริ่มต้นครั้งแรก แต่ถ้าคุณคิดว่าระบบแบตช์ของ Windows จะทำให้คุณตกใจง่าย…เอ่อเพื่อนคุณกำลังตกใจ ฉันใช้เวลาตลอดทั้งวันกับปีศาจนี้และหลังจากการวิจัยและการทดลองที่เจ็บปวดมากในที่สุดฉันก็จัดการบางสิ่งบางอย่างที่เป็นประโยชน์สำหรับยูทิลิตี้ในชีวิตจริง

foobarให้เราบอกว่าเราต้องการที่จะใช้ยูทิลิตี้ มันต้องมีคำสั่งเริ่มต้น มันมีพารามิเตอร์ทางเลือก--fooซึ่งรับค่าตัวเลือก (ซึ่งไม่สามารถเป็นพารามิเตอร์อื่นได้) defaultถ้าค่าจะหายไปค่าเริ่มต้นของมัน นอกจากนี้ยังมีพารามิเตอร์ตัวเลือก--barที่จะใช้เวลาที่ต้องการความคุ้มค่า สุดท้ายสามารถใช้แฟลก--bazโดยไม่อนุญาตให้มีค่า โอ้และพารามิเตอร์เหล่านี้สามารถมาในลำดับใดก็ได้

กล่าวอีกนัยหนึ่งดูเหมือนว่า:

foobar <command> [--foo [<fooval>]] [--bar <barval>] [--baz]

ซับซ้อน? ไม่ดูเหมือนเป็นเรื่องปกติของสาธารณูปโภคในชีวิตจริง ( gitใคร?)

หากไม่มีความกังวลใจต่อไปนี้เป็นวิธีแก้ปัญหา:

@ECHO OFF
SETLOCAL
REM FooBar parameter demo
REM By Garret Wilson

SET CMD=%~1

IF "%CMD%" == "" (
  GOTO usage
)
SET FOO=
SET DEFAULT_FOO=default
SET BAR=
SET BAZ=

SHIFT
:args
SET PARAM=%~1
SET ARG=%~2
IF "%PARAM%" == "--foo" (
  SHIFT
  IF NOT "%ARG%" == "" (
    IF NOT "%ARG:~0,2%" == "--" (
      SET FOO=%ARG%
      SHIFT
    ) ELSE (
      SET FOO=%DEFAULT_FOO%
    )
  ) ELSE (
    SET FOO=%DEFAULT_FOO%
  )
) ELSE IF "%PARAM%" == "--bar" (
  SHIFT
  IF NOT "%ARG%" == "" (
    SET BAR=%ARG%
    SHIFT
  ) ELSE (
    ECHO Missing bar value. 1>&2
    ECHO:
    GOTO usage
  )
) ELSE IF "%PARAM%" == "--baz" (
  SHIFT
  SET BAZ=true
) ELSE IF "%PARAM%" == "" (
  GOTO endargs
) ELSE (
  ECHO Unrecognized option %1. 1>&2
  ECHO:
  GOTO usage
)
GOTO args
:endargs

ECHO Command: %CMD%
IF NOT "%FOO%" == "" (
  ECHO Foo: %FOO%
)
IF NOT "%BAR%" == "" (
  ECHO Bar: %BAR%
)
IF "%BAZ%" == "true" (
  ECHO Baz
)

REM TODO do something with FOO, BAR, and/or BAZ
GOTO :eof

:usage
ECHO FooBar
ECHO Usage: foobar ^<command^> [--foo [^<fooval^>]] [--bar ^<barval^>] [--baz]
EXIT /B 1

ใช่มันเลวร้ายจริงๆ ดูโพสต์ที่คล้ายกันของฉันที่https://stackoverflow.com/a/50653047/421049ที่ฉันให้การวิเคราะห์เพิ่มเติมเกี่ยวกับสิ่งที่เกิดขึ้นในตรรกะและเหตุผลที่ฉันใช้โครงสร้างบางอย่าง

น่าเกลียด ส่วนใหญ่ฉันต้องเรียนรู้วันนี้ และมันก็เจ็บ


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