我有一个坏习惯,就是因为没有耐心而在程序运行时终止它们。对于我所做的 99% 的事情来说,这不会造成问题,因为我的程序通常不会编辑文件。
但是,这样做会导致 git 严重损坏。我花了几个小时才通过 ctrl + c 修复了几秒钟内出现的问题。
我希望终端问我“您确定要终止这个程序吗?如果在它完成之前终止它,您的生活将会很痛苦。”
是否可以?
答案1
机制
终端本身不能直接知道进程SIGINT
在Ctrl+上接收了什么C。它向前台进程组发送信号然后由内核向组中的每个成员传递信号。通常还有一个 shell,但 shell 不会中继信号;它只会通知终端哪个进程组在前台。
此机制允许Ctrl+C中断前台管道中的所有进程。终端所知道的只是当前前台进程组的 PGID(进程组 ID)。
修改终端
您可以修改终端,这样如果它要发送SIGINT
,它将检查git
前台进程组中是否存在并采取相应措施。(我认为您需要修改 tty/pts 驱动程序,而不是您最喜欢的终端仿真器;但这远远超出了我的专业知识,所以我可能是错的。)
修改 shell
如果 shell 中继,您可以修改其代码,在中继到(或包含 的进程组)SIGINT
之前请求确认。但 shell 不会中继信号。要中继信号,修改后的 shell 应始终将自己单独置于前台(因此从终端只发送到 shell)并处理额外的前台-后台抽象级别,以便始终能够分辨出应该将信号中继到哪个进程组。这种天真的方法是不够的(调查和),shell 应该提供一个git
git
SIGINT
SIGTTIN
SIGTTOU
點數. 提供 pts 是终端多路复用器已经做的事情。
终端多路复用器
我不熟悉screen
,我用的是tmux
。该工具是有用 通过它自己,但现在最重要的是它能解决你的问题。
将此行添加到您的.tmux.conf
:
bind -T root 'C-c' if-shell 'tty="#{pane_tty}"; ps -eo tty,stat,comm | grep "^${tty#/dev/} .*+.* git$"' 'confirm-before -p "Git detected. Confirm SIGINT? (y/n)" "send-keys C-c"' 'send-keys C-c'
笔记:
- 我用 测试了这个
sleep
,而不是git
(因为我不使用git
)。 ps -o stat
不可移植。我在 Debian 10 上使用过ps
。procps-ng 3.3.15
很有stat
用,因为它可以打印+
前台进程组中的进程。这个想法是git
在后台忽略(如果有的话),因为Ctrl+无论如何C都不会发送SIGINT
给它。
这个解决方案是我的个人选择(部分原因是我tmux
每天都使用)。这是我的回答中唯一真正要求确认的解决方案。
修改git
您可以修改git
以使其表现不同。我不一定是指 Git(即工具,尽管也可以修改它),而是指命令。您可以创建一个名为的包装器脚本或 shell 函数,git
它将:
git
以使其忽略的方式运行真实SIGINT
,git
或者在另一个从未在前台运行的进程组中运行实际进程,- 或者重新配置控制终端,运行真实的
git
,然后重新配置终端。
以下是在 Bash 中测试的示例函数。如果您决定创建名为 的包装器脚本(而不是函数)git
并通过 提供PATH
,则使用真实的完整路径git
以避免脚本调用自身。
为了真正地git
忽略它SIGINT
,请将其包装在以下函数中:
git () ( trap '' INT; exec git "$@" )
注意函数体在子 shell 中运行,因此trap
不会影响主 shell。但有缺点:
- 真实
git
会忽略一切SIGINT
(尽管它不会忽略SIGTERM
)。 - 如果
git
在管道中使用,则Ctrl+C仍会影响管道的其他部分。然后 realgit
可能会因为 而退出SIGPIPE
。我们trap '' PIPE
也可以这样做,但我想您首先不想中断管道。
在另一个进程组中运行实际git
(无论您如何操作)在我看来并不更好,有时甚至比上述“忽略SIGINT
”解决方案更糟糕。
这是您来回重新配置终端的方法:
git () ( trap '' INT; stty -F /dev/tty intr '^G'; ( trap - INT; exec git "$@" ); stty -F /dev/tty intr '^C' )
现在只要git
运行,Ctrl+C将不起作用;如果您确实想中断它,请改用Ctrl+ 。G
笔记:
- 如果
git
在管道中使用,则Ctrl+C不会影响它的其他部分。Ctrl+G会影响整个管道。 - 如果您在后台运行(包装器),那么由于尝试与控制终端交互,
git
它将立即暂停。为了避免这种情况,您可以在前台启动,并在第一次运行后,然后。在+时,shell 可能会恢复 tty 设置(Bash 会这样做),如果您打算这样做,这是幸运的;但是如果您这样做,您将能够再次使用+终止真实。stty
git
CtrlZstty
bg
CtrlZbg
fg
git
CtrlC - 如果前台管道中有两个或多个
git
s,那么第一个退出的 s 将恢复默认设置,而您肯定希望只有最后一个执行此操作。