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











up vote
6
down vote

favorite
2












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.








share|improve this question




















  • 2




    Do you need to know if it's /dev/null, or just that it's not a tty?
    – roaima
    13 hours ago










  • The output of { readlink -f /dev/stdin; } <&6 for the case where you used exec and removed the node is /root/secretunknownname (deleted). As it shows that the file got deleted: Isn't that enough for what you need?
    – Isaac
    11 hours ago










  • I need (actually "needed") to know if the standard input was the null device.
    – Sylvain Leroux
    11 hours ago










  • But checking for the /dev/null won't work for rm secretunknownname, would it?
    – Isaac
    11 hours ago










  • I am trying to find my way in a (very poorly designed!) industrial system. And it sometimes maps input of worker utility to the null device, or, some other times, to the actual hardware device. In both cases using the same code, but with different major/minor dev numbers. We are trying to track when (and why!) it sometimes chose to use one or the other. For now, the stat solution is the only one working.
    – Sylvain Leroux
    11 hours ago

















up vote
6
down vote

favorite
2












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.








share|improve this question




















  • 2




    Do you need to know if it's /dev/null, or just that it's not a tty?
    – roaima
    13 hours ago










  • The output of { readlink -f /dev/stdin; } <&6 for the case where you used exec and removed the node is /root/secretunknownname (deleted). As it shows that the file got deleted: Isn't that enough for what you need?
    – Isaac
    11 hours ago










  • I need (actually "needed") to know if the standard input was the null device.
    – Sylvain Leroux
    11 hours ago










  • But checking for the /dev/null won't work for rm secretunknownname, would it?
    – Isaac
    11 hours ago










  • I am trying to find my way in a (very poorly designed!) industrial system. And it sometimes maps input of worker utility to the null device, or, some other times, to the actual hardware device. In both cases using the same code, but with different major/minor dev numbers. We are trying to track when (and why!) it sometimes chose to use one or the other. For now, the stat solution is the only one working.
    – Sylvain Leroux
    11 hours ago















up vote
6
down vote

favorite
2









up vote
6
down vote

favorite
2






2





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.








share|improve this question















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.





linux shell devices stdin






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 12 hours ago

























asked 13 hours ago









Sylvain Leroux

40729




40729








  • 2




    Do you need to know if it's /dev/null, or just that it's not a tty?
    – roaima
    13 hours ago










  • The output of { readlink -f /dev/stdin; } <&6 for the case where you used exec and removed the node is /root/secretunknownname (deleted). As it shows that the file got deleted: Isn't that enough for what you need?
    – Isaac
    11 hours ago










  • I need (actually "needed") to know if the standard input was the null device.
    – Sylvain Leroux
    11 hours ago










  • But checking for the /dev/null won't work for rm secretunknownname, would it?
    – Isaac
    11 hours ago










  • I am trying to find my way in a (very poorly designed!) industrial system. And it sometimes maps input of worker utility to the null device, or, some other times, to the actual hardware device. In both cases using the same code, but with different major/minor dev numbers. We are trying to track when (and why!) it sometimes chose to use one or the other. For now, the stat solution is the only one working.
    – Sylvain Leroux
    11 hours ago
















  • 2




    Do you need to know if it's /dev/null, or just that it's not a tty?
    – roaima
    13 hours ago










  • The output of { readlink -f /dev/stdin; } <&6 for the case where you used exec and removed the node is /root/secretunknownname (deleted). As it shows that the file got deleted: Isn't that enough for what you need?
    – Isaac
    11 hours ago










  • I need (actually "needed") to know if the standard input was the null device.
    – Sylvain Leroux
    11 hours ago










  • But checking for the /dev/null won't work for rm secretunknownname, would it?
    – Isaac
    11 hours ago










  • I am trying to find my way in a (very poorly designed!) industrial system. And it sometimes maps input of worker utility to the null device, or, some other times, to the actual hardware device. In both cases using the same code, but with different major/minor dev numbers. We are trying to track when (and why!) it sometimes chose to use one or the other. For now, the stat solution is the only one working.
    – Sylvain Leroux
    11 hours ago










2




2




Do you need to know if it's /dev/null, or just that it's not a tty?
– roaima
13 hours ago




Do you need to know if it's /dev/null, or just that it's not a tty?
– roaima
13 hours ago












