So finden Sie mehrere Dateien im Linux-System

3928
FlyingCat

Ich habe riesige Dateien in meinem System und jede Datei hat einen entsprechenden Dateinamen. Zum Beispiel,

test.pdfhat eine test-project.zip test2.pdfhat einetest2-project.zip

test.pdfund test2.pdfsind die Originaldateien und test-project.zipund test2-project.zipwerden von meinem Skript generiert.

Ich muss herausfinden, ob alle meine Originaldateien 'filename'-project.zipder Originaldatei entsprechen.

ich kann nutzen

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

Um herauszufinden, ob die Zahlen übereinstimmen, muss ich jedoch wissen, welche Datei keine entsprechende Datei hat.

Kann mir jemand weiterhelfen? Danke vielmals!

3
Ist es ein einzelner Ordner `/ project /` oder sind Unterverzeichnisse beteiligt? Daniel Beck vor 11 Jahren 0
Unterverzeichnisse enthalten .. FlyingCat vor 11 Jahren 0
Befinden sich `test.pdf` und` test-project.zip` (und so weiter) immer im selben Verzeichnis? evilsoup vor 11 Jahren 0
Ja, sie sind alle im selben Verzeichnis FlyingCat vor 11 Jahren 0

2 Antworten auf die Frage

5
evilsoup

Quicky-Skript, passen Sie es an:

#!/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'setzt das Trennzeichen für readnullbyte, während dies -print0das Äquivalent für ist find, also sollte dies kugelsicher gegen Dateien sein, deren Namen Leerzeichen und Zeilenumbrüche enthalten (in diesem Fall offensichtlich irrelevant, aber im Allgemeinen nützlich). $ersetzt das .pdfam Ende der Variablen $idurch -project.zip. Abgesehen davon ist dies alles Standard-Shell-Scripting-Zeug.

Wenn Sie es noch weiter verkürzen wollten, können Sie es auch verwenden

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

... statt der ifAussage. Ich denke, das ifist einfacher zu handhaben, wenn Sie mehr als eine einzelne, kurze Leitung verwenden (Sie können dies umgehen, indem Sie eine Funktion verwenden, aber an diesem Punkt erhalten Sie keine Platzersparnis gegenüber der Verwendung der if).

Vorausgesetzt, Sie haben bash 4+ (was Sie wahrscheinlich tun; Sie können dies überprüfen bash --version), können Sie die globstar-Option anstelle von 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 

Dies hat den Vorteil, dass es ein reiner Bash ist, also sollte es schneller sein (allerdings nur bei mindestens Hunderten von Dateien).

Sie schützen vor Zeilenumbrüchen, aber der Test "[...]" bricht immer noch, wenn $ i Leerzeichen enthält. grawity vor 11 Jahren 0
@grawity - Ich kann nicht glauben, dass ich vergessen habe, die Variable zu zitieren, behoben. evilsoup vor 11 Jahren 0
+1 für '-d' \ 0 '... aber benötigen Sie / bin / env bash? / bin / bash ist eine POSIX-Notwendigkeit. Machst du dir wirklich Sorgen, welche Schläge du getroffen hast? Rich Homolka vor 11 Jahren 0
@RichHomolka AFAIK Es gibt keinen Nachteil bei der Verwendung von `/ usr / bin / env`, und obwohl dies in diesem Fall nicht unbedingt erforderlich ist, betrachte ich es als eine gute Angewohnheit, mich für die Arbeit mit anderen Sprachen zu bilden. evilsoup vor 11 Jahren 0
@RichHomolka: ** `/ bin / sh` ** ist eine Notwendigkeit für POSIX. "bash" hingegen ist ein Programm eines Drittanbieters und häufig in "/ usr / bin", "/ usr / local / bin" oder sogar "/ usr / pkg / bin". grawity vor 11 Jahren 3
@grawity vielleicht denke ich nur an SVR4, was es erfordert hat. Vielen Dank Rich Homolka vor 11 Jahren 0
@RichHomolka: Bash gab es nicht, als SVR4 veröffentlicht wurde, afaik grawity vor 11 Jahren 0
0
Aaron Miller

Hier sind zwei Möglichkeiten, wie Sie es tun können. Einer ist ein gottesfürchtiger Bash-Einzeiler, der mindestens einen, möglicherweise zwei Prozesse für jede Datei erzeugt, auf die er zutrifft:

[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 

Da dies genug ist, um jedermanns Augen zum Bluten zu bringen, gibt es hier ein Perl-Skript, das die gleiche Arbeit leistet, und zwar viel sinnvoller als jedes Bash-Skript je:

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

Kopieren Sie das in beispielsweise "find-missing.pl" und rufen Sie es dann auf find-missing.pl /project/.

`for file in \` find… `ist ein verbreitetes Anti-Pattern und sollte vermieden werden. Siehe: http://mywiki.wooledge.org/ParsingLs slhck vor 11 Jahren 1