任意のキーが押されたときに停止する無限ループを作成する必要があります。
残念ながら、これはキーが押されたときにのみループします。
アイデアはどうですか?
#!/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
標準入力を非ブロッキングモードにする必要があります。これが機能する例です:
#!/bin/bash
if [ -t 0 ]; then
SAVED_STTY="`stty --save`"
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 "$SAVED_STTY"; fi
echo "You pressed '$keypress' after $count loop iterations"
echo "Thanks for using this script."
exit 0
2014/12/09を編集:stty
に-icrnl
フラグを追加してReturnキーを正しくキャッチし、read
の代わりにcat -v
を使用しますスペースをキャッチするために。
cat
は、十分な速度でデータが供給されている場合、複数の文字を読み取る可能性があります。望ましい動作でない場合は、cat -v
をdd bs=1 count=1 status=none | cat -v
に置き換えます。
2019/09/05を編集:stty --save
を使用してTTY設定を復元します。
read
には文字数パラメーター-n
とタイムアウトパラメータ-t
使用できます。
から bash manual :
-nnchars readは、入力の完全な行を待つのではなく、nchars文字を読み取った後に戻りますが、ncharsより少ない文字が読み取られる前に、区切り文字を優先します。デリミタ。
-ttimeout
入力(または指定された数の文字)の完全な行がタイムアウト秒以内に読み取られない場合、readがタイムアウトして失敗を返します。タイムアウトは、小数点に続く小数部分のある10進数です。このオプションは、readが端末、パイプ、またはその他の特殊ファイルから入力を読み取る場合にのみ有効です。通常のファイルから読み取る場合は効果がありません。読み取りがタイムアウトした場合、readは、読み取られた部分的な入力を指定された変数名に保存します。タイムアウトが0の場合、readはデータを読み取ろうとせずに、すぐに戻ります。指定されたファイル記述子で入力が利用可能な場合、終了ステータスは0です。それ以外の場合はゼロ以外です。タイムアウトを超えると、終了ステータスは128を超えます。
ただし、組み込みの読み取りは、独自の設定を持つ端末を使用します。他の回答が指摘したように、stty
を使用して端末のフラグを設定する必要があります。
#!/bin/bash
old_tty=$(stty --save)
# Minimum required changes to terminal. Add -echo to avoid output to screen.
stty -icanon min 0;
while true ; do
if read -t 0; then # Input ready
read -n 1 char
echo -e "\nRead: ${char}\n"
break
else # No input
echo -n '.'
sleep 1
fi
done
stty $old_tty
通常、私は単純なCTRL-Cでbashの無限ループを壊してもかまいません。これは、たとえばtail -f
を終了するための従来の方法です。
これが別の解決策です。スペース、エンター、矢印など、どのキーを押しても機能します。
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
Bashとdashでテストされた改善されたソリューション:
if [ -t 0 ]; then
old_tty=$(stty --save)
stty raw -echo min 0
fi
while
IFS= read -r REPLY
[ -z "$REPLY" ]
do :; done
if [ -t 0 ]; then stty "$old_tty"; fi
Bashでは、REPLY
コマンドのread
変数を省略することもできます。これは、この変数がデフォルトの変数だからです。
私は 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"
実行 このスクリプト