Moins obtient une entrée au clavier de stderr?
-
10-07-2019 - |
Question
Je regarde le code de l'utilitaire 'less', en particulier la façon dont il est saisi au clavier. Fait intéressant, à la ligne 80 de ttyin.c, il définit le descripteur de fichier à lire:
/*
* Try /dev/tty.
* If that doesn't work, use file descriptor 2,
* which in Unix is usually attached to the screen,
* but also usually lets you read from the keyboard.
*/
#if OS2
/* The __open() system call translates "/dev/tty" to "con". */
tty = __open("/dev/tty", OPEN_READ);
#else
tty = open("/dev/tty", OPEN_READ);
#endif
if (tty < 0)
tty = 2;
Le descripteur de fichier 2 n'est-il pas stderr? Si oui, WTH?! Je pensais que la saisie au clavier était envoyée via stdin.
Fait intéressant, même si vous le faites ls -l * | less
, une fois le chargement du fichier terminé, vous pouvez toujours utiliser le clavier pour faire défiler de haut en bas, mais si vous le faites ls -l * | vi
, vi vous criera dessus car il ne le fera pas. lu de stdin. Quelle est la grande idée? Comment suis-je arrivé dans ce nouveau pays étrange où stderr est à la fois un moyen de signaler des erreurs à l'écran et de le lire au clavier? Je ne pense plus être au Kansas ...
La solution
$ ls -l /dev/fd/ lrwx------ 1 me me 64 2009-09-17 16:52 0 -> /dev/pts/4 lrwx------ 1 me me 64 2009-09-17 16:52 1 -> /dev/pts/4 lrwx------ 1 me me 64 2009-09-17 16:52 2 -> /dev/pts/4
Une fois connectés à un terminal interactif, les trois descripteurs de fichier standard renvoient à la même chose: votre téléscripteur (ou pseudo-téléscripteur).
$ ls -fl /dev/std{in,out,err} lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stdin -> fd/0 lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stdout -> fd/1 lrwxrwxrwx 1 root root 4 2009-09-13 01:57 /dev/stderr -> fd/2
Par convention, nous lisons à partir de 0
et écrivons dans 1
et 2
. Cependant, rien ne nous empêche de faire autrement.
Lorsque votre shell exécute ls -l * | less
, il crée un canal entre le descripteur de fichier de ls
less
et le descripteur de fichier de open("/dev/tty")
<=>. De toute évidence, <=> ne peut plus lire l'entrée au clavier de l'utilisateur à partir du descripteur de fichier <=> & # 8211; il essaie de récupérer le téléscripteur comme il le peut.
Si <=> n'a pas été détaché du terminal, <=> lui attribuera le ATS.
Cependant, si cela échoue ... que pouvez-vous faire? <=> tente une dernière fois d'obtenir le TTY, en supposant que le descripteur de fichier <=> est attaché à la même chose que le descripteur de fichier <=>, s'il n'était pas redirigé.
Ceci n'est pas à l'épreuve des échecs:
$ ls -l * | setsid less 2>/dev/null
Ici, <=> reçoit sa propre session (de sorte qu'il ne fait plus partie du groupe de processus actif du terminal, ce qui entraîne l'échec de <=>), et son descripteur de fichier <=> a été modifié & # 8211; maintenant <=> quitte immédiatement, car il émet vers un téléscripteur mais il n'obtient aucune entrée d'utilisateur.
Autres conseils
Eh bien ... tout d'abord, vous semblez manquer l'appel open()
qui ouvre "/ dev / tty". Il utilise uniquement le descripteur de fichier 2 si l'appel à open () échoue. Sur un système Linux standard, et probablement sur de nombreux Unices, '/ dev / tty' existe et ne risque pas de provoquer un échec.
Deuxièmement, le commentaire en haut fournit une quantité limitée d'explications quant à la raison pour laquelle ils retombent dans le descripteur de fichier 2. Mon hypothèse est que stdin
, stdout
et stderr
sont assez liés à '/ dev / tty / 'de toute façon, sauf si redirigé. Et puisque les redirections les plus courantes pour stdin et / ou stdout (via la tuyauterie ou <
/ >
), mais moins souvent pour <=>, il y a de fortes chances que l'utilisation de <=> soit toujours connectée au " clavier ".
La même question avec une réponse finale de la personne qui l'a posée se trouve sur linuxquestions bien qu'ils citent une source légèrement différente de less
. Et non, je ne comprends pas la majeure partie, je ne peux donc rien faire au-delà de ça:)
Il semble que ce soit une fonctionnalité spécifique à Linux qui envoie une entrée au clavier à FD 2.