Set a parent shell's variable from a subshell
Solution 1
The whole point of a subshell is that it doesn't affect the calling session. In bash a subshell is a child process, other shells differ but even then a variable setting in a subshell does not affect the caller. By definition.
Do you need a subshell? If you just need a group then use braces:
a=3
{ a=4;}
echo $a
gives 4
(be careful of the spaces in that one). Alternatively, write the variable value to stdout and capture it in the caller:
a=3
a=$(a=4;echo $a)
echo $a
avoid using back-ticks ``, they are deprecated and can be difficult to read.
Solution 2
There is the gdb-bash-variable hack:
gdb --batch-silent -ex "attach $$" -ex 'set bind_variable("a", "4", 0)';
although that always sets a variable in the global scope, not just the parent scope
Solution 3
You don't. The subshell doesn't have access to its parent's environment. (At least within the abstraction that Bash provides. You could potentially try to use gdb
, or smash the stack, or whatnot, to gain such access clandestinely. I wouldn't recommend that, though.)
One alternative is for the subshell to write assignment statements to a temporary file for its parent to read:
a=3
(echo 'a=4' > tmp)
. tmp
rm tmp
echo "$a"
Solution 4
If the problem is related to a while loop, one way to fix this is by using Process Substitution:
var=0
while read i;
do
# perform computations on $i
((var++))
done < <(find . -type f -name "*.bin" -maxdepth 1)
as shown here: https://stackoverflow.com/a/13727116/2547445
Solution 5
To change variables in a script called from a parent script, you can call the script preceded with a "."
a=3
echo $a
. ./calledScript.sh
echo $a
in calledScript.sh
a=4
Expected output
3
4
Matt Joiner
About Me I like parsimonious code, with simple interfaces and excellent documentation. I'm not interested in enterprise, boiler-plate, or cookie-cutter nonsense. I oppose cruft and obfuscation. My favourite languages are Go, Python and C. I wish I was better at Haskell. Google+ GitHub Bitbucket Google code My favourite posts http://stackoverflow.com/questions/3609469/what-are-the-thread-limitations-when-working-on-linux-compared-to-processes-for/3705919#3705919 http://stackoverflow.com/questions/4352425/what-should-i-learn-first-before-heading-to-c/4352469#4352469 http://stackoverflow.com/questions/6167809/how-much-bad-can-be-done-using-register-variables-in-c/6168852#6168852 http://stackoverflow.com/questions/4141307/c-and-c-source-code-profiling-tools/4141345#4141345 http://stackoverflow.com/questions/3463207/how-big-can-a-malloc-be-in-c/3486163#3486163 http://stackoverflow.com/questions/4095637/memory-use-of-stl-data-structures-windows-vs-linux/4183178#4183178
Updated on July 05, 2022Comments
-
Matt Joiner almost 2 years
How do I set a variable in the parent shell, from a subshell?
a=3 (a=4) echo $a
-
chepner about 11 yearsAlthough less dangerous, I'd say this should be used about as frequently as a fork bomb in an actual script.
-
Christian over 10 yearsThank you for pointing out the curly braces. I had seen them, but never knew what they did nor use them. Good advice!
-
Benoit Duffez over 9 yearsNot pretty, but pretty much the better option in some cases. Thanks.
-
aroth over 8 yearsThe file approach is quite useful if you're using a subshell to collect the values for multiple variables that the parent shell will need later, particularly in cases where not using a subshell is nontrivial.
-
dingalapadum over 8 yearsI had to
..."attach $PPID"...
in order to make this work - $$ contains the PID of the current shell. -
BeniBela over 7 years@dingalapadum not within OP's parenthesis. Probably the subshell runs in the same process and just resets the variables afterwards
-
dan_linder about 6 yearsI had to use this because I use "set -u" and "set -e" at the start of my main script, but I needed to run some commands to set a variable that exit with a non-zero exit code (and thus triggering the "-e" to kill the script).
-
ArchimedesMP almost 6 yearsIs there any way to use this when piping? E.g.
{ false; a=$?;} | true
will not set the global(?)a
to the desired value :( -
cdarke almost 6 years@ArchimedesMP: A pipe is used to pass data between processes using standard streams, there are no processes involved here (except the shell). What is it you are trying to achieve?
-
ArchimedesMP almost 6 yearsI wanted to filter a meaningless warning from a third party tools stderr inside a script, without messing up stderr/stdout and while returning the original exit code. E.g.
{ some-tool 2>&1 1>&3; ec=$?; } | grep -v "Ignore some warning" 3>&1 1>&2; exit $ec
(theX>&Y
might be a bit off since I can not access the script right now). [& thanks for the reply on a 4y old comment!] -
cdarke almost 6 years@ArchimedesMP: sounds a bit complex to do in one line, I would go for a wrapper script or a function to filter it out (you can redirect a function, e.g.
myfunc() { echo stuff and nonsense; } > gash.txt
) -
Ajeetkumar over 5 yearsHi @Carl. this works but can explanation to the answer?
-
Carl Bosch over 5 years@Ajeetkumar Please find a link to the unix.stackexchange.com/a/114301 . is a shortcut to source cammand ss64.com/bash/source.html
-
ivan_pozdeev about 5 yearsProne to race conditions since access to files is not synchronized.
-
ivan_pozdeev about 5 years
calledScript.sh
is run in the current shell, so it doesn't qualify as "subshell". -
ivan_pozdeev about 5 years@BeniBela in a
()
subshell,$$
remains the same. The actual subshell's PID can be seen with$BASHPID
. -
Carl Bosch about 5 yearsPoint taken ivan_pozdeev, technically I did not answer to the question as it is was asked
-
opinion_no9 about 3 yearscan this be done more elegant with file descriptors? Are file descriptors accessible from sub shell and parent shell the like?
-
Ale almost 3 yearsUsing
read
allows to pass several variables. The subshell inherits variables from the parent, modifies them as needed, before exiting prints them out. That way it's easy to insolate a large span of code, for example the body of a loop. -
erikbstack over 2 yearsif you source the shell script there is no subshell anymore
-
andreagalle about 2 yearswhat about this workaround? stackoverflow.com/a/15383353/6466510
-
midnite about 2 yearsI am looking for a more elegant way similar to this approach too. How to use file descriptors for this? Is it the same way as khachik's answer below writing to output streams? I suppose that limits to one variable only.