ฉันจะตรวจสอบตัวอักษรคำต่อคำของสตริงคำสั่ง bash ได้อย่างไร


15

ฉันมีพฤติกรรมที่แปลกประหลาดนี้เมื่อเช้านี้ในสถานีทุบตี:

user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
bash: [: missing «]»
user@home:/home/user$ [ -f /etc/openvpn/client.conf ] && echo true
true
  • คำสั่งแรกคือ วาง จากสคริปต์ที่แก้ไขด้วย gedit
  • ประการที่สองคือ พิมพ์โดยตรง ในอาคารผู้โดยสาร

หลังจากขุดไปแล้วฉันก็พบว่า การลบอักขระที่ 30 (ช่องว่างระหว่าง client.conf และ "]") และแทนที่ด้วยช่องว่างทำให้คำสั่งทำงานอีกครั้ง

สมมติฐานของฉันถูกต้อง: อักขระว่างที่ไม่รู้จักเลื่อนลงในคำสั่ง แต่คำถามคือ:

  1. ฉันจะเปิดเผยตัวละครเหล่านั้นใน terminal ได้อย่างไร และที่สำคัญกว่า:
  2. ฉันจะป้องกันไม่ให้สิ่งนี้เกิดขึ้นอีกได้อย่างไร

BTW ฉันใช้ Ubuntu 18.04 / ภาษาฝรั่งเศสสคริปต์ที่ฉันวางคำสั่งนั้นอยู่ในไดรฟ์ USB และอาจถูกแก้ไขบน Windows ด้วย


ขอบคุณสำหรับคำตอบที่ดี ตัวละครที่ไม่ดีคือ c2 a0 อักขระ UTF-8 แบบไม่ทำลาย คำถาม วิธีการลบตัวอักษร 'M-BM-' แบบพิเศษด้วย sed มีข้อเท็จจริงที่น่าสนใจเกี่ยวกับตัวละครนั้น

สิ่งที่แปลกคือสคริปต์นี้ปราศจากตัวละคร ดังนั้นฉันไม่รู้ว่ามันมาจากไหน


3
ใช้เครื่องมือแก้ไขที่เน้นอักขระดังกล่าว การเน้นไวยากรณ์ช่วยได้มากเช่นกัน อย่าวางโดยตรงจากเว็บไปยังเทอร์มินัลเสมอผ่านตัวแก้ไขดังกล่าว
choroba

2
Yo อาจต้องการค้นหาคำสั่ง problem ในรายการประวัติของคุณจากนั้นไพพ์เอาต์พุตผ่านโปรแกรมการแสดงผลฐานสิบหก เพื่อที่คุณจะได้ไม่ต้องเดินผ่านรายการที่มีความยาวไม่ว่าจะเป็นการรันคำสั่งเพื่อวางไว้ที่ด้านล่างของรายการประวัติ history 2|xxd (เพราะว่า history คำสั่งตัวเองมักจะเป็นคนสุดท้ายในรายการ) หรือพิมพ์ history|grep "CommandWithProblem"|xxd. คุณสามารถใช้โปรแกรมแสดงผล hex อื่น ๆ แทน xxdแต่ค่าเริ่มต้นนี้เป็นรูปแบบที่ฉันชอบ
AFH

@Gabriel Glenn โปรดทำเครื่องหมายที่ดีที่สุด / เป็นประโยชน์มากที่สุด / ตอบอะไรก็ได้เป็น " ได้รับการยอมรับ "ใช้เครื่องหมายขีด - แทนที่จะแสดงความคิดเห็นในแต่ละข้อที่ช่วย ข้อมูล
Attie

1
@Attie ใช่ฉันมักจะรอ 24 ชั่วโมงก่อนที่จะยอมรับคำตอบที่ดีที่สุดตามที่แนะนำใน meta.stackexchange.com/questions/5234/...
Gabriel Glenn

1
ส่วนตัวฉันจะใช้ set -x. นี่จะแสดงคำสั่ง & amp; มันเป็นอย่างไร มันไม่จำเป็นต้องพูดว่า "ตัวละครที่ไม่ดีที่นี่" แต่มันจะแสดงให้คุณเห็นว่าการทุบตีไม่ได้แยกตัวละครนั้น
Patrick

คำตอบ:


11

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

$ hexdump -Cv <<"EOF"
> [ -f /etc/openvpn/client.conf ] && echo true
> EOF
00000000  5b 20 2d 66 20 2f 65 74  63 2f 6f 70 65 6e 76 70  |[ -f /etc/openvp|
00000010  6e 2f 63 6c 69 65 6e 74  2e 63 6f 6e 66 20 5d 20  |n/client.conf ] |
00000020  26 26 20 65 63 68 6f 20  74 72 75 65 0a           |&& echo true.|
0000002d

คุณสามารถดูที่นี่ว่า space, close-square-brace, space ถูกต้อง - 0x20, 0x5D, 0x20.

ค่าเหล่านี้คือรหัส ASCII ที่แสดงใน เลขฐานสิบหก . ค่าใด ๆ ที่อยู่นอกช่วง 0x20 - 0x7E ไม่ใช่ " ตัวอักษรที่พิมพ์ได้ " เท่าที่เกี่ยวข้องกับ ASCII และส่วนใหญ่จะเล่นได้ไม่ดีกับอินเตอร์เฟสบรรทัดคำสั่ง

บันทึก: ฉันคัดลอกแรกของคุณ " แตก "บรรทัดสำหรับใช้ใน hexdump ตัวอย่างด้านบนดังนั้นมีบางอย่างเข้ามาแทนที่ ไม่ใช้ ASCII พื้นที่ ด้วยช่องว่าง ASCII ระหว่างแหล่งต้นฉบับและคำถามที่แสดง


ในการทำซ้ำสิ่งนี้ทำตามขั้นตอนต่อไปนี้:

  1. ชนิด hexdump -Cv <<"EOF" และกด เข้าสู่
  2. วางข้อความที่คุณต้องการใช้
  3. ชนิด EOF ในบรรทัดของตัวเองและกด เข้าสู่

เทอร์มินัลและอินเตอร์เฟสบรรทัดคำสั่งไม่สามารถจัดการอักขระพิเศษได้อย่างที่คุณค้นพบ หากคุณไม่ระมัดระวังในการจัดรูปแบบเอกสารคุณจะประสบปัญหากับ Microsoft Word (และอื่น ๆ ) โดยใช้ " คำพูดสมาร์ท ", em-dashes, รายการดำเนินต่อไป ...

จุดแตกต่าง: (ด้านบนคือ " คำพูดสมาร์ท "ด้านล่างคือ" คำพูดตรง ")

example of smart quotes vs straight quotes

$ hexdump -Cv <<"EOF"
> “quoted string”
> EOF
00000000  e2 80 9c 71 75 6f 74 65  64 20 73 74 72 69 6e 67  |...quoted string|
00000010  e2 80 9d 0a                                       |....|
00000014

ที่นี่คำพูดที่เปิดอยู่ไม่ใช่คำพูดแบบ ASCII ธรรมดา ( " ) แต่เป็น Unicode / UTF-8 ซีรีย์ - 0xE2, 0x80, 0x9C, หรือ U+201C - ซึ่งเทอร์มินัลจะไม่จัดการตามที่คุณคาดหวัง

คำแนะนำของกีวี่ cat -A ก็ทำหน้าที่:

$ cat -A <<"EOF"
> “quoted string”
> EOF
M-bM-^@M-^\quoted stringM-bM-^@M-^]$

บันทึก: เมื่อใช้ echo "..." | hdคุณมีโอกาสที่จะทุบตีแทนส่วนของสตริงที่คุณพยายามตรวจ นี่เป็นเรื่องที่น่ากังวลเป็นพิเศษเมื่อพยายามตรวจสอบองค์ประกอบของสคริปต์

ตัวอย่างเช่นลอง:

$ echo "${USER}"
attie

$ echo "`whoami`"
attie

$ echo "$(whoami)"
attie

$ cat <<EOF
> ${USER}
> EOF
attie

