端末出力で単位区切り文字 (ASCII 31) が表示されないのはなぜですか?

端末出力で単位区切り文字 (ASCII 31) が表示されないのはなぜですか?

単位区切りの ASCII 文字 (ASCII 31、8 進数 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 シェルで標準出力に出力されたときに、単位区切りが目に見える形で表示されないのはなぜでしょうか。シェルの出力を正しくコピーして貼り付けることすらできず、その過程で単位区切りが失われてしまいます。

答え1

単位区切りUS文字( )は、 とも呼ばれIS1、文字クラスに属しcntrlない文字クラスでprint。これはテキストをグループにまとめるための制御文字です。その情報を利用するように設計されたプログラムの場合一般に、印刷できない文字は、プログラムや環境によって解釈やレンダリングの仕方が異なります。

Vim でこのように表現されるのは、^_Vim が対話型エディタだからです。正しいバイナリ文字がディスクに書き込まれている限り、印刷できない文字を自由にレンダリングできます。

Unix シェル プログラムはプレーン テキストを操作して相互に渡すように記述されているため、シェルでは同じ動作を実現できませんcat。ファイルを使用する場合、端末に書き込まれるテキストは、実際にファイル内にあるテキストである必要があります。

つまり、文字を解釈するのは端末デバイスに任されることになります。そして、一部の端末エミュレーターではするは、文字を他の文字とは異なる方法でレンダリングしますUSgnome-terminal(またはvte任意の ベースの端末) では、文字は 16 進コード を含むボックスとしてレンダリングされます001Fxtermまたはではrxvt、文字は実際には表示されません。

答え2

単位区切り文字はASCIIの範囲です。制御文字したがって、視覚的な表現はありません (通常は視覚的な表現がないはずです)。

Vim や他のエディタではこれらが表示されるので、編集できます。お気づきのとおり、cat -vにも表示されます。man ページには、-vの短縮形が示されています--show-nonprinting。これにより、印刷されない文字が印刷可能な表現に置き換えられますが、これはファイルの元のコンテンツではないため、実際に別のプログラムに出力される場合は問題が発生する可能性があります。

表示されている表現から、それが制御文字であることがすでにわかります。先頭に a が付いた文字は、 + 文字^の一般的な表記法でありCtrl、これは端末でこの文字を生成するキーの組み合わせです。たとえば、vim ではCtrl+_で単位区切りを入力できます。ただし、別のエディターや GUI ビューアーでは、16 進コード、プレースホルダー、またはまったく異なるものが表示される場合があります。

端末は制御文字を印刷しないので、テキストを選択しても制御文字はコピーされません (改行やタブなどの空白文字は例外で、これらも制御文字です)。端末でコピー時に通常無視される制御文字のもう 1 つの例は、カラー コードです。カラー コードとは、文字の後にテキストの色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互換シェル)に通知します。制御文字エイリアスのリストについてはWikipediaを参照「キャレット表記」を使用します。この構文が気に入らない場合は、代わりに 8 進数$'\037'または 16 進数$'\x1f'表記を使用することをお勧めします。

関連情報