0

In my Korn shell days I could do the following:

#!/bin/ksh

(
    echo a=1
    echo b=2
) |
    while read line
    do
        name=${line%%=*}
        val=${line#*=}
        eval "$name=$val"
        eval "echo $name=\$$name"
    done
echo a=$a
echo b=$b

Output:

a=1
b=2
a=1
b=2

Meaning that the while loop runs in the foreground shell.

But when you run that in bash, you get:

a=1
b=2
a=
b=

Meaning that it runs in a sub-shell.

I know of other mechanisms to get what I want for this specific usage, however, is there a way to make bash run it in the foreground like ksh?

Marshall Jobe
  • 89
  • 1
  • 8
  • See [BashFAQ #24](http://mywiki.wooledge.org/BashFAQ/024), which covers this in detail. – Charles Duffy Oct 13 '16 at 16:29
  • ...an answer to this specific question is also included in the answers to the slightly-more-general question http://stackoverflow.com/questions/7313491/bash-while-read-resetting-variable-values-using-the-read-builtin-in-a-pipeline (aside: the answer by mklement0 is IMHO the best there). – Charles Duffy Oct 13 '16 at 16:31

1 Answers1

5

bash 4.2 introduced the lastpipe option, which (given some conditions that are basically true for non-interactive shells) allows the last command in a pipeline to run in the current shell.

shopt -s lastpipe
x=foo
echo bar | read x
echo "$x"   # outputs bar, not foo

In earlier versions, you are limited to workarounds such as process substitution

while read line; do
...
done < <(echo a=1; echo b=2)

and named pipes

mkfifo p
(echo a=1; echo b=2) > p &
while read line; do
...
done < p

And, just to address the use of eval here:

shopt -s lastpipe
( echo a=1; echo b=2 ) |
   while IFS== read -r name value; do
       IFS= read -r "$name" <<< "$value"
   done
chepner
  • 497,756
  • 71
  • 530
  • 681
  • Thank you. Nice comment. I'll not use the IFS== thought since it is always possible for the value to contain an '=' symbol. – Marshall Jobe Oct 13 '16 at 16:24
  • That's not a problem; `IFS== read name value <<< "foo=bar=baz"` sets `name` to `foo` and `value` to `bar=baz`. With only two arguments, `read` only splits on and discards the first `=`. I have edited the nested `read` to ensure that the value of `$value` is used verbatim. – chepner Oct 13 '16 at 16:26
  • Worth using `read -r` to fix handling of strings with literal backslashes. – Charles Duffy Oct 13 '16 at 16:32