Nested default arguments in bash?
Asked Answered
P

2

6

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'

Proto answered 25/4, 2019 at 14:13 Comment(6)
So what is the question here? looks like you have got it figured out?Reld
Whether or not nested expansion (something like this VAR=${{1:-$ENV_VAR}:-hard-coded default}) can be done.Proto
bash does not supported nested expansion like above, zsh could I guessReld
I've edited the question to make it clearer, but I guess the answer is 'not possible' then. Thanks, @ReldProto
in this particular case following should work VAR=${1:-${ENV_VAR:-hardcoded}}Compressed
There is actually an example of exactly this in the manual (under fc), for the editor being used: "If ename is not given, the value of the following variable expansion is used: ${FCEDIT:-${EDITOR:-vi}}."Numerator
C
6

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

Compressed answered 25/4, 2019 at 14:38 Comment(1)
Wow! I feel so stupid not to have tried that before. Many thanks!Proto
L
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.

Leptospirosis answered 25/4, 2019 at 14:43 Comment(2)
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). ;)Leptospirosis
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.Proto

© 2022 - 2024 — McMap. All rights reserved.