ทำไมตัวคั่นหน่วย (ASCII 31) มองไม่เห็นในเทอร์มินอลเอาท์พุท


17

ตัวละครหน่วยคั่น ASCII (ASCII 31 ฐานแปด 37) ^_ปรากฏอยู่ในกลุ่มเป็น แต่ถ้าฉันพิมพ์ไฟล์เดียวกันไปที่เทอร์มินัลตัวละครจะมองไม่เห็น สิ่งนี้ทำให้ฟิลด์บนบรรทัดติดกัน:

# In Vim and less:

first field^_second field^_last field

# cat the same file to terminal:
cat delim.txt
first fieldsecond fieldlast field

# print 2nd field with awk 
cat delim.txt | awk 'BEGIN {FS = "\037"} {print $2}'
second field

ฉันคิดว่าฉันสามารถทำให้ตัวคั่นหน่วยมองเห็นได้ด้วย cat -v:

cat -v delim.txt
first field^_second field^_last field

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


อักขระบางตัวไม่สามารถพิมพ์ได้ตัวแยกหน่วยเป็นหนึ่งในอักขระเหล่านี้ ผู้แก้ไขบางคนจะแสดงผลในทางที่จะทำให้การแก้ไขเป็นไปได้ คุณต้องแปลมันเป็นลำดับตัวอักษรที่พิมพ์ได้และอาจเป็นแบบอักษร / สีที่แตกต่างกันเพื่อลดความคลุมเครือ
ctrl-alt-delor

3
รหัส ASCII ที่อายุต่ำกว่า 31 และ 127 มีจุดประสงค์เพื่อทำให้เทอร์มินัลหรืออุปกรณ์ทำอะไรบางอย่าง (เพราะเหตุใดพวกเขาจึงถูกเรียกว่ารหัสควบคุม) หรือสนับสนุนบางสิ่งในโปรโตคอล (เช่น EOT หรือ SOH) ซึ่งตรงกันข้ามกับการแสดงอะไรบางอย่าง มันกลับมาอีกครั้งเมื่อเทอร์มินัลเป็นอุปกรณ์ที่เหมือนเครื่องพิมพ์ดีดและสิ่งต่าง ๆ เช่นการบอกโทรพิมพ์เพื่อรับคืนรถนั้นเป็นสิ่งจำเป็นทางร่างกาย ผู้แก้ไขอาจเลือกให้แสดงโดยใช้เครื่องหมาย "^" เนื่องจากคุณกำลังแก้ไขบางอย่างและไม่ต้องการให้เทอร์มินัลทำสิ่งที่รหัสควบคุมถาม
LawrenceC

1
@LawrenceC: รหัส 127 ตั้งใจที่จะทำให้เครื่องไม่ทำอะไรเลยหากมีการต่อยเทปและทำผิดพลาดก็จะกดปุ่มเพื่อสำรองเทปด้วยช่องว่างหนึ่งช่องแล้วกด "rub-out" เพื่อต่อยทั้งหมด แปดหลุม เมื่อผู้อ่านพบตัวละครที่เจาะทุกรูมันจะส่งผ่านสาย แต่ผู้รับก็ไม่สนใจ
supercat

คำตอบ:


19

USอักขระตัวคั่นหน่วย ( ) ที่รู้จักในชื่อIS1อยู่ในcntrlคลาสอักขระและไม่ได้อยู่ในprintคลาสอักขระ มันเป็นตัวควบคุมที่มีไว้สำหรับการจัดระเบียบข้อความเป็นกลุ่มสำหรับโปรแกรมที่ถูกออกแบบมาเพื่อทำให้การใช้งานของข้อมูลที่ โดยทั่วไปแล้วอักขระที่ไม่สามารถพิมพ์ได้อาจถูกตีความและแสดงผลแตกต่างกันในโปรแกรมหรือสภาพแวดล้อมที่แตกต่างกัน

เหตุผลที่คุณเห็นมันเป็นตัวแทน^_ใน Vim เป็นเพราะ Vim เป็นตัวแก้ไขเชิงโต้ตอบ สามารถแสดงอักขระที่ไม่สามารถพิมพ์ได้อย่างอิสระอย่างไรก็ตามมันต้องการตราบใดที่อักขระไบนารี่ที่ถูกต้องเขียนลงดิสก์

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

