ใน Bash เมื่อระบุอาร์กิวเมนต์บรรทัดคำสั่งให้กับคำสั่งจำเป็นต้องใช้อักขระใดในการหลีกเลี่ยง
พวกเขาจะถูก จำกัด ให้ metacharacters ของทุบตี: พื้นที่แท็บ
|
, &
, ;
, (
, )
, <
และ>
?
ใน Bash เมื่อระบุอาร์กิวเมนต์บรรทัดคำสั่งให้กับคำสั่งจำเป็นต้องใช้อักขระใดในการหลีกเลี่ยง
พวกเขาจะถูก จำกัด ให้ metacharacters ของทุบตี: พื้นที่แท็บ
|
, &
, ;
, (
, )
, <
และ>
?
คำตอบ:
อักขระต่อไปนี้มีความหมายพิเศษต่อเชลล์เองในบางบริบทและอาจจำเป็นต้องมีการหลบหนีในอาร์กิวเมนต์:
`
Backtick (U + 0060 Grave Accent)~
หนอน (U + 007E)!
เครื่องหมายอัศเจรีย์ (U + 0021)#
Hash (เครื่องหมายหมายเลข U + 0023)$
เครื่องหมายดอลลาร์ (U + 0024)&
เครื่องหมาย & (U + 0026)*
เครื่องหมายดอกจัน (U + 002A)(
วงเล็บซ้าย (U + 0028))
วงเล็บปิด (U + 0029)
( ⇥
) แท็บ (U + 0009){
วงเล็บปีกกาซ้าย (U + 007B วงเล็บปีกกาซ้าย)[
วงเล็บเหลี่ยมด้านซ้าย (U + 005B)|
แถบแนวตั้ง (U + 007C เส้นแนวตั้ง)\
ทับขวา (U + 005C ย้อนโซลิดัส);
อัฒภาค (U + 003B)'
คำพูดเดี่ยว / Apostrophe (U + 0027)"
เครื่องหมายคำพูดคู่ (U + 0022)↩
บรรทัดใหม่ (U + 000A)<
น้อยกว่า (U + 003C)>
มากกว่า (U + 003E)?
เครื่องหมายคำถาม (U + 003F)
Space (U + 0020) 1ตัวละครเหล่านี้บางตัวใช้สำหรับสิ่งต่าง ๆ และในที่มากกว่าตัวละครที่ฉันเชื่อมโยง
มีบางกรณีที่มีมุมที่เป็นทางเลือกอย่างชัดเจน:
!
สามารถปิดการใช้งานด้วยset +H
ซึ่งเป็นค่าเริ่มต้นในเปลือกไม่ใช่แบบโต้ตอบ{
set +B
สามารถใช้งานกับ*
และ?
สามารถใช้งานด้วยหรือset -f
set -o noglob
=
เครื่องหมายเท่ากับ (U + 003D) ต้องมีการหลีกหนีหากเปิดใช้งานset -k
หรือset -o keyword
เปิดใช้งานการขึ้นบรรทัดใหม่ต้องใช้การอ้างอิง - แบ็กสแลชจะไม่ทำงาน ตัวละครอื่น ๆ ที่ระบุในIFSจะต้องมีการจัดการที่คล้ายกัน คุณไม่จำเป็นที่จะหลบหนี]
หรือ}
แต่คุณไม่จำเป็นต้องหนี)
เพราะมันเป็นผู้ดำเนินการ
ตัวละครเหล่านี้บางตัวมีข้อ จำกัด ที่เข้มงวดมากขึ้นเมื่อพวกเขาต้องการหลบหนีอย่างแท้จริง ตัวอย่างเช่นa#b
ก็โอเค แต่a #b
เป็นความคิดเห็นในขณะที่>
จะต้องหลบหนีในบริบททั้งสอง มันไม่เจ็บที่จะหลบหนีพวกเขาอย่างอนุรักษ์นิยมทั้งหมดและมันง่ายกว่าจดจำความแตกต่างที่ดี
ถ้าชื่อคำสั่งของคุณเองเป็นคำหลักเปลือก ( if
, for
, do
) แล้วคุณจะต้องหลบหนีหรือพูดมันมากเกินไป สิ่งที่น่าสนใจเพียงอย่างเดียวคือin
เพราะมันไม่ชัดเจนว่าเป็นคำหลักเสมอ คุณไม่จำเป็นต้องทำเช่นนั้นสำหรับคำหลักที่ใช้ในการโต้แย้งเฉพาะเมื่อคุณ (โง่เขลา!) ตั้งชื่อคำสั่งหลังจากหนึ่งในนั้น ตัวดำเนินการเชลล์ ( (
, &
ฯลฯ ) จำเป็นต้องมีการอ้างอิงทุกที่
1 Stéphaneตั้งข้อสังเกตว่าอักขระว่างไบต์เดียวอื่น ๆจากโลแคลของคุณต้องหลบหนี ในสถานที่ที่พบเห็นได้ทั่วไปส่วนใหญ่อย่างน้อยที่อยู่บนพื้นฐานของ C หรือ UTF-8 เป็นเพียงอักขระช่องว่างด้านบน ในที่ตั้ง ISO-8859-1 บางพื้นที่ U + 00A0 ไม่มีการหยุดพักถือว่าว่างเปล่ารวมถึง Solaris, BSDs และ OS X (ฉันคิดว่าไม่ถูกต้อง) หากคุณกำลังจัดการกับสถานที่ที่ไม่รู้จักโดยพลการมันอาจรวมถึงอะไรก็ได้รวมถึงตัวอักษรโชคดีมาก
น่าจะเป็นไบต์เดียวที่พิจารณาว่าว่างเปล่าอาจปรากฏขึ้นในตัวละครหลายไบต์ที่ไม่ได้ว่างเปล่าและคุณไม่มีทางที่จะหลบหนีไปได้นอกจากการใส่ทุกอย่างไว้ในเครื่องหมายคำพูด นี่ไม่ใช่ข้อกังวลทางทฤษฎี: ในโลแคล ISO-8859-1 จากด้านบนA0
ไบต์ที่ถือว่าว่างสามารถปรากฏภายในอักขระหลายไบต์เช่น UTF-8 ที่เข้ารหัส "à" ( C3 A0
) "à"
ที่จะจัดการกับตัวอักษรเหล่านั้นได้อย่างปลอดภัยคุณจะต้องพูดกับพวกเขา ลักษณะการทำงานนี้ขึ้นอยู่กับการกำหนดค่าโลแคลในสภาพแวดล้อมที่ใช้งานสคริปต์ไม่ใช่สิ่งที่คุณเขียน
ฉันคิดว่าพฤติกรรมนี้เสียไปหลายวิธี แต่เราต้องเล่นด้วยมือที่เราจัดการ หากคุณกำลังทำงานกับชุดอักขระหลายไบต์ที่ไม่ซิงโครไนซ์ด้วยตนเองสิ่งที่ปลอดภัยที่สุดคือการพูดทุกอย่าง หากคุณอยู่ใน UTF-8 หรือ C คุณจะปลอดภัย (ในขณะนี้)
!
เมื่อเปิดใช้งานการขยายประวัติ csh โดยปกติแล้วจะไม่ได้อยู่ในสคริปต์ [ ! -f a ]
หรือfind . ! -name...
ไม่เป็นไร สิ่งนี้กล่าวถึงในส่วน จำกัด ที่เข้มงวดยิ่งขึ้นของคุณแต่อาจคุ้มค่าที่จะกล่าวถึงอย่างชัดเจน
hash[foo"]"]=
, ${var-foo"}"}
, [[ "!" = b ]]
, [[ a = "]]" ]]
ผู้ประกอบการ regexp [[ x =~ ".+[" ]]
สำหรับ คำหลักอื่น ๆ กว่า{
( if
, while
, for
... ) จะต้องมีการยกมาเพื่อให้พวกเขาไม่ได้รับการยอมรับว่าเป็นเช่นนั้น ...
]
) ดังนั้นฉันจึงไม่แสดงรายการเหล่านั้น ฉันไม่คิดว่าคำหลักใด ๆ ที่จำเป็นต้องมีการอ้างถึงในตำแหน่งอาร์กิวเมนต์
ใน GNU Parallel การทดสอบและใช้อย่างกว้างขวาง:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
จะมีการทดสอบในbash
, dash
, ash
, ksh
, และzsh
fish
อักขระบางตัวไม่จำเป็นต้องมีการอ้างถึงในบางเชลล์ (เวอร์ชั่น) แต่การทำงานด้านบนในเชลล์ที่ทดสอบทั้งหมด
หากคุณต้องการสตริงที่ยกมาคุณสามารถไปที่parallel --shellquote
:
printf "&*\t*!" | parallel --shellquote
สำหรับโซลูชันการหลบหนีที่มีน้ำหนักเบาใน Perl ฉันกำลังทำตามหลักการของการเสนอราคาเดียว สตริง Bash ในเครื่องหมายคำพูดเดี่ยวสามารถมีอักขระใด ๆ ยกเว้นเครื่องหมายคำพูดเดียว
รหัสของฉัน:
my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);
while(<>) {
if (/$bash_reserved_characters_re/) {
my $quoted = s/'/'"'"'/gr;
print "'$quoted'";
} else {
print $_;
}
}
ตัวอย่างการเรียกใช้ 1:
$ echo -n "abc" | perl escape_bash_special_chars.pl
abc
ตัวอย่างการรัน 2:
echo "abc" | perl escape_bash_special_chars.pl
'abc
'
ตัวอย่างการรัน 3:
echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c
ตัวอย่างการเรียกใช้ 4:
echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'
ตัวอย่างรัน 5:
echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'
echo 'ab'"'"'c'
ab'c