Come verificare se stdin è / dev / null dalla shell?


9

Su Linux, c'è un modo per uno script di shell di verificare se il suo input standard viene reindirizzato dal dispositivo null (1, 3) * , idealmente senza leggere nulla?

Il comportamento previsto sarebbe:

./checkstdinnull
-> no
./checkstdinnull < /dev/null
-> yes
echo -n | ./checkstdinnull
-> no

EDIT

mknod secretunknownname c 1 3
exec 6<secretunknownname
rm secretunknownname
./checkstdinnull <&6
-> yes

Sospetto di aver "solo" bisogno di leggere il numero maggiore / minimo del dispositivo di input . Ma non riesco a trovare un modo per farlo dalla shell.


* Non necessario /dev/null, ma qualsiasi dispositivo null anche se creato manualmente con mknod.


2
Hai bisogno di sapere se lo è /dev/null, o semplicemente che non è un tty?
roaima,

L'output di { readlink -f /dev/stdin; } <&6per il caso in cui è stato utilizzato exec e rimosso il nodo è /root/secretunknownname (deleted). Come dimostra che il file è stato cancellato: non è abbastanza per quello che ti serve?
Isaac,

Ho bisogno (in realtà "necessario") di sapere se l'input standard era il dispositivo null.
Sylvain Leroux,

2
Sto cercando di trovare la mia strada in un sistema industriale (progettato molto male!). E a volte associa l'input dell'utilità worker al dispositivo null o, altre volte, al dispositivo hardware effettivo. In entrambi i casi si utilizza lo stesso codice, ma con numeri di sviluppo maggiori / minori diversi. Stiamo cercando di tracciare quando (e perché!) A volte ha scelto di usare l'uno o l'altro. Per ora, la statsoluzione è l'unica che funziona.
Sylvain Leroux,

"Quindi, l'esempio sulla tua EDIT non riproduce realmente il problema che descrivi, oppure: vero?" Lo fa. Input reindirizzato dal dispositivo null . Di solito si accede attraverso /dev/null, ma non è necessario. Puoi "alias" con mknods illustrato nel mio esempio.
Sylvain Leroux,

Risposte:


18

Su Linux, puoi farlo con:

stdin_is_dev_null(){ test "`stat -Lc %t:%T /dev/stdin`" = "`stat -Lc %t:%T /dev/null`"; }

Su un Linux senza stat (1) (es. La busybox sul tuo router):

stdin_is_dev_null(){ ls -Ll /proc/self/fd/0 | grep -q ' 1,  *3 '; }

Su * bsd:

stdin_is_dev_null(){ test "`stat -f %Z`" = "`stat -Lf %Z /dev/null`"; }

Su sistemi come * BSD e Solaris, /dev/stdin, /dev/fd/0e /proc/PID/fd/0non sono i collegamenti simbolici "magici" come su Linux, ma i dispositivi a carattere, che passerà al file reale una volta aperto . Una stat (2) sul loro percorso restituirà qualcosa di diverso da un fstat (2) sul descrittore di file aperto.

Questo significa che l'esempio di Linux non funzionerà lì, anche con i coreutils GNU installati. Se le versioni di GNU stat (1) sono abbastanza recenti, puoi usare l' -argomento per fargli fare un fstat (2) sul descrittore di file 0, proprio come stat (1) da * bsd:

stdin_is_dev_null(){ test "`stat -Lc %t:%T -`" = "`stat -Lc %t:%T /dev/null`"; }

E 'anche molto facile da fare il check- portabile in tutte le lingue, che offre un'interfaccia per fstat (2), ad esempio. in perl:

stdin_is_dev_null(){ perl -e 'exit((stat STDIN)[6]!=(stat "/dev/null")[6])'; }

1
Poiché il tipo di dispositivo /dev/nullè 1:3, è possibile verificarlo immediatamente.
RudiC,

12
FWIW la domanda non riguardava la sintassi della shell. Per quanto riguarda il mio problema, se la risposta mi avesse solo indicato il statcomando sarei già abbastanza soddisfatto. Non vedo il punto di iniziare una guerra di editing tra `e i $(sostenitori. Personalmente preferisco $(...)e ci sono alcune motivazioni POSIX a favore di quella sintassi ( pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) Ma non vedo il punto nel downgrade di una risposta altrimenti corretta per qualcosa che non è correlato al domanda.
Sylvain Leroux,

2
Qualcuno potrebbe spiegare perché $( ... )è preferito rispetto ai backtick nel contesto di questa risposta?
user1717828,

" quale bug risolve "? Non corregge un bug. Lo $(..)stile nidifica più facilmente e AIUI è l'approccio preferito da POSIX. Sicuramente non avevo intenzione di iniziare alcuna forma di modifica della guerra, preferendo commentare con un suggerimento piuttosto che cambiare la tua eccellente risposta.
roaima,

@ user1717828 vedi qui e qui e qui per un po 'di chiarezza.
roaima,

16

Su Linux, per determinare se reindirizzare l'input standard /dev/null, è possibile verificare se /proc/self/fd/0ha lo stesso dispositivo e lo stesso inode di /dev/null:

if [ /proc/self/fd/0 -ef /dev/null ]; then echo yes; else echo no; fi

Puoi usare /dev/stdininvece di /proc/self/fd/0.

Se si desidera verificare se l'input standard viene reindirizzato dal dispositivo null, è necessario confrontare i numeri dei dispositivi principali e secondari, ad esempio utilizzando stat(vedere anche la risposta di Mosvy ):

if [ "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)" ]; then echo yes; else echo no; fi

o, se non ti interessa che questo sia specifico di Linux ,

if [ "$(stat -Lc %t:%T /dev/stdin)" = "1:3" ]; then echo yes; else echo no; fi

2
-ef, True se FILE1 e FILE2 si riferiscono allo stesso dispositivo e inode
Rui F Ribeiro,

molto bello. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null'quindi farlo di nuovo con </dev/null. +1
glenn jackman,

1
L' /dev/stdinessere un link simbolico al file originale è specifico di Linux, quindi tutte quelle soluzioni sono comunque specifiche di Linux. Gli statquelli basati su GNU richiedono o busybox stat. Con le versioni recenti di GNU stat, puoi usare stat -per fare un fstat()su fd 0 che funzionerebbe quindi su sistemi non Linux.
Stéphane Chazelas il

@ Stéphane l'ultima parte è esattamente la situazione in cui si è verificato l'OP, motivo per cui ho scritto entrambe le soluzioni, distinguendo tra /dev/nullil dispositivo nullo.
Stephen Kitt,

Oops, l'ho perso.
Stéphane Chazelas,

3

Portabilmente, per verificare che stdin sia il nulldispositivo (aperto /dev/nullo meno (come una copia di /dev/null)), con zsh(il cui statbuiltin precede sia GNU che FreeBSD stattra l'altro (non IRIX 'comunque))):

zmodload zsh/stat
if [ "$(stat +rdev -f 0)" = "$(stat +rdev /dev/null)" ]; then
  echo stdin is open on the null device
fi

(nota che non dice se il descrittore di file era aperto in modalità di sola lettura, sola lettura o lettura + scrittura).

Per verificare che sia aperto sul /dev/nullfile corrente in modo specifico (non /some/chroot/dev/nullad esempio), solo su Linux (dove /dev/stdinè implementato come link simbolico al file aperto su fd 0 invece di un dispositivo speciale che quando aperto si comporta come un dup(0)in altri sistemi):

if [ /dev/stdin -ef /dev/null ]; then
  echo stdin is open on /dev/null
fi

Su non Linux, puoi provare:

if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
  echo stdin is open on /dev/null
fi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.