我试图让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”周围加上“”引号,但也不起作用。
我想要类似的东西——一个可以解析字符串的函数,可以作为参数或管道传递。
我提出了一个解决方案如下(工作作为#!/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结束输入。
我想要类似的东西——一个可以解析字符串的函数,可以作为参数或管道传递。
我提出了一个解决方案如下(工作作为#!/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结束输入。
一个智能脚本,可以从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