查找同一目录中同时存在该文件名的多个变体的文件

查找同一目录中同时存在该文件名的多个变体的文件

我想列出给定目录中存在的所有文件:

  • <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.areAR0505.tisAR0505.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.tisfoo.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/;
   }
'

相关内容