1
$ p="pineapple" ; echo $p
pineapple
$ (p="peach" ; echo $p)
peach
$ echo $p
pineapple

Why does the shell doesn't display peach since it was initialized last ? Does the parentheses play a role in this result ?

ForzaTekk
  • 105

1 Answers1

4

Yes, that's exactly what the parenthesis are for in Bourne-like and csh-like shells: introduce a sub-shell environment (which in most shells including bash is implemented by forking a child process) where modifications are confined in.

Any change to the shell state within that subshell environment whether it's a variable, option, alias, function, redirection, current working directory, signal disposition... is lost (reverted) upon leaving it.

It is very useful to run only some commands in a different environment.

For instance:

(cd /some/dir && cmd)

To run cmd in a different directory.

Or in things like:

(IFS=:; set -o noglob; ls -l -- $PATH)

where we tune the split+glob operator only for that one expansion of $PATH.

If you want to group commands without introducing a subshell environment, use the { and } keywords instead:

a=1
{ echo "I'm running in the main shell environemnt"; a=2;}
echo "$a"
(echo "I'm running in a subshell environment"; a=3)
echo "$a"

Note the space after a { and ; before } as those are keywords made of ordinary characters, while ( and ) are special characters in the shell syntax, here used for the (...) subshell construct.

Also note that (...) is not the only construct that introduces a subshell environment. There's also (in Bourne/Korn-like shells):

  • some forms of command substitution: $(subshell) or `subshell`
  • process substitution: <(subshell), >(subshell), =(subshell)
  • pipeline components: { subshell; } | othercommand (not the last component in AT&T ksh or zsh).
  • asynchronous command: { subshell; } &
  • co-processes: { subshell; } |& or coproc { subshell; }

In the POSIX shell grammar, both { ...; } and (...) are so called compound commands. Both can be assigned to functions. Defining a function as:

func() (
  ...
)

instead of

func() {
  ...
}

means that, once invoked, the body of that function is run in a subshell environment which makes it behave more like a script (not the same as it still inherits all the variables, aliases, functions, options... of the caller).

In the fish shell, (...) is something completely different. It is command substitution, but one that does not introduce a subshell environment:

fish> set a 1; echo $a (set a 2; echo $a) $a
1 2 2

It is similar to the ${ ...; } form of command substitution of the ksh93 or mksh shells which also don't introduce a subshell environment.