Bash: Assign output of pipe to a variable
I am trying to get the output of a pipe into a variable. I tried the following things.
echo foo | myvar=$(</dev/stdin)
echo foo | myvar=$(cat)
echo foo | myvar=$(tee)
But $myvar
is empty.
I don’t want to do.
myvar=$(echo foo)
Because I don’t want to spawn a subshell.
Any ideas?
Edit: I don’t want to spawn a subshell because the command before the pipe needs to edit global variables, which it can’t do in a subshell. Can it? The echo
thing is just for simplification. It’s more like.
complex_function | myvar=$(</dev/stdin)
And I don’t get, why that doesn’t work. This works for example:
complex_function | echo $(</dev/stdin)
The correct solution is to use command substitution like this.
variable=$(complex_command)
as in
message=$(echo 'hello')
(or for that matter, message=hello
in this case).
Your pipeline.
echo 'hello' | message=$(</dev/stdin)
or
echo 'hello' | read message
actually works. The only problem is that the shell that you're using will run the second part of the pipeline in a subshell. This subshell is destroyed when the pipeline exits, so the value of $message
is not retained in shell.
Here you can see that it works.
$ echo 'hello' | { read message; echo "$message"; }
hello
... but since the subshell's environment is separate (and gone).
$ echo "$message"
(no output)
One solution for you would be to switch to ksh93
which is smarter about this.
$ echo 'hello' | read message
$ echo "$message"
hello
Another solution for bash
would be to set the lastpipe
shell option. This would mean the last part of the pipeline would run in the current environment This however does not work in interactive shells as lastpipe
requires that job control is not active.
#!/bin/bash
shopt -s lastpipe
echo 'hello' | read message
echo "$message"