在运行进程中按 Ctrl+C 后,通过脚本打开的 Shell 选项卡挂起

在运行进程中按 Ctrl+C 后,通过脚本打开的 Shell 选项卡挂起

我有以下脚本:

#!/usr/bin/env zsh
START_FOREMAN='/usr/bin/zsh -c "source /home/user/.zshrc; foreman start" zsh'
xfce4-terminal --tab -H -T app-server --working-directory=/home/user/git/app -e $START_FOREMAN

xfce4-terminal --tab -H -T api-server --working-directory=/home/user/git/api -e $START_FOREMAN

这两个命令都取决于环境设置(chruby配置),所以我./zshrc在运行之前获取我的文件foreman宝石。

但是,如果我运行此命令,然后尝试Ctrl+C退出长时间运行的进程 - shell 会结束,并且我永远不会得到提示。

注意:在同一目录中的新 shell 中运行 foreman start 后会向我返回提示符Ctrl+C

编辑:人们似乎对工头的问题感到困扰,但我认为情况并非如此,因为这与运行./gradlew bootRun或任何长时间运行的流程有关。

工头肯定退出:

^CSIGINT received
16:13:09 system       | sending SIGTERM to all processes
16:13:10 api.1 | exited with code 130

与 Spring boot 一样:

java.io.IOException: Stream closed
    at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:170)
    at java.io.BufferedInputStream.read1(BufferedInputStream.java:291)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
    at java.io.FilterInputStream.read(FilterInputStream.java:107)
    at org.gradle.process.internal.streams.ExecOutputHandleRunner.run(ExecOutputHandleRunner.java:51)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
    at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
:bootRun FAILED
> Building 100%

此时我无能为力 - 一切都被忽略,我必须关闭选项卡。

答案1

您观察到的是两件事的组合:

  1. Ctrl-C 将 INT 发送到进程组,这意味着不仅是您长时间运行的进程,还包括桀骜它正在运行的进程将同时终止(并且它不会有机会重新启动)。

  2. xfce4-terminal,由于 -H 标志,在进程结束后不会关闭选项卡:

-H, --hold 使终端在子命令终止后保持不变

这让它看起来像是悬挂着的

最简单的测试用例可能如下所示:

CMD=xeyes
START=$'/usr/bin/zsh -c \''$CMD$'; /usr/bin/zsh\''
xfce4-terminal --tab -H -T mycommand --working-directory=$HOME -e "$START"

如果你启动这个,“xeyes”会跟着你,直到你按下Ctrl+C,此时它们将关闭,并且您的终端将显示为挂起。

但如果不是点击Ctrl+C你只需杀死 xeyes 本身(即使用 xkill 或窗口管理器任务栏),桀骜会话将按预期开始。

解决此问题的方法是拦截 SIGINT 并重新启动 shell,如下所示:

CMD=xeyes
START=$'/usr/bin/zsh -c \'trap "exec /usr/bin/zsh" INT;'$CMD$'; exec /usr/bin/zsh\''
xfce4-terminal --tab -H -T mycommand --working-directory=$HOME -e "$START"

请注意,您可能还需要删除“-H”,以便在退出 shell 时关闭选项卡。

相关内容