Return and exit behave the same way inside a try block at the top-level but not inside a try block nested in a subshell itself nested in a function. Is that expected or a bug?
Test script:
if [[ -v ZSH_EXEPATH ]]; then alias zsh=$ZSH_EXEPATH; fi;
zsh --version;
zsh <<EOF
{
exit;
} always {
echo "Global exit";
}
EOF
zsh <<EOF
{
return;
} always {
echo "Global return";
}
EOF
zsh <<EOF
({
exit;
} always {
echo "Global subshell exit";
})
EOF
zsh <<EOF
({
return;
} always {
echo "Global subshell return";
})
EOF
zsh <<EOF
() {
{
exit;
} always {
echo "Function exit";
}
}
EOF
zsh <<EOF
() {
{
return;
} always {
echo "Function return";
}
}
EOF
zsh <<EOF
() {
({
exit;
} always {
echo "Function subshell exit";
})
}
EOF
zsh <<EOF
() {
({
return;
} always {
echo "Function subshell return";
})
}
EOF
Output:
zsh 5.9.0.2-test (x86_64-apple-darwin24.4.0)
Function exit
Function return
Function subshell return
Section 6.3 of the manual contains the following 3 sentences:
When a try block occurs outside of any function, a return or a exit encountered in try-list does not cause the execution of always-list. Instead, the shell exits immediately after any EXIT trap has been executed. Otherwise, a return command encountered in try-list will cause the execution of always-list, just like break and continue.
The first sentence explains why the first 4 examples don't trigger the try-block and why the next two do trigger it. It's less clear to me why the last two don't behave the same. It is my impression that for most aspects return statements directly in a subshell behave like exit statements but not here. Is this difference implied by the third sentence from the manual? If not, should return statements not trigger the try-block or should exit statements trigger it?
I find the manual a little confusing because the first sentence mentions an exceptional behavior of return and exit statements. Then the last sentence states that otherwise return statements work as expected but so do exit statements, except if they are directly within a subshell. There is actually no explanation of why such exit statements don't trigger the always block.
Note that if functions are replaced with external source files, the result is the same (i.e., a "source <script-path>" is equivalent to a function call, in these examples).
Philippe