為什麼單位分隔符號 (ASCII 31) 在終端輸出中不可見?

為什麼單位分隔符號 (ASCII 31) 在終端輸出中不可見?

單位分隔符 ASCII 字元(ASCII 31,八進位 37)在 Vim 中可見為^_.但是,如果我將相同的文件列印到終端,則該字元是不可見的。這會導致一行上的字段黏在一起:

# 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

但這是比較麻煩的。為什麼單位分隔符號在 Bash shell 中列印到 stdout 時沒有可見的表示形式?我甚至無法正確複製和貼上 shell 輸出;單位分隔符號在此過程中遺失。

答案1

單位分隔符 ( US) 字符,也稱為IS1,屬於cntrl字符類,並且是不是print字元類別中。它是一個控製字符,用於將文字組織成群組,對於旨在利用該資訊的程序。一般來說,不可列印的字元在不同的程式或環境中可能會有不同的解釋和呈現。

您看到它在 Vim 中表示的原因^_是因為 Vim 是一個互動式編輯器。只要將正確的二進位字元寫入磁碟,它就可以隨意呈現不可列印的字元。

您無法在 shell 中獲得相同的行為,因為 Unix shell 程式是為了操作純文字並將純文字相互傳遞而編寫的。當您cat建立文件時,寫入終端的文字必須是文件中實際的內容。

這樣就將其留給終端設備來解釋該字元。事實證明,一些終端模擬器使US角色與其他角色不同。在gnome-terminal(或任何vte基於 的終端)中,字元將呈現為包含十六進位代碼的方塊001F。在xtermor中rxvt,該字元確實是不可見的。

答案2

單位分隔符號的 ASCII 範圍為控製字元,因此沒有(或通常不應該)有視覺表示。

Vim 和其他一些編輯器會顯示它們,以便您可以編輯它們。正如您所注意到的,cat -v它也顯示出來。手冊頁顯示,這-v是 的縮寫形式--show-nonprinting,這會導致它用可列印表示替換非列印字符,這不是文件的原始內容,因此如果輸出實際上是另一個程序,可能會導致麻煩。

您看到的表示形式已經暗示它是一個控製字元:前面帶有 a 的字元^Ctrl+ 字元的常見表示法,它是在終端機中產生該字元的組合鍵。例如,Ctrl+可以讓你在 vim 中輸入單位分隔符號。_但另一個編輯器或某些 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 相容 shell)取代對應的控製字元。看維基百科的控製字元別名列表使用“插入符號”。如果您不喜歡這種語法,您可能更喜歡使用八進位$'\037'或十六進位$'\x1f'表示法。

相關內容