bash: วิธีการส่งผ่านอาร์กิวเมนต์บรรทัดคำสั่งที่มีอักขระพิเศษ


31

ฉันได้เขียนโปรแกรม linux programที่ต้องการนิพจน์ทั่วไปเป็นอินพุต

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

[abc]\_[x|y]

แต่น่าเสียดายที่ตัวละคร[, ]และมีอักขระพิเศษใน| bashดังนั้นการโทร

program [abc]\_[x|y] anotheragument

ไม่ทำงาน มีวิธีส่งผ่านนิพจน์โดยใช้อักขระ escape หรือเครื่องหมายอัญประกาศเป็นต้น

(การโทรprogram "[abc]\_[x|y] anotheragument"ไม่ทำงานอย่างใดอย่างหนึ่งเนื่องจากมันตีความสองข้อโต้แย้งเป็นหนึ่ง)

คำตอบ:


27

คุณสามารถ

  1. ยกเว้นสัญลักษณ์พิเศษแต่ละอันด้วยเครื่องหมายแบ็กสแลช (ตาม\[abc\]_\[x\|y\]) หรือ
  2. อ้างถึงอาร์กิวเมนต์ทั้งหมดสองครั้ง (ตามใน"[abc]_[x|y]")

แก้ไข:ในขณะที่บางคนชี้ให้เห็น dobleqouting ไม่ได้ป้องกันการขยายตัวของตัวแปรหรือการทดแทนคำสั่ง ดังนั้นหาก regex ของคุณมีบางสิ่งที่สามารถตีความได้โดย bash เป็นหนึ่งในนั้นให้ใช้เครื่องหมายคำพูดเดี่ยวแทน


4
ในทุบตีสองครั้งอ้างไม่ได้บายพาสขยายตัวแปร"$HOME"หรือพารามิเตอร์"${USER:-root}"แทนคำสั่งในรูปแบบทั้ง"$(date)"หรือ"`date`"การขยายตัวทางคณิตศาสตร์"$((1 + 2))"การขยายตัวประวัติศาสตร์หรือทับขวาหลบหนี"!!" "\\"ใช้เครื่องหมายคำพูดเดี่ยวแทน ดูหน้าคู่มือของคู่มือทุบตีส่วนหัวข้อ "การอ้างอิง"
Flimm

25

ใช้เครื่องหมายคำพูดเดี่ยว เครื่องหมายคำพูดเดี่ยวช่วยให้แน่ใจว่าไม่มีการตีความอักขระใด ๆ

$ printf %s 'spaces  are  not  interpreted away
neither are new lines
nor variable names $TESTING
nor square brackets [TESTING]
nor pipe characters or redirection symbols | > <
nor the semicolon ;
nor backslashes \a \b \c \\
the only thing that does not work is the single quote itself
'

มีสองวิธีแก้ไขหากคุณจำเป็นต้องฝังคำพูดเดียว:

$ printf '%s\n' '[ Don'"'"'t worry, be happy! ]'
[ Don't worry, be happy! ]
$ printf '%s\n' '[ Don'\''t worry, be happy! ]'
[ Don't worry, be happy! ]

ใช่คุณ +1
antichris

6

ต่อ man bash

มีกลไกการอ้างถึงสามแบบ: อักขระยกเว้นเครื่องหมายคำพูดเดี่ยวและเครื่องหมายคำพูดคู่

ทับขวาไม่ใช่ยกมา ( \ ) เป็น ตัวหนี มันรักษาคุณค่าที่แท้จริงของตัวละครต่อไปที่ตามมาด้วยข้อยกเว้นของ <newline> หากคู่\ <newline> ปรากฏขึ้นและเครื่องหมายแบ็กสแลชไม่ได้อ้างถึงตัวเอง\ <newline> จะถือว่าเป็นการต่อเนื่องของบรรทัด (นั่นคือจะถูกลบออกจากอินพุตสตรีมและละเว้นอย่างมีประสิทธิภาพ)

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

การใส่อักขระในเครื่องหมายคำพูดคู่จะเก็บรักษาค่าตัวอักษรของอักขระทั้งหมดภายในเครื่องหมายคำพูดยกเว้น$ , ` , \ , และเมื่อเปิดใช้งานการขยายประวัติ! . อักขระ$และ`รักษาความหมายพิเศษไว้ในเครื่องหมายคำพูดคู่ เครื่องหมายทับขวายังคงมีความหมายพิเศษเฉพาะเมื่อตามด้วยหนึ่งในอักขระต่อไปนี้: $ , ` , " , \ , หรือ<newline>เครื่องหมายคำพูดคู่อาจถูกยกมาภายในเครื่องหมายคำพูดคู่โดยนำหน้าด้วยเครื่องหมายแบ็กสแลชหากเปิดใช้งาน จะถูกดำเนินการยกเว้น! ปรากฏขึ้นในเครื่องหมายคำพูดคู่หนีออกมาโดยใช้เครื่องหมายทับขวา แบ็กสแลชก่อนหน้า! จะไม่ถูกลบ

พารามิเตอร์พิเศษ*และ@มีความหมายพิเศษเมื่ออยู่ในเครื่องหมายคำพูดคู่ (ดูพารามิเตอร์ด้านล่าง)

คำของฟอร์ม$ ' string 'ได้รับการปฏิบัติเป็นพิเศษ คำนี้ขยายออกเป็นสตริงโดยแทนที่อักขระเครื่องหมายทับขวาที่ทับหลังตามที่ระบุโดยมาตรฐาน ANSI C Backslash escape sequences ถ้ามีจะถูกถอดรหัสดังนี้:

       \ a      การแจ้งเตือน (ระฆัง)
        \ ข      Backspace
        \ E 
       \ E      ตัวหนี
        \ ฉ      รูปแบบฟีด
        \ n      บรรทัดใหม่
        \ r      กลับสายการบิน
        \ t      แนวแท็บ
        \ วี      แท็บแนวตั้ง
        \\      ทับขวา
        \'      คำพูดเดียว
        \"      สองเท่าอ้าง
        \ nnn    อักขระแปดบิตที่มีค่าเป็นค่าฐานแปดnnn
              (หนึ่งถึงสามหลัก)
       \ x HH    อักขระแปดบิตที่มีค่าคือค่าเลขฐานสิบหกHH
              (หนึ่งหรือสองหลักฐานสิบหก)
       \ u HHHHอักขระ Unicode (ISO / IEC 10646) ที่มีค่าคือ
              ค่าเลขฐานสิบหกHHHH (หนึ่งถึงสี่หลักสิบหก)
        \ U HHHHHHHH
              อักขระ Unicode (ISO / IEC 10646) ที่มีค่าคือ
              ค่าเลขฐานสิบหกHHHHHHHH (1-8 ตัวเลขฐานสิบหก)
        \ คx     ควบคุมxตัวอักษร

ผลลัพธ์ที่ขยายออกมาเป็นแบบเสนอราคาเดียวราวกับว่าไม่มีเครื่องหมายดอลลาร์อยู่

สตริงที่ยกมาสองครั้งนำหน้าด้วยเครื่องหมายดอลลาร์ ( $ " สตริง" ) จะทำให้สตริงที่จะแปลตามสถานที่ปัจจุบัน หากโลแคลปัจจุบันคือCหรือPOSIXเครื่องหมายดอลลาร์จะถูกละเว้น หากสตริงถูกแปลและแทนที่การแทนที่จะถูกใส่เครื่องหมายคำพูดคู่


2

คุณสามารถใช้เครื่องหมายแบ็กสแลช ( \) ด้านหน้าอักขระพิเศษเพื่อหลีกเลี่ยงสิ่งต่อไปนี้:

john @ awesome: ~ # echo \ &
&

2

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

program '[abc]_[x|y]' anotherargument

อ้างถึงแต่ละข้อโต้แย้งแยกกัน (ถ้าพวกเขาต้องการข้อความ) เพื่อที่พวกเขาจะถูกตีความว่าเป็นข้อโต้แย้งที่เป็นอิสระ คุณยังสามารถใช้อาร์เรย์ในบางกรณี:

param_array=('[abc]_[x|y]' anotherargument)    # create an array
param_array+=(yetanother)     # append another element to the array
program "${param_array[@]}"   # use the array elements as arguments to program



0

รูปแบบมาจากไหน? มันคงที่หรือจากผู้ใช้? เป็นผู้ใช้ที่เรียกใช้สคริปต์ในระบบภายในเครื่องหรือผู้อื่นจากระยะไกล?

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

  1. การเสนอราคาสองครั้งซึ่งยังอนุญาตการตีความบางอย่าง ($ Expand และ `backticks`)
  2. คำพูดเดียวซึ่งส่งผ่านทุกอย่างผ่านตัวอักษรอย่างแท้จริง

เนื่องจาก$เป็นอักขระที่ถูกต้องใน regexps (end-of-line / buffer) คุณอาจต้องการใช้เครื่องหมายอัญประกาศเดี่ยวเพื่อเก็บ regexp เว้นแต่คุณจะเก็บไว้ในตัวแปร หากคุณรับข้อมูลโดยพลการจากบุคคลที่ไม่น่าไว้วางใจคุณจะต้องแทนที่'ด้วย'"'"'และใส่คำพูดคำเดียว

โปรดทราบว่า[abc]_[x|y]ดูเหมือนว่าคุณต้องการจับคู่xหรือyในขณะที่มันจับคู่หนึ่งในสามตัวละครxy|จริงๆ เครื่องหมายวงเล็บเหลี่ยมจับคู่อักขระภายในและเฉพาะ-สำหรับช่วงและ a ^เมื่อเริ่มต้นสำหรับการปฏิเสธ ดังนั้น[abc]_(x|y)อาจเป็นสิ่งที่คุณหมายถึงและวงเล็บคืออักขระที่พิเศษสำหรับเชลล์ วงเล็บเหลี่ยมไม่ได้พิเศษกับเชลล์ แต่ดูเหมือนว่าพวกมันเป็น วงเล็บเหลี่ยมสองชั้น[[ ... ]]เป็นพิเศษ


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

มันมีความพิเศษในบริบทบางอย่างเช่นตัวห้อยตัวแปรหรือสำหรับการวนรอบ แต่คุณยังสามารถพิมพ์foo=a[b]และจากนั้นecho $fooดูว่าสตริงไม่จำเป็นต้องมีการอ้างอิง คุณพูดถูกฉันสั้นเกินไป
ฟิล P

หากคุณเป็นผู้โชคร้ายมีไฟล์abในไดเรกทอรีปัจจุบันและจากนั้นfooจะมีมากกว่าab a[b]อ้างอิงวงเล็บเหลี่ยมของคุณคน
2066 clacke

(เพื่อความชัดเจน: ฉันพูด (ตามคำตอบเดิมชัดเจนที่ฉันถูกผลักสำหรับการอ้างอิง) และนี่คือการตกรางด้านข้างที่ฉันพูดถึง) คำยืนยันนี้ทำให้ฉันประหลาดใจดังนั้นฉันจึงทดสอบ ไม่เป็นความจริงใน zsh หรือ bash แต่เป็นจริงใน BSD / bin / sh สิ่งนี้ขัดต่อ POSIX และเป็นพฤติกรรมที่ไม่ได้มาตรฐานดังนั้นคุณจะต้องพูดเพื่อจัดการ ใน zsh คุณสามารถsetopt glob_assignเปิดใช้งานลักษณะการทำงานนี้ได้เช่นกันดังนั้นการอ้างอิงเป็นคำตอบที่ปลอดภัยที่สุด
Phil P
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.