我有一个包含多行的文件,其中的字段由标签:
ID Code Date
1 XX 23/1/2018
1 XX 11/3/2021
2 XX 14/5/2011
2 XX 20/9/2013
3 XX 08/7/2014
3 XX 11/9/2016
3 XX 27/10/2018
我想ID
根据列中最早日期的条目为每个参与者保留一个条目Date
。对于每个参与者,日期按从最早到最新的顺序排列。
我想要的输出是:
1 XX 23/1/2018
2 XX 14/5/2011
3 XX 08/7/2014
答案1
由于您声明每个参与者的记录是按从最旧到最新的顺序排列的,并且您只想打印每个参与者的最早日期的记录ID
,因此这相当于打印每个新的遇到的第一行ID
。使用以下方法可以轻松实现这一点awk
:
awk -F'\t' 'FNR>1 && !seen[$1]++' input.txt
这将首先将字段分隔符设置为\t
。然后,它会评估之间的条件' ... '
来决定是否打印当前行。如果出现以下情况,将会打印一行
- 每个文件的行计数器大于一(为了跳过标题行),和
- 该数组
seen
尚不包含第一列 ($1
) 的当前值的条目。这是有效的,因为取消引用尚未分配的数组值的计算结果为false
。此外,后缀运算符++
仅在该评估之后应用,因此对于特定的第一次遇到,ID
此返回 true,但对于任何以后的遇到,其中seen[$1]
大于 0,它将返回false
并从而禁止打印该行。
如果你想保留标题行,只需删除FNR>1
条件:
awk -F'\t' '!seen[$1]++' input.txt
(它将被打印,因为ID
这一行的字面上地 ID
,当然还有该特定值的第一次出现。)
答案2
以下用途磨坊主(mlr
,一种处理结构化数据的工具)来解析 TSV 文件中的记录。它按ID
值和输出对记录进行分组首先在每组中发现价值:
$ mlr --tsv head -g ID -n 1 file
ID Code Date
1 XX 23/1/2018
2 XX 14/5/2011
3 XX 08/7/2014
如果日期是不是对每个进行排序ID
,我们可以通过将每个日期字符串转换为 Unix 时间戳并在这个新字段上进行数字排序来对它们进行排序。排序后,我们进行与上面相同的操作,然后对剪切(删除)时间戳字段后的值head
重新排序。ID
mlr --tsv \
put '$ts = strptime($Date, "%d/%m/%Y")' then \
sort -n ts then \
head -g ID -n 1 then \
cut -x -f ts then \
sort -n ID file
输出与问题中所示的示例相同。
答案3
您可以使用以下代码获得所需的输出:
sed 1d file_of_data | sort -k1,2n -u
这样做的作用是,
- 用于
sed
丢弃(删除)包含标题的第一行 sort
结果文件按第一列数字排列,丢弃(该排序字段的)重复项
输出
1 XX 23/1/2018
2 XX 14/5/2011
3 XX 08/7/2014