Dlaczego separator jednostek (ASCII 31) jest niewidoczny na wyjściu terminala?


17

Znak ASCII separatora jednostek (ASCII 31, ósemka 37) jest widoczny w Vimie jako ^_. Ale jeśli wydrukuję ten sam plik na terminalu, znak będzie niewidoczny. Powoduje to, że pola linii łączą się ze sobą:

# 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

Przypuszczam, że mogę sprawić, by separator jednostek był widoczny za pomocą cat -v:

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

Ale to raczej kłopotliwe. Dlaczego separator jednostek nie ma widocznej reprezentacji po wydrukowaniu na standardowe wyjście w powłoce Bash? Nie mogę nawet poprawnie skopiować i wkleić danych wyjściowych powłoki; separator jednostek gubi się w tym procesie.


Nie wszystkie znaki można drukować, separator jednostek jest jednym z nich. Niektórzy redaktorzy wyświetlają go w jakiś sposób, aby umożliwić edycję. Musisz przełożyć go na ciąg znaków do wydrukowania, a może inną czcionkę / kolor, aby zmniejszyć niejednoznaczność.
ctrl-alt-delor

3
Kody ASCII poniżej 31 i 127 mają na celu spowodowanie, że terminal lub urządzenie coś zrobią (dlatego nazywane są kodami sterującymi), lub będą oznaczały coś w protokole (jak EOT lub SOH), a nie wyświetlają coś. Słucha, kiedy terminale były urządzeniami podobnymi do maszyn do pisania, a fizycznie potrzebne były takie rzeczy, jak przekazanie telegrafu zwrotowi karetki. Redaktorzy mogą wybrać renderowanie ich za pomocą notacji „^”, ponieważ coś edytujesz i nie chcesz, aby terminal faktycznie robił to, o co proszą kody sterujące.
LawrenceC

1
@LawrenceC: Kod 127 faktycznie zamierzał spowodować, że terminal nic nie zrobi. Gdyby ktoś wybił taśmę i popełnił błąd, nacisnąłby przycisk, aby cofnąć taśmę o jedną spację i nacisnąć „wycieranie”, aby wybić wszystko osiem dołków. Gdy czytnik napotkał znak z dziurkami, wyśle ​​go przez drut, ale odbiorca może go po prostu zignorować.
supercat

Odpowiedzi:


19

Znak separatora jednostek ( US), znany również jako IS1, należy do cntrlklasy znaków i nie należy do printklasy znaków. Jest to znak kontrolny, który jest przeznaczony do organizowania tekstu w grupy, w programach zaprojektowanych do korzystania z tych informacji . Zasadniczo znaki niedrukowalne będą prawdopodobnie interpretowane i renderowane inaczej w różnych programach lub środowiskach.

Powodem, dla którego widzisz go reprezentowanego jak ^_w Vimie, jest to, że Vim jest interaktywnym edytorem. Może dowolnie renderować znaki niedrukowalne, o ile chce, pod warunkiem, że na dysk zapisany jest prawidłowy znak binarny.

Nie można uzyskać takiego samego zachowania w powłoce, ponieważ programy powłoki w systemie Unix są napisane, aby działać i przekazywać sobie nawzajem zwykły tekst. Gdy masz catplik, tekst zapisany w terminalu musi być tym, co faktycznie znajduje się w pliku.

Pozostawia to urządzeniu końcowym interpretację znaku. I okazuje się, że niektóre emulatory terminali zrobić renderowania UScharakter odmienny od innych. W gnome-terminal(lub dowolnym vteterminalu bazowym) znak będzie renderowany jako ramka zawierająca kod szesnastkowy 001F. W xtermlub rxvtpostać jest rzeczywiście niewidoczna.


Nie powiedziałbym, że USjest całkowicie niewidoczny. Kiedy wstawię ten znak do terminala za pomocą Ctrl+/(potwierdzonego przez <C-v><C-/>), usuwa nieprzewidywalną ilość tekstu w linii. Nie do końca rozumiem jego zachowanie, ale wydaje się, że ma głównie pewien efekt „odwracania tabulatorów”, w którym zamiast wstawiać spacje, usuwa liczbę znaków, ale czasami czasami losowo wstawia tekst, więc jest to mylące .
Braden Best

10

Separator jednostek należy do zakresu znaków kontrolnych ASCII , a zatem nie ma (lub zwykle nie powinien) przedstawiać wizualnie.

Vim i niektóre inne edytory wyświetlają je, więc możesz je edytować. Jak zauważyłeś, cat -vwyświetla również. Strona -vpodręcznika pokazuje, że jest to krótka forma --show-nonprinting, która powoduje, że zastępuje ona znaki niedrukowalne reprezentacją do wydrukowania, która nie jest oryginalną zawartością pliku i dlatego może powodować problemy, jeśli dane wyjściowe są w rzeczywistości w innym programie .

Reprezentacja, którą już widzisz, wskazuje, że jest to znak kontrolny: znak poprzedzony znakiem a ^jest powszechną notacją Ctrlznaku +, który jest kombinacją klawiszy, która tworzy ten znak w terminalu. Ctrl+ _pozwoli ci na przykład wprowadzić separator jednostek w vimie. Ale inny edytor lub przeglądarka GUI może wyświetlać kod szesnastkowy, symbol zastępczy lub coś zupełnie innego.

Ponieważ twój terminal nie drukuje znaków kontrolnych, nie jest również kopiowany podczas zaznaczania tekstu (znaki białych znaków, takie jak nowa linia i tab, są tutaj wyjątkiem, które również są znakami kontrolnymi). Innym przykładem znaków kontrolnych w terminalu, które są zwykle ignorowane podczas kopiowania, są kody kolorów, które są ESCznakami, po których następuje kod do kolorowania tekstu.

Aby więc wyświetlić znaki na terminalu, nie ma innego sposobu niż użycie programu, który zamienia separator jednostek na znak do wydruku.


3

Trochę na marginesie innych (bardzo dobrych) odpowiedzi, jeśli chcesz zmienić tylko znak kontrolny ^_podczas wyświetlania zawartości pliku, możesz chcieć transliterować go za pomocą trnarzędzia (i trochę składni kompatybilnej z bash) :

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

Jeśli musisz zastąpić ten znak kontrolny jego „rozwiniętą” postacią, musisz sedzamiast tego:

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

Zwróć uwagę na składnię $'\cX': ta składnia informuje twoją (powłokę kompatybilną z bash), aby zastąpić odpowiedni znak kontrolny. Zobacz wikipedię, aby uzyskać listę aliasów znaków kontrolnych używających „notacji karetki”. Jeśli nie podoba ci się ta składnia, możesz zamiast tego użyć notacji ósemkowej $'\037'lub szesnastkowej $'\x1f'.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.