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
而不是单独的函数和设置。
更多信息:
问题的最小化测试用例:
我关注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
而不是单独的函数和设置。
更多信息: