LoginSignup
5
1

More than 1 year has passed since last update.

【シェルスクリプト】readコマンドを使用したwhile文内で、処理を一時停止できなかった件(解決)

Last updated at Posted at 2022-10-29

テキスト読込みreadとwhile文がうまく動かない!!!

シェルスクリプトで遊んでいたのですが、下記の問題に当たってしまいました・・・。

check.txt
100
200
300
400
while文(ループ)
while read line; do
  echo $line
  read -p "--> 確認してください。【Enter】" stop
done < /work/check.txt
実行結果
100
300

あれ、処理が止まらずに一気に実行されてしまっている!!?
しかも値が足りない!!!
試しに【 read -p "--> 確認してください。【Enter】 stop 】を抜いてみて実行してみた。

while文(ループ)
while read line; do
  echo $line
done < /work/check.txt
実行結果
100
200
300
400

値は、想定通り出力されている。
てことは、やはり抜いた部分がおかしい・・・?
今度は、下記のようにしてみる。

while文(ループ)
while read line; do
  echo $line
  read -p "--> 確認してください。【Enter】" stop
 echo "確認:$stop"
done < /work/check.txt
実行結果
100
確認:200
300
確認:400

stop 】のやつが、値を拾ってしまっているやないかい!!

なぜこういうことが起こったか・・・?

そもそもreadコマンドって何だっけ・・・?

readコマンド
標準入力からの入力をシェル変数に読み込むコマンド
書式:read 変数 [変数 変数...]

~~参考リンク~~
read - 標準入力から変数に代入する
[シェルスクリプト] readコマンドについて整理してみた

どうやら readコマンド で複数の変数を指定するパターンと同じことが起きているようだ。

例えば
[root]# read line stop
test1 test2
[root]# echo $line
test1
[root]# echo $stop
test2

別々でwhile文で指定した【read line】とその中で指定した【read stop】は、別物として扱われると思ってたのだが、一つの【read line stop】として扱われてしまうのですね・・・。

while文(ループ)
while read line; do
  echo $line
  read -p "--> 確認してください。【Enter】" stop
done < /work/check.txt

これをどのようにして想定通りの結果にしようか?

気持ち的には、下記のようにしたい!!!
妥協して、sleepコマンドを使って数秒待機させるか・・・?
もう少し方法を探してみたいと思います。

実行結果
100
--> 確認してください。【Enter】
200
--> 確認してください。【Enter】
300
--> 確認してください。【Enter】
400
--> 確認してください。【Enter】

解決しました!

まず下記の認識は、間違っていました。

別々でwhile文で指定した【read line】とその中で指定した【read stop】は、別物として扱われると思ってたのだが、一つの【read line stop】として扱われてしまうのですね・・・。

@angel_p_57 さんによると、今回うまくいかなかった原因は、
While文で使用していた2つの【readコマンド】でFD(ファイルディスクリプタ)がバッティングし、値が交互にそれぞれの変数に代入されてしまったから。とのこと!

そもそもFD(ファイルディスクリプタ)って何だっけ?
そういえば、LPIC1勉強してた時にちらっと出てきてたなー・・・。

FD(ファイルディスクリプタ)
プログラムがアクセスするファイルや標準入出力などをOSが識別するために用いる識別子のこと

~~参考リンク~~
ファイルディスクリプタ (FD)とは
Linuxのファイルディスクリプタ数を変更・確認する方法

またFDを指定していない read コマンドは、標準入力 ( FD:0 ) を使用するとのこと。

---- 上記の情報を踏まえたうえで解決するとしたら ----

① readコマンドで使用するDFを指定する 【by @angel_p_57 さんより】
 --> 指定する方法 オプション(-u)を使用する

check.txt
100
200
300
400
while文(ループ)
# FDを10に指定(使用可能FD範囲で、0-2以外なら何でもOK?)
# 内部の read は、デフォルトでOK!

while read -u 10 line; do
  echo $line
  read -p "--> 確認してください。【Enter】" stop
done 10< /work/check.txt
実行結果
100
--> 確認してください。【Enter】
200
--> 確認してください。【Enter】
300
--> 確認してください。【Enter】
400
--> 確認してください。【Enter】

② 確認用 read 部分で入力を端末に指定する 【by @papiron さんより】
 (入力リダイレクトで /dev/tty を指定)

while文(ループ)
# /dev/tty は、今使っている端末を示す

while read line; do
  echo $line
  read -p "--> 確認してください。【Enter】" stop < /dev/tty
done < /work/check.txt
実行結果
100
--> 確認してください。【Enter】
200
--> 確認してください。【Enter】
300
--> 確認してください。【Enter】
400
--> 確認してください。【Enter】

これでやりたかったことができる!!!
@papiron さん @angel_p_57 さん ご教授、ありがとうございました!!!

5
1
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1