Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash -- setting multiple variables in a single pipeline stage

I am hoping to do something like:

echo 1 2 | read foo bar

To set two new variables, foo and bar, to the values 1 and 2 respectively. (In reality, "echo 1 2" will be an awk / cut invocation for an external data source.)

I am finding that foo and bar do not exist after this line which makes me wonder if it is a scoping issue? I have only used read in while loops and in those cases the loop body was able to access the variables.

like image 543
argetek Avatar asked Feb 23 '23 01:02

argetek


2 Answers

Pipes execute in a sub-shell. As such, the variables foo and bar are created, 1 and 2 are stored in them, then the subshell exits and you return to the parent shell in which these variables do not exist.

One way to read into variables as you appear to want is with a "here string"

read foo bar <<<"1 2"

Which will do what you expected the pipe version to do.

This is non-portable, however, and some shells will not support it. You can use the "here document" form instead, which is broadly supported.

$ read foo bar <<EOF
> 1 2
> EOF

Note that EOF here can be any unique string. A here document will store all lines until one that contains EOF, or whatever marker you chose, and nothing else. In this case the behavior is also identical with the previous example (but harder to copy and paste and longer to type).

What's going on here?

Both the "here document" and the "here string" are ways to represent text passed to standard input without having to enter it interactively. It is functionally equivalent to just saying read foo bar, hitting enter, then manually writing 1 2 and hitting enter again.

like image 56
sorpigal Avatar answered Mar 05 '23 11:03

sorpigal


Instead of pipe, you can do something like this -

[jaypal:~/Temp] exec 3< <(echo "Jaypal Singh")
[jaypal:~/Temp] while read word1 word2 ; do echo "$word1 $word2"; done <&3
Jaypal Singh

[jaypal:~/Temp] exec 3< <(echo "Jaypal Singh")
[jaypal:~/Temp] while read word1 word2 ; do echo "$word1"; done <&3
Jaypal
like image 45
jaypal singh Avatar answered Mar 05 '23 12:03

jaypal singh