Bash – Why is it possible to refer to a closed stderr under bash

bashfile-descriptorsio-redirectionshellstderr

I'd like to know why bash doesn't display an error message when we refer to a closed stderr. When it comes to other file descriptors, they have to be opened if we want to, for example, duplicate them. Stderr seems to be kinda special in this case:

$ cat file_1
echo Test1 1>&5
$ cat file_2
echo Test2 1>&2

$ ./file_1 5>&-
./file_1: line 1: 5: Bad file descriptor
$ ./file_1 5>&1
Test1
$ ./file_2 2>&-
$ #NO ERROR and no output!
$ ./file_2
Test2

Why does the shell allow it?

Best Answer

Where would the error be sent when running file_2?

When you type ./file_2 (with said file executable), the system actually runs /bin/sh ./file_2 -- i.e. it's running a new copy of /bin/sh, which is responsible for running the commands in ./file2, and for reporting the errors it finds there, outputting them to stderr.

But you've just run that /bin/sh with stderr closed. So it wants to emit an error, but has nowhere to do so.

Which you can verify with:

$ strace -e write,dup2 -fo /dev/stdout sh -c 'echo foo >&2' 2>&-
8785  dup2(2, 1)                        = -1 EBADF (Bad file descriptor)
8785  write(2, "sh: 1: ", 7)            = -1 EBADF (Bad file descriptor)
8785  write(2, "2: Bad file descriptor", 22) = -1 EBADF (Bad file descriptor)

The dup2 fails because fd 2 is closed, sh tries to report the error on stderr, but that fails as well as stderr (fd 2) is closed.