-1

I'm a beginner at Linux shell, but I know that this command creates a subshell:

Subshells are typically created using subshell operators or commands such as parentheses (), backticks `, or the $() syntax.

: ${FOO:=$([ "$BAR" = "baz" ] && echo "true" || echo "false" )}

This could be a problem e.g. in a loop (this is not the case here) but I like to learn how to avoid it. Generally speaking, in the above assignment, can a subshell be avoided using the following?

if [ -z "$FOO" ]; then
  if [ "$BAR" = "baz" ]; then
    FOO=true
  else
    FOO=false
  fi
fi
Toby Speight
  • 8,678
gremo
  • 167
  • As for the downvotes on your previous iteration of this question, the popup on the downvote button says "The question doesn't show any research effort; it is unclear or not useful". And that question seemed based pretty much completely on unverified hearsay, which doesn't make for a very useful or well-researched question. (It'd be hearsay from a friend too, not just from an AI, but what with the recent discussion about AI-produced crap on SE sites, it's not surprising that explicitly mentioning AI as a source for some misconception would get even more flak) – ilkkachu Jul 04 '23 at 11:15
  • So let's remove any AI reference, maybe some SE linux nerd doesn't downvote it and respect a linux beginner. – gremo Jul 04 '23 at 11:17
  • Reiterating my comment on the deleted question: This should be trivial to test depending on the shell. In bash, for example, replace true and false with $BASH_SUBSHELL and check the output. – muru Jul 04 '23 at 11:18
  • @muru thanks, I didn't specified it but it's a posix script. I can test it changing to bash ofc. – gremo Jul 04 '23 at 11:19
  • Well, please do, because the concern of "being a problem in a loop" is completely dependent on the actual shell on how it optimizes subshells. If no forking is involved, as seems to be the case in some shells depending on the command run, it's really not that big of a deal. See also: https://unix.stackexchange.com/a/421028/70524 https://unix.stackexchange.com/a/264199/70524 – muru Jul 04 '23 at 11:30
  • @gremo, I'm happy that you read my comment in full. – ilkkachu Jul 04 '23 at 11:48
  • eh, so, what exactly is the question now? You know $(...) creates a subshell, and you have one solution with it, and another without, and you want to know if the script that has nothing that would create a subshell runs without creating a subshell? (How much the subshell is a performance issue or not is an orthogonal matter, imo.) – ilkkachu Jul 04 '23 at 11:51
  • @muru thanks for the link, you seems to be the only calm and peaceful guy here. Unfort, I'm goint to delete this too. – gremo Jul 04 '23 at 12:17

2 Answers2

3

Generally speaking, in the above assignment, does a subshell can be avoided using the following?

if [ -z "$FOO" ]; then
  if [ "$BAR" = "baz" ]; then
    FOO=true
  else
    FOO=false
  fi
fi

Yes, and that would be the correct way to write it.

: ${FOO:=$([ "$BAR" = "baz" ] && echo "true" || echo "false" )}

Runs a subshell (which in most shells involves the costly forking of a process) and is also wrong for several reasons:

  • That ${FOO...} expansion is unquoted and therefore subject to split+glob, making it at least a DoS vulnerability (that's one of the examples given at Security implications of forgetting to quote a variable in bash/POSIX shells).
  • echo "false" is run if either [ or echo true fails while you want it to be run when [ fails only. a && b || c is no proper substitute for if a; then b; else c; fi.

In the ksh93 shell, the subshell and those issues can be avoided with:

: "${FOO:=${
  if [ "$VAR" = baz ]; then
    echo true
  else
    echo false
  fi
}}"

But that has little advantage over the standard and obvious if statement above.

0

For a cryptic one-liner, I think this would achieve the desired result without sub-shells:

[[ "$BAR" = "baz" ]] && FOO=${FOO-true} || FOO=${FOO-false}

But I'd go with if....

symcbean
  • 5,540