Ubuntu 中不同终端的不同输出

Ubuntu 中不同终端的不同输出

我正在 Ubuntu 下开发一个 C++ 应用程序,需要将输出广播到多个终端。我需要以编程方式执行此操作,从 C++ 应用程序调用(例如)bash 命令并将输出定向到相应的终端。而且我无法安装任何已开发的“多终端”工具(例如“终结者”或其他);相反,我需要使用标准 bash 命令。
所以:

process A -> will show its output in terminal A.
process B -> will show its output in terminal B.
process C -> will show its output in terminal C.

那么请注意:

  • 我将同时向多个终端广播不同的信息,并且向特定的终端广播特定的信息。
  • 你见过空气裂缝工作吗?我记得该应用程序同时显示三个不同的终端,每个终端位于屏幕的特定 x,y 坐标处,并且每个终端都显示不同的信息。嗯,我想这就是我所需要的。
  • 浏览后,我发现了以下“gnome-terminal”命令,并将其改编为运行 3 个终端:

    gnome-terminal --geometry=45x20+10+10; gnome-terminal --geometry=45x20+505+10; gnome-terminal --geometry=45x20+950+10
    

一些细节:

  • 终端不需要是 gnome 终端。它们可以只是简单的控制台、xterms; Ubuntu 默认提供的。
  • 我不需要立即启动三个终端(如上面的示例命令)。但是,当相应的进程需要向其终端广播时,终端必须是打开的。
  • 程序如何知道向哪个终端广播输出?可能正在使用终端的pid?如果是的话,有终端 pid,我将如何将输出重定向到该终端?
  • 我试图获取每个终端的 pid;例如,像这样:

    gnome-terminal --geometry=45x20+10+10 &
    

并寻找某种方法将 pid 重定向到变量(尚未找到...)。

答案1

Unix 会话由 TTY 处理,这应该是您的起点。如果您对所有这些会话使用相同的用户帐户,那么您应该能够将输出直接发送到您想要的 TTY。

因此,您只需使用要在输出中使用的不同 TTY 来调用您的程序,它就能够打开这些 TTY 以进行输出。我刚刚在Gentoo和Centos上试了一下,没有任何问题。

要查找会话的 TTY,请使用以下tty命令。

我更喜欢的另一个选择是采用客户端-服务器方法,其中客户端终端将连接到您的服务器进程,因为它在与其他用户打交道时具有较少的安全隐患。这可以像为 3 个输出终端中的每一个使用命名管道一样简单。

答案2

如果您只是打开一个终端模拟器并向其发送一些数据,您必须意识到用户的默认 shell(很可能bash)也将在那里运行。这会产生一些在您的用例中很可能不受欢迎的后果。由于提示,输出的第一列将未对齐(除非您注意清除屏幕)。无论用户输入什么,都会进一步弄乱屏幕,更重要的是,它将作为 shell 命令执行,这尤其具有误导性,因为用户可能不再看到提示。另外,如果您还想从终端读取数据,您将无法可靠地执行此操作(对于每次按键,无论它到达 shell 还是您的应用程序,都是随机的。

如果我正确理解你问题的上下文,这对你来说是不可取的。您打开的终端应该仅用于显示应用程序的输出,并且它们不应该同时运行 shell。因此,您必须指定要启动的自定义命令,而不是默认 shell。这个自定义命令可以很容易地成为一个简单的脚本(或C++实用程序),它将终端的行号(命令的输出tty)发送回您的应用程序,也许可以更改一些终端和信号设置(例如关闭本地回显(stty),禁用信号) (sttytrap)),最后输入一个巨人sleep

有多种方法可以将 tty 号码发送回您的主应用程序。请注意,从应用程序的角度来看,启动这些终端和其中的脚本是异步的。例如,如果您将tty的输出放置在具有固定文件名的临时文件中,则必须确保应用程序不会过早读取该文件的先前版本。例如,您可以每次创建一个唯一的随机文件名,然后在主应用程序中等待它出现。

让我向您推荐一种完全不同的考虑方法。

gnome-terminal 的(以及大多数(如果不是全部)其他基于 Gtk+ 的终端仿真器)实际的终端仿真是由 VTE 小部件完成的。如果您使用 Gtk+ 工具包编写应用程序,添加 VTE 小部件就像添加复选框一样简单。

您的应用程序本身可能会显示一个包含多个 VTE 小部件的图形窗口,或者每个内部都有一个 VTE 的多个图形窗口,而不是使用gnome-terminal或其他什么,无论您喜欢哪种。xterm或者,如果您不想在实际应用程序中依赖 Gtk+,您可以轻松地为此任务创建一个单独的小型帮助应用程序(您甚至可以考虑使用 Python 而不是 C/C++)。

在这种情况下,默认情况下不会启动 shell(您必须使用vte_terminal_spawn_sync()您乐意不这样做的方法显式地执行此操作)。您只需使用 获取终端行vte_pty_get_fd(),将其转换为字符串ptsname(),然后将其传递回您的主应用程序。或者,如果您在单个应用程序中执行此操作,那么您甚至可以vte_terminal_feed()显示要显示的数据。

答案3

问题应该很简单:从wor获取一个列表who,它为您提供用户名和终端名称,如下所示:

$ w
 19:34:00 up  7:17,  5 users,  load average: 0.14, 0.08, 0.06
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
tom      pts/1    michener:S.0     14:07    3:21m 15.16s 15.08s vile /tmp/foo
tom      pts/4    michener:S.1     12:34    2.00s  0.22s  0.00s w
tom      pts/5    michener:S.2     13:00    9:48   3.13s  2.79s vile /usr/build
thomas   :0                        19:32   ?xdm?  47.31s  0.34s fvwm2 -f /usr/b
thomas   pts/3    :0               19:33    7.00s  0.04s  0.04s bash
$ who
tom      pts/1        2016-06-04 14:07 (michener:S.0)
tom      pts/4        2016-06-04 12:34 (michener:S.1)
tom      pts/5        2016-06-04 13:00 (michener:S.2)
thomas   :0           2016-06-04 19:32
thomas   pts/3        2016-06-04 19:33 (:0)

然而,并非所有终端都支持 utmp(存储此信息的地方)。如果您仅限于 Linux,那么您可以在 中获取一些有用的信息/dev/pts,即具有所有权信息的设备:

$ ls -l /dev/pts
total 0
crw--w---- 1 tom    tty  136, 0 Jun  4 19:34 0
crw--w---- 1 tom    tty  136, 1 Jun  4 16:12 1
crw--w---- 1 thomas tty  136, 2 Jun  4 19:33 2
crw--w---- 1 thomas tty  136, 3 Jun  4 19:33 3
crw--w---- 1 tom    tty  136, 4 Jun  4 19:34 4
crw--w---- 1 tom    tty  136, 5 Jun  4 19:24 5
c--------- 1 root   root   5, 2 Jun  4 12:16 ptmx

脚本可以轻松检查这些,确定哪些是预期用户,并写入这些(终端)设备。

笔记:

  • 关于“程序如何知道向哪个终端广播输出?”,通常采取的方法是在每个要区分的终端上运行客户端,使它们与服务器进行通信。

  • 有评论询问程序如何知道在哪里客户出现在屏幕上。您可以使用窗口属性来获取该信息,例如,以 window-id 开头并使用xwininfo.终端仿真器的类型以及合适(或可用)的 window-id 之间存在差异。但是WINDOWID每个终端中的环境变量是获取此信息的常用方法(如果您不只是想广播,则通过似乎需要的客户端)。以下是使用该方法的示例输出:

    xwininfo: 窗口 ID: 0x400023 “[!xwininfo] - 卑鄙”

      绝对左上角X:0
      绝对左上角 Y:23
      相对左上角X:0
      相对左上角Y:22
      宽度:486
      身高:551
      深度:24
      视觉:0x22
      视觉等级:真彩色
      边框宽度:0
      类:输入输出
      颜色图:0x21(已安装)
      位重力状态:NorthWestGravity
      窗口重力状态:NorthWestGravity
      后备存储状态:无用
      保存状态: 否
      地图状态:IsViewable
      覆盖重定向状态:否
      角球:+0+23 -794+23 -794-428 +0-428
      -几何80x40+0+1

进一步阅读:

相关内容