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

Makefile:如何运行bash脚本并忽略其退出状态?,bash,makefile,gnu-make,Bash,Makefile,Gnu Make,最小化问题的测试用例: 我有以下Makefile: test.sh包含 当我运行make测试并按Ctrl+C退出bash read时,make将发出 Makefile:2: recipe for target 'test' failed make: *** [test] Interrupt 如何让make忽略脚本的退出状态?在脚本之后,我已经有了| | true,这通常足以让make继续运行,但由于某种原因,SIGINT中断读取将导致make在这种情况下表现不同 我正在寻找一个通用的答案,它适

最小化问题的测试用例:

我有以下Makefile:

test.sh包含

当我运行make测试并按Ctrl+C退出bash read时,make将发出

Makefile:2: recipe for target 'test' failed
make: *** [test] Interrupt
如何让make忽略脚本的退出状态?在脚本之后,我已经有了| | true,这通常足以让make继续运行,但由于某种原因,SIGINT中断读取将导致make在这种情况下表现不同


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

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


无法使忽略^C操作;无论何时在终端上按^C,make都将停止。

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

无法使忽略^C操作;只要在终端上按^C,make就会停止。

ctrl+C会向程序发送一个信号,告诉它停止。您需要的是ctrl+d,它在传输结束时发送信号EOT。您需要发送ctrl+d两次,除非您在行首

一些文本 或

一些文本 ctrl+c向程序发送一个信号,告诉它停止。您需要的是ctrl+d,它在传输结束时发送信号EOT。您需要发送ctrl+d两次,除非您在行首

一些文本 或

一些文本
我找到了一个让这一切顺利的方法。这有点棘手,所以我将首先解释解决方案。重要的是要理解Ctrl+C是由您的终端处理的,而不是像我之前所想的那样由终端中当前正在运行的进程处理的。当终端捕捉到您的Ctrl+C时,它将检查前台进程组,然后立即向该组中的所有进程发送SIGINT。当您通过Makefile运行某个程序并按Ctrl+C时,SIGINT将立即发送到Makefile及其启动的所有进程,因为这些进程都属于前台进程组。GNU Make通过等待任何当前执行的子进程停止,然后通过消息退出来处理SIGINT

Makefile:<line number>: recipe for target '<target>' failed
make: *** [<target>] Interrupt
test.sh包含

set-m触发创建一个新的前台进程组,int_处理程序负责在退出时返回成功的退出代码。当然,如果您希望有一些其他退出代码,但在Ctrl+C上为零,请随意选择任何合适的值。如果希望使用更短的内容,则子脚本只需要trap“exit 0”INT,而不需要单独的函数和设置

有关更多信息:


我找到了一个让这一切顺利的方法。这有点棘手,所以我将首先解释解决方案。重要的是要理解Ctrl+C是由您的终端处理的,而不是像我之前所想的那样由终端中当前正在运行的进程处理的。当终端捕捉到您的Ctrl+C时,它将检查前台进程组,然后立即向该组中的所有进程发送SIGINT。当您通过Makefile运行某个程序并按Ctrl+C时,SIGINT将立即发送到Makefile及其启动的所有进程,因为这些进程都属于前台进程组。GNU Make通过等待任何当前执行的子进程停止,然后通过消息退出来处理SIGINT

Makefile:<line number>: recipe for target '<target>' failed
make: *** [<target>] Interrupt
test.sh包含

set-m触发创建一个新的前台进程组,int_处理程序负责在退出时返回成功的退出代码。当然,如果您希望有一些其他退出代码,但在Ctrl+C上为零,请随意选择任何合适的值。如果希望使用更短的内容,则子脚本只需要trap“exit 0”INT,而不需要单独的函数和设置

有关更多信息:


从技术上讲,Ctrl+C将被发送到脚本,而不是make脚本。额外的测试表明,如果我在test.sh中捕获SIGINT,我可以根据需要延迟SIGINT。但是,即使test.sh稍后调用exit 0,最终结果也不会从外壳返回exit值为0的结果,而是此时的SIGINT。因此,似乎没有办法不让make早晚看到SIGINT。正如我所说的,SIGINT总是立即发送给make。您看到的效果是,当make接收到信号时,它不会立即退出,而是等待其子进程死亡并在其之后清理,然后退出自身。因此,如果您延迟脚本的退出,也会延迟make的退出。但是,make已经收到了信号,他会死的。我会改正的。我从ManBash部分信号中找到了对整个过程的很好的解释。bash文档
使用当前终端进程组ID来描述有时仅称为进程组的consept。当终端接收到Ctrl+C时,它将自动向前台进程组中的所有进程发送SIGINT。重要的一点是,如果bash正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前,陷阱将不会执行child无法阻止信号传递,只能延迟处理。事实证明,这毕竟是可以做到的,请参见下面我的回答:从技术上讲,Ctrl+C将发送到脚本,而不是make脚本。额外的测试表明,如果我在test.sh中捕获SIGINT,我可以根据需要延迟SIGINT。但是,即使test.sh稍后调用exit 0,最终结果也不会从外壳返回exit值为0的结果,而是此时的SIGINT。因此,似乎没有办法不让make早晚看到SIGINT。正如我所说的,SIGINT总是立即发送给make。您看到的效果是,当make接收到信号时,它不会立即退出,而是等待其子进程死亡并在其之后清理,然后退出自身。因此,如果您延迟脚本的退出,也会延迟make的退出。但是,make已经收到了信号,他会死的。我会改正的。我从ManBash部分信号中找到了对整个过程的很好的解释。bash文档使用当前的终端进程组ID来描述concept,它有时被称为进程组。当终端接收到Ctrl+C时,它将自动向前台进程组中的所有进程发送SIGINT。重要的一点是,如果bash正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前,陷阱将不会执行孩子不能阻止信号的传递,只能延迟处理。事实证明,这终究是可以做到的,见下面我的答案:
Makefile:<line number>: recipe for target '<target>' failed
make: *** [<target>] Interrupt
test:
    bash -c 'set -m; bash ./test.sh'
    echo OK
#!/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