我正在使用 bash shell。我想解析一个 CSV 文件,其中 CSV 文件观察真正的 CSV 格式。从这个线程——https://stackoverflow.com/questions/4286469/how-to-parse-a-csv-file-in-bash, 我懂了
#!/bin/bash
file_path=$1
echo $1
while IFS=, read -r ID name address zipcode
do
echo "I got:$ID|$name|$address|$zipcode"
done < $file_path
但是,在 CSV 文件中,由于某些单元格本身可能包含逗号,因此这些项目周围有引号。所以下面的文件无法正确解析
1,1871,"222 W. Merchandise Mart Plaza, Suite 1212",60605
有没有一种方法可以修改上述脚本(或生成新脚本),从而可以准确解析 CSV 文件?
答案1
cvskit
就是您所需要的:它具有针对 CSV 文件的强大 grep、cut、join 等功能。我只会使用csvformat
.
在这种情况下我喜欢:
(1) 将输入数据转换为“好的”分隔符(例如:“,”到“§”),删除不必要的引号
csvformat -d § input | ...
(2) 用“好”分隔符处理数据
... | awk 'BEGIN{FS=OFS="§"} ...' | ...
(3)再次转换为CSV(“§”到“,”)必要时添加引号
csvformat -D § > final
答案2
输入文件a.csv:
1,1111,"111 W. Merchandise Mart's Plaza, Suite 1111",10101
2,2222,"222 Ben's St, Suite 222",20202
使用 python 3 解析输入文件的一个衬垫:
$ cat a.csv|python -c $'import csv,sys;reader=csv.reader(sys.stdin);\nfor row in reader: print row'
输出:
['1', '1111', "111 W. Merchandise Mart's Plaza, Suite 1111", '10101']
['2', '2222', "222 Ben's St, Suite 222", '20202']
更复杂的一行输出:
$ cat a.csv |python -c $'import csv,sys;reader=csv.reader(sys.stdin);\na=0\nb=0\nfor row in reader:\n\ta+=1\n\tprint "Column",a\n\tfor col in row:\n\t\tb+=1\n\t\tprint "\tColumn",b,":",col'
Column 1
Column 1 : 1
Column 2 : 1111
Column 3 : 111 W. Merchandise Mart's Plaza, Suite 1111
Column 4 : 10101
Column 2
Column 5 : 2
Column 6 : 2222
Column 7 : 222 Ben's St, Suite 222
Column 8 : 20202
第二行代码的可读版本:
import csv,sys;
reader=csv.reader(sys.stdin);
a=0
b=0
for row in reader:
a+=1
print "Column",a
for col in row:
b+=1
print " Column",b,":",col
Gnu awk(gawk):
$ cat a.csv| awk -vFPAT='[^,]*|"[^"]*"' '{for (i=1; i<=NF; i++) {print ">"$i"<"}; print ""}'
>1<
>1111<
>"111 W. Merchandise Mart's Plaza, Suite 1111"<
>10101<
>2<
>2222<
>"222 Ben's St, Suite 222"<
>20202<
答案3
我在某处有一个 awk 脚本,用于处理我见过的 Excel 输出的任何内容:可变数量的字段;字段中的逗号、换行符和双引号;即使不需要的地方也要引用字段;列标题行;修剪空白区域;回车换行转换。我需要寻找它——我认为它在几种格式之间进行了转换,大约需要 300 行(包括它自己的手册页)。还对列进行一些统计以帮助您指定 DDL。
主要问题是决定输出的格式。我选择了“|”字段用 bar 分隔,换行符用 $ 分隔,以避免将相同的问题传播到输出中。很容易使用(例如)ASCII 0x1f(单位分隔符)表示列,使用 0x1D(组分隔符)表示字段内换行符。
我可以看到对先前线程的引用,其中提到了各种工具和库。当我被锁定的关键系统困住时——无法下载,我写了这篇文章。我什至不被允许使用 C 语言,以防我破坏了他们供应商的产品,但他们承认“我可以编写脚本——你不能用它们造成任何损害。”