Bash脚本,从stdinpipe道读取值

我试图让bash来处理数据从标准input获取pipe道,但没有运气,我的意思是没有以下工作:

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= 

我希望输出成为test=hello world 。 注意我试过在"$test"周围放置“”引号,也不起作用。

使用

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

可以read变成像这样的pipe道接受:

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

甚至写一个这样的函数:

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

但没有意义 – 你的variables分配可能不会持续! 一个pipe道可能产生一个子shell,其中的环境是由值inheritance的,而不是通过引用。 这就是为什么read不会打扰来自pipe道的input – 这是未定义的。

仅供参考, http://www.etalabs.net/sh_tricks.html是一个非常漂亮的集合,用于打击Bourne shell的怪异和不兼容性。

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

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

如果你想将这些行分成多个单词,你可以使用多个variables来代替这个x:

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

或者:

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

但是一旦你开始想要做这样的事情真的很聪明,你最好去像Perl一样的脚本语言,你可以尝试这样的事情:

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

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

read不会从pipe道读取(或者可能由于pipe道创build子shell而丢失结果)。 但是,您可以在Bash中使用这个string:

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

这是另一种select

 $ read test < <(echo hello world) $ echo $test hello world 

我不是Bash的专家,但我想知道为什么没有提出:

 stdin=$(cat) echo "$stdin" 

单线程的certificate,它适用于我:

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

bash 4.2引入了lastpipe选项,它允许你的代码按照写入的方式工作,通过在当前shell的pipe道中执行最后一个命令,而不是一个子shell。

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

从shell命令到bashvariables的隐式pipe道的语法是

 var=$(command) 

要么

 var=`command` 

在你的例子中,你正在将数据传递给一个赋值语句,这个赋值语句没有期望任何input。

第一次尝试非常接近。 这种变化应该工作:

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

输出是:

testing=你好世界

你需要在pipe道后面加上括号,以便将testing任务和回声封装起来。

如果没有大括号,要testing的分配(在pipe道之后)在一个shell中,echo“test = $ test”位于不知道该分配的单独shell中。 这就是为什么你在输出中获得“test =”而不是“test = hello world”的原因。

在我眼中,从bash中读取stdin的最好方法是下面这个,它也可以让你在input结束之前在行上工作:

 while read LINE; do echo $LINE done < /dev/stdin 

将某些东西转换为涉及赋值的expression式并不像那样。

相反,请尝试:

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

以下代码:

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

也会起作用,但是会在pipe道后面打开另一个新的子shell

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

惯于。


我不得不禁用作业控制来使用chepnars的方法(我从terminal运行这个命令):

 set +m;shopt -s lastpipe echo "hello world" | read test; echo test=$test echo "hello world" | test="$(</dev/stdin)"; echo test=$test 

Bash手册说 :

lastpipe

如果设置,并且作业控制未激活 ,则shell将运行当前shell环境中未在后台执行的pipe道的最后一个命令。

注意:默认情况下,非交互式shell中的作业控制是closures的,因此您不需要脚本中的set +m

我想你正在试图写一个可以从stdininput的shell脚本。 但是当你试图把它内联的时候,你试图创buildtest =variables就会迷路了。 我认为这样做是没有道理的,这就是为什么它不能像你期望的那样工作。

我试图减less

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

从各种input中获得特定的线路。 所以我可以键入…

 cat program_file.c | line 34 

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

 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 ~ $ 

你去了

这个怎么样:

 echo "hello world" | echo test=$(cat) 

这是另一种解决scheme,当读取多个variables时,以及当读入variables的数量多于进入pipe道的字数时,也可以使用这种解决scheme。

 eval $(echo hickery dickery dock the mouse | { read ABC ; echo A=\"${A}\" B=\"${B}\" C=\"${C}\" ; }) echo $A hickery echo $B dickery echo $C dock the mouse 

因为我爱上它,所以我想放下一张纸条。 我发现这个线程,因为我必须重写一个旧的sh脚本是POSIX兼容的。 这基本上意味着通过重写这样的代码来规避POSIX引入的pipe道/子shell问题:

 some_command | read abc 

成:

 read abc << EOF $(some_command) EOF 

和这样的代码:

 some_command | while read abc; do # something done 

成:

 while read abc; do # something done << EOF $(some_command) EOF 

但后者在空input上performance不一样。 用旧的表示法,while循环没有被input到空input上,但是在POSIX表示法中它是! 我认为这是由于EOF之前的换行符,这是不能被遗漏的。 performance得更像旧符号的POSIX代码如下所示:

 while read abc; do case $a in ("") break; esac # something done << EOF $(some_command) EOF 

在大多数情况下,这应该足够好。 但不幸的是,如果some_command打印一个空行,这仍然不像旧的表示法。 在旧的记号中,身体被执行,而在POSIX记号中,我们在身体的前面打破。

解决这个问题的方法可能是这样的:

 while read abc; do case $a in ("something_guaranteed_not_to_be_printed_by_some_command") break; esac # something done << EOF $(some_command) echo "something_guaranteed_not_to_be_printed_by_some_command" EOF