หลีกเลี่ยงเครื่องหมายคำพูดคู่ในพารามิเตอร์


109

ในระบบปฏิบัติการยูนิกซ์ฉันสามารถเรียกใช้และฉันจะได้รับmyscript '"test"'"test"

ใน Windows ฉันได้รับcmd'test'

ฉันจะส่งเครื่องหมายคำพูดคู่เป็นพารามิเตอร์ได้อย่างไร ฉันต้องการทราบวิธีการดำเนินการนี้ด้วยตนเองจากcmdหน้าต่างเพื่อที่ฉันจะได้ไม่ต้องเขียนโปรแกรมเพื่อทดสอบโปรแกรมของฉัน


2
เป็นเวลาหลายปีแล้วที่ฉันสัมผัสเครื่อง windows แต่อักขระ Escape มาตรฐาน (แบ็กสแลช \) ใช้งานไม่ได้? เช่นmyscript \"test\"
Gazler

ไม่ ฉันได้รับการทดสอบ \. ฉันสงสัยว่าเป็นเพราะ windows ใช้ \ แทน / ดังนั้นจึงไม่สามารถใช้แบ็กสแลชเป็นเอสเคปเปอร์ได้ แต่ฉันไม่รู้จริงๆ
Bryan Field

Idk เวอร์ชันของ Windows ที่คุณใช้อยู่ แต่ \ "ทำงานได้ดีบน Windows 7 (Ultimate) แม้ว่าจะมีวิธีอื่นในการจัดการกับเครื่องหมายคำพูดหลายคำ (เช่น" "" กลาย "หรือบางอย่าง) แต่ฉันทำไม่ได้ คิดว่ามันทำงานเมื่อไหร่และอย่างไร
Codesmith

2
อาจทำซ้ำได้ของEscaping Double Quotes ใน Batch Script
sirdank

คำตอบ:


22

ฉันไม่สามารถทำซ้ำอาการได้อย่างรวดเร็ว: ถ้าฉันลองmyscript '"test"'ใช้ไฟล์แบตช์myscript.batที่มีเพียงแค่@echo.%1หรือแม้กระทั่ง@echo.%~1ฉันจะได้รับเครื่องหมายคำพูดทั้งหมด:'"test"'

บางทีคุณอาจลองใช้อักขระหนี^เช่นนี้: myscript '^"test^"'?


3
ถ้าอย่างนั้นคำตอบของคำถามนี้อาจช่วยคุณเพิ่มเติมได้หรือไม่?
mousio

2
ฮา! ฉันไม่เคยเดาเลยว่ามันเป็นwscriptความผิด! ปล่อยให้ Windows :)
Bryan Field

4
จริงๆแล้ว ^ ไม่ได้ผลสำหรับฉัน แต่ \ ทำตามคำตอบนี้: stackoverflow.com/questions/2403647/…
kalenjordan

27
Windows: ระบบปฏิบัติการที่ใช้ globbing การขยายเชลล์และพารามิเตอร์ unescaping โดยการเรียกใช้งานปฏิบัติการแทนเชลล์ คุณไม่มีทางรู้ว่าอนุสัญญาใดที่เรียกได้ว่ามีเกียรติประวัติในการปฏิบัติการ
binki

7
ข้อมูลที่มีค่า: blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/… . cmdเครื่องหมายตกย่อมเป็นตัวหนีของทางเลือกสำหรับ
ปีเตอร์ - คืนสถานะโมนิกา

198

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