The output of { readlink -f /dev/stdin; } <&6 for the case where you used exec and removed the node is /root/secretunknownname (deleted). As it shows that the file got deleted: Isn't that enough for what you need?
– Isaac
11 hours ago




The output of { readlink -f /dev/stdin; } <&6 for the case where you used exec and removed the node is /root/secretunknownname (deleted). As it shows that the file got deleted: Isn't that enough for what you need?
– Isaac
11 hours ago












I need (actually "needed") to know if the standard input was the null device.
– Sylvain Leroux
11 hours ago




I need (actually "needed") to know if the standard input was the null device.
– Sylvain Leroux
11 hours ago












But checking for the /dev/null won't work for rm secretunknownname, would it?
– Isaac
11 hours ago




But checking for the /dev/null won't work for rm secretunknownname, would it?
– Isaac
11 hours ago












I am trying to find my way in a (very poorly designed!) industrial system. And it sometimes maps input of worker utility to the null device, or, some other times, to the actual hardware device. In both cases using the same code, but with different major/minor dev numbers. We are trying to track when (and why!) it sometimes chose to use one or the other. For now, the stat solution is the only one working.
– Sylvain Leroux
11 hours ago






I am trying to find my way in a (very poorly designed!) industrial system. And it sometimes maps input of worker utility to the null device, or, some other times, to the actual hardware device. In both cases using the same code, but with different major/minor dev numbers. We are trying to track when (and why!) it sometimes chose to use one or the other. For now, the stat solution is the only one working.
– Sylvain Leroux
11 hours ago












4 Answers
4






active

oldest

votes

















up vote
14
down vote



accepted










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])'; }





share|improve this answer



















  • 13




    Would strongly recommend $( ...) instead of backticks.
    – roaima
    13 hours ago








  • 8




    Not suggesting another command expansion. Simply that you replace the backtick characters with $( and ). stdin_is_dev_null(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)"; }.
    – roaima
    12 hours ago






  • 3




    @roaima, I was just wondering why you're strongly recommend $(...) instead of backticks? I use backticks most of the times and it works fine except in case of nested of backticks where I prefer $(...)?
    – finn
    12 hours ago






  • 3




    @roaima what bug does that fix? my point was that I know & agree that $(...) is much more robust wrt embedded quotings and also can be easily nested, but in this case that's not necessary. So let's not increase the entropy of the universe with unnecessary changes ;-) Better think of some way to eliminate the repetition; something like stat -c %t:%T /dev/stdin /dev/null | uniq -u, but lighter.
    – mosvy
    12 hours ago






  • 8




    FWIW the question was not about shell syntax. For what is concerning my issue, if the answer had only pointed me to the stat command I would have already been quite satisfied. I don't see the point in starting an editing war between ` and $( supporters. Personally, I prefer $(...) and there are some POSIX rationales in favor of that syntax (pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) But I don't see the point in downvoting an otherwise correct answer for something not related with the question.
    – Sylvain Leroux
    11 hours ago




















up vote
14
down vote













On Linux, to determine whether standard input is redirected from /dev/null, you can check whether /proc/self/fd/0 has the same device and inode as /dev/null:



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


You can use /dev/stdin instead of /proc/self/fd/0.



If you want to check whether standard input is redirected from the null device, you need to compare major and minor device numbers, for example using stat (see also mosvy’s answer):



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


or, if you don’t care about this being Linux-specific,



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





share|improve this answer



















  • 1




    -ef, True if FILE1 and FILE2 refer to the same device and inode
    – Rui F Ribeiro
    13 hours ago












  • very cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null' then do that again with </dev/null. +1
    – glenn jackman
    11 hours ago






  • 1




    The /dev/stdin being a symlink to the original file is specific to Linux, so all those solutions are Linux-specific anyway. The stat-based ones require GNU or busybox stat. With recent versions of GNU stat, you can use stat - to do a fstat() on fd 0 which would then work on non-Linux systems.
    – Stéphane Chazelas
    9 hours ago












  • @Stéphane the last part is exactly the situation the OP ran into, which is why I wrote up both solutions, distinguishing between /dev/null and the null device.
    – Stephen Kitt
    9 hours ago










  • Oops, missed that.
    – Stéphane Chazelas
    7 hours ago


















up vote
1
down vote













Portably, to check that stdin is the null device (open on /dev/null or not (like a copy of /dev/null)), with zsh (whose stat builtin predates both GNU and FreeBSD stat by the way (not IRIX' though))):



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


(note that it doesn't say if the file descriptor was open in read-only, write-only or read+write mode).



To check that it's open on the current /dev/null file specifically (not /some/chroot/dev/null for instance), on Linux only (where /dev/stdin is implemented as a symlink to the file open on fd 0 instead of a special device which when open acts like a dup(0) in other systems):



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


On non-Linux, you can try:



if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
echo stdin is open on /dev/null
fi





share|improve this answer




























    up vote
    0
    down vote













    In an EDIT you supplied this code as an example to reproduce the problem:



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


    I'll code that into two functions (insecure, don't use unless you do know what you are doing):



    # f(){ f=secretunknownname; mknod "$f" c "$1" "$2"; exec 6<$f; rm "$f"; }
    # checkstdinnull(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)" && echo yes || echo no; }


    It works for the test cases you presented:



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


    And (apparently) for your edit:



    # f 1 3
    # checkstdinnull <&6
    yes


    But that doesn't actually check for /dev/null, only that the fd of the redirected file was 1:3 (it got deleted).



    Try:



    # f 1 5                        # not /dev/null
    # checkstdinnull <&6
    no


    you seem to need something a bit more robust:



    # checkstdinnull(){ 
    f="$(readlink -f /dev/stdin)";
    if [ "$f" = /dev/null ] || [ "$f" != "${f%(deleted)*}" ];
    then echo yes; else echo no; fi;
    }


    # checkstdinnull
    no
    # checkstdinnull </dev/null
    yes
    # echo -n | checkstdinnull
    no
    # f 1 3
    # checkstdinnull <&6
    yes
    # f 1 5
    # checkstdinnull <&6
    yes


    Note: this may fail positive if the device name contains (deleted) (very unlikely but worth knowing).






    share|improve this answer





















      Your Answer








      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "106"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














       

      draft saved


      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f484228%2fhow-to-check-if-stdin-is-dev-null-from-the-shell%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      14
      down vote



      accepted










      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])'; }





      share|improve this answer



















      • 13




        Would strongly recommend $( ...) instead of backticks.
        – roaima
        13 hours ago








      • 8




        Not suggesting another command expansion. Simply that you replace the backtick characters with $( and ). stdin_is_dev_null(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)"; }.
        – roaima
        12 hours ago






      • 3




        @roaima, I was just wondering why you're strongly recommend $(...) instead of backticks? I use backticks most of the times and it works fine except in case of nested of backticks where I prefer $(...)?
        – finn
        12 hours ago






      • 3




        @roaima what bug does that fix? my point was that I know & agree that $(...) is much more robust wrt embedded quotings and also can be easily nested, but in this case that's not necessary. So let's not increase the entropy of the universe with unnecessary changes ;-) Better think of some way to eliminate the repetition; something like stat -c %t:%T /dev/stdin /dev/null | uniq -u, but lighter.
        – mosvy
        12 hours ago






      • 8




        FWIW the question was not about shell syntax. For what is concerning my issue, if the answer had only pointed me to the stat command I would have already been quite satisfied. I don't see the point in starting an editing war between ` and $( supporters. Personally, I prefer $(...) and there are some POSIX rationales in favor of that syntax (pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) But I don't see the point in downvoting an otherwise correct answer for something not related with the question.
        – Sylvain Leroux
        11 hours ago

















      up vote
      14
      down vote



      accepted










      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])'; }





      share|improve this answer



















      • 13




        Would strongly recommend $( ...) instead of backticks.
        – roaima
        13 hours ago








      • 8




        Not suggesting another command expansion. Simply that you replace the backtick characters with $( and ). stdin_is_dev_null(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)"; }.
        – roaima
        12 hours ago






      • 3




        @roaima, I was just wondering why you're strongly recommend $(...) instead of backticks? I use backticks most of the times and it works fine except in case of nested of backticks where I prefer $(...)?
        – finn
        12 hours ago






      • 3




        @roaima what bug does that fix? my point was that I know & agree that $(...) is much more robust wrt embedded quotings and also can be easily nested, but in this case that's not necessary. So let's not increase the entropy of the universe with unnecessary changes ;-) Better think of some way to eliminate the repetition; something like stat -c %t:%T /dev/stdin /dev/null | uniq -u, but lighter.
        – mosvy
        12 hours ago






      • 8




        FWIW the question was not about shell syntax. For what is concerning my issue, if the answer had only pointed me to the stat command I would have already been quite satisfied. I don't see the point in starting an editing war between ` and $( supporters. Personally, I prefer $(...) and there are some POSIX rationales in favor of that syntax (pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) But I don't see the point in downvoting an otherwise correct answer for something not related with the question.
        – Sylvain Leroux
        11 hours ago















      up vote
      14
      down vote



      accepted







      up vote
      14
      down vote



      accepted






      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])'; }





      share|improve this 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])'; }






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited 3 hours ago

























      answered 13 hours ago









      mosvy

      4,671322




      4,671322








      • 13




        Would strongly recommend $( ...) instead of backticks.
        – roaima
        13 hours ago








      • 8




        Not suggesting another command expansion. Simply that you replace the backtick characters with $( and ). stdin_is_dev_null(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)"; }.
        – roaima
        12 hours ago






      • 3




        @roaima, I was just wondering why you're strongly recommend $(...) instead of backticks? I use backticks most of the times and it works fine except in case of nested of backticks where I prefer $(...)?
        – finn
        12 hours ago






      • 3




        @roaima what bug does that fix? my point was that I know & agree that $(...) is much more robust wrt embedded quotings and also can be easily nested, but in this case that's not necessary. So let's not increase the entropy of the universe with unnecessary changes ;-) Better think of some way to eliminate the repetition; something like stat -c %t:%T /dev/stdin /dev/null | uniq -u, but lighter.
        – mosvy
        12 hours ago






      • 8




        FWIW the question was not about shell syntax. For what is concerning my issue, if the answer had only pointed me to the stat command I would have already been quite satisfied. I don't see the point in starting an editing war between ` and $( supporters. Personally, I prefer $(...) and there are some POSIX rationales in favor of that syntax (pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) But I don't see the point in downvoting an otherwise correct answer for something not related with the question.
        – Sylvain Leroux
        11 hours ago
















      • 13




        Would strongly recommend $( ...) instead of backticks.
        – roaima
        13 hours ago








      • 8




        Not suggesting another command expansion. Simply that you replace the backtick characters with $( and ). stdin_is_dev_null(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)"; }.
        – roaima
        12 hours ago






      • 3




        @roaima, I was just wondering why you're strongly recommend $(...) instead of backticks? I use backticks most of the times and it works fine except in case of nested of backticks where I prefer $(...)?
        – finn
        12 hours ago






      • 3




        @roaima what bug does that fix? my point was that I know & agree that $(...) is much more robust wrt embedded quotings and also can be easily nested, but in this case that's not necessary. So let's not increase the entropy of the universe with unnecessary changes ;-) Better think of some way to eliminate the repetition; something like stat -c %t:%T /dev/stdin /dev/null | uniq -u, but lighter.
        – mosvy
        12 hours ago






      • 8




        FWIW the question was not about shell syntax. For what is concerning my issue, if the answer had only pointed me to the stat command I would have already been quite satisfied. I don't see the point in starting an editing war between ` and $( supporters. Personally, I prefer $(...) and there are some POSIX rationales in favor of that syntax (pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) But I don't see the point in downvoting an otherwise correct answer for something not related with the question.
        – Sylvain Leroux
        11 hours ago










      13




      13




      Would strongly recommend $( ...) instead of backticks.
      – roaima
      13 hours ago






      Would strongly recommend $( ...) instead of backticks.
      – roaima
      13 hours ago






      8




      8




      Not suggesting another command expansion. Simply that you replace the backtick characters with $( and ). stdin_is_dev_null(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)"; }.
      – roaima
      12 hours ago




      Not suggesting another command expansion. Simply that you replace the backtick characters with $( and ). stdin_is_dev_null(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)"; }.
      – roaima
      12 hours ago




      3




      3




      @roaima, I was just wondering why you're strongly recommend $(...) instead of backticks? I use backticks most of the times and it works fine except in case of nested of backticks where I prefer $(...)?
      – finn
      12 hours ago




      @roaima, I was just wondering why you're strongly recommend $(...) instead of backticks? I use backticks most of the times and it works fine except in case of nested of backticks where I prefer $(...)?
      – finn
      12 hours ago




      3




      3




      @roaima what bug does that fix? my point was that I know & agree that $(...) is much more robust wrt embedded quotings and also can be easily nested, but in this case that's not necessary. So let's not increase the entropy of the universe with unnecessary changes ;-) Better think of some way to eliminate the repetition; something like stat -c %t:%T /dev/stdin /dev/null | uniq -u, but lighter.
      – mosvy
      12 hours ago




      @roaima what bug does that fix? my point was that I know & agree that $(...) is much more robust wrt embedded quotings and also can be easily nested, but in this case that's not necessary. So let's not increase the entropy of the universe with unnecessary changes ;-) Better think of some way to eliminate the repetition; something like stat -c %t:%T /dev/stdin /dev/null | uniq -u, but lighter.
      – mosvy
      12 hours ago




      8




      8




      FWIW the question was not about shell syntax. For what is concerning my issue, if the answer had only pointed me to the stat command I would have already been quite satisfied. I don't see the point in starting an editing war between ` and $( supporters. Personally, I prefer $(...) and there are some POSIX rationales in favor of that syntax (pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) But I don't see the point in downvoting an otherwise correct answer for something not related with the question.
      – Sylvain Leroux
      11 hours ago






      FWIW the question was not about shell syntax. For what is concerning my issue, if the answer had only pointed me to the stat command I would have already been quite satisfied. I don't see the point in starting an editing war between ` and $( supporters. Personally, I prefer $(...) and there are some POSIX rationales in favor of that syntax (pubs.opengroup.org/onlinepubs/9699919799/xrat/… ) But I don't see the point in downvoting an otherwise correct answer for something not related with the question.
      – Sylvain Leroux
      11 hours ago














      up vote
      14
      down vote













      On Linux, to determine whether standard input is redirected from /dev/null, you can check whether /proc/self/fd/0 has the same device and inode as /dev/null:



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


      You can use /dev/stdin instead of /proc/self/fd/0.



      If you want to check whether standard input is redirected from the null device, you need to compare major and minor device numbers, for example using stat (see also mosvy’s answer):



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


      or, if you don’t care about this being Linux-specific,



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





      share|improve this answer



















      • 1




        -ef, True if FILE1 and FILE2 refer to the same device and inode
        – Rui F Ribeiro
        13 hours ago












      • very cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null' then do that again with </dev/null. +1
        – glenn jackman
        11 hours ago






      • 1




        The /dev/stdin being a symlink to the original file is specific to Linux, so all those solutions are Linux-specific anyway. The stat-based ones require GNU or busybox stat. With recent versions of GNU stat, you can use stat - to do a fstat() on fd 0 which would then work on non-Linux systems.
        – Stéphane Chazelas
        9 hours ago












      • @Stéphane the last part is exactly the situation the OP ran into, which is why I wrote up both solutions, distinguishing between /dev/null and the null device.
        – Stephen Kitt
        9 hours ago










      • Oops, missed that.
        – Stéphane Chazelas
        7 hours ago















      up vote
      14
      down vote













      On Linux, to determine whether standard input is redirected from /dev/null, you can check whether /proc/self/fd/0 has the same device and inode as /dev/null:



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


      You can use /dev/stdin instead of /proc/self/fd/0.



      If you want to check whether standard input is redirected from the null device, you need to compare major and minor device numbers, for example using stat (see also mosvy’s answer):



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


      or, if you don’t care about this being Linux-specific,



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





      share|improve this answer



















      • 1




        -ef, True if FILE1 and FILE2 refer to the same device and inode
        – Rui F Ribeiro
        13 hours ago












      • very cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null' then do that again with </dev/null. +1
        – glenn jackman
        11 hours ago






      • 1




        The /dev/stdin being a symlink to the original file is specific to Linux, so all those solutions are Linux-specific anyway. The stat-based ones require GNU or busybox stat. With recent versions of GNU stat, you can use stat - to do a fstat() on fd 0 which would then work on non-Linux systems.
        – Stéphane Chazelas
        9 hours ago












      • @Stéphane the last part is exactly the situation the OP ran into, which is why I wrote up both solutions, distinguishing between /dev/null and the null device.
        – Stephen Kitt
        9 hours ago










      • Oops, missed that.
        – Stéphane Chazelas
        7 hours ago













      up vote
      14
      down vote










      up vote
      14
      down vote









      On Linux, to determine whether standard input is redirected from /dev/null, you can check whether /proc/self/fd/0 has the same device and inode as /dev/null:



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


      You can use /dev/stdin instead of /proc/self/fd/0.



      If you want to check whether standard input is redirected from the null device, you need to compare major and minor device numbers, for example using stat (see also mosvy’s answer):



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


      or, if you don’t care about this being Linux-specific,



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





      share|improve this answer














      On Linux, to determine whether standard input is redirected from /dev/null, you can check whether /proc/self/fd/0 has the same device and inode as /dev/null:



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


      You can use /dev/stdin instead of /proc/self/fd/0.



      If you want to check whether standard input is redirected from the null device, you need to compare major and minor device numbers, for example using stat (see also mosvy’s answer):



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


      or, if you don’t care about this being Linux-specific,



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






      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited 6 hours ago

























      answered 13 hours ago









      Stephen Kitt

      158k23345421




      158k23345421








      • 1




        -ef, True if FILE1 and FILE2 refer to the same device and inode
        – Rui F Ribeiro
        13 hours ago












      • very cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null' then do that again with </dev/null. +1
        – glenn jackman
        11 hours ago






      • 1




        The /dev/stdin being a symlink to the original file is specific to Linux, so all those solutions are Linux-specific anyway. The stat-based ones require GNU or busybox stat. With recent versions of GNU stat, you can use stat - to do a fstat() on fd 0 which would then work on non-Linux systems.
        – Stéphane Chazelas
        9 hours ago












      • @Stéphane the last part is exactly the situation the OP ran into, which is why I wrote up both solutions, distinguishing between /dev/null and the null device.
        – Stephen Kitt
        9 hours ago










      • Oops, missed that.
        – Stéphane Chazelas
        7 hours ago














      • 1




        -ef, True if FILE1 and FILE2 refer to the same device and inode
        – Rui F Ribeiro
        13 hours ago












      • very cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null' then do that again with </dev/null. +1
        – glenn jackman
        11 hours ago






      • 1




        The /dev/stdin being a symlink to the original file is specific to Linux, so all those solutions are Linux-specific anyway. The stat-based ones require GNU or busybox stat. With recent versions of GNU stat, you can use stat - to do a fstat() on fd 0 which would then work on non-Linux systems.
        – Stéphane Chazelas
        9 hours ago












      • @Stéphane the last part is exactly the situation the OP ran into, which is why I wrote up both solutions, distinguishing between /dev/null and the null device.
        – Stephen Kitt
        9 hours ago










      • Oops, missed that.
        – Stéphane Chazelas
        7 hours ago








      1




      1




      -ef, True if FILE1 and FILE2 refer to the same device and inode
      – Rui F Ribeiro
      13 hours ago






      -ef, True if FILE1 and FILE2 refer to the same device and inode
      – Rui F Ribeiro
      13 hours ago














      very cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null' then do that again with </dev/null. +1
      – glenn jackman
      11 hours ago




      very cool. bash -c 'ls -l /proc/self/fd/0 /dev/null; [[ /proc/self/fd/0 -ef /dev/null ]] && echo dev null' then do that again with </dev/null. +1
      – glenn jackman
      11 hours ago




      1




      1




      The /dev/stdin being a symlink to the original file is specific to Linux, so all those solutions are Linux-specific anyway. The stat-based ones require GNU or busybox stat. With recent versions of GNU stat, you can use stat - to do a fstat() on fd 0 which would then work on non-Linux systems.
      – Stéphane Chazelas
      9 hours ago






      The /dev/stdin being a symlink to the original file is specific to Linux, so all those solutions are Linux-specific anyway. The stat-based ones require GNU or busybox stat. With recent versions of GNU stat, you can use stat - to do a fstat() on fd 0 which would then work on non-Linux systems.
      – Stéphane Chazelas
      9 hours ago














      @Stéphane the last part is exactly the situation the OP ran into, which is why I wrote up both solutions, distinguishing between /dev/null and the null device.
      – Stephen Kitt
      9 hours ago




      @Stéphane the last part is exactly the situation the OP ran into, which is why I wrote up both solutions, distinguishing between /dev/null and the null device.
      – Stephen Kitt
      9 hours ago












      Oops, missed that.
      – Stéphane Chazelas
      7 hours ago




      Oops, missed that.
      – Stéphane Chazelas
      7 hours ago










      up vote
      1
      down vote













      Portably, to check that stdin is the null device (open on /dev/null or not (like a copy of /dev/null)), with zsh (whose stat builtin predates both GNU and FreeBSD stat by the way (not IRIX' though))):



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


      (note that it doesn't say if the file descriptor was open in read-only, write-only or read+write mode).



      To check that it's open on the current /dev/null file specifically (not /some/chroot/dev/null for instance), on Linux only (where /dev/stdin is implemented as a symlink to the file open on fd 0 instead of a special device which when open acts like a dup(0) in other systems):



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


      On non-Linux, you can try:



      if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
      echo stdin is open on /dev/null
      fi





      share|improve this answer

























        up vote
        1
        down vote













        Portably, to check that stdin is the null device (open on /dev/null or not (like a copy of /dev/null)), with zsh (whose stat builtin predates both GNU and FreeBSD stat by the way (not IRIX' though))):



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


        (note that it doesn't say if the file descriptor was open in read-only, write-only or read+write mode).



        To check that it's open on the current /dev/null file specifically (not /some/chroot/dev/null for instance), on Linux only (where /dev/stdin is implemented as a symlink to the file open on fd 0 instead of a special device which when open acts like a dup(0) in other systems):



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


        On non-Linux, you can try:



        if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
        echo stdin is open on /dev/null
        fi





        share|improve this answer























          up vote
          1
          down vote










          up vote
          1
          down vote









          Portably, to check that stdin is the null device (open on /dev/null or not (like a copy of /dev/null)), with zsh (whose stat builtin predates both GNU and FreeBSD stat by the way (not IRIX' though))):



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


          (note that it doesn't say if the file descriptor was open in read-only, write-only or read+write mode).



          To check that it's open on the current /dev/null file specifically (not /some/chroot/dev/null for instance), on Linux only (where /dev/stdin is implemented as a symlink to the file open on fd 0 instead of a special device which when open acts like a dup(0) in other systems):



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


          On non-Linux, you can try:



          if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
          echo stdin is open on /dev/null
          fi





          share|improve this answer












          Portably, to check that stdin is the null device (open on /dev/null or not (like a copy of /dev/null)), with zsh (whose stat builtin predates both GNU and FreeBSD stat by the way (not IRIX' though))):



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


          (note that it doesn't say if the file descriptor was open in read-only, write-only or read+write mode).



          To check that it's open on the current /dev/null file specifically (not /some/chroot/dev/null for instance), on Linux only (where /dev/stdin is implemented as a symlink to the file open on fd 0 instead of a special device which when open acts like a dup(0) in other systems):



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


          On non-Linux, you can try:



          if sh -c 'lsof -tad0 -p"$$" /dev/null' > /dev/null 2>&-; then
          echo stdin is open on /dev/null
          fi






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 9 hours ago









          Stéphane Chazelas

          294k54555898




          294k54555898






















              up vote
              0
              down vote













              In an EDIT you supplied this code as an example to reproduce the problem:



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


              I'll code that into two functions (insecure, don't use unless you do know what you are doing):



              # f(){ f=secretunknownname; mknod "$f" c "$1" "$2"; exec 6<$f; rm "$f"; }
              # checkstdinnull(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)" && echo yes || echo no; }


              It works for the test cases you presented:



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


              And (apparently) for your edit:



              # f 1 3
              # checkstdinnull <&6
              yes


              But that doesn't actually check for /dev/null, only that the fd of the redirected file was 1:3 (it got deleted).



              Try:



              # f 1 5                        # not /dev/null
              # checkstdinnull <&6
              no


              you seem to need something a bit more robust:



              # checkstdinnull(){ 
              f="$(readlink -f /dev/stdin)";
              if [ "$f" = /dev/null ] || [ "$f" != "${f%(deleted)*}" ];
              then echo yes; else echo no; fi;
              }


              # checkstdinnull
              no
              # checkstdinnull </dev/null
              yes
              # echo -n | checkstdinnull
              no
              # f 1 3
              # checkstdinnull <&6
              yes
              # f 1 5
              # checkstdinnull <&6
              yes


              Note: this may fail positive if the device name contains (deleted) (very unlikely but worth knowing).






              share|improve this answer

























                up vote
                0
                down vote













                In an EDIT you supplied this code as an example to reproduce the problem:



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


                I'll code that into two functions (insecure, don't use unless you do know what you are doing):



                # f(){ f=secretunknownname; mknod "$f" c "$1" "$2"; exec 6<$f; rm "$f"; }
                # checkstdinnull(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)" && echo yes || echo no; }


                It works for the test cases you presented:



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


                And (apparently) for your edit:



                # f 1 3
                # checkstdinnull <&6
                yes


                But that doesn't actually check for /dev/null, only that the fd of the redirected file was 1:3 (it got deleted).



                Try:



                # f 1 5                        # not /dev/null
                # checkstdinnull <&6
                no


                you seem to need something a bit more robust:



                # checkstdinnull(){ 
                f="$(readlink -f /dev/stdin)";
                if [ "$f" = /dev/null ] || [ "$f" != "${f%(deleted)*}" ];
                then echo yes; else echo no; fi;
                }


                # checkstdinnull
                no
                # checkstdinnull </dev/null
                yes
                # echo -n | checkstdinnull
                no
                # f 1 3
                # checkstdinnull <&6
                yes
                # f 1 5
                # checkstdinnull <&6
                yes


                Note: this may fail positive if the device name contains (deleted) (very unlikely but worth knowing).






                share|improve this answer























                  up vote
                  0
                  down vote










                  up vote
                  0
                  down vote









                  In an EDIT you supplied this code as an example to reproduce the problem:



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


                  I'll code that into two functions (insecure, don't use unless you do know what you are doing):



                  # f(){ f=secretunknownname; mknod "$f" c "$1" "$2"; exec 6<$f; rm "$f"; }
                  # checkstdinnull(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)" && echo yes || echo no; }


                  It works for the test cases you presented:



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


                  And (apparently) for your edit:



                  # f 1 3
                  # checkstdinnull <&6
                  yes


                  But that doesn't actually check for /dev/null, only that the fd of the redirected file was 1:3 (it got deleted).



                  Try:



                  # f 1 5                        # not /dev/null
                  # checkstdinnull <&6
                  no


                  you seem to need something a bit more robust:



                  # checkstdinnull(){ 
                  f="$(readlink -f /dev/stdin)";
                  if [ "$f" = /dev/null ] || [ "$f" != "${f%(deleted)*}" ];
                  then echo yes; else echo no; fi;
                  }


                  # checkstdinnull
                  no
                  # checkstdinnull </dev/null
                  yes
                  # echo -n | checkstdinnull
                  no
                  # f 1 3
                  # checkstdinnull <&6
                  yes
                  # f 1 5
                  # checkstdinnull <&6
                  yes


                  Note: this may fail positive if the device name contains (deleted) (very unlikely but worth knowing).






                  share|improve this answer












                  In an EDIT you supplied this code as an example to reproduce the problem:



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


                  I'll code that into two functions (insecure, don't use unless you do know what you are doing):



                  # f(){ f=secretunknownname; mknod "$f" c "$1" "$2"; exec 6<$f; rm "$f"; }
                  # checkstdinnull(){ test "$(stat -Lc %t:%T /dev/stdin)" = "$(stat -Lc %t:%T /dev/null)" && echo yes || echo no; }


                  It works for the test cases you presented:



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


                  And (apparently) for your edit:



                  # f 1 3
                  # checkstdinnull <&6
                  yes


                  But that doesn't actually check for /dev/null, only that the fd of the redirected file was 1:3 (it got deleted).



                  Try:



                  # f 1 5                        # not /dev/null
                  # checkstdinnull <&6
                  no


                  you seem to need something a bit more robust:



                  # checkstdinnull(){ 
                  f="$(readlink -f /dev/stdin)";
                  if [ "$f" = /dev/null ] || [ "$f" != "${f%(deleted)*}" ];
                  then echo yes; else echo no; fi;
                  }


                  # checkstdinnull
                  no
                  # checkstdinnull </dev/null
                  yes
                  # echo -n | checkstdinnull
                  no
                  # f 1 3
                  # checkstdinnull <&6
                  yes
                  # f 1 5
                  # checkstdinnull <&6
                  yes


                  Note: this may fail positive if the device name contains (deleted) (very unlikely but worth knowing).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 9 hours ago









                  Isaac

                  9,70311445




                  9,70311445






























                       

                      draft saved


                      draft discarded



















































                       


                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f484228%2fhow-to-check-if-stdin-is-dev-null-from-the-shell%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      サソリ

                      広島県道265号伴広島線

                      Accessing regular linux commands in Huawei's Dopra Linux