Shell – How to check if stdin is /dev/null from the shell

deviceslinuxshellstdin

On Linux, is there a way for a shell script to check if its standard input is redirected from the null device (1, 3) *, ideally without reading anything?

The expected behavior would be:

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

EDIT

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

I suspect I "just" need to read the maj/min number of the input device. But I can't find a way of doing that from the shell.


*No necessary just /dev/null, but any null device even if manually created with mknod.

Best Answer

On linux, you can do it with:

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

On a linux without stat(1) (eg. the busybox on your router):

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

On *bsd:

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

On systems like *bsd and solaris, /dev/stdin, /dev/fd/0 and /proc/PID/fd/0 are not "magical" symlinks as on linux, but character devices which will switch to the real file when opened. A stat(2) on their path will return something different than a fstat(2) on the opened file descriptor.

This means that the linux example will not work there, even with GNU coreutils installed. If the versions of GNU stat(1) is recent enough, you can use the - argument to let it do a fstat(2) on the file descriptor 0, just like the stat(1) from *bsd:

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

It's also very easy to do the check portably in any language which offers an interface to fstat(2), eg. in perl:

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