×
UNIX.COM Login
Username:
Password:  
Show Password






👤


Shell Programming and Scripting

BSD, Linux, and UNIX shell scripting — Post awk, bash, csh, ksh, perl, php, python, sed, sh, shell scripts, and other shell scripting languages questions here.

Problem reading terminal response string from Zsh

Tags
tty, zsh

👤 Login to reply

 
Thread Tools Search this Thread Display Modes
    #1  
Old 01-03-2018
rovf rovf is offline
Registered User
 
Join Date: Jun 2011
Last Activity: 11 July 2018, 2:25 AM EDT
Posts: 227
Thanks: 32
Thanked 51 Times in 44 Posts
Problem reading terminal response string from Zsh

Note: This posting is related to my posting at bash - Reading answer to control string sent to xterm - Stack Overflow , but I could get there a solution only for bash. I can use that solution, but for curiosity, I wonder, whether I could do this in Zsh as well.

The problem is to send a (Posix-) terminal query string to the terminal where the (interactive) shell is running, and to read the response from the terminal. For example, when we send Escape followed by the letter Z, the terminal is supposed to respond with the terminal ID. This response also starts with an Escape, followed by an arbitrary number of characters. Since I don't know the number of characters returned in advance, I have to accumulate them one by one.

This is the solution I achieved with bash, ask_tty.sh:



Code:
#!/bin/bash

str='' # Buffer for response
tty=$(tty)

# Send query string to terminal. Example: Esc Z queries for terminal id
echo -e '\e'${1:-Z}  >$tty

# Read response from terminal
while :
do
  read -rs -t 1 -n 1 <$tty
  if [[ -z $REPLY ]]
  then
    break
  fi
  str="${str}$REPLY"
done

# Output response without leading Esc
echo "${str#?}"

If I run in my terminal either ask_tty.sh Z or ask_tty.sh (because I made Z the default value), I get as response on stdout

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

The actual reading of each character is done by read -rs -t 1 -n 1 <$tty.

I feel that for adapting this solution to Zsh, I have to change the bash read to an equivalent Zsh read, but I could not get it done: Either the command hangs, or it returns only the first character of the answer string. For instance, I tried read -rs -t -k and read -rs -t 1 -k 1.

How can I solve this in Zsh?

Update: I'm using Zsh 5.3 (given the evolution of Zsh, version might matter here), running on Cygwin.

Last edited by rovf; 01-03-2018 at 08:46 AM.. Reason: Providing additional information
Sponsored Links
    #2  
Old 01-03-2018
Scrutinizer's Unix or Linux Image
Scrutinizer Scrutinizer is offline Forum Staff  
Moderator
 
Join Date: Nov 2008
Last Activity: 15 July 2018, 11:26 PM EDT
Location: Amsterdam
Posts: 11,853
Thanks: 546
Thanked 3,469 Times in 3,057 Posts
Did you try:


Code:
read -rs -t 1 -q <$tty

Sponsored Links
    #3  
Old 01-03-2018
rovf rovf is offline
Registered User
 
Join Date: Jun 2011
Last Activity: 11 July 2018, 2:25 AM EDT
Posts: 227
Thanks: 32
Thanked 51 Times in 44 Posts
Quote:
Originally Posted by Scrutinizer View Post
Did you try:


Code:
read -rs -t 1 -q <$tty
According to the man page, this can not work. Quoting the man-page:

-q Read only one character from the terminal and set name to `y' if this character was `y' or `Y' and to `n' otherwise.

So, even if it would work, it would not return the answered character, but set my variable to y or n.

Interestingly, the actual effect is that I don't even get this result, but instead the script loops forever, always returning n. It doesn't seem to actually "consume" the character.
    #4  
Old 01-03-2018
Chubler_XL's Unix or Linux Image
Chubler_XL Chubler_XL is offline Forum Staff  
Moderator
 
Join Date: Oct 2010
Last Activity: 16 July 2018, 12:07 AM EDT
Posts: 3,551
Thanks: 159
Thanked 1,266 Times in 1,160 Posts
In bash you could simplify the logic as -t will timeout if a full line is not received



Code:
#!/bin/bash

str='' # Buffer for response
tty=$(tty)

# Send query string to terminal. Example: Esc Z queries for terminal id
echo -e '\e'${1:-Z}  >$tty

# Read response from terminal (200ms timeout empty delimiter)
read -rs -t 0.2 -d "" <$tty

# Output response without leading Esc
echo "Response: ${REPLY#?}"

Under zsh -t is just a timeout for the first character being available. Use return value of read to detect a timeout, as REPLY is not emptied on timeout:



Code:
#!/bin/zsh
str='' # Buffer for response
tty=$(tty)

# Send query string to terminal. Example: Esc Z queries for terminal id
echo -e '\e'${1:-Z}  >$tty

# Read response from terminal
while :
do
  read -rs -t 0.2 -k 1 <$tty || break
  str="${str}$REPLY"
done


# Output response without leading Esc
echo "Response: ${str#?}"


Last edited by Chubler_XL; 01-03-2018 at 08:30 PM..
Sponsored Links
    #5  
Old 01-04-2018
apmcd47 apmcd47 is offline
Registered User
 
Join Date: Feb 2011
Last Activity: 16 July 2018, 4:59 AM EDT
Posts: 360
Thanks: 16
Thanked 102 Times in 95 Posts
From a 1980's script, written by somebody else for Suns:


Code:
stty raw >/dev/tty
echo -n "$report" >/dev/tty
ch=`dd </dev/tty count=1 2>/dev/null`
stty cooked >/dev/tty

Where $report is your input string.

The above still works today in a ROXTERM and xfce4-terminal on Linux, and should work on other terminal emulators.

Also note the /dev/tty will use the current terminal without having to find it with tty

Andrew
The Following User Says Thank You to apmcd47 For This Useful Post:
rovf (01-04-2018)
Sponsored Links
    #6  
Old 01-04-2018
rovf rovf is offline
Registered User
 
Join Date: Jun 2011
Last Activity: 11 July 2018, 2:25 AM EDT
Posts: 227
Thanks: 32
Thanked 51 Times in 44 Posts
Quote:
Originally Posted by apmcd47 View Post


Code:
stty raw >/dev/tty
echo -n "$report" >/dev/tty
ch=`dd </dev/tty count=1 2>/dev/null`
stty cooked >/dev/tty

Where $report is your input string.
This does work too, indeed, though I don't fully understand the script: Why do we need the count parameter here. I see that we do need it, because when I set it to a higher value or omit it, the script hangs (probably waiting for input). But how does this parameter make it work?

I understand that with count=1, you tell dd to return one block only, where the default block size is 512 bytes. I can understand, how this works, when reading from a file, but how does dd know that it has finished reading? There is, I think, no EOF when reading from /dev/tty, and if there were an EOF condition, the count parameter would not be needed at all.
Sponsored Links
    #7  
Old 01-05-2018
Don Cragun's Unix or Linux Image
Don Cragun Don Cragun is offline Forum Staff  
Administrator
 
Join Date: Jul 2012
Last Activity: 16 July 2018, 1:02 AM EDT
Location: San Jose, CA, USA
Posts: 11,406
Thanks: 649
Thanked 3,969 Times in 3,393 Posts
The assumption is that the terminal will send its entire response to your terminal query in a single burst of characters. That burst of characters will be read as one "block" by dd and with the directive count=1 it will quit after it has successfully read that single block. Without the count=1, dd will continue reading blocks from the terminal until it hits an EOF condition, which won't happen until you type CTL-D (i.e., hold down the control key while you hit the "d" key).
The Following User Says Thank You to Don Cragun For This Useful Post:
rovf (01-05-2018)
Sponsored Links
👤 Login to reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

More UNIX and Linux Forum Topics You Might Find Helpful
Thread Thread Starter Forum Replies Last Post
[Solved] Need Help in reading Response file mallak Shell Programming and Scripting 6 03-02-2014 09:19 PM
slow response on solaris terminal skamal4u Solaris 3 09-06-2011 10:31 AM
ssh error: Error reading response length from authentication socket cpp6f UNIX for Advanced & Expert Users 1 10-27-2009 06:16 PM
Running a String as a command, zsh. drnkhmlck Shell Programming and Scripting 2 04-03-2008 02:21 PM
Reading response from server frustrated1 Shell Programming and Scripting 4 03-24-2004 01:22 PM



All times are GMT -4. The time now is 08:44 AM.

Unix & Linux Forums Content Copyright©1993-2018. All Rights Reserved.