นี่คือชุดของกฎพื้นฐาน:

  1. เมื่อไม่ได้ห่อในกลุ่มยกมาสองครั้งพื้นที่แยกพารามิเตอร์
    program param1 param2 param 3จะผ่านพารามิเตอร์สี่ถึงprogram.exe:
         param1, param2, และparam3
  2. กลุ่มยกมาสองครั้งละเว้นช่องว่างเป็นตัวคั่นค่าพารามิเตอร์เมื่อผ่านไปยังโปรแกรม:
    program one two "three and more"จะผ่านสามพารามิเตอร์program.exe:
         one, และtwothree and more
  3. ตอนนี้เพื่ออธิบายความสับสน:
  4. กลุ่มที่ปรากฏอยู่ติดกันโดยตรงกับข้อความที่ไม่ได้ห่อด้วยราคาสองครั้งเข้าร่วมออกเป็นพารามิเตอร์หนึ่งยกมาสองครั้ง: ทำหน้าที่เป็นหนึ่งพารามิเตอร์:
    hello"to the entire"worldhelloto the entireworld
  5. หมายเหตุ: กฎก่อนหน้านี้ไม่ได้หมายความว่ากลุ่มที่ยกมาคู่สองกลุ่มสามารถปรากฏติดกันได้โดยตรง
  6. เครื่องหมายอัญประกาศคู่ใด ๆโดยตรงหลังเครื่องหมายคำพูดปิดจะถือว่าเป็น (หรือเป็นส่วนหนึ่งของ) ข้อความธรรมดาที่ไม่ได้ปิดทับที่อยู่ติดกับกลุ่มเครื่องหมายคำพูดคู่ แต่มีเครื่องหมายอัญประกาศคู่เดียวเท่านั้น:
    "Tim says, ""Hi!"""จะทำหน้าที่เป็นพารามิเตอร์เดียว:Tim says, "Hi!"

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

"เปิดกลุ่มคำพูดคู่
T ภายใน "" s
ฉันอยู่ข้างใน "" s
ม. ภายใน "" s
    ภายใน "" s - ช่องว่างไม่แยกจากกัน
s ภายใน "" s
ภายใน "" s
y ข้างใน "" s
s ภายใน "" s
, ข้างใน "" s
    ภายใน "" s - ช่องว่างไม่แยกจากกัน
"ปิดกลุ่มที่ยกมาสองครั้ง
"quote โดยตรงตามใกล้ - ทำหน้าที่เป็นข้อความธรรมดาที่ไม่ได้ห่อ:"
H ภายนอก "" - เข้าร่วมกับกลุ่มที่อยู่ติดกันก่อนหน้านี้
ฉันอยู่ข้างนอก "" ส - ...
! ภายนอก "" ส - ...
"เปิดกลุ่มคำพูดคู่
"ปิดกลุ่มเครื่องหมายคำพูดคู่
"quote โดยตรงตามใกล้ - ทำหน้าที่เป็นข้อความธรรมดาที่ไม่ได้ห่อ:"

ดังนั้นข้อความจึงรวมกลุ่มของอักขระสี่กลุ่มได้อย่างมีประสิทธิภาพ (กลุ่มหนึ่งไม่มีอะไรเลย):
Tim says,  เป็นกลุ่มแรกที่ห่อเพื่อหลีกเลี่ยงช่องว่าง
"Hi!คือกลุ่มที่สองไม่ได้ห่อ (ไม่มีช่องว่าง)
 เป็นกลุ่มที่สามซึ่งเป็นกลุ่มเครื่องหมายคำพูดคู่ที่ไม่ห่ออะไรเลย
"เป็นคำพูดที่สี่ซึ่งเป็นคำพูดปิดท้าย

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

จากสิ่งนี้ควรเป็นที่จดจำได้ดังนั้นอัญประกาศภายในและภายนอกเครื่องหมายคำพูดคู่สามคำจึงทำหน้าที่เป็นเครื่องหมายอัญประกาศคู่แบบข้อความธรรมดาที่ไม่ใช้ Escape:

"ทิมพูดกับเขา" "" เมื่อเร็ว ๆ นี้เกิดอะไรขึ้น "" ""

