186 lines
4.5 KiB
Bash
186 lines
4.5 KiB
Bash
|
|
#! /bin/bash
|
|||
|
|
#
|
|||
|
|
#From: kaz@cafe.net (Kaz Kylheku)
|
|||
|
|
#Newsgroups: comp.unix.shell
|
|||
|
|
#Subject: Funky little bash script
|
|||
|
|
#Message-ID: <6mspb9$ft2@espresso.cafe.net>
|
|||
|
|
#Date: Thu, 25 Jun 1998 06:11:39 GMT
|
|||
|
|
|
|||
|
|
#Here is something I wrote a few years ago when I was bored one day.
|
|||
|
|
#Warning: this contains control characters.
|
|||
|
|
|
|||
|
|
# Line input routine for GNU Bourne-Again Shell
|
|||
|
|
# plus terminal-control primitives.
|
|||
|
|
#
|
|||
|
|
# by Kaz Kylheku
|
|||
|
|
# June 1996, Vancouver, Canada
|
|||
|
|
|
|||
|
|
|
|||
|
|
#
|
|||
|
|
# Function to disable canonical input processing.
|
|||
|
|
# Terminal modes are saved into variable "savetty"
|
|||
|
|
#
|
|||
|
|
#
|
|||
|
|
|
|||
|
|
function raw
|
|||
|
|
{
|
|||
|
|
savetty=$(stty -g)
|
|||
|
|
stty -icanon -isig -echo -echok -echonl inlcr
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#
|
|||
|
|
# Function to restore terminal settings from savetty variable
|
|||
|
|
#
|
|||
|
|
|
|||
|
|
function restore
|
|||
|
|
{
|
|||
|
|
stty $savetty
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#
|
|||
|
|
# Set terminal MIN and TIME values.
|
|||
|
|
# If the input argument is a zero, set up terminal to wait for
|
|||
|
|
# a keystroke indefinitely. If the argument is non-zero, set up
|
|||
|
|
# an absolute timeout of that many tenths of a second. The inter-keystroke
|
|||
|
|
# timer facility of the terminal driver is not exploited.
|
|||
|
|
#
|
|||
|
|
|
|||
|
|
function settimeout
|
|||
|
|
# $1 = tenths of a second
|
|||
|
|
{
|
|||
|
|
if [ "$1" = "0" ] ; then
|
|||
|
|
min=1
|
|||
|
|
timeout=0
|
|||
|
|
else
|
|||
|
|
min=0
|
|||
|
|
timeout="$1"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
stty min $min time $timeout
|
|||
|
|
|
|||
|
|
unset min timeout
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#
|
|||
|
|
# Input a single key using 'dd' and echo it to standard output.
|
|||
|
|
# Launching an external program to get a single keystroke is a bit
|
|||
|
|
# of a pig, but it's the best you can do! Maybe we could convince the
|
|||
|
|
# GNU guys to make 'dd' a bash builtin.
|
|||
|
|
#
|
|||
|
|
|
|||
|
|
function getkey
|
|||
|
|
{
|
|||
|
|
eval $1="\"\$(dd bs=1 count=1 2> /dev/null)\""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#
|
|||
|
|
# Input a line of text gracefully.
|
|||
|
|
# The first argument is the name of a variable where the input line is
|
|||
|
|
# to be stored. If this variable is not empty, its contents are printed
|
|||
|
|
# and treated as though the user had entered them.
|
|||
|
|
# The second argument gives the maximum length of the input line; if it
|
|||
|
|
# is zero, the input is unlimited (bad idea).
|
|||
|
|
# ^W is used to delete words
|
|||
|
|
# ^R redraws the line at any time by backspacing over it and reprinting it
|
|||
|
|
# ^U backspaces to the beginning
|
|||
|
|
# ^H or ^? (backspace or del) delete a single character
|
|||
|
|
# ^M (enter) terminates the input
|
|||
|
|
# all other control keys are ignored and cause a beep when pressed
|
|||
|
|
#
|
|||
|
|
#
|
|||
|
|
|
|||
|
|
|
|||
|
|
function getline
|
|||
|
|
{
|
|||
|
|
settimeout 0 # No keystroke timeout.
|
|||
|
|
save_IFS="$IFS" # Save word delimiter and set it to
|
|||
|
|
IFS="" # to null so ${#line} works correctly.
|
|||
|
|
eval line=\${$1} # Fetch line contents
|
|||
|
|
echo -n "$line" # and print the existing line.
|
|||
|
|
while [ 1 ] ; do
|
|||
|
|
getkey key # fetch a single keystroke
|
|||
|
|
case "$key" in
|
|||
|
|
| ) # BS or DEL
|
|||
|
|
if [ ${#line} != 0 ] ; then # if line not empty
|
|||
|
|
echo -n " " # print destructive BS
|
|||
|
|
line="${line%%?}" # chop last character
|
|||
|
|
else # else if line empty
|
|||
|
|
echo -n # beep the terminal
|
|||
|
|
fi
|
|||
|
|
;;
|
|||
|
|
) # kill to line beg
|
|||
|
|
while [ ${#line} != 0 ] ; do # while line not empty
|
|||
|
|
echo -n " " # print BS, space, BS
|
|||
|
|
line="${line%?}" # shorten line by 1
|
|||
|
|
done
|
|||
|
|
;;
|
|||
|
|
) # redraw line
|
|||
|
|
linesave="$line" # save the contents
|
|||
|
|
while [ ${#line} != 0 ] ; do # kill to line beg
|
|||
|
|
echo -n " "
|
|||
|
|
line="${line%?}"
|
|||
|
|
done
|
|||
|
|
echo -n "$linesave" # reprint, restore
|
|||
|
|
line="$linesave"
|
|||
|
|
unset linesave # forget temp var
|
|||
|
|
;;
|
|||
|
|
)
|
|||
|
|
while [ "${line% }" != "$line" -a ${#line} != 0 ] ; do
|
|||
|
|
echo -n " "
|
|||
|
|
line="${line%?}"
|
|||
|
|
done
|
|||
|
|
while [ "${line% }" = "$line" -a ${#line} != 0 ] ; do
|
|||
|
|
echo -n " "
|
|||
|
|
line="${line%?}"
|
|||
|
|
done
|
|||
|
|
;;
|
|||
|
|
| | | | | | | | | | |
)
|
|||
|
|
echo -n # ignore various control characters
|
|||
|
|
;; # with an annoying beep
|
|||
|
|
| | | | | | | | | | | | )
|
|||
|
|
echo -n
|
|||
|
|
;;
|
|||
|
|
' ' | | | | | )
|
|||
|
|
echo -n
|
|||
|
|
;;
|
|||
|
|
'' ) # Break out of loop on carriage return.
|
|||
|
|
echo # Send a newline to the terminal.
|
|||
|
|
break # (Also triggered by NUL char!).
|
|||
|
|
;;
|
|||
|
|
* ) # Append character to the end of the line.
|
|||
|
|
# If length is restricted, and the line is too
|
|||
|
|
# long, then beep...
|
|||
|
|
|
|||
|
|
if [ "$2" != 0 -a $(( ${#line} >= $2 )) = 1 ] ; then
|
|||
|
|
echo -n
|
|||
|
|
else # Otherwise add
|
|||
|
|
line="$line$key" # the character.
|
|||
|
|
echo -n "$key" # And echo it.
|
|||
|
|
fi
|
|||
|
|
;;
|
|||
|
|
esac
|
|||
|
|
done
|
|||
|
|
eval $1=\"\$line\"
|
|||
|
|
IFS="$save_IFS"
|
|||
|
|
unset line save_IFS
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# uncomment the lines below to create a standalone test program
|
|||
|
|
#
|
|||
|
|
echo "Line input demo for the GNU Bourne-Again Shell."
|
|||
|
|
echo "Hacked by Kaz Kylheku"
|
|||
|
|
echo
|
|||
|
|
echo "Use ^H/Backspace/Del to erase, ^W to kill words, ^U to kill the"
|
|||
|
|
echo "whole line of input, ^R to redraw the line."
|
|||
|
|
echo "Pass an argument to this program to prime the buffer contents"
|
|||
|
|
raw
|
|||
|
|
echo -n "go: "
|
|||
|
|
if [ ${#1} != 0 ] ; then
|
|||
|
|
LINE=$1
|
|||
|
|
fi
|
|||
|
|
getline LINE 50
|
|||
|
|
restore
|
|||
|
|
|
|||
|
|
echo "<$LINE>"
|
|||
|
|
|