Ash, Dash or Bash, Zsh handles invalid empty parameters ${var:?}
expansion error in a here-document differently.
Here is the experiment.sh
code using genuine POSIX grammar:
#!/usr/bin/env sh
empty_var=
read -r value << EOF
Expected fail here ${empty_var:?}"
EOF
printf '$?=%d\nvalue=%s\n' $? "$value"
And here is the code to run the experiment with different shells:
for sh in ash bash dash ksh zsh; do
printf 'Testing with: %s\n' "$sh"
LC_ALL=C "$sh" ./experiment.sh || :
echo
done
Obtained results:
Testing with: ash
./experiment.sh: 5: empty_var: parameter not set or null
$?=2
value=
Testing with: bash
./experiment.sh: line 5: empty_var: parameter null or not set
Testing with: dash
./experiment.sh: 5: empty_var: parameter not set or null
$?=2
value=
Testing with: ksh
./experiment.sh[5]: empty_var: parameter null
$?=1
value=
Testing with: zsh
./experiment.sh:5: empty_var: parameter not set
Bash and Zsh stops execution immediately while other shells continue the execution, just raising the return code $?
.
What explanations are there, for this behavior difference with this genuine POSIX grammar construct?
Is it documented why Bash or Zsh choose to exit the script rather than return a failure code like Ksh, Dash or Ash?
Note that within other contexts like expansion in a string, all shells exit out of the script.
The behavior discrepancy occurs only in here-documents as far as I know.
$sh -i ./experiment.sh
, and you'll see the behaviors of most shells other than zsh line up. To get zsh to exhibit the same non-exit behavior as others, use$sh -is < ./experiment.sh
. dash, bash, zsh, oksh, ksh93, and BusyBox ash all continue execution when using you use-is
and input redirection. Even if you dislike having to handle the issue where shells continue executing the script, it means those shells are consistent, which is easy enough to handle. Of course, you could simply not use the${parameter:?[word]}
form. – Weepy