จะพิมพ์Tim said to him, "What's been happening lately?"ตามที่คาดไว้ ดังนั้นจึงสามารถใช้เครื่องหมายคำพูดสามคำเพื่อหลีกหนีได้อย่างน่าเชื่อถือ
อย่างไรก็ตามในการทำความเข้าใจคุณอาจสังเกตได้ว่าเครื่องหมายอัญประกาศสี่รายการในตอนท้ายสามารถลดลงเหลือเพียงสองเนื่องจากในทางเทคนิคแล้วเป็นการเพิ่มกลุ่มที่มีเครื่องหมายอัญประกาศว่างเปล่าที่ไม่จำเป็นอีกกลุ่มหนึ่ง

ต่อไปนี้เป็นตัวอย่างบางส่วนในการปิด:

โปรแกรม ab REM ส่ง (a) และ (b)
โปรแกรม "" "a" "" REM ส่ง ("a")
โปรแกรม "" "a b" "" REM ส่ง ("a) และ (b")
โปรแกรม "" "" สวัสดี "" "ไมค์กล่าว" REM ส่ง ("สวัสดี" ไมค์กล่าว)
โปรแกรม "" a "" b "" c "" d "" REM ส่ง (abcd) เนื่องจากกลุ่ม "" ไม่ได้ตัดอะไรเลย
โปรแกรม "hello to" "" quotes "" REM ส่ง (สวัสดีกับ "quotes")
โปรแกรม "" "" hello world "" REM ส่ง ("hello world")
โปรแกรม "" "hello" world "" REM ส่ง ("hello world")
โปรแกรม "" "hello" world "" REM ส่ง ("hello) และ (world")
โปรแกรม "hello" "world" "" REM ส่ง (สวัสดี "world")
โปรแกรม "hello" "" world "" REM ส่ง (สวัสดี "world")

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

ฉันทดสอบสิ่งนี้บน Windows 7, 64 บิตโดยใช้การโทร * .exe เท่านั้นที่มีการส่งผ่านพารามิเตอร์ (ไม่ใช่ * .bat แต่ฉันคิดว่ามันใช้งานได้เหมือนกัน)


12
+1 แต่โปรดทราบว่าพฤติกรรมนี้ขึ้นอยู่กับแอปพลิเคชัน ใน Windows แต่ละแอปพลิเคชันจะแยกวิเคราะห์พารามิเตอร์บรรทัดคำสั่งของตนเอง ฉันเชื่อว่าพฤติกรรมที่คุณอธิบายนั้นเป็นของไลบรารี C มาตรฐานของ Microsoft ซึ่งฉันคิดว่ามีการทำซ้ำโดยคอมไพเลอร์ Windows C อื่น ๆ ส่วนใหญ่
Harry Johnston

