3

In a bash shell I tried the following 2 commands producing different effects:

$ a=`echo UPDATED` echo ${a:-DEFAULT}
DEFAULT

$ a=`echo UPDATED`; echo ${a:-DEFAULT}
UPDATED

Isn't possible to achive the result in one command (first case) ? And if not, why?

Some quotes from the man:

A simple command is a sequence of optional variable assignments followed by blank-separated words and redirections, and terminated by a control operator.

Expansion is performed on the command line after it has been split into words.

For clarity, the real wold case involves providing a binary to be executed by an event handler. The binary path is got from a configuration file, falling back to default if not defined in the configuration file.

Something closer to real case is this snippet, that is called by event handler:

a=`getConfigVariable "myExec"` ${a:-/opt/bin/default}

Where getConfigVariable "myExec" returns the configuration variable "myExec", or an empty string if it is not defined. For example:

$ getConfigVariable "myExec"
/opt/bin/updated
2
  • Why not just a='UPDATED' in both commands ? Commented Dec 15, 2017 at 11:00
  • During expansion the variable assignment is probably not done yet. Commented Dec 15, 2017 at 11:00

2 Answers 2

5

The shell parses the command line before executing any of it.

In other words, ${a:-DEFAULT} is evaluated before a=UPDATED is assigned.

(Notice also how this rearticulation of the assignment avoids the useless use of echo.)

Chapter 3.5 of the Bash Reference Manual has a detailed account of in which order a command line gets parsed. You will notice that parameter expansion is near the beginning, after tilde and brace expansion.

Sign up to request clarification or add additional context in comments.

3 Comments

OK I did a RTFM and in section 3.7.1 it is clear that variable assignment is evaluated just before command execution, while parameter expansion is evaluated earlier. Clause 1.The words that the parser has marked as variable assignments (those preceding the command name) and redirections are saved for later processing, Clause 2 The words that are not variable assignments or redirections are expanded, and finaly Clause 4. The text after the ‘=’ in each variable assignment undergoes .. expansions. gnu.org/software/bash/manual/…
And by the way I was reading the "man bash" manual (which has the afforemention explanation under the title "SIMPLE COMMAND EXPANSION", which I missed) , but this online gnu reference is more readable.
So this explains why even the simplest form a='UPDATED' echo $a, outputs an empty string.
2

You may use:

a=$(echo UPDATED) bash -c 'echo "${a:-DEFAULT}"'

UPDATED

bash -c will fork a new sub-shell that has inline value of a available.

Note that a=$(echo UPDATED) is meaningless unless you have some other command substitution there. It can be shortened to:

a='UPDATED' bash -c 'echo "${a:-DEFAULT}"'

3 Comments

Running the assignment as a separate command is hugely more efficient than spawning a new shell to run the echo!
OP can clarify further but I suspect OP is trying to avoid setting an env variable in current shell.
This is indeed an answer achieving the result in one command (i.e. no semicolon), but I would agree with @tripleee that the overhead of spawning a new shell would be bigger than the alternative of two commands. Also A new quoting level is introduced making the snippet less readable. The requirement of one command is more a preference and curiosity since I tried the 2 command example and it works (As I clarified in the answer, this snipped is called by an event handler). Thank you in any case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.