重置awk中的行号计数

时间:2012-10-22 22:54:26

标签: bash awk

我有一个像这样的文件

file.txt

0   1   a
1   1   b
2   1   d
3   1   d
4   2   g
5   2   a
6   3   b
7   3   d
8   4   d
9   5   g
10   5   g
.
.
.

我希望每当第二列$1中的字段值使用awk或bash脚本更改时,第一列$2中的重置行数会计为0。

结果

0   1   a
1   1   b
2   1   d
3   1   d
0   2   g
1   2   a
0   3   b
1   3   d
0   4   d
0   5   g
1   5   g
.
.
. 

4 个答案:

答案 0 :(得分:8)

只要你不介意一点多余的内存使用量,并且第二列是排序的,我认为这是最有趣的:

awk '{$1=a[$2]+++0;print}' input.txt

答案 1 :(得分:6)

这个awk单行似乎对我有用:

[ghoti@pc ~]$ awk 'prev!=$2{first=0;prev=$2} {$1=first;first++} 1' input.txt
0 1 a
1 1 b
2 1 d
3 1 d
0 2 g
1 2 a
0 3 b
1 3 d
0 4 d
0 5 g
1 5 g

让我们分开脚本,看看它的作用。

  • prev!=$2 {first=0;prev=$2} - 这就是重置你的计数器的原因。由于prev的初始状态为空,我们重置第一行输入,这很好。
  • {$1=first;first++} - 对于每一行,设置第一个字段,然后增加我们用来设置第一个字段的变量。
  • 1 - 这是“打印线”的简写。它实际上是一个总是求值为“true”的条件,当条件/语句对缺少一个语句时,该语句默认为“print”。

非常基本,真的。

当然,一个问题是当你更改awk中任何字段的值时,它会使用设置的任何字段分隔符重写该行,默认情况下它只是一个空格。如果要调整此值,可以设置OFS变量:

[ghoti@pc ~]$ awk -vOFS="   " 'p!=$2{f=0;p=$2}{$1=f;f++}1' input.txt | head -2
0   1   a
1   1   b

盐味。

答案 2 :(得分:2)

解决方案:

file="/PATH/TO/YOUR/OWN/INPUT/FILE"

count=0
old_trigger=0

while read a b c; do
    if ((b == old_trigger)); then
        echo "$((count++)) $b $c"
    else
        count=0
        echo "$((count++)) $b $c"
        old_trigger=$b
    fi

done < "$file"

该解决方案(IMHO)具有使用可读算法的优点。我喜欢其他人给出的答案,但这并不是 对初学者来说很全面。

注意

((...))是一个算术命令,如果表达式非零,则返回退出状态0;如果表达式为零,则返回1。如果需要副作用(赋值),也用作let的同义词。见http://mywiki.wooledge.org/ArithmeticExpression

答案 3 :(得分:0)

Perl解决方案:

perl -naE '
    $dec  =  $F[0] if defined $old and $F[1] != $old;
    $F[0] -= $dec;
    $old  =  $F[1];
    say join "\t", @F[0,1,2];'
每次从第一列中减去

$dec。当第二列更改(其先前值存储在$old中)时,$dec会增加以将第一列再次设置为零。第一行工作需要defined条件。