Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this bash construct works? (parameter-substitution)

Tags:

bash

Code: ${non_existent_variable:+whatever} && echo "it works"

Result is it works. But why? part before && evaluates to empty string. Trying to run however: && echo test gives an error.

I've got this by accident trying to create ternary operator replacement for bash with different results for set and unset variable. It works this way, but I'm lost why it works at all.

PARAM=$(${tested_variable:+false} && echo var_exists || echo var_empty)

like image 670
yatsek Avatar asked Jan 05 '23 12:01

yatsek


2 Answers

According to the section 2.9.1 of the POSIX spec:

A "simple command" is a sequence of optional variable assignments and redirections, in any sequence, optionally followed by words and redirections, terminated by a control operator.

The very last sentence of section 2.9.1 is the relavant one:

If there is a command name, execution shall continue as described in Command Search and Execution . If there is no command name, but the command contained a command substitution, the command shall complete with the exit status of the last command substitution performed. Otherwise, the command shall complete with a zero exit status.

So if after all expansion, redirections, etc, no command name is found, it is treated as completing successfully with an exit status of 0.

However, the grammar does not allow a null string prior to the && operator. The following is a syntax error:

&& echo it works

The only way to get a completely empty simple command is to have a non-empty string "evaporate" during expansion. One way of accomplishing that is with the unquoted parameter expansion that produces the empty string, which is exactly what ${non_existent_variable:+whatever} does.

like image 99
chepner Avatar answered Jan 14 '23 15:01

chepner


The resulting string is not important, what the && construct is testing is the exit code of the statement before it (i.e. $?) and not what's echoed on screen. Because there wasn't an error in the parameter expansion (indeed, I'm not sure there could be an error) the statement continues.

In comments you asked why $(echo "") && echo test echoes a value, and it's the same reason. The echo statement exits 0 (i.e. true) so the subshell exits 0 as well, and the statement continues running.

like image 35
miken32 Avatar answered Jan 14 '23 13:01

miken32