Intereting Posts
Начальные вопросы относительно «<», «<<» и чтения файлов Как проверить поврежденные и дублированные шрифты на Linux? Создание нескольких временных псевдонимов Как установить последовательный порт в режим RS-485? Как заставить ksh действовать так, как если бы он был вызван в качестве оболочки входа (AIX)? многие неудачные попытки входа в систему, хотя вход в root отключен скрипт iptables для блокировки всего интернет-доступа, за исключением желаемых приложений почему выполнение оболочки в задании cron занимает больше времени, чем обычно? Снижение с 14.04LTS до 12.04LTS Как запустить вентилятор вручную в Linux? Предварительная загрузка Killer OOM Solaris 11: Как использовать ILB для создания HA loadbalancer на двух серверных серверах? Как я могу узнать, что делает мой SLAB Unreclaimable Memory Grow без границ Как добавить горизонтальное разделение на окно tmux, которое охватывает всю ширину родительского окна? Процесс nohup не работает в ssh

Найти файлы, для которых несколько вариантов этого имени файла существуют вместе в одном каталоге

Я хочу, чтобы список файлов, для которых существует, в данном каталоге, ВСЕ эти файлы:

  • <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 

В основном я цепляю find , два sed и некоторое while read для каждого расширения, на которое я хочу фильтровать.

Требуется> 35 секунд для файлов размером не менее 30 Кбайт! Как я могу улучшить его?

пример

Если в каталоге есть файлы с именем AR0505.are , AR0505.tis , AR0505.wed и AR0505LM.bmp , тогда сценарий будет печатать «AR0505».

Если один или несколько из этих файлов отсутствуют, сценарий не будет печатать.

Я думаю, что основным узким местом является количество процессов, которые вы создаете. Вот простой скрипт, который перечисляет и фильтрует ваш каталог за один проход:

 #!/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"; } } 

Если я правильно вас понимаю, вы ищете все имена файлов, которые существуют с каждым из целевых расширений. Если это так, вы можете сделать:

 ( 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, который заставляет globs расширяться до нулевой строки, а не самостоятельно, если совпадающие файлы не найдены. Функция ( ) предназначена только для того, чтобы параметр был установлен только для этой команды и не повлияет на родительскую оболочку.
  • for i in *.wed; do ...; done 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 файла, поэтому 3 в дополнение к оригиналу .wed , print имя файла без расширения.

Если вы хотите напечатать все 4 имени файла, включая расширение, просто измените printf '%s\n' "${i//.wed}" на printf '%s\n' "$i" .

 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 ' {} {} \; 

NB: Здесь мы не смотрим ни на что другое, кроме этих 4-х файлов и в конкретном случае, и только когда ALL 4 найдены, то он отображает их, даже если другие файлы foobar.XXX существуют в одном каталоге. Coz OP не был очень ясен об этом.

удар

Мы создали цикл for с выражением glob *LM.bm[p] , так что мы можем устранить неоднозначность сценария файла с именем, заканчивающимся на p фактически существующим или нет. Это разновидность shopt nullglob . Если мы увидим конец имени в p =>, оболочке удалось расширить этот glob, то есть такой файл существовал. OTOH, если мы увидим конец имени в [p] => оболочке NOT удалось расширить glob *LM.bm[p] значит, не было файла с этим именем.

Следующий шаг: мы скопируем конечные 6 символов (LM. Bmp) из имени файла, которое мы теперь знаем. Используя оставшуюся часть имени файла, мы установили 3 позиционных параметра, соответствующих 3 расширениям .wed .are .tis .

Ключ состоит в том, что даже если одно из расширений остается нерасширенным, тогда его имя будет отображаться с последним символом, включенным в [ ] . => Все 3 файла не все присутствуют. => пропустите это. И else else => все 3 файла присутствуют + 1 (* LM.bmp) уже присутствует из-за нашей предварительной проверки. Следовательно, мы видим все 4 файла и => подходит для печати.

 for i in *LM.bm[p]; do case $i in *[p] ) f=${i%??????} set -- "$f".we[d] "$f".ar[e] "$f".ti[s] savIFS=$IFS IFS=/ case "$*/" in *"]/"* ) : ;; * ) printf '%s\n' "$f" ;; esac IFS=$savIFS esac done 
 perl -le ' while ( <*LM.bmp> ) { (my $f = $_) =~ s|LM\.bmp$||; print $f if 3 == grep { -e $f . $_ } qw/.tis .are .wed/; } '