按文件名中最大的数字对文件进行排序

按文件名中最大的数字对文件进行排序

我有一堆文件,全部命名如下:

name_file-1.txt
name_file-2.txt
name_file-3.txt
some_other_file-1.txt
some_other_file-2.txt

有数千种不同的文件名,有些-1.txt最后只有一个,有些带有-1.txt, -2.txt...-60.txt

我需要复制每个文件的最大编号,因此name_file-3.txt, some_other_file-2.txt。如何在 Linux 命令行上执行此操作?

答案1

zsh

typeset -A greatest
for f (*-*(n)) greatest[${f%-*}]=$f
cp -- $greatest /destination
  • *-*(n):名称包含-( *-*) 的非隐藏文件,按数字排序((n)glob 限定符)。
  • ${f%-*}:文件名的一部分,直到最右边-(如果没有,则到最后-)。
  • $greatest: 扩展到非空价值观的关联数组。所以这里,对于共享相同根目录的文件,只有编号最大的文件才会被扩展。

答案2

files=(*)
mapfile -t prefixes < <(printf "%s\n" "${files[@]%-*}" | sort -u)
for p in "${prefixes[@]}"; do ls -v "$p"* | tail -1; done
name_file-3.txt
some_other_file-2.txt

然后将它们复制到其他目录:

for ...; done | xargs cp -t /destination/directory

答案3

如果文件位于当前工作目录中并且它们的名称符合示例(数字前面有一个破折号),则以下符合 POSIX 标准的管道应该可以工作:

ls | sort -t- -k1,1 -k2,2rn | awk -F- 'k!=$1 {print; k=$1}' | pax -rw /path/to/dir

如果排序的 -u 选项稳定,则 awk 组件可以替换为 sort -u(以便始终选择集合的第一行来表示该集合)。 POSIX 不需要这种稳定性,但根据其手册,{Free,Net,Open}BSD 和 GNU 实现提供了这种稳定性。如果你喜欢诱人的命运:

ls | sort -t- -k1,1 -k2,2rn | sort -mut- -k1,1 | pax -rw /path/to/dir

无论哪种情况,目标目录都不能位于当前工作目录中。

答案4

我将文件拆分为制表符分隔的部分,以便进行更可靠、可自定义的文件名解析,然后使用 awk 查找每个部分的最高排名并进行报告。在继续下一步之前,请先尝试管道的每个部分!

find DIR -type f <other find criteron> -print | 
perl -lne 'print join("\t",(/^(.*?-)(\d+)(\.\w+)$/))' |
awk -F\\t '$2 > f[$1] { f[$1]=$2;e[$1]=$3; } END { for (k in f) { print k f[k] e[k] }}' |
xargs cp -t <desination_directory>

awk 脚本将每个文件名放入关联的数组条目中,始终保留找到的最高排名。扩展名存储在其自己的数组中。处理完所有输入后,将输出所有数组条目,每行一个。该xargs cp -t行将所有文件复制到您指定的目录。

还有另一种方法行不通如果数字大于 9 并且没有用 0 填充,那就很好。该方法按字典顺序对文件进行排序,然后在解析列表时,第一部分发生变化,使用最近看到的文件名。当文件名是这样的时候,它就不起作用:

file-9.txt
file-10.txt

因为 file-10.txt 将出现在 file-9 之前。上面的 awk 脚本进行了数值比较。

注意:带有制表符和换行符的文件名会导致阻塞。

注意事项 2:如果每个文件名前缀可以有多个扩展名,我们将不得不进行一些调整以使其正确。

相关内容