LoginSignup
60
43

More than 5 years have passed since last update.

BASHのwhile readで最終行が処理されない問題の解決方法

Posted at

BASHでリストファイルなどをwhile readすることはよくあると思う。
そんな時のハマりどころ、 『ファイル最終行を処理する方法』 について、すぐ忘れるのでスニペットとしてメモしておく。

問題

BASHで巨大なファイルを読むときなど、こんなコードがメジャーだと思う。

よくあるコード
while read LINE; do
  echo "LINE: ${LINE}"
done < /tmp/test.txt

このコードだと、 最終行に改行文字が付いていないと、最終行が処理されない。
readは改行文字を期待しているからだ。

解決

while read LINEの返戻値がfalseのときでも、空行じゃない場合は処理するようなOR文を入れると良い。

うまく動くコード
while read LINE || [ -n "${LINE}" ]; do
  echo "LINE: ${LINE}"
done < /tmp/test.txt

こういう書き方のほうが読みやすいかもしれない。

うまく動くコードその2
cat /tmp/test.txt | while read LINE || [ -n "${LINE}" ]; do
  echo "LINE: ${LINE}"
done

補足: 試験用のテキストデータ作成

「最終行に改行がないファイル」は、IDEや高機能エディタを使っていると発生しやすい。

しかしviだとうまく再現できないということがわかった。
どうやら最終行に改行を入れてくれるviのお節介仕様のようだ。

ダメな例
$ vi /tmp/vi_test.txt

1
2
3 ⇐ここを改行せずに保存

### 確認 - 最終行が改行してしまっている
$ cat /tmp/vi_test.txt
1
2
3
$   ⇐改行されてプロンプトが出る

:set binary noeol等をすれば改行文字を付けずに保存できるらしいけど・・・絶対忘れる。

ということでviについては深く追わず、手っ取り早く再現する方法を取ることにした。
echo -n "xxxx"あるいはecho -e "xxxx\\c"で、改行しない行を追記する方法だ。

再現方法
$ echo -n "4" >> /tmp/vi_test.txt

### 確認 - 追加行は改行していない
$ cat /tmp/vi_test.txt
1
2
3
4$  ⇐最終行にプロンプトが出る

### 上記の代わりにこれでも良い
$ echo -e "4\\c" >> /tmp/vi_test.txt

この応用でテスト用テキストデータを作れば良い。

60
43
2

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
60
43