为什么非交互式 bash 会话中的 运行 gradlew 会关闭会话的标准输入?

Why does running gradlew in a non-interactive bash session closes the session's stdin?

我注意到在 CI 系统中使用 gradlew 时脚本提前成功退出这个奇怪的问题。以下步骤有助于概括这一点。

  1. 创建名为 script 的文件,内容为:

    ./gradlew
    echo DONE
    
  2. 从某处随机gradlew

  3. 运行 cat script | bash

注意 DONE 永远不会出现

AFAICT,运行 bash 非交互地导致 gradlew 末尾的 exec java blah 以某种方式允许 java 关闭标准输入并且永远不允许要从脚本中读取的 echo DONE 通过标准输入从 cat 读取。支持这一点的事实是:

如果你有一个 exec something 某处(在你的情况下 gradlew 内),你正在用其他东西(java 替换当前过程映像(bash) ).

来自help exec

exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
Replace the shell with the given command.

所以问题不在于 stdin 正在关闭,而是新进程 (java) 将成为读取该输入 ("echo DONE") 并且可能什么都不做。


举例说明

考虑这个 script.sh:

#!/bin/bash

echo Hello
exec cat
echo World

如果你执行它为 cat:

提供一些输入
$ ./script.sh <<< "Nice"
Hello
Nice

您可能还希望屏幕上打印 World 这个词...错了!
这里没有任何反应,因为在 exec 命令之后执行了任何其他操作。

现在,如果您将脚本通过管道传输到 bash:

$ cat script.sh | bash
Hello        <- bash interpreted "echo Hello" and printed Hello
echo World   <- cat read "echo World" and printed it (no interpertation ocurred)

在这里您可以清楚地看到正在运行的过程图像替换