Shell 为什么管道后的回显返回值($?)总是返回;0“;

Shell 为什么管道后的回显返回值($?)总是返回;0“;,shell,echo,pipeline,Shell,Echo,Pipeline,我意识到这一事实,但我不知道为什么: cat abc | echo $? 如果abc不存在,但上面的命令仍然返回0。有人知道为什么吗 回声$?将给出以前执行的命令的输出,而不是管道命令的输出。那么,您将始终获得echo$?即使命令在管道之前失败,也为0。它与cat abc无关,而是与您执行的上一个命令有关。因此,执行cat abc | echo$?时得到的代码告诉您历史记录中的上一个命令是否成功 从manbash: 特殊参数 ?-扩展到最近执行的前台管道的退出状态 所以当你这样做的时候: ca

我意识到这一事实,但我不知道为什么:

cat abc | echo $?

如果
abc
不存在,但上面的命令仍然返回
0
。有人知道为什么吗

回声$?将给出以前执行的命令的输出,而不是管道命令的输出。那么,您将始终获得echo$?即使命令在管道之前失败,也为0。

它与
cat abc
无关,而是与您执行的上一个命令有关。因此,执行
cat abc | echo$?
时得到的代码告诉您历史记录中的上一个命令是否成功

manbash

特殊参数

-扩展到最近执行的前台管道的退出状态

所以当你这样做的时候:

cat abc | echo $?
echo$?
指的是您以前使用的命令,而不是
cat abc

例子 所以

之所以必须采用这种方式,是因为管道是由同时运行的进程组成的
cat
的退出代码不可能作为参数传递给
echo
,因为参数是在命令开始运行时设置的,并且
echo
cat
完成之前开始运行

echo
不从stdin获取输入,因此管道字符右侧的
echo
总是错误的

更新:

既然现在很清楚你在问一个真正的问题,而不仅仅是误解你所看到的,我自己也试过了。我从我尝试的大多数shell(dash、zsh、pdksh、posh和Bash4.2.37)中得到了我认为正确的结果(1),但从Bash4.1.10和ksh(JM93U+2012-02-29版)中得到了0

我假设bash在不同版本之间的行为变化是有意的,而4.1.x行为被认为是一个bug。如果你仔细看的话,你可能会在变更日志中找到它。我不知道ksh

csh和tcsh(用
$status
代替
$?
)也表示0,但我敢打赌没有人关心这一点

邀请具有更大外壳集合的人员进行测试:

for sh in /bin/sh /bin/ksh /bin/bash /bin/zsh ...insert more shells here...; do
  echo -n "$sh "
  $sh -c 'false;true|echo $?'
done

将输出从“cat abc”传输到“echo$?”,这不是您想要的。 您想回显“cat”的退出代码

cat abc; echo $?

这就是你想要的。如果可以的话,也可以简单地写两行。

IMHO,OP会问“为什么cat不执行上一个命令”?(在echo…;)之前)您是否询问为什么
echo$?
返回0,或者为什么它输出字符串
0
?它返回0,因为它成功了。它输出零,因为它的参数是字符串
0
,这是shell将
$?
扩展到的,这是因为在此之前的命令(简单命令或管道或列表)返回了0。感谢您的响应,您是对的,我知道,我只是想知道管道发生了什么。为什么我的测试和你的不同?我的试验台是CentOS 6.4<代码>-bash-4.1$cat a-bash-4.1$echo$?0-bash-4.1$cata-bash-4.1$cata | echo$?0-bash-4.1$cat abc cat:abc:没有这样的文件或目录-bash-4.1$echo$?1-bash-4.1$cat abc cat:abc:没有这样的文件或目录-bash-4.1$cat abc | echo$?0 cat:abc:没有这样的文件或目录Uhms,因此您将获得
0
,即使前面的命令是对不存在的文件的
cat
。你的系统是什么?我试过GNUBash,版本4.2.45(1)-发布版(x86_64-pc-linux-GNU),Ubuntu 13.10。是的,我的测试平台是CentOS 6.4,GNUBash,版本4.1.2(1)-发布版(x86_64-redhat-linux-GNU)。我用bash版本4.2试过另一个测试平台,它的结果和你说的一样,现在一切都清楚了。那么你是说
echo$?
显示上一个命令返回值的值,如下面的答案所示?但是为什么我的测试结果总是返回“0”?非常感谢您的详细解释和测试!现在我明白了。
for sh in /bin/sh /bin/ksh /bin/bash /bin/zsh ...insert more shells here...; do
  echo -n "$sh "
  $sh -c 'false;true|echo $?'
done
cat abc; echo $?