6

I know that I can run a command with an environment variable like this:

FOO=bar mycommand

I know that I can run commands in a subshell like this:

(firstcommand && secondcommand)

But can I somehow combine those two?

FOO=bar (firstcommand && secondcommand)

gives:

sh: syntax error: unexpected "("

at least in busybox shell (ash).

Edit: Kusalananda suggested FOO=bar sh -c 'first && second' which is indeed a solution. However, I am also interested in alternative answers because I like the subshell syntax because it doesn't require fiddling around with escaping of quotes.

  • What is FOO=bar mycommand? Shouldn't mycommand come one line under the variable declaration? – user9303970 Mar 9 '18 at 5:23
8

One way:

FOO=bar sh -c 'first && second'

This sets the FOO environment variable for the single sh command.

To set multiple environment variables:

FOO=bar BAZ=quux sh -c 'first && second'

Another way to do this is to create the variable and export it inside a subshell. Doing the export inside the subshell ensures that the outer shell does not get the variable in its environment:

( export FOO=bar; first && second )

Summarizing the comments: The export is needed to create an environment variable (as opposed to a shell variable). The thing with environment variables is that they get inherited by child processes. If first and second are external utilities (or scripts) that look at their environment, they would not see the FOO variable without the export.

  • 3
    Or (FOO=bar; first && second). – Satō Katsura Sep 13 '17 at 18:10
  • @SatōKatsura That'll work, but it's not an environment variable in the same way. One may export it though. – Kusalananda Sep 13 '17 at 18:12
  • 1
    @AndreKR It works without the export, but if first and/or second are shell scripts, then FOO won't be set within those scripts since it's just an unexported shell variable. Saying FOO=bar cmd creates an environment variable in the cmd process. – Kusalananda Sep 13 '17 at 18:19
  • 1
    @AndreKR Everything unknown is weird. – Kusalananda Sep 13 '17 at 18:21
  • 2
    You don't need the env for multiple variables, FOO=bar BAZ=quux sh -c 'first && second' works as well. – Stéphane Chazelas Oct 4 '17 at 10:05
-1

The environment of the subshell has a lot in common with the parent. Let's look at the definition first. subshell is a child process launched by a shell (when we are in front of a shell prompt) or a shell script.

In shell programming (bash in particular), "( )" starts a subshell. Whatever variables you define and assign inside the subshell is not visible to the parent process. This is usually the source of some shell programming errors.

A function in bash is essentially a command and a subshell but with the side effect of all its varables are also GLOBAL unless you add the LOCAL qualifier. The variable outside the function is visible inside the function. Thus your subshell's environment is essentially the global variable in the shell script.

As a small example in Bourne shell:

#!/bin/sh

a_function() {
    echo "function is essentially a subshell"
    echo "inside a_function"
    echo "it can see parent variables: shellvar=$shellvar"
}

shellvar="shellvariable is set from parent shell"
echo "shellvar from parent: $shellvar "
a_function

If you run this program:

./test.sh
shellvar from parent: shellvariable is set from parent shell 
function is essentially a subshell
inside a_function
it can see parent variables: shellvar=shellvariable is set from parent shell

To fully understand processes, child processes, subshells, you may want to read about fork, exec. Note the export somevar=somevalue is making somevar visible to all subsequent processes, not just the subshell. Process is organized like a tree.

  • You can't really compare a function with a subshell, as setting a variable in a function will make it available in the calling environment whereas setting a variable in a subshell would not. – Kusalananda Mar 23 at 21:32
  • Yes, your are right. Only when you use local inside the function then you can hide it. This is the tricky part of shell programing, inside function you can trump some global variable. I tried to stick to the principle of adding local to variable inside function. I think this feature is only available in bash not in Bourne. – Kemin Zhou Mar 24 at 1:50
  • You could write the function with func () (...) instead of with func () {...} which would make it run in a subshell... But that would be because of the actual subshell and not because it was a function. – Kusalananda Mar 24 at 7:06
-2

For general export, add this line in top makefile

SHELL:=NODE_PATH=. ${SHELL}

where "NODE_PATH=." is an example var

I use this in this example project:

https://github.com/rzr/webthing-iotjs/blob/sandbox/rzr/node/master/Makefile#L24

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.