From Bash Reference Manual:
${parameter:?word}
If parameter
is null or unset, the expansion of word
(or a message to that effect if word
is not present) is written to the standard error and the shell, if it is not interactive, exits. Otherwise, the value of parameter
is substituted.
It may not be obvious but "standard error" here means the standard error of the shell. When you do echo … 2> testfile
you redirect standard error of echo
. They both normally end up in your terminal but are not the same.
To make it work as you want create a subshell and redirect its standard error:
(echo ${var:?"This var is not set"}) 2> testfile
This will also work:
{ echo ${var:?"This var is not set"}; } 2> testfile
Note the actual command (echo
) will inherit the already redirected standard error of the subshell, so effectively this redirection affects them both. It hardly ever matters when the command is echo
but with a command that returns error message it does. Compare:
unset var
(dd ${var:?"This var is not set"}) 2> testfile
cat testfile
var=foo
(dd ${var:?"This var is not set"}) 2> testfile
cat testfile