| 1 | #! /bin/bash
|
|---|
| 2 | #
|
|---|
| 3 | #From: [email protected] (Kaz Kylheku)
|
|---|
| 4 | #Newsgroups: comp.unix.shell
|
|---|
| 5 | #Subject: Funky little bash script
|
|---|
| 6 | #Message-ID: <[email protected]>
|
|---|
| 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 |
|
|---|
| 25 | function 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 |
|
|---|
| 35 | function 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 |
|
|---|
| 48 | function 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 |
|
|---|
| 71 | function 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 |
|
|---|
| 93 | function 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 | |
|
|---|
| 140 | )
|
|---|
| 141 | echo -n # ignore various control characters
|
|---|
| 142 | ;; # with an annoying beep
|
|---|
| 143 | | | | | | | | | | | | | )
|
|---|
| 144 | echo -n
|
|---|
| 145 | ;;
|
|---|
| 146 | ' ' | | |
|---|
| 147 | | |
|---|
| 148 | | | |
|---|
| 149 | )
|
|---|
| 150 | echo -n
|
|---|
| 151 | ;;
|
|---|
| 152 | '' ) # Break out of loop on carriage return.
|
|---|
| 153 | echo # Send a newline to the terminal.
|
|---|
| 154 | break # (Also triggered by NUL char!).
|
|---|
| 155 | ;;
|
|---|
| 156 | * ) # Append character to the end of the line.
|
|---|
| 157 | # If length is restricted, and the line is too
|
|---|
| 158 | # long, then beep...
|
|---|
| 159 |
|
|---|
| 160 | if [ "$2" != 0 ] && [ $(( ${#line} >= $2 )) = 1 ] ; then
|
|---|
| 161 | echo -n
|
|---|
| 162 | else # Otherwise add
|
|---|
| 163 | line="$line$key" # the character.
|
|---|
| 164 | echo -n "$key" # And echo it.
|
|---|
| 165 | fi
|
|---|
| 166 | ;;
|
|---|
| 167 | esac
|
|---|
| 168 | done
|
|---|
| 169 | eval $1=\"\$line\"
|
|---|
| 170 | IFS="$save_IFS"
|
|---|
| 171 | unset line save_IFS
|
|---|
| 172 | }
|
|---|
| 173 |
|
|---|
| 174 | # uncomment the lines below to create a standalone test program
|
|---|
| 175 | #
|
|---|
| 176 | echo "Line input demo for the GNU Bourne-Again Shell."
|
|---|
| 177 | echo "Hacked by Kaz Kylheku"
|
|---|
| 178 | echo
|
|---|
| 179 | echo "Use ^H/Backspace/Del to erase, ^W to kill words, ^U to kill the"
|
|---|
| 180 | echo "whole line of input, ^R to redraw the line."
|
|---|
| 181 | echo "Pass an argument to this program to prime the buffer contents"
|
|---|
| 182 | raw
|
|---|
| 183 | echo -n "go: "
|
|---|
| 184 | if [ ${#1} != 0 ] ; then
|
|---|
| 185 | LINE=$1
|
|---|
| 186 | fi
|
|---|
| 187 | getline LINE 50
|
|---|
| 188 | restore
|
|---|
| 189 |
|
|---|
| 190 | echo "<$LINE>"
|
|---|