Wie kann ich alle Dateien in Unterverzeichnissen rekursiv in ein einzelnes Verzeichnis verschieben?

10

Ich versuche, alle Dateien im aktuellen Verzeichnis und alle Unterverzeichnisse in einem Verzeichnis zu sammeln. Ich versuche so etwas wie das Folgende

find -type f -exec mv {} collection/{} \; 

Der obige Befehl funktioniert nicht, da der zweite {}den vollständigen Pfad angibt. Wie kann ich alle Dateien sammeln?

Häschen
quelle

Antworten:

14

Wenn Sie das {}von entfernen mv, mvwird es als Zielverzeichnis verwendet, wobei alle übergeordneten Verzeichnisse ignoriert werden:

find -type f -exec mv {} collection/ \;
Lekensteyn
quelle
ohh das ist mir nicht eingefallen. danke :)
Bunny Rabbit
Wie ich in meiner Antwort auf die Frage sage, ist dies möglicherweise eine schlechte Idee. Vielleicht -maxdepth 1würde es helfen , das Argument zu verwenden.
Loevborg
Kommen Sie und denken Sie darüber nach, es scheint, als hätte ich Ihre Frage falsch gelesen :) Entschuldigung.
Loevborg
@loevborg: Ich habe dem Titel jetzt "rekursiv" hinzugefügt. Wenn es immer noch Verwirrung gibt, bearbeiten Sie es bitte und verbessern Sie es :)
Lekensteyn
1
Eine schnellere Variante dieser Antwort istfind -type f -print0|xargs -0r mv -it colection/
hildred
5

Anstatt zu verwenden find(was die Arbeit gut macht), können Sie auch die Shell zu diesem Zweck verwenden.

Angenommen, Sie möchten alle Dateien von $ PWD bis $ DEST. Der natürliche Versuch wäre:

mv $PWD/* $DEST

Wie funktioniert das? Der Ausdruck "$ PWD / *" wird auf die Namen aller Dateien in diesem Verzeichnis erweitert. Diese Shell-Funktion wird als "Globbing" bezeichnet. Das letzte Argument von mvist das Zielverzeichnis. Wenn Sie sehr viele Dateien haben, funktioniert dies nicht, da die Länge der Befehlszeile begrenzt ist.

Die Lösung hat jedoch das Problem, dass Punktdateien weggelassen werden - oder "versteckte" Dateien, Dateien und Verzeichnisse, deren Name mit einem "." Beginnt. Um dies zu lösen, müssen Sie Ihre Shell anweisen, beim Globbing Dotfiles einzuschließen. Verwenden Sie dazu

shopt -s dotglob

bei der Verwendung bash(und Sie verwenden wahrscheinlich, es bashsei denn, Sie haben die Standardeinstellung geändert). In dieser Shell funktioniert der obige Befehl auch für Punktedateien.

Im zshÜbrigen haben Sie die Möglichkeit, dies von Fall zu Fall zu wählen. Um dies zu tun, setzen Sie

setopt extendedglob

in deinem .zshrc. Dann können Sie verwenden

mv $PWD/*(D) $DEST

um alle Dateien einschließlich der Punktedateien zu verschieben. (Das "D" bewirkt, dass die Option "GLOB_DOTS" vorübergehend aktiviert wird.)

Die ursprüngliche Frage war nun, alle regulären Dateien (nicht Verzeichnisse) aus allen Unterverzeichnissen und ihren Unterverzeichnissen in ein einziges Verzeichnis zu verschieben. Dies kann erreicht werden mit zsh:

mv $PWD/**/*(D.)

Hier lässt der Ausdruck **/*den Globber rekursiv in Unterverzeichnisse absteigen. Das Dbedeutet "auch Punktdateien auswählen"; das .Mittel "nur reguläre Dateien auswählen, keine Verzeichnisse".

loevborg
quelle
Nun, ich wollte auch in alle Unterverzeichnisse zurückkehren, aber dank der Informationen, die nützlich sind, stoße ich auch oft auf diese Situation :)
Bunny Rabbit
Tatsächlich ist find kein Overkill dafür. Globbing wählt alle Übereinstimmungen aus, nicht nur Dateien, sondern auch Verzeichnisse. Wenn Sie sich Sorgen um die Leistung machen, können Sie auch Folgendes verwenden : find -type f -exec mv -t collection/ {} +. Informationen zur Funktionsweise finden Sie auf der Handbuchseite.
Lekensteyn
Lekensteyn, du hast recht. Ich habe die Antwort jetzt aktualisiert, da ich die Frage verstanden habe.
Loevborg
2
Wunderbare Antwort, schade, dass es für die Frage nicht besonders relevant ist :).
crazy2be