วิธีการเหล่านี้จะแทนที่ส่วนประกอบด้วยข้อความที่เกี่ยวข้อง เพื่อหลีกเลี่ยงปัญหานี้ให้ใช้วิธีการใดวิธีการหนึ่งต่อไปนี้ หมายเหตุการใช้คำพูดเดียว ( ' ) และ a " อ้าง heredoc " ( "EOF" )

$ echo '${USER}'
${USER}

$ echo '`whoami`'
`whoami`

$ echo '$(whoami)'
$(whoami)

$ cat <<"EOF"
> ${USER}
> EOF
${USER}

วิธีนี้ใช้ได้ผล: echo "[ -f /etc/openvpn.ovpn ]" | hd ผลตอบแทน [...] c2 a0 [...]. เราสามารถเห็น c2 a0 อักขระ UT-8 พื้นที่ไม่ทำลาย
Gabriel Glenn

18

คุณสามารถใช้ cat กับ -A ตัวเลือก: จากคู่มือ:

   -A, --show-all
          equivalent to -vET
   -E, --show-ends
          display $ at end of each line
   -T, --show-tabs
          display TAB characters as ^I
   -v, --show-nonprinting
          use ^ and M- notation, except for LFD and TAB

ดังนั้น cat -A yourscrip.sh จะแสดงให้คุณเห็นตัวละครที่มองไม่เห็นและแปลก


7
วิธีนี้ใช้ได้ผล: echo "[ -f /etc/openvpn.ovpn ]" | cat -A ผลตอบแทน [ -f /etc/openvpn/client.ovpnM-BM- ]$. เราสามารถเห็น M-BM- อักขระ UT-8 พื้นที่ไม่ทำลาย
Gabriel Glenn

@GabrielGlenn ดีใจที่นี่ช่วยคุณได้
Kiwy

9

echo "<your command>" | hd ควรทำงาน. ค้นหา backspace (0x08) หรือตัวอักษรที่มีรหัส & gt; = 80 echo "<your command>" | wc -b และตรวจสอบว่าการนับตรงกับสิ่งที่คุณเห็นก็เป็นความคิดที่ดี

การคัดลอกเนื้อหาจากไฟล์ที่สร้างด้วยอะไรก็ตามที่มี "Office" ในชื่อนั้นเป็นสิ่งที่อันตรายเพราะซอฟต์แวร์ดังกล่าวมักจะมีเสรีภาพในการแทนที่ตัวอักษร: ในฝรั่งเศสให้มองหาเครื่องหมายคำพูดคู่ เทียบเท่าเปิด / ปิด สิ่งที่ยากที่สุดที่ฉันเคยพบคือพื้นที่ว่างแบบไม่ทำลายความกว้าง 0 ท่ามกลางชื่อไฟล์ (เซิร์ฟเวอร์หยุดทำงาน 3 วัน ... )


2
มันเป็นมูลค่าการกล่าวขวัญ hd สั้นสำหรับ hexdump ซึ่งยังกล่าวถึงในคำตอบของ Attie
Mikael Kjær

@ MikaelKjær - บน Ubuntu hd เทียบเท่ากับ hexdump -C.
AFH

1
@ xenoid: ฉันบอกว่า 'แก้ไขบน Windows' ไม่ได้แก้ไขด้วย Office Writer เราไม่ได้บ้าเลย ถ้ามันถูกแก้ไขมันเป็นด้วย Notepad ++
Gabriel Glenn

1
วิธีนี้ใช้ได้ผล: echo "[ -f /etc/openvpn.ovpn ]" | hd ผลตอบแทน [...] c2 a0 [...]. เราสามารถเห็น c2 a0 อักขระ UT-8 พื้นที่ไม่ทำลาย
Gabriel Glenn

2

Bash และเชลล์อื่น ๆ เช่น zsh สามารถเปิดบรรทัดคำสั่งปัจจุบันในโปรแกรมแก้ไขได้ ทางลัดเริ่มต้นสำหรับทุบตีคือ C-x C-e ( Ctrl X Ctrl E ) และจะเปิดขึ้นในครั้งแรกที่มี $VISUAL, $EDITOR และ emacs ในทางปฏิบัติสิ่งนี้มีค่าสำหรับการดีบักและแก้ไขคำสั่งที่ซับซ้อน ขึ้นอยู่กับว่าคุณมองอย่างไร zsh นั้นเป็นมิตรมากกว่าทุบตีที่นี่: เมื่อตัวแก้ไขออก bash จะรันคำสั่งทันทีในขณะที่ zsh รอให้คุณกด เข้าสู่ (ให้โอกาสคุณมากขึ้นในการแก้ไขคำสั่ง)

หลังจากเปิดคำสั่งในโปรแกรมแก้ไขคุณสามารถกำหนดค่าโปรแกรมแก้ไขของคุณให้แสดงอักขระที่ไม่ใช่ ASCII ได้

ตัวอย่างเช่น, กับกลุ่ม โดยใช้การตั้งค่าเหล่านี้:

set encoding=latin1
set isprint=
set display+=uhex

enter image description here

หรือปรับวิธีการของคำตอบอื่น ๆ :

bash-4.4$ f() { cat -A "$@"; false; }   # exit false to prevent bash from running the command
bash-4.4$ VISUAL=f
bash-4.4$ [ -f /etc/openvpn/client.conf ] && echo true  # C-x C-e here
[ -f /etc/openvpn/client.confM-BM- ] && echo true$
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.