Как найти несколько файлов в системе Linux
В моей системе масса файлов, и каждому файлу соответствует одно имя файла. Например,
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 ответа
Быстрый скрипт, адаптируйся по своему усмотрению:
#!/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/
,