Как найти несколько файлов в системе Linux

В моей системе масса файлов, и каждому файлу соответствует одно имя файла. Например,

test.pdf имеет test-project.ziptest2.pdf имеет test2-project.zip

test.pdf а также test2.pdf исходные файлы и test-project.zip а также test2-project.zip генерируются моим сценарием.

Мне нужно выяснить, все ли мои оригинальные файлы имеют 'filename'-project.zip соответствует исходному файлу.

я могу использовать

find /project/ -name "*.pdf" | wc -l
find /project/ -name "*-project.zip" | wc -l

чтобы узнать, совпадают ли числа, но мне нужно знать, в каком файле нет соответствующего файла.

Может ли кто-нибудь помочь мне об этом? Большое спасибо!

2 ответа

Быстрый скрипт, адаптируйся по своему усмотрению:

#!/usr/bin/env bash

find /project/ -name '*.pdf' -print0 | while read -d $'\0' i; do
  if [ ! -e "${i/%.pdf/-project.zip}" ]; then
    echo "${i/%.pdf/-project.zip} doesn't exist!"
  fi
done

exit 0

-d $'\0' устанавливает разделитель для read ноль, пока -print0 эквивалент для find, так что это должно быть пуленепробиваемым от файлов с пробелами и символами новой строки в их именах (очевидно, не имеет значения в этом случае, но полезно знать в общем). ${i/%.pdf/-project.zip} заменяет .pdf в конце переменной $i с -project.zip, Кроме этого, это все стандартные сценарии оболочки.

Если вы хотите сократить его еще больше, вы также можете использовать

[ -e "${i/%.pdf/-project.zip}" ] || echo "${i/%.pdf/-project.zip} doesn't exist!"

... вместо if заявление. я думаю что if с ним легче работать, если вы используете более одной короткой строки (вы можете обойти это, используя функцию, но в этот момент вы не получаете никакой экономии psace по сравнению с использованием if).

Предполагая, что у вас есть bash 4+ (вы, вероятно, делаете; вы можете проверить с помощью bash --version), вы можете использовать опцию globstar вместо find:

#!/usr/bin/env bash

shopt -s globstar
for f in /project/**/*.pdf; do
  if [ ! -e "${f/%.pdf/-project.zip}" ]; then
    echo "${f/%.pdf/-project.zip} doesn't exist!"
  fi
done

exit 0

Это имеет преимущество, заключающееся в том, что это чистый bash, поэтому он должен быть быстрее (хотя это заметно только с сотнями файлов).

Вот два способа сделать это. Один из них - чертовски однострочный Bash, который порождает как минимум один, возможно, два процесса для каждого файла, которому он соответствует:

[me@box] $ for file in `find -name '*.pdf' -exec perl -le'$f=shift(); $f =~ s@\.pdf$@@; print $f' {} \;`; do (TESTFILE="$file-project.zip"; if [ ! -f $TESTFILE ]; then echo "missing $TESTFILE"; fi); done

Поскольку этого достаточно, чтобы у кого-то кровоточили глаза, вот скрипт Perl, который выполняет ту же работу, гораздо более разумно, чем любой скрипт Bash:

#!/usr/bin/env perl
use strict;

my $path = shift() || die "$0 requires a path argument\n";
my @files = `find "$path" -name '*.pdf'`;

foreach my $file (@files) {
  chomp $file;
  my $zip = $file;
  $zip =~ s@\.pdf$@-project.zip@;
  next if -f $zip;
  print "missing $zip\n";
};

Скопируйте это, например, в "find-missing.pl", а затем вызовите find-missing.pl /project/,

Другие вопросы по тегам