I have a bash script "backup.sh", which prints out everything to stdout, including all the files that are transferred during backup.

I'd like to make it possible to keep that full output, but when it's called with

./backup.sh 2>stderr.log

, then only a few important lines from stdout should be copied into stderr.log.

My script currently uses the following function to print out these important lines:

errEcho() {
    echo "$1"
    echo "$1" 1>&2

echo "Some info message"
errEcho "Very important message"

But now, if somebody calls the script simply as


Then the errEcho lines appear duplicated on stdout.

What's the best way to solve this? (Effectively, I'd like my script to recognize, if stdout == stderr, and then skip output to stderr, but I'm not sure, if I need a very different approach maybe).

Please note: I don't want to have two scripts, where one of them calls "backup.sh 2>stderr.log".

  • 1
    This is abusing stderr. The reason it exists is to report errors. You should use another file descriptor as an alternate output stream. – Keith Jul 10 '11 at 12:14
  • @Keith: That's basically what I mean with my important messages: They're mostly error (or warning) messages. Overall, what I want to achieve is, that when the backup script is run by cron/anacron, the important messages should appear in syslog (but they should not, when the script is run manually). – Chris Lercher Jul 10 '11 at 12:49
  • @Keith: ... However, I'm not so sure how to do this anyway, I was just looking at some scripts in /etc/cron.daily, and at least some of them send their messages to stderr. Probably you're right: It's better to use a separate descriptor. But how would I best incorporate this into my script (i.e. if it's missing, ignore it, ...) – Chris Lercher Jul 10 '11 at 12:58
  • @Keith: I think, for the special case of this backup script, you pointed me in the right direction: I'm now simply using errEcho() { echo "$@" >> /var/log/backup.log ... } to append to a separate log file. – Chris Lercher Jul 10 '11 at 13:41

You are clearly over-engineering here.

Print information lines only to stdout and error messages only to stderr. Your problem solved.

When you run the script from console and want to hide information messages, use >/dev/null redirection: this way you'll only see the error lines.

  • I need to see the error messages in ordered context on the console - always, no matter how the user calls the script (except if they use >/dev/null of course). Some consoles we're using (especially Java based consoles) process stdout and stderr in parallel (using buffering), so their outputs are interweaved (it's possible, that stderr starts printing in the middle of a line while stdout is writing). With these consoles, you can effectively only receive one stream at a time. This is why the stream must contain all the messages. – Chris Lercher Jul 10 '11 at 13:27
  • 1
    Why not make error message contain the reference to file which caused it? Like: /path/to/problematic/file: Permission denied – alex Jul 10 '11 at 15:08
  • Let's not make this personal. Don't you see how my answer and comment about putting context into the error stream solve your problem? – alex Jul 11 '11 at 7:13
  • It's certainly helpful in some situations, but it isn't the full solution. The output of one of the streams should give full context (meaning: it shows all the preparation steps for the backup, like mounting file systems, then showing all the files that have been processed, and then - in context - the error ), while the other stream should only contain the error message (with a little bit of context information like in your example). In the special case of my backup script, I now chose another solution (see my comments above) - but I'd still like to have a general solution. – Chris Lercher Jul 11 '11 at 10:34
  • When a user wants both streams, he/she can just run backup.sh >output.log 2>&1 That's what he/she would do with any other program and get the expected output log. So just use echo for information and echo 1>&2 for errors. – alex Jul 11 '11 at 16:32
errEcho () {
  echo 1>&2 "$@"

Call your script with backup.sh 2>&1 or just backup.sh if you want to see all messages and with basckup.sh >/dev/null if you only want error messages.

  • Thanks (also for reminding me to use "$@") - the problem which remains is: I'd like to have a way to call the script, so that it prints everything to the console, and only stderr to "stderr.log". Is that possible? – Chris Lercher Jul 10 '11 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.