Makefile:如何 运行 bash 脚本并忽略其退出状态?

Makefile: how to run bash script and ignore its exit status?

问题的最小化测试用例:

我关注Makefile:

test:
    bash test.sh || true
    echo OK

并且 test.sh 包含

#!/bin/bash
while read -p "Enter some text or press Ctrl+C to exit > " input
do
    echo "Your input was: $input"
done

当我 运行 make test 并按 Ctrl+C 退出 bash read make 将发出

Makefile:2: recipe for target 'test' failed
make: *** [test] Interrupt

如何告诉 make 忽略脚本的退出状态? 我已经在脚本之后有 || true 通常足以获取make 继续,但由于某种原因,信号中断 read 将导致 make 在这种情况下表现不同。

我正在寻找适用于 bash 中的 while read 循环以外的进程的通用答案。

这与脚本的退出状态无关。当您按下 ^C 时,您正在向 make 程序发送一个中断信号,而不仅仅是您的脚本。这会导致 make 程序停止,就像 ^C 总是那样。

没有办法让 make 忽略 ^C 操作;每当您在终端按 ^C 时,make 就会停止。

ctrl+c 向程序发送一个信号,告诉它停止。你想要的是 ctrl+d 发送信号 EOT(传输结束)。你需要发送 ctrl+d 两次,除非你在一行的开头。

some text<c-d><c-d>

some text<return>
<c-d>

我找到了一种方法来完成这项工作。这有点棘手,所以我会先解释解决方案。重要的是要了解 Ctrl+C 由您的 终端 处理,而不是像我之前认为的那样由终端中当前的 运行ning 进程处理。当终端捕捉到您的 Ctrl+C 时,它将检查 前台进程组 ,然后立即将 SIGINT 发送到该组中的 all 进程.当您通过 Makefile 运行 某些东西并按 Ctrl+C 时,SIGINT 会立即发送到 Makefile 和它启动的所有进程,因为它们都属于前台进程组。 GNU Make 通过 等待 处理 SIGINT 任何当前执行的 child 进程停止然后退出并显示消息

Makefile:<line number>: recipe for target '<target>' failed
make: *** [<target>] Interrupt

如果 child 以 non-zero 退出状态退出。如果 child 自己处理 SIGINT 并以状态 0 退出,GNU Make 将静默退出。许多程序在 SIGINT 上通过状态代码 130 退出,但这不是必需的。此外,内核和 wait() C API 接口可以区分状态码 130 和状态码 130 + child 收到 SIGINT 所以如果 Make 想在这些情况下表现不同,无论退出代码如何,都有可能。 bash 不支持测试 child 进程 SIGINT 状态,但仅支持退出状态代码。

解决方案是设置进程,以便您的前台进程组不包含 GNU Make,而您希望专门处理 Ctrl+C。但是,由于 POSIX 没有定义创建任何进程组的工具,我们必须使用 bash 特定技巧:使用 bash 作业控制来触发 bash 创建一个新进程组。请注意,这会导致一些 side-effects(例如 stdin 和 stdout 的行为略有不同),但至少对我来说已经足够好了。

操作方法如下:

我有以下Makefile(像往常一样,嵌套行必须有制表符而不是空格):

test:
    bash -c 'set -m; bash ./test.sh'
    echo OK

并且 test.sh 包含

#!/bin/bash
int_handler()
{
    printf "\nReceived SIGINT, quitting...\n" 1>&2
    exit 0
}
trap int_handler INT 

while read -p "Enter some text or press Ctrl+C to exit > " input
do
    echo "Your input was: $input"
done

set -m 触发创建一个新的前台进程组,int_handler 负责在退出时返回成功的退出代码。当然,如果您想要一些其他退出代码但 Ctrl+C 为零,请随意选择任何合适的值。如果你想要更短的东西,child 脚本只需要 trap 'exit 0' INT 而不是单独的函数和设置。

更多信息: