Pourquoi la touche Enter ne renvoie-t-elle pas EOL?

Unix / Linux EOL est LF, saut de ligne, ASCII 10, séquence d'échappement \n .

Voici un extrait de code Python pour get exactement une touche:

 import sys, tty, termios fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(sys.stdin.fileno()) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ch 

Lorsque j'appuie sur Entrée sur mon keyboard en réponse à cet extrait, il donne \r , return chariot, ASCII 13.

Sous Windows , Enter envoie CR LF == 13 10 . * nix n'est pas Windows; pourquoi est-ce que Enter donne 13 plutôt que 10?


On sait que l'extrait de Python est correct.

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 complètement programmable.

La page man 3 termios man contient essentiellement toutes les informations pertinentes. (Le lien renvoie au projet man-pages Linux , qui mentionne quelles fonctionnalités sont uniquement Linux et qui sont communes à POSIX ou à d'autres systèmes, vérifiez toujours la section Conforming to de chaque page.)

Les iflag terminal iflag ( old_settings[0] dans le code affiché dans la question en Python ) ont trois indicateurs pertinents sur tous les systèmes POSIXy:

  • INLCR : Si défini, traduisez NL en CR sur l'input
  • ICRNL : Si set (et IGNCR n'est pas défini), traduisez CR en NL sur l'input
  • IGNCR : IGNCR CR sur l'input

De même, il existe des parameters de sortie associés ( old_settings[1] ), aussi:

  • OPOST : OPOST traitement de sortie.
  • OCRNL : OCRNL CR en NL sur la sortie.
  • ONLCR : ONLCR NL à CR sur la sortie. (XSI, non disponible dans 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 module tty . L'opération "makeraw" efface simplement un set de drapeaux (et définit le 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 pouvez vérifier si toutes ces constantes existent dans le module termios (si vous utilisez 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 bloquera s'il n'y a pas de données en attente et combien de time (en integer de décisecondes). (Typiquement, VMIN est mis à 0 et VTIME à 0 si les lectures doivent renvoyer immédiatement ou à un nombre positif (dixième de secondes) combien de time la lecture doit attendre au plus).

Comme vous pouvez le voir, ce qui précède (et "makeraw" en général) désactive toute traduction en input, ce qui explique le comportement que le chat voit:

  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 get un comportement normal, il suffit d'omettre les lignes qui effacent ces trois lignes, et la traduction d'input est inchangée, même lorsque "raw".

La ligne new_settings[1] = new_settings[1] & ~termios.OPOST désactive tout le traitement de sortie, indépendamment de ce que disent les autres indicateurs 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'input est automatiquement répercutée ou non, cela est contrôlé par la command ECHO dans new_settings[3] .)

Enfin, lorsque de nouveaux attributes sont définis, l'appel aboutira si l' un des nouveaux parameters a été défini. Si les parameters sont sensibles – par exemple, si vous requestz un mot de passe sur la command line -, vous devez get les nouveaux parameters et vérifier que les indicateurs importants sont correctement définis / désactivés.

Si vous souhaitez voir vos parameters de terminal actuels, exécutez

 stty -a 

Les drapeaux d'input sont généralement sur la quasortingème ligne, et les drapeaux de sortie sur la cinquième ligne, avec un - précédant le nom du drapeau si le drapeau est désactivé. 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 -issortingp -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 périphériques 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 passwords, 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 piège EXIT est exécuté chaque fois que le shell se ferme. Le stty -g lit les parameters actuels du terminal au début du script, de sorte que les parameters actuels sont restaurés lorsque le script se ferme automatiquement. Vous pouvez même interrompre le script avec Ctrl + C , et il fera la bonne chose. (Dans certains cas de coin avec des signaux, j'ai trouvé que le terminal se coinçait parfois avec les parameters raw / noncanonical (nécessitant de taper reset + Enter aveuglément au terminal), mais en exécutant stty sane avant de restaurer les parameters d'origine réels a guéri que chaque fois pour moi, c'est pour ça que c'est là, une sorte de security supplémentaire.)

Vous pouvez lire les lignes d'input (non échouées au terminal) en utilisant read bash embedded, ou même lire l'input caractère par caractère en utilisant

 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 read embeddede consum les séparateurs, de sorte que c sera vide. Piège pour les jeunes joueurs.

Essentiellement "parce que cela a été fait de cette façon depuis les machines à écrire manuelles". Vraiment.

Une machine à écrire manuelle avait un chariot sur lequel le papier était alimenté, et il a avancé en tapant (chargement d'un ressort) et avait un levier ou une key qui libérerait le chariot, laissant le ressort returnner le chariot à la marge de gauche.

Comme la saisie électronique des données (téléimprimeur, etc.) a été introduite, ils l'ont fait avancer. Ainsi, la touche Entrée de nombreux terminaux serait étiquetée Retour .

Les returns à la ligne sont arrivés (dans le process manuel) après avoir ramené le chariot dans la marge de gauche. Encore une fois, les appareils électroniques imitaient les appareils manuels, effectuant une opération d' alimentation en ligne distincte.

Les deux opérations sont codées (pour que le télétype soit plus qu'un périphérique autonome créant un type de papier), nous avons donc CR (return chariot) et LF ( LF ligne). Cette image de ASR 33 Teletype Information montre le keyboard, avec Return sur le côté droit et Line-Feed juste à gauche. Être à droite , c'était la key principale:

entrer la description de l'image ici

Unix est venu plus tard. Ses développeurs ont aimé raccourcir les choses (regardez toutes les abréviations, même creat pour "créer"). Face à un process en deux parties, ils ont décidé que les returns à la ligne n'avaient de sens que s'ils étaient précédés d'un return chariot. Ils ont donc abandonné les returns chariot explicites à partir des files et ont traduit la touche Retour du terminal pour envoyer le saut de ligne correspondant. Juste pour éviter la confusion, ils ont appelé le saut de ligne comme "nouvelle ligne".

Lors de l'écriture de text sur le terminal, Unix traduit dans l'autre direction: un saut de ligne devient chariot-return / saut de ligne.

(C'est-à-dire "normalement": ce que l'on appelle le "mode cuit", contrairement au mode "brut" où aucune traduction n'est faite).

Résumé:

  • chariot-return / saut de ligne est la séquence 13 10
  • l' appareil envoie 13 (depuis "pour toujours" selon vos termes)
  • Les systèmes de type Unix changent à 13 10
  • D'autres systèmes ne stockent pas nécessairement seulement 10 (Windows accepte en gros seulement 10 ou 13 10, selon l'importance de la compatibilité).