Help us understand the problem. What is going on with this article?

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

More than 3 years have 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

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

Ets
インフラエンジニア。スクリプト系の言語を中心に勉強してます。
livesense
求人情報サイト「マッハバイト」「転職ナビ」「転職会議」「転職ドラフト」および不動産情報サイト「IESHIL」などを開発・運営しています。
https://www.livesense.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away