我目前正在我的家庭服务器上的 tmux 会话中运行 mcabber 作为我的 Jabber 客户端(使用 ncurses)。在本地,我将 iTerm2 作为终端模拟器运行,它支持通过字符转义序列触发咆哮通知。
注意:echo
这个问题中的所有内容都类似于bash 和 GNU 中的printf %b
, or 。echo -e
echo
例如,echo "\e]9;foobar\007"
让 iTerm2 发送一条带有文本“foobar”的 Growl 消息。
然而,在 tmux 会话中,转义序列会被耗尽。因此,\Ptmux
可以像这样使用专有的字符转义序列:
echo "\ePtmux;\e\e]9;foobar\007\e\\"
这会从 tmux 会话中触发一条咆哮消息。
但是,当我在收到新消息时触发的 mcabber 事件脚本中使用它时,不会触发任何通知,就好像回显发送到错误的终端一样。
我想这与触发脚本的 mcabber 是一个 ncurses 应用程序有关,因此我的正常 bash 脚本的输出会丢失,而 iTerm 2 永远不会看到它。
在根据我发现的一些想法进行回显之前,我也尝试过调用 smcup 但没有成功
tput smcup
echo "\ePtmux;\e\e]9;$FROM: $MSG\007\e\\"
tput rmcup
我认为这不起作用,因为问题不是切换回“真实终端窗口”,而是更多地在 ncurses 窗口中引导输出。
对这个有什么想法吗?
答案1
事件脚本无法发送“咆哮者”消息的原因是mcabber
关闭标准输入,输出以及运行事件命令时的错误流。你可以在hooks.c
:
if ((pid=fork()) == -1) {
scr_LogPrint(LPRINT_LOGNORM, "Fork error, cannot launch external command.");
g_free(datafname);
return;
}
if (pid == 0) { // child
// Close standard file descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
if (execl(extcmd, extcmd, arg_type, arg_info, bjid, arg_data,
(char *)NULL) == -1) {
// scr_LogPrint(LPRINT_LOGNORM, "Cannot execute external command.");
exit(1);
}
}
g_free(datafname);
这使得事件脚本运行时不会干扰所使用的流mcabber
。
没有专门的ncurses模式拦截消息(毕竟tmux
是已经作为 terminfo 应用程序运行)。您可以通过将您的echo
(最好printf
)重定向到 来解决该问题/dev/tty
,例如,
#!/bin/sh
printf '\033Ptmux;\033\033]9;foobar\007\033\\' >/dev/tty
答案2
tmux 和 screen 程序不直接通过转义序列。它们向应用程序提供一种终端(屏幕终端类型),并且本身就是另一个终端的 ncurses 应用程序。实际上,它有点像终端翻译器。所以是的,它消耗(或丢弃)“屏幕”终端类型的序列,并建立一个您看到的缓冲区。然后它会获取这些缓冲区更改事件并使用您当前使用的任何类型的终端来显示当前缓冲区。所以原来的app和查看端是解耦的。
答案3
如果你要放一些像...
export "PTTY=$(tty)"
...在您的/etc/profile
then中-l
,您将调用每个新的 ogin shell(这是当您打开新的终端窗口时通常会发生的情况)该环境变量将可供其所有子进程使用 - 其中应包括tmux
及其所有子进程。
这应该使您能够...
printf '\033]9;foobar\007' >"$PTTY"
...从而直接跳过pty
当前 shell 和您正在使用的终端模拟器之间可能存在的任何层。
答案4
如果问题是 bash 脚本的输出丢失,那么您可以通过重定向赢得战斗:
echo "\ePtmux;\e\e]9;foobar\007\e\" > /dev/tty
但是,我怀疑真正的问题是您应该使用echo -e
bash 来处理字符串中的转义序列。