Posted at

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

More than 1 year has passed since last update.

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


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