Bashシェルスクリプトで”while read”ループ内で”read”コマンドを使う方法
Contents
はじめに
決して多くないケースですが、 while read ループ中で read コマンドを利用したいという場合に起きる問題と、その対処法について紹介します。
検証環境
$ uname -moi
aarch64 aarch64 GNU/Linux
$ head -n 3 /etc/os-release
PRETTY_NAME="Ubuntu Kinetic Kudu (development branch)"
NAME="Ubuntu"
VERSION_ID="22.10"
$ bash -version | head -n 1
GNU bash, バージョン 5.2.0(1)-release (aarch64-unknown-linux-gnu)while read ループ中で read コマンドを利用するとどうなるか?
while read ループ中で read コマンドを利用するとどうなるか。
具体例をもとに見ていきます。
例えば、簡単な英単語の暗記スクリプトを作ってみます。
仕様は単純で、単語を1つ表示しては ENTER キーの入力を待つ、を繰り返します。
$ cat <<EOF >words.txt
one
two
three
EOF
$ cat words.txt \
| while read -r WORD; do
echo "WORD: $WORD"
echo "---"
read -r -p "次に進むには ENTER を押してね >"
echo "---"
done実行結果は以下のようになります。
$ cat words.txt \
| while read -r WORD; do
echo "WORD: $WORD"
echo "---"
read -r -p "次に進むには ENTER を押してね >"
echo "---"
done
WORD: one
---
---
WORD: three
---
---ENTER キーの入力を求められないどころか、 two という単語が表示されていません。
cat words.txt | ... のようにパイプを使わず、リダイレクトで読み込ませても結果は変わりません。
$ while read -r NUM; do
echo "NUM: $NUM"
echo "---"
read -r -p "Press enter to continue"
echo "---"
done <words.txt
NUM: one
---
---
NUM: three
---
---これはループ内の read が パイプあるいはリダイレクトで渡された words.txt の内容を読み込んでしまうことが原因です。
対処法 1 : while read ループを避け for ループを使用する
while read を避けられるのなら for ループに書き換えます。
ちゃんと、3 回 ENTER キーの入力を求められます。
$ for NUM in $(cat words.txt); do
echo "NUM: $NUM"
echo "---"
read -r -p "Press enter to continue"
echo "---"
done
NUM: one
---
Press enter to continue
---
NUM: two
---
Press enter to continue
---
NUM: three
---
Press enter to continue
---
対処法 2 : /dev/tty から read するように明示する
どうしても while read を使いたい場合には、 ループ内の read に対して TTY からの入力を待ち受けるように明示します。
ちゃんと、3 回 ENTER キーの入力を求められます。
$ while read -r NUM; do
echo "NUM: $NUM"
echo "---"
read -r -p "Press enter to continue" </dev/tty
echo "---"
done <words.txt
NUM: one
---
Press enter to continue
---
NUM: two
---
Press enter to continue
---
NUM: three
---
Press enter to continue
---ひとこと
たまたまインタラクティブな操作を求めるループ処理を書いたときに遭遇した問題でした。
ディスカッション
コメント一覧
まだ、コメントがありません