1#! /bin/bash 2# 3#From: kaz@cafe.net (Kaz Kylheku) 4#Newsgroups: comp.unix.shell 5#Subject: Funky little bash script 6#Message-ID: <6mspb9$ft2@espresso.cafe.net> 7#Date: Thu, 25 Jun 1998 06:11:39 GMT 8 9#Here is something I wrote a few years ago when I was bored one day. 10#Warning: this contains control characters. 11 12# Line input routine for GNU Bourne-Again Shell 13# plus terminal-control primitives. 14# 15# by Kaz Kylheku 16# June 1996, Vancouver, Canada 17 18 19# 20# Function to disable canonical input processing. 21# Terminal modes are saved into variable "savetty" 22# 23# 24 25function raw 26{ 27 savetty=$(stty -g) 28 stty -icanon -isig -echo -echok -echonl inlcr 29} 30 31# 32# Function to restore terminal settings from savetty variable 33# 34 35function restore 36{ 37 stty $savetty 38} 39 40# 41# Set terminal MIN and TIME values. 42# If the input argument is a zero, set up terminal to wait for 43# a keystroke indefinitely. If the argument is non-zero, set up 44# an absolute timeout of that many tenths of a second. The inter-keystroke 45# timer facility of the terminal driver is not exploited. 46# 47 48function settimeout 49# $1 = tenths of a second 50{ 51 if [ "$1" = "0" ] ; then 52 min=1 53 timeout=0 54 else 55 min=0 56 timeout="$1" 57 fi 58 59 stty min $min time $timeout 60 61 unset min timeout 62} 63 64# 65# Input a single key using 'dd' and echo it to standard output. 66# Launching an external program to get a single keystroke is a bit 67# of a pig, but it's the best you can do! Maybe we could convince the 68# GNU guys to make 'dd' a bash builtin. 69# 70 71function getkey 72{ 73 eval $1="\"\$(dd bs=1 count=1 2> /dev/null)\"" 74} 75 76# 77# Input a line of text gracefully. 78# The first argument is the name of a variable where the input line is 79# to be stored. If this variable is not empty, its contents are printed 80# and treated as though the user had entered them. 81# The second argument gives the maximum length of the input line; if it 82# is zero, the input is unlimited (bad idea). 83# ^W is used to delete words 84# ^R redraws the line at any time by backspacing over it and reprinting it 85# ^U backspaces to the beginning 86# ^H or ^? (backspace or del) delete a single character 87# ^M (enter) terminates the input 88# all other control keys are ignored and cause a beep when pressed 89# 90# 91 92 93function getline 94{ 95 settimeout 0 # No keystroke timeout. 96 save_IFS="$IFS" # Save word delimiter and set it to 97 IFS="" # to null so ${#line} works correctly. 98 eval line=\${$1} # Fetch line contents 99 echo -n "$line" # and print the existing line. 100 while [ 1 ] ; do 101 getkey key # fetch a single keystroke 102 case "$key" in 103 | ) # BS or DEL 104 if [ ${#line} != 0 ] ; then # if line not empty 105 echo -n " " # print destructive BS 106 line="${line%%?}" # chop last character 107 else # else if line empty 108 echo -n # beep the terminal 109 fi 110 ;; 111 ) # kill to line beg 112 while [ ${#line} != 0 ] ; do # while line not empty 113 echo -n " " # print BS, space, BS 114 line="${line%?}" # shorten line by 1 115 done 116 ;; 117 ) # redraw line 118 linesave="$line" # save the contents 119 while [ ${#line} != 0 ] ; do # kill to line beg 120 echo -n " " 121 line="${line%?}" 122 done 123 echo -n "$linesave" # reprint, restore 124 line="$linesave" 125 unset linesave # forget temp var 126 ;; 127 ) 128 while [ "${line% }" != "$line" ] && [ ${#line} != 0 ] ; do 129 echo -n " " 130 line="${line%?}" 131 done 132 while [ "${line% }" = "$line" ] && [ ${#line} != 0 ] ; do 133 echo -n " " 134 line="${line%?}" 135 done 136 ;; 137 | | | | | | | | | | | 138 ) 139 echo -n # ignore various control characters 140 ;; # with an annoying beep 141 | | | | | | | | | | | | ) 142 echo -n 143 ;; 144 ' ' | | | | | ) 145 echo -n 146 ;; 147 '' ) # Break out of loop on carriage return. 148 echo # Send a newline to the terminal. 149 break # (Also triggered by NUL char!). 150 ;; 151 * ) # Append character to the end of the line. 152 # If length is restricted, and the line is too 153 # long, then beep... 154 155 if [ "$2" != 0 ] && [ $(( ${#line} >= $2 )) = 1 ] ; then 156 echo -n 157 else # Otherwise add 158 line="$line$key" # the character. 159 echo -n "$key" # And echo it. 160 fi 161 ;; 162 esac 163 done 164 eval $1=\"\$line\" 165 IFS="$save_IFS" 166 unset line save_IFS 167} 168 169# uncomment the lines below to create a standalone test program 170# 171echo "Line input demo for the GNU Bourne-Again Shell." 172echo "Hacked by Kaz Kylheku" 173echo 174echo "Use ^H/Backspace/Del to erase, ^W to kill words, ^U to kill the" 175echo "whole line of input, ^R to redraw the line." 176echo "Pass an argument to this program to prime the buffer contents" 177raw 178echo -n "go: " 179if [ ${#1} != 0 ] ; then 180 LINE=$1 181fi 182getline LINE 50 183restore 184 185echo "<$LINE>" 186