read stdin into variable?

Harald van Dijk harald at gigawatt.nl
Sun Nov 8 21:41:51 UTC 2020


On 08/11/2020 20:18, Hadrien Lacour wrote:
> On Sun, Nov 08, 2020 at 09:12:13PM +0100, chiasa.men wrote:
>> Ahoy,
>>
>> how to get the following idiom ash-like translated? (I just called busybox on
>> my raspbian buster)
>>
>>
>> echo '12 34' | read a b ; echo "'${a}''${b}'"
>> ''''
>>
>> Doesnt the manual state that "The read utility shall read a single logical
>> line from standard input into one or more shell variables."
>> https://pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html
>>
>> IFS
>>      Determine the internal field separators used to delimit fields; see Shell
>> Variables.
>>
>> And
>> The shell shall set IFS to <space> <tab> <newline> when it is invoked.
>>
> 
> Per POSIX (https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12),
> commands in a pipeline all run in their own subshell unless your shell has an
> extension to circumvent this. So read won't affect the environment outside the
> pipeline.

For the avoidance of doubt, they mean here that such an extension is 
permissible, if shells want to implement that it's fine, even in a 
default mode. Some POSIX-conforming shells do that. Portable scripts can 
neither assume that commands in a pipeline are, nor that they are not, 
executed in a subshell environment. busybox could add this, if wanted, 
as part of the many bash extensions it already adds to ash.

It is difficult to implement correctly in a way that plays nicely with 
job control though, and I do not know of any shell that has tried to 
make that work. In bash, the pipeline behaviour is controlled by the 
lastpipe option, except that because of this issue the lastpipe option 
is simply ignored when job control is active. Oversimplified, that means 
it works in scripts but not in interactive mode.

> The usual way to solve this is:
>> read a b <<EOF
> $(echo 12 34)
> EOF
>> echo "$a" "$b"

There are two good workarounds. One is yours, which ensures read a b is 
not executed in a subshell environment. Depending on the use case, 
another good alternative is

echo 12 34 | {
   read a b
   echo "'${a}''${b}'"
}

This still executes `read a b` in a subshell environment, but lets the 
following commands that use $a and $b also execute in that same subshell 
environment. This workaround can be used when the following commands do 
not need to read from the original stdin.

Cheers,
Harald van Dijk


More information about the busybox mailing list