我有一个这样的文件:
K1 bla STARTED
K1 bla FINISHED
K2 blu FINISHED
K3 bli STARTED
K3 bli DIED_SKIPPED_PERMANENTLY
K4 blo STARTED
K5 ble STARTED
K5 ble DIED_SKIPPED_PERMANENTLY
K6 blou STARTED
K6 blou STARTED
由此,我想获得一个文件,当第1列中的每个名称都有FINISHED
或DIED_SKIPPED_PERMANENTLY
时,只有包含此信息的行存在,而没有其他信息(带有STARTED或其他内容)。此外,如果两行相同(如K6中的那行),我只想打印一行。
在我的例子中,输出将是:
K1 bla FINISHED
K2 blu FINISHED
K3 bli DIED_SKIPPED_PERMANENTLY
K4 blo STARTED
K5 ble DIED_SKIPPED_PERMANENTLY
K6 blou STARTED
我不能只通过删除
grep -v STARTED
因为对于一些名称,比如我的例子中的K4,只有这一行存在,我想知道它是否开始,所以我需要保留这些信息。
我有一个文件,里面有我用获得的第1列的所有名称
awk '{print $1}' file | sort | uniq > names # 7,752 lines
我在想一个这样的循环:
对于文件"名称"中存在的每个名称,执行:
如果带有$line
的行中有一行包含FINISHED
或DIED_SKIPPED_PERMANENTLY
,则在我的输出中只打印该行,不打印其他行。否则,保留所有包含该名称的行。但删除相同的行。
这是我的想法,但我不知道该怎么做。如果有人能帮助,我将不胜感激
我们可以使用STARTED
在字典上大于FINISHED
和DIED_SKIPPED_PERMANENTLY
这一事实,并使用
sort filename | awk '!seen[$1,$2]++'
因为STARTED
在字典上是最大的,所以当sort
完成时,STARTED
行将总是出现在FINISHED
或DIED_SKIPPED_PERMANENTLY
行之后。awk代码遍历如此排序的行,只打印那些以前没有看到字段1和2组合的行。
使用awk和数组
awk '!a[$1]||/DIED_SKIPPED_PERMANENTLY|FINISHED/{a[$1]=$0}END{for(i in a)print a[i]}' f
输出
K1 bla FINISHED
K2 blu FINISHED
K3 bli DIED_SKIPPED_PERMANENTLY
K4 blo STARTED
K5 ble DIED_SKIPPED_PERMANENTLY
K6 blou STARTED
请注意,这是为了获得您发布的预期输出,但不适用于实际描述。
awk '$3 ~ /FINISHED|DIED_SKIPPED_PERMANENTLY/ && !a[$0]++' input
这只需检查第三列是否与FINISHED或DIED_SKIPPED_PERMANENTLY匹配,并将整行存储在数组a
中,仅在第一次看到时打印。注意,这将打印第三列中包含"FOO_FINISHED"的行,但这应该不是问题。然而,考虑到提供的示例输出,我认为您实际上正在寻找:
awk '$1!=p && NR>1{print l}; {p=$1;l=$0}END{ if($1!=p)print l}' input
当列1中的键连续出现时,它打印列1中出现给定字段的最后一行。