こんにちは。
テキストデータ末尾(およびテキストファイル末尾)の改行 \n
1を削除2(およびその逆となる追加)の方法を調べました。
データ末尾の \n
を一個を削除
データを head -c -1
へ渡せば末尾に \n
が存在すれば一個が削除されます。GNU head を利用しています3。
wc -l コマンドで確認
その確認方法例として、wc -l
は全ての \n
をカウントしますので、一個減ったことが確認できます。
$ brew install coreutils
$ echo -ne 'aa\nbb\n' | wc -l
2
$ echo -ne 'aa\nbb\n' | ghead -c -1 | wc -l
1
用途例
利用例として、末尾の改行を削除し空要素が現れないようにしてから、tr
、jq
コマンドへ渡しました。
$ echo -ne 'aa\nbb\n' | ghead -c -1 | tr '\n' '/' | awk 1
aa/bb
$ echo -ne 'aa\nbb\n' | ghead -c -1 | jq -scR 'split("\n")'
["aa","bb"]
jq コマンドで空要素を削除
なお、jq
コマンドではselect
コマンドを利用して空要素を削除できます。
$ echo -ne 'aa\nbb\n' | jq -scR 'split("\n") | map(select(. != ""))'
["aa","bb"]
$ echo -ne 'aa\nbb\n' | jq -scR 'split("\n") | map(select(length > 0))'
["aa","bb"]
データ末尾が \n
で終わるように必要ならば追加
上記とは逆に、もしも最終行が \n
で終わっていなくとも awk '{print}'
に渡せば受け取ってくれ4、その print
が \n
を末尾に追加して出力します。もしくは grep ^
へ渡しても同様です5。
read
コマンドなどは \n
で終わっている行を読み取った時のみに正常な終了ステータスとなるので、前もってこのような追加が必要となります。
$ echo -ne 'aa\nbb' | grep ^ | while read line; do echo $line; done
aa
bb
$
$ echo -ne '' | grep ^ | wc -l
0
$ echo -ne 'aa\nbb' | grep ^ | wc -l
2
$ echo -ne 'aa\nbb\n' | grep ^ | wc -l
2
$ echo -ne 'aa\nbb\n\n' | grep ^ | wc -l
3
なお行数カウントが目的ならば、grep -c ^
でも同等となります。
$ echo -ne '' | grep -c ^
0
$ echo -ne 'aa\nbb' | grep -c ^
2
$ echo -ne 'aa\nbb\n' | grep -c ^
2
$ echo -ne 'aa\nbb\n\n' | grep -c ^
3
データ末尾の \n
の存在を判定
tail コマンドを利用し tail -c 1
により末尾の 1 バイトを抜き出せます。したがって、それが \n
なのかを判定することができます。下記例は wc -l
でカウントして確認しています(なお tail -n 1
により最終行を抜き出しても同じとなります)。
$ echo -ne 'aa\nbb\n' | tail -c 1 | wc -l
1
$ echo -ne 'aa\nbb\n' | ghead -c -1 | tail -c 1 | wc -l
0
判定方法
また、より判定に向いた方法は、tail -c 1
の出力を "$(...)"
に入れて末尾の \n
を取り除き、空文字となるかを判定する方法があります(test -z
コマンドを利用)。
$ [ -z "$(echo -ne 'aa\nbb\n' | tail -c 1)" ]; echo $?
0
$ [ -z "$(echo -ne 'aa\nbb\n' | ghead -c -1 | tail -c 1)" ]; echo $?
1
これは下記のような利用例となります。
$ filename="example.txt"
$ [ -z "$(tail -c 1 $filename)" ] && echo "$filename: 末尾は改行です/もしくは中身が空です" || echo "$filename: 末尾は改行ではありません"
example.txt: 末尾は改行です/もしくは中身が空です
中身が空(= 0 行)かどうかの判定は、
$ wc -c empty.txt | awk '{print $1}'
0
末尾の改行の個数をカウント
テキストデータ末尾の連続した改行 \n
の個数を求めるシェルスクリプトを作りました。
$ echo -ne '\n\n' | ./count.sh
2
$ echo -ne '\nA\nA' | ./count.sh
0
#!/bin/sh
n=0
while read -r line; do
[ -n "${line}" ] && n=0
n=$((n + 1))
done
[ -n "${line}" ] && n=0
echo "$n"
下記の方法も参考になりました。
- 「ファイル末尾の改行を自在にコントロールする」(ザリガニが見ていた...。)
- "Removing a newline character at the end of a file" (Stack Overflow)
-
本稿は、最終行末尾の改行
\n
についての話題です(行末毎の改行ではありません)。 ↩ -
ただし、Unix (POSIX) の原則論ではテキストデータ(およびテキストファイル)の最終行末尾に改行
\n
を付けることになります。したがって削除が必要となる場合は多くないだろうと思います ↩ -
macOS では
homebrew
を用いてインストール可能。 ↩ -
もしくは
print
を省略してもawk
の引数へパターン条件の真値を与えるだけでも同じことになります(すなわち non-zero 数値(例えばawk 1
)、もしくは non-empty 文字列(例えば'" "'
) を与える)。参考例は、「複数のファイルを終端に改行がなければ改行を追加して結合する」 ↩ -
grep
を含むいくつかコマンドは、最終行が\n
で終わっていなくとも受け取ってくれ、 その場合は\n
を末尾に追加して出力します。ただし実装依存のようで、例えば GNU sed は追加しません。 ↩