Ich möchte die PDF-Dateien finden, deren Name (ohne die Erweiterung) größer als drei ist.
$ find ~ -iregex ".{3,}/.pdf"
gibt nichts zurück, aber
$ find ~ -iregex ".+/.pdf"
funktioniert.
Wie kann ich die {3,}
Variante aktivieren ?
Ich möchte die PDF-Dateien finden, deren Name (ohne die Erweiterung) größer als drei ist.
$ find ~ -iregex ".{3,}/.pdf"
gibt nichts zurück, aber
$ find ~ -iregex ".+/.pdf"
funktioniert.
Wie kann ich die {3,}
Variante aktivieren ?
Antworten:
Angenommen, Sie verwenden GNU find
(was Sie wahrscheinlich sind, da -iregex
es sich um eine GNU-Erweiterung für POSIX handeltfind
) -regex
und -iregex
standardmäßig reguläre Emacs-Ausdrücke, die nicht erkannt werden {3,}
. Mit der -regextype
Option müssen Sie einen anderen Typ regulärer Ausdrücke angeben . Darüber hinaus müssen Sie Ihren regulären Ausdruck an die Tatsache anpassen, dass der Ausdruck mit dem vollständigen Pfad übereinstimmt:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'
Sie sollten auch dem entkommen, .
damit es mit "." Übereinstimmt. eher als irgendein Charakter:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'
Der reguläre Ausdruck kann vereinfacht werden, da wir uns nur um drei Nicht-"/" -Zeichen kümmern:
find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'
Der Vollständigkeit halber würden Sie mit FreeBSD oder NetBSD find
(eine andere Implementierung, die unterstützt -iregex
, aber nicht Ihre, da .+
sie dort nicht funktionieren -E
würde) schreiben:
find ~ -iregex '.*[^/]\{3\}\.pdf'
oder:
find -E ~ -iregex '.*[^/]{3}\.pdf'
Ohne -E
ist das ein grundlegender regulärer Ausdruck (wie in grep
) und mit einem -E
erweiterten regulären Ausdruck (wie in grep -E
).
Mit Ast-Open find
:
find ~ -iregex '.*[^/]{3}\.pdf'
(Das sind erweiterte reguläre Ausdrücke aus der Box).
Hier ist es mit Standard-Platzhaltern einfacher:
find ~ -name '*???.[pP][dD][fF]'
Oder mit einigen find
Implementierungen (diejenigen, die -regex
auch unterstützen -iname
):
find ~ -iname '*???.pdf'
Wenn Sie eine beliebige Anzahl von Zeichen anstelle von 3
verwenden möchten, ziehen Sie es möglicherweise vor, auf die -iregex
verfügbaren zurückzugreifen (siehe Antwort von @Stephen Kitt ), oder Sie könnten Folgendes verwenden zsh
oder ksh93
globs:
zsh
::
set -o extendedglob # best in ~/.zshrc
printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
(die (D)
versteckten Dateien und Dateien in versteckten Verzeichnissen wie mit zu berücksichtigen find
)
(#cx,y)
ist das zsh
Platzhalteräquivalent von regulärem Ausdruck{x,y}
(#i)
für Groß- und Kleinschreibung nicht berücksichtigen?
Standard-Platzhalter für ein einzelnes Zeichen (wie regulärer Ausdruck .
)**/
: jede Ebene von Unterverzeichnissen (einschließlich 0)ksh93
::
FIGNORE='@(.|..)' # to consider hidden files
set -o globstar
printf '%s\n' **/{3,}(?).~(i:pdf)
@(x|y)
: erweiterter ksh-Platzhalteroperator ähnlich wie regulärer Ausdruck (x|y)
.FIGNORE
: Spezielle Variable, die steuert, welche Dateien von Globs ignoriert werden. Wenn diese Option aktiviert ist, werden versteckte Dateien normalerweise nicht ignoriert. Wir möchten jedoch die Einträge .
und, ..
sofern vorhanden , ignorieren .{x,y}(z)
ist ksh93
das Äquivalent von regulärem Ausdruck z{x,y}
.~(i:...)
: Groß- und Kleinschreibung wird nicht berücksichtigt.Globs haben hier einige zusätzliche Vorteile find
: Sie erhalten eine sortierte Liste (Sie können diese Sortierung zsh
mit dem oN
Glob-Qualifikationsmerkmal deaktivieren oder andere Sortierkriterien verwenden) und funktionieren auch, wenn Dateinamen eine Folge von Bytes enthalten, die keine gültigen Zeichen bilden (z In einem Gebietsschema, das den UTF-8-Zeichensatz verwendet, würde der find
Ansatz beispielsweise a nicht melden $'St\xE9phane Chazelas - CV.pdf
, \xE9
da kein Zeichen nicht mit regulärem Ausdruck .
oder Platzhalter ?
oder *
mit GNU übereinstimmt find
.
shopt -s dotglob globstar; printf '%s\n' ~/**/*???.[pP][dD][fF]
Sie tun es nicht, wenn Sie nicht fragen. Sicher, ich bin pedantisch, aber Sie haben nicht nach Dateien.pdf
gefragt, deren Namen enthalten sind . Nur weil eine Datei die Zeichen .pdf
im Dateinamen enthält, wird sie nicht zu einer PDF-Datei .
Lassen Sie uns diesbezüglich ganz pedantisch vorgehen: Wenn die letzten vier Zeichen des Dateinamens lauten .pdf
, enthält der Name immer mehr als drei Zeichen .
Wenn Sie dies also falsch machen , könnten Sie sagen:
$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf
Sehen Sie den zweiten? Es ist eigentlich eine ausführbare Datei. (Ich weiß, ich habe den Namen geändert.) Und ich vermisse auch ein PDF, von dem ich schwören könnte, dass es sich im Dokumentenverzeichnis befindet ...
$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf
Wenn -iname
wir also eine verwenden, können wir diese finden, aber diese Nicht-PDF-Datei wird immer noch angezeigt.
Was wir in diesem Fall wirklich tun möchten, ist die magische Nummer der Datei mit dem file
Befehl zu untersuchen. Eine Option gibt den MIME-Typ aus , der einfacher zu analysieren ist. Die find
Abfrage wird dann einfach -name "???*"
.
$ find . -type f -name "???*" -print0|xargs -0 file --mime
./.bash_history: text/plain; charset=us-ascii
./.bash_logout: text/plain; charset=us-ascii
./.bashrc: text/plain; charset=us-ascii
./.profile: text/plain; charset=us-ascii
./Documents/McLaren 720s Coupe:Order Summary.pdf: application/pdf; charset=binary
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF: application/pdf; charset=binary
./Documents/Setup_MagicISO.exe.pdf: application/x-dosexec; charset=binary
./Downloads/Setup_MagicISO.exe: application/x-dosexec; charset=binary
./Downloads/WindowsUpdate.diagcab: application/vnd.ms-cab-compressed; charset=binary
Verwenden wir das Doppelpunkttrennzeichen, suchen nach dem MIME-Typ application/pdf
, setzen diesen Teil auf Null und drucken das Ergebnis. Beachten Sie, dass eine meiner Dateien einen Doppelpunkt im Namen hat. also kann ich nicht einfach awk fragen ($2==":"){print $1}
.
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
Beenden Nun lassen sie durch Einfädeln PDF Dateien mit dem Namen enthalten a
und abc
:
$ mkdir Documents/other
$ cp -a Documents/McLaren\ 720s\ Coupe\:Order\ Summary.pdf Documents/other/a
$ cp -a Documents/Pioneer\ Premier\ DEH-P490IB\ CD\ Install\ Manual.PDF Documents/other/abc
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
./Documents/other/abc
Das ist alles. Ich weiß, dass ich mich wahrscheinlich dafür begeistern werde, schrecklich pedantisch zu sein, aber bei meiner Arbeit mit Tausenden von zu jagenden NFS-Bänden und allen Arten von Dateien mit schlechtem Namen wünschte ich mir, mehr Menschen wären pedantisch.
Bearbeitet, um hinzuzufügen: In der realen Welt möchte ich möglicherweise updatedb
einen durchsuchbaren Dateiindex erstellen, locate
anstatt find
diesen Index zu lesen und parallel
anstatt ihn xargs
zu fädeln. Das liegt jedoch etwas außerhalb des Rahmens dieser Frage. Das habe ich auch mit ernstem Gesicht geschrieben. Warum kümmert es mich so sehr? Ich suche möglicherweise nach Film- und Audiodateien. oder bestimmte Arten von Fotografien; oder binäre ausführbare Dateien in einem Projektdatenverzeichnis.
.pdf
, wird Ihre Pedanterie sehr geschätzt. Aber es ist eine relativ ungewöhnliche Situation (trotz Ihres Jobs) und wir haben keinen Grund zu der Annahme, dass der Fragesteller sich tatsächlich damit befassen muss. Ich denke also, dass der Punkt, den Sie machen, zwar gültig, aber irgendwie ablenkend ist - und ich denke, die kraftvolle Art, wie Sie es formuliert haben, drückt die Antwort in den Bereich von "(wahrscheinlich) nicht nützlich". (Nur meine Meinung natürlich.)