为什么 if 表达式取反后退出代码会重置

问题描述 投票:0回答:1

我最近偶然发现了一些似乎没有意义的事情:

echo "Hit ENTER to continue or CTRL+D to abort."
read -s -t 3 || {
    case $? in
        0) echo "should not occur"; ;;
        1) echo "CTRL+D"; ;;
        *) echo "Timeout"; ;;
    esac
}

按预期工作(CTRL+D/EOF 和超时均被捕获),但是

echo "Hit ENTER to continue or CTRL+D to abort."
if ! read -s -t 3; then
    case $? in
        0) echo "should not occur"; ;;
        1) echo "CTRL+D"; ;;
        *) echo "Timeout"; ;;
    esac
fi

NOT 是否按预期工作(

$?
始终为 0)。

为什么(以及如何)在执行

$?
的身体之前重置
if

有趣的是,倒置的结构:

echo "Hit ENTER to continue or CTRL+D to abort."
if read -s -t 3; then
    :
else
    case $? in
        0) echo "should not occur"; ;;
        1) echo "CTRL+D"; ;;
        *) echo "Timeout"; ;;
    esac
fi

确实按预期工作。这表明

!
可能对此负责,但我找不到任何文档来支持这一点。

Bash 版本:5.1.16

bash
1个回答
0
投票

!
不会重置退出代码。它否定后面命令的退出代码并生成管道的最终退出代码。

Bash 文档的 “3.2.3 Pipelines” 节对此进行了解释(它也在

man bash
上,但没有章节编号)。

管道的格式是

[time [-p]] [!] command1 [ | or |& command2 ] ...

...

管道的退出状态是管道中最后一个命令的退出状态[...]。如果保留字

!
在管道之前,则退出状态是上述退出状态的逻辑非。

!
不是
if
语句语法的一部分。
if
语句的语法是:

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

命令列表是一个序列或一个或多个管道,由运算符

;
&
&&
||
之一分隔。通常,单个管道用于描述
if
语句中的条件。

因为

!
是管道的一部分,所以您获得的结果也可以在不使用
if
语句的情况下进行描述:

$ echo foo
foo
$ echo $?
0
$ ! echo foo
foo
$ echo $?
1
© www.soinside.com 2019 - 2024. All rights reserved.