-
Notifications
You must be signed in to change notification settings - Fork 1.8k
SC2031
There are many ways of accidentally creating subshells, but a common one is piping to a loop:
n=0
printf "%s\n" {1..10} | while read i; do (( n+=i )); done
echo $n
# Bash specific: process substitution. Also try shopts like lastpipe.
n=0
while read i; do (( n+=i )); done < "$(printf "%s\n" {1..10})"
echo $n
In sh
, a temp file (better if fifo or fd) can be used instead of process substitution. And if it's acceptable to do it with waiting, try Here Documents.
Variables set in subshells are not available outside the subshell. This is a wide topic, and better described on the Wooledge Bash Wiki.
Here are some constructs that cause subshells (shellcheck may not warn about all of them). In each case, you can replace subshell1
by a command or function that sets a variable, e.g. simply var=foo
, and the variable will appear to be unset after the command is run. Similarly, you can replace regular
with var=foo
, and it will be set afterwards:
Pipelines:
subshell1 | subshell2 | subshell3 # Bash, Dash, Ash
subshell1 | subshell2 | regular # Ksh, Zsh
Command substitution:
regular "$(subshell1)" "`subshell2`"
Process substitution:
regular <(subshell1) >(subshell2)
Some forms of grouping:
( subshell )
{ regular; }
Backgrounding:
subshell1 &
subshell2 &
Anything executed by external processes:
find . -exec subshell1 {} \;
find . -print0 | xargs -0 subshell2
sudo subshell3
su -c subshell4
This applies not only to setting variables, but also setting shell options and changing directories.
You can ignore this error if you don't care that the changes aren't reflected, because work on the value branches and shouldn't be recombined.