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

ファイルの末が改行 LF であるか判定する Bash スクリプト

More than 3 years have passed since last update.

ファイルの最後の文字が改行なら 0 で終了、それ以外なら 1 で終了する Bash スクリプト。

かなりちまちましているけど、ファイルの末尾については重要な問題だと思っている。

今回は Bash のスクリプトで書いてしまったが、できれば POSIX 原理主義的なやり方も知りたいと思う。

The Open Group Base Specifications Issue 7

The Open Group Base Specifications Issue 7 によると

3.397 Text File

A file that contains characters organized into one or more lines.

3.206 Line

A sequence of zero or more non- <newline> characters plus a terminating <newline> character.

どうやらテキストファイルとは「1 つ以上の行」行は「0 個以上の改行以外の文字と末尾の改行」らしい。

このように末尾が改行で終わっているか判定し、正常なら 0 、それ以外なら 0 以外 で終了コードを返すスクリプトが欲しくなった。

もちろん、「この仕様に基づいた上でのテキストファイルとは」という話なだけなので、
私が「この世の全てのテキストファイルとはかくあるべし」と主張しているわけではない。
いろいろな OS に、それぞれの仕様があると思う。

書いた

endswith_linebreak
#!/usr/bin/env bash
exec tail -c 1 | cmp -s - <(echo)

使い方

終了コードだけではコンソールからは判別つかないので、 echo "$?" をつけて例示してみる。
調べたいファイルを標準入力にする。

$ ./endswith_linebreak < target_file ; echo "$?"
0

なお Bash 特有の機能である、コマンドを <() でリダイレクトする機能を使っている。
ので、このスクリプトは POSIX 準拠というわけではない。無念。

これではダメだった

最初、もっとシンプルに次のようなスクリプトを考えていた。

test "$(tail -c 1 "$1")" = $'\n'

残念ながら、これでは意図通りの動作にならない。
コマンド置換は末尾の改行が潰されてしまうのだ。そのため常に終了コードは 1 になる。

これは普段

$ echo "$(pwd)/somefile"

と実行したとき

$ echo "$(pwd)/somefile"
/foo/bar
somefile

とならずに

$ echo "$(pwd)/somefile"
/foo/bar/somefile

となることからも理解できる。

今回はそこでいろいろと苦心したものの、結局思い浮かばなかった。
Bash スクリプトで割りきって書くことにした。
また、せっかくなのでファイルを引数で指定するのではなく標準入力を使うことにした。

もし標準入力ではなく引数でファイルを指定する形式なら

endswith_linebreak
#!/usr/bin/env bash
exec cmp -s <(tail -c 1 "$1") <(echo)

と書けばいい。

2015-05-30 追記:

コメント欄にて tail -n 1 | wc -l すると良いとのことを教えていただいたので更新。

endswith_linebreak
#!/bin/sh
set -eu
PATH='/bin:/usr/bin'
LANG='C'
exec test "$(tail -n 1 "$1" | wc -l)" -eq 1
Why do not you register as a user and use Qiita more conveniently?
  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
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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