读取发送到 xterm 的控制字符串的答案

Reading answer to control string sent to xterm

xterm 中的交互式程序运行 可以向xterm 发送控制代码,这会导致xterm 通过发回应答来进行响应。我想阅读答案。有几个这样的控制代码,所以为了便于讨论,让我们坚持使用控制序列 ESC Z,它会导致 xterm 发回其终端 ID。例如,当我输入 shell 时(我使用的是 Zsh,但据我所知,这也适用于 bash)

echo -e '\eZ'

我在终端缓冲区中看到字符串

63;1;2;4;6;9;15;22;29c

并听到哔声(因为从 xterm 发送的答案也包含不可打印的字符,特别是它还包含一个 ESC)。我的目标是以某种方式将此字符串 63;1;2;4;6;9;15;22;29c 读入 shell 变量。 我主要使用 Zsh,但也欢迎 bash 中的解决方案(或任何其他脚本语言,例如 Ruby、Perl 或 Python).

我的第一次尝试非常简单:

#!/bin/zsh
echo -e '\eZ'
read -rs -k 25
echo $REPLY | xxd

这行得通,因为我发现(经过一些反复试验)我的特定 xterm 上的这个特定示例中的答复字符串的长度为 25 个字符。在一般情况下,当然,我事先并不知道确切的长度,所以我想要一个更灵活的解决方案。我的想法是一次读取一个字符,直到什么都没有为止,我编写了以下程序来测试我的想法:

#!/bin/zsh
str=''
echo -e '\eZ'
while :
do
  read -rs -t -k
  if [[ -z $REPLY ]]
  then
    echo '(all read)'
    break
  fi
  str="${str}$REPLY"

完成 回声 $海峡 | xxd

然而,这并没有读取任何内容。回复总是空的。

我还尝试了变体 read -rs -t -k 1(同样的效果)和 read -rs -k 1(永远挂起)。甚至 read -rs k 25 也不再起作用,所以我猜罪魁祸首是 while 循环,而不是 read 命令。但是,如果我想一次读取一个字符的应答字符串,我确实需要一个循环。

有人可以解释一下为什么我的方法失败了,我该如何解决我的问题?

您可以直接从终端读取 read-statement,例如,

read -rs -t -k < $(tty)

解决 shell 的重定向问题。

因为我在这里没有得到关于这个问题的任何新发现,所以我在 Unix/Linux Forums 交叉发布了这个问题并收到了 Zsh 的答案,以及 bash 的改进答案,我想在这里总结一下:

假设 tty 包含表示我的终端的字符串(这里遵循@ThomasDickey 在他的回答中给出的建议),Zsh-command

read -rs -t 0.2 -k 1 <$tty # zsh

将下一个单个字符读入变量REPLY。重要的是要注意 -t 必须被赋予一个超时值,事实上,没有字符可用,不能从空的 REPLY 中推断出来,而是从 [= 的退出代码中推断出来16=]命令。

至于 bash,有一个比我在评论中发布的解决方案更简单的解决方案:With

read -rs -t 0.2 -d "" <$tty # bash

整个回复字符串一次性读入REPLY;不需要循环。

整理一下这里的答案,成品如下:

#!/usr/bin/env bash

tty=/dev/tty

cat >$tty
read -rs -t 0.2 -d "" <$tty
echo $REPLY | xxd -r -p
$ printf '\eP+q544e\e\' | escape_code_answer_read.bash
TNxterm-kitty