diff --git a/SC2031.md b/SC2031.md new file mode 100644 index 0000000..063b68d --- /dev/null +++ b/SC2031.md @@ -0,0 +1,60 @@ +# var was modified in a subshell. That change might be lost. + +### Problematic code: + +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 + +### Correct code: + + # Bash specific: + n=0 + while read i; do (( n+=i )); done < <(printf "%s\n" {1..10}) + echo $n + +In `sh`, a temp file can be used instead of process substitution. + +### Rationale: + +Variables set in subshells are not available outside the subshell. This is a wide topic, and better described on the [Wooledge Bash Wiki](http://mywiki.wooledge.org/BashFAQ/024). + +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. + +### Contraindications + +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. \ No newline at end of file