CLI 小助手 GUI

作者:Shawn Powers

我几乎尝试过所有适用于 Linux 和 OS X 的 IRC 客户端。(我的日常工作同时使用这两个平台。)无论我尝试多少次寻找满足我需求的 GUI 应用程序,我总是回到 Irssi。它非常好用,而且我可以从任何地方访问它(图 1)。感谢我在奥地利的 Raspberry Pi 主机托管,我可以始终保持登录状态,并且永远不会错过任何消息。不幸的是,我希望 Irssi 拥有的唯一功能是当有人给我发送消息或在频道中提及我时,能弹出通知。所以,我决定给 Irssi 添加一个小的 GUI。这很有趣,而且事实证明,它非常好用。

图 1. 我实际上不得不向上滚动了一点,才找到一些足够无害的东西发布在杂志上!

如果您在您面前的 Linux 机器上本地运行 Irssi,则此过程要简单得多。由于我连接 Irssi 的机器在另一个大陆,因此过程稍微复杂一些,但也更有趣。为了获得远程提及我的用户名的本地 GUI 通知,我需要完成几件事

  1. 我必须让 Irssi 在 IRC 频道或查询中提及我时生成某种事件和/或日志。

  2. 我必须解析该信息,并将其通过互联网实时传输到我的本地机器。

  3. 当远程事件发生时,我需要在我的本地机器上显示 GUI 弹出窗口,同样是实时的。

  4. 我需要能够断开并重新连接到屏幕会话,并让 GUI 通知跟随我,无论我实际在哪台计算机上。(在我的情况下,这意味着 Linux 或 OS X。)

幸运的是,Linux 提供了我需要的所有工具,并且只需编写少量脚本,我就可以使系统正常工作。

步骤 1:Irssi 事件

显然,我不是第一个想要 Irssi 的 GUI 通知系统的人,值得庆幸的是,Thorsten Leemhuis 分享了他的 Irssi 插件供大家使用。您可以在 http://www.leemhuis.info/files/fnotify/fnotify 下载该插件,并且由于它是根据 GPL 发布的,您可以随意分享它。

为了使用该脚本,请将其另存为 fnotify.pl 到 Irssi 运行的 ~/.irssi/scripts/ 文件夹中。对我来说,那是在我在奥地利的远程服务器上。保存后,您可以通过键入以下内容来加载脚本


/script load fnotify.pl

从 Irssi 应用程序内部。如果您希望 fnotify.pl 在每次 Irssi 启动时自动加载(我的建议),请在 scripts 文件夹内的 autorun 文件夹中创建一个符号链接。为此,请键入


