我在具有特定命名系统的文件夹中有大量文件。它看起来有点像这样:
my_file_A_a.txt
my_file_A_d.txt
my_file_A_f.txt
my_file_A_t.txt
my_file_B_r.txt
my_file_B_x.txt
my_file_C_f.txt
my_file_D_f.txt
my_file_D_g.txt
my_file_E_r.txt
我想要一个命令行或一系列命令(可以使用临时文件,我有写权限),它们会返回如下内容:
A: 4
B: 2
C: 1
D: 2
E: 1
可以用很多ls -1 *A* | wc -l
命令来完成,但是需要很长时间,因为要计算几百个“组”。
此外,每个组名都是唯一的。有一个A
群,一个B
群,但没有AB
群。
假设您的文件名是“行为良好的”,即它们不包含换行符,下面的
ls
和组合awk
将起作用:这将重定向
ls
列出所有开始my_file*
到awk
程序的文件的命令的输出。该awk
程序将使用_
as 字段分隔符并检查第三个字段以跟踪数组中的出现count
,该数组使用组号作为“数组索引”。最后,它会打印出每个组发生频率的概览。
注意
_
中不能是文件名的一部分。a
d
f
awk
中的数组索引。for (i in count)
如果需要排序,您可以在sort
. 或者,如果您使用 GNU Awk,您可以通过添加配置设置 在NF==4{...}
规则之前。这将确保根据数组索引遍历数组,按字典(ASCII)顺序排序。ls
.for
循环重新格式化每个文件名以f
去除前导my_file_
和尾随_whatever.txt
,然后对该输出进行排序,并用于uniq
计算每个唯一值的出现次数。我会在通配符上循环处理它,然后在
[[
Conditional Expression 构造中使用 bash 的正则表达式功能从文件名中提取字段。唯一带括号的字段是第三个下划线分隔的字段;
collect
一旦它被捕获,我们在关联数组 ( )中增加该值。包含四个下划线分隔的字段并以字符串结尾的文件名与
.txt
扩展的通配符模式匹配+([!_])_+([!_])_+([!_])_+([!_]).txt
。每个+([!_])
匹配一个或多个非下划线字符,就像[^_]+
作为扩展正则表达式一样。我们可以通过删除最初的两个字段和最后一个字段以及
.txt
后缀字符串来从中提取第三个字段。该脚本仅假定文件名中的第三个字段不包含嵌入的换行符。
对问题中的示例文件名进行测试:
您可以通过一个简单的
awk
脚本对其进行过滤,以将其转换为您想要的任何格式。如果您的名字表现良好,这意味着其中任何一个都没有嵌入的换行符,那么您可以稍微简化脚本并
cut
改用它。使用 Raku(以前称为 Perl_6)
示例输入(当前目录列表):
样本输出:
作为简要说明,获取当前目录
dir()
列表并按_
下划线拆分。[假定文件名不以_
下划线开头/结尾]。因此获得的元素是:在那之后,Raku 有一个相当健壮的机制来生成/理解序列:只需输入就
[2,5,8...*]
可以拉出字母A,B,C,D,E
(每三个元素,编号从 开始0
)。然后Bag
,pairs
和sort
。(如果您确定
文件名中没有空格,则可以
split(" ")
在第一个调用之后添加第二个调用。然后您要提取的元素是[2,6,10...*]
)。注意 1:如果您有不符合 OP 列出的模式的无关文件名(并且正在弄乱您的计数),那么您可以将
dir
调用更改为类似于dir(test => / [ <-[_]>+ _ ] ** 3 /)
regex 上一个或多个文件名的子集非下划线后面跟着一个下划线,重复三遍。注意 2:如果您想要两列输出(
=>
中间没有),只需更改.say
为.put
. 或者,如果您更喜欢“Raku-ish”输出,请尝试使用.raku.say
,它会返回以下内容:https://docs.raku.org/routine/dir
https://docs.raku.org/type/Bag
https://raku.org
排序,sed 和 uniq 足够了:
另一个 oneliner,只有 3 个变量:
需要在排序输出中多放一行。