I understand the subshell syntax to be (<commands...>)
, is $()
just a subshell that you can retrieve variable values from?
Note: This applies to bash 4.4 based on different wording in their documentation.
I understand the subshell syntax to be (<commands...>)
, is $()
just a subshell that you can retrieve variable values from?
Note: This applies to bash 4.4 based on different wording in their documentation.
$(…)
is a subshell by definition: it's a copy of the shell runtime state¹, and changes to the state made in the subshell have no impact on the parent. A subshell is typically implemented by forking a new process (but some shells may optimize this in some cases).
It isn't a subshell that you can retrieve variable values from. If changes to variables had an impact on the parent, it wouldn't be a subshell. It's a subshell whose output the parent can retrieve. The subshell created by $(…)
has its standard output set to a pipe, and the parent reads from that pipe and collects the output.
There are several other constructs that create a subshell. I think this is the full list for bash:
( … )
does nothing but create a subshell and wait for it to terminate). Contrast with { … }
which groups commands purely for syntactic purposes and does not create a subshell.… &
creates a subshell and does not wait for it to terminate.… | …
creates two subshells, one for the left-hand side and one for the right-hand side, and waits for both to terminate. The shell creates a pipe and connects the left-hand side's standard output to the write end of the pipe and the right-hand side's standard input to the read end. In some shells (ksh88, ksh93, zsh, bash with the lastpipe
option set and effective), the right-hand side runs in the original shell, so the pipeline construct only creates one subshell.$(…)
(also spelled `…`
) creates a subshell with its standard output set to a pipe, collects the output in the parent and expands to that output, minus its trailing newlines. (And the output may be further subject to splitting and globbing, but that's another story.)<(…)
creates a subshell with its standard output set to a pipe and expands to the name of the pipe. The parent (or some other process) may open the pipe to communicate with the subshell. >(…)
does the same but with the pipe on standard input.coproc …
creates a subshell and does not wait for it to terminate. The subshell's standard input and output are each set to a pipe with the parent being connected to the other end of each pipe.x=$(command)
(which has a subshell in the rhs by definition, as you say) the only way to store the output of command
into a variable? Is "command substitution without a subshell" something?
– Enlico
Oct 10 '19 at 18:27
command | { read line; … }
(depending on the shell, line
may or may not still available after the pipeline). All the ways involve a subshell because the command that produces output has to run independently of the shell that reads the input. If the command is purely internal to the shell (only shell constructs and builtins, no external commands), the shell might not create a subprocess, but that's just an optimization, it still creates a subshell.
– Gilles 'SO- stop being evil'
Oct 10 '19 at 18:48
From the bash(1) man page in bash version 4.4, "EXPANSION" section, "Command Substitution" subsection:
Bash performs the expansion by executing
command
in a subshell environment [...]
bash
manpage doesn't mention any subshell: Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.
I wonder if this was a deliberate omission.
– dr_
May 09 '18 at 06:55
Yes, ( commands... )
is a bash
subshell that will execute commands...
in another process.
The only difference when you have $( commands... )
is that this part of code will after execution of commands...
be replaced with everything that commands...
wrote to stdout
.