Awk 删除第一次和最后一次出现列值的行

Awk 删除第一次和最后一次出现列值的行,awk,sed,find-occurrences,Awk,Sed,Find Occurrences,我有以下文件 ID Score Other ABR 0.98 NBNMSB BCG 0.76 NBNMSB CVD 0.6 NBNMSB BCG 0.9 VSCVA CVD 0.56 VSCVA ABR 0.9 VSCVA CVD 0.7 BAVSC BCG 0.4 BAV

我有以下文件

    ID      Score    Other
    ABR     0.98     NBNMSB
    BCG     0.76     NBNMSB
    CVD     0.6      NBNMSB
    BCG     0.9      VSCVA
    CVD     0.56     VSCVA
    ABR     0.9      VSCVA
    CVD     0.7      BAVSC
    BCG     0.4      BAVSC
    ABR     0.5      BAVSC
    AAC     0.1      BAVSC
    ABR     0.8      NBNMSB
    BCG     0.6      NBNMSB
    CVD     0.3      NBNMSB
    BCG     0.7      VSCVA
    CVD     0.0      VSCVA
    ABR     0.1      VSCVA
    CVD     0.5      BAVSC
    BCG     0.8      BAVSC
    ABR     1.0      BAVSC
我想排除第3列中第一次和最后一次出现的值,这样我得到的输出是:

ID      Score    Other
BCG     0.76     NBNMSB
CVD     0.56     VSCVA
BCG     0.4      BAVSC
ABR     0.5      BAVSC
BCG     0.6      NBNMSB
CVD     0.0      VSCVA
BCG     0.8      BAVSC

在awk你可以试试这个

awk 'NR==1
     {last[NR%3]=$3;lastLine[NR%3]=$0;}
     last[(NR-1)%3]==last[(NR-2)%3] && 
           last[(NR-1)%3]==last[NR%3]{print lastLine[(NR-1)%3]}' test
这将产生预期的输出:

ID      Score    Other
BCG     0.76     NBNMSB
CVD     0.56     VSCVA
BCG     0.4      BAVSC
ABR     0.5      BAVSC
BCG     0.6      NBNMSB
CVD     0.0      VSCVA
BCG     0.8      BAVSC
解释
1.NR==1简单打印第一行。
2.
{last[NR%3]=$3;lastLine[NR%3]=$0;}
将最后两行和当前行存储在一个数组中(
lastLine
)。

3.通过
last[(NR-1)%3]==last[(NR-2)%3]&&last[(NR-1)%3]==last[NR%3]
我们检查最后一行在第三列中是否与当前行具有相同的值,第二行是否与最后一行具有相同的值(即,它们在第三列中是否都具有相同的值)。在本例中,我们打印最后一行。

如果您有
tac
(或
gtac
),您可以删除第一个实例,反转文件,删除第一个(实际上是最后一个)实例,最后一次翻转文件

$ awk '$3==p;{p=$3}' file1 | tac | awk '$3==p;{p=$3}' | tac
BCG     0.76     NBNMSB
CVD     0.56     VSCVA
BCG     0.4      BAVSC
ABR     0.5      BAVSC
BCG     0.6      NBNMSB
CVD     0.0      VSCVA
BCG     0.8      BAVSC
编辑

这是一个更灵活的版本。只需将
c
的初始值设置为所需的列:

使用第3栏:

 c=3 && awk -v c=$c '$c==p;{p=$c}' file1 | tac | awk -v c=$c '$c==p;{p=$c}' | tac
使用第4列:

 c=4 && awk -v c=$c '$c==p;{p=$c}' file1 | tac | awk -v c=$c '$c==p;{p=$c}' | tac

另一个更简单的awk是:

awk 'NR == 1; prev != $3 {prev = $3; line = 0; next} 
{if (line) print line; line = $0}' foo.txt | column -t
你会得到

ID   Score  Other
BCG  0.76   NBNMSB
CVD  0.56   VSCVA
BCG  0.4    BAVSC
ABR  0.5    BAVSC
BCG  0.6    NBNMSB
CVD  0.0    VSCVA
BCG  0.8    BAVSC
这样做的目的是将第3列和行存储在名为
prev
line
的变量中,如果它们不是第一次和最后一次出现,则将它们打印出来

请注意,与使用
tac
和多次传递不同,这只需要对文件进行一次传递。

这可能适用于您(GNU-sed):


无需打印第一行(标题行)。一次读两行,如果这两行没有相同的第三列,则将其全部删除。否则,请打印第一行并附加下一行,然后重复。

如果不太麻烦的话,您能中断代码吗?我必须提供一个解释。你的意思是吗?是的,如果我有4列而不是3列,我该怎么做?例如,我的格式是abc 1234 2345 NBNMSB,等等,作为行,我该如何调整上面的代码以获得唯一的第4列,我试图用4替换3,还有什么我需要更改的吗?在这种情况下,只需将每个$3替换为$4。不要更改
%3
——这是只比较最后三行所必需的(即,正确放弃指定列值的第一次和最后一次出现)。我这样做:awk'NR==1{last[NR%4]=$4;lastLine[NR%4]=$0;}last[(NR-1)%4]==last[(NR-2)%4]&&last[(NR-1)%4]==last[NR%4]{print lastLine[(NR-1)%4]}'文件,但它没有吐出任何结果,我希望我做得对。还有,如果我有4列而不是3列,我该怎么做?例如,我的格式是abc 1234 2345 NBNMSB,等等,作为行,我该如何调整上述代码以获得唯一的第4列,我尝试用4替换3,还有什么我需要更改的吗?将
$3
全局更改为
$4
将是唯一需要的更改。非常好。另请参见编辑以获得更灵活的版本。如果通过过滤器反馈建议的输出(即,如果第3列中只有两个特定值,那么从字面上删除第一个和最后一个匹配项实际上会删除所有匹配项),您希望得到什么?
sed -r '1p;$!N;/(\S+)\n.*\1$/!d;P;D' file