2

I'm trying to assign the output of a command to multiple variables, one per output "word". Doing (bash on linux)

echo foo bar baz | read FOO BAR BAZ
echo $FOO $BAR $BAZ

shows only empty strings. Doing

read FOO BAR BAZ < <(echo foo bar barz)
echo $FOO $BAR $BAZ

works as expected. What's wrong here? I thought using a pipe was the most obvious and right way to do that.

lurker
  • 56,987
  • 9
  • 69
  • 103
agnul
  • 12,608
  • 14
  • 63
  • 85
  • Pipes create shubshells which cannot alter the non-subshell environment. I'll link a duplicate with answers in a minute. – Socowi Jul 22 '19 at 10:46
  • 1
    [This answer](https://unix.stackexchange.com/a/143959/187122) explains the problem but is on unix SE. When someone finds a good duplicate on StackOVerflow please link it. I'm sure there is one. – Socowi Jul 22 '19 at 10:49
  • Since you already have a working code I guess you just want an explanation of what is hapenning. User [pbhd](https://stackoverflow.com/users/1799742/pbhd) nicely explains it [in his post](https://stackoverflow.com/a/13764174/5521670). Piped operations happen in a subshell and therefore any declared variables are accessible only inside it. – Šimon Kocúrek Jul 22 '19 at 10:48
  • 1
    See: http://mywiki.wooledge.org/BashFAQ/024 – kvantour Jul 22 '19 at 12:22

2 Answers2

4
echo foo bar baz | read FOO BAR BAZ
echo $FOO $BAR $BAZ

In this case it prints nothing. The reason is because pipe creates a subshell in which FOO, BAR and BAZ get values.

echo foo bar baz | { read FOO BAR BAZ ;  echo $FOO $BAR $BAZ ;}

Try this, it will print correct value of all variables. Here, the braces encapsulated the echo command to run in the same subshell in which the variables are read.

read FOO BAR BAZ < <(echo foo bar barz)
echo $FOO $BAR $BAZ

In this case everything happens in the same shell, so you see the output you expect.

Mihir Luthra
  • 6,059
  • 3
  • 14
  • 39
1

One addition to Mihir's answer -

read a b c <<< "$( echo 1 2 3 )" # a here-string
Paul Hodges
  • 13,382
  • 1
  • 17
  • 36