As for a solution to redirect lots of command at once:
#!/bin/bash
{
somecommand
somecommand2
somecommand3
} 2>&1 | tee -a $DEBUGLOG
Why your original solution does not work: exec 2>&1 will redirect the standard error output to the standard output of your shell, which, if you run your script from the console, will be your console. the pipe redirection on commands will only redirect the standart output of the command.
On the point of view of somecommand
, its standard output goes into a pipe connected to tee
and the standard error goes into the same file/pseudofile as the standard error of the shell, which you redirect to the standard output of the shell, which will be the console if you run your program from the console.
The one true way to explain it is to see what really happens:
Your shell's original environment might look like this if you run it from the terminal:
stdin -> /dev/pts/42
stdout -> /dev/pts/42
stderr -> /dev/pts/42
After you redirect standard error into standard output (exec 2>&1
), you ... basically change nothing. But if you redirect the script's standart output to a file, you would end up with an environment like this:
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /dev/pts/42
Then redirecting the shell standard error into standard output would end up like this :
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /your/file
Running a command will inherit this environment. If you run a command and pipe it to tee, the command's environment would be :
stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file
So your command's standard error still goes into what the shell uses as its standard error.
You can actually see the environment of a command by looking in /proc/[pid]/fd
: use ls -l
to also list the symbolic link's content. The 0
file here is standard input, 1
is standard output and 2
is standard error. If the command opens more files (and most programs do), you will also see them. A program can also choose to redirect or close its standard input/output and reuse 0
, 1
and 2
.
After you run exec &>filename
, the standard output and standard error of the shell go to filename
. Standard input is file descriptor 0 by definition, and standard output is fd 1 and standard error is fd 2.
A file descriptor isn't either redirected or non-redirected: it always go somewhere (assuming that the process has this descriptor open). To redirect a file descriptor means to change where it goes. When you ran exec &>filename
, stdout and stderr were formerly connected to the terminal, and became connected to filename
.
There is always a way to refer to the current terminal: /dev/tty
. When a process opens this file, it always means the process's controlling terminal, whichever it is. So if you want to get back that shell's original stdout and stderr, you can do it because the file they were connected to is still around.
exec &>/dev/tty
Best Answer
I think it is possible if you attach the process of the related interpreter to gdb. I tried it with this perl one-liner
and it works but unfortunately not with a similar bash script.
First of all you have to figure out the PID of that process whose output you want to capture. Then start
gdb
in another terminal and execute the following gdb-commandsafter that the whole data that is written to
stderr
is redirected to/abs/olu/te/path/filename
, sinceattach PID
attaches the process to gdb and stops itcall close(2)
closes thestderr
filedescriptor of the process (forstdout
the filedescriptor is 1)call open(...)
opens a new file and takes the lowest unused integer for the newly created filedescriptor anddetach PID
continues the processAt least on my machine. The first two lines are POSIX compatible but not the third one.
The second and the third argument of
open
in the third line are documented inman 2 open
. In my case 65 means thatopen
should create the file and open the file write-only i.e.O_WRONLY | O_CREAT
(defined infcntl.h
). The third argument tells open to create the file with read and write permission for the user i.e.S_IWUSR | S_IRUSR
(defined insys/stat.h
). So maybe you have to find out appropriate values on your machine by yourself.