在这个BASH片段中,行开头的感叹号是什么?

cal*_*-io 6 bash shell

我理解C-shell和BASH中的历史扩展,但是我不明白为什么在read我看到的某些来源的代码片段中使用了该命令行的感叹号:

#!/bin/bash

set -e

. "$(dirname "$0")/includes.sh"

! read -d '' SOME_VAR <<"EOT"
  some ASCII art
EOT

echo -e "\033[95m$SOME_VAR\033[0m"
Run Code Online (Sandbox Code Playgroud)

你为什么要否定read命令的返回值(我认为这是它的影响,而不是历史扩展)?除了内存外,是否有任何可能的错误情况?我唯一能想到的就是EINTR,我认为这将是一个中止条件(SIGINTSIGHUP).为什么你会引用起始heredoc标记(EOT在这种情况下),而不是结束标记?

它来自一个主要的开源项目,所以我猜测作者有一些理由这样做,我无法辨别.

Kei*_*son 9

set -e如果管道返回非零退出状态(基本上如果命令失败),该命令告诉bash退出.

!否定了退出状态,但它也抑制的效果set -e.这个想法是,如果一个命令作为一个条件的一部分被执行,你不想终止shell.如果它在前面!,则shell有效地假定它作为条件执行(即使结果被忽略).

引用bash手册:

如果失败的命令是紧跟在'while'或'until'关键字之后的命令列表的一部分,在'if'语句中的测试的一部分,在'&&'中执行的任何命令的一部分,则shell不会退出'||' 列表除了最后的'&&'或'||'之外的命令,管道中的任何命令但是最后一个命令,或者命令的返回状态是否被'!'反转.

https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html

(你是正确的,!在这种情况下,它与历史替换无关.)

read内置的返回码是

零,除非遇到文件结束,read超时(在这种情况下它大于128),发生变量赋值错误,或者提供无效的文件描述符作为-u的参数.

这里的相关案例是文件结尾.重定向的输入read使用<<EOT(和禁用使用正常终止-d '')意味着该read命令将遇到结束文件,这会导致它返回一个非0状态.在!从中止所述脚本(但该值仍赋给防止此$SOME_VAR).