如何优雅地暂停和恢复 `cmd1 && cmd2 && cmd3` 链?

如何优雅地暂停和恢复 `cmd1 && cmd2 && cmd3` 链?

来自上一个问题看来我无法理解如何正确&&交互^Z

$ command1 && command2 && command3
Running command1 ...
Running command2 ...^Z
[1]+  Stopped
$ fg && command4
Running command3
Running command4

,我认为可以用来在链启动后“追加”链,似乎只因为是command3最后一个命令才起作用;并停止它command2,例如, who 会提供不同的结果(command3who 应该被忽略)。

如何&&在不取消其余命令的情况下优雅地挂起链?如果命令行中需要进一步的逻辑,我还希望保留退出代码。

如果我知道我可能想提前暂停链,我可以这样启动它:( command1 && command2 && command3 ),所以它应该可以优雅地暂停。但是当它直接启动时我该怎么做?

如果命令不提供输出(与上面的示例不同),不应运行两次或乱序,那么我能想到的唯一方法是按^Z,分析停止的内容,然后手动构建fd && the_rest_of_commands,这是不方便且错误的 -易于。

答案1

我认为你误解了正在发生的事情。当你这样做时:

cmd1 && cmd2

shellcmd1在子进程中启动,等待该进程,然后在以零退出状态退出cmd2时启动。cmd1

如果按Ctrl+Z,等待返回,shell 设置$?为 148 例如 (128 + SIGTSTP),其余部分的评估完成在那时候,也是cmd2如此不是被执行。并cmd1成为后台工作。

如果您输入:

cmd1 || cmd2

或者:

cmd1; cmd2

cmd2会被处决之上Ctrl-Z并且您必须等待它完成才能收到下一个提示(如果可以fgbg您的后台作业)。

在 中zsh,当您按Ctrl-Zin 时:

{cmd1 && cmd2 && cmd3}

这会暂停整个组(并将其移至子 shell)。但是,在恢复时,挂起的命令在终止时将设置$?为 20,无论其退出状态如何,我认为没有办法解决这个问题,因此您最终会得到相同的行为(尽管在{cmd1 || cmd2}cmd2 中将在 cmd1 之后执行)已经完成而不是直接上Ctrl-Z)。

答案2

gdb -p看起来像是通过提供优雅的暂停来暂停当前正在运行的组件,这与kill -STOP.

因此,如果您知道command2当前正在执行,您可以执行以下操作:

gdb -p $(pgrep -f 'command2')

从其他终端暂停,然后退出或继续 GDB 恢复。

答案3

您可以挂起父 shell - 您在其中启动命令的交互式 shell:

在运行命令之前打印 PID(或稍后查找 PID,见下文):

$ echo $$
1234

从另一个终端,您可以通过挂起交互式 shell 来停止整个命令列表 - 该列表由交互式 shell 的子进程组成:

$ kill -STOP 1234

并继续命令列表:

$ kill -CONT 1234


由于echo $$在运行命令列表之前不需要进行任何准备(如 ),这是用例的一个重要部分,因此当列表已在前台运行时,以下是如何获取要停止的 shell 的 PID。

这个想法是找到列表中任何命令的父进程的 PID:

首先,我们用来pgrep查找当前正在运行的命令的PID。找到其中任何一个的 PID 就足够了,因为一次只运行一个:

$ pgrep 'command1|command2|command3'

如果command1等实际上不是进程的命令名称 - 即命令行的第一个单词 - 您需要添加该-f选项(并用于-a实验以查看不仅仅是PID):

$ pgrep -f 'command1|command2|command3'

然后,我们使用ps查找命令的父PID:

$ ps -o ppid= 

结合起来,我们得到要挂起的 shell 的 PID,如下所示:

$ pid=$(ps -o ppid= $(pgrep 'command1|command2|command3'))

全部一起:

$ kill -STOP $(ps -o ppid= $(pgrep 'command1|command2|command3'))
$ kill -CONT $(ps -o ppid= $(pgrep 'command1|command2|command3'))

相关内容