Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In bash, how do I open a writable file descriptor that's externally redirectable?

I'm trying to use bash to open a new descriptor for writing extra diagnostic messages. I don't want to use stderr, because stderr should only contain output from the programs called by bash. I also want my custom descriptor to be redirectable by the user.

I tried this:

exec 3>/dev/tty
echo foo1
echo foo2 >&2
echo foo3 >&3

But when I try to redirect fd 3, the output still writes to the terminal.

$ ./test.sh >/dev/null 2>/dev/null 3>/dev/null
foo3
like image 475
Kelvin Avatar asked May 14 '12 17:05

Kelvin


3 Answers

First the parent shell sets file descriptor 3 to /dev/null
Then your program sets file descriptor 3 to /dev/tty
So your symptoms are not really surprising.

Edit: You could check to see if fd 3 has been set:

if [[ ! -e /proc/$$/fd/3 ]]
then
    exec 3>/dev/tty
fi
like image 95
cdarke Avatar answered Oct 18 '22 23:10

cdarke


Simple enough: If the parent shell is not redirecting fd 3, then test.sh will be redirecting fd 3 to /dev/tty.

if ! { exec 0>&3; } 1>/dev/null 2>&1; then
   exec 3>/dev/tty
fi
echo foo1
echo foo2 >&2
echo foo3 >&3
like image 30
kaluy Avatar answered Oct 18 '22 23:10

kaluy


Here's a way to check if a file descriptor has already been set using the (Bash) shell only.

(
# cf. "How to check if file descriptor exists?", 
# http://www.linuxmisc.com/12-unix-shell/b451b17da3906edb.htm

exec 3<<<hello

# open file descriptors get inherited by child processes, 
# so we can use a subshell to test for existence of fd 3
(exec 0>&3) 1>/dev/null 2>&1 && 
    { echo bash: fd exists; fdexists=true; } || 
    { echo bash: fd does NOT exists; fdexists=false; }

perl -e 'open(TMPOUT, ">&3") or die' 1>/dev/null 2>&1 && 
    echo perl: fd exists || echo perl: fd does NOT exist

${fdexists} && cat <&3
)
like image 31
gregc Avatar answered Oct 19 '22 01:10

gregc