Search code examples
bashzshxterm

Reading answer to control string sent to xterm


An interactive program running in an xterm can send control codes to the xterm, which cause the xterm to respond by sending back an answer. I would like to read the answer. There are several of these control codes, so for the sake of this discussion, let's stick with the control sequence ESC Z, which causes the xterm to send back its terminal id. For instance, when I type in my shell (I'm using Zsh, but as far I can see, this applies to bash as well)

echo -e '\eZ'

I see in my terminal buffer the string

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

and hear a beep (because the answer sent from xterm also contains non-printable characters, in particular it also contains an ESC). My goal is to somehow read this string 63;1;2;4;6;9;15;22;29c into a shell variable. I mainly use Zsh, but a solution in bash would be welcome as well (or in any other scripting language, such as Ruby, Perl or Python).

My first attempt was pretty straightforward:

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

This works, because I found out (with a little bit of trial and error) that the answerback string in this particular example on my particular xterm has a length of 25 characters. In the general case, of course, I don't know the exact length in advance, so I wanted a more flexible solution. The idea would be to read one character at a time, until nothing is left, and I wrote the following program to test my idea:

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

done echo $str | xxd

However, this doesn't read anything. REPLY is always empty.

I also tried the variations read -rs -t -k 1 (same effect) and read -rs -k 1 (hangs forever). Even read -rs k 25 does not work anymore, so I guess the culprit is the while loop, not the read command. However, I do need a loop if I want to read the answerback string one character at a time.

Could someone explain, why my approach failed, and how I could solve my problem?


Solution

  • Since I hadn't got any new findings for this question here, I have crossposted the problem at Unix/Linux Forums and received an answer for Zsh, and an improved answer for bash, which I would like to summarize here:

    Assuming that tty contains the string denoting my terminal(following here the advice given by @ThomasDickey in his answer), the Zsh-command

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

    reads the next single character into the variable REPLY. It is important to note that -t must be given a timeout value, and the fact, that no character is available, can not be deduced from an empty REPLY, but from the exit code of the read command.

    As for bash, there is an easier solution than the one I've posted in my comment: With

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

    the whole answerback string is read as once into REPLY; no loop is necessary.