Comment vérifier si stdin est / dev / null du shell?


9

Sous Linux, existe-t-il un moyen pour un script shell de vérifier si son entrée standard est redirigée depuis le périphérique nul (1, 3) * , idéalement sans rien lire?

Le comportement attendu serait:

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

EDIT

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

Je soupçonne que j'ai "juste" besoin de lire le nombre maj / min du périphérique d' entrée . Mais je ne peux pas trouver un moyen de le faire à partir du shell.


* Pas nécessaire seulement /dev/null, mais tout appareil nul même s'il a été créé manuellement avec mknod.


2
Avez-vous besoin de savoir si c'est le cas /dev/null, ou tout simplement que ce n'est pas un tty?
roaima

La sortie de { readlink -f /dev/stdin; } <&6pour le cas où vous avez utilisé exec et supprimé le nœud est /root/secretunknownname (deleted). Comme cela montre que le fichier a été supprimé: n'est-ce pas suffisant pour ce dont vous avez besoin?
Isaac

J'ai besoin (en fait "nécessaire") de savoir si l'entrée standard était le périphérique nul.
Sylvain Leroux

2
J'essaie de trouver ma voie dans un système industriel (très mal conçu!). Et il mappe parfois l'entrée de l'utilitaire de travail sur le périphérique nul ou, à d'autres moments, sur le périphérique matériel réel. Dans les deux cas, en utilisant le même code, mais avec des numéros de développement majeurs / mineurs différents. Nous essayons de savoir quand (et pourquoi!) Il a parfois choisi d'utiliser l'un ou l'autre. Pour l'instant, la statsolution est la seule qui fonctionne.
Sylvain Leroux

"Donc, l'exemple sur votre EDIT ne reproduit pas vraiment le problème que vous décrivez, ou: est-ce le cas?" Cela fait. Entrée redirigée depuis le périphérique nul . Qui est généralement accessible via /dev/null, mais pas nécessaire. Vous pouvez "alias" est avec mknods illustré dans mon exemple.
Sylvain Leroux

Réponses:


18

Sous linux, vous pouvez le faire avec:

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

Sur un Linux sans stat (1) (par exemple, la busybox de votre routeur):

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

Sur * bsd:

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

Sur les systèmes tels que * bsd et solaris, /dev/stdin, /dev/fd/0et /proc/PID/fd/0ne sont pas des liens symboliques « magiques » comme sur les périphériques Linux, mais le caractère qui passera au fichier réel lors de l' ouverture . Un stat (2) sur leur chemin retournera quelque chose de différent d'un fstat (2) sur le descripteur de fichier ouvert.

Cela signifie que l'exemple Linux ne fonctionnera pas là-bas, même avec les coreutils GNU installés. Si les versions de GNU stat (1) sont assez récentes, vous pouvez utiliser l' -argument pour le laisser faire un fstat (2) sur le descripteur de fichier 0, tout comme le stat (1) de * bsd:

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

Il est également très facile de faire la vérification de manière portative dans n'importe quelle langue qui offre une interface à fstat (2), par exemple. dans perl:

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

1
Comme le type d'appareil /dev/nullest 1:3, vous pouvez le tester immédiatement.
RudiC

12
FWIW la question ne portait pas sur la syntaxe du shell. Pour ce qui concerne mon problème, si la réponse m'avait seulement indiqué la statcommande, j'aurais déjà été assez satisfait. Je ne vois pas l'intérêt de lancer une guerre d'édition entre `et $(partisans. Personnellement, je préfère $(...)et il y a des raisons POSIX en faveur de cette syntaxe ( pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) Mais je ne vois pas l'intérêt de voter en aval une réponse par ailleurs correcte pour quelque chose qui n'est pas lié à la question.
Sylvain Leroux

2
Quelqu'un pourrait-il expliquer pourquoi $( ... )on préfère les raccourcis dans le contexte de cette réponse?
user1717828

" quel bug ça corrige "? Cela ne corrige pas un bug. Le $(..)style s'imbrique plus facilement et AIUI est l'approche préférée de POSIX. Je n'avais certainement pas l'intention de commencer une quelconque forme d'édition de guerre, préférant commenter avec une suggestion plutôt que de changer votre excellente réponse.
roaima

@ user1717828 voir ici et ici et ici pour plus de clarté.
roaima

16

Sous Linux, pour déterminer si l'entrée standard est redirigée à partir de /dev/null, vous pouvez vérifier si /proc/self/fd/0le même périphérique et le même inode que /dev/null:

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

Vous pouvez utiliser à la /dev/stdinplace de /proc/self/fd/0.

Si vous souhaitez vérifier si l'entrée standard est redirigée à partir du périphérique nul, vous devez comparer les numéros de périphérique majeur et mineur, par exemple en utilisant stat(voir également la réponse de mosvy ):

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

ou, si vous ne vous souciez pas que ce soit spécifique à Linux ,

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

2
-ef, True si FILE1 et FILE2 font référence au même périphérique et inode
Rui F Ribeiro

très cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null'puis recommencez avec </dev/null. +1
glenn jackman

1
Le fait d' /dev/stdinêtre un lien symbolique vers le fichier d'origine est spécifique à Linux, donc toutes ces solutions sont spécifiques à Linux de toute façon. Les statceux à base exigent GNU ou busybox stat. Avec les versions récentes de GNU stat, vous pouvez utiliser stat -pour faire un fstat()sur fd 0 qui fonctionnerait alors sur des systèmes non Linux.
Stéphane Chazelas

@ Stéphane la dernière partie est exactement la situation dans laquelle s'est déroulé l'OP, c'est pourquoi j'ai rédigé les deux solutions, en distinguant entre /dev/nullet le dispositif nul.
Stephen Kitt

Oups, j'ai raté ça.
Stéphane Chazelas

3

De manière portative, pour vérifier que stdin est le nullpériphérique (ouvert /dev/nullou non (comme une copie de /dev/null)), avec zsh(dont la statversion antérieure à GNU et FreeBSD est statd'ailleurs (pas IRIX 'cependant))):

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

(notez qu'il ne dit pas si le descripteur de fichier était ouvert en mode lecture seule, écriture seule ou lecture + écriture).

Pour vérifier qu'il est ouvert /dev/nullspécifiquement sur le fichier actuel (pas /some/chroot/dev/nullpar exemple), sur Linux uniquement (où /dev/stdinest implémenté en tant que lien symbolique vers le fichier ouvert sur fd 0 au lieu d'un périphérique spécial qui, lorsqu'il est ouvert, agit comme un dup(0)dans d'autres systèmes):

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

Sur non-Linux, vous pouvez essayer:

if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
  echo stdin is open on /dev/null
fi
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.