Left side of pipe is the subshell?
Asked Answered
O

2

14

Edit:

My comment below regarding sed 's@^@ @' <(f1) is incorrect While $BASH_SUBSHELL indicates that we are in the same level as the launch, the variables are lost in the main script. based on Gordons answer I tested f1 > >(sed 's@^@ @') instead and that seems to work correctly. Still, shouldn't BASH_SUBSHELL should be 1 and not 0 for the first form?


Consider this small test

#!/bin/bash
declare -i i=0
function f1()
{
  let i++
  echo "In f1, SUBSHELL: $BASH_SUBSHELL, i=$i" >&2
}

f1
f1 | sed 's@^@     @'

echo "at end, i=$i"

with the following output:

In f1, SUBSHELL: 0, i=1
In f1, SUBSHELL: 1, i=2
at end, i=1

(the purpose of the sed is just to have a pipe to something, don't expect it to do anything because f1 outputs to stderr)

The function f1 logs the current BASH_SUBSHELL and the current value of i

I know why at the end of the script we get i=1, its because the second invocation was in a subshell, and the value of i at subshell 1 was lost.

What I don't know is why the left side of the pipe was not executed in the current shell

Though I figured that I could avoid this with sed 's@^@ @' <(f1) I would like to know why the left side is not at the same level as the main script

Oviduct answered 22/4, 2011 at 22:22 Comment(3)
I think the shell is allowed to have both ends of the pipe in subshellBetweentimes
A quick google found this: linuxprogrammingblog.com/pipe-in-bash-can-be-a-trapYenta
@Brian that article's does not discuss the LEFT side of the pipe ... I already know that it is bad news for variable assignments on the right side of a pipeOviduct
D
27

From the bash man page: "Each command in a pipeline is executed as a separate process (i.e., in a subshell)." I suppose it would be possible to execute one component of a pipeline in the current shell (i.e. the first, or the last, or maybe one in the middle), it doesn't play favorites like this: they all execute in subshells. If you modify your script like this:

#!/bin/bash
declare -i i=0
function f1()
{
    let i++
    echo "In f1, SUBSHELL: $BASH_SUBSHELL, i=$i" >&2
}

f1
f1 | f1 | f1

echo "at end, i=$i"

it prints:

In f1, SUBSHELL: 0, i=1
In f1, SUBSHELL: 1, i=2
In f1, SUBSHELL: 1, i=2
In f1, SUBSHELL: 1, i=2
at end, i=1

because all 3 invocations of f1 in the pipeline run in subshells.

Dropsonde answered 22/4, 2011 at 22:59 Comment(6)
I guess my confusion comes from thinking of pipe and file redirection are somewhat equal f1 < /etc/passwd, for example, does not start a new subshell (and i figured if we are just temporarily redirecting a descriptor - why not be consistent about it). But as it is in the manpage - I guess it will have to doOviduct
@nhed: I wouldn't think of a pipe like an output redirection. A pipeline is a series of commands strung together by I/O redirections, and all run simultaneously; since the shell doesn't do multitasking, it can run at most one of them in the main shell, and since they're all basically equal there's no reason to pick one to run in the main shell, so for fairness they're all run in subshells. In bash, you can use < <() and > >() to explicitly relegate some of the commands to subshells, allowing one command to run in the main shell.Dropsonde
@nhed: (continuing) for example, to force the first command in a pipeline to run in the main shell, use cmd1 > >(cmd2 | cmd3 | ...). To run cmd2 in the main shell, use cmd2 < <(cmd1) > >(cmd3 | ...), etc.Dropsonde
thanks - I thought I was missing something (the additional < or > before the <() or >()). Still wondering about the BASH_SUBSHELL ... if it was in a subshell it should not print 0Oviduct
Minor quibble, as bash does play favorites: jobs on the left-hand side of a pipe doesn't run in a sub-shell.Hosea
<3 @GordonDavisson, save my day, i need exactly 1 must be in current shellGraber
J
-3

Here is a much concise example if someone cares :

cd / && cd /tmp/ | pwd  ; pwd
/
/

Or :

cd / && cd /tmp/ | cd /var/  ; pwd
/

Yes this page says it all

http://linux.die.net/man/1/bash# Each command in a pipeline is executed as a separate process (i.e., in a subshell).

Jitterbug answered 26/2, 2014 at 22:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.