I am trying to get bash to process data from stdin that gets piped into, but no luck. What I mean is none of the following work:
echo "hello world" | test=($(< /dev/stdin)); echo test=$test
test=
echo "hello world" | read test; echo test=$test
test=
echo "hello world" | test=`cat`; echo test=$test
test=
where I want the output to be test=hello world
. I've tried putting "" quotes around "$test"
that doesn't work either.
Because I fall for it, I would like to drop a note. I found this thread, because I have to rewrite an old sh script to be POSIX compatible. This basically means to circumvent the pipe/subshell problem introduced by POSIX by rewriting code like this:
into:
And code like this:
into:
But the latter does not behave the same on empty input. With the old notation the while loop is not entered on empty input, but in POSIX notation it is! I think it's due to the newline before EOF, which cannot be ommitted. The POSIX code which behaves more like the old notation looks like this:
In most cases this should be good enough. But unfortunately this still behaves not exactly like the old notation if some_command prints an empty line. In the old notation the while body is executed and in POSIX notation we break in front of the body.
An approach to fix this might look like this:
if you want to read in lots of data and work on each line separately you could use something like this:
if you want to split the lines up into multiple words you can use multiple variables in place of x like this:
alternatively:
But as soon as you start to want to do anything really clever with this sort of thing you're better going for some scripting language like perl where you could try something like this:
There's a fairly steep learning curve with perl (or I guess any of these languages) but you'll find it a lot easier in the long run if you want to do anything but the simplest of scripts. I'd recommend the Perl Cookbook and, of course, The Perl Programming Language by Larry Wall et al.
In my eyes the best way to read from stdin in bash is the following one, which also lets you work on the lines before the input ends:
How about this:
The following code:
will work too, but it will open another new sub-shell after the pipe, where
won't.
I had to disable job control to make use of chepnars' method (I was running this command from terminal):
Bash Manual says:
Note: job control is turned off by default in a non-interactive shell and thus you don't need the
set +m
inside a script.This is another option