(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
当然のことながら、これはこれで困る。
求めることは、途中の改行は空白にし、行末の改行はそのままに残したい。
特殊な環境で作成した場合に限るが…
ここから、とても特殊な環境に限定されるが、あることに気がついた。
というのも、筆者は、WindowsのExcelでCSVファイルを作成し、WSL2のDebianのBashで処理をしようと考えていた。
余談だが、最近のExcelは文字コードをUTF-8でCSVファイルを作ることができるんだね。ちょっとびっくり。
で、作成した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
もう少し汎用性を
前節の例は、WindowsのExcelでCSVファイルを作成して、LinuxのBashで加工する非常に特殊な場合の方法であるが、もう少し汎用性がある方法を検討してみた。
で、思いついたのが、元々の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
#!/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ファイルの処理について記述した。どなたかの参考になれば幸い。