如何将制表符分隔值(TSV)文件转换为BASH中的逗号分隔值(CSV)文件?

时间:2014-03-15 05:28:59

标签: bash csv awk tsv

我有一些TSV文件需要转换为CSV文件。 BASH中是否有任何解决方案,例如使用awk来转换这些?我可以像这样使用sed,但我担心它会犯一些错误:

sed 's/\t/,/g' file.tsv > file.csv
  • 无需添加引号。

如何将TSV转换为CSV?

4 个答案:

答案 0 :(得分:11)

更新以下解决方案通常不健全 ,尽管它们确实适用于OP的特定用例;请参阅底部,了解基于awk的强大解决方案


总结选项(有趣的是,它们的表现大致相同):

<强> TR

devnull的解决方案(在对问题的评论中提供)是最简单的:

tr '\t' ',' < file.tsv > file.csv

<强> SED

OP自己的sed解决方案完全正常,因为输入中不包含带引号的字符串(可能嵌入\t个字符。):

sed 's/\t/,/g' file.tsv > file.csv

唯一需要注意的是,在某些平台(例如,macOS)上,不支持转义序列\t,因此文字制表符号为char。必须使用ANSI引用($'\t')拼接到命令字符串中:

sed 's/'$'\t''/,/g' file.tsv > file.csv

<强> AWK

awk的警告是FS - 输入字段分隔符 - 必须明确地设置为\t - 否则默认行为会剥离前导和拖尾标签并仅使用一个,替换多个标签的内部跨度:

awk 'BEGIN { FS="\t"; OFS="," } {$1=$1; print}' file.tsv > file.csv

请注意,只需将$1分配给自身,awk就可以使用OFS - 输出字段分隔符重建输入行;这有效地取代了所有\t个字符。 ,个字符。 print然后只打印重建的行。


强大的awk解决方案

正如A. Rabus所指出的,上述解决方案无法正确处理本身包含,个字符的未加引号的输入字段 - 您最终将获得额外的CSV字段。

以下awk解决方案通过在"..."按需封装此类字段来解决此问题(请参阅上面的非健壮的awk解决方案,以获得该方法的部分解释):

awk 'BEGIN { FS="\t"; OFS="," } {
  rebuilt=0
  for(i=1; i<=NF; ++i) {
    if ($i ~ /,/ && $i !~ /^".*"$/) { $i = "\"" $i "\""; rebuilt=1 }
  }
  if (!rebuilt) { $1=$1 }
  print
}' file.tsv > file.csv
  • $i ~ /,/ && $i !~ /^".*"$/检测到包含,并且未用双引号括起来的任何字段

  • $i = "\"" $i "\""将字段用双引号括起来更新字段

  • 如前所述,更新任何字段会导致awk 重建来自带有OFS值的字段的行,即,在这种情况下,,,相当于有效的TSV - &gt; CSV转换;标记rebuilt用于确保每个输入记录至少重建一次

答案 1 :(得分:1)

这也可以通过Perl来实现:

为了将结果传递给新的输出文件,您可以使用以下内容:
perl -wnlp -e 's/\t/,/g;' input_file.tsv > output_file.csv

如果您想编辑该文件,可以调用-i选项:
perl -wnlpi -e 's/\t/,/g;' input_file.txt

如果您发现所处理的内容实际上不是制表符,而是多个空格,您可以使用以下内容用逗号替换每个出现的两个或多个空格:
perl -wnlpi -e 's/\s+/,/g;' input_file

请记住,\s表示任何空白字符,包括空格,制表符或换行符,不能在替换字符串中使用。

答案 2 :(得分:0)

tr命令:

tr '\t' ',' < file.tsv > file.csv

非常简单,即使在一个非常大的文件(大约10 GB)上也能给出绝对正确且非常快速的结果。

答案 3 :(得分:0)

使用 awk 对我有用

将tsv转换为csv

awk 'BEGIN { FS="\t"; OFS="," } {$1=$1; print}' file.tsv > file.csv

或将csv转换为tsv

awk 'BEGIN { FS=","; OFS="\t" } {$1=$1; print}' file.csv > file.tsv