端末から1文字ずつ読み込むにはreadではなくsttyコマンドを使います。
これとddコマンドを組み合わせています。
また、tputコマンドでカーソルを移動させています。
#!/bin/sh
#
# Reference Web sites:
# http://d.hatena.ne.jp/anmino/20091029/1256806944
# http://www.geocities.jp/abandonment_cat/cygwin/bshell/read.html
# http://www.ibm.com/developerworks/jp/aix/library/au-learningtput/
#
declare -i x_position=`expr \`tput lines\` / 3`
declare -i y_position=`expr \`tput cols\` / 3`
function string_generator() {
string[1]="Behold, Laputa's thunder."
string[2]="Stay hungry, stay foolish!"
string[3]="Innovation distinguishes between a leader and a follower"
string[4]="Your time is limited, so don't waste it living someone else's life."
string[5]="Life is like riding a bicycle. To keep your balance you must keep moving."
string[6]="Everything should be made as simple as possible, but not simpler."
string[7]="We never surrender"
string[8]="Life is not fair; get used to it."
string[9]="You can always become better."
string[10]="Don't find fault, find a remedy"
echo ${string[$(((RANDOM%10) + 1))]}
}
function set_timer() {
if [ `uname` == "Darwin" ] ; then
echo `printf '%.3f' \`date '+%s'\``
elif [ `uname` == "Linux" ] ; then
echo `printf '%.3f' \`date '+%s.%N'\``
fi
}
##############
### main ###
##############
### set invisible cursor ###
tput civis
### set terminal in raw mode ###
stty raw -echo
### # of characters you type ###
characters=0
### # of typing ###
typing=0
### start timer ###
start=`set_timer`
for itry in {1..10}; do
### clear display ###
clear
### set typing word ###
string="`string_generator`"
### increase total # of characters ###
characters=`expr ${characters} + ${#string}`
### print information ###
tput cup ${x_position} ${y_position}
echo "Type following sentence (type '|' to quit)"
### stop if # of characters of ${string} is zero ###
while [ ${#string} -gt 0 ] ; do
### set length of the string ###
declare -i string_length=${#string}
### print the remaining string ###
tput cup `expr ${x_position} + 5` `expr ${y_position} + ${string_length}` ; printf " "
tput cup `expr ${x_position} + 5` ${y_position}
echo "${string}"
flag=0
while [ "${flag}" == 0 ] ; do
### increase total # of typing ###
let typing=${typing}+1
### real time input => ${char} ###
tput cup `expr ${x_position} + 5` ${y_position}
tput cnorm
char=`dd bs=1 count=1 2>/dev/null`
tput civis
### if ${char} matches the first character of ${string}... ###
if [ "${char}" == "${string:0:1}" ] ; then
flag=1
break 1
fi
### "|" is defined as an escape key ###
if [ "${char}" == "|" ] ; then
clear
stty -raw echo
tput cnorm
exit
fi
### beep for wrong typing ###
echo '\a'
done
### if the first character of ${string} is blank... ###
if [ "${string:0:1}" == " " ] ; then
string=`echo ${string} | sed -e 's|^\s||'`
### cut the first character of ${string}... ###
else
string=`echo ${string} | sed -e 's|^.||'`
fi
done
done
### stop timer (in mill-seconds) ###
stop=`set_timer`
### unset terminal in raw mode ###
stty -raw echo
### set visible cursor ###
tput cnorm
### print the result ###
clear
tput cup ${x_position} ${y_position}
echo " --- Your Score ---"
time=`echo "scale=3;${stop}-${start}" | bc`
tput cup `expr ${x_position} + 2` ${y_position}
if [ `uname` == "Darwin" ] ; then
echo "total time : "${time} "[sec]"
elif [ `uname` == "Linux" ] ; then
echo "total time : "${time} "[msec]"
fi
tput cup `expr ${x_position} + 4` ${y_position}
echo "total characaters : "${characters} "[characters]"
tput cup `expr ${x_position} + 6` ${y_position}
echo "# of typing : "${typing} "[typing]"
tput cup `expr ${x_position} + 8` ${y_position}
echo "accuracy : "`echo "scale=3;${characters}/${typing}*100" |bc` "[%]"
tput cup `expr ${x_position} + 10` ${y_position}
echo "typing speed : "`echo "scale=3;${time}/${characters}" | bc` "[sec/character]"
tput cup `expr ${x_position} + 12` ${y_position}
echo "hit return key"
read *
clear