4

Is it possible to do nested parameter expansion in bash? (e.g.: VAR=${{1:-$ENV_VAR}:-hard-coded default})

I want to set command line arguments with default values. However, before using a hard-coded default I would like to check for an environmental variable. Thus, the expected order would be (e.g.):

$1 -> $ENV_VAR -> "hard-coded default"

I can solve this problem in two ways (see below), but both look bad:

1:

VAR=${1:-$ENV_VAR}
VAR=${VAR:-hard-coded default}

2:

VAR2=$([ -n "${1:-$ENV_VAR}" ] && echo "${1:-$ENV_VAR}" || echo "hard-coded default")

Minimal example:

$ cat test.sh 
#!/bin/bash

VAR=${1:-$ENV_VAR}
VAR=${VAR:-hard-coded default}
VAR2=$([ -n "${1:-$ENV_VAR}" ] && echo "${1:-$ENV_VAR}" || echo "hard-coded default")

echo ENV_VAR is "'$ENV_VAR'"
echo VAR is "'$VAR'"
echo VAR2 is "'$VAR2'"

$ ./test.sh 
ENV_VAR is ''
VAR is 'hard-coded default'
VAR2 is 'hard-coded default'

$ env ENV_VAR=test ./test.sh 
ENV_VAR is 'test'
VAR is 'test'
VAR2 is 'test'

$ ./test.sh parameter
ENV_VAR is ''
VAR is 'parameter'
VAR2 is 'parameter'

$ env ENV_VAR=test ./test.sh parameter
ENV_VAR is 'test'
VAR is 'parameter'
VAR2 is 'parameter'

ruasoliveira
  • 192
  • 1
  • 11
  • 1
    So what is the question here? looks like you have got it figured out? – Inian Apr 25 '19 at 14:16
  • Whether or not nested expansion (something like this `VAR=${{1:-$ENV_VAR}:-hard-coded default}`) can be done. – ruasoliveira Apr 25 '19 at 14:20
  • bash does not supported nested expansion like above, `zsh` could I guess – Inian Apr 25 '19 at 14:21
  • I've edited the question to make it clearer, but I guess the answer is 'not possible' then. Thanks, @Inian – ruasoliveira Apr 25 '19 at 14:23
  • 1
    in this particular case following should work `VAR=${1:-${ENV_VAR:-hardcoded}}` – Nahuel Fouilleul Apr 25 '19 at 14:34
  • 1
    There is actually an example of exactly this in the manual (under [`fc`](https://www.gnu.org/software/bash/manual/bash.html#index-fc)), for the editor being used: "If *`ename`* is not given, the value of the following variable expansion is used: `${FCEDIT:-${EDITOR:-vi}}`." – Benjamin W. Apr 25 '19 at 14:57

2 Answers2

3

in this particular case following should work VAR=${1:-${ENV_VAR:-hardcoded}} (the right side of :-) documentation:

${parameter:-word}

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

the left side is a parameter not the dereferenced value

Community
  • 1
  • 1
Nahuel Fouilleul
  • 18,726
  • 2
  • 31
  • 36
1

Parameter expansion in bash supports parameter evaluation in the RHS of expansion modifiers, but by default does not on the LHS.

$: unset a; b=foo; echo "${a:-$b}"; echo "${$b}";
foo
bash: ${$b}: bad substitution

It is possible to achieve similar results with an eval.

$: unset a; b=foo; foo=bar; echo "${a:=$b}"; eval "echo \${$a}";
foo
bar

It's probably better to just break your logic out into several statements, and add comments.

Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
  • 1
    Or use Nathan's awesome solution, lol -- but still add comments for the poor guy who comes along behind you in six months to maintain it (which in my case is usualy me). ;) – Paul Hodges Apr 25 '19 at 14:44
  • 1
    Thanks also. You actually gave the same answer, but Nathan's came first and was shorter. About maintenance, I added: `# how to read this: https://stackoverflow.com/a/55851899/519536` in the code. However, I find it pretty self-explanatory once you learn about parameter expansion. – ruasoliveira Apr 25 '19 at 14:55