Mengapa pemisah unit (ASCII 31) tidak terlihat dalam output terminal?

17

Pemisah unit karakter ASCII (ASCII 31, oktal 37), terlihat dalam Vim sebagai a ^_. Tetapi jika saya mencetak file yang sama ke terminal, karakternya tidak terlihat. Hal ini menyebabkan bidang pada garis saling menempel:

# 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

Saya kira saya dapat membuat pemisah unit terlihat dengan cat -v:

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

Tapi ini agak rumit. Mengapa pemisah unit tidak memiliki representasi yang terlihat saat dicetak ke stdout di shell Bash? Saya bahkan tidak bisa menyalin dan menempelkan output shell dengan benar; pemisah unit tersesat dalam proses.

dan
sumber
Tidak semua karakter dapat dicetak, pemisah unit adalah salah satunya. Beberapa editor akan menampilkannya dalam beberapa cara untuk memungkinkan pengeditan. Anda perlu menerjemahkannya ke dalam urutan karakter yang dapat dicetak, dan mungkin font / warna yang berbeda, untuk mengurangi ambiguitas.
ctrl-alt-delor
3
Kode ASCII di bawah 31, dan 127, dimaksudkan untuk menyebabkan terminal atau perangkat melakukan sesuatu (karenanya mengapa mereka disebut kode kontrol), atau berdiri untuk sesuatu dalam protokol (seperti EOT atau SOH), sebagai lawan menampilkan sesuatu. Ia mendengar kembali ketika terminal adalah perangkat seperti mesin tik dan hal-hal seperti mengatakan teletype untuk carriage-return secara fisik diperlukan. Editor dapat memilih untuk merendernya menggunakan notasi "^" karena Anda mengedit sesuatu dan tidak ingin terminal benar-benar melakukan apa yang diminta kode kontrol.
LawrenceC
1
@LawrenceC: Kode 127 sebenarnya dimaksudkan untuk menyebabkan terminal tidak melakukan apa - apa , Jika seseorang meninju kaset dan membuat kesalahan, orang akan menekan tombol untuk membuat cadangan rekaman dengan satu spasi dan tekan "rub-out", untuk meninju semua delapan lubang. Ketika pembaca menemukan karakter berlubang-lubang, itu akan mengirimkannya ke atas kawat tetapi penerima bisa mengabaikannya.
supercat

Jawaban:

19

Karakter pemisah unit ( US), juga dikenal sebagai IS1, ada di cntrlkelas karakter dan tidak di printkelas karakter. Ini adalah karakter kontrol yang dimaksudkan untuk mengatur teks ke dalam grup, untuk program yang dirancang untuk memanfaatkan informasi itu . Secara umum, karakter yang tidak dapat dicetak mungkin akan ditafsirkan dan diterjemahkan secara berbeda dalam program atau lingkungan yang berbeda.

Alasan Anda melihatnya diwakili ^_dalam Vim adalah karena Vim adalah editor interaktif. Ia dapat dengan bebas membuat karakter yang tidak dapat dicetak sesuai keinginannya, selama karakter biner yang benar ditulis ke disk.

Anda tidak bisa mendapatkan perilaku yang sama di shell karena program shell Unix ditulis untuk beroperasi dan saling menyampaikan teks biasa. Saat Anda catfile, teks yang ditulis ke terminal harus apa yang sebenarnya ada dalam file.

Sehingga meninggalkannya ke perangkat terminal untuk menafsirkan karakter. Dan ternyata bahwa beberapa emulator terminal melakukan render USkarakter berbeda dari orang lain. Dalam gnome-terminal(atau vteterminal berbasis apa pun ), karakter akan diberikan sebagai kotak yang berisi kode hex 001F. Dalam xtermatau rxvt, karakternya memang tidak terlihat.

Mike Miller
sumber
Yah saya tidak akan mengatakan USitu sama sekali tidak terlihat. Ketika saya menyisipkan karakter itu ke terminal dengan Ctrl+/(dikonfirmasi melalui <C-v><C-/>), itu menghapus jumlah teks yang tidak dapat diprediksi pada baris. Saya tidak sepenuhnya memahami perilakunya, tetapi tampaknya terutama memiliki semacam efek "tab terbalik" di mana alih-alih menyisipkan sejumlah spasi, ia menghapus sejumlah karakter, tetapi kemudian terkadang secara acak memasukkan teks, sehingga membingungkan .
Braden Best
10

Pemisah unit berada dalam kisaran ASCII Karakter Kontrol , dan oleh karena itu tidak (atau seharusnya tidak biasanya) memiliki representasi visual.

Vim dan beberapa editor lain menampilkannya, sehingga Anda dapat mengeditnya. Seperti yang Anda perhatikan, cat -vtampilkan juga. Halaman manual menunjukkan, itu -vadalah bentuk singkat dari --show-nonprinting, yang menyebabkannya untuk mengganti karakter yang tidak dicetak dengan representasi yang dapat dicetak, yang bukan konten asli dari file dan karena itu dapat menyebabkan masalah, jika output sebenarnya ke program lain .

Representasi yang Anda lihat sudah mengisyaratkan itu adalah karakter kontrol: karakter yang diawali dengan a ^adalah notasi umum untuk Ctrl+ karakter, yang merupakan kombinasi kunci yang menghasilkan karakter ini di terminal. Ctrl+ _akan membiarkan Anda memasukkan pemisah unit dalam vim, misalnya. Tetapi editor lain atau beberapa penampil GUI mungkin menampilkan kode hex, pengganti atau sesuatu yang sama sekali berbeda.

Karena terminal Anda tidak mencetak karakter kontrol, itu juga tidak disalin ketika memilih teks (karakter spasi seperti baris dan tab baru adalah pengecualian di sini, yang juga karakter kontrol). Contoh lain dari karakter kontrol di terminal yang biasanya diabaikan ketika menyalin adalah kode warna, yang merupakan ESCkarakter yang diikuti oleh kode untuk mewarnai teks.

Jadi untuk menunjukkan karakter pada terminal Anda, tidak ada cara lain selain menggunakan program yang menggantikan pemisah unit dengan beberapa karakter yang dapat dicetak.

crater2150
sumber
3

Sedikit di margin yang lain jawaban (sangat baik), jika Anda ingin mengubah hanya karakter kontrol ^_ketika menampilkan isi file, Anda mungkin ingin transliterasi itu menggunakan trutilitas (dan sedikit sintaks yang kompatibel dengan bash) :

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

Jika Anda perlu mengganti karakter kontrol itu dengan formulir "diperluas", Anda perlu sed:

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

Harap perhatikan sintaks $'\cX': sintaks ini memberi tahu Anda (shell yang kompatibel dengan bash) untuk mengganti karakter kontrol yang sesuai. Lihat wikipedia untuk daftar karakter kontrol alias menggunakan "notasi caret". Jika Anda tidak menyukai sintaks itu, Anda mungkin lebih suka menggunakan notasi oktal $'\037'atau heksadesimal $'\x1f'.

Sylvain Leroux
sumber