为了能够将一些数据导入某个工具,我必须将这种格式转换成 CSV 文件
"data","data","data data","data","123"
变成这种格式
data;data;data data;data;123
列中不包含任何"
,;
或,
但可以有空格。目前我使用以下
sed -e 's/","/;/g' -e 's/"//g' input.csv > output.csv
虽然这很好用,但我想知道是否可以做得更优雅,即
- sed 是适合这个工作的正确(标准 Unix)工具吗?
- 可以将两个表达式合并为一个吗?
感谢您的输入!
答案1
( tr , ';' | tr -d '"' ) < input.csv > output.csv
我会使用 Perl
perl -pe 'tr/,"/;/d' input.csv > output.csv
——但这个特定任务并不超出 sed 的范围。您不能合并这两个表达式。
答案2
您更喜欢哪种 (perl、sed 还是 awk) 取决于您自己;它们都能完成工作。既然您要求使用 sed,并且其他的都已发布,那就使用吧。这是您的正则表达式的更简单形式,可与您的示例行配合使用:
$ sed -e 's/"//g; s/,/;/g' infile.csv > outfile.csv
注意你能每次替换后用分号连接两个表达式。使用 GNU sed v4.1.5 测试。
以下是您原来的表达式:
$ sed -e 's/","/;/g; s/"//g' infile.csv > outfile.csv
我相当确信可以合并这两个替换。不确定这会是什么样的结果,而且我相当确信结果会比顶部的脚本更难读。如果我想到了什么(或者其他人在评论中提出意见),我会在这里添加它。
答案3
由于您正在处理记录,awk
因此更有意义。 话虽如此,它对 CSV 并不擅长,因为字段分隔符有些可变。 但如果您确定所有字段都用双引号括起来,那么这将有效:
awk -F'","' 'BEGIN {OFS=";"} { gsub(/(^")|("$)/, ""); $1=$1; print }'
这将 awk 的输入字段分隔符设置为“ ","
”(包括内部的双引号)。这几乎可以正常工作,但您必须处理前导和尾随的双引号,这些双引号会被函数剥离gsub
。强制它使用新的输出字段分隔符重新编译记录,该分隔符在 BEGIN 块中$1=$1
定义。然后打印出整个记录。;
print
这更整洁一些:
awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { $1=$1; print }'
它将输入字段分隔符设置为包含记录开头和结尾的双引号的正则表达式,但也会导致打印出一个空的开头和结尾字段。您可以轻松删除结尾字段:
awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { NF=NF-1; $1=$1; print }'
NF
是字段数,减一会砍掉最后一个字段。但我想不出砍掉第一个字段的方法。
但是,如果您知道输入始终有五个字段,那么您可以这样做:
awk -F '(^")|(",")|("$)' 'BEGIN {OFS=";"} { print $2,$3,$4,$5,$6 }'
请注意,这会摆脱$1=$1
构造,我们只有在打印(隐含的)$0 时才需要它。
尽管如此,我可能最终会使用 perl 和众多可用的CPAN 上的 CSV 模块。