Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

From what I've read, putting a command in parentheses should run it in a subshell, similar to running a script. If this is true, how does it see the variable x if x isn't exported?

x=1

Running (echo $x) on the command line results in 1

Running echo $x in a script results in nothing, as expected

share|improve this question

2 Answers 2

up vote 7 down vote accepted

A subshell starts out as an almost identical copy of the original shell process. Under the hood, the shell calls the fork system call, which creates a new process whose code and memory are copies¹. When the subshell is created, there are very few differences between it and its parent. In particular, they have the same variables. Even the $$ special variable keeps the same value in subshells: it's the original shell's process ID. Similarly $PPID is the PID of the parent of the original shell.

A few shells change a few variables in the subshell. Bash sets BASHPID to the PID of the shell process, which changes in subshells. Bash, zsh and mksh arrange for $RANDOM to yield different values in the parent and in the subshell. But apart from built-in special cases like this one, all variables have the same value in the subshell as in the original shell, the same export status, the same read-only status, etc. All function definitions, alias definitions, shell options and other settings are inherited as well.

A subshell created by (…) has the same file descriptors as its creator. Some other means of creating subshells modify some file descriptors before executing user code; for example, the left-hand side of a pipe runs in a subshell² standard output connected to the pipe. The subshell also starts out with the same current directory, the same signal mask and traps, etc.

A subshell is thus different from executing a script. A script is a separate program. This separate program might coincidentally be also a script which is executed by the same interpreter as the parent, but this coincidence doesn't give the separate program any special visibility on internal data of the parent. Non-exported variables are internal data, so when the interpreter for the child shell script is executed, it doesn't see these variables. Exported variables, i.e. environment variables, are transmitted to executed programs.

Thus:

x=1
(echo $x)

prints 1 because the subshell is a replication of the shell that spawned it.

x=1
sh -c 'echo $x'

happens to run a shell as a child process of a shell, but the x on the second line has no more connection with the x on the second line than in

x=1
perl -le 'print $x'

or

x=1
python -c 'print x'

¹ Semantically, they're copies. From an implementation perspective, there's a lot of sharing going on.
² For the right-hand side, it depends on the shell.

share|improve this answer

Obviously, yes, as all the documentation says, a parenthesized command is run in a subshell.

The subshell inherits a copy of all the parent's variables. The difference is that any changes you make in the subshell aren't also made in the parent.

The ksh man page makes this a little clearer than the bash one...

man ksh

A parenthesized command is executed in a sub-shell without removing non-exported variables.

man bash

   (list) list is executed in a subshell environment (see COMMAND
          EXECUTION ENVIRONMENT below).  Variable assignments and
          builtin commands that affect the shell's environment do not
          remain in effect after the command completes. 

COMMAND EXECUTION ENVIRONMENT
   The shell has an execution environment, which consists of the following:
   ...
   ·      shell  parameters that are set by variable assignment 
   ...
   Command  substitution,  commands  grouped with parentheses, and asynchronous commands
   are invoked in a subshell environment that is a duplicate of the  shell  environment,
share|improve this answer
1  
This is to be contrasted to When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following., which contains the item: · shell variables and functions marked for export, along with variables exported for the command, passed in the environment (from the same man bash section) which explains why an echo $x-script prints nothing if x is not exported. –  Johan E Jun 21 at 23:50

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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