为什么cat会退出shell脚本,但只有当它被管道输入时?

时间:2014-09-08 02:15:18

标签: shell sed sh cat

为什么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'

2 个答案:

答案 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}}退出而不打印任何内容。