Angenommen, ich möchte den Inhalt eines Verzeichnisses mit Ausnahme von Dateien und Ordnern kopieren, deren Namen das Wort "Musik" enthalten.
cp [exclude-matches] *Music* /target_directory
Was sollte anstelle von [Ausschluss-Übereinstimmungen] geschehen, um dies zu erreichen?
bash
shell
pattern-matching
glob
Benutzer4812
quelle
quelle
ls /dir/*/!(base*)
f
, außerfoo
?Mit der
extglob
Shell-Option erhalten Sie einen leistungsstärkeren Mustervergleich in der Befehlszeile.Sie schalten es mit ein
shopt -s extglob
und ausshopt -u extglob
.In Ihrem Beispiel würden Sie zunächst Folgendes tun:
Die gesamte verfügbare ext beendet glob bing Operatoren sind (Auszug aus
man bash
):So zum Beispiel, wenn Sie alle Dateien im aktuellen Verzeichnis aufzulisten wollen , die nicht
.c
oder.h
Dateien, würden Sie tun:Natürlich funktioniert normales Shell-Globing, daher könnte das letzte Beispiel auch wie folgt geschrieben werden:
quelle
.c
oder.h
Dateien ein Verzeichnis ist.D
, jedoch nicht der Inhalt von Unterverzeichnissen, die möglicherweise im Verzeichnis enthalten sindD
.Nicht in Bash (von dem ich weiß), aber:
Ich weiß, dass dies nicht genau das ist, wonach Sie gesucht haben, aber es wird Ihr Beispiel lösen.
quelle
Wenn Sie die Mem-Kosten für die Verwendung des Befehls exec vermeiden möchten, können Sie mit xargs meiner Meinung nach besser abschneiden. Ich denke, das Folgende ist eine effizientere Alternative zu
quelle
In Bash
shopt -s extglob
ist dieGLOBIGNORE
Variable eine Alternative zu . Es ist nicht wirklich besser, aber ich finde es einfacher, mich zu erinnern.Ein Beispiel, das das Originalplakat wollte:
Wenn Sie fertig sind
unset GLOBIGNORE
, können Sierm *techno*
im Quellverzeichnis.quelle
Sie können auch eine ziemlich einfache
for
Schleife verwenden:quelle
-maxdepth 1
für nicht rekursive?find
in Backticks wird auf unangenehme Weise unterbrochen, wenn nicht triviale Dateinamen gefunden werden.Meine persönliche Präferenz ist die Verwendung von grep und dem while-Befehl. Auf diese Weise können Sie leistungsstarke und dennoch lesbare Skripte schreiben, die sicherstellen, dass Sie genau das tun, was Sie möchten. Außerdem können Sie mit einem Echo-Befehl einen Probelauf durchführen, bevor Sie den eigentlichen Vorgang ausführen. Zum Beispiel:
druckt die Dateien aus, die Sie am Ende kopieren werden. Wenn die Liste korrekt ist, besteht der nächste Schritt darin, den Echo-Befehl wie folgt durch den Kopierbefehl zu ersetzen:
quelle
bash
Sie verwendenwhile IFS='' read -r filename
, aber dann sind Zeilenumbrüche immer noch ein Problem. Im Allgemeinen ist es am besten, keinels
Dateien aufzulisten. Werkzeuge wiefind
sind viel besser geeignet.for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
Ein Trick, den ich hier noch nicht gesehen habe und der nicht verwendet
extglob
wirdfind
oder der daringrep
besteht, zwei Dateilisten als Mengen zu behandeln und sie mit folgenden Elementen zu "diff".comm
comm
ist vorzuziehen,diff
weil es keine zusätzliche Kruft hat.Dies gibt alle Elemente von Satz 1 zurück,
ls
die nicht auch in Satz 2 enthalten sindls *Music*
. Dies erfordert, dass beide Sätze sortiert sind, damit sie ordnungsgemäß funktionieren. Kein Problem fürls
und Glob-Erweiterung, aber wenn Sie so etwas verwendenfind
, rufen Sie unbedingt aufsort
.Potenziell nützlich.
quelle
comm -23 <(ls) exclude_these.list
Eine Lösung hierfür finden Sie mit find.
Find hat eine ganze Reihe von Optionen. Sie können ziemlich genau festlegen, was Sie ein- und ausschließen.
Bearbeiten: Adam in den Kommentaren festgestellt, dass dies rekursiv ist. Suchoptionen mindepth und maxdepth können hilfreich sein, um dies zu steuern.
quelle
find -maxdepth 1 -not -name '*Music*'
/ target_directoryDie folgenden Arbeiten listen alle auf
*.txt
Dateien im aktuellen , mit Ausnahme derjenigen, die mit einer Zahl beginnen.Dies funktioniert in
bash
,dash
,zsh
und alle anderen POSIX - kompatibelen Muscheln.In Zeile 1
/some/dir/*.txt
bewirkt das Muster , dass diefor
Schleife alle Dateien durchläuft,/some/dir
deren Name mit endet.txt
.In Zeile zwei wird eine case-Anweisung verwendet, um unerwünschte Dateien auszusortieren. - Der
${FILE##*/}
Ausdruck entfernt alle führenden Verzeichnisnamenkomponenten vom Dateinamen (hier/some/dir/
), sodass Muster nur mit dem Basisnamen der Datei übereinstimmen können. (Wenn Sie nur Dateinamen basierend auf Suffixen aussortieren, können Sie diese$FILE
stattdessen auf kürzen .)In Zeile drei werden alle Dateien, die dem
case
Muster[0-9]*
entsprechen, übersprungen (diecontinue
Anweisung springt zur nächsten Iteration derfor
Schleife). - Wenn Sie möchten, können Sie hier etwas Interessanteres tun, z. B. alle Dateien überspringen, die nicht mit einem Buchstaben (a - z) beginnen[!a-z]*
, oder Sie können mehrere Muster verwenden, um verschiedene Arten von Dateinamen[0-9]*|*.bak
zu überspringen, z. B. um Dateien in beiden.bak
Dateien zu überspringen und Dateien, die nicht mit einer Nummer beginnen.quelle
*.txt
statt nur abgestimmt*
). Jetzt behoben.Dies würde es tun, ohne genau 'Musik' auszuschließen.
dies und das, um Dinge wie Musik auszuschließen? * oder *? Musik
quelle
cp
Handbuchseite unter MacOS hat eine-a
Option, macht aber etwas ganz anderes. Welche Plattform unterstützt dies?