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
---
ひとこと
たまたまインタラクティブな操作を求めるループ処理を書いたときに遭遇した問題でした。
ディスカッション
コメント一覧
まだ、コメントがありません