如何在unix shell脚本中使用group by和max函数

如何在unix shell脚本中使用group by和max函数

输入:

20210602_1234_abc.txt
20210603_1234_def.txt
20210507_5678_abc.txt
20210607_5678_def.txt

输出:

20210603_1234_def.txt
20210607_5678_def.txt

我的脚本应首先根据第二列(此处为 1234 和 5678)进行搜索,然后选择与其关联的最大日期的文件(在本例中)20210603 和 20210607。

如何通过 UNIX shell 脚本获得这个?

答案1

对于zshshell,假设这些文件位于当前目录中:

$ ls
20210507_5678_abc.txt  20210602_1234_abc.txt  20210603_1234_def.txt  20210607_5678_def.txt
$ typeset -A h; for f (*_*_*.txt) h[${${(s[_])f}[2]}]=$f; print -rC1 - $h
20210603_1234_def.txt
20210607_5678_def.txt

在哪里

  • 的扩展*_*_*.txt将按词法排序,因此也按时间顺序排序。
  • ${(s[_])f}分裂$f_
  • ${...[2]}获取该分割产生的第二个字段
  • h[that]=$fh A:在该循环中,为 key 关联数组的元素that分配了完整的文件名。由于排序,最终您将获得给定日期的最新日期that
  • print -rC1 -- $h: s 列上的print哈希值aw 。r1 C

如果编写脚本,您可能需要对其进行一些分解以提高易读性:

typeset -A max

for file in *_*_*.txt(N); do
  parts=( ${(s[_]file} )
  max[$parts[2]]=$file
done

print -rC1 -- $max

(这里还添加N(nullglob) glob 限定符以避免该 glob 与任何文件不匹配时出现错误)。

答案2

使用awk并假设输入来自文本文件(问题从未以任何方式指定):

$ awk -F '_' 'max[$2] < $1 { max[$2] = $1; maxline[$2] = $0 } END { for (i in maxline) print maxline[i] }' file
20210607_5678_def.txt
20210603_1234_def.txt

这将每个输入行视为一组_- 分隔的字段。该max数组跟踪给定第二个字段的键的第一个字段的最大值,并且maxline[i]是与 中的最大值相对应的整行max[i]

当找到某个键​​的新最大值时,该键的maxmaxline值都会更新。最后,maxline打印所有字符串。


使用sort

$ sort -t _ -k 1,1nr file | sort -s -u -t _ -k 2,2
20210603_1234_def.txt
20210607_5678_def.txt

第一个按第一个分隔字段以相反的数字顺序对sort整个文件进行排序。_第二个sort对第二个字段进行排序,并且仅保留该字段的任何值的第一行。该-u选项sort使实用程序丢弃带有已经看到的排序键的行,并-s确保稳定的正在使用排序算法(即保证具有相同键的行不会重新排序)。

相关内容