Comment `moins` prend-il les données de stdin tout en pouvant lire les commandes de l'utilisateur?

47

Comme la plupart d'entre vous l'ont fait à maintes reprises, il est pratique d'afficher un texte long en utilisant less:

some_command | less

Maintenant, son stdin est connecté à un tuyau (FIFO). Comment peut-il toujours lire des commandes comme up / down / quit?

iBug
la source
15
lesslit les données à afficher à partir de stdin, et lit les commandes du tty. Ce sont des choses différentes.
William Pursell
2
@ WilliamPursell Ouais je sais. Mais il n'y a qu'un seul flux d'entrée standard, non?
iBug
4
Oui, il y a un flux d'entrée et un tty. lesslit les données de stdin et les commandes du terminal.
William Pursell

Réponses:

52

Comme mentionné par William Pursell , lesslit les frappes de l'utilisateur depuis le terminal. Il ouvre explicitement /dev/ttyle terminal de contrôle; cela lui donne un descripteur de fichier, distinct de l'entrée standard, à partir duquel il peut lire l'entrée interactive de l'utilisateur. Il peut simultanément lire des données à afficher à partir de son entrée standard si nécessaire. (Il pourrait aussi écrire directement sur le terminal si nécessaire.)

Vous pouvez voir cela arriver en exécutant

some_command | strace -o less.trace -e open,read,write less

Déplacez-vous dans l'entrée, quittez less-le et examinez le contenu de less.trace: vous verrez qu'il s'ouvre /dev/ttyet lit le descripteur de fichier 0 et celui qui a été renvoyé lors de son ouverture /dev/tty(probablement 3).

C'est une pratique courante pour les programmes qui souhaitent s'assurer qu'ils lisent et écrivent sur le terminal. SSH en est un exemple, par exemple lorsqu'il demande un mot de passe ou une phrase secrète.

Comme expliqué par schily , si /dev/ttyimpossible, lessnous lirons son erreur standard (descripteur de fichier 2). lessL'utilisation de de a /dev/ttyété introduite dans la version 177, publiée le 2 avril 1991.

Si vous essayez de courir cat /dev/tty | less, comme suggéré par Hagen von Eitzen , vous lessréussirez à ouvrir /dev/ttymais n’obtiendrez aucune information de sa part avant la catfermeture. Donc, vous verrez l'écran vide et rien d'autre jusqu'à ce que vous appuyiez sur CtrlCpour tuer cat(ou le tuer d'une autre manière); puis lessmontrera tout ce que vous avez tapé pendant que vous étiez en catcours d’exécution, et vous permettra de le contrôler.

Stephen Kitt
la source
4
@HagenvonEitzen Votre ordinateur va exploser! C'est comme la façon dont Kirk et Spock ont ​​provoqué le crash des androïdes de Mudd.
Barmar
7
@ HagenvonEitzen Wow. Une utilisation doublement inutile du chat . Je suis impressionné.
Andrew Henle
8
@grawity Je pense que le point de vue d’Andrew est que cela cat blah |peut être remplacé par < blah, et même cela est inutile dans ce cas puisque cela less blahfonctionne aussi (bien, less -f /dev/tty). Mais la lecture de /dev/ttyest un cas un peu spécial, et les trois variantes ( cat /dev/tty | less, less < /dev/ttyet less -f /dev/tty) produisent des résultats différents.
Stephen Kitt
1
Est-ce que / dev / tty pointe toujours au bon endroit? Je penserais que vous auriez besoin d'utiliser / dev / ptsX habituellement?
StarWeaver
2
@ StarWeaver voir cette question sur la différence entre /dev/ttyet /dev/pts/....
Stephen Kitt
26

UNIX donne deux méthodes pour lire les entrées des utilisateurs lorsque stdin a été redirigé:

  • La méthode originale est de lire stderr . Stderr est ouvert à l'écriture et à la lecture et cela est toujours mentionné dans POSIX.

  • Les versions ultérieures d'UNIX (vers 1979) ont ajouté une /dev/ttyinterface de pilote permettant d'ouvrir le contrôle d'un processus. Puisqu'il existe des processus sans tty de contrôle, il est possible qu'une tentative d'ouverture /dev/ttyéchoue. Le logiciel écrit amical a donc un recours à la méthode originale et essaie ensuite de lire stderr.

schily
la source
11
Lu de stderr? J'ai appris quelque chose de nouveau.
iBug
1
Je suis content que quelqu'un se souvienne des anciennes méthodes.
Josué
3
Est-ce que stderr est utilisé pour la lecture, car c'est le moins susceptible d'avoir été redirigé? Je ne vois aucune autre différence entre cela et stdout (ou pour ce mater stdin, avant la redirection).
ctrl-alt-delor
4
Oui, c’est parce que c’est le descripteur de fichier qui a le moins de chance d’être redirigé.
Schily
@ ctrl-alt-delor: Il était / est typique que les shells s'exécutent avec stdin, stdout et stderr, tous étant des dup()licences de la même description de fichier, bien que tous soient ouverts sur le tty. (Apparemment, POSIX exige ou suggère toujours (cette réponse ne dit pas) que stderr soit une FD en lecture / écriture, non ouverte avec quelque chose comme open("/dev/ttyS0", O_WRONLY). La lecture de stderr échouerait dans ce cas.)
Peter Cordes