Linux:列出文件名中唯一的部分

3
我在一个目录中有大约50K个文件(使用Linux操作系统),它们的命名规则如下:USER_ID.ORACLE_JOB_ID.SEQUENCED_NUMBER.pdf 我需要将所有唯一的ORACLE_JOB_ID列出到一个文本文件中。该如何实现?
PS:忘记提到同一目录中还有其他命名规则不同的文件,我必须避免它们。
谢谢!
示例: 1.6778390.done 2.o6778390.out 3.AWRX_GBL_FAR1.98567432.4.dat.xml 4.AWRX_GBL_FAR1.34789214.4.pdf

这三个字段中允许使用哪些字符?例如,如果USER_ID没有数字,而ORACLE_JOB_ID只有数字,那么解决方案将更简单。但是解决方案可能会是“ls -1 | sed yada yada yada | uniq”。 - Camille Goudeseune
忘了提到同一目录中还有其他文件,它们具有不同的命名约定,我必须避免它们。USER_ID 是字母数字混合,ORACLE_JOB_ID 和 SEQ_NUM 是数字。 - Nitin
1
@Nitin,如果我们要帮助你把好坏分开,我们需要看到目录中所有命名约定的具体示例。 - pilcrow
@pilcrow 在上述问题中添加了示例。 - Nitin
2个回答

9
ls | awk 'BEGIN{FS="."}{ print $2 }' | sort | uniq > file.txt

ls命令可以获取当前目录中所有文件名的列表。

awk命令可以将每个文件名按照字段分隔符“.”进行拆分,并只打印第二个字段。

sort命令可以对这个第二个字段进行排序。

uniq命令可以去除连续重复的行。

编辑:如果您想限制只列出当前目录中的.pdf文件,请使用:

find . -iname '*.pdf' | awk 'BEGIN{FS="."}{ print $3 }' | sort | uniq > file.txt

当当前目录中有大量pdf文件时,使用ls *.pdf命令将会将参数溢出到ls命令中,错误信息显示因为这个相当于使用50K个不同的命令行参数调用ls,导致ARGV溢出。


1
我认为你的awk脚本需要是'BEGIN {FS="."} {print $2}' - zwol
2
@Nitin 处理这个问题的一种常见方法是将 ls *.pdf 更改为 find . -maxdepth 1 \( -type f -a -name '*.pdf' \) -print | sed 's:^\./::' - zwol
1
@qwwqwwq 您所说的-iname选项是什么?此外,前导的./意味着您现在需要在awk脚本中使用print $3,我认为。 - zwol
@qwwqwwq 感谢你的正确解决方案,太棒了!"find" 命令运行良好。 - Nitin
2
“sort | uniq” 是如此常见,以至于该功能已经内置到 sort 中。 - pilcrow
显示剩余4条评论

2

本着“有多种方法可以做到”的精神,这里有一个Perl的一行代码,它在功能上等同于qwwqwwq的shell管道:

perl -le 'my %seen; print for sort grep !$seen{$_}++, map { (split /\./)[1] } <*>'

<*>可以替换为任何glob表达式,例如<*.pdf>仅操作文件名以.pdf结尾的文件。


在好的一面,这将高效地流式传输目录,而不是一次性读取它。(甚至我的系统上的find()也是如此。)但坏的一面是,它也会对每个匹配的条目进行stat(2)操作。(对我来说,find()也是这样做的。) - pilcrow
@pilcrow 可能可以通过使用 opendirreaddir 来规避这个问题,但这样你就必须自己完成全局匹配,而额外的代码会超出我的一行代码的限制。 - zwol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接