特定のディレクトリにあるすべてのファイルを一覧表示したいと思います。
<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を連結しますsed
。while 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.tis
etc。に拡張されます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.XXX
OPはこれについては明確ではないからです。
答え4
perl -le '
while ( <*LM.bmp> ) {
(my $f = $_) =~ s|LM\.bmp$||;
print $f if 3 == grep { -e $f . $_ } qw/.tis .are .wed/;
}
'