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
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 =========================