Linux 从管道将值读入 shell 变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2746553/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:59:37  来源:igfitidea点击:

Read values into a shell variable from a pipe

linuxbashpipe

提问by ldog

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:

我试图让 bash 处理来自 stdin 的数据,这些数据通过管道输入,但没有运气。我的意思不是以下工作:

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.

我希望输出在哪里test=hello world。我试过在周围加上 "" 引号"$test"也不起作用。

采纳答案by yardena

Use

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

You cantrick readinto accepting from a pipe like this:

可以欺骗read从这样的管道接受:

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 readdoesn't bother with input from a pipe - it's undefined.

但是没有意义——你的变量赋值可能不会持久!管道可能会产生一个子外壳,其中的环境是通过值继承的,而不是通过引用继承的。这就是为什么read不用管来自管道的输入的原因——它是未定义的。

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

仅供参考,http://www.etalabs.net/sh_tricks.html是对抗 bourne shell 的古怪和不兼容性所必需的精巧集合,sh。

回答by bta

Piping something into an expression involving an assignment doesn't behave like that.

将某些内容传递到涉及赋值的表达式中并不是那样的行为。

Instead, try:

相反,请尝试:

test=$(echo "hello world"); echo test=$test

回答by mob

The syntax for an implicit pipe from a shell command into a bash variable is

从 shell 命令到 bash 变量的隐式管道的语法是

var=$(command)

or

或者

var=`command`

In your examples, you are piping data to an assignment statement, which does not expect any input.

在您的示例中,您将数据传送到赋值语句,该语句不需要任何输入。

回答by Paused until further notice.

readwon'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不会从管道中读取(或者结果可能会丢失,因为管道创建了一个子外壳)。但是,您可以在 Bash 中使用 here 字符串:

$ read a b c <<< $(echo 1 2 3)
$ echo $a $b $c
1 2 3

But see @chepner's answer for information about lastpipe.

但有关lastpipe.

回答by Nick

if you want to read in lots of data and work on each line separately you could use something like this:

如果你想读入大量数据并分别处理每一行,你可以使用这样的东西:

cat myFile | while read x ; do echo $x ; done

if you want to split the lines up into multiple words you can use multiple variables in place of x like this:

如果要将行拆分为多个单词,可以使用多个变量代替 x,如下所示:

cat myFile | while read x y ; do echo $y $x ; done

alternatively:

或者:

while read x y ; do echo $y $x ; done < myFile

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:

但是一旦你开始想用这种东西做任何真正聪明的事情,你最好使用像 perl 这样的脚本语言,你可以尝试这样的事情:

perl -ane 'print "$F[0]\n"' < myFile

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.

perl(或者我猜这些语言中的任何一种)有一个相当陡峭的学习曲线,但从长远来看,如果你想做最简单的脚本以外的任何事情,你会发现它更容易。我推荐 Perl Cookbook,当然还有 Larry Wall 等人的 The Perl Programming Language。

回答by Steven Penny

This is another option

这是另一种选择

$ read test < <(echo hello world)

$ echo $test
hello world

回答by Mathieu J.

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.

我认为您正在尝试编写一个可以从 stdin 获取输入的 shell 脚本。但是当您尝试使用它进行内联时,您在尝试创建 test= 变量时迷路了。我认为内联执行它没有多大意义,这就是为什么它不能按您期望的方式工作。

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.

所以我需要一个能够从标准输入读取的小型 shell 程序。像你所做地。

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

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

there you go.

你去吧。

回答by djanowski

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

我不是 Bash 专家,但我想知道为什么没有提出这个建议:

stdin=$(cat)

echo "$stdin"

One-liner proof that it works for me:

单行证明它对我有用:

$ fortune | eval 'stdin=$(cat); echo "$stdin"'

回答by jbuhacoff

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".

没有大括号,测试的分配(在管道之后)在一个外壳中,而 echo "test=$test" 位于一个不知道该分配的单独外壳中。这就是为什么你在输出中得到“test=”而不是“test=hello world”的原因。

回答by chepner

bash4.2 introduces the lastpipeoption, which allows your code to work as written, by executing the last command in a pipeline in the current shell, rather than a subshell.

bash4.2 引入了该lastpipe选项,通过在当前 shell 而非子 shell 的管道中执行最后一个命令,允许您的代码按编写的方式工作。

shopt -s lastpipe
echo "hello world" | read test; echo test=$test