ไม่สามารถใช้เครื่องหมายอัศเจรีย์ (!) ในการทุบตี?


86

ฉันพยายามใช้คำสั่ง curl เพื่อเข้าถึง http url ด้วยเครื่องหมายอัศเจรีย์ ( !) ในเส้นทาง เช่น:

curl -v "http://example.org/!287s87asdjh2/somepath/someresource"

bash: ... event not foundคอนโซลตอบกลับด้วย

เกิดขึ้นที่นี่คืออะไร? และไวยากรณ์ที่เหมาะสมในการหลีกเลี่ยงเครื่องหมายอัศเจรีย์คืออะไร


แก้ไขใน bash 4.4+
Isaac

คำตอบ:


98

เครื่องหมายอัศเจรีย์เป็นส่วนหนึ่งของการขยายประวัติในทุบตี หากต้องการใช้งานคุณต้องใช้เครื่องหมายอัญประกาศเดี่ยว (เช่น:) 'http://example.org/!132'หรือใช้เครื่องหมายแบคสแลช ( \) ข้างหน้าอักขระ (เช่น:) "http://example.org/\!132"โดยตรง

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


8
"http://example.org/\!132"จริง ๆ แล้วขยายโดยไม่ต้องตีความแบ็กสแลช (POSIX ฉันเชื่อว่าเหตุผลการปฏิบัติตาม)
Chris Down

@ ChrisDown ฉันพยายามชี้แจงว่าเป็นตัวเลือกที่สองของฉันในข้อความ ขอบคุณสำหรับการชี้ให้เห็นถึงศักยภาพของความสับสน
Daniel Pittman

6
สำหรับเร็กคอร์ด: มันไม่สามารถพกพาไปได้เพื่อหลบหนี "!" คำแนะนำวิธีปฏิบัติที่ดีที่สุดคือเสนอราคา (คำพูดเดียว) "!" เสมอ ที่เกี่ยวข้อง: "^" (คาเร็ต) เป็นอักขระที่ไม่ใช่เมตาดาต้า ในที่สุด "!" ไม่ควรใช้คำสั่ง if ใช้เป็นอาร์กิวเมนต์เพื่อทดสอบแทนหากเป็นไปได้ (อีกครั้งเนื่องจาก Solaris / bin / sh)
Nicholas Wilson

5
คำพูดเดียวเท่านั้นที่ทำงานสำหรับฉัน zsh ยังคงเป็นการตีความ\!และเครื่องหมายคำพูดคู่
orkoden

1
บน Solaris (เชลล์ pre-XPG4 เก่าขยะ) '^' เป็นนามแฝงสำหรับ|และใช้เพื่อสร้างไพพ์ หากคุณส่งสคริปต์ให้กับลูกค้าและไม่สามารถแน่ใจได้ว่าพวกเขาจะใช้เชลล์อะไรคุณต้องทดสอบกับพวกเขาทั้งหมด!
นิโคลัสวิลสัน

61

set +Hเช่นเดียวกับคำตอบที่ได้รับจากแดเนียลคุณยังสามารถเพียงแค่ปิดการขยายตัวของประวัติศาสตร์โดยสิ้นเชิงถ้าคุณไม่ได้ใช้มันด้วย


19
การปิดการขยายประวัติศาสตร์ทั้งหมดเป็นคำแนะนำที่ดีที่สุดที่ฉันได้ยินมาทั้งวัน! ประวัติความเป็นมาการขยายตัวที่เป็นอันตรายและไบเซนไทน์เมื่อมีทางเลือกที่ดีมาก (ประวัติการค้นหาที่เพิ่มขึ้นด้วยCtrl-R) ที่ช่วยให้คุณสามารถดูตัวอย่างและแก้ไขคำสั่งของคุณเพื่อให้คุณไม่สุ่มสี่สุ่มห้ายิงออกไปด้วยคำสั่ง!-14ที่คุณ แต่อยู่ที่ว่าโอ๊ะจะเกิดขึ้น!-12 rm -rf *ปลอดภัย. ปิดใช้งานการขยายประวัติ! หลีกเลี่ยง!!
aculich

6
คำตอบที่ใหญ่ที่สุด: การขยายประวัติศาสตร์เป็นความเสี่ยงด้านความปลอดภัยที่ยิ่งใหญ่! มันสามารถใช้โจมตี Unix ของคุณผ่าน URL ที่สร้างขึ้น
แดน

@aculich หรือเพียงใช้คำสั่งที่ระบุ POSIX fc -14แทน แต่มันเป็นความจริงที่คุณสามารถทำได้โดยไม่ต้องเปิดใช้งานการขยายประวัติ ส่วนตัวผมใช้!$และ!viและsudo !!และแม้กระทั่งgit add !vi:$มักจะพอที่จะรับประกันการขยายตัวออกจากประวัติศาสตร์ที่เปิดใช้งาน
สัญลักษณ์แทน

ฉันคิดว่าฉันจะเพิ่มสิ่งนี้ลงในไฟล์ shell RC ของฉัน ฉันเคยใช้สิ่งนี้เป็น "เคล็ดลับ" เรียบร้อย
TonyH

17

ผมเองจะทำคำพูดเดียว แต่เพื่อความสมบูรณ์เราจะทราบเพราะมันเป็น URL ที่คุณสามารถเข้ารหัส!เป็นเช่น%21curl -v http://example.org/%21132


13

สิ่งนี้ยังสามารถทำได้