3
ข้อผิดพลาดหลายประการในคำอธิบายล่าสุดของคุณ โปรแกรม "" "ab" "" -> ("ab"), โปรแกรม "hello to" "" quotes "" -> (hello to "quotes), program" "" "hello world" "-> (" Hello) (world), โปรแกรม "" "hello" world "" -> ("hello) (world), program" "" hello "world" "-> (" hello world), โปรแกรม "hello" "" world "" - > (hello "world)
Thomson

46
... ทั้งหมดที่ฉันพูดได้คือไฟล์แบตช์ของ Windows มีปัญหา นี่คือคำพูดที่หลบหนีเพราะเห็นแก่พระคริสต์ มันไม่ควรจะเป็นวิทยาศาสตร์จรวดอะไรสักอย่าง
James Ko

4
@JamesKo ฉันไม่เห็นด้วยมากกว่านี้ ความไร้สาระและความไม่ลงรอยกันของบรรทัดคำสั่ง Windows ไม่เคยทำให้ฉันโกรธ ใครเป็นคนออกแบบขยะนี้? โอ้ชั่วโมงที่เสียไปตลอดหลายปี! Unix นั้นง่ายมากและสมเหตุสมผลมากในการเปรียบเทียบ
Carlos A.Ibarra


24

ลองสิ่งนี้:

myscript """test"""

"" Escape to a single "ในพารามิเตอร์


1
นั่นไม่ถูกต้องนัก ลองmyscript """test test"""แล้วไม่ได้ผล (พารามิเตอร์ตัวแรกถูกส่งมาเป็นแบบ"testเฉียบพลันคุณต้องมีเครื่องหมายคำพูดสามคำ: myscript """"test test""แม้ว่าเครื่องหมายคำพูดที่สามในตอนท้ายสามารถข้ามไปได้
Ignitor

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

2
อาจจะไม่จุดสำหรับคำถามนี้ แต่ช่วยให้ฉันเมื่อฉันต้องการที่จะผ่านchar **argvจากตัวฉัน C กับกระบวนการอื่นโดยใช้ฟังก์ชั่นเหมือนหรือspawn execขอบคุณ. :-)
ราศีกันย์ 47

2

เอกสารฉบับที่ 2 ที่ Peter Mortensen กล่าวถึงในความคิดเห็นของเขาเกี่ยวกับคำตอบของ Codesmith ทำให้สิ่งต่างๆชัดเจนขึ้นสำหรับฉัน เอกสารนั้นเขียนโดย windowsinspired.com การเชื่อมโยงซ้ำ: วิธีที่ดีกว่าการทำความเข้าใจและ Quoting หนีของข้อโต้แย้งของ

การลองผิดลองถูกเพิ่มเติมบางอย่างนำไปสู่แนวทางต่อไปนี้:

หลีกหนีทุกคำพูดคู่"ด้วยเครื่องหมายคาเร็^ต หากคุณต้องการตัวละครอื่น ๆ ที่มีความหมายเป็นพิเศษกับเปลือกคำสั่งของ Windows (เช่น<, >, |, &) ที่จะตีความว่าเป็นตัวละครปกติแทนแล้วหลบหนีพวกเขาด้วยเครื่องหมายมากเกินไป

หากคุณต้องการโปรแกรมของคุณfooจะได้รับข้อความบรรทัดคำสั่ง"a\"b c" > dและการเปลี่ยนเส้นทางการส่งออกไปยังแฟ้มout.txtแล้วเริ่มต้นโปรแกรมของคุณดังนี้จากเปลือกคำสั่งของ Windows:

foo ^"a\^"b c^" ^> d > out.txt

ถ้าfooตีความ\"เป็นราคาคู่ที่แท้จริงและคาดว่าราคาคู่ใช้ Escape ข้อโต้แย้งคั่นที่มีช่องว่างแล้วfooตีความคำสั่งตามที่ระบุหนึ่งอาร์กิวเมนต์a"b cหนึ่งอาร์กิวเมนต์และอาร์กิวเมนต์หนึ่ง>d

หากแทนfooตีความเครื่องหมายอัญประกาศคู่""เป็นเครื่องหมายคำพูดคู่ตามตัวอักษรให้เริ่มโปรแกรมของคุณเป็น

foo ^"a^"^"b c^" ^> d > out.txt

ข้อมูลเชิงลึกที่สำคัญจากเอกสารที่ยกมาคือสำหรับเชลล์คำสั่งของ Windows เครื่องหมายคำพูดคู่ที่ไม่ใช้ Escape จะเรียกการสลับระหว่างสองสถานะที่เป็นไปได้

การทดลองและข้อผิดพลาดเพิ่มเติมบางอย่างบ่งบอกว่าในสถานะเริ่มต้นระบบจะรับรู้การเปลี่ยนเส้นทาง (ไปยังไฟล์หรือไปป์) และเครื่องหมายคาเร็ตจะหลีกเลี่ยงเครื่องหมาย^คำพูดคู่และเครื่องหมายคาเร็ตจะถูกลบออกจากอินพุต ในอีกสถานะหนึ่งจะไม่รู้จักการเปลี่ยนเส้นทางและเครื่องหมายคาเร็ตจะไม่หนีเครื่องหมายอัญประกาศคู่และจะไม่ถูกลบออก ลองอ้างถึงสถานะเหล่านี้ว่า 'ภายนอก' และ 'ภายใน' ตามลำดับ

หากคุณต้องการเปลี่ยนทิศทางผลลัพธ์ของคำสั่งของคุณเชลล์คำสั่งจะต้องอยู่ในสถานะภายนอกเมื่อถึงการเปลี่ยนเส้นทางดังนั้นจึงต้องมีเครื่องหมายคำพูดคู่ที่ไม่ใช้ Escape (โดยคาเร็ต) จำนวนเท่ากันก่อนการเปลี่ยนเส้นทาง foo "a\"b " > out.txtจะไม่ทำงาน - เชลล์คำสั่งผ่านทั้ง"a\"b " > out.txtการfooเป็นอาร์กิวเมนต์บรรทัดคำสั่งรวมของมันแทนการส่งผ่านเพียง"a\"b "และเปลี่ยนเส้นทางออกไปout.txt

foo "a\^"b " > out.txtจะไม่ทำงานอย่างใดอย่างหนึ่งเพราะลูกศร^จะพบในรัฐภายในที่เป็นตัวอักษรธรรมดาและไม่ได้เป็นตัวหนีเพื่อให้"a\^"b " > out.txtได้รับการส่งผ่านไปยังfoo

วิธีเดียวที่ (หวังว่า) จะใช้ได้ผลเสมอคือให้เชลล์คำสั่งอยู่ในสถานะภายนอกเสมอเพราะการเปลี่ยนเส้นทางจะทำงาน

หากคุณไม่ต้องการการเปลี่ยนเส้นทาง (หรืออักขระอื่น ๆ ที่มีความหมายพิเศษสำหรับเชลล์คำสั่ง) คุณสามารถทำได้โดยไม่ต้องใช้คาเร็ต หากfooตีความ\"ว่าเป็นเครื่องหมายคำพูดคู่ตามตัวอักษรคุณสามารถเรียกมันว่า

foo "a\"b c"

จากนั้นfooรับเป็นข้อความข้อโต้แย้งรวมและสามารถตีความมันเป็นอาร์กิวเมนต์เดียวเท่ากับ"a\"b c"a"b c

ตอนนี้ - สุดท้าย - สำหรับคำถามเดิม myscript '"test"'เรียกจากเปลือกคำสั่งของ Windows ผ่าน'"test"'ไปMyScript เห็นได้ชัดว่าmyscriptตีความเครื่องหมายคำพูดเดี่ยวและคู่เป็นตัวคั่นอาร์กิวเมนต์และลบออก คุณต้องหาว่าmyscriptยอมรับอะไรเป็นเครื่องหมายคำพูดคู่ตามตัวอักษรจากนั้นระบุในคำสั่งของคุณโดยใช้^เพื่อหลีกเลี่ยงอักขระใด ๆ ที่มีความหมายพิเศษกับเชลล์คำสั่งของ Windows เนื่องจากmyscriptมีให้ใน Unix ด้วยอาจ\"จะเป็นเคล็ดลับ ลอง

myscript \^"test\^"

หรือหากคุณไม่ต้องการการเปลี่ยนเส้นทาง

myscript \"test\"

ขอบคุณ! ฉันทุบหัวของฉันบนผนังพยายามเรียกใช้ vbscript โดยข้อความพรอมต์ cmd ถูกสะท้อนเป็นข้อความพรอมต์ cmd - ฉันได้รับสิ่งนี้มา - และไม่สามารถหาวิธีที่จะหลบหนีเครื่องหมายคำพูดได้
PopeDarren

0

ฉันเรียก powershell จาก cmd และการส่งผ่านคำพูดและการหลบหนีที่นี่ไม่ได้ผล สำเนียงที่รุนแรงใช้เพื่อหลีกเลี่ยงเครื่องหมายคำพูดคู่ใน Win 10 surface pro นี้

>powershell.exe "echo la`"" >> test
>type test
la"

ด้านล่างนี้เป็นผลลัพธ์ที่ฉันได้รับสำหรับอักขระอื่น ๆ เพื่อหลีกเลี่ยงเครื่องหมายคำพูดคู่:

la\
la^
la
la~

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

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