web-dev-qa-db-ja.com

Bash:引用符、カンマ、改行でCSVを解析します

次のcsvファイルがあるとします。

 id,message,time
 123,"Sorry, This message
 has commas and newlines",2016-03-28T20:26:39
 456,"It makes the problem non-trivial",2016-03-28T20:26:41

時間列のみを返すbashコマンドを書きたいのですが。つまり.

time
2016-03-28T20:26:39
2016-03-28T20:26:41

これを行う最も簡単な方法は何ですか? awk、gawk、cut、grepなどの標準的なUNIXユーティリティの可用性を想定できます。

エスケープする ""の存在と、ささいな試みを行う改行文字に注意してください。

cut -d , -f 3 file.csv

無駄。

11
Jacob Horbulyk

chepnerが言った のように、csvを解析できるプログラミング言語を使用することをお勧めします。

これがPythonの例です:

import csv

with open('a.csv', 'rb') as csvfile:
    reader = csv.reader(csvfile, quotechar='"')
    for row in reader:
        print(row[-1]) # row[-1] gives the last column
10
hek2mgl

言ったように ここ

gawk -v RS='"' 'NR % 2 == 0 { gsub(/\n/, "") } { printf("%s%s", $0, RT) }' file.csv \
 | awk -F, '{print $NF}'

二重引用符で囲まれた文字列にある改行を具体的に処理し、GNU awkRTの場合)を使用して、それらの外にある改行をそのままにします。

gawk -v RS='"' 'NR % 2 == 0 { gsub(/\n/, "") } { printf("%s%s", $0, RT) }' file

これは、"文字に沿ってファイルを分割し、他のすべてのブロックの改行を削除することで機能します。

出力

time
2016-03-28T20:26:39
2016-03-28T20:26:41

次に、awkを使用して列を分割し、最後の列を表示します

3
SriniV

CSVは、適切なパーサーを必要とする形式です(つまり、正規表現だけでは解析できません)。 Python がインストールされている場合は、プレーンなBASHの代わりに csv module を使用します。

そうでない場合は、コマンドラインからCSVファイルを処理するための強力なツールがたくさんある csvkit を検討してください。

以下も参照してください。

1
Aaron Digulla
sed -e 's/,/\n/g' file.csv | egrep ^201[0-9]-
0
Eduardo

fSを使用した別のawk代替

$ awk -F'"' '!(NF%2){getline remainder;$0=$0 OFS remainder}
                NR>1{sub(/,/,"",$NF); print $NF}' file

2016-03-28T20:26:39
2016-03-28T20:26:41
0
karakfa

Lspci -mの出力を処理しようとすると、同様の問題に遭遇しましたが、埋め込まれた改行を最初にエスケープする必要があります(IFS =はbashの引用評価を悪用するため、ここで機能するはずです)。ここに例があります

f:13.3 "System peripheral" "Intel Corporation" "Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel Target Address Decoder" -r01 "Super Micro Computer Inc" "Device 0838"

そして、私がそれをbashに取り込むために見つけることができる唯一の合理的な方法は、次の行に沿っています:

# echo 'f:13.3 "System peripheral" "Intel Corporation" "Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel Target Address Decoder" -r01 "Super Micro Computer Inc" "Device 0838"' | { eval array=($(cat)); declare -p array; }
declare -a array='([0]="f:13.3" [1]="System peripheral" [2]="Intel Corporation" [3]="Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Memory Controller 0 - Channel Target Address Decoder" [4]="-r01" [5]="Super Micro Computer Inc" [6]="Device 0838")'
# 

完全な答えではありませんが、役立つかもしれません!

0
Brian Chrisman