curl -v "http://example.org/"'!'"287s87asdjh2/somepath/someresource"
หรือ
curl -v "http://example.org/"\!"287s87asdjh2/somepath/someresource"

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

curl -v 'http://example.org/!'"287s87asdjh2/${basepath}/someresource"

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


มีหลายวิธีในการสร้างคำสั่ง Unix และประโยคภาษาอังกฤษที่ใช้อักขระมากกว่าที่พวกเขาต้องการและสร้างความสับสนมากกว่าที่พวกเขาต้องการ วิธีนี้เหนือกว่าคำตอบแรก / ยอมรับ / โหวตสูงสุดคือการใส่ URL ทั้งหมดในคำพูดเดียว?
G-Man

2
@ G-Man: มันเป็นอีกวิธีในการสร้างอาร์กิวเมนต์ของ bash ฉันไม่รู้วิธีนี้ ไม่มีอะไรผิดปกติในการเรียนรู้สิ่งใหม่
Sahil Singh

@SahilSingh ใหม่นี้อย่างไร มันเชื่อมสามสายเข้าด้วยกันสองอันอยู่ในเครื่องหมายคำพูดคู่และอีกหนึ่งบรรทัดอยู่ในเครื่องหมายคำพูดเดี่ยว ไม่มีรังอยู่ที่นี่
Raphael

@ G-Man ไม่ชัดเจนว่าเมื่อคุณใส่ 2 สายที่อยู่ติดกันมันจะต่อกัน printf ("hello" "world") จะทำงานใน c เช่นกัน แต่ printf ("hello" 'w') จะไม่ทำงานดังนั้นคุณจะเห็นว่าการทุบตีรองรับนิพจน์ดังกล่าวเป็นเรื่องใหม่สำหรับฉัน แต่ฉันเห็นด้วยจาก มุมมองยูทิลิตี้นี้ไม่ได้ดีกว่า ฉันชอบคำตอบดังนั้น Mark Shust ก็เช่นกัน
Sahil Singh

2
@ G-Man นอกจากนี้ยังมีประโยชน์เมื่อมีการขยายสตริงอื่น ๆ ที่ไม่ต้องการให้เกิดขึ้นในสตริงเดียวกัน นี่เป็นวิธีที่ง่ายในการแยกพฤติกรรมการอ้างอิงสองประเภท
WAF

7

ฉันเจอปัญหาเดียวกันและวิธีแก้ปัญหาง่ายๆของฉันคือใช้ตัวแปร:

E=!  
curl -v "http://example.org/${E}287s87asdjh2/somepath/someresource"

ความเรียบง่ายนี่คือ (1) เป็นแบบพกพาข้ามเชลล์และคำสั่ง (2) ไม่จำเป็นต้องรู้ไวยากรณ์การหลบหนีและรหัส ASCII


3

ตั้งแต่ Bash 4.3 ตอนนี้คุณสามารถใช้เครื่องหมายคำพูดคู่เพื่ออ้างอิงอักขระการขยายประวัติ:

$ bash --version
GNU bash, version 4.3...
[...]
$ echo "Hello World!"
Hello World!

สิ่งนี้ใช้ไม่ได้ผลechoecho ดูเหมือนว่าจะจัดการสิ่งนี้ด้วยตัวของมันเอง
phil294

@Blauhirn สิ่งนี้ไม่เกี่ยวกับเสียงก้องและทุกอย่างที่เกี่ยวกับการอ้างอิงและเวอร์ชั่นของ bash ที่คุณกำลังใช้อยู่
Flimm

2
คำตอบนี้ผิดและควรลบ bashรุ่นของคุณไม่มีส่วนเกี่ยวข้องกับการระเบิดที่ไม่ได้ถูกขยายเนื่องจากข้อเท็จจริงที่ว่าในตัวอย่างของคุณ!ตามด้วย "จุดสิ้นสุดของบรรทัด" และที่ป้องกันไม่ให้เชลล์พยายามขยาย ลอง echo "!Hello World"และคุณจะเห็นว่าจะตอบกลับด้วยbash ดูคู่มือสำหรับรายละเอียดเพิ่มเติมbash: !Hello: event not found
don_crissti

0

สำหรับผู้ที่ใช้ git bash ใน windows คำตอบที่ได้รับการยอมรับจาก @DanielPittman อย่างไรก็ตามคุณควรแทนที่แบ็กสแลช (\) ด้วยเครื่องหมายสแลช (/)

ตัวอย่างเช่นในยูนิกซ์มันจะออกมาเป็นแบบนี้:

curl https://abc.com/services -H 'Authorization: Bearer 111A80BBZZCnS\!ZR412543s'

สำหรับ windows มันจะเป็นแบบนี้ (โฟกัสไปที่เครื่องหมายสแลชในส่วนหัวการให้สิทธิ์)

curl https://abc.com/services -H 'Authorization: Bearer 111A80BBZZCnS/!ZR412543s'


มันไม่สมเหตุสมผลเลย คุณมีอาร์กิวเมนต์ที่ยกมาเดี่ยวดังนั้นโดยไม่คำนึงถึงเครื่องหมายทับที่เกี่ยวข้องกับ exclam จะไม่ส่งผลในการขยายประวัติ
สัญลักษณ์แทน

โอ้คุณพูดถูก ฉันโพสต์คำตอบนี้เพียงเพราะเมื่อฉันใช้คำตอบของ Daniel (ใช้แบ็กสแลช) ข้อผิดพลาดจะปรากฏขึ้น
SamuelDev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.