我有一个旧的shell脚本需要移动到bash。此脚本打印某些活动的进度并等待用户的命令。如果用户未执行任何操作15秒,则会重新绘制屏幕并显示新进度并再次启动计时器。这是我的问题:
我正在尝试使用read -t 15 myVar
- 这样在15秒的等待循环后将重新启动。然而,有一个场景给我带来了一个问题:
Enter command:
')foo
但未按输入 foo
未显示在屏幕上的任何位置(打印“Enter command:
”)bar
并按输入 此时变量$myVar
包含“foobar
”。
我需要什么?我正在寻找一种方法来查找用户输入的第一个字符串,因此我可以在刷新状态后重新显示它。这样用户会看到:
Enter command: foo
在Solaris上,我可以使用stty -pendin
将输入保存到某种缓冲区中,并在刷新后运行stty pendin
以从缓冲区获取此输入并将其打印在屏幕上。
Linux是否等同于stty pendin
功能?或许你知道我的问题的一些bash解决方案?
答案 0 :(得分:2)
我想一种方法是手动累积用户输入...使用read
和-n1
,以便它在每个字符后返回,然后你可以将它添加到你的字符串中。为防止过度绘制,您必须计算15秒钟内剩余秒数...
附录:
有关空格/返回的注释 - 您基本上想要使用没有所需字符的IFS,例如空格
示例:
XIFS="${IFS}" # backup IFS
IFS=$'\r' # use a character your user is not likely to enter (or just the same but w/o the space)
# Enter will look like en empty string
$ read -n1 X; echo --; echo -n "${X}" | od -tx1
--
0000000
# space will be presented as a character
$ read -n1 X; echo --; echo -n "${X}" | od -tx1
--
0000000 20
0000001
# after you are all done, you probably wantto restore the IFS
IFS="${XIFS}"
答案 1 :(得分:1)
扩展@nhed所说的内容,或许是这样的:
#!/bin/bash
limit=5
draw_screen () {
clear;
echo "Elapsed time: $SECONDS" # simulate progress indicator
printf 'Enter command: %s' "$1"
}
increment=$limit
str=
end=0
while ! [ $end -eq 1 ] ; do
draw_screen "$str"
while [ $SECONDS -lt $limit ] && [ $end -eq 0 ] ; do
c=
IFS= read -t $limit -r -n 1 -d '' c
if [ "$c" = $'\n' ] ; then
end=1
fi
str="${str}${c}"
done
let limit+=increment
done
str="${str%$'\n'}" # strip trailing newline
echo "input was: '$str'"
解决方案并不理想:
但也许这对你来说已经足够了。
答案 2 :(得分:1)
如果你有Bash 4:
read -p 'Enter something here: ' -r -t 15 -e -i "$myVar" myVar
-e
打开用户文本条目的readline支持。 -i
使用以下文本作为它向用户显示的输入缓冲区的默认内容。在这种情况下,以下文本是您正在阅读的变量的先前内容。
演示:
$ myVar='this is some text' # simulate previous entry
$ read -p 'Enter something here: ' -r -t 15 -e -i "$myVar" myVar
Enter something here: this is some text[]
[]
表示光标。如果需要,用户将能够退格并更正以前的文本。
答案 3 :(得分:1)
好的,我想我有解决方案。我接受了nhed的命题,并对它进行了一些工作:)
主代码打印一些状态并等待输入:
while :
do
# print the progress on the screen
echo -n "Enter command: "
tput sc # save the cursor position
echo -n "$tmpBuffer" # this is buffer which holds typed text (no 'ENTER' key yet)
waitForUserInput
read arguments <<< $(echo $mainBuffer) # this buffer is set when user presses 'ENTER'
mainBuffer="" # don't forget to clear it after reading
# now do the action requested in $arguments
done
函数waitForUserInput等待10秒按键。如果没有输入 - 退出,但已输入的键保存在缓冲区中。如果按下了键,则会对其进行解析(添加到缓冲区,或者在退格时从缓冲区中删除)。输入缓冲区保存到另一个缓冲区,从中读取该缓冲区以进行进一步处理:
function waitForUserInput {
saveIFS=$IFS # save current IFS
IFS="" # change IFS to empty string, so 'ENTER' key can be read
while :
do
read -t10 -n1 char
if (( $? == 0 ))
then
# user pressed something, so parse it
case $char in
$'\b')
# remove last char from string with sed or perl
# move cursor to saved position with 'tput rc'
echo -n "$tmpBuffer"
;;
"")
# empty string is 'ENTER'
# so copy tmpBuffer to mainBuffer
# clear tmpBuffer and return to main loop
IFS=$saveIFS
return 0
;;
*)
# any other char - add it to buffer
tmpBuffer=$tmpBuffer$char
;;
esac
else
# timeout occured, so return to main function
IFS=$saveIFS
return 1
fi
done
}
感谢各位的帮助!