POSIX alternative to bash read with timeout and character limit

断了今生、忘了曾经 提交于 2020-01-30 02:39:23

问题


I am writing an interactive shell script that needs to run on as many systems as possible. Is there an alternative way to implement the following that is compatible with a standard POSIX system?

#! /bin/bash
echo -n "Do you wish to continue? (Y/n) 5 seconds to respond... "
read -n 1 -t 5 answer # accepts a single character, 5 second timeout.
if [ "$answer" = "n" ] || [ "$answer" = "N" ] ; then
  echo -e "\nExiting..."
  exit
fi
echo -e "\nContinuing with script..."
# More code

The timeout on read is most important to me (read -t 5). The one character limit for read is desirable but not essential (read -n 1). Ideally, the script would work on POSIX systems and also within bash without having to enable a special POSIX compatibility mode.


回答1:


Adapting the stty settings from Mr Dickey's answer, the following seems to work and continues with the script if anything other than 'n' or 'N' is pressed.

As far as I can tell, all of the stty settings are posix.

#!/bin/sh

read_char() {
        old=$(stty -g)
        stty raw -echo min 0 time 50
        eval "$1=\$(dd bs=1 count=1 2>/dev/null)"
        stty $old
}

printf "Do you wish to continue? (Y/n) 5 seconds to respond..."
read_char answer
# answer=$(getch)
# answer=$(getche)

if [ "$answer" = "n" ] || [ "$answer" = "N" ] ; then
  printf "\nExiting...\n"
  exit
fi

printf "\nContinuing with script...\n"

Alternatives to "read_char":

This avoids using eval (can be unsafe)

getch() {
        old=$(stty -g)
        stty raw -echo min 0 time 50
        printf '%s' $(dd bs=1 count=1 2>/dev/null)
        stty $old
}

This avoids eval and prints the pressed key

getche() {
        old=$(stty -g)
        stty raw min 0 time 50
        printf '%s' $(dd bs=1 count=1 2>/dev/null)
        stty $old
}



回答2:


The stty program provides the means to do this. xterm has several scripts (in its source's "vttests" subdirectory) which save, modify and restore terminal settings to allow it to read the terminal's response to escape sequences. Here is a part of dynamic2.sh (the beginning sets up printf or echo, to address some old systems with the $CMD variable):

echo "reading current color settings"

exec </dev/tty
old=`stty -g`
stty raw -echo min 0  time 5

original=
for N in $FULL
do
    $CMD $OPT "${ESC}]$N;?^G${SUF}" > /dev/tty
    read reply
    eval original$N='${reply}${SUF}'
    original=${original}${reply}${SUF}
done
stty $old

if ( trap "echo exit" EXIT 2>/dev/null ) >/dev/null
then
    trap '$CMD $OPT "$original" >/dev/tty; exit' EXIT HUP INT TRAP TERM
else
    trap '$CMD $OPT "$original" >/dev/tty; exit' 0    1   2   5    15
fi


来源:https://stackoverflow.com/questions/32213758/posix-alternative-to-bash-read-with-timeout-and-character-limit

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!