【问题标题】:Why does cat exit a shell script, but only when it's fed by a pipe?为什么 cat 退出 shell 脚本,但只有当它由管道提供时?
【发布时间】:2014-11-01 05:18:29
【问题描述】:

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

【问题讨论】:

    标签: shell sed sh cat


    【解决方案1】:

    不,$1 不是“foo”。 $1 是

    即,未定义/无。

    与编程语言不同,shell 中的变量被相当笨拙地替换,并且生成的命令以文本方式执行(嗯,有点像)。在这种情况下,“cat $1”变成了“cat”,它将从标准输入中获取输入。这对您的执行非常方便,因为您已经通过管道在标准输入上提供了“foo”!

    看看发生了什么?

    sed 同样会从标准输入读取,但已经在流的末尾,所以退出。

    【讨论】:

    • 好的,但是我怎么知道通过标准输入发送了什么?有那个环境变量吗?
    • 不。您可能会玩一些有趣的游戏,但通常只有流的消费者才能看到流中的内容。把它想象成一个字面管道。你在一端塞一些东西,它们从另一端出来。里面发生的事情不透明,你看不到。
    • 好吧,我可以使用 read 命令将 stdin 分配给一个 var,然后从那里开始。我已经更新了我的问题...
    【解决方案2】:

    当您不给cat 提供参数时,它会从标准输入读取。当$1 没有给出时,cat $1 与简单的cat 相同,它会读取您输入的文本 (cat foo.txt)。

    然后sed 命令运行,和cat 一样,它从标准输入读取,因为它没有文件名参数。 cat 已经消耗了所有的标准输入。没有什么要读的了,所以sed 不打印任何东西就退出了。

    【讨论】:

      猜你喜欢
      • 2018-05-27
      • 2012-04-19
      • 2018-11-28
      • 2010-12-07
      • 2012-12-27
      • 1970-01-01
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多