【问题标题】:extract some lines according to one field using bash scripting使用 bash 脚本根据一个字段提取一些行
【发布时间】:2016-04-12 06:58:12
【问题描述】:

我需要您的帮助才能从 file1 获取以下结果文件,file1 太大了,我想根据第一列(字段 1)提取文件中的每个部分。提前致谢。

文件 1:
1111 3 4 5 7
1111 2 4 6 8
1111 1 5 9 3
1112 4 6 8 9
1112 6 8 7 7
1113 6 6 6 6
1113 7 7 7 7
...

结果
我们根据第一个字段获取所有文件,在简要文件中,结果应该是 3 个文件(file_1111、file_1112 和 file_1113),如下所示:
file_1111 1111 3 4 5 7
1111 2 4 6 8
1111 1 5 9 3

file_1112
1112 4 6 8 9
1112 6 8 7 7

file_1113
1113 6 6 6 6
1113 7 7 7 7

最好的问候,

人力资源

【问题讨论】:

    标签: bash


    【解决方案1】:

    试试这个经过测试的版本:

    awk '{print>>"file_" $1;}' File_1
    

    默认情况下,awk 会在 $1 $2 等字段中拆分包含空格的行。

    这个单行命令将文件中的每一行写入与当前行的第一个字段关联的文件:$1。

    测试:

    $ cat File_1
    1111 3 4 5 7
    1111 2 4 6 8
    1111 1 5 9 3
    1112 4 6 8 9
    1112 6 8 7 7
    1113 6 6 6 6
    1113 7 7 7 7
    
    $ awk '{print>>"file_" $1;}' File_1
    
    $ ls
    File_1  file_1111  file_1112  file_1113
    $ cat file_1111
    1111 3 4 5 7
    1111 2 4 6 8
    1111 1 5 9 3
    $ cat file_1112
    1112 4 6 8 9
    1112 6 8 7 7
    $ cat file_1113
    1113 6 6 6 6
    1113 7 7 7 7
    

    纯 bash 脚本可能会在一个循环中运行许多进程,我相信它应该比一个 awk 命令慢。

    --edited-- File_1 是否排序无关紧要。它会成功的。

    【讨论】:

    • 这和脚本解决方案都可能受益于文件扩展名(例如"file_" $1 ".txt";)无论如何都是一个好的解决方案。
    • 您应该使用>,而不是>> 进行输出重定向(这是awk,而不是shell - 语义不同),并且您需要在输出右侧为任何表达式加上括号重定向或行为未定义,因此只会在某些 awk 中执行您期望的操作。您不需要结尾的分号。所以正确的脚本是awk '{print>("file_" $1)}' File_1,除非你的文件很重要并且你使用的awk不能在内部管理打开的文件(gawk可以),然后你需要awk '$1!=prev{close(out); out="file_" $1; prev=$1} {print > out}' File_1
    • @EdMorton 谢谢你,首先请注意测试确实执行了,所以解决方案就像一个魅力!我将测试所有这些信息。我可以使用 debian squeezie 进行测试和mawk。盒子上没有gawk。我的主要来源是Awk -A Tutorial and Introduction - by Bruce Barnett - The Grymoire!。
    • @EdMorton Remark1 > 正在截断已经存在的输出文件。我故意使用了>>。
    • @EdMorton 我想我今天学到了东西 :) 他!这最后一个来源也来自你! ;) 我知道awk 解析器在标准中的规定不够准确,这就是为什么需要( 和)。
    【解决方案2】:

    如果数据按照显示的方式排序,shell 可以做得很好。

    while read FileField DataFields || [ "$FileField" ] ;do
      echo "$FileField $DataFields" >> "file_$FileField"
    done < "$yourInputFile"
    

    如果数据未按所示排序,对于大型数据集,awk 答案可能会更快。

    ...尽管文件字段在新文件中似乎毫无意义。 echo "$DataFields" &gt;&gt; "file_$FileField"

    【讨论】:

    • 我喜欢它。我更喜欢它的扩展。如果您的read 支持-r,那是值得添加的。
    • @DavidC.Rankin A read 没有 -r ? :-) pubs.opengroup.org/onlinepubs/9699919799/utilities/read.html
    • @DavidC.Rankin -r 可能加快速度,但结果应该与指定的数据集相同......我只是想保持它“尽可能简单,但并不简单。”
    • 我在一台旧的 Linux 机器上测试了这个解决方案和 (@Jay jargot) Awk 解决方案。对于输入,我使用了一个百万行排序文件和一个百万行未排序文件。对于已排序的文件,此解决方案耗时 36 秒,而 Awk 解决方案耗时 0.5 (!) 秒。对于未排序的文件,此解决方案耗时 36 秒(如预期的那样没有变化),而 Awk 解决方案耗时 14 秒。我对 awk 在已排序文件上的速度和未排序文件上的巨大减速感到惊讶。 Bash 的表现比我预期的要好,但它显然不适合这样的工作。
    • @pjh 所有的 shell 实现都不是一样的。在大多数基本用例中,与busybox ash相比,Bash 的速度非常慢,尤其是当 LANG 设置为 C 以外的任何内容时。仅通过更改 shebang 并将 LANG 设置为 C,我就看到了 80-100 倍(不是百分比)的改进。FWIW ,2.x 版本的 bash 通常比当前版本快 4-8 倍。 IIRC,我之前的测试发现这种方法比 awk 更快,文件长达 1000 行左右,之后 awk 迅速获胜。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 2014-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多