【问题标题】:Use bash script to extract certain type names and corresponding numbers使用 bash 脚本提取某些类型名称和对应的数字
【发布时间】:2012-02-21 21:34:18
【问题描述】:
A: XXX (Done after 2 rounds)
A: YYY (Done after 1 rounds)
A: ZZZZ (Done after 4 rounds)
A: XXX (Done after 2 rounds)
A: ZZZZ (Done after 1 rounds)
A: YYY (Done after 2 rounds)
A: YYY (Done after 1 rounds)

对于上述文件,我想提取某些名称,例如XXX, YYY, ZZZZ 以及每个名字的轮数。

最后,我期望的结果是这样的:

XXX 2 2
YYY 1 2 1
ZZZZ 4 1

我觉得我应该使用 sed 或 awk,但不知道如何使用它们。有没有人有好的解决方案?非常感谢。

【问题讨论】:

  • “我觉得应该用sed或者awk,但是不知道怎么用”。我推荐阅读sed & awk

标签: bash sed awk extract


【解决方案1】:
awk '{ names[$2] = names[$2] " " $5; } END { for (name in names) print name " " names[name] }' file

说明:

每个输入行都传递给命令names[$2] = names[$2] " " $5,该命令会创建一个名为names 的数组,其索引不是数字——它们是在输入行中显示为第二个字段的单词:XXX, YYY 和 ZZZZ。它们的值在每行的第 5 个字段中累积相应的数字。

当输入文件用完时,END 遍历索引名称,打印每个名称后跟它的累积数字字符串。

【讨论】:

  • v 不错 +1!但是,打印语句中不需要“”。此外,如果通过管道传输到 sort,您将获得所需的输出,准确无误。
  • 它有效。但是我不明白names[$2] = names[$2] " " $5这个命令是如何实现累加数的..
  • 这是 awk 的奇迹之一。以第一行输入为例,$1 = Classification:, $2 = "XXX", $3 = "(CLASSIFIED", $4 = "after", $5 = "2"。所以awk的命令变成names["XXX"] = names["XXX"] " " 2。 awk 有“关联数组”,这意味着它们的索引可以是非数字的。字符串“XXX”用作称为“names”的数组的索引。因此该行设置数组 element到之前的任何内容,后跟一个空格,然后是输入行中的数字。这有帮助吗?
  • 那么对于第一次出现,names["XXX"] 的元素值是多少?因为names["XXX"]没有初始化
  • awk 中未初始化的变量为空。请参阅gnu.org/software/gawk/manual/gawk.html 了解更多信息。
【解决方案2】:

我喜欢这样的 Perl 数据结构(数组的散列):

perl -lane '
        push @{$packets{$F[1]}}, $F[4]
    } 
    END {
        foreach $name (keys %packets) {print join(" ", $name, @{$packets{$name}})
    }
'

【讨论】:

    【解决方案3】:

    这可能对你有用:

    cut -d' ' -f2,5 file |
    sort -sk1,1 |
    sed ':a;$!N;s/^\(\(\S\+\).*\)\n\2/\1/;ta;P;D'
    XXX 2 2
    YYY 1 2 1
    ZZZZ 4 1
    

    解释:

    • 使用cut -d' ' -f2,5 file提取字段2和5,即第一行XXX 2
    • 按第一个字段排序但保留顺序sort -sk1,1
    • Sed 连接第一个字段相同的行并附加第二个字段。 sed ':a;$!N;s/^\(\(\S\+\).*\)\n\2/\1/;ta;P;D'

    sed 命令的工作原理如下:

    • 创建标签:a
    • 将换行符添加到当前行(模式空间 PS),然后是下一行,除非它是最后一行。 $!N
    • 使用替换命令将当前行的第一个字段与前一行的第一个字段匹配,然后将其与前面的换行符一起删除。 s/^\(\(\S\+\).*\)\n\2/\1/
    • 如果替换成功,则跳转到标签。 ta
    • 如果替换不成功,将 PS 打印到第一个换行符。 P
    • 删除 PS 直到并包括第一个换行符,然后在不刷新 PS 的情况下开始新的循环。 D

    【讨论】:

    • 感谢您的回复。我对sed不熟悉,你能解释一下吗?
    • @user1224398 我已经编辑了我的解决方案并提供了解释。
    猜你喜欢
    • 1970-01-01
    • 2021-10-23
    • 2017-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 1970-01-01
    • 2011-12-16
    相关资源
    最近更新 更多