ksh has a really interesting construct to do this, detailed in this answer: https://stackoverflow.com/a/11172617/636849
Since Bash 4.0, there is a builtin mapfile builtin command that should solve this problem: http://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html
But strangely, it doesn't seem to work with process substitution:
foo () { echo ${BASH_SUBSHELL}; }
mapfile -t foo_output <(foo) # FAIL: hang forever here
subshell_depth=${foo_output[0]} # should be 0
But how to do this in Bash v3.2 ?
To store the output of a command in a variable, you can use the shell command substitution feature in the forms below: variable_name=$(command) variable_name=$(command [option ...] arg1 arg2 ...) OR variable_name='command' variable_name='command [option ...]
To make a variable available in a subshell (or any other subprogram of the shell), we have to “export” the variable with the export command.
The shell provides a way to protect variables as read-only by using the readonly command. After a variable is marked read-only, we cannot change the value of the variable. As we can see from the output, we cannot assign to the variable declared as readonly. If we drop "$", we get an error.
Here's another way to do it, which is different enough that it warrants a separate answer. I think this method is subshell-free and bash sub-process free:
ubuntu@ubuntu:~$ bar () { echo "$BASH_SUBSHELL $BASHPID"; }
ubuntu@ubuntu:~$ bar
0 8215
ubuntu@ubuntu:~$ mkfifo /tmp/myfifo
ubuntu@ubuntu:~$ exec 3<> /tmp/myfifo
ubuntu@ubuntu:~$ unlink /tmp/myfifo
ubuntu@ubuntu:~$ bar 1>&3
ubuntu@ubuntu:~$ read -u3 a
ubuntu@ubuntu:~$ echo $a
0 8215
ubuntu@ubuntu:~$ exec 3>&-
ubuntu@ubuntu:~$
The trick here is to use exec
to open the FIFO in read-write mode with an FD, which seems to have the side-effect of making the FIFO non-blocking. Then you can redirect your command to the FD without it blocking, then read the FD.
Note that the FIFO will be a limited-size buffer, probably around 4K, so if your command produces more output than this, it will end up blocking again.
This question comes up very often while looking how to just capture output of any "printing" command into variable. So for anyone looking it's possible (since bash v3.1.0) with:
printf -v VARIABLE_NAME "whatever you need here: %s" $ID
If you tweak your scripts for speed then you can use pattern of setting some global variable at the end of functions instead of just "echoing" it - use this with care, it's sometimes criticized as leading to hard to maintain code.
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