1

How can I set a one-shot variable that affects an entire compound command?

E.g., something like:

FOO=1 ./foo.sh && ./foo.sh

where foo.sh contains echo "FOO=$FOO" will print:

FOO=1
FOO=

I would like the value of FOO to be set for entire pipeline (but I don't want to set or export it in my current shell). A subshell works:

( export FOO=1; ./foo.sh && ./foo.sh )

... but is there a way w/o a subshell?

  • 2
    "Compound command line" might describe your examples better than "pipeline", as the current examples don't have any pipes. – Jeff Schaller Jun 18 at 23:42
  • I assume, since you didn't say, that FOO=1 ./foo.sh && FOO=1 ./foo.sh is unacceptable? – Jeff Schaller Jun 19 at 0:16
  • Thanks @JeffSchaller - yes, "compound command" is more accurate: I've updated it. I mean it's not "unacceptable" necessarily but I was trying to avoid it (yes, I am aware that I could repeat it like that). The actual command line has more than two commands, and I want to quickly change one FOO to change it in all of them. The subshell works OK I guess, just wondering if there was a syntax I was missing. – BeeOnRope Jun 20 at 2:42
1

What you ask is something not achievable without any hacks done. The reason is when you run the script with

FOO=1 ./foo.sh && ./foo.sh

you are basically launching two separate instances of shell which inherit all the traits (variables) from the parent shell you launched this on. If you print the $$ variable inside the foo.sh you will notice separate proc-ids for each of the scripts started.

Now FOO=1 in the first part only affects the environment started by the first process. The variable is not even available in the parent shell launched on, but only in the scope of the first process. There is no way this variable set can be reflected on the environment of the second process which runs on a separate user-space altogether.

There is no way this second process sees this value in its environment unless the value is inherited from its parent ( when the variable is explicitly exported from the shell the pipeline is run ) or the value is passed again locally to the second script.

1

The subshell approach would be the approach with less typing:

(
    export FOO="value"
    ./foo.sh && ./foo.sh
)

The other way to do it would be through starting a child shell and set the environment variable for that shell:

FOO="value" sh -c './foo.sh && ./foo.sh'

Other variations are to explicitly set the variable for each invocation of your script, as in

FOO="value" ./foo.sh &&
FOO="value" ./foo.sh

which could be made slightly more convenient with

foo=( env FOO="value" ./foo.sh )
"${foo[@]}" && "${foo[@]}"

or, with /bin/sh,

set -- env FOO="value" ./foo.sh
"$@" && "$@"

Or you may set it in the calling script and then unset it once you're done with it, as in

export FOO="value"
./foo.sh && ./foo.sh
unset FOO

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.