Say I have a file myfile
in my current working directory. I want to set a variable if a command executes normally, but also use its result.
$ ls myfile && v=3
myfile
$ echo "$v"
3
But now I also want to pipe the result, so I use the { list; }
syntax to group the commands:
$ unset v $ { ls myfile && v=3; } | grep myf myfile $ echo "$v" # v is not set
Bash reference manual -> 3.2.4.3 Grouping Commands says:
{ list; }
Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. The semicolon (or newline) following list is required.
So, to my understanding, v
should be set to 3. But it is not happening. Why?
It's not the curly braces that are causing a subshell to be created, it's the pipe.
To prove it:
$ { ls && v=3; } > tmp
$ echo "$v"
3
To quote Greg:
In most shells, each command of a pipeline is executed in a separate SubShell.
You can use BASH_SUBSHELL
variable to verify whether you're in subshell or not.
# BASH_SUBSHELL will print level of subshell from top due to pipe
{ unset v && ls file && v=3 && echo "$BASH_SUBSHELL - $v"; } | nl
1 file
2 1 - 3
# outside BASH_SUBSHELL will print 0
echo "$BASH_SUBSHELL - $v";
0 -
You can use for piped command it prints 1
meaning it is in a subshell hence value of v
isn't available outside (evident from 2nd output)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With