เพื่อให้มันไปยังอุปกรณ์ปลายทางเพื่อตีความตัวละคร และปรากฎว่าบางเลียนแบบขั้วทำทำให้USตัวละครที่แตกต่างจากคนอื่น ๆ ในgnome-terminal(หรือvteขั้วชั่น) 001Fตัวละครจะไม่สามารถแสดงผลเป็นกล่องที่มีรหัสฐานสิบหก ในxtermหรือrxvtตัวละครที่มองไม่เห็นแน่นอน


ดีฉันจะไม่พูดUSคือทั้งหมดที่มองไม่เห็น เมื่อฉันแทรกตัวละครนั้นลงในเทอร์มินัลด้วยCtrl+/(ยืนยันผ่าน<C-v><C-/> ) มันจะลบข้อความจำนวนที่คาดเดาไม่ได้ในบรรทัด ฉันไม่เข้าใจพฤติกรรมของมันอย่างสมบูรณ์ แต่ดูเหมือนว่าส่วนใหญ่จะมีผลกระทบ "แท็บย้อนกลับ" บางส่วนซึ่งแทนที่จะแทรกช่องว่างจำนวนหนึ่งมันจะลบอักขระจำนวนหนึ่ง แต่บางครั้งก็สุ่มแทรกข้อความดังนั้นจึงทำให้เกิดความสับสน .
Braden ที่ดีที่สุด

10

ตัวคั่นหน่วยอยู่ในช่วง ASCII ของอักขระควบคุมและดังนั้นจึงไม่มี (หรือไม่ควรเป็นปกติ) มีการแสดงภาพ

เสียงเรียกเข้าและเครื่องมือแก้ไขอื่น ๆ แสดงขึ้นมาดังนั้นคุณจึงสามารถแก้ไขได้ ตามที่คุณสังเกตเห็นcat -vมันแสดงเช่นกัน man page แสดง, นั่น-vเป็นรูปแบบสั้น ๆ--show-nonprinting, ซึ่งทำให้มันแทนที่ตัวอักษรที่ไม่ได้พิมพ์ด้วยการเป็นตัวแทนที่พิมพ์ได้, ซึ่งไม่ใช่เนื้อหาต้นฉบับของไฟล์และอาจทำให้เกิดปัญหา, ถ้าผลลัพธ์เป็นโปรแกรมอื่นจริง ๆ .

การเป็นตัวแทนที่คุณเห็นอยู่นั้นบ่งบอกว่ามันเป็นตัวควบคุม: ตัวละครที่เติมด้วย a ^เป็นสัญกรณ์ทั่วไปสำหรับCtrl+ ตัวละครซึ่งเป็นชุดคีย์ที่สร้างอักขระนี้ในเทอร์มินัล Ctrl+ _จะให้คุณป้อนตัวคั่นหน่วยเป็นกลุ่ม, เช่น. แต่เครื่องมือแก้ไขอื่นหรือโปรแกรมดู GUI บางตัวอาจแสดงรหัสฐานสิบหกตัวยึดตำแหน่งหรือสิ่งที่แตกต่างอย่างสิ้นเชิง

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

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


3

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

# Replace the control character US (^_) by *one* other character
$ cat my.file | tr $'\c_' ':'

หากคุณต้องการแทนที่อักขระควบคุมนั้นด้วยฟอร์ม "ขยาย" คุณจะต้องsedแทน:

# Replace the control character US (^_) by any string
cat /tmp/f | sed s/$'\c_'/^_/g

โปรดทราบไวยากรณ์$'\cX': ไวยากรณ์นี้แจ้งให้คุณทราบ (bash-compatible shell) เพื่อแทนที่อักขระควบคุมที่เกี่ยวข้อง ดูวิกิพีเดียสำหรับรายการของนามแฝงอักขระควบคุมโดยใช้ "เครื่องหมายรูปสัณฐานวิทยา" หากคุณไม่ชอบไวยากรณ์นั้นคุณอาจต้องการใช้สัญกรณ์ฐานแปด$'\037'หรือฐานสิบหก$'\x1f'แทน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.