What method should I use to write error messages to 'stderr' using 'printf' in a bash script?
bash, bash4, io-redirection, stderr
Solution
First, yes, `1>&2` is the right thing to do.
Second, the reason your `1>&2 2>errors.txt` example doesn't work is because of the details of exactly what redirection does.
`1>&2` means "make filehandle 1 point to wherever filehandle 2 does currently" — i.e. stuff that would have been written to stdout now goes to stderr. `2>errors.txt` means "open a filehandle to `errors.txt` and make filehandle 2 point to it" — i.e. stuff that would have been written to stderr now goes into `errors.txt`. But filehandle 1 isn't affected at all, so stuff written to stdout still goes to stderr.
The correct thing to do is `2>errors.txt 1>&2`, which will make writes to both stderr and stdout go to `errors.txt`, because the first operation will be "open `errors.txt` and make stderr point to it", and the second operation will be "make stdout point to where stderr is pointing now".
Problem
I want to direct the output of a `printf` in a `bash` script to `stderr` instead of `stdout`. I am not asking about redirecting either `stderr` or `stdout` from where ever they are currently routed. I just want to be able to send the output from a `printf` to `stderr` instead of to the default of `stdout`. I experimented a little and found that appending `1>&2` to the `printf`, as shown in the example below, appears to do what I want. However, I have no experience using bash. So my primary question is if there is a "better" way to do this in `bash`? By "better" I mean is there another way to do this which is more commonly used, more conventional, or more idiomatic? How would a more experienced bash programmer do it? ``` #!/bin/bash printf "{%s} This should go to stderr.\n" "$(date)" 1>&2 printf "[(%s)] This should go to stdout.\n" "$(date)" ``` I also have a secondary question. I am asking it not so much because I need to know, but more because I am just curious and would like to have a better understanding about what is happening. It seems the above will only work when it runs inside a shell script. It does not appear to work when I try it from a command line. Here is an example of what I mean. ``` irrational@VBx64:~$ printf "{%s} Sent to stderr.\n" "$(date)" 1>&2 2> errors.txt {Sat Jun 9 14:08:46 EDT 2012} Sent to stderr. irrational@VBx64:~$ ls -l errors.txt -rw-rw-r-- 1 irrational irrational 0 Jun 9 14:39 errors.txt ``` I would expect the `printf` command above to have no output because the output should go to `stderr`, which in turn should go to a file. But this does not happen. Huh?