我想列出给定目录中存在的所有文件:
<filename>.wed
<filename>.tis
<filename>.are
<filename>LM.bmp
我目前正在使用 和 进行此find
操作sed
。它可以工作,但不优雅且缓慢!
find . -iname "*.wed" -exec echo {} \; | sed s/.wed$// $1 | sed s/..// $1 | while read in; do find . -name "$in.are"; done | sed s/.are$// $1 | sed s/..// $1 | while read in; do find . -name "$in.tis"; done | sed s/.tis$// $1 | sed s/..// $1 | while read in; do find . -name "$in*.bmp"; done
基本上,我为每个要过滤的扩展链接 a find
、twosed
和 a 。while read
仅仅 30K 的文件需要 >35 秒!我该如何改进它?
例子
如果目录中有名为AR0505.are
、AR0505.tis
、AR0505.wed
和 的文件AR0505LM.bmp
,则脚本将打印“AR0505”。
如果这些文件中的一个或多个丢失,则脚本将不会打印它。
答案1
如果我理解正确,您正在查找每个目标扩展名存在的所有文件名。如果是这样,你可以这样做:
( shopt -s nullglob;
for i in *.wed; do
set -- "${i//.wed}"{.tis,.are,LM.bmp}*;
[[ $# -eq 3 ]] && printf '%s\n' "${i//.wed}";
done )
解释
shopt -s nullglob
:这是一个特定于 bash 的选项,如果没有找到匹配的文件,则使 glob 扩展为空字符串而不是自身。它们的( )
存在只是为了确保仅为该命令设置该选项,并且不会影响父 shell。for i in *.wed; do ...; done
:迭代当前目录中名称以 结尾的所有文件或目录.wed
,将每个文件或目录保存为$i
."${i//.wed}"
:不带扩展名的文件名.wed
。set -- "${i//.wed}"{.tis,.are,LM.bmp}*
:大括号将扩展为foo.tis
等foo.are
,这*
是一个让 bash 尝试将它们匹配为通配符的技巧。这意味着它仅在实际文件名存在时才有效。[[ $# -eq 3 ]] && printf '%s\n' "${i//.wed}"
:如果 中正好有 3 个文件$@
,那么除原始.wed
文件外还有 3 个文件,则打印不带扩展名的文件名。
如果要打印所有 4 个文件名(包括扩展名),只需printf '%s\n' "${i//.wed}"
将printf '%s\n' "$i"
.
答案2
我认为主要瓶颈是产生的进程数量。这是一个简单的脚本,它一次性列出并过滤您的目录:
#!/usr/bin/perl
use strict;
use warnings;
my %files;
my $dir;
my @extensions = ("\.tis","\.are","LM\.bmp","\.wed");
opendir($dir, ".") || die "Error opening dir\n";
while (my $file = readdir($dir)) {
foreach my $ext (@extensions) {
if ($file =~ /^(.*)$ext$/sm) {
$files{$1} += 1;
}
}
}
closedir($dir);
foreach my $file (keys %files) {
if ($files{$file} == scalar(@extensions)) {
print "$file\n";
}
}
答案3
find . -type d -exec sh -c '
h=$1; cd "$h" || exit
set -- /dev/nul[l] [f]oobar.{wed,tis,are} [f]oobarLM.bmp; shift
case $# in 4 ) for arg; do printf "%s/%s\n" "$h" "$arg"; done ;; esac
' {} {} \;
注意:在这里,除了这 4 个文件之外,我们不查看其他任何文件,并且只有在ALL 4
找到时,才会显示它们,即使foobar.XXX
同一目录中存在其他文件。因为OP对此不是很清楚。
答案4
perl -le '
while ( <*LM.bmp> ) {
(my $f = $_) =~ s|LM\.bmp$||;
print $f if 3 == grep { -e $f . $_ } qw/.tis .are .wed/;
}
'