【问题标题】:How to split a CSV file into multiple txt files using awk (or other command line tool)?如何使用 awk(或其他命令行工具)将 CSV 文件拆分为多个 txt 文件?
【发布时间】:2022-01-07 06:52:25
【问题描述】:

我有一个如下所示的 CSV 文件:

1,apple
2,orange
3,orange
4,pear
5,banana

CSV 文件有数千行。

现在我想将它拆分成数千个单独的 .txt 文件。

每个 .txt 文件都应以逗号前的数字命名,并且 .txt 文件的内容应包含逗号后的单词,如下所示:

1.txt  contains: apple
2.txt  contains: orange
3.txt  contains: orange
4.txt  contains: pear
5.txt  contains: banana

等等。

有一个 similar question here 询问如何使用 bash 脚本执行此操作,但我想使用命令行(awk 或类似的)执行此操作,并且使用 awk 对该问题的当前答案无法正常工作。

【问题讨论】:

  • This "awk -F, '{print $2 > $1 ".txt"}' file.csv " 来自类似问题的命令运行良好,我尝试使用您给定的“示例”输入文件,它给出了所需的输出文件(带有文件名)及其内容。
  • @c_bfx 这很奇怪,因为当我尝试时它会给出这个错误awk: syntax error at source line 1 context is {print $2 > $1 >>> ".txt" <<< awk: illegal statement at source line 1。我在 Mac 上。那会有什么不同吗?
  • 试试:awk -F, '{print $2 > ($1 ".txt")}' file.csv
  • 成功了!谢谢!如果您将其添加为答案,我将接受它作为解决方案。或者如果你不想,我会为你做。
  • 第一列中的这些数字是唯一的吗,或者您是否可以在第一列中有两行编号为1?您的 CSV 是否有标题行(如果有,请在您的示例中显示)?

标签: awk command-line terminal


【解决方案1】:
print $2 > $1 ".txt"

根据 POSIX awk 是一种未定义的行为,因此不同的 AWK 会对 print > a b 的行为做出不同的选择。

您应该在重定向运算符之后将字符串连接分组在一个表达式中,如下所示:

awk -F, '{print $2 > ($1 ".txt")}' file.csv

我认为原因是 > 运算符优先于 sting 连接,从而使 $2 > $1 成为单个命令,然后将 .txt 视为语法错误。


在非 gnu AWK 上,> 运算符每次都会打开一个新文件,如果输入超过几行,awk 将由于打开文件句柄的限制而开始抛出错误。每次使用后都应使用此命令关闭文件句柄:

awk -F, '{fn = $1 ".txt"; print $2 > fn; close(fn)}' file.csv

【讨论】:

  • 这有效,但一旦达到记录号 2557 就会停止并抛出此错误 awk: can't open file 2557.txt input record number 2557, file file.csv source line number 1。它与 2557 单元格中的文本没有任何关系,因为如果我删除该单元格并重新运行它仍然会卡在 2557 处(现在该单元格中有不同的文本)。知道这里发生了什么吗?
  • 试试这个:awk -F, '{fn = $1 ".txt"; print $2 > fn; close(fn)}' file.csv
  • 不仅仅是旧版本的 awk 需要括号,它只是每个 POSIX 未定义的行为,因此不同的 awk 对 print > foo bar 的含义做出不同的选择。我已经看到“打开的文件太多”错误发生在少于 20 个输出文件的情况下,所以不仅仅是大量的输出文件可能会出现问题,除非你有少于 15 个,否则我不会指望没有这个问题输出文件。
  • 非常感谢 Ed 的洞察力。我将在我的答案中编辑解释。
【解决方案2】:

使用这个awk你可以获得五个文件:

awk -F, '/^[[:digit:]]+/ {close(output); output=$1} {$1=$1".txt";$2=" contains: " $2;print > output}' file
  • 每个文件的内容和名称:
$ cat 1                                                                        
1.txt  contains: apple
$ cat 2
2.txt  contains: orange
$ cat 3
3.txt  contains: orange
$ cat 4
4.txt  contains: pear
$ cat 5
5.txt  contains: banana

你可以看到这些帖子:

【讨论】:

  • 这是抛出错误awk: null file name in print or getline input record number 1, file file2.csv source line number 1
  • 也许我在最后写了名字file,而你写了名字file.csv...
  • 我的 csv 文件名为 file2.csv。当我使用awk -F, '/^[[:digit:]]+/ {close(ouput); output=$1} {$1=$1".txt";$2=" contains: " $2;print > output}' file2.csv 时,它会给出错误awk: null file name in print or getline input record number 1, file file2.csv source line number 1。当我尝试awk -F, '/^[[:digit:]]+/ {close(ouput); output=$1} {$1=$1".txt";$2=" contains: " $2;print > output}' file2 时,它会给出错误awk: can't open file file2 source line number 1
  • OP 可能有一个示例中未显示的不以数字开头的标题行,或者他们可能正在运行不支持字符的非 POSIX awk(例如nawk[[:digit:]] 等类在第一次调用 print 时不会填充 output
  • 顺便说一句,你有一个错字 - close(ouput) 应该是 close(output)(中间有一个 t)。
猜你喜欢
  • 1970-01-01
  • 2017-11-09
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多