同じディレクトリ内の複数のファイル名を持つ変形ファイルを見つける

同じディレクトリ内の複数のファイル名を持つ変形ファイルを見つける

特定のディレクトリにあるすべてのファイルを一覧表示したいと思います。

  • <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、two、およびaを連結しますsedwhile read

30Kファイルは35秒以上かかります!どのように改善できますか?

はい

AR0505.areディレクトリに、AR0505.tisおよび名前AR0505.wedのファイルがある場合、AR0505LM.bmpスクリプトは「AR0505」を印刷します。

これらのファイルの1つ以上が欠落している場合、スクリプトはそのファイルを印刷しません。

答え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:一致するファイルが存在しない場合、globがそれ自体ではなく空の文字列に拡張されるようにするbash固有のオプション。( )オプションがそのコマンドに対してのみ設定され、親シェルに影響を与えないようにするためにのみ存在します。
  • for i in *.wed; do ...; done:名前が現在のディレクトリで終わるすべてのファイルまたはディレクトリを繰り返し、.wed各ファイルまたはディレクトリを$i
  • "${i//.wed}":拡張子のないファイル名.wed
  • set -- "${i//.wed}"{.tis,.are,LM.bmp}*:中括弧はfoo.tisetc。に拡張されますfoo.are。これは*bashがそれをワイルドカードに一致させるトリックです。つまり、実際のファイル名が存在する場合にのみ機能します。
  • [[ $# -eq 3 ]] && printf '%s\n' "${i//.wed}":に正確に3つのファイルがある場合ソースファイルに加えて3つのファイルがある$@場合は、拡張子なしでファイル名を出力します。.wed

printf '%s\n' "${i//.wed}"4つのファイル名(拡張子を含む)をすべて印刷するには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.XXXOPはこれについては明確ではないからです。

答え4

perl -le '
   while ( <*LM.bmp> ) {
      (my $f = $_) =~ s|LM\.bmp$||;
      print $f if 3 == grep { -e $f . $_ } qw/.tis .are .wed/;
   }
'

関連情報