【问题标题】:Shell or AWK script to group duplicate entry using first field and find difference using last field使用第一个字段对重复条目进行分组并使用最后一个字段查找差异的 Shell 或 AWK 脚本
【发布时间】:2013-01-29 19:01:23
【问题描述】:

我想编写一个脚本(shell 脚本或 awk)来打印所有重复条目的 $1(第一个字段)以收集,然后使用最后一个值来查找最后一个条目和第一个条目之间的差异,或者可能会注意值的差异在每个重复的条目。

例如,我的文件有以下条目:

counter1 is 100
counter2 is 200
counter3 is 300
counter1 is 1000
counter2 is 2000
counter3 is 3000
counter1 is 10000
counter2 is 20000
counter3 is 30000

我要打印:

counter1 is 100
counter1 is 1000
counter1 is 10000
counter2 is 200
counter2 is 2000
counter2 is 20000
counter3 is 300
counter3 is 3000
counter3 is 30000

现在每个计数器都有一些增加的值,所以我想找出同一个计数器的每个值之间的差异:

counter1 is 100
counter1 is 1000 | difference 1000-100 = 900
counter1 is 10000| difference 10000-100= 9900

我能够打印重复的条目,但无法将它们捆绑在一起,它的出现顺序与文件的顺序相同。

MacBook-Air:linuxscripts jimdev$ awk 'NR==FNR && a[$1]++ {b[$1];next} $1 in b' FS=" " countr.txt countr.txt 

counter1 is 100
counter2 is 200
counter3 is 300
counter1 is 1000
counter2 is 2000
counter3 is 3000
counter1 is 10000
counter2 is 20000
counter3 is 30000

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    这对你有用吗?

    sort countr.txt | grep -v '^$'  | awk '
    BEGIN { field1="different" ; firstval="0" ; }
         $1 !~ field1 { print $0 ; field1 = $1 ; firstval = $NF ; continue;}
         $1  ~ field1 { print $0 " | difference " $NF "-" firstval " = " $NF-firstval ; }'
    

    这是输入文件的输出,如您的帖子所示:

    counter1 is 100
    counter1 is 1000 | difference 1000-100 = 900
    counter1 is 10000 | difference 10000-100 = 9900
    counter2 is 200
    counter2 is 2000 | difference 2000-200 = 1800
    counter2 is 20000 | difference 20000-200 = 19800
    counter3 is 300
    counter3 is 3000 | difference 3000-300 = 2700
    counter3 is 30000 | difference 30000-300 = 29700
    

    【讨论】:

    • 您可以使用 printf 和 "%40s" 或 "%-40s" 之类的东西漂亮地打印整个内容
    • MacBook-Air:linuxscripts jimdev$ sort countr.txt | grep -v '^$' | awk' 开始 { field1="不同" ; firstval="0" ; } $1 !~ field1 { 打印 $0 ;字段1 = $1 ;第一个值 = $NF ; continue;} $1 ~ field1 { print $0 " | difference " $NF "-" firstval " = " $NF-firstval > 它打印 > 不确定我是否没有正确复制它
    • 没有正确复制,但它给了我一些错误:MacBook-Air:linuxscripts jimdev$ sort countr.txt | grep -v '^$' | awk '开始 { field1="不同" ; firstval="0" ; } $1 !~ field1 { 打印 $0 ;字段1 = $1 ;第一个值 = $NF ;继续;} $1 ~ field1 { 打印 $0 " | 差异 " $NF "-" firstval " = " $NF-firstval ; }' awk: 在源代码第 1 行的循环之外继续非法上下文是 BEGIN { field1="different" ; firstval="0" ; } $1 !~ field1 { 打印 $0 ;字段1 = $1 ;第一值 =(NF) ; >>> 继续;}
    • 感谢 Olivier 的帮助
    • 您可以复制/粘贴整个块,这样会更好(因为语法非常精确)。如果有帮助我很高兴
    【解决方案2】:

    假设您的数据位于名为data.txt 的文件中。 您可以通过 sort 和 awk 简单的 if(或使用模式)来获得它:

    sort data.txt | awk 'BEGIN{last = ""; value = 0;} {if ($1 == last) {print $1" is "$3" | difference "$3"-"value" = "($3-value)}else{last = $1; value = $3; print $1" is "$3;}}' -
    

    解释:首先对输入进行排序以使“计数器”按升序排列。然后在这里我们使用AWK 表达式:

    1. 我们使用 2 个时间变量:last,存储当前计数器,以及第一个计数器的值。我们在 AWK 脚本的 BEGIN 部​​分对其进行初始化:BEGIN{last = ""; value = 0;}

    现在,对于每一行,我们执行以下代码:

    if ($1 == last) {
        print $1" is "$3" | difference "$3"-"value" = "($3-value);
    } else {
        last = $1;
        value = $3;
        print $1" is "$3;
    }
    

    第 1 行:将第一个字段(计数器)与 last 进行比较,该字段存储了最后一个计数器标签,以便了解我们是否应该打印差异。

    第 2 行:如果当前行的计数器标签与前一行相同,我们打印差异。

    第 3 行:否则,这是一个基本情况,所以我们保存当前的计数器标签以便与下一行进行比较,其值计算差异并打印该行。

    1. 如果新行与前一行具有相同的计数器标记,我们将保留这些值并计算与该计数器第一个值的差值。否则,我们存储新的计数器标签(在最后一个变量中)及其值(在值中),我们只打印该行。

    这是您输入样本的输出:

    counter1 is 100
    counter1 is 1000 | difference 1000-100 = 900
    counter1 is 10000 | difference 10000-100 = 9900
    counter2 is 200
    counter2 is 2000 | difference 2000-200 = 1800
    counter2 is 20000 | difference 20000-200 = 19800
    counter3 is 300
    counter3 is 3000 | difference 3000-300 = 2700
    counter3 is 30000 | difference 30000-300 = 29700
    

    【讨论】:

    • 嘿,我们几乎有相同的解决方案 ^^ 除了他坚持使用“最后一个字段”所以我使用 $NF 而不是 $3 ...我选择了模式而不是 if,但这显然是相同的算法。高五^^
    • Jajaja 即使是sort 之前的AWK !我在回答之前提到使用模式而不是 if 语句,然后查看您的解决方案,虽然模式更优雅,但我认为 if 对于初学者来说会更容易。恭喜您的解决方案!
    • Arutaku,这是输出
    • MacBook-Air:linuxscripts jimdev$ sort countr.txt | awk '开始{最后一个 = ""; value = 0;} {if ($1 == last) {print $1" is "$3" | 差值 "$3"-"value" = "($3-value)}else{last = $1;价值 = 3 美元;打印 $1" 是 "$3;}}' 是 |差 -0 = 0 是 |差 -0 = 0 是 |差异 -0 = 0 计数器 1 为 100 计数器 1 为 1000 |差异 1000-100 = 900 counter1 是 10000 |差异 10000-100 = 9900 counter2 是 200 counter2 是 2000 |差异 2000-200 = 1800 counter2 是 20000 |差异 20000-200 = 19800 counter3 是 300 counter3 是 3000 |差异 3000-300 = 2700 counter3 是 30000 |区别3
    • 那是因为您的输入文件中有空行,不是吗?您可以删除它们,按照 Olivier 的建议添加 |grep -v "^$"|,或者在 AWK 中添加 if 语句,检查 if (NF != 3) { ... }。就是这样!
    猜你喜欢
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 2017-01-02
    • 2018-07-31
    • 1970-01-01
    • 1970-01-01
    • 2013-07-29
    相关资源
    最近更新 更多