我理解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"
为什么要否定read
命令的返回值(我认为这是影响,而不是历史扩展)?除了内存外,是否有任何可能的错误情况?我能想到的唯一一个是EINTR
,我认为这将是一个中止条件(SIGINT
或SIGHUP
)。为什么你会引用起始heredoc
标记(在这种情况下为EOT
),而不是结尾标记?
这是来自一个主要的开源项目,所以我猜测作者有一些理由这样做,我无法辨别。
答案 0 :(得分:9)
如果管道返回非零退出状态(基本上如果命令失败),set -e
命令告诉bash退出。
!
否定退出状态,但它也会抑制set -e
的效果。这个想法是,如果一个命令作为一个条件的一部分被执行,你不想终止shell。如果它前面有!
,那么shell实际上假定它作为条件执行(即使结果被忽略)。
引用bash手册:
如果失败的命令是shell的一部分,则shell不会退出 命令列表紧跟在'while'或'until'关键字之后,部分 'if'语句中的测试,是在a中执行的任何命令的一部分 '&安培;&安培;'或'||'列表除了最后的'&amp;&amp;'之后的命令或'||', 管道中的任何命令,但是最后一个,或者命令的返回 状态正在以'!'反转。
https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
(在这种情况下,!
与历史替换无关,这是正确的。)
read
内置的返回码是
零,除非遇到文件结尾,
的参数read
次超时(在这种情况下它是 大于128),发生变量赋值错误, 或者提供了无效的文件描述符作为-u。
此处的相关案例是文件结尾。使用read
重定向<<EOT
的输入(并使用-d ''
禁用正常终止)意味着read
命令将遇到文件结束,这将导致它返回非零状态。 !
阻止此操作中止脚本(但该值仍分配给$SOME_VAR
)。