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


当前回答

一个智能脚本,可以从PIPE和命令行参数读取数据:

#!/bin/bash
if [[ -p /dev/stdin ]]
    then
    PIPE=$(cat -)
    echo "PIPE=$PIPE"
fi
echo "ARGS=$@"

输出:

$ bash test arg1 arg2
ARGS=arg1 arg2

$ echo pipe_data1 | bash test arg1 arg2
PIPE=pipe_data1
ARGS=arg1 arg2

解释:当脚本通过管道接收任何数据时,/dev/stdin(或/proc/self/fd/0)将是到管道的符号链接。

/proc/self/fd/0 -> pipe:[155938]

如果不是,它将指向当前终端:

/proc/self/fd/0 -> /dev/pts/5

bash [[-p选项可以检查它是否是管道。

Cat -读取from stdin。

如果我们在没有stdin的情况下使用cat -,它将永远等待,这就是为什么我们把它放在If条件中。

其他回答

一个智能脚本,可以从PIPE和命令行参数读取数据:

#!/bin/bash
if [[ -p /dev/stdin ]]
    then
    PIPE=$(cat -)
    echo "PIPE=$PIPE"
fi
echo "ARGS=$@"

输出:

$ bash test arg1 arg2
ARGS=arg1 arg2

$ echo pipe_data1 | bash test arg1 arg2
PIPE=pipe_data1
ARGS=arg1 arg2

解释:当脚本通过管道接收任何数据时,/dev/stdin(或/proc/self/fd/0)将是到管道的符号链接。

/proc/self/fd/0 -> pipe:[155938]

如果不是,它将指向当前终端:

/proc/self/fd/0 -> /dev/pts/5

bash [[-p选项可以检查它是否是管道。

Cat -读取from stdin。

如果我们在没有stdin的情况下使用cat -,它将永远等待,这就是为什么我们把它放在If条件中。

因为我上当了,我想留个便条。 我发现了这个线程,因为我必须重写一个旧的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

Use

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

你可以像这样诱使read从管道中接受:

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

或者写一个这样的函数:

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

但这没有意义——你的可变任务可能不会持久!管道可以生成子shell,其中环境是按值继承的,而不是按引用继承的。这就是为什么read不打扰管道的输入——它是未定义的。

仅供参考,http://www.etalabs.net/sh_tricks.html是一个漂亮的cruft收集必要的战斗奇怪和不兼容的伯恩炮弹,sh。

这是另一种选择

$ read test < <(echo hello world)

$ echo $test
hello world

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

相反,尝试:

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