我需要编写一个无限循环,在按下任何键时停止。
不幸的是,只有在按下某个键时才会循环。
想法好吗?
#!/bin/bash
count=0
while : ; do
# dummy action
echo -n "$a "
let "a+=1"
# detect any key press
read -n 1 keypress
echo $keypress
done
echo "Thanks for using this script."
exit 0
答案 0 :(得分:33)
您需要将标准输入置于非阻塞模式。这是一个有效的例子:
#!/bin/bash
if [ -t 0 ]; then stty -echo -icanon -icrnl time 0 min 0; fi
count=0
keypress=''
while [ "x$keypress" = "x" ]; do
let count+=1
echo -ne $count'\r'
keypress="`cat -v`"
done
if [ -t 0 ]; then stty sane; fi
echo "You pressed '$keypress' after $count loop iterations"
echo "Thanks for using this script."
exit 0
修改2014/12/09:将-icrnl
标记添加到stty
以正确捕获Return键,使用cat -v
代替read
为了抓住空间。
如果cat
足够快地输入数据,cat -v
可能会读取多个字符;如果不是所需的行为,请将dd bs=1 count=1 status=none | cat -v
替换为{{1}}。
答案 1 :(得分:8)
read
具有可以使用的超时参数-t
。对输入执行非阻塞检查,查看返回状态是否为0,如果是,则从循环中断。
来自bash manual:
-t 超时
如果在 timeout 秒内未读取完整的输入行,则读取会超时并返回失败。 timeout 可以是十进制数,小数点后面有小数部分。此选项仅在读取从终端,管道或其他特殊文件读取输入时有效;从常规文件中读取时没有任何效果。如果 timeout 为0,如果输入在指定的文件描述符上可用,读取将返回成功,否则失败。 如果超出超时,则退出状态大于128.
Here一些使用示例。
答案 2 :(得分:2)
通常我不介意用简单的CTRL-C打破bash无限循环。这是终止tail -f
的传统方式。
答案 3 :(得分:0)
这是另一种解决方案。它适用于任何按下的按键,包括空格,输入,箭头等。
在bash中测试:
IFS=''
if [ -t 0 ]; then stty -echo -icanon raw time 0 min 0; fi
while [ -z "$key" ]; do
read key
done
if [ -t 0 ]; then stty sane; fi
答案 4 :(得分:0)
我发现了this forum post,并将era
的帖子改写成了这种非常通用的格式:
# stuff before main function
printf "INIT\n\n"; sleep 2
INIT(){
starting="MAIN loop starting"; ending="MAIN loop success"
runMAIN=1; i=1; echo "0"
}; INIT
# exit script when MAIN is done, if ever (in this case counting out 4 seconds)
exitScript(){
trap - SIGINT SIGTERM SIGTERM # clear the trap
kill -- -$$ # Send SIGTERM to child/sub processes
kill $( jobs -p ) # kill any remaining processes
}; trap exitScript SIGINT SIGTERM # set trap
MAIN(){
echo "$starting"
sleep 1
echo "$i"; let "i++"
if (($i > 4)); then printf "\nexiting\n"; exitScript; fi
echo "$ending"; echo
}
# main loop running in subshell due to the '&'' after 'done'
{ while ((runMAIN)); do
if ! MAIN; then runMain=0; fi
done; } &
# --------------------------------------------------
tput smso
# echo "Press any key to return \c"
tput rmso
oldstty=`stty -g`
stty -icanon -echo min 1 time 0
dd bs=1 count=1 >/dev/null 2>&1
stty "$oldstty"
# --------------------------------------------------
# everything after this point will occur after user inputs any key
printf "\nYou pressed a key!\n\nGoodbye!\n"
答案 5 :(得分:0)
我已经做到这一点,而不必和stty一起玩了:
loop=true
while $loop; do
trapKey=
if IFS= read -d '' -rsn 1 -t .002 str; then
while IFS= read -d '' -rsn 1 -t .002 chr; do
str+="$chr"
done
case $str in
$'\E[A') trapKey=UP ;;
$'\E[B') trapKey=DOWN ;;
$'\E[C') trapKey=RIGHT ;;
$'\E[D') trapKey=LEFT ;;
q | $'\E') loop=false ;;
esac
fi
if [ "$trapKey" ] ;then
printf "\nDoing something with '%s'.\n" $trapKey
fi
echo -n .
done
这将