我试图让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”周围加上“”引号,但也不起作用。


当前回答

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

我试着减少

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

从不同的输入中得到特定的一行。 所以我可以输入…

cat program_file.c | line 34

所以我需要一个小shell程序能够从stdin读取。就像你一样。

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" | { test=$(< /dev/stdin); echo "test=$test"; };

输出为:

test = hello world

在管道后面需要用大括号括起要测试的赋值和回显。

如果没有大括号,test的赋值(在管道之后)在一个shell中,而echo "test=$test"在一个单独的shell中,该shell不知道该赋值。这就是为什么在输出中得到"test="而不是"test=hello world"。

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

while read LINE; do
    echo $LINE
done < /dev/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结束输入。

因为我上当了,我想留个便条。 我发现了这个线程,因为我必须重写一个旧的sh脚本 POSIX兼容。 这基本上意味着绕过POSIX引入的管道/子shell问题,重写如下代码:

some_command | read a b c

成:

read a b c << EOF
$(some_command)
EOF

代码是这样的:

some_command |
while read a b c; do
    # something
done

成:

while read a b c; do
    # something
done << EOF
$(some_command)
EOF

但后者在空输入时表现不一样。 使用旧的符号,while循环不会在空输入时输入, 但在POSIX符号中它是! 我认为这是由于EOF之前的换行, 这一点不容忽视。 POSIX代码的行为更像旧的符号 看起来是这样的:

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

在大多数情况下,这就足够了。 但不幸的是,这仍然不完全像以前的符号 如果some_command打印空行。 在旧的表示法中,执行while主体 在POSIX符号中,我们在主体前面中断。

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

while read a b c; 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