Wykryj, ile Unicode obsługuje mój terminal, nawet na ekranie

10

Oto problem: chcę być w stanie rozpoznać, czy mój terminal jest w stanie przyzwoicie unicode, czy nie, aby użyć niektórych znaków, czy nie, podobnie jak spojrzenia, które czasami używają kolorów, a inne podkreślają.

Motywacja wynika z tego, że na dowolnym terminalu wirtualnym dostaję przyzwoite czcionki, ale rozumiem, że podstawowa konsola Linux ma zestaw znaków 256 lub 512 symultanicznych symboli, więc nie można oczekiwać pełnej obsługi czcionek.

Na początku myślałem, że mogę użyć $TERMlub tty, ale oto haczyk: ja też używam byobu, więc $TERMzawsze jest to „screen.linux”. Wyniki tty również nie są zbyt wymowne: /dev/pts/<some number>zarówno w kategoriach „rzeczywistych”, jak i wirtualnych.

$BYOBU_TTYteż nie jest pomocne, ponieważ np. może być /dev/tty1i kiedy sesja jest otwarta w Ctrl+ Alt+, F1znaki nie pokazują się, ale podczas dołączania do tej samej sesji z jakiegoś X terminu, pokazują się poprawnie i nadal $BYOBU_TTYsię nie zmieniają. Poza tym chciałbym móc to wykryć bez zakładania, że ​​byobu jest, czy nie.

Ponadto ustawienia regionalne pokazują się we wszystkich przypadkach en_US.UTF-8

Jednak w jakiś sposób spogląda (aby wymienić konkretne narzędzie, które to wykrywam), nawet wewnątrz byobu, używa różnych danych wyjściowych w zależności od terminala, który podłączam do sesji byobu.

Mam problem z Google, ponieważ terminale i tty wydają się zbyt częstymi wyszukiwanymi hasłami. Co najwyżej docieram do rozwiązań polecających $TERMlub tty.

Álex
źródło

Odpowiedzi:

6

Cóż, najpierw myślę, że zwróciłbym uwagę, że prawie wszystkie terminale w dzisiejszych czasach są „wirtualne” w tym sensie, o którym mówisz ... nawet jeśli terminal znajduje się na drugim końcu portu szeregowego w dobrej wierze. Mam na myśli, że czasy VT-100 , terminali Wyse i innych terminali „fizycznych”, „prawdziwych” już minęły!

Poza tym, powiedzmy, że chcesz wykryć, jaki rodzaj obsługi Unicode ma twój terminal. Możesz to zrobić, pisząc znaki testowe do i sprawdzając, co się stanie. (Możesz wtedy spróbować usunąć znaki testowe po ich napisaniu, ale użytkownik może je jeszcze przez chwilę zobaczyć lub ich usunięcie może nie działać poprawnie).

Chodzi o to, aby poprosić terminal o podanie jego pozycji kursora, wypisać znak testowy, ponownie poprosić terminal o podanie jego pozycji i porównanie dwóch pozycji, aby zobaczyć, jak daleko kursor przesunął się.

Aby zapytać terminal o jego pozycję, zobacz tutaj . Głównie:

echo -e "\033[6n"; read -d R foo; echo -en "\nCurrent position: "; echo $foo | cut -d \[ -f 2

Spróbuj wypisać „é”. Ten znak zajmuje 2 bajty w UTF-8, ale wyświetla się tylko w jednej kolumnie na ekranie. Jeśli wykryjesz, że wyjście „é” powoduje przesunięcie kursora o 2 pozycje, terminal nie ma w ogóle obsługi UTF-8 i prawdopodobnie wyrzucił jakieś śmieci. Jeśli kursor w ogóle się nie poruszył, wówczas terminal jest prawdopodobnie tylko ASCII. Jeśli przesunął się o 1 pozycję, to gratulacje, prawdopodobnie może wyświetlać francuskie słowa.

Spróbuj wypisać „あ”. Ten znak zajmuje 3 bajty w UTF-8, ale wyświetla się tylko w dwóch kolumnach na ekranie. Jeśli kursor przesunie się o 0 lub 3, złe wiadomości, podobnie jak powyżej. Jeśli przesuwa się o 1, wygląda na to, że terminal obsługuje UTF-8, ale nie wie o szerokich znakach (czcionkami o stałej szerokości). Jeśli przesuwa się o 2 kolumny, wszystko jest w porządku.

Jestem pewien, że istnieją inne znaki próbne, które możesz wysłać, które mogłyby prowadzić do użytecznych informacji. Nie znam narzędzia, które robi to automatycznie.

Celada
źródło
1
Dziękuję za sugestię, Celada. Jednak to nie działa: poprawnie widzę zgłoszone zaawansowane pozycje (1 dla é, 2 dla あ). Jedyną różnicą jest to, że w XI widzę prawdziwe postacie, podczas gdy w tty1 widzę diament. Sądzę więc, że terminal naprawdę obsługuje utf-8, ale brakuje znaku w używanej czcionce.
Álex,
Widziałem teraz polecenie showconsolefont. Wydawało się to możliwym rozwiązaniem (z -v zgłasza, że ​​czcionka ma 512 znaków). Niestety działa to tylko wtedy, gdy nie używa się byobu. W tym ostatnim przypadku występuje błąd „Nie można uzyskać deskryptora pliku odnoszącego się do konsoli”. Jeśli jawnie przekażę tty (opcja -C), pojawia się błąd „Nie można otworzyć / dev / pts / 37”
Álex
Przy okazji: skrypt sh, aby określić szerokość terminala w łańcuchu (ale nie o to chodzi w tym pytaniu)
Gilles 'SO - przestań być zły'
3

Rzeczywistym pytaniem OP jest: jakie wartości Unicode obsługuje konsola Linux i czy można je wykryć podczas działania screen. Zasadniczo można to zrobić, pobierając mapę konsoli dla Unicode.

kbdDrzewo źródłowy zawiera getunimap(i jego strona podręcznika). Strona podręcznika to mówi

Program getunimap jest stary i przestarzały. Jest teraz częścią setfont

co nie jest do końca prawdą. setfontma opcję, która robi mniej więcej to samo:

   -ou file                                  
          Save previous Unicode map in file

Różnice:

  • setfontzapisuje do pliku, a getunimapzapisuje na standardowe wyjście
  • getunimap pokazuje znak, który zostałby zmapowany, jako komentarz.

Na przykład:

0x0c4   U+2500  # ─ 
0x0c4   U+2501  # ━ 
0x0b3   U+2502  # │ 
0x0b3   U+2503  # ┃ 
0x0da   U+250c  # ┌ 
0x0da   U+250d  # ┍ 
0x0da   U+250e  # ┎ 
0x0da   U+250f  # ┏ 
0x0bf   U+2510  # ┐ 
0x0bf   U+2511  # ┑ 
0x0bf   U+2512  # ┒ 
0x0bf   U+2513  # ┓ 
0x0c0   U+2514  # └ 
0x0c0   U+2515  # ┕ 
0x0c0   U+2516  # ┖ 
0x0c0   U+2517  # ┗ 

przeciw

0xc4    U+2500
0xc4    U+2501
0xb3    U+2502
0xb3    U+2503
0xda    U+250c
0xda    U+250d
0xda    U+250e
0xda    U+250f
0xbf    U+2510
0xbf    U+2511
0xbf    U+2512
0xbf    U+2513
0xc0    U+2514
0xc0    U+2515
0xc0    U+2516
0xc0    U+2517

Jeśli działasz screen (lub na przykład działasz, xtermale nie na konsoli), pojawi się błąd uprawnień, z którym możesz się obejść sudo.

Jeśli się dowiem, która czcionka została załadowana, mogę to sprawdzić (bez specjalnych uprawnień) za pomocą psfgettable np.

zcat /usr/share/consolefonts/Lat2-Fixed16.psf.gz | psfgettable -

i zobacz dane mapowania, które setfont byłyby użyte do załadowania czcionki (z mapowaniem Unicode):

#
# Character table extracted from font -
#
0x000   U+00a9
0x001   U+00ae
0x002   U+00dd
0x003   U+0104
0x004   U+2666 U+25c8 U+fffd
0x005   U+0105
0x006   U+0111
0x007   U+0150
0x008   U+0151
0x009   U+0162
0x00a   U+0164
0x00b   U+0170
0x00c   U+0171
0x00d   U+021a 
0x00e   U+02dd  
0x00f   U+2014 U+2015
0x010   U+2020
0x011   U+2021
0x012   U+2022 U+25cf
...

Obie getunimap i setfontdają dane nieposortowane, podczas gdy psfgettablewydaje się być posortowane (a także łączą linie dla wartości Unicode, które są mapowane na ten sam glif). Istnieją więc różnice, ale informacje są dostępne.

Dalsza lektura (ilustrująca, dlaczego nie możesz użyć showconsolefont do rozwiązania tego problemu):

Thomas Dickey
źródło
Dzięki, Thomas, za wyjaśnienie mojego pierwotnego pytania i postawienie mnie na właściwej drodze. Spróbuję uzyskać prosty jeden wiersz z twoich informacji i wrócę z wynikami. Korzystanie sudonie stanowi przeszkody dla mojego przypadku użycia.
Álex,
To ciekawe: setfontnic nie wyświetla (nie tworzy podanego pliku ani nie wyświetla błędu) w wirtualnych terminalach, ale działa w rzeczywistych terminalach zgodnie z oczekiwaniami. To jest w Ubuntu 16.04
Álex
2

Natknąłem się na to pytanie, gdy próbowałem osiągnąć to samo, ale nie chciałem pozostawiać niczego na ekranie i ustawić zmienną, więc umieściłem następujące polecenie w skrypcie powłoki, który otrzymuję:

function test_unicode {
  echo -ne "\xe2\x88\xb4\033[6n\033[1K\r"
  read -d R foo
  echo -ne "\033[1K\r"
  echo -e "${foo}" | cut -d \[ -f 2 | cut -d";" -f 2 | (
    read UNICODE
    [ $UNICODE -eq 2 ] && return 0
    [ $UNICODE -ne 2 ] && return 1
  )
}

test_unicode
RC=$?
export UNICODE_SUPPORT=`[ $RC -eq 0 ] && echo "Y" || echo "N"`
unset test_unicode
Jeff
źródło
1
Dziękuję za wkład, Jeff. Niestety zawsze dostaję Y, nawet w podstawowej konsoli: S
Álex,