วิธีที่จะสะท้อนปัง!


59

ฉันพยายามสร้างสคริปต์โดยecho'ing เนื้อหาลงในไฟล์แทนที่จะเปิดมันด้วยเครื่องมือแก้ไข

echo -e "#!/bin/bash \n /usr/bin/command args"  > .scripts/command

เอาท์พุท :

bash:! / bin / bash: ไม่พบเหตุการณ์

ฉันได้แยกพฤติกรรมแปลกนี้ไปปัง

$ echo !
!  

$ echo "!"
bash: !: event not found

$ echo \#!
#!

$ echo \#!/bin/bash
bash: !/bin/bash: event not found
  • ทำไมปังทำให้สิ่งนี้
  • "กิจกรรม" ที่ทุบตีหมายถึงอะไร
  • ฉันจะแก้ไขปัญหานี้แล้วพิมพ์ "#! / bin / bash" ไปที่หน้าจอหรือไฟล์ของฉันได้อย่างไร

คำตอบ:


59

ลองใช้คำพูดเดียว

echo -e '#!/bin/bash \n /usr/bin/command args'  > .scripts/command

echo '#!'

echo '#!/bin/bash'

ปัญหาเกิดขึ้นเนื่องจาก bash กำลังค้นหาประวัติของ! / bin / bash การใช้อัญประกาศเดี่ยวจะหลีกเลี่ยงพฤติกรรมนี้


3
นอกจากนี้ยังปิดใช้งานการแก้ไขสตริง :(
Hubro

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

3
$''คุณยังสามารถใช้สตริงสไตล์ซีในทุบตีด้วย ตัวอย่างเช่นecho $'1!\n2!\n3!\n'พิมพ์แต่ละหมายเลขตามด้วยปังและขึ้นบรรทัดใหม่
spelufo

1
การใส่ปังในเครื่องหมายคำพูดเดี่ยวไม่ได้ช่วยฉันเลยเมื่อป้อนสตริงหลายบรรทัด:! ทุบตี - คำพูดเดียวไม่หนีปัง (ของจริง)
binki

1
@kbolino คุณพูดถูก ดังนั้นสตริงตัวอย่างแบบเต็มจะเป็น: echo '0123'"$var"'456'ให้สังเกตเครื่องหมายคำพูดเดี่ยวสองคู่และเครื่องหมายคำพูดคู่หนึ่งคู่
phyatt

16

ในฐานะที่เป็นRichm กล่าวว่าทุบตีพยายามที่จะทำตรงกับประวัติศาสตร์ อีกวิธีหนึ่งในการหลีกเลี่ยงคือการหนีจากปังด้วย\:

$ echo \#\!/bin/bash
#!/bin/bash

แม้ว่าระวังว่าภายในเครื่องหมายคำพูดคู่ แต่\จะไม่ถูกลบออก:

$ echo "\!"
\!

8
ใน bash "\!"จริง ๆ แล้วขยายไปถึง\!ไม่ใช่!เพื่อให้สอดคล้องกับ POSIX
มิเคล

@Mikel ถอนหายใจ ความแตกต่างมากมายระหว่าง zsh และ bash
Michael Mrozek

สิ่งนี้ใช้ได้แม้กระทั่งเมื่อป้อนสตริงหลายบรรทัด การระลึกถึง 1. อยู่นอกสตริงเมื่อป้อน bang และ 2. ใช้วิธีนี้ (แบ็กสแลช) ดูเหมือนว่าจะทำงานด้วยความประหลาดใจน้อยที่สุดในสถานการณ์ส่วนใหญ่
binki

1
จะมีประโยชน์เมื่อทราบว่า bash ไม่ทำการค้นหาประวัติเมื่อเรียกใช้สคริปต์ดังนั้นจึงไม่จำเป็นต้องทำอะไรเป็นพิเศษในนั้น
binki

ไม่มีไวยากรณ์ใดที่จะหนีจาก!เครื่องหมายคำพูดคู่โดยไม่มีพฤติกรรมเวทมนต์ได้หรือไม่? นี่คือถั่ว ...
Lassi

13

!เริ่มการทดแทนประวัติ (“ เหตุการณ์” เป็นบรรทัดในประวัติคำสั่ง); ตัวอย่างเช่น!lsขยายบรรทัดคำสั่งสุดท้ายที่มีlsและขยายไปยังบรรทัดคำสั่งสุดท้ายที่มี!?foo fooคุณยังสามารถแยกคำที่เฉพาะเจาะจง (เช่น!!:1หมายถึงคำแรกของคำสั่งก่อนหน้า) และอื่น ๆ ; ดูคู่มือสำหรับรายละเอียด

คุณลักษณะนี้คิดค้นขึ้นเพื่อเรียกคืนคำสั่งก่อนหน้าอย่างรวดเร็วในวันที่รุ่นบรรทัดคำสั่งดั้งเดิม ด้วยเชลล์ที่ทันสมัย ​​(อย่างน้อย bash และ zsh) และ copy-and-paste การขยายประวัติไม่เป็นประโยชน์อย่างที่เคยเป็น - มันยังคงมีประโยชน์ แต่คุณสามารถทำได้โดยไม่ต้องใช้มัน

คุณสามารถเปลี่ยนได้ว่าจะให้ตัวละครตัวไหนแทนค่าประวัติโดยการตั้งค่าhistcharsตัวแปร; ถ้าคุณไม่ค่อยใช้ทดแทนประวัติคุณสามารถตั้งค่าเช่นhistchars='¡^'เพื่อให้ก่อให้เกิดการขยายตัวของประวัติศาสตร์แทน¡ คุณยังสามารถปิดคุณลักษณะทั้งหมดที่มี!set +o histexpand


3

หากต้องการปิดใช้งานการขยายประวัติในบรรทัดคำสั่งเฉพาะคุณสามารถใช้spaceเป็นอักขระที่ 3 ของ$histchars:

histchars='!^ '

จากนั้นหากคุณป้อนคำสั่งด้วยช่องว่างนำหน้าการขยายประวัติจะไม่ถูกดำเนินการ

bash-4.3$ echo "#!/bin/bash"
bash: !/bin/bash: event not found
bash-4.3$  echo "#!/bin/bash"
#!/bin/bash

โปรดทราบว่าช่องว่างนำยังใช้เมื่อ$HISTCONTROLมีignorespaceเป็นวิธีที่จะบอกbashไม่ให้บันทึกบรรทัดคำสั่งในประวัติ

หากคุณต้องการคุณลักษณะทั้งสอง indenpendantly $histcharsคุณจะต้องเลือกตัวละครอื่นเป็นตัวละครที่ คุณต้องการสิ่งที่ไม่ส่งผลกระทบต่อวิธีการตีความคำสั่งของคุณ ตัวเลือกไม่กี่:

  • using backslash ( \): ใช้\echo fooงานได้ แต่มีผลข้างเคียงของการปิดใช้งานนามแฝงหรือคำหลัก
  • แท็บแทรกในตำแหน่งแรกที่คุณต้องกดCtrl+VTabแม้ว่า
  • ถ้าคุณไม่ทราบพิมพ์สองปุ่มคุณสามารถเลือกตัวอักษรใด ๆ ที่ปกติจะไม่ปรากฏในตำแหน่งแรก ( %, @, ?เลือกของคุณเอง) และทำให้นามแฝงว่างสำหรับมัน

    histchars='!^%'
    alias %=
    

    จากนั้นป้อนอักขระช่องว่างและคำสั่งของคุณ:

    bash-4.3$ % echo !!
    !!
    

(คุณจะไม่สามารถบันทึกคำสั่งที่ปิดใช้งานการแทนที่ประวัติได้นอกจากนี้โปรดทราบว่าอักขระตัวที่ 3 ที่เป็นค่าเริ่มต้น$histcharsคือ#เพื่อไม่ให้มีการขยายประวัติในความคิดเห็นหากคุณเปลี่ยนและคุณป้อนความคิดเห็นที่ คุณควรตระหนักถึงความจริงที่ว่า! ลำดับอาจขยายได้)


2

โซลูชันที่นำเสนอไม่ทำงานเช่นตัวอย่างต่อไปนี้:

$ bash -c "echo 'hello World!'"
-bash: !'": event not found
$

ในกรณีนี้ปังสามารถพิมพ์โดยใช้รหัส ASCII ฐานแปด:

$ bash -c "echo -e 'hello World\0041'"
hello World!
$

1
ในคำสั่งแรกของคุณ!อยู่ระหว่างเครื่องหมายคำพูดคู่ซึ่งเป็นคำตอบอื่น ๆ ระบุว่ามันยังคงมีความหมายการขยายประวัติ คุณสามารถใช้ หรือbash -c 'echo '\''hello World!'\' bash -c "echo 'hello World"\!"'"
Gilles

หากไม่มีพารามิเตอร์ -i สภาพแวดล้อมอาจเปลี่ยนแปลง (เช่น ~ / .profile ไม่ทำงาน) อย่างไรก็ตามการทำ -i หมายถึงเอาต์พุตใด ๆ จาก. profile ของคุณจะถูกดักจับในเอาต์พุตของคำสั่งที่คุณต้องการรัน
เบรนต์

-1

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

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

4
ไม่นั่นเป็นเพียงการ!ติดตามโดย"ที่ไม่พิเศษอีกต่อไป echo "foo!"ก็โอเคecho "foo!bar"ไม่ได้
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.