Bien que la réponse de Thomas Dickey soit tout à fait correcte, Stéphane Chazelas a correctement mentionné dans un commentaire à la réponse de Dickey que la conversion n'est pas figée; cela fait partie de la discipline de ligne.
En fait, la traduction est entièrement programmable.
La page de manuel man 3 termios contient essentiellement toutes les informations pertinentes. (Le lien mène au projet de pages de manuel Linux , qui mentionne les fonctionnalités qui sont uniquement Linux et celles qui sont communes à POSIX ou à d'autres systèmes; vérifiez toujours la section Conformité à sur chaque page.)
Les iflag
attributs de terminal ( old_settings[0]
dans le code montré dans la question en Python ) ont trois drapeaux pertinents sur tous les systèmes POSIXy:
INLCR
: Si défini, traduire NL en CR en entrée
ICRNL
: Si défini (et IGNCR
n'est pas défini), traduire CR en NL en entrée
IGNCR
: Ignorer CR sur l'entrée
De même, il existe également des paramètres de sortie associés ( old_settings[1]
):
OPOST
: Activer le traitement de sortie.
OCRNL
: Mappez CR à NL en sortie.
ONLCR
: Mappez NL sur CR en sortie. (XSI; non disponible sur tous les systèmes POSIX ou Single-Unix-Specification.)
ONOCR
: Ignorer (ne pas sortir) CR dans la première colonne.
ONLRET
: Ignorer (ne pas sortir) CR.
Par exemple, vous pourriez éviter de vous fier au tty
module. L'opération "makeraw" efface simplement un ensemble d'indicateurs (et définit l' 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
bien que pour des raisons de compatibilité, vous souhaiterez peut-être vérifier si toutes ces constantes existent d'abord dans le module termios (si vous exécutez sur des systèmes non-POSIX). Vous pouvez également utiliser new_settings[6][termios.VMIN]
et new_settings[6][termios.VTIME]
pour définir si une lecture se bloquera s'il n'y a pas de données en attente, et combien de temps (en nombre entier de décisecondes). (Il VMIN
est généralement défini sur 0 et VTIME
sur 0 si les lectures doivent revenir immédiatement, ou sur un nombre positif (dixième de seconde) pendant combien de temps la lecture doit attendre au plus.)
Comme vous pouvez le voir, ce qui précède (et "makeraw" en général) désactive toutes les traductions en entrée, ce qui explique le comportement du chat:
new_settings[0] = new_settings[0] & ~termios.INLCR
new_settings[0] = new_settings[0] & ~termios.ICRNL
new_settings[0] = new_settings[0] & ~termios.IGNCR
Pour obtenir un comportement normal, il suffit d'omettre les lignes effaçant ces trois lignes, et la traduction d'entrée est inchangée même lorsqu'elle est "brute".
La new_settings[1] = new_settings[1] & ~termios.OPOST
ligne désactive tout le traitement de sortie, indépendamment de ce que disent les autres drapeaux de sortie. Vous pouvez simplement l'omettre pour garder le traitement de sortie intact. Cela maintient la sortie "normale" même en mode brut. (Cela n'affecte pas si l'entrée est automatiquement répercutée ou non; cela est contrôlé par le ECHO
cflag in new_settings[3]
.)
Enfin, lorsque de nouveaux attributs sont définis, l'appel réussit si l' un des nouveaux paramètres a été défini. Si les paramètres sont sensibles - par exemple, si vous demandez un mot de passe sur la ligne de commande -, vous devez obtenir les nouveaux paramètres et vérifier que les indicateurs importants sont correctement définis / désactivés, pour être sûr.
Si vous souhaitez voir vos paramètres de terminal actuels, exécutez
stty -a
Les drapeaux d'entrée sont généralement sur la quatrième ligne et les drapeaux de sortie sur la cinquième ligne, avec un -
précédant le nom du drapeau si le drapeau n'est pas défini. Par exemple, la sortie pourrait être
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
Sur les pseudoterminaux et les périphériques USB TTY, le débit en bauds n'est pas pertinent.
Si vous écrivez des scripts Bash qui souhaitent lire par exemple des mots de passe, considérez l'idiome suivant:
#!/bin/bash
trap 'stty sane ; stty '"$(stty -g)" EXIT
stty -echo -echonl -imaxbel -isig -icanon min 1 time 0
Le EXIT
trap est exécuté à chaque sortie du shell. Le stty -g
lit les paramètres actuels du terminal au début du script, afin que les paramètres actuels soient restaurés automatiquement à la sortie du script. Vous pouvez même interrompre le script avec Ctrl+ C, et cela fera la bonne chose. (Dans certains cas d'angle avec des signaux, j'ai constaté que le terminal est parfois bloqué avec les paramètres bruts / non canoniques (en exigeant un pour taper reset
+ Enteraveuglément sur le terminal), mais courir stty sane
avant de restaurer les paramètres d'origine réels a guéri cela à chaque fois pour C'est pourquoi c'est là, une sorte de sécurité supplémentaire.)
Vous pouvez lire les lignes d'entrée (sans écho sur le terminal) à l'aide de read
bash intégré, ou même lire l'entrée caractère par caractère à l'aide
IFS=$'\0'
input=""
while read -N 1 c ; do
[[ "$c" == "" || "$c" == $'\n' || "$c" == $'\r' ]] && break
input="$input$c"
done
Si vous ne définissez pas IFS
sur ASCII NUL, la fonction read
intégrée consommera les séparateurs, ce qui c
sera vide. Piège pour jeunes joueurs.