Chociaż odpowiedź Thomasa Dickeya jest całkiem poprawna, Stéphane Chazelas słusznie wspomniał w komentarzu do odpowiedzi Dickeya, że nawrócenie nie jest ugruntowane; jest częścią dyscypliny liniowej.
W rzeczywistości tłumaczenie jest całkowicie programowalne.
Man 3 termios strona podręcznika zawiera w zasadzie wszystkie istotne informacje. (Odsyłacz prowadzi do projektu stron podręcznika systemu Linux , w którym wspomniano, które funkcje są dostępne tylko w systemie Linux i które są wspólne dla POSIX lub innych systemów; zawsze sprawdź tam sekcję Zgodność z na każdej stronie).
Te iflag
atrybuty terminali ( old_settings[0]
w kodzie przedstawionym w pytaniu w Pythonie ) ma trzy odpowiednie flagi na wszystkich systemach POSIXy:
INLCR
: Jeśli jest ustawiony, przetłumacz NL na CR na wejściu
ICRNL
: Jeśli jest ustawiony (i IGNCR
nie jest ustawiony), przetłumacz CR na NL na wejściu
IGNCR
: Zignoruj CR na wejściu
Podobnie istnieją również powiązane ustawienia wyjściowe ( old_settings[1]
):
OPOST
: Włącz przetwarzanie wyjściowe.
OCRNL
: Mapuj CR na NL na wyjściu.
ONLCR
: Mapuj NL na CR na wyjściu. (XSI; nie jest dostępny we wszystkich systemach POSIX lub Single-Unix-Specification.)
ONOCR
: Pomiń (nie wysyłaj) CR w pierwszej kolumnie.
ONLRET
: Pomiń (nie wysyłaj) CR.
Na przykład możesz uniknąć polegania na tty
module. Operacja „makeraw” po prostu usuwa zestaw flag (i ustawia CS8
oflag):
import sys
import termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
ch = None
try:
new_settings = termios.tcgetattr(fd)
new_settings[0] = new_settings[0] & ~termios.IGNBRK
new_settings[0] = new_settings[0] & ~termios.BRKINT
new_settings[0] = new_settings[0] & ~termios.PARMRK
new_settings[0] = new_settings[0] & ~termios.ISTRIP
new_settings[0] = new_settings[0] & ~termios.INLCR
new_settings[0] = new_settings[0] & ~termios.IGNCR
new_settings[0] = new_settings[0] & ~termios.ICRNL
new_settings[0] = new_settings[0] & ~termios.IXON
new_settings[1] = new_settings[1] & ~termios.OPOST
new_settings[2] = new_settings[2] & ~termios.CSIZE
new_settings[2] = new_settings[2] | termios.CS8
new_settings[2] = new_settings[2] & ~termios.PARENB
new_settings[3] = new_settings[3] & ~termios.ECHO
new_settings[3] = new_settings[3] & ~termios.ECHONL
new_settings[3] = new_settings[3] & ~termios.ICANON
new_settings[3] = new_settings[3] & ~termios.ISIG
new_settings[3] = new_settings[3] & ~termios.IEXTEN
termios.tcsetattr(fd, termios.TCSANOW, new_settings)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
chociaż ze względu na kompatybilność, możesz najpierw sprawdzić, czy wszystkie te stałe istnieją w module termios (jeśli działasz na systemach innych niż POSIX). Możesz także użyć new_settings[6][termios.VMIN]
i, new_settings[6][termios.VTIME]
aby ustawić, czy odczyt będzie blokowany, jeśli nie ma żadnych oczekujących danych, i jak długo (w liczbach całkowitych w decisekundach). (Zazwyczaj VMIN
jest ustawiony na 0 i VTIME
na 0, jeśli odczyty powinny natychmiast powrócić, lub do liczby dodatniej (dziesiąta sekunda), jak długo odczyt powinien czekać najwyżej.)
Jak widać powyższe (i ogólnie „ekspresaw”) wyłącza wszystkie tłumaczenia na wejściu, co wyjaśnia zachowanie, które widzi cat:
new_settings[0] = new_settings[0] & ~termios.INLCR
new_settings[0] = new_settings[0] & ~termios.ICRNL
new_settings[0] = new_settings[0] & ~termios.IGNCR
Aby uzyskać normalne zachowanie, po prostu pomiń wiersze usuwające te trzy wiersze, a tłumaczenie wejściowe pozostanie niezmienione, nawet gdy „surowe”.
new_settings[1] = new_settings[1] & ~termios.OPOST
Linia wyłącza wszystkie wyjścia przetwarzania, niezależnie co inne flagi wyjściowe powiedzieć. Możesz to pominąć, aby zachować nienaruszone przetwarzanie danych wyjściowych. Dzięki temu wyjście jest „normalne”, nawet w trybie surowym. (Nie wpływa to na to, czy sygnał wejściowy jest automatycznie powtarzany, czy nie; jest to kontrolowane przez ECHO
cflag in new_settings[3]
.)
Na koniec, gdy zostaną ustawione nowe atrybuty, połączenie zakończy się powodzeniem, jeśli zostaną ustawione jakiekolwiek nowe ustawienia. Jeśli ustawienia są wrażliwe - na przykład, jeśli pytasz o hasło w wierszu poleceń - powinieneś uzyskać nowe ustawienia i upewnić się, że ważne flagi są poprawnie ustawione / wyłączone.
Jeśli chcesz zobaczyć swoje aktualne ustawienia terminala, uruchom
stty -a
Flagi wejściowe są zwykle w czwartym wierszu, a flagi wyjściowe w piątym wierszu, z -
poprzedzającą nazwą flagi, jeśli flaga jest rozbrojona. Na przykład dane wyjściowe mogą być
speed 38400 baud; rows 58; columns 205; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
Na pseudoterminalach i urządzeniach USB TTY szybkość transmisji jest nieistotna.
Jeśli piszesz skrypty Bash, które chcą czytać np. Hasła, rozważ następujący idiom:
#!/bin/bash
trap 'stty sane ; stty '"$(stty -g)" EXIT
stty -echo -echonl -imaxbel -isig -icanon min 1 time 0
EXIT
Pułapka jest wykonywany, gdy powłoka wychodzi. stty -g
Odczytuje aktualne ustawienia terminal na początku skryptu, więc obecne ustawienia są przywracane po wyjściu skrypcie automatycznie. Możesz nawet przerwać skrypt za pomocą Ctrl+ C, a zrobi to dobrze. (W niektórych narożnych przypadkach z sygnałami stwierdziłem, że terminal czasami blokuje się w ustawieniach surowych / niekanonicznych (wymaga wpisania reset
+ na Enterślepo w terminalu), ale uruchomienie stty sane
przed przywróceniem faktycznych ustawień wyleczyło to za każdym razem ja. To dlatego tam jest; coś w rodzaju dodatkowego bezpieczeństwa.)
Możesz czytać wiersze wejściowe (niezwiązane z terminalem) za pomocą read
wbudowanego bash, a nawet czytać dane wejściowe znak po znaku za pomocą
IFS=$'\0'
input=""
while read -N 1 c ; do
[[ "$c" == "" || "$c" == $'\n' || "$c" == $'\r' ]] && break
input="$input$c"
done
Jeśli nie ustawisz IFS
ASCII NUL, read
wbudowane zużyją separatory, więc c
będą puste. Pułapka dla młodych graczy.