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

3780
FlyingCat

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

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 

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

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

3
Это одна папка `/ project /`, или в ней есть подкаталоги? Daniel Beck 10 лет назад 0
подкаталоги включены .. FlyingCat 10 лет назад 0
`test.pdf` и` test-project.zip` (и т. д.) всегда находятся в одном каталоге? evilsoup 10 лет назад 0
да они все в одном режиссере FlyingCat 10 лет назад 0

2 ответа на вопрос

5
evilsoup

Quicky script, adapt as you see fit:

#!/usr/bin/env bash find /project/ -name '*.pdf' -print0 | while read -d $'\0' i; do if [ ! -e "$" ]; then echo "$ doesn't exist!" fi done exit 0 

-d $'\0' sets the delimiter for read to nullbyte, while -print0 is the equivalent for find, so this should be bulletproof against files with spaces and newlines in their names (obviously irrelevant in this case, but useful to know in general). $ replaces the .pdf at the end of the variable $i with -project.zip. Other than that, this is all standard shell scripting stuff.

If you wanted to shorten it even more, you could also use

[ -e "$" ] || echo "$ doesn't exist!" 

...instead of the if statement. I think that if is easier to work with if you're using more than a single, short line (you can get around this by using a function, but at that point you aren't getting any psace saving vs. using the if).

Assuming you have bash 4+ (you probably do; you can check with bash --version), you can use the globstar option instead of find:

#!/usr/bin/env bash shopt -s globstar for f in /project/**/*.pdf; do if [ ! -e "$" ]; then echo "$ doesn't exist!" fi done exit 0 

This has the advantage of being pure bash, so it should be faster (only noticeably so with at least hundreds of files, though).

Вы защищаетесь от перевода строки, но тест `[...]` все равно сломался бы, если бы у $ i были пробелы. grawity 10 лет назад 0
@ Grawity - я не могу поверить, что я забыл процитировать переменную, исправлено. evilsoup 10 лет назад 0
+1 для '-d' \ 0 '... но вам нужен / bin / env bash? / bin / bash является необходимостью POSIX. Вы действительно беспокоитесь о том, какой удар вы попали? Rich Homolka 10 лет назад 0
@RichHomolka AFAIK В действительности нет никаких недостатков в использовании `/ usr / bin / env`, и, хотя в этом случае это может и не понадобиться, я считаю, что это хорошая привычка для работы с другими языками. evilsoup 10 лет назад 0
@RichHomolka: ** `/ bin / sh` ** - необходимость POSIX. `bash`, с другой стороны, является сторонней программой, и она часто находится в` / usr / bin`, `/ usr / local / bin` или даже` / usr / pkg / bin`. grawity 10 лет назад 3
@ Grawity Может быть, я просто думаю SVR4, который требовал этого. Спасибо Rich Homolka 10 лет назад 0
@RichHomolka: bash не существовало, когда SVR4 был выпущен, afaik grawity 10 лет назад 0
0
Aaron Miller

Here are two ways you could do it. One is a godawful Bash one-liner which spawns at least one, possibly two, processes for each file it matches:

[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 

Since that's enough to make anyone's eyes bleed, here's a Perl script which does the same job, much more sanely than any Bash script ever could:

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

Copy that into, e.g., 'find-missing.pl', then invoke find-missing.pl /project/.

`for file in \` find… `является распространенным антишаблоном, и его следует избегать. Смотрите: http://mywiki.wooledge.org/ParsingLs slhck 10 лет назад 1

Похожие вопросы