6

I have this simple script which redirects the output and append it to a file.

filename="/home/ronnie/tmp/hello"

date=$(date)
echo "$date" >> $filename

Now, lets suppose I change date=$(date) to date= $(date) which will generate an error.

My modified script:

filename="/home/ronnie/tmp/hello"

date= $(date)
echo "$date" >> $filename 2>> $filename 
#Also tried echo "$date" >> $filename 2>&1

I was thinking that above script will redirect the error test.sh: line 5: Fri: command not found to the file hello but it just enters a new line into the file and the error gets printed on my stdout.

My bash version:

ronnier@ronnie:~/tmp$ bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)

So, where am I going wrong.

2 Answers 2

9

The line which causes the error is date =$(date), that error is sent to stderr. At that stage, you're not redirecting stderr anywhere. The subsequent line sends stderr to $filename, but it's not that line which causes the error.

One of the ways to get the effect you want, you would run your script and direct stderr to somewhere else at the same time, so,

./myscript 2>> errors.txt

at that point, errors.txt will contain your error.

So the issue is, the line generating the error is an error in the script itself, not an error caused by an external command the script calls which has it's output redirected. i.e. it's the top level script output you need to redirect.

1
  • 1
    Another strategy would be to surround several lines in your script with {...} 2>> errors.txt or (...) 2>> errors.txt. The second is less efficient but behaves in ways that are useful in certain circumstances. (Read about "subshells" to learn more.)
    – dubiousjim
    Commented Oct 19, 2012 at 14:20
2

The shell emits an error message when it reaches line 5. The shell's error stream is not redirected at this point.

If you write date= $(date) 2>/dev/null, the “command not found” message comes from the shell, not from the command whose error stream is redirected. Therefore you'll still see the error message.

To avoid seeing the error message, put the whole command inside a group and redirect the error stream from the whole group:

{ date= $(date); } 2>/dev/null

With braces, the command is still executed in the parent shell, so it can change its environment and other state (not that it does here). You can also put the command in a function body, or in a subshell (commands inside parentheses, which are executed in a separate shell process).

You can redirect the file descriptors of the shell permanently (or at least until the next time you change them) by using a redirection on the exec builtin with no command name.

exec 2>/dev/null
# From this point on, all error messages are lost
date= $(date)
…
exec 2>/some/log/file
# From this point on, all error messages go to the specified file
1
  • Thanks for suggesting the alternatives. What is {} called in bash. I am aware of <() and $() process and command substitution respectively but not of {}.
    – ronnie
    Commented Oct 20, 2012 at 6:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .