How (...) and {...} interact with creating subshell using pipes in bash?

I am trying to understand the difference between invoking a shell subprocess using parentheses and curly braces. I thought that curly braces do not start the subprocess, but it seems that they start the subprocess.

#!/bin/sh a=1 b=1 ( a=2; ) | ( a=3; ) { b=2; } | { b=3; } echo "a=$a" echo "b=$b" 

This script prints

 a=1 b=1 

So, it seems that all calls are made inside subprocesses. Is there any difference between the two in this context? I understand that if I used && and || , then {..} will not start the subprocess, but I'm trying to understand how pipes work.

+4
bash
Apr 27 '16 at 17:04 on
source share
3 answers

To demonstrate that this is the pipeline itself creating the subshell, and that the curly braces will not change anyway:

 #!/bin/bash echo "Base: $BASHPID" ( echo "In (): $BASHPID" ) # This will differ from the base { echo "In {}: $BASHPID"; } # This will match the base # In bash, these will both differ from the base echo "Pipeline, default config:" { echo " X: $BASHPID" >&2; } | { echo " Y: $BASHPID" >&2; } # This is exactly the same without the {}s echo "Pipeline, no {}s, default config:" echo " X: $BASHPID" >&2 | echo " Y: $BASHPID" >&2 # Only the former will differ from the base if running a new enough bash shopt -s lastpipe echo "Pipeline, lastpipe enabled:" { echo " X: $BASHPID" >&2; } | { echo " Y: $BASHPID" >&2; } 

By doing this locally with bash 4.3, I get:

 Base: 82811 In (): 82812 In {}: 82811 Pipeline, default config: X: 82813 Y: 82814 Pipeline, no {}s, default config: X: 82815 Y: 82816 Pipeline, lastpipe enabled: Y: 82811 X: 82817 

Please note that since all components of the pipeline are executed simultaneously, there is no specific order from which the first output from X or Y will be output; however, when lastpipe enabled lastpipe last component of the pipeline is called in the already running and running shell ( fork() not required from the main process), which slightly changes the probability of who writes the first to stdout.

+5
Apr 27 '16 at 17:40
source share

{ ... } does not spawn a sub-shell. What you see is related to what you use | between two curly list commands.

This will be apparent with this test:

 $> b=1 $> echo $BASHPID 4401 $> { echo "X. $BASHPID"; b=2; } | { echo "Y. $BASHPID"; b=3; } Y. 46902 $> echo $BASHPID 4401 $> declare -pb declare -- b="1" 

You can see that { echo "Y. $BASHPID"; b=3; } { echo "Y. $BASHPID"; b=3; } { echo "Y. $BASHPID"; b=3; } is executed in another sub-shell, so changes made to b are not reflected in the current shell, where b is still 1 .

+3
Apr 27 '16 at 17:20
source share

Parentheses execute commands in a subshell. Curly braces execute commands in the current shell:

 $ echo $BASHPID; (TEST=test; echo "sub:$TEST;$BASHPID"; exit 1);\ > { echo "current:$TEST;$BASHPID;$?"; } 2920 sub:test;3700 current:;2920;1 

Another difference is that curly braces require spaces between them and the attached commands and a semicolon after the last, while parentheses do not execute.

All of this is documented on the bash man page, "Compound Commands."




The only exception (more precisely, another aspect) is the use of channels:

 command1 | command2 

In this case, both commands are executed in separate subshells - regardless of what they are (and which include compound commands). The Piping section of the manual page documents this.

+1
Apr 27 '16 at 17:12
source share



All Articles