Let us say I redirect the STDOUT
, STDERR
of a program to files.
./script.sh 1> output.log 2> error.log
Can the running program find this out i.e. know the paths to these files?
Let us say I redirect the STDOUT
, STDERR
of a program to files.
./script.sh 1> output.log 2> error.log
Can the running program find this out i.e. know the paths to these files?
{ readlink /dev/fd/[1,2] ; echo "out" ; } >./file 2>./error
{ readlink /dev/fd/0 ; cat ; } <./file
OUTPUT:
/home/mikeserv/file
/home/mikeserv/file
/home/mikeserv/error
out
{ readlink /proc/$$/fd/[1,2] ; echo out ; } >./file 2>./error
{ readlink /proc/$$/fd/0 ; cat ; } <./file
OUTPUT:
/home/mikeserv/file
/home/mikeserv/file
/home/mikeserv/error
out
You can call lsof
to list the open files of the shell process. Use -a -p $$
to limit the output to the shell process ($$
), -d 1
to limit the output to file descriptor 1 (for instance), and -F n
to print the output in parseable form. Here's a shell snippet that copes with arbitrary characters in file names:
output_file=$(lsof -a -p $$ -d 1 -F pn; echo .)
output_file=${output_file%.}
output_file=${output_file#n}
If the file name doesn't contain a newline, you'll be able to get away with output_file=$(lsof -a -p $$ -d 1 -F pn | sed -n '2s/.//p')
.
Note that the file name may not always exist, in particular if the file has been deleted.
Under Linux, another way to access the file names is through /proc/$$/fd
: /proc/$$/fd/1
is a slightly magic symbolic link to the file opened by the shell on file descriptor 1 (the link works even if the file name returned by readlink
doesn't exist, for example in the case of a deleted file).
It is usually a very bad idea to make any use of the information obtained this way. If someone calls your script with the output redirected to a file, they won't like it if you behave differently because of the location of the file, or affect the file in ways other than appending to it. There is one exception: you may want to react differently depending on whether you're writing to a terminal or to something else (pipe, socket, file), for example to display colors or progress indicators on a terminal. There is a specific test to determine whether a file descriptor is connected to a terminal:
if [ -t 2 ]; then
# stderr is a terminal
printf 1>&2 '\e[31mError: widget not found\e[0m'
else
# stderr is not a terminal
echo 1>&2 'Error: widget not found'
fi
lsof,
of course. Though not the last bit, obviously.
– mikeserv
Apr 07 '14 at 21:10
lsof
is awesome - its just not always there. Neither is readlink
for that matter - though I think the chances are a little better. - I agree. I was writing that addendum before even I knew you had replied. Speaking of readlink - my preference is for realpath,
actually.
– mikeserv
Apr 07 '14 at 21:15
/proc/<pid>/fd
is there, then there's a very good chance that you're running Linux (but it could also be Solaris or some other SysV unices) and therefore readlink
is available (it's in GNU coreutils and BusyBox). realpath
is less common: under Linux, it's a deprecated program from the time before readlink
, which may still be installed if some legacy application depends on it.
– Gilles 'SO- stop being evil'
Apr 07 '14 at 21:23
realpath
is deprecated? I thought i remembered reading it it was just added to GNU in 2012. Maybe I've got it backwards.
– mikeserv
Apr 07 '14 at 21:25
In your case, STDOUT
will be saved to file output.log
and STDERR
will be saved to file error.log
. Both files are saved in the same directory with script.sh
.
If you want your program "know the path to these files", you must use absolute path:
./script.sh > /path/to/output.log 2> /path/to/error.log
The output.log
and error.log
files are created in the current directory i.e. the $PWD
variable value.
If you want your program to use these files later, just save their directory in a variable before running your script. Here is an example :
OUTDIR=$PWD
./script.sh 1> output.log 2> error.log
# Whatever you want to do else ...
echo The output file : =======
cat $OUTDIR/output.log
echo =========================
echo
echo The errors file : =======
cat $OUTDIR/error.log
echo =========================
/proc
is missing for BSDs or are the/dev/fd/N
links also unavailable? – mikeserv Apr 07 '14 at 17:14/dev/fd/N
exist, but don't provide any information as to what's behind the file (they aren't symlinks). – Gilles 'SO- stop being evil' Apr 07 '14 at 17:22