Read values into a shell variable from a pipe

2019-01-03 04:11发布

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.

标签: linux bash pipe
14条回答
我欲成王,谁敢阻挡
2楼-- · 2019-01-03 04:18

I think you were trying to write a shell script which could take input from stdin. but while you are trying it to do it inline, you got lost trying to create that test= variable. I think it does not make much sense to do it inline, and that's why it does not work the way you expect.

I was trying to reduce

$( ... | head -n $X | tail -n 1 )

to get a specific line from various input. so I could type...

cat program_file.c | line 34

so I need a small shell program able to read from stdin. like you do.

22:14 ~ $ cat ~/bin/line 
#!/bin/sh

if [ $# -ne 1 ]; then echo enter a line number to display; exit; fi
cat | head -n $1 | tail -n 1
22:16 ~ $ 

there you go.

查看更多
叼着烟拽天下
3楼-- · 2019-01-03 04:19

I'm no expert in Bash, but I wonder why this hasn't been proposed:

stdin=$(cat)

echo "$stdin"

One-liner proof that it works for me:

$ fortune | eval 'stdin=$(cat); echo "$stdin"'
查看更多
够拽才男人
4楼-- · 2019-01-03 04:20

Use

IFS= read var << EOF
$(foo)
EOF

You can trick read into accepting from a pipe like this:

echo "hello world" | { read test; echo test=$test; }

or even write a function like this:

read_from_pipe() { read "$@" <&0; }

But there's no point - your variable assignments may not last! A pipeline may spawn a subshell, where the environment is inherited by value, not by reference. This is why read doesn't bother with input from a pipe - it's undefined.

FYI, http://www.etalabs.net/sh_tricks.html is a nifty collection of the cruft necessary to fight the oddities and incompatibilities of bourne shells, sh.

查看更多
放荡不羁爱自由
5楼-- · 2019-01-03 04:20

The first attempt was pretty close. This variation should work:

echo "hello world" | { test=$(< /dev/stdin); echo "test=$test"; };

and the output is:

test=hello world

You need braces after the pipe to enclose the assignment to test and the echo.

Without the braces, the assignment to test (after the pipe) is in one shell, and the echo "test=$test" is in a separate shell which doesn't know about that assignment. That's why you were getting "test=" in the output instead of "test=hello world".

查看更多
男人必须洒脱
6楼-- · 2019-01-03 04:22

bash 4.2 introduces the lastpipe option, which allows your code to work as written, by executing the last command in a pipeline in the current shell, rather than a subshell.

shopt -s lastpipe
echo "hello world" | read test; echo test=$test
查看更多
三岁会撩人
7楼-- · 2019-01-03 04:28

read won't read from a pipe (or possibly the result is lost because the pipe creates a subshell). You can, however, use a here string in Bash:

$ read a b c <<< $(echo 1 2 3)
$ echo $a $b $c
1 2 3
查看更多
登录 后发表回答