2009-09-17 6 views
12

Je jette un coup d'oeil sur le code à l'utilitaire 'less', en particulier comment il obtient l'entrée au clavier. Fait intéressant, la ligne 80 de ttyin.c, il définit le descripteur de fichier à lire:Moins d'entrées au clavier de stderr?

 /* 
     * 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; 

est un fichier non descripteur 2 stderr? Si oui, WTH ?! Je pensais que l'entrée au clavier était envoyée via stdin.

Fait intéressant, même si vous ls -l * | less, après que le fichier se termine le chargement, vous pouvez toujours utiliser le clavier pour faire défiler de haut en bas, mais si vous le faites ls -l * | vi, alors vi criera à vous, car il ne lit pas de stdin . Quelle est la grande idée? Comment est-ce que je me suis retrouvé dans cette étrange nouvelle contrée où stderr est à la fois un moyen de signaler des erreurs à l'écran et de lire depuis le clavier? Je ne pense pas que je suis au Kansas plus ...

+0

BTW, si vous écrivez 'ls -l * | vim -', vim effectuera une magie similaire. – ephemient

Répondre

19
 
$ 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é Dans un terminal interactif, les trois descripteurs de fichier standard pointent vers la même chose: votre TTY (ou pseudo-TTY).

 
$ 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 de 0 et écrire à 1 et 2. Cependant, rien ne nous empêche de faire autrement.

Lorsque votre shell fonctionne ls -l * | less, il crée un tuyau de ls « descripteur de fichier de 1 à less » descripteur de fichier de 0. Évidemment, less ne peut plus lire l'entrée du clavier de l'utilisateur à partir du descripteur de fichier 0 – il essaie de récupérer le TTY comme il le peut. Si less n'a pas été détaché du terminal, open("/dev/tty") lui donnera le TTY. Cependant, en cas d'échec ... que pouvez-vous faire? less fait une dernière tentative pour obtenir le TTY, en supposant que le descripteur de fichier 2 est attaché à la même chose que le descripteur de fichier 0 serait attaché, s'il n'était pas redirigé.

Ce n'est pas failproof:

 
$ ls -l * | setsid less 2>/dev/null 

Ici, less est donné sa propre session (donc il ne fait plus partie du groupe de processus actif du terminal, ce qui open("/dev/tty") à l'échec), et son fichier le descripteur 2 a été modifié – maintenant less se ferme immédiatement, car il est en train d'émettre vers un TTY mais il n'obtient aucune entrée utilisateur.

+3

+1, très complet. –

+0

Oh, je le vois maintenant. Parce que stderr n'est rien de plus qu'un bon descripteur de fichier connecté au terminal, il peut lire ou écrire à sa guise. C'EST SUPER! Merci, éphémère. – Michael

+0

Le descripteur '2 'ne serait-il pas ouvert à l'écriture? –

2

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 plusieurs Unix, '/ dev/tty' existe et il est peu probable qu'il provoque un échec.

En second lieu, le commentaire au sommet fournit une quantité limitée d'expliquer pourquoi ils se rabattent au descripteur de fichier 2. Je pense que stdin, stdout et stderr sont à peu près connecté à «/dev/TTY/» de toute façon, à moins d'être redirigé. Et puisque les redirections les plus courantes pour stdin et/ou stdout (via piping ou </>), mais moins souvent pour stderr, les chances sont que l'utilisation de stderr serait plus susceptible de toujours se connecter au "clavier".

+0

La raison de l'utilisation de stderr est que stdin/stdout sont plus susceptibles d'être des canaux créés par le shell de frai. Piping dans ou hors de moins est un noop, mais fonctionne. Mais rediriger stderr d'une commande moins a spécifiquement peu de valeur et n'est pas susceptible d'être fait. Donc parier que stderr est "vraiment" l'appareil terminal est une supposition raisonnable. –

1

La même question avec une réponse en fin de compte de la personne qui l'a demandé est sur linuxquestions bien qu'ils citent une source légèrement différente de less. Et non, je ne comprends pas la plus grande partie je ne peux pas aider au-delà :)

-2

Il semble être une fonctionnalité spécifique Linux qui envoie l'entrée du clavier à FD 2.

+1

Vraiment faux. Essayez ceci sur n'importe quel autre UNIX. – ephemient

Questions connexes