根据一个复杂的条件删除一些行

时间:2015-11-26 15:31:45

标签: bash

文本文件的内容如下。

600466 a 37.50 25.28
600466 b 31.13 18.22
600466 c 64.80 61.39
600467 a 38.79 30.00
600467 b 28.73 41.04
600467 c 58.32 61.39
600468 a 33.09 25.28
600468 b 35.57 42.69
600468 c 58.32 60.12
600469 a 36.89 29.80
600469 b 35.57 30.94
600469 c 64.80 62.49
600470 b 37.35 35.02 *
600470 c 58.32 58.32 *
600471 a 29.22 25.47
600471 b 34.74 20.61
600471 c 64.80 62.81
600472 b 31.13 30.28*
600472 c 58.32 62.04 *

我用星号检查了一些行。

你可以让一行的第一个字段重复3次(所以它连续出现3次),但有些行不是。我想用一些shell命令删除那些行。

有没有人有想法?

(欢迎任何纠正我可怜的英语。谢谢你的提前)

4 个答案:

答案 0 :(得分:2)

您可以使用以下awk命令:

awk '++c[$1]<=3{m[$1]=m[$1]?m[$1]"\n"$0:$0}c[$1]==3{print m[$1]}c[$1]>3'

在多行而非优化版本中更好地解释:

example.awk:

{
    # Count the occurences of $1
    c[$1]++
}

c[$1]<=3{
    # Append the current line to a temporary storage. If the
    # temporary storage doesn't exist, create it.
    m[$1]=m[$1]?m[$1]"\n"$0:$0
}

# Print the temporary storage once $1 has appeared 3 times 
c[$1]==3{
    printf "%s\n", m[$1]
}

# Print the current line if the count of $1 is above '3'
c[$1]>3

这样称呼:

awk -f example.awk input.txt

输出:

600466 a 37.50 25.28
600466 b 31.13 18.22
600466 c 64.80 61.39
600467 a 38.79 30.00
600467 b 28.73 41.04
600467 c 58.32 61.39
600468 a 33.09 25.28
600468 b 35.57 42.69
600468 c 58.32 60.12
600469 a 36.89 29.80
600469 b 35.57 30.94
600469 c 64.80 62.49
600471 a 29.22 25.47
600471 b 34.74 20.61
600471 c 64.80 62.81

答案 1 :(得分:2)

如果你的连续行不能连续超过3行,那么:

$ cat tst.awk
$1 != prev { buf=""; cnt=0 }
{ buf = buf $0 ORS; cnt++; prev=$1 }
cnt == 3 { printf "%s", buf }

否则:

$ cat tst.awk
($1 != prev) && (NR>1) {
    if (cnt == 3) {
        printf "%s", buf
    }
    buf = ""
    cnt = 0
}
{ buf = buf $0 ORS; cnt++; prev=$1 }
END {
    if (cnt == 3) {
        printf "%s", buf
    }
}

无论哪种方式:

$ awk -f tst.awk file
600466 a 37.50 25.28
600466 b 31.13 18.22
600466 c 64.80 61.39
600467 a 38.79 30.00
600467 b 28.73 41.04
600467 c 58.32 61.39
600468 a 33.09 25.28
600468 b 35.57 42.69
600468 c 58.32 60.12
600469 a 36.89 29.80
600469 b 35.57 30.94
600469 c 64.80 62.49
600471 a 29.22 25.47
600471 b 34.74 20.61
600471 c 64.80 62.81

答案 2 :(得分:1)

cut -d' ' -f1 file \
| uniq -c \
| grep -v ' 3 ' \
| rev | cut -d' ' -f1 | rev \
| grep -vwFf- file > output

第一行输出第一列。

第二行计算每个值出现的频率。

第三行排除了存在3次的那些行。

第四行删除了计数。

第五行从原始文件中排除字符串。

答案 3 :(得分:1)

我会说:

awk '$1 != prev_1 {if (a[prev_1]==3) print buffer; buffer=""}
    {a[$1]++; buffer = (buffer?buffer ORS:"") $0}
    {prev_1=$1}
    END {if (a[$1]==3) print buffer}' file

也就是说,将缓冲区存储在变量buffer中,并在第一个字段发生更改时打印它,以防它的计数器正好3

测试

$  awk '$1 != prev_1 {if (a[prev_1]==3) print buffer; buffer=""} {a[$1]++; buffer = (buffer?buffer ORS:"") $0} {prev_1=$1} END {if (a[$1]==3) print buffer}' a
600466 a 37.50 25.28
600466 b 31.13 18.22
600466 c 64.80 61.39
600467 a 38.79 30.00
600467 b 28.73 41.04
600467 c 58.32 61.39
600468 a 33.09 25.28
600468 b 35.57 42.69
600468 c 58.32 60.12
600469 a 36.89 29.80
600469 b 35.57 30.94
600469 c 64.80 62.49
600471 a 29.22 25.47
600471 b 34.74 20.61
600471 c 64.80 62.81