2009-09-17 7 views
12

sto prendendo uno sguardo al codice per l'utilità 'di meno', in particolare come si arriva input da tastiera. È interessante notare che, sulla linea 80 della ttyin.c, imposta il descrittore di file per leggere da:Meno riceve l'input da tastiera da 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; 

non è il file descrittore di 2 stderr? Se è così, WTH ?! Pensavo che l'input da tastiera fosse stato inviato tramite stdin.

È interessante notare che, anche se si fa ls -l * | less, dopo che il file termine del caricamento, è comunque possibile utilizzare la tastiera per scorrere verso l'alto e verso il basso, ma se lo fai ls -l * | vi, allora vi sarà urlare a voi, perché non legge da stdin . Qual è la grande idea? Come ho fatto a finire in questa strana nuova terra dove stderr è sia un modo per segnalare errori allo schermo e leggere dalla tastiera? Non credo di essere più in Kansas ...

+0

BTW, se scrivi 'ls -l * | vim -', vim eseguirà una magia simile. – ephemient

risposta

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 

Quando si accede a un terminale interativo, tutti e tre i descrittori di file standard indicano la stessa cosa: il tuo TTY (o 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 

Per convenzione, si legge da 0 e scrivere 1 e 2. Tuttavia, nulla ci impedisce di fare diversamente.

Quando la shell viene eseguito ls -l * | less, si crea una pipa da ls 'descrittore di file s 1 a less' s file di descrizione 0. Ovviamente, less non è più in grado di leggere l'input da tastiera dell'utente dal descrittore di file 0 – ma cerca di ottenere il TTY di nuovo, ma può farlo.

Se less non è stato scollegato dal terminale, open("/dev/tty") assegnerà il TTY.

Tuttavia, in caso di esito negativo ... cosa si può fare? less fa un ultimo tentativo di ottenere il TTY, assumendo che il descrittore di file 2 sia collegato alla stessa cosa a cui sarebbe assegnato il descrittore di file 0, se non fosse reindirizzato.

Questo non è failproof:

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

Qui, less è dato una propria sessione (in modo che non è più una parte del gruppo di processo attivo del terminale, provocando open("/dev/tty") a fallire), e il suo file il descrittore 2 è stato modificato – ora less termina immediatamente, perché è in uscita su un TTY ma non riesce a ricevere alcun input da parte dell'utente.

+3

+1, molto completo. –

+0

Oh, lo vedo ora. Poiché stderr non è altro che un descrittore di file che è effettivamente connesso al terminale, può leggere o scrivere da esso come preferisce. QUESTO È FIGO! Grazie, effeminato. – Michael

+0

Tuttavia, il descrittore di file '2' non dovrebbe essere aperto per la scrittura? –

2

Beh ... prima di tutto, sembra che manchi la chiamata open() che apre '/ dev/tty'. Utilizza solo il descrittore di file 2 se la chiamata a open() fallisce. Su un sistema standard di Linux, e probabilmente molti sistemi Unix, '/ dev/tty' esiste ed è improbabile che a causare un fail.

In secondo luogo, il commento alla parte superiore offre una quantità limitata di spiegazione sul perché ricadono al descrittore di file 2. La mia ipotesi è che stdin, stdout, e stderr sono più o meno collegato a '/ dev/tty /' comunque, a meno che non sia reindirizzato. E poiché i reindirizzamenti più comuni per stdin e/o stdout (tramite piping o </>), ma meno spesso per stderr, è probabile che l'utilizzo di stderr sia comunque connesso alla "tastiera".

+0

Il motivo dell'utilizzo di stderr è che stdin/stdout è più probabile che siano pipe create dalla shell di spawning. Piping dentro o fuori di meno è un noop, ma funziona. Ma il reindirizzamento dello stderr di un comando meno ha in particolare un valore limitato e non è probabile che venga eseguito. Quindi scommettere che stderr è "veramente" il dispositivo terminale è un'ipotesi ragionevole. –

1

La stessa domanda con una risposta in definitiva da parte della persona che lo ha richiesto è linuxquestions sebbene essi citino una fonte leggermente diversa da less. E no, non capisco la maggior parte di esso in modo non posso fare oltre a questo :)

-2

Sembra essere funzionalità specifiche di Linux che trasmette l'input da tastiera per FD 2.

+1

Davvero falso. Prova questo su qualsiasi altro UNIX. – ephemient