通过行前缀拆分文件


4

我的数据如下:

60  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
61  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
62  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
63  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
64  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

我想通过行前缀将它拆分成单独的文件..像这样:

file 60 contains all lines prefixed with "60"
file 61 contains all lines prefixed with "61"
...

到目前为止我提出的最好的想法是grep所有的行前缀,然后遍历它并将其中的每一个grep插入一个单独的文件,但它是一个相当大的文件,所以这可能需要很长时间。也许有比循环和grepping更好的方法? grep分组的一些方法?我知道如果每个部分之间都有标记,有一种方法可以将文件剪切掉 - 但我不完全确定这是最好的方法。


另外,如果有一些方法可以在vim中做到这一点也很好
slf

Answers:


9

如果调用输入文件 data,一个解决方案是:

awk '{print>$1}' data

awk,调用第一个字段(列) $1。以上循环遍历每一行输入( awk 这是隐含的)并将该行写入名称为第一个字段的文件。

更详细:

  • 该命令放在大括号中。由于大括号前没有限定符,因此命令将在每个输入行上运行。

  • 命令 print没有参数,将打印整个输入行。

  • 符号 > 表示将输出重定向到文件

  • 文件名指定为 $1 它再次指的是输入行第一个字段中的任何文本。

因此,此命令将创建名为的文件 60, 61等等,它将包含输入文件中的相应行。

处理非常大的数据集

默认情况下, awk 保持所有文件句柄处于打开状态,直到整个命令完成。因此,对于非常大的数据集,可能会超出打开文件数量的系统限制。最简单的解决方案是在写完后使用append并关闭每个文件:

awk '{print>>$1; close($1)}' data

因为这样使用 >> (追加),这将添加到现有数据文件而不是覆盖它们。如果这不是您想要的,请在运行此命令之前删除它们。


所以在bash我需要说>>附加到文件但在awk中单个>会追加?
slf

@slf awk 不喜欢 bash。在单个调用中 awk,如上面的命令,第一次使用 >filename 将覆盖 filename。任何后续使用 >filename但是,会的 附加 。因此,上面的代码 awk 应该做你想做的事。使用 >> 如果你想要总是追加,保留之前文件中的内容 awk 跑了。
John1024

这是我遇到的同样问题 stackoverflow.com/questions/21093626/split-file-using-awk - 没有关闭(fd)然后你用完文件句柄
slf

@slf好点。为了处理大型数据集,我在答案中添加了一个版本 close
John1024

@ l0b0这听起来很奇怪。 Awk逐行处理。此脚本不会创建任何可能占用RAM的数组或其他数据结构。虽然处理那么多数据可能需要时间,但在这种情况下,我认为没有理由使用RAM。您是否尝试过不同版本的awk,例如gawk或mawk,以查看结果是否有所不同?
John1024
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.