为什么cat退出shell脚本,但只有当它由管道提供时?
例如,采用名为“foobar.sh”的shell脚本:
#! /bin/sh
echo $#
echo $@
cat $1
sed -e 's|foo|bar|g' $1
一个名为“foo.txt”的文本文件,其中只包含一行:
foo
现在如果我在命令行输入./foobar.sh foo.txt
,那么我将得到这个预期的输出:
1
foo.txt
foo
bar
但是,如果我输入cat foo.txt | ./foobar.sh
,那么令人惊讶的是我只得到这个输出:
0
foo
我不明白。如果$#
报告的参数数量为零,那么cat $1
如何仍然返回foo
?在这种情况下,为什么sed -e 's|foo|bar|g' $1
没有返回任何内容,因为显然$ 1是foo
?
这似乎非常像一个错误,但我认为这是魔术。请解释一下!
更新
根据给定的答案,以下脚本给出了预期的输出,假设是一行foo.txt:
#! /bin/sh
if [ $# ]
then
yay=$(cat $1)
else
read yay
fi
echo $yay | cat
echo $yay | sed -e 's|foo|bar|g'
答案 0 :(得分:3)
不,$ 1不是" foo"。 $ 1是
即,undefined / nothing。
与编程语言不同,shell中的变量非常笨拙且字面上被替换,并且生成的命令以文本方式执行(好吧,sorta有点)。在这种情况下," cat $ 1"变得只是" cat",它将从stdin获取输入。这是非常方便您执行的,因为您已经提供了" foo"通过你的烟斗在stdin上!
看看发生了什么?
sed同样会从stdin读取,但已经在流的末尾,所以退出。
答案 1 :(得分:2)
当你不向cat
提出论据时,它会从标准输入读取。如果$1
未被cat $1
提供,则cat
与简单cat foo.txt
相同,后者会读取您在(sed
)中传输的文字。
然后cat
命令运行,与cat
相同,它从stdin读取,因为它没有文件名参数。 sed
已经消耗了所有标准输入。没有什么可以阅读的,所以{{1}}退出而不打印任何内容。