我试图让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=

我希望输出为test=hello world。我尝试在“$test”周围加上“”引号,但也不起作用。


当前回答

问题是如何捕获命令的输出,以保存在变量中,以便稍后在脚本中使用。我可能会重复一些之前的答案,但我试着把我能想到的所有答案排列起来进行比较和评论,所以请容忍我。

直观的构造

echo test | read x
echo x=$x

在Korn shell中是有效的,因为ksh已经实现了管道系列中的最后一个命令是当前shell的一部分。前面的管道命令是子shell。相反,其他shell将所有管道命令定义为子shell,包括最后一个。 这正是我更喜欢ksh的原因。 但必须复制与其他shell, bash f.ex。,则必须使用另一种结构。

要捕获1个值,这个构造是可行的:

x=$(echo test)
echo x=$x

但这只能满足收集1个值以供以后使用的需求。

为了捕获更多的值,这个构造是有用的,在bash和ksh中工作:

read x y <<< $(echo test again)
echo x=$x y=$y

有一个变种,我注意到在bash工作,但不是在ksh:

read x y < <(echo test again)
echo x=$x y=$y

<<< $(…)是一个here-document变体,它提供了标准命令行的所有元处理。< <(…)是文件替换操作符的输入重定向。

我现在在所有脚本中都使用“<<< $(”,因为它似乎是shell变量之间最可移植的构造。我有一套工具,可以在任何Unix风格的作业中随身携带。

当然,有一个普遍可行但粗糙的解决方案:

command-1 | {command-2; echo "x=test; y=again" > file.tmp; chmod 700 file.tmp}
. ./file.tmp
rm file.tmp
echo x=$x y=$y

其他回答

在我看来,在bash中读取stdin的最好方法是下面的方法,它还可以让你在输入结束之前处理这些行:

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

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

stdin=$(cat)

echo "$stdin"

一行程序证明它对我有效:

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

将一些内容输出到包含赋值的表达式中就不是这样了。

相反,尝试:

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

我想要类似的东西——一个可以解析字符串的函数,可以作为参数或管道传递。

我提出了一个解决方案如下(工作作为#!/bin/sh和作为#!/bin/bash)

#!/bin/sh

set -eu

my_func() {
    local content=""
    
    # if the first param is an empty string or is not set
    if [ -z ${1+x} ]; then
 
        # read content from a pipe if passed or from a user input if not passed
        while read line; do content="${content}$line"; done < /dev/stdin

    # first param was set (it may be an empty string)
    else
        content="$1"
    fi

    echo "Content: '$content'"; 
}


printf "0. $(my_func "")\n"
printf "1. $(my_func "one")\n"
printf "2. $(echo "two" | my_func)\n"
printf "3. $(my_func)\n"
printf "End\n"

输出:

0. Content: ''
1. Content: 'one'
2. Content: 'two'
typed text
3. Content: 'typed text'
End

对于最后一种情况(3.),您需要键入,按enter和CTRL+D结束输入。

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

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

如果你想把这些行分成多个单词,你可以使用多个变量来代替x,就像这样:

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

另外:

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

但是一旦你开始想要做一些真正聪明的事情,你最好选择一些脚本语言,比如perl,你可以尝试这样的事情:

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

使用perl(或者我猜这些语言中的任何一种)有一个相当陡峭的学习曲线,但如果您想做任何事情,而不是最简单的脚本,从长远来看,您会发现它要容易得多。我推荐《Perl烹饪书》,当然还有Larry Wall等人写的《Perl编程语言》。