mkdir ~/.irssi/scripts/autorun (if it doesn't exist already)
ln -s ~/.irssi/scripts/fnotify.pl 
 ↪~/.irssi/scripts/autorun/fnotify.pl

然后,每次 Irssi 启动时都应加载 fnotify。为了确保它正常工作,请让某人在 IRC 频道中提及您,并检查消息是否已写入文件 ~/.irssi/fnotify。

一旦您确定插件正在工作,并且提及您名字的内容已写入 fnotify 文件,就该将该信息传输到您的本地计算机了。但首先,您需要为 GUI 弹出消息设置本地计算机,以便在传输信息时有地方发送信息。

本地 GUI 通知

等式的这一部分相当简单。大多数 Linux 发行版都带有某种通知系统。我更喜欢 GNOME 环境,所以我选择使用 libnotify,更具体地说,是 notify-send 命令,该命令在从命令行或脚本调用时创建 GUI 弹出窗口。KDE 用户可以使用 kdialog 程序获得类似的效果,而 OS X 用户将需要查看 Terminal Notifier,托管在 https://github.com/alloy/terminal-notifier

从您的 Linux 命令行,通过键入以下内容测试 notify-send


notify-send "Test Title" "Sample message..."

这应该会弹出一个带有您的标题和消息的 libnotify 框(图 2)。如果您使用的是 KDE(或 OS X),则命令将类似,但您需要检查确切的语法。也可以调整程序以获得自定义图标,更改弹出窗口的持续时间,甚至更改通知的系统紧急程度。我实际上使用 Pidgin 图标作为通知框,只是因为我使用 Pidgin 已经很久了,该图标让我联想到聊天。

图 2. 弹出系统真的非常巧妙。

远程 fnotify,本地 libnotify

这是等式中长期困扰我的部分。我曾在 SSH 上完成远程 X 隧道,但由于 Irssi 没有原生 GUI 弹出窗口,因此没有 X 内容可以隧道传输。我也知道,如果我 SSH 到我的远程服务器,我运行的任何命令都将在远程服务器上执行。值得庆幸的是,通过足够的谷歌搜索和挠头,我学到了一些东西:可以在 SSH 上运行除了 shell 之外的远程程序!我从未将此视为一种可能性,但这当然很有道理。

了解到我可以在远程服务器上通过 SSH 运行程序,并让其输出显示在我的本地机器上,这变成了一个简单的脚本问题,即将 fnotify 文本管道输入到 libnotify。我应该指出,如果您设置了密钥对以避免需要输入密码,则远程 SSH 操作会容易得多。可以交互式地运行命令,但是您会失去很多自动化方面的好处。我在这里有一个简单的教程视频,用于设置 SSH 密钥对:https://www.youtube.com/watch?v=R65HTJeObkI

这是我的脚本;稍后我将解释它


#!/bin/bash
# Location: /usr/local/bin/irc_notify
(ssh spowers@my.remote.server.com \
-o PermitLocalCommand=no -o ServerAliveInterval=30 \
"> .irssi/fnotify; tail -f .irssi/fnotify" |
while read title message; do
notify-send -u critical -i pidgin "${title}" "${message}";
done)

我必须再次承认,上面的代码是从其他人的工作中搜罗来的,并被我稍微调整了一下。我当然不声称拥有这个概念的所有权。该脚本假定已安装密钥对,但是如果没有设置密钥对,它也可能会交互式地工作。

这是脚本的作用

  1. 该脚本启动 SSH 并带有几个选项。我添加了 ServerAliveInterval=30 选项,因为在我的情况下,我的 SSH 连接会在一段时间后超时。这夺走了脚本的全部意义,因此该选项是为了保持连接处于活动状态。

  2. 我没有运行 shell(这是默认设置),而是指定了 SSH 应该在远程计算机上运行的程序。我实际上让它做两件事:首先,清除 .irssi 中的 fnotify 文件,其次,在同一文件上运行 tail -f。我清除该文件是为了使其不会变得太长,但是如果您想保留所有消息的记录,则可以忽略第一部分 - 它不会影响脚本的工作方式。

  3. tail -f 是一个保持运行的命令,并将指定文件中的任何新条目打印到命令行。它通常用于监视日志文件,但在这种情况下,它是完美的。每次有人提及我的用户名时,tail -f 都会将其打印到屏幕上。

  4. 请注意,该行末尾的管道符号 (|) - 它将输出发送到其后的程序,而不是将其打印到屏幕上。在这种情况下,它将 tail -f 的输出管道传输到一个 while 循环中,该循环将文本读取到两个不同的变量中。命令 read title message 将输出中的第一个单词(通常是向我发送消息的人的名字)分配给变量 $title,并将消息的其余部分分配给变量 $message

  5. 然后,while 循环使用上面的变量运行 notify-send,并重新启动循环,等待来自远程 SSH 的 tail 命令的另一个输出。要结束程序,您可以按 ^C。(但实际上我也自动化了这一点;稍后会详细介绍。)

脚本本身很简单,但是要弄清楚哪些部分在远程发生,哪些部分在本地发生可能会令人困惑。一旦我了解到 SSH 程序可以在远程系统上运行 shell 以外的程序,脚本概念就开始变得有意义了。希望这对您也有意义。

将它们组合在一起

您现在拥有一个系统,可以在有人在正在运行的 Irssi 会话中提及您的名字时通知您。我假设您在 screen 或 tmux 会话中运行 Irssi,因此您可以根据需要连接和断开连接。因为我从不同的机器连接,所以我就是这样做的。但是,为了简化操作,我编写了第二个脚本,该脚本建立通知 SSH 连接,然后通过 SSH 连接到服务器。然后,当我从交互式 SSH 会话断开连接时,它也会终止通知连接。我将上面的脚本称为 irc_notify,将下面的脚本简称为 irc。当我想使用 IRC 时,我从命令行键入 irc,通知内容就会自动发生。这是“irc”脚本


#!/bin/bash
# Location: /usr/local/bin/irc
#
# Kill any existing fnotify sessions that might be 
# running to avoid duplicate notifications
kill $(ps aux | grep [f]notify | awk '{print $2}') > 
 ↪/dev/null &2>1
irc_notify &
ssh spowers@my.remote.server.com
# Kill all current fnotify sessions, so notifications 
# don't pop up while I'm not connected to IRC
kill $(ps aux | grep [f]notify | awk '{print $2}')

该脚本实际上并不复杂,但是 kill 行有点棘手。我运行 ps aux,然后 grep fnotify 以确保我有正确的 SSH 会话。不幸的是,当您 grep 特定单词时,您也会得到实际的 grep 进程。使用 [f]notify 正则表达式,仅返回 SSH 进程。然后,第二个字段是进程 ID (PID),因此我使用 awk 仅获取该信息并通过数字杀死该进程。

我两次使用该命令:一次是在启动交互式 SSH 会话之前,以确保通知脚本尚未运行,另一次是在我断开连接后进行清理。理想情况下,第一个 kill 语句永远不会找到任何要 kill 的东西,因为我的脚本会在自身之后进行清理,但是有时事情会出错。我想确保我不会由于运行多个 fnotify 脚本而获得重复的通知。

跨平台,以及更进一步!

我经常在 Linux 和 OS X 上使用这些脚本。我不知道 Windows 上是否有可以进行图形弹出的东西,但我认为脚本部分可以使用 Cygwin 工作。我还没有需要在 Windows 上测试这样的东西,但是如果您使其工作,我很乐意听到有关它的信息。

我喜欢使用 Irssi 通过 IRC 聊天,现在我有了它的 GUI 通知系统,我可能会开始使用 Bitlbee 进行其他 IM 协议,使 Irssi 真正成为我聊天需求的一站式商店。我希望这个脚本课程能激励您完成比我所完成的更多的事情——对于 Linux,唯一的限制因素是您的想象力!

Shawn 是 Linux Journal 的副编辑,并且从一开始就接触 Linux。他对开源充满热情,并且喜欢教学。他还喝太多咖啡,这经常在他的写作中表现出来。

加载 Disqus 评论