Why doesn't '>' redirect error messages from gcc?

I stored the following program in new.c

int main() 
{ 
    a;
    return 0; 
}

It returns an error message. I want to send this message to a file. So I used the following command

gcc new.c > temp.txt

But still I was getting the output on the terminal. I am using Ubuntu 13.04. How can I make it work?


Solution 1:

When you compile a program with gcc, there are different kinds of output: to stdout and stderr. Normally, the > will direct stdout stream to a file (for example, the result of a printf("hello world\n"); is sent to stdout). However, the stderrcontinues to be sent to the screen, since it's assumed to be "something exceptional that you need to be told about".

There is a way to redirect stderr to a file - you do this with the following (not very intuitive) command:

gcc new.c &> myFile

where &> is "bash shorthand" for "redirect everything". As was pointed out by @CharlesDuffy, the POSIX compliant form is

gcc new.c > myFile 2>&1

This means "compile 'new.c' and send stdout to myFile. And send stderr (2) to the same place as stdout (&1 = "the same place as stdout").

You will find more details on different redirects at http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html and http://mywiki.wooledge.org/BashFAQ/055

By the way, if you want to send something from within your program specifically to stderr, you can do so with the following

fprintf(stderr, "hello world - this is urgent.\n");

If you include that in a program, run the program and send the "normal" output to a file, this will still appear on the console. So if you compile the above into the executable urgent, then type

./urgent > /dev/null

at the console, your output will appear on screen.

Solution 2:

Because > redirects only stdout, and errors are written to stderr, you need to use one of the following instead:

gcc new.c &> temp.txt ## redirect both stdout and stderr using bash or zsh only

...or...

gcc new.c >temp.txt 2>&1 ## redirect both stdout and stderr in any POSIX shell

&> is a BASH extension which redirects both stdout and stderr to a file; otherwise, the easiest approach is to first redirect stdout (>temp.txt), and then make stderr (FD 2) a copy of the already-redirected file handle on stdout (FD 1), like so: 2>&1.

Solution 3:

As the others have said, linux provides two different output streams:

stdout, or "standard output" is where all regular output goes.
              You can reference it using file descriptor 1.

stderr, or "standard error" is a separate stream for out-of-band information.
              You can reference it using file descriptor 2.

Why two different output streams? Consider a pipeline of imaginary commands:

 decrypt $MY_FILE | grep "secret" | sort > secrets.txt

Now imagine the decrypt command fails and generates an error message. If it sent that message to stdout, it would send into the pipe, and unless it had the word "secret" you'd never see it. So you'd end up with an empty output file, with no idea what went wrong.

However, since the pipe only captures stdout, the decrypt command can send its errors to stderr, where they'll be displayed on the console.

You can redirect stdout and stderr, either together or independently:

# Send errors to "errors.txt" and output to "secrets.txt"
# The following two lines are equivalent, as ">" means "1>"
decrypt $MY_FILE 2> errors.txt > secrets.txt
decrypt $MY_FILE 2> errors.txt 1> secrets.txt

You can redirect the errors to stdout and process them as if they were normal output:

# The operation "2>&1" means "redirect file descriptor 2 to file
# descriptor 1. So this sends all output from stderr to stdout.
# Note that the order of redirection is important.
decrypt $MY_FILE > errors.txt 2>&1 

# This may be confusing.  It will store the normal output in a file
# and send error messages to stdout, where they'll be captured by 
# the pipe and then sorted.
decrypt $MY_FILE 2>&1 > output.txt | sort

You can also use a "shorthand" notation to redirect both stdout and stderr to the same file:

decrypt $MY_FILE &> output.txt

And, finally, the > operator will first truncate its output file before writing to it. If, instead, you want to append data to an existing file, use the >> operator:

decrypt $MY_FILE 2>> more_errors.txt >> more_secrets.txt
decrypt $MY_FILE >> more_output.txt 2>&1