Reading from a pipe (bash )
Probably every bash programmer
[1] has at least once stumbled across this problem:
a=1 b=2
echo "4711 4712" | read a b
echo "a=$a b=$b" # Output: a=1 b=2
Generally spoken, the output of a command (in the example: echo )
is to be read into one or more variables. With the approach shown
above, however, the variable settings remain unchanged. The
reason is that bash executes every part of a pipe in a subshell,
including the last one. So a and b don't belong to the actual shell,
but are local variables of the last subshell.
Other shells, such as ksh and zsh , execute the last part
in the actual shell, so the problem doesn't occur there.
One method to work around this annoyance is to keep
all processing of the variables within the last subshell:
some_command |
{
read a b
do_something_with $a $b
# usw.
}
This makes sense only in relatively simple cases.
A more generally applicable and commonly used method is the following:
read a b <<EOF
$(some_command)
EOF
Or (provided the shell supports here-strings):
read a b <<<$(some_command)
Here, the output of the command is inserted by command replacement into
the actual shell, and then read as a here-document or a here-string.
The variables used belong to the actual shell.
The following little function readfrom works similar,
but is somewhat more general. The example from above would look
like this:
text=$(some_command)
readfrom "$text" a b
or
readfrom "$(some_command)" a b
With the option -tc the separator
c is used instead of $IFS . Example:
readfrom -t: "$(grep "JohnDoe" /etc/passwd)" user x uid gid
[1] Present company excepted, of course
|