'Duplicate IO with file descriptors
I would like to route a file descriptor to multiple places at the same time. For instance I would like every command in my script to print stdout to /dev/ps/9 and ./myscript.stdout at the same time.
I'm looking to achieve similar results as piping every command in a script (or a section of a script) into tee
, perhaps with file descriptors. I also want the ability to restore default output behavior later in the script.
This code doesn't work, but it's an attempt at expressing my intent. To restore stdout as FD 1 later, I copy it into FD 4.
exec 3>(tee /dev/ps/9 ./myscript.stdout)
exec 4>&1
exec 1>&3
Restore normal output behavior, deleting FDs 3 and 4.
exec 1>&4
exec 4>&-
exec 3>&-
Solution 1:[1]
I would like every command in my script to print stdout to /dev/ps/9 and ./myscript.stdout at the same time.
exec 1> >(tee ./myscript.stdout >/dev/ps/9)
The above combines redirection and process substitution. With redirection alone, one can send stdout to a file. For example:
exec 1> filename
However, with bash, filenames can often be replaced with commands. This is called process substitution and it looks like >(some command)
or <(some command)
depending on whether one wants to write-to or read-from the process. In our case, we want to write to a tee
command. Thus:
exec 1> >(some command)
Or, more specifically:
exec 1> >(tee ./myscript.stdout >/dev/ps/9)
Note that we have to maintain the space between the redirect (1>
) and the process substitution (>(tee ./myscript.stdout >/dev/ps/9)
. Without the space, it would look like we were trying to append to a file whose name starts with a parens and this would generate a bash
error.
For more information on this see the sections entitled "REDIRECTION" and "Process Substitution" in man bash
.
Solution 2:[2]
#!/bin/bash
random=$$ # generate a random seed number to name the log files with
out=out.$random
err=err.$random
dev=`echo $(who -m) | cut -d' ' -f2` # for finding the right pseudo-terminal
: >$out # create the log files or empty their contents
: >$err # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
exec 1> >(tee ./$out >/dev/$dev) # I don't know how this works but it does
exec 2> >(tee ./$err >/dev/$dev) # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
echo # writing directly to the pts in /dev doesn't look right until sending a blank line
##########################################
echo 'hello'
for i in `seq 0 1 10`; do
echo $i
done
bad_command
THANKS @John1024
Here's a script for anybody else wishing to test this out.
Could somebody please explain in detail the exec lines to me.
For instance, why is there a blank space after the arrow in:
exec 1>
?
Solution 3:[3]
#!/bin/bash
logfile=$$.log
exec > $logfile 2>&1 | tee
echo "test"
The $$
does a random seed number which is optional.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | PhysicalChemist |