web-dev-qa-db-ja.com

bash:ループ内の非ブロック読み取り

次の小さなbashスクリプトがあります

var=a

while true :
do
    echo $var
    sleep 0.5
    read -n 1 -s var
done

ユーザーが入力した文字を出力し、次の入力を待つだけです。私がやりたいのは、実際には読み取りをブロックしないことです。つまり、0.5秒ごとにユーザーが入力した最後の文字を印刷します。ユーザーがキーを押すと、次のキーが押されるまで新しいキーが無限に印刷され続けます。

助言がありますか?

7

help readから:

  -t timeout    time out and return failure if a complete line of input is
        not read within TIMEOUT seconds.  The value of the TMOUT
        variable is the default timeout.  TIMEOUT may be a
        fractional number.  If TIMEOUT is 0, read returns immediately,
        without trying to read any data, returning success only if
        input is available on the specified file descriptor.  The
        exit status is greater than 128 if the timeout is exceeded

だから試してください:

while true
do
    echo "$var"
    IFS= read -r -t 0.5 -n 1 -s holder && var="$holder"
done

holderがタイムアウトになった場合でも、変数がreadと一緒に使用されると、変数が読み取り専用でない場合(その場合は役に立たない)でない限り、read変数はその内容を失うため、使用されます。

$ declare -r a    
$ read -t 0.5 a
bash: a: readonly variable
code 1

私はこれを防ぐ方法を見つけることができませんでした。

14
muru

少し遅れますが(よ​​り良い)解決策は次のとおりです。

while true ; do
    read -r -s -t 0.5; RETVAL=$?
    # ok? echo && continue
    [ $RETVAL -eq 0 ] && echo -E "$REPLY" && continue
    # no timeout ? (EOF or error) break
    [ $RETVAL -gt 128 ] || break
done

新しい行が利用可能になるとすぐに「読み取り」が戻るので、IMHOが大きいタイムアウトは誰にも害を与えません...

1
ATorras