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

标签 bash awk csv

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

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

如何将 TSV 转换为 CSV?

最佳答案

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


总结这些选项(有趣的是,它们的表现都差不多):

:

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

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

sed:

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

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

唯一需要注意的是,在某些平台(例如 macOS)上,不支持转义序列 \t,因此只能使用文字制表符。必须使用 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上面的解决方案是对该方法的部分解释)。

如果此类字段还嵌入了 " 字符。,这些字符将转义为 "",符合 RFC 4180谢谢,Wyatt Israel

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

  • gsub("\"", "\"\"", $i) 转义嵌入的 " 字符。将它们加倍

  • $i = "\""$i "\"" 通过将结果括在双引号中来更新结果

  • 如前所述,更新任何字段都会导致 awk 使用 OFS重建来自字段的行,即本例中的 ,,相当于有效的 TSV -> CSV 转换; flag rebuilt 用于确保每条输入记录至少重建一次

关于bash - 如何在 BASH 中将制表符分隔值 (TSV) 文件转换为逗号分隔值 (CSV) 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22419979/

相关文章:

linux - 缩短 awk 命令管道

unix - 比较两个文件中的列,如果匹配则更改另一列中的字符串

python - 如何使用字符串作为 csv 阅读器的输入而不将其存储到文件中

python - .writerow() csv 返回一个数字而不是写入行

regex - 使用正则表达式忽略时,Bash "diff"实用程序将文件显示为不同

linux - Bash 跳过 python 命令

node.js - 无法在 Linux 中安装和运行我自己的 npm 模块

python - 文本文件之间的交集

linux - AWK - 如何列匹配文件 A 中的多个匹配项匹配文件 B 中的一个匹配项

python - pandas 在 csv 上提高 OutOfBoundsDatetime 但不在 sql 上提高 OutOfBoundsDatetime