![Ubuntu 中不同终端的不同输出](https://linux22.com/image/8243/Ubuntu%20%E4%B8%AD%E4%B8%8D%E5%90%8C%E7%BB%88%E7%AB%AF%E7%9A%84%E4%B8%8D%E5%90%8C%E8%BE%93%E5%87%BA.png)
我正在 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
),禁用信号) (stty
或trap
)),最后输入一个巨人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
问题应该很简单:从w
or获取一个列表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
进一步阅读: