ひゃまだのblog

ひゃまだ(id:hymd3a)の趣味のブログ

Bashでセル内改行が含まれるCSVファイルを処理するときの対処方法

(2025-05-20 初稿)

最初に言っておくけど、CSVファイルを扱うときに、pythonで import csvするのが最も簡単な方法だと思う。

ただ、ちょっとした処理で、わざわざpythonまで使う必要がないと思いBashで書こうと思ったら、少しハマったので記事にする。

Excelファイルの中で、セルの中で改行(Alt + Enter)して、読みやすい表を作成することは良くある。

このセル内の改行がなければ、BashでもCSVファイルを扱うことはそれほど難しいことはないが、以下のようなCSVファイルを処理するbashスクリプトを作成する場合のこと。

"abc", "あいう", "途中で\n改行", 123
"def", "えおか", "途中で\n改行", 456
"ghi", "きくけ", "途中で\n改行", 789

このファイルをbashで1行ごと読み込むと以下のように、セル内の改行も反映して行の途中で改行してしまう。

"abc", "あいう", "途中で
改行", 123
"def", "えおか", "途中で
改行", 456
"ghi", "きくけ", "途中で
改行", 789

途中で改行してしまうと一行ごと読み込むBashスクリプトは、正常に動作をしなくなるので、trでセル内の改行を半角スペースに変換した。

tr '\n' ’ ’ < input.csv > output.csv

出来上がったファイルは以下のとおり。

"abc", "あいう", "途中で 改行", 123"def", "えおか", "途中で 改行", 456"ghi", "きくけ", "途中で 改行", 789

当然のことながら、これはこれで困る。

求めることは、途中の改行は空白にし、行末の改行はそのままに残したい。

特殊な環境で作成した場合に限るが…

ここから、とても特殊な環境に限定されるが、あることに気がついた。

というのも、筆者は、WindowsExcelCSVファイルを作成し、WSL2のDebianBashで処理をしようと考えていた。

余談だが、最近のExcel文字コードUTF-8CSVファイルを作ることができるんだね。ちょっとびっくり。

で、作成したCSVファイルをよく見ると、セル内の改行は\n、行末の改行はWindowsのため\r\nになっていた。

これを確認する方法は、いくつかあるが、Vimを用いた場合は、該当ファイルを開いたのち、「:set list」で「^M$」となっていれば「\r\n」だと確認できる。

ということで、まずは、\nを空白に、次に\rを\nに変更してやれば、うまいこと行く。

tr '\n' ' ' < input.csv | tr '\r' '\n' > output.csv
abc,あいう,"途中で 改行",123
def,えおか,"途中で 改行",456
ghi,きくけ,"途中で 改行",789

もう少し汎用性を

前節の例は、WindowsExcelCSVファイルを作成して、LinuxBashで加工する非常に特殊な場合の方法であるが、もう少し汎用性がある方法を検討してみた。

で、思いついたのが、元々のExcelファイルを改変できるのであればだが、行の最後のセルに「#end」等の他のセルでは使われなていない文字を挿入してから、以下のようにCSVファイルを作成する。

"abc", "あいう", "途中で\n改行",123,#end
"def", "えおか", "途中で\n改行",456,#end
"ghi", "きくけ", "途中で\n改行",789,#end

このCSVファイルをmotofile.csvとすると、以下のとおりtrとsedを使って行を編集すれば、当たり前だが一行ごとに処理することができる。

まあ、元のExcelファイルを編集することができればの話だが…

tr '\n' ' ' < motofile.csv | tr -d '\r' | sed 's/,#end/\n/g' > output.csv

上記の変換をBashスクリプトにすると、以下のとおり。

#!/usr/bin/bash
# CSVファイルを加工する

# 最後のセルのカンマと#endを改行に変更
source_line=$(tr '\n' ' ' < motofile.csv | tr -d '\r' | sed 's/,#end/\n/g')

while read -r line; do
    echo "${line}"
done <<< "${source_line}"

なお、上記Bashスクリプトの行を読み込む部分を以下のようにすると、各セルの値が変数に入力されるので便利だ。

変数の数が多くて記述が大変な場合は、配列に入力することもできる。

while IFS="," read -r v01 v02 v03 v04; do
    echo "${v01}":"${v02}":"${v03}":"${v04}"
done <<< "${source_line}"

ということで、今回はセル内に改行が含まれるCSVファイルの処理について記述した。どなたかの参考になれば幸い。

関連ページ