末尾に改行がないファイルを抽出する Bash スクリプト

ソースコードなど、テキストファイルの末尾には改行を入れている。大元は POSIX の仕様でそう定められているからで、Git でファイルを扱う時も都合が良いので、自分は従っている。

最終行に改行が無かったとします。
その次に行を追加したとします。
このとき,修正差分を取ると,変更前の最終行は,実質的には何も変更が無いにも関わらず,行末に改行が付加されたことで,変更された行として検出されてしまいます。
こういう事態を防ぐためには,すべての行が改行で終わっているほうが都合がいいんです。

最近はほとんど VSCode で物書きをしているので、EditorConfig などの Linter・Formatter を組み合わせて、ファイル保存時に自動修正するようにしても良いのだけど、なんとなく執筆中からオートフォーマットされるのが嫌で避けていたりする。仕事上書くモノについてはガチガチにフォーマッタをかけているが、個人で書く時は、たとえ非効率だろうと自分の精神的に気持ち良い方を選ぶことにしている。w

んで、そんなことをしていると末尾の改行を入れ忘れているファイルがところどころ出てくる。

今回はそうしたファイルを抽出するための Bash スクリプトを組んだので紹介する。

# カレントディレクトリ配下の全てのファイルについて
# ファイル末尾に改行がなければ標準出力する
for file in $(find . -type f); do
  line="$(tail -n1 "${file}" | wc -l)"
  if [ "${line}" -eq 0 ]; then
    echo "${file} : 末尾改行なし"
  fi
done

for 部分の $(find) はダブルクォートで囲っちゃダメ。対象のファイルは適宜、-name だとかで指定すること。このままだと .png みたいなテキストファイル以外も引っ掛けてしまう。w

find -exec とか xargs とか使うと Bash っぽいのは分かるのだが、今回はファイル末尾に改行がなかった時だけ echo したいので、可読性も考慮して forif を書くことにした。

ファイル末尾に改行があるかどうかを調べる方法は、以下の記事を参考にした。末尾の1行を tail -n1 で取り出し、その行を wc -l でカウントした時、ファイル末尾にちゃんと改行が入っていれば 1 になるのだが、改行をし忘れていると 0 になるので判別可能なのだ。なので if 部分を -eq 0 ではなく -eq 1 にすれば、「ファイル末尾に改行が入っているファイル」だけを抽出できることになる。