LoginSignup
12
7

テキストデータ末尾の改行 \n を削除(および追加、判定、カウント)

Last updated at Posted at 2018-09-28

こんにちは。
テキストデータ末尾(およびテキストファイル末尾)の改行 \n1を削除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

用途例

利用例として、末尾の改行を削除し空要素が現れないようにしてから、trjqコマンドへ渡しました。

$ 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
count.sh
#!/bin/sh
n=0
while read -r line; do
  [ -n "${line}" ] && n=0
  n=$((n + 1))
done
[ -n "${line}" ] && n=0
echo "$n"

下記の方法も参考になりました。

  1. 本稿は、最終行末尾の改行 \n についての話題です(行末毎の改行ではありません)。

  2. ただし、Unix (POSIX) の原則論ではテキストデータ(およびテキストファイル)の最終行末尾に改行 \n を付けることになります。したがって削除が必要となる場合は多くないだろうと思います

  3. macOS では homebrew を用いてインストール可能。

  4. もしくは print を省略しても awk の引数へパターン条件の真値を与えるだけでも同じことになります(すなわち non-zero 数値(例えば awk 1)、もしくは non-empty 文字列(例えば '" "') を与える)。参考例は、「複数のファイルを終端に改行がなければ改行を追加して結合する

  5. grep を含むいくつかコマンドは、最終行が \n で終わっていなくとも受け取ってくれ、 その場合は \n を末尾に追加して出力します。ただし実装依存のようで、例えば GNU sed は追加しません。

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7