0

Something I've come across a few times recently: how to set a variable and execute commands using that variable in a one-liner? I often want to do this when I have one string which needs to be embedded in a long list of commands in multiple places:

The most obvious approach is this (contrived example):

FOO=foo date > $FOO.txt && echo "Wrote to $FOO.txt"

The problem is that $FOO gets expanded with the value of whatever FOO is when the command is parsed, not when it's executed. So if FOO is initially empty, that example will write to .txt and not foo.txt.

One solution is to use a subshell:

(FOO=foo; date > $FOO.txt && echo "Wrote to $FOO.txt")

That works fine. FOO is assigned inside the subshell and evaluated correctly where it's used.

What I don't get is why this doesn't work:

FOO=foo (date > $FOO.txt && echo "Wrote to $FOO.txt")

That's a bash: syntax error near unexpected token ``(' error.

How come that doesn't temporarily assign FOO=foo and then execute the subshell?

7
  • 1
    Note that it's not just subshells; it's any compound command.
    – chepner
    Commented Sep 8, 2022 at 19:13
  • 2
    I suspect it's to simplify the parser (which is already a gnarly mess of special cases). All compound commands begin with a fixed string of one sort or another: (, ((, [[, if, while, etc. Anything that does not begin with one of that small set of strings is a simple command. If compound commands could start with precommand assignments, you would need an arbitrary amount of lookahead to decide what kind of command you were parsing.
    – chepner
    Commented Sep 8, 2022 at 19:19
  • You can use this work-around : FOO=foo bash -c 'date > $FOO.txt && echo "Wrote to $FOO.txt"', which is equivalent of a subshell.
    – Philippe
    Commented Sep 8, 2022 at 19:49
  • Note, too, that FOO=foo date > $FOO.txt does not write the current date to foo.txt, because $FOO.txt undergoes parameter expansion before the assignment FOO=foo takes effect.
    – chepner
    Commented Sep 8, 2022 at 20:13
  • 1
    Note that a subshell is not necessarily a subprocess; creating a new process is just a convenient way to separate the operating evironment. (If the subshell were in the same process, the shell would be responsible for keeping the two environments distinct.)
    – chepner
    Commented Sep 10, 2022 at 14:09

0

Browse other questions tagged or ask your own question.