同一程序的多个实例,获取输出

同一程序的多个实例,获取输出

我在 Ubuntu 16.04 中有一个名为 的 shell 程序,foo当我按下任何按钮时,它会输出状态更新。它位于/usr/local/bin/foo,所以我可以在任何地方调用该程序。该程序的工作原理如下:

$ foo
Welcome

当我按下一个键后,它会显示:

Time now is 01:23:45

如果我按Ctrl-C,它将像大多数其他 shell 程序一样退出。

我希望这个foo程序在多个实例中运行。我知道 GNU Screen 命令可以在任务之间切换,但这是正确的方法吗?

或者,我知道我可以让程序在后台运行,如下所示:

$ foo &
[1]  123456

作业 ID 1 是在后台创建的,我可以通过它的作业 ID 来调用它:

$ fg %1

但是,在获得程序的最新输出后,我需要将其放回后台(通过按任意按钮:是否有任何方法可以以编程方式执行此操作?)。我怎样才能实现这个目标?

答案1

据我所知,您的要求是能够:

  1. 同时运行该程序的多个实例。
  2. 随时获得对任何实例的终端控制。
  3. 实例输出后立即将其发送回后台。

如果我们坚持这种&方法,那么是的,(3)有一个捷径。当程序控制终端时,可以使用信号将其发送到后台SIGTSTP。很方便,这通常就是Ctrl+ 的Z作用。

因此你可以有这样的东西:

$ foo &
Welcome
[1] 10

$ foo &
Welcome
[2] 11

$ fg %1
<ENTER>
Time now is 01:23:45
<Ctrl+Z>
[1]+ Stopped

据我所知,没有这样的捷径fg(以及您如何指示要带回哪个实例?)

请注意,SIGTSTP信号实际上不需要来自启动进程的 shell。如果您kill -TSTP在第二个 shell 中通过 PID 进行处理,您也可以fg在第一个 shell 中将其恢复。

在获得程序的最新输出后,我需要将其放回后台(通过按任意按钮:是否有任何方法可以以编程方式执行此操作?)

如果通过以编程方式您的意思是您可以访问foo的源代码,然后您可以使用我们刚刚看到的内容。程序raise可以使用系统调用向自身发送信号。如果我们采用一个非常简单的版本foo,我们可以得到这样的结果:

#include <stdio.h>
#include <signal.h>

int main(void)
{
    printf("Welcome");
    while(getchar()) { /* Use termios to switch to unbuffered mode */
        fprintf(stdout, "The time is... something");
        fflush(stdout);
        fflush(stdin);
        raise(SIGTSTP);
    }

    return 0;
}

虽然这一切都相当不错,但我同意这screen可能是完成这一切的更好方法,主要是因为您可以命名屏幕会话,因此永远不需要记住作业或进程 ID。就像该&方法一样,它也具有不需要更改源代码的优点。

$ screen -S foo1
$ ./foo
Welcome
<Ctrl-a d>
[detached from 10.foo1]

$ screen -s foo1
<ENTER>
Time now is 01:23:45
<Ctrl-a d>
[detached from 10.foo1]

这里的另一个优点是您不需要在分离之前停止程序。如果您希望它在您不注意时在后台执行操作,这非常方便。在之前的方法中,bg每次停止时都需要运行foo

您还可以使用 获取正在运行的屏幕列表screen -ls。在我的机器上,我设置了一些别名~/.bashrc来解决我额外的懒惰:

alias S='screen -S'
alias s='screen -r'
alias sls='screen -ls'

S foo1通过这种方式,您可以简单地执行诸如, , ...之类的操作。s foo1有些人可能会争辩说,当您在命令中放错空格或其他内容时,单字符别名可能会有点烦人,但我认为screen这是其中一个程序太方便了您有能力破例。

现在假设您采用该screen方法,以下是如何将密钥发送到会话并从 shell 获取其最后一行输出。有一些方法可以调整这个(我已经允许自己走一些捷径)但无论如何。您可以在中定义以下函数~/.bashrc

screen_key_tail() {
    screen -S $1 -X stuff "^M"
    tmp="$(mktemp)"
    screen -S $1 -X hardcopy "$tmp"
    grep -v ^$ "$tmp" | tail -n1
    rm "$tmp"
}

并使用以下命令调用它:

$ screen_key_tail foo1

其中是您要定位的会话foo1的名称。screen

相关内容