Bash – How to debug why stderr is being suppressed

bashio-redirectionstderrzsh

Running some shell functions and ctrl-c-ing them leads to my stderr being suppressed, such that echo hi >&2 and echo hi > /dev/stderr print nothing. I want to debug this, but I have no idea how to start. How can I check where stderr is redirected to? Doing a exec zsh doesn't solve this problem in an affected shell, which indicates the problem is indeed with a rogue redirection.

I'm on macOS.

I tried:

ll /dev/fd
crw--w---- 0,11 evar 12 May 18:32 0
crw--w---- 0,11 evar 12 May 18:32 1
crw-rw-rw-  0,2 root 12 May 18:32 2

Perhaps the issue is that /dev/fd/2 is somehow owned by root?

Update:

lsof -p $$
COMMAND   PID USER   FD   TYPE DEVICE  SIZE/OFF                NODE NAME
zsh     69568 evar  cwd    DIR    1,6      1472          8624004142 /Users/evar/Base/Lectures
zsh     69568 evar  txt    REG    1,6    618652          8678375637 /usr/local/Cellar/zsh/5.8/bin/zsh
zsh     69568 evar  txt    REG    1,6    452676          8677805768 /usr/local/Cellar/pcre/8.44/lib/libpcre.1.dylib
zsh     69568 evar  txt    REG    1,6    312924          8678370072 /usr/local/Cellar/ncurses/6.2/lib/libncursesw.6.dylib
zsh     69568 evar  txt    REG    1,6    251160          8678375669 /usr/local/Cellar/zsh/5.8/lib/zsh/zle.bundle
zsh     69568 evar  txt    REG    1,6    123012          8678375645 /usr/local/Cellar/zsh/5.8/lib/zsh/complete.bundle
zsh     69568 evar  txt    REG    1,6     65188          8678375676 /usr/local/Cellar/zsh/5.8/lib/zsh/compctl.bundle
zsh     69568 evar  txt    REG    1,6     18220          8678375661 /usr/local/Cellar/zsh/5.8/lib/zsh/terminfo.bundle
zsh     69568 evar  txt    REG    1,6     27888          8678375680 /usr/local/Cellar/zsh/5.8/lib/zsh/system.bundle
zsh     69568 evar  txt    REG    1,6     17240          8678375681 /usr/local/Cellar/zsh/5.8/lib/zsh/langinfo.bundle
zsh     69568 evar  txt    REG    1,6     38064          8678375656 /usr/local/Cellar/zsh/5.8/lib/zsh/parameter.bundle
zsh     69568 evar  txt    REG    1,6     22864          8678375674 /usr/local/Cellar/zsh/5.8/lib/zsh/pcre.bundle
zsh     69568 evar  txt    REG    1,6     37588          8678375667 /usr/local/Cellar/zsh/5.8/lib/zsh/zutil.bundle
zsh     69568 evar  txt    REG    1,6     62316          8678375647 /usr/local/Cellar/zsh/5.8/lib/zsh/complist.bundle
zsh     69568 evar  txt    REG    1,6     22620          8678375675 /usr/local/Cellar/zsh/5.8/lib/zsh/stat.bundle
zsh     69568 evar  txt    REG    1,6     29076          8678375649 /usr/local/Cellar/zsh/5.8/lib/zsh/zpty.bundle
zsh     69568 evar  txt    REG    1,6     18736          8678375668 /usr/local/Cellar/zsh/5.8/lib/zsh/datetime.bundle
zsh     69568 evar  txt    REG    1,6     17628          8678375660 /usr/local/Cellar/zsh/5.8/lib/zsh/zleparameter.bundle
zsh     69568 evar  txt    REG    1,6     18208          8678375654 /usr/local/Cellar/zsh/5.8/lib/zsh/termcap.bundle
zsh     69568 evar  txt    REG    1,6     63728          8678375662 /usr/local/Cellar/zsh/5.8/lib/zsh/computil.bundle
zsh     69568 evar  txt    REG    1,6     22440          8678375673 /usr/local/Cellar/zsh/5.8/lib/zsh/sched.bundle
zsh     69568 evar  txt    REG    1,6   1534352 1152921500311885154 /usr/lib/dyld
zsh     69568 evar    0u   CHR  16,11   0t56261                3469 /dev/ttys011
zsh     69568 evar    1u   CHR  16,11   0t56261                3469 /dev/ttys011
zsh     69568 evar    2w   CHR    3,2 0t1314232                 314 /dev/null
zsh     69568 evar   10u   CHR  16,11   0t21049                3469 /dev/ttys011
zsh     69568 evar   11u   CHR   15,9    0t9086                 583 /dev/ptmx

Best Answer

The usual way of obtaining the information is the normal BSD command

fstat -p $$
but your listing of /dev/fd already has enough to tell you that file descriptor 2 is not connected to the terminal character device that file descriptors 0 and 1 are. The major and minor numbers of files under /dev/fd are somewhat complex to grasp, but they do tell you, in conjunction with the permissions and owners, that there is a difference here.

Sans explicit redirection, processes running in a terminal login session will have all three descriptors referencing the same (terminal) character device. File descriptors 0 and 1 are clearly still referencing your terminal character device, owned by you and only readable and writable by you, as is common for terminal devices in login sessions.

Standard error has not been "suppressed". Writes to it are still happening, and are being sent to a character device of some kind, which you do not own but to which you have write access. Almost certainly that character device that file descriptor 2 references is /dev/null, and you've sourced a script that redirected standard error to /dev/null with something like

exec 2>/dev/null

So, after checking to see what fstat tells you just to expand your knowledge, redirect it back again.

exec 2>&1

Related Question