7

I'm writing a bash script.

Per this original post I have learned that c=${a:-b} can be used to set the variable c if var a turns out to be unset or empty.

I wonder if we can extend this case into assigning the output of a command to a var. For example, I have a bash command some command, and I can assign it to the var c with

c=$(some command)

But I also want to include the case that if the output of some command is empty, I assign another default value to c.

I know that I can write vanilla if-else in the bash script, but just wonder if there's any more elegant way similar to c=${a:-b}?

2
  • 1
    c=${a:=b} would assign to both a and c, which might be a bit confusing to a reader. (I don't think the linked question had that either.) The one that doesn't assing to a is c=${a:-b}.
    – ilkkachu
    Jan 3, 2022 at 10:48
  • @ilkkachu thanks for pointing it out! have changed it.
    – IsaIkari
    Jan 3, 2022 at 15:31

1 Answer 1

10

In zsh, you can do:

var=${$(cmd):-default}

But in any POSIX-like shell including bash, you can always do:

var=$(cmd)
var=${var:-default}

Or

: "${var:=default}"

You do lose the exit status, but you could save it in a variable in between the two steps:

var=$(cmd)
exit_status=$?
: "${var:=default}"

You can also do things like:

var=$(cmd) exit_status=$? || var=default

For $var to be set to default if cmd failed (regardless of whether it output something or not).

Note that if cmd output is non-empty but consists only of newline characters, then after var=$(cmd), $var will still be empty as command substitution strips all trailing newline characters. bash also strips all NUL characters. zsh preserves them, some other shells strip everything after the first NUL character. yash chokes on sequences of bytes not forming valid characters in the locale.

For $var to be set to default only if cmd's output is non-empty, with GNU grep (or any implementation that can cope with (and not modify) non-text input, and doesn't ignore non-delimited lines), you can do:

var=$(cmd | grep '^') || var=default

where grep '^' returns true if it finds the beginning of at least one line in its input (and passes its whole input undisturbed to its output).

In that case, cmd's exit status is lost. $var could end up being empty if cmd outputs only NULs or newlines.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .