【问题标题】:Use AWK to get unique count of record file based on certain columns使用 AWK 根据某些列获取记录文件的唯一计数
【发布时间】:2017-09-08 02:43:36
【问题描述】:

我有一个 AWK 命令要修改,以根据主键获取记录文件的唯一计数。在记录文件中,有 21 个元素,第 1 列和第 18 列是 PK。记录都在一行上,记录分隔符是\^,字段分隔符是|。这是我到目前为止所拥有的,但它仍然给了我文件中的总记录数,但不是唯一的:

awk 'BEGIN{RS="\\^";FS="\\|";} {a[ $1  $18 ]++;}END{print length(a);}' filename

样本数据:

1|01212121|0|OUTGOING| | | | | |57 OHARE DR|not available|DALLAS|TX|03560|US|1131142334825|1|Jan 15 2004 11:12:06:576AM|Jan 15 2004  2:54:41:226PM|SYSTEM|\^

这类数据有 200 万行,我有 30 个重复项。

预期输出应为:1999970

【问题讨论】:

  • 提供样本输入和预期输出。
  • 您说 PK 是第 1 列和第 18 列,但您在脚本中使用的是第 1 列和第 19 列。
  • 抱歉,刚刚更新。
  • 等待你增加索引给定从 $1 $18 创建的键?只做 = 1 而不是 ++ ?还是我不懂语法
  • 为什么这个问题用pythonsed标记?

标签: shell unix awk


【解决方案1】:

对多字符 RS 使用 GNU awk 并在数组索引组件字段之间使用 SUBSEP 以使结果唯一:

awk 'BEGIN{RS="\\^"; FS="|"} NF>1{a[$1,$18]} END{print length(a)}' filename

如果您的输入文件/行以\^\n 而不仅仅是\n 结尾,则需要NF>1 测试。我们知道它确实以\n 结尾,因为您说if I do a wc -l on the file, it will return 1wc -l 只计算\ns 并且您的1 个示例输入行以\^ 结尾,所以这一切都让我相信您的文件确实以@ 结尾987654330@ 等NF>1 的测试是必要的,以避免在最终的\^ 之后包含空白记录。

【讨论】:

    【解决方案2】:

    至少记录分隔符 RS 只能容纳单个字符。由于所有内容都挤在一行中,您需要选择数据行的最后一个字符作为 RS 并丢弃最后一个字段(由 \ 组成)。 像这样修复它:

    awk 'BEGIN{RS="^";FS="|"} {a[$1,$18]++} END{print length(a)}' filename
    

    请注意,awk 现在将在输入中遇到的每个^ 上进行拆分。如果您只需要在 \^ 上拆分,建议如下:

    sed 's/\\^/\n/g' filename |awk 'BEGIN{FS="|"} {a[$1,$18]++} END{print length(a)}'
    

    编辑: 合并了@Ed 的评论。

    【讨论】:

    • wrt The record separator RS and the field separator FS can only hold a single character. - FS 在任何 awk 中都包含一个多字符正则表达式字符串,而在 GNU awk 中,RS 也可以是这样的正则表达式字符串(POSIX 需要 1 个字符 RS 并且多字符未定义)。切勿尝试通过连接字符串来创建唯一索引,在它们之间使用,(或 FS 或 SUBSEP)。问题是a bcab c 在连接时都是abc,因此您需要它们之间的一些东西来为每个组合创建一个唯一的值。
    • 添加了这个,这样建议看起来还可以。 @埃德莫顿
    • @EdMorton 我不确定 sed 是否能够解析这么长的一行,对此有何评论?
    • 我希望 sed 会窒息,OP 应该只使用 GNU awk 进行多字符 RS。
    猜你喜欢
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 2021-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多