【问题标题】:How can `$?` after while loop not be a value that would have terminated the while loop?while 循环之后的 `$?` 怎么可能不是会终止 while 循环的值?
【发布时间】:2023-11-04 07:19:01
【问题描述】:

我在 bash 函数中有这个代码片段:

while ! mkdir lock ; do
    inotifywait -t $WAIT_TIMEOUT -e delete_self lock
done
local es=$?
if (( $es != 0 )); then
    echo "Checkpoint A"
    exit $es
fi

我认为检查点 A 将完全无法访问(因为成功的 mkdir 肯定是 while 循环终止时执行的最后一个命令)。

但是,我发现有时会到达检查点 A。即使在原则上,这怎么可能?

【问题讨论】:

  • (除此之外:您使用基于目录存在的锁定而不是flock 的任何特殊原因?后者不仅代码更少,而且——更重要的是——在进程时自动解锁保持锁定 FD 退出,即使是在断电或其他不干净/意外情况下)。
  • (第二点:您可以考虑无条件引用您的展开式,即使您知道值内没有空格。-t "$WAIT_TIMEOUT" 将允许在值意外未设置时提供更有用的错误消息-t $WAIT_TIMEOUT 将,因为前者确保在槽中传递一个空字符串;更令人惊讶的是非默认 IFS 的行为,如果 @987654327 可能导致 101 的值扩展为两个单独的单词@)。
  • @CharlesDuffy 谢谢你的建议。我是 Linux 的新手,并且不喜欢使用我怀疑“可能有问题”的工具。 this 的语气让我很反感,无论好坏。
  • 该文档的 flock() 部分中没有任何内容是不真实的,但坦率地说,我不认为任何这些问题都使它成为避免使用的工具,除非在非常狭窄的情况下(特别是文件系统未能完全实现相关语义)。坦率地说,如果您担心不标准或行为不端的文件系统语义,即使您使用flock(),旧版本的 NFS 也会出现问题。
  • flock()fcntl(LOCK_*) 锁位于不同的命名空间中,因此不会相互排斥,这也是完全正确的,但这只是当你有两个不同的软件试图相互在使用不同的调用时相互排斥——使用相同调用的单个软件存在问题的唯一情况是,一个软件直接作用于文件系统,而另一个软件通过(旧版本)与同一个文件系统交互NFS。

标签: bash while-loop mkdir exit-code built-in


【解决方案1】:

来自http://pubs.opengroup.org/onlinepubs/9699919799/ 的第 2.9.4 节关于 while 循环的退出状态:

while循环的退出状态应该是最后一次的退出状态 Compound-list-2 已执行,如果未执行,则为零。

(这里,“compound-list-2”是 while 循环的 do...done 部分内的命令。)因此,$? 的值将是最后一次执行 inotifywait 时返回的结果,如果它返回则为零永远不会被调用。

【讨论】: