3

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

test.pdf имеет test-project.zip test2.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 ответа2

5

Быстрый скрипт, адаптируйся как хочешь:

#!/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 на nullbyte, в то время как -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, поэтому он должен быть быстрее (хотя это заметно только с сотнями файлов).

0

Вот два способа сделать это. Один из них - чертовски однострочный 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/ .

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .