Search code examples
shellhttp-redirectgccstdoutstderr

Shell redirect: scons calls gcc, build error redirection doesn't work


I was using scons(python build tool) which calls gcc to build a file, like this:

$scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o 1.o -c 1.cpp
1.cpp:20:5: error: no matching function for call to 'g'
    g(&obj2);
    ^
1.cpp:12:6: note: candidate function not viable: no known conversion from 'B *' to 'A &' for 1st argument; remove &
void g(A&a){
     ^
1 error generated.
scons: *** [1.o] Error 1
scons: building terminated because of errors.

Then I try to save all output to a file. I suppose the error messages are in stderr, so I try to redirect fd=2 to fd=1 like this:

$scons 2>&1 >error1
1.cpp:20:5: error: no matching function for call to 'g'
    g(&obj2);
    ^
1.cpp:12:6: note: candidate function not viable: no known conversion from 'B *' to 'A &' for 1st argument; remove &
void g(A&a){
     ^
1 error generated.
scons: *** [1.o] Error 1

But seems error1 only contains information of "scons" command itself. All gcc error messages are still on screen, not saved in "error1"

$cat error1
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o 1.o -c 1.cpp
scons: building terminated because of errors.

So how to make all scons called progrems re-direct their fd=2 to fd=1? Or this is a limitation of shell redirection that only the top caller's stream could be redirected?


Solution

  • Redirections are executed left-to-right, referring to the state of their destination as of the time when the immediately prior one completed execution.

    • 2>&1 >error1 is executed with the following order of operations:

      1. FD 2 is pointed to whichever destination FD 1 was directed to when the operation started (since you're reporting that content is written to the screen, this is presumably your terminal).

      2. FD 1 is pointed to the file error1.

    • >error1 2>&1 is executed with the following order of operations:

      1. FD 1 is pointed to the file error1

      2. FD 2 is pointed to the location FD 1 presently points to (thus, also the file error1).


    Thus, in the 2>&1 >error1 case, only FD 1 (stdout) -- and not FD 2 (stderr) -- is pointing to error1, since when 2>&1 is invoked, FD 1 is directed at the terminal.