คำตอบของ eplawlessสามารถแก้ปัญหาเฉพาะของเขาได้อย่างง่ายดายและมีประสิทธิภาพ: มันจะแทนที่"
อินสแตนซ์ทั้งหมดในรายการอาร์กิวเมนต์ทั้งหมดด้วย\"
ซึ่งเป็นวิธีที่ Bash ต้องการเครื่องหมายคำพูดคู่ภายในสตริงที่ยกมาสองครั้งเพื่อแสดง
โดยทั่วไปจะตอบคำถามเกี่ยวกับวิธีหลีกเลี่ยงเครื่องหมายอัญประกาศคู่ภายในสตริงที่ยกมาสองครั้งโดยใช้cmd.exe
ตัวแปลบรรทัดคำสั่งของ Windows (ไม่ว่าจะเป็นในบรรทัดคำสั่ง - มักจะเรียกผิดว่า "พรอมต์ DOS" หรือในไฟล์แบตช์): ดูด้านล่างสำหรับการดูที่PowerShell
tl; dr :
คุณต้องใช้""
เมื่อส่งสตริงไปยังไฟล์แบตช์ (nother)และคุณสามารถใช้""
กับแอปพลิเคชันที่สร้างด้วยคอมไพเลอร์ C / C ++ / NET ของ Microsoft (ซึ่งยอมรับเช่นกัน\"
) ซึ่งใน Windows รวมถึง Python และ Node.js :
\"
ถูกต้อง - เป็นตัวเลือกเพียง - โดยโปรแกรมอื่น ๆ อีกมากมาย (! เช่นทับทิม, Perl, และแม้กระทั่งไมโครซอฟท์เอง Windows PowerShell ()) แต่การใช้งานเป็นไม่ปลอดภัย :
\"
เป็นสิ่งที่โปรแกรมเรียกทำงานและตัวแปลจำนวนมากต้องการ - รวมถึง Windows PowerShell - เมื่อส่งผ่านสตริงจากภายนอก - หรือในกรณีของคอมไพเลอร์ของ Microsoft จะสนับสนุนเป็นทางเลือกอื่นใน ""
ท้ายที่สุดแม้ว่าโปรแกรมเป้าหมายจะแยกวิเคราะห์รายการอาร์กิวเมนต์ .
- ตัวอย่าง:
foo.exe "We had 3\" of rain."
- อย่างไรก็ตามการใช้
\"
สามารถส่งผลในการดำเนินการตามคำสั่งของอนุญาโตตุลาการโดยไม่ต้องการและ / หรือการเปลี่ยนทิศทางอินพุต / เอาต์พุต :
- อักขระต่อไปนี้แสดงความเสี่ยงนี้:
& | < >
- ตัวอย่างเช่นผลลัพธ์ต่อไปนี้ในการดำเนินการ
ver
คำสั่งโดยไม่ได้ตั้งใจ ดูเพิ่มเติมด้านล่างสำหรับคำอธิบายและสัญลักษณ์แสดงหัวข้อย่อยถัดไปสำหรับวิธีแก้ปัญหา:
foo.exe "3\" of snow" "& ver."
- สำหรับWindows PowerShell ,
\""
และ"^""
มีประสิทธิภาพ แต่ทางเลือก จำกัด (ดูส่วน "เรียก CLI PowerShell ของ ..." ด้านล่าง)
หากคุณต้องใช้\"
มีเพียง 3 วิธีที่ปลอดภัยซึ่งเป็นวิธีที่ค่อนข้างยุ่งยาก : เคล็ดลับของหมวกสำหรับTSเพื่อขอความช่วยเหลือ
การใช้ (อาจเลือก ) ล่าช้าการขยายตัวของตัวแปรในแฟ้มชุดของคุณคุณสามารถเก็บอักษร\"
ในตัวแปรและการอ้างอิงตัวแปรภายใน"..."
สตริงโดยใช้!var!
ไวยากรณ์ - ดูคำตอบที่เป็นประโยชน์ TS ของ
- วิธีการข้างต้นแม้จะยุ่งยาก แต่ก็มีข้อได้เปรียบที่คุณสามารถนำไปใช้ได้อย่างมีระบบและใช้งานได้ดีกับอินพุตใด ๆ
เฉพาะกับสตริงแบบ LITERAL เท่านั้นซึ่งไม่เกี่ยวข้องกับตัวแปร - คุณจะได้รับแนวทางที่เป็นระเบียบในทำนองเดียวกันหรือไม่: จัดหมวดหมู่^
-escape ตัวละครทั้งหมด cmd.exe
: " & | < >
และ - หากคุณต้องการระงับการขยายตัวแปรด้วย - %
:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
มิฉะนั้นคุณต้องกำหนดสตริงของคุณโดยพิจารณาจากการรับรู้ว่าส่วนใดของสตริงที่cmd.exe
พิจารณาว่าไม่ได้ใส่\"
เครื่องหมายคำพูดเนื่องจากตีความผิดว่าเป็นตัวคั่นปิด:
ในส่วนที่เป็นตัวอักษรที่มีตัวอักษรเชลล์: ^
-escape พวกเขา; จากตัวอย่างข้างต้นจะ&
ต้องเป็น^
-escaped:
foo.exe "3\" of snow" "^& ver."
ในส่วนที่มี%...%
การอ้างอิงตัวแปรสไตล์ : ให้แน่ใจว่าcmd.exe
จะพิจารณาเป็นส่วนหนึ่งของพวกเขา"..."
สตริงและว่าค่าตัวแปรไม่ได้ว่าตัวเองมีการฝังตัว, คำพูดที่ไม่สมดุล - ซึ่งไม่ได้เป็นไปได้เสมอ
สำหรับข้อมูลพื้นฐานโปรดอ่านต่อ
พื้นหลัง
หมายเหตุ: นี่มาจากการทดลองของฉันเอง โปรดแจ้งให้ฉันทราบหากฉันผิด
เชลล์ที่เหมือน POSIX เช่น Bash บนระบบที่เหมือน Unix จะทำให้รายการอาร์กิวเมนต์ (สตริง) เป็นโทเค็นก่อนที่จะส่งอาร์กิวเมนต์ทีละรายการไปยังโปรแกรมเป้าหมาย: ในการขยายอื่น ๆ พวกเขาแยกรายการอาร์กิวเมนต์ออกเป็นแต่ละคำ (การแบ่งคำ) และลบอักขระการอ้างอิงออกจาก คำที่เป็นผลลัพธ์ (การลบใบเสนอราคา) โปรแกรมเป้าหมายที่ถูกส่งอาร์เรย์ของข้อโต้แย้งของแต่ละบุคคลด้วยประโยคคำพูดที่เอาออก
ในทางตรงกันข้ามตัวแปลคำสั่งของ Windows ดูเหมือนจะไม่โทเค็นรายการอาร์กิวเมนต์และเพียงแค่ส่งผ่านสตริงเดียวที่ประกอบด้วยอาร์กิวเมนต์ทั้งหมด - รวมถึงการอ้างอิงอักขระ - ไปยังโปรแกรมเป้าหมาย
อย่างไรก็ตามการประมวลผลล่วงหน้าบางอย่างเกิดขึ้นก่อนที่สตริงเดี่ยวจะถูกส่งผ่านไปยังโปรแกรมเป้าหมาย: ^
Escape chars ภายนอกของสตริงที่ยกมาสองครั้งจะถูกลบออก (ซึ่งจะหลีกเลี่ยงอักขระต่อไปนี้) และการอ้างอิงตัวแปร (เช่น%USERNAME%
) จะถูกแก้ไขก่อน
ดังนั้นไม่เหมือนใน Unix คือความรับผิดชอบของโปรแกรมเป้าหมายในการแยกวิเคราะห์เพื่อแยกวิเคราะห์สตริงอาร์กิวเมนต์และแยกย่อยออกเป็นอาร์กิวเมนต์แต่ละรายการโดยลบเครื่องหมายคำพูดออก ดังนั้นโปรแกรมที่แตกต่างกันอาจต้องการวิธีการหลบหนีที่แตกต่างกันโดยสมมุติฐานและไม่มีกลไกการหลบหนีเดียวที่รับประกันว่าจะทำงานกับทุกโปรแกรมได้ - https://stackoverflow.com/a/4094897/45375มีพื้นหลังที่ยอดเยี่ยมเกี่ยวกับอนาธิปไตยซึ่งเป็นบรรทัดคำสั่งของ Windows การแยกวิเคราะห์
ในทางปฏิบัติ\"
เป็นเรื่องปกติมาก แต่ไม่ปลอดภัยดังที่กล่าวไว้ข้างต้น:
เนื่องจากcmd.exe
ตัวเองไม่ได้รับรู้\"
เป็นหนีอ้างดับเบิลก็สามารถเข้าใจผิดในภายหลังสัญญาณในบรรทัดคำสั่งเป็นunquotedและอาจตีความว่าเป็นคำสั่งและ / หรืออินพุต / เอาต์พุตเปลี่ยนเส้นทาง
โดยสรุป: ปัญหาจะปรากฏขึ้นหากอักขระใด ๆ ต่อไปนี้เป็นไปตามการเปิดหรือไม่สมดุล \"
:& | < >
; ตัวอย่างเช่น:
foo.exe "3\" of snow" "& ver."
cmd.exe
เห็นโทเค็นต่อไปนี้ซึ่งเป็นผลมาจากการตีความผิด\"
เป็นเครื่องหมายคำพูดคู่ปกติ:
"3\"
of
snow" "
- พักผ่อน:
& ver.
เนื่องจากcmd.exe
คิดว่า& ver.
ไม่มีเครื่องหมายอัญประกาศจึงตีความเป็น&
(ตัวดำเนินการลำดับคำสั่ง) ตามด้วยชื่อของคำสั่งเพื่อดำเนินการ ( ver.
- .
ถูกละเว้นข้อมูลเวอร์ชันของver
รายงานcmd.exe
)
ผลกระทบโดยรวมคือ:
- ขั้นแรก
foo.exe
ถูกเรียกใช้ด้วยโทเค็น3 ตัวแรกเท่านั้น
- จากนั้นคำสั่ง
ver
จะถูกดำเนินการ
แม้ในกรณีที่คำสั่งโดยไม่ได้ตั้งใจไม่เป็นอันตราย แต่คำสั่งโดยรวมของคุณจะไม่ทำงานตามที่ออกแบบไว้เนื่องจากไม่ได้ส่งผ่านอาร์กิวเมนต์ทั้งหมดไป
คอมไพเลอร์ / ล่ามจำนวนมากรู้จักเฉพาะ\"
- เช่นคอมไพเลอร์ GNU C / C ++, Python, Perl, Ruby แม้กระทั่ง Windows PowerShell ของ Microsoft เองเมื่อเรียกใช้จากcmd.exe
- และยกเว้น (มีข้อ จำกัด ) สำหรับ Windows PowerShell ด้วย\""
สำหรับพวกเขาไม่มีวิธีง่ายๆ กับปัญหานี้
โดยพื้นฐานแล้วคุณจะต้องรู้ล่วงหน้าว่าส่วนใดของบรรทัดคำสั่งของคุณถูกตีความผิดว่าไม่มีการ^
อ้างถึงและเลือก - คัดลอกอินสแตนซ์ทั้งหมด& | < >
ในส่วนเหล่านั้น
ในทางตรงกันข้ามการใช้งาน""
คือ SAFEแต่น่าเสียดายที่ได้รับการสนับสนุนโดยไฟล์ปฏิบัติการและไฟล์แบตช์ที่ใช้คอมไพเลอร์ของ Microsoft เท่านั้น (ในกรณีของไฟล์แบตช์ที่มีลักษณะไม่ชอบมาพากลที่กล่าวถึงข้างต้น) ซึ่งโดดเด่นไม่รวมPowerShell - ดูหัวข้อถัดไป
การเรียก CLI ของ PowerShell จากcmd.exe
หรือเชลล์แบบ POSIX:
หมายเหตุ: ดูส่วนด้านล่างสำหรับวิธีจัดการใบเสนอราคาภายใน PowerShell
เมื่อเรียกใช้จากภายนอก - เช่นจากcmd.exe
ไม่ว่าจะจากบรรทัดคำสั่งหรือแบตช์ไฟล์:
PowerShell [หลัก] v6 +ตอนนี้ต้องตระหนัก""
(นอกเหนือ\"
) ซึ่งเป็นทั้งความปลอดภัยในการใช้งานและช่องว่างการรักษา
pwsh -c " ""a & c"".length "
ไม่แตกและให้ผลผลิตอย่างถูกต้อง 6
Windows PowerShell (รุ่นดั้งเดิมที่มีเวอร์ชันล่าสุดคือ 5.1) จะ รับรู้เท่านั้น \"
และใน Windows ด้วย"""
และยิ่งมีประสิทธิภาพมากขึ้น\""
/"^""
(แม้ว่าPowerShellภายในจะใช้`
เป็นอักขระหลีกในสตริงที่ยกมาสองครั้งและยังยอมรับ""
- ดูส่วนด้านล่าง):
การเรียกWindows PowerShell จากcmd.exe
/ ไฟล์แบตช์:
""
หยุดพักเนื่องจากไม่ได้รับการสนับสนุนโดยพื้นฐาน:
powershell -c " ""ab c"".length "
-> ข้อผิดพลาด "สตริงไม่มีตัวยุติ"
\"
และ"""
ทำงานตามหลักการแต่ไม่ปลอดภัย :
powershell -c " \"ab c\".length "
ทำงานตามที่ตั้งใจไว้: เอาต์พุต5
(สังเกต2ช่องว่าง)
- แต่มันไม่ปลอดภัยเพราะ
cmd.exe
metacharacters ทำลายคำสั่งเว้นแต่จะ Escape:
powershell -c " \"a& c\".length "
หยุดพักเนื่องจากสิ่ง&
ที่จะต้องหนีในฐานะ^&
\""
เป็นที่ปลอดภัยแต่การตกแต่งภายในปกติช่องว่างซึ่งสามารถที่ไม่พึงประสงค์:
powershell -c " \""a& c\"".length "
เอาต์พุต4
(!) เนื่องจากช่องว่าง 2 ช่องถูกทำให้เป็นมาตรฐานเป็น 1
"^""
เป็นตัวเลือกที่ดีที่สุดสำหรับการWindows PowerShellโดยเฉพาะซึ่งจะมีทั้งความปลอดภัยและช่องว่างการรักษา แต่กับ PowerShell หลัก (ใน Windows) มันเป็นเช่นเดียวกับ\""
คือด้วยช่องว่างnormalizing เครดิตไปที่Venryxสำหรับการค้นพบแนวทางนี้
powershell -c " "^""a& c"^"".length "
ผลงาน : ไม่แตก - แม้จะ&
- และผลลัพธ์5
คือช่องว่างที่เก็บรักษาไว้อย่างถูกต้อง
PowerShell หลัก : pwsh -c " "^""a& c"^"".length "
ทำงานแต่ผล4
คือNormalizes ช่องว่างเป็น\""
ไม่
บนแพลตฟอร์มที่เหมือน Unix (Linux, macOS) เมื่อเรียกใช้CLI ของPowerShell [Core]pwsh
จากเชลล์ที่คล้าย POSIX เช่นbash
:
คุณต้องใช้\"
อย่างไรก็ตามทั้งปลอดภัยและรักษาช่องว่าง :
$ pwsh -c " \"a& c|\".length"
ข้อมูลที่เกี่ยวข้อง
^
เท่านั้นที่สามารถนำมาใช้เป็นตัวหนีในunquotedสตริง - สตริงภายในสองครั้งที่ยกมา^
เป็นพิเศษและไม่ถือว่าเป็นตัวอักษร
- CAVEAT : การใช้
^
ในพารามิเตอร์ที่ส่งผ่านไปยังcall
คำสั่งนั้นใช้ไม่ได้ (ใช้กับทั้งการใช้call
: การเรียกใช้ไฟล์แบตช์หรือไบนารีอื่นและการเรียกรูทีนย่อยในไฟล์แบตช์เดียวกัน):
^
กรณียกมาสองครั้งค่าเท่าตัวลึกลับเปลี่ยนแปลงมูลค่าที่ถูกส่ง: เช่นถ้าตัวแปร%v%
มีค่าที่แท้จริงa^b
, call :foo "%v%"
กำหนด"a^^b"
ที่จะ (!) %1
(พารามิเตอร์แรก) :foo
ในย่อย
- unquotedใช้
^
กับcall
จะเสียโดยสิ้นเชิงในการที่^
จะไม่สามารถใช้ในการหลบหนีตัวอักษรพิเศษ : เช่นcall foo.cmd a^&b
เงียบ ๆ แบ่ง (แทนการส่งผ่านตัวอักษรa&b
มากเกินไปfoo.cmd
เช่นจะเป็นกรณีที่โดยไม่ต้องcall
) -foo.cmd
ไม่เคยเรียกแม้อย่างน้อยบน Windows (!) 7.
การหลีกเลี่ยงลิเทอรัล%
เป็นกรณีพิเศษน่าเสียดายที่ต้องใช้ไวยากรณ์ที่แตกต่างกันขึ้นอยู่กับว่าสตริงถูกระบุในบรรทัดคำสั่งเทียบกับภายในไฟล์แบตช์หรือไม่ ดูhttps://stackoverflow.com/a/31420292/45375
- สั้น ๆ : ภายในไฟล์แบตช์ให้ใช้
%%
. ในบรรทัดคำสั่งที่%
ไม่สามารถหนีออกมา แต่ถ้าคุณวาง^
ที่เริ่มต้นสิ้นสุดหรือภายในชื่อตัวแปรในunquotedสตริง (เช่นecho %^foo%
) คุณสามารถป้องกันไม่ให้เกิดการขยายตัวของตัวแปร (แก้ไข); %
อินสแตนซ์บนบรรทัดคำสั่งที่ไม่ได้เป็นส่วนหนึ่งของการอ้างอิงตัวแปรจะถือว่าเป็นตัวอักษร (เช่น100%
)
โดยทั่วไปในการทำงานอย่างปลอดภัยกับค่าตัวแปรที่อาจมีช่องว่างและอักขระพิเศษ :
- ที่ได้รับมอบหมาย : แนบทั้งชื่อตัวแปรและความคุ้มค่าในที่เดียวคู่ของราคาสองครั้ง ; เช่น
set "v=a & b"
กำหนดค่าตามตัวอักษรa & b
ให้กับตัวแปร%v%
(ในทางตรงกันข้ามset v="a & b"
จะทำให้เครื่องหมายคำพูดคู่เป็นส่วนหนึ่งของค่า) หลีกเลี่ยง%
อินสแตนซ์ตามตัวอักษรเป็น%%
(ใช้ได้เฉพาะในไฟล์แบตช์ - ดูด้านบน)
- การอ้างอิง : การอ้างอิงตัวแปร double-quoteเพื่อให้แน่ใจว่าค่าของพวกเขาไม่ได้ถูกแก้ไข เช่น
echo "%v%"
ไม่อยู่ภายใต้ค่าของ%v%
การแก้ไขและการพิมพ์"a & b"
(แต่โปรดทราบว่าเครื่องหมายคำพูดคู่จะถูกพิมพ์อย่างสม่ำเสมอด้วย) โดยคมชัดecho %v%
ผ่านตัวอักษรa
ที่จะecho
ตำเป็นผู้ประกอบการลำดับคำสั่งและดังนั้นจึงพยายามที่จะดำเนินการคำสั่งที่มีชื่อว่า&
โปรดสังเกตข้อแม้ข้างต้นที่ใช้ซ้ำกับคำสั่งb
^
call
- โดยทั่วไปโปรแกรมภายนอกจะดูแลการลบเครื่องหมายอัญประกาศคู่รอบพารามิเตอร์ แต่ตามที่ระบุไว้ในไฟล์แบตช์คุณต้องทำด้วยตัวเอง (เช่น
%~1
เพื่อลบการปิดเครื่องหมายอัญประกาศคู่ออกจากพารามิเตอร์ที่ 1) และน่าเศร้าที่ไม่มีโดยตรง วิธีที่ฉันรู้ที่จะได้รับecho
การพิมพ์ค่าตัวแปรนับถือโดยไม่ต้องล้อมรอบราคาสองครั้ง
- นีลมีวิธีแก้ปัญหาชั่นว่างานตราบเท่าที่คุ้มค่าได้ฝังไม่มีคำพูดสอง ; เช่น:
for
set "var=^&')|;,%!"
for /f "delims=" %%v in ("%var%") do echo %%~v
cmd.exe
ไม่ได้รับรู้เดียว -quotesเป็นตัวคั่นสตริง - พวกเขาจะถือว่าเป็นตัวอักษรและไม่สามารถโดยทั่วไปจะใช้ในการสตริงคั่นด้วยช่องว่างฝัง; นอกจากนี้ยังเป็นไปตามที่โทเค็นที่ติดเครื่องหมายคำพูดเดี่ยวและโทเค็นใด ๆ ที่อยู่ระหว่างนั้นจะถือว่าไม่มีการอ้างสิทธิ์cmd.exe
และตีความตามนั้น
- อย่างไรก็ตามเนื่องจากโปรแกรมเป้าหมายดำเนินการแยกวิเคราะห์อาร์กิวเมนต์ของตนเองในท้ายที่สุดโปรแกรมบางโปรแกรมเช่น Ruby จะรู้จักสตริงที่มีเครื่องหมายอัญประกาศเดี่ยวแม้ใน Windows ในทางตรงกันข้ามไฟล์ปฏิบัติการ C / C ++, Perl และ Python ไม่รู้จักสิ่งเหล่านี้
แม้ว่าได้รับการสนับสนุนโดยโปรแกรมเป้าหมาย cmd.exe
แต่ก็ไม่แนะนำให้ใช้สายเดียวที่ยกมาระบุว่าเนื้อหาของพวกเขาจะไม่ได้รับการคุ้มครองจากการตีความที่ไม่พึงประสงค์ที่อาจเกิดขึ้นโดย
การอ้างอิงจากภายใน PowerShell:
Windows PowerShellเป็นเชลล์ขั้นสูงกว่าcmd.exe
มากและเป็นส่วนหนึ่งของ Windows มาหลายปีแล้ว (และPowerShell Coreก็นำประสบการณ์ PowerShell มาสู่ macOS และ Linux เช่นกัน)
PowerShell ทำงานภายในอย่างสม่ำเสมอเกี่ยวกับการอ้างถึง:
- ภายในสตริงที่ยกมาคู่ใช้
`"
หรือ""
เพื่อหลีกเลี่ยงเครื่องหมายอัญประกาศคู่
- ภายในสตริงที่ยกมาเดี่ยวใช้
''
เพื่อหลีกเลี่ยงเครื่องหมายคำพูดเดี่ยว
สิ่งนี้ใช้ได้กับบรรทัดคำสั่ง PowerShell และเมื่อส่งผ่านพารามิเตอร์ไปยังสคริปต์หรือฟังก์ชันPowerShell จากภายใน PowerShell
(ดังที่ได้กล่าวไว้ข้างต้นการส่งคำพูดคู่ที่ใช้ Escape ไปยัง PowerShell จากภายนอกต้องใช้\"
หรือมีประสิทธิภาพมากขึ้น\""
- ไม่มีอะไรทำงานได้อีก)
น่าเศร้าเมื่อเรียกใช้โปรแกรมภายนอกจาก PowerShell คุณต้องเผชิญกับความจำเป็นในการรองรับกฎการอ้างสิทธิ์ของ PowerShell และเพื่อหลีกเลี่ยงโปรแกรมเป้าหมาย :
พฤติกรรมที่เป็นปัญหานี้จะกล่าวถึงและสรุปไว้ในคำตอบนี้ด้วย
Double -quotes ภายในสตริงdouble -quoted :
พิจารณาสตริง"3`" of rain"
ซึ่ง 3" of rain
PowerShell-ภายในแปลเป็นตัวอักษร
หากคุณต้องการส่งสตริงนี้ไปยังโปรแกรมภายนอกคุณต้องใช้การหลบหนีของโปรแกรมเป้าหมายเพิ่มเติมจาก PowerShell's ; สมมติว่าคุณต้องการส่งสตริงไปยังโปรแกรม C ซึ่งคาดว่าเครื่องหมายคำพูดคู่ที่ฝังไว้จะถูก Escape เป็น\"
:
foo.exe "3\`" of rain"
หมายเหตุวิธีการทั้งสอง `"
- เพื่อให้มีความสุข PowerShell - และ\
- เพื่อให้มีความสุขโปรแกรมเป้าหมาย - จะต้องนำเสนอ
ตรรกะเดียวกันนี้ใช้กับการเรียกไฟล์แบตช์โดยที่""
ต้องใช้:
foo.bat "3`"`" of rain"
ในทางตรงกันข้ามการฝังsingle -quotes ในสตริงdouble -quotedไม่จำเป็นต้องมีการหลบหนีเลย
โสด -quotes ภายในเดียวสตริง -quotedไม่ไม่จำเป็นต้องเสริมหลบหนี; พิจารณา'2'' of snow'
ซึ่งเป็นตัวแทน PowerShell 2' of snow
ของ
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShell แปลสตริงที่ยกมาเดี่ยวเป็นสตริงที่ยกมาสองครั้งก่อนที่จะส่งต่อไปยังโปรแกรมเป้าหมาย
อย่างไรก็ตามdouble -quotes ภายในสตริงsingle -quotedซึ่งไม่จำเป็นต้องมีการ Escape สำหรับPowerShellยังคงต้องมีการ Escape สำหรับโปรแกรมเป้าหมาย :
foo.exe '3\" of rain'
foo.bat '3"" of rain'
PowerShell v3แนะนำ--%
ตัวเลือกเวทย์มนตร์ที่เรียกว่าสัญลักษณ์หยุดการแยกวิเคราะห์ซึ่งช่วยบรรเทาความเจ็บปวดบางอย่างโดยการส่งผ่านอะไรก็ได้หลังจากที่ไม่ได้ตีความไปยังโปรแกรมเป้าหมายบันทึกcmd.exe
การอ้างอิงตัวแปรสภาพแวดล้อม - style (เช่น%USERNAME%
) ซึ่งจะขยาย; เช่น:
foo.exe --% "3\" of rain" -u %USERNAME%
หมายเหตุวิธีหนีฝังตัว"
เป็น\"
โปรแกรมเป้าหมายเท่านั้น (และไม่ยัง PowerShell เป็น\`"
) ก็เพียงพอแล้ว
อย่างไรก็ตามแนวทางนี้:
- ไม่อนุญาตให้มีการหลีกเลี่ยง
%
อักขระเพื่อหลีกเลี่ยงการขยายตัวแปรสภาพแวดล้อม
- ห้ามการใช้ตัวแปรและนิพจน์ PowerShell โดยตรง แทนที่จะสร้างบรรทัดคำสั่งในตัวแปรสตริงในขั้นตอนแรกจากนั้นเรียกใช้
Invoke-Expression
ในวินาที
ดังนั้นแม้จะมีความก้าวหน้ามากมาย แต่ PowerShell ก็ไม่ได้ทำให้การหลบหนีง่ายขึ้นเมื่อเรียกโปรแกรมภายนอก อย่างไรก็ตามมีการแนะนำการสนับสนุนสำหรับสตริงที่ยกมาเดี่ยว
ผมสงสัยว่ามันเป็นไปได้ที่ลึกซึ้งในโลกของ Windows เพื่อสลับเคยไปแบบ Unix ของการปล่อยให้เปลือกทำทุก tokenization และอ้างการกำจัดที่ไม่คาดฝัน , ขึ้นด้านหน้า , โดยไม่คำนึงถึงโปรแกรมเป้าหมายและจากนั้นเรียกใช้โปรแกรมเป้าหมายโดยผ่านราชสกุลที่เกิด .