ShellScript: テキストファイル末尾が改行かどうか調べる．

# 要約
　テキストファイルの末尾が改行かどうかを調べる方法を以下に述べる．末尾の一文字をとりだし（tail -c 1），末尾を示すダラー`$`を可視化し（cat -e），その文字が'$'と一致するかどうかで調べる`test`．

# はじめに

　テキストファイル末尾が改行か調べたいことがある[[1]]．末尾が改行かどうかを知る方法がしばしば話題になる[[2]][[3]]．そこで，あらためて，末尾が改行かどうかを調べる方法を述べることにした．

# 環境
MacOS: 10.15.3
zsh: 5.7.1

# 準備
### テキストファイルを準備．

- 検証のため以下の2つのファイル作成する．
- 文章の末尾に改行がない，すなわち最終行が改行で終わらないテキストファイル（file_1.txt）．
- 文章最後に改行がある，すなわち最終行が改行で終わるテキストファイル（file_2.txt）．
- 改行の有無を見てわかるように，`cat -e`で文末をダラー`$`で表示させた[[4]]．

```zsh:file_1.txtの内容を示す．

% cat -e file_1.txt
a$
b$
c%  #zshでは改行がない行の行末は色が反転した%となる．        
```

```zsh:file_2.txtの内容を示す．

% cat -e file_2.txt
A$
B$
C$
D$
```
</br>
</br>

# テキストファイル末尾が改行かどうか調べる．（方法）

- 上記のように，末尾が改行で終わるかどうかは，`cat -e`で標準出力させた結果の最後の文字がダラー`$`かどうかを調べればわかる．
- そこで以下の手順とする．

- 手順1: `tail -c 1`で最後の一文字を取り出す．
- 手順2: `cat -e`でそれを受ける． 
- 手順3: `test` で最後の一文字が`$`と一致するか確認する．

### 手順1

- `cat file_1.txt | wc -c`のようにしてバイト数を調べると，file_1.txtの場合，"7"と返ってくる．すなわち，改行も一文字として数えられている．

```zsh:file_1.txtの最後の一文字を取り出す．

% tail -c 1 file_1.txt
c% #　最後の一文字が"F"であり，"改行"ではない．
```

```zsh:file_2.txtの最後の一文字を取り出す．

% tail -c 1 file_2.txt
   # 改行なのでなにも表示されない．
```

### 手順2

- zsh:手順1の結果をcat -eで受ける

```zsh:file_1.txtの場合．

% tail -c 1 file_1.txt | cat -e
c% 
```

```zsh:file_2.txtの場合
% tail -c 1 file_2.txt | cat -e
$ 　　　
# 取り出した末尾の一文字が改行であることがわかる．
```

### 手順3
- 上記結果を，`$()`で変数のように扱えるようにする[[5]][[6]]．この結果はfile_1.txtの場合は文字 "F" であり，file_2.txtの場合は "改行" ，すなわち "$" が入る．
- `test`で`$()`が，文字 "$" と一致するかを調べる．
- その結果を`$?`を用いて表示する（`$?`は直前の処理の結果を示す）[[7]]．
- `test`は結果が真であれば`0`，偽であれば`1`を返すという点に注意[[8]]．

```zsh:file_1.txtの場合

% test $(tail -c 1 file_1.txt|cat -e) = '$'; echo $?
1 
# test部分はF = $ の判定をすることとなる．
# 結果は偽．
# なので戻り値は1
```

```zsh:file_2.txtの場合

% test $(tail -c 1 file_2.txt|cat -e) = '$'; echo $?
0
# test部分は$ = $ の判定．
# 結果は真．
# なので返り値は0
```


#### <font color="red">追記</font>
## `wc -l` を用いる方法

- スマートな方法を教えていただきました．
- 末尾に改行がない行（不完全な行）は行としてカウントされないことを利用する．
- 末尾の一文字を`tail -c 1`で取り出し，`wc -l`で行を数える．
- もしくは最後の行を取り出し，`wc -l`で行を数える．

```zsh:
% tail -c 1 file_1.txt | wc -l
       0 

% tail -c 1 file_2.txt | wc -l
       1
```
```zsh:
% tail -n1 file_1.txt | wc -l
       0
% tail -n1 file_2.txt | wc -l
       1
```

- データ末尾の改行有無の確認，削除，追加，それらの適応状況についてよくまとめられた記事です[[9]]．

\[9]テキストデータ末尾の改行 \n を削除（および追加、カウント） - Qiita
https://qiita.com/kkdd/items/35707fa38358ec8c17fc


#結果
　上記の方法でfile_1.txtは改行で終わっていない，file_2.txtは改行で終わっていることが確認できた．

# まとめ

　テキストファイル末尾が改行で終えるかどうかを調べる方法を述べた．

#参考

\[1]https://zariganitosh.hatenablog.jp/entry/20131216/end_of_file_lf_control
ファイル末尾の改行を自在にコントロールする - ザリガニが見ていた...。
\[2]https://teratail.com/questions/5315
Linux - 最後の文字が改行かどうか調べる｜teratail
\[3]https://stackoverflow.com/questions/38746/how-to-detect-file-ends-in-newline
svn - How to detect file ends in newline? - Stack Overflow
\[4]http://g-network.boo.jp/wiki/2018/05/post-1215/
catで改行コードを確認する | インフラ勉強wiki
\[5]https://qiita.com/kou029w/items/3e1285e3cef14682f4fe
シェルスクリプト（Bash）の記号の意味 - Qiita
\[6]https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html#Command-Substitution
Command Substitution (Bash Reference Manual)
\[7]http://kajitiluna.hatenablog.com/entry/20111023/1319381392
Linuxのシェルスクリプト変数の記号あれこれ - 気まぐれな備忘録(仮)
\[8]https://shellscript.sunone.me/if_and_test.html
if 文と test コマンド | UNIX & Linux コマンド・シェルスクリプト リファレンス
\[9]https://qiita.com/kkdd/items/35707fa38358ec8c17fc
テキストデータ末尾の改行 \n を削除（および追加、カウント） - Qiita

[1]:https://zariganitosh.hatenablog.jp/entry/20131216/end_of_file_lf_control
[2]:https://teratail.com/questions/5315
[3]:https://stackoverflow.com/questions/38746/how-to-detect-file-ends-in-newline
[4]:http://g-network.boo.jp/wiki/2018/05/post-1215/
[5]:https://qiita.com/kou029w/items/3e1285e3cef14682f4fe
[6]:https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html#Command-Substitution
[7]:http://kajitiluna.hatenablog.com/entry/20111023/1319381392
[8]:https://shellscript.sunone.me/if_and_test.html
[9]:https://qiita.com/kkdd/items/35707fa38358ec8c17fc