Ich habe einen Ordner mit vielen Dateien. Ich möchte alle Dateien kopieren, die mit einem dieser Namen beginnen (durch Leerzeichen getrennt):
abc abd aer ab-x ate
in einen anderen Ordner. Wie kann ich das machen?
Antwort1
Mit csh
, tcsh
, ksh93
, bash
, fish
oder zsh -o cshnullglob
können SieKlammererweiterungUndGlotzenum das zu tun ( --
ist für diese Dateinamen nicht nötig, aber ich nehme an, dass es sich nur um Beispiele handelt):
cp -- {abc,abd,aer,ab-x,ate}* dest/
Wenn Sie die Klammererweiterung lieber nicht verwenden möchten, können Sie eine For-Schleife verwenden (hier Syntax im POSIX/Bourne-Stil):
for include in abc abd aer ab-x ate; do
cp -- "$include"* dest/
done
Wenn Sie eine sehr große Anzahl von Dateien haben, kann dies aufgrund des cp
einmaligen Aufrufs pro Include langsam sein. Eine andere Möglichkeit wäre, ein Array zu füllen und von dort aus weiterzumachen (hier ksh93
oder zsh
aktuelle bash
Syntax):
files=()
includes=(abc abd aer ab-x ate)
for include in "${includes[@]}"; do
files+=( "$include"* )
done
cp -- "${files[@]}" dest/
Antwort2
Ein Hinweis zur Klammererweiterung im Vergleich zum Globbing.
Die Klammererweiterung ist kein Globbing (obwohl der Unterschied in csh/tcsh, wo sie ihren Ursprung hat, nicht so klar ist wie in anderen Shells). Sie wird durchgeführtVorGlobben.
Wenn Sie das also tun:
cp {a,b}* /dest
Es wird zunächst erweitert zu:
cp a* b* /dest
Das bedeutet, dass die Shell zwei Globs erweitern muss, also die vollständige Dateiliste zweimal abrufen und zweimal prüfen muss, welche dem Muster entsprechen.
Mit zsh
bedeutet dies auch, dass der gesamte Befehl abgebrochen wird, wenn einer der Globs mit keiner Datei übereinstimmt (Sie können dies umgehen, indem Sie die cshnullglob
Option aktivieren, sich wie in csh zu verhalten).
Das bedeutet auch, dass Sie, wenn Sie
cp {a,ab}* /dest
cp
kopiert die ab*
Dateien zweimal.
Das ist etwas anderes als:
cp @(a|b)* /dest
von ksh
oder bash -O extglob
oder zsh -o kshglob
, oder
cp (a|b)* /dest
von zsh
. Dort ist es nureinsglob, daher ist es effizienter und Dateien werden nur einmal eingefügt.
Mit zsh
, wenn Sie die Liste der Präfixe in einem Array haben:
prefixes=(abc abd aer ab-x ate)
cp -- (${(j:|:)~prefixes})* /dest
(oben werden die Präfixe als Globs behandelt.) Das heißt, die Elemente des Arrays werden mit verknüpft |
und das Ergebnis wird als Glob ( ~
) betrachtet.
Wenn die Liste groß ist, kann es sein, dass die Ausführung cp
mit einem„Argumentliste zu lang“Fehler. In diesem Fall können Sie zsh
die integrierte Version verwenden, indem Sie das Modul ( ) cp
laden .zsh/files
zmodload zsh/files
Antwort3
Beispielsweise habe ich diese Dateien im aktuellen Verzeichnis:
1-s2.0-S0038092X0000058X-main.pdf ANNDHW.pdf HPcalculation2 1-s2.0-S0306261999000422-main.pdf ANNlee.pdf HPcalculation3 ANNCanada.pdf HPcalculation HPcalculation4
Ich möchte alle Dateien beginnend mit HP in den Ordner verschieben:
./NewFolder/
Ich kann:
cp ./HP* ./NewFolder/
./HP*
teilt Linux mit, dass ich an allen Dateien interessiert bin, die mit HP beginnen. Umgekehrt gilt, wenn ich alle Dateien verschieben möchte, die mit enden.pdf
. Ich kann*
vor das setzen.pdf
:cp ./*.pdf ./NewFolder/
Antwort4
Einfach können Sie tun
cp abc* abd* aer* ab-x* ate* DestinationPath
Eine Lösung für Ihr erweitertes Problem kann sein
- setze alle Dateinamen in eine Liste zB list0.txt
Alles kopieren mit
cp `cat list0.txt` DestinationPath # Benötigt keine Leerzeichen in den Dateinamen
oder besser,
während lesen -r Datei; mache cp "$file" dest/ ; fertig < list0.txt
Anmerkungen:
- "$file", weil Sie so Namen mit Leerzeichen darin behandeln können als
One Package.deb
-r
es schützt Sie vor Escape-Sequenzen.-r Backslash fungiert nicht als Escape-Zeichen. Der Backslash wird als Teil der Zeile betrachtet. Insbesondere darf ein Backslash-Newline-Paar nicht als Zeilenfortsetzung verwendet werden.