Wie verschieben Sie alle Dateien (einschließlich versteckter) von einem Verzeichnis in ein anderes?

133

Wie verschiebe ich alle Dateien in einem Verzeichnis (einschließlich der ausgeblendeten) in ein anderes Verzeichnis?

Wenn ich zum Beispiel einen Ordner "Foo" mit den Dateien ".hidden" und "notHidden" habe, wie verschiebe ich beide Dateien in ein Verzeichnis mit dem Namen "Bar"? Das Folgende funktioniert nicht, da die ".hidden" -Datei in "Foo" bleibt.

mv Foo/* Bar/

Versuch es selber.

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
Cory Klein
quelle
Bah, ich wusste, dass ich die Antworten hätte aktualisieren müssen, bevor ich meine eintippte. Sehr hilfreicher Link.
Steven D
Leider ist diese Frage hier gelandet, weil ich auf SO gesagt habe, dass sie hier oder SU verschoben werden soll, also ist sie natürlich hierher gezogen, als es bereits ein Duplikat von SU gab :)
Michael Mrozek
Persönlich denke ich, dass * nix spezifische Fragen und Antworten zu SU off-topic sein sollten. Nach den aktuellen Regeln kommt es häufig zu Kollisionen zwischen den beiden Inhalten - wie diese Frage.
Cory Klein

Antworten:

152

Zsh

mv Foo/*(DN) Bar/

oder

setopt -s glob_dots
mv Foo/*(N) Bar/

(Lassen Sie das weg, (N)wenn Sie wissen, dass das Verzeichnis nicht leer ist.)

Bash

shopt -s dotglob nullglob
mv Foo/* Bar/

Ksh93

Wenn Sie wissen, dass das Verzeichnis nicht leer ist:

FIGNORE='.?(.)'
mv Foo/* Bar/

Standard (POSIX) sh

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

Wenn Sie möchten, dass der mvBefehl trotz Erfolg einen Fehlerstatus zurückgibt, ist dies viel einfacher:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU find und GNU mv

find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +

Standard finden

Wenn es Ihnen nichts ausmacht, in das Quellverzeichnis zu wechseln:

cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -prune

Im Folgenden erfahren Sie, wie Sie steuern, ob Punktdateien in bash, ksh93 und zsh abgeglichen werden.

Bash

Stellen Sie die dotglobOption ein .

$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero

Es gibt auch die flexiblere GLOBIGNOREVariable , die Sie auf eine durch Doppelpunkte getrennte Liste von Platzhaltern setzen können, die ignoriert werden sollen. Wenn nicht gesetzt (Standardeinstellung), verhält sich die Shell so, als ob der Wert leer wäre dotglob, wenn gesetzt, und als ob der Wert leer wäre , .*wenn die Option nicht gesetzt ist. Siehe Dateinamenerweiterung im Handbuch. Die allgegenwärtigen Verzeichnisse .und ..werden immer weggelassen, es sei denn, .das Muster stimmt ausdrücklich mit dem überein.

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

Ksh93

Stellen Sie die FIGNOREVariable ein . Wenn nicht festgelegt (Standardeinstellung), verhält sich die Shell so, als wäre der Wert .*. Um .und zu ignorieren .., müssen sie explizit übereinstimmen (das Handbuch in ksh 93s + 2008-01-31 besagt, dass .und ..immer ignoriert werden, aber dies beschreibt das tatsächliche Verhalten nicht korrekt).

$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero

Sie können Punktedateien in ein Muster aufnehmen, indem Sie sie explizit abgleichen.

$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero

Wenn die Erweiterung leer sein soll, wenn das Verzeichnis leer ist, verwenden Sie die NMustervergleichsoption: ~(N)@(*|.[^.]*|..?*)oder ~(N:*|.[^.]*|..?*).

Zsh

Stellen Sie die dot_globOption ein .

% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero

.und ..werden nie abgeglichen, auch wenn das Muster .explizit mit dem führenden übereinstimmt .

% echo .*
..two .one

Sie können Punktdateien in ein bestimmtes Muster mit dem D Glob-Qualifikationsmerkmal aufnehmen .

% echo *(D)
..two .one none zero

Fügen Sie die Nglob Qualifier die Erweiterung kommen leer in ein leeres Verzeichnis zu machen: *(DN).


Hinweis: Sie können Dateinamen Expansion führen zu unterschiedlichen Aufträgen erhalten (zB nonegefolgt von .onegefolgt von ..two) auf der Grundlage Ihrer Einstellungen der LC_COLLATE, LC_ALLund LANGVariablen.

Gilles
quelle
1
Warum nullglob? Es wäre sinnvoller, den mvBefehl abzubrechen (wie fish, csh / tcsh, zsh (without (N)) do oder bash with failglob), als einen mv /Bar/Befehl auszuführen, der wenig Sinn ergibt .
Stéphane Chazelas
1
Ich würde sagen, Ihre GLOBIGNORE-Beschreibung ist ungenau und irreführend. Einstellen GLOBIGNORE auf einen nicht leeren Wert schaltet dotglob und macht das .und ..werden nie erreicht (wie in anderen sinnvollen Schalen wie zsh, Fisch, pdksh und Derivate) , auch wenn Sie dotglob wieder aus danach drehen. ( GLOBIGNORE=:; shopt -u dotglob; echo .*wird nicht ausgegeben .und ..). setzen Sie GLOBIGNORE auf .:..oder .oder :haben Sie den gleichen Effekt.
Stéphane Chazelas
ksh93immer ignorierend .und ..scheint zwischen ksh93k+(wo es funktioniert) und ksh93m(wo es nicht mehr funktioniert) unterbrochen worden zu sein . Beachten Sie, dass dies ksh93der Umgebung den Wert von FIGNORE entzieht, sodass beispielsweise eine Umgebungsvariable FIGNORE='!(..)'Chaos verursachen kann.
Stéphane Chazelas
24
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

Von man bash

dotglob Wenn gesetzt, enthält bash Dateinamen, die mit einem '.' beginnen. in den Ergebnissen der Pfadnamenerweiterung.

SiegeX
quelle
Mit der Einschränkung, dass dieser Befehl einen Fehlercode zurückgibt, wenn das Verzeichnis leer war (obwohl der Befehl tatsächlich wie beabsichtigt ausgeführt wurde).
Gilles
1
@ Gilles, der Fehler ist dann, mvdass die aufgerufene Datei Foo/*nicht existiert. Interessanterweise wird, wenn Foodurchsuchbar, aber nicht lesbar ist und dort eine Datei aufgerufen *wird, keine Fehlermeldung angezeigt, diese Datei wird verschoben, nicht jedoch die anderen Dateien im Verzeichnis. bashEs hat eine failglobOption, mit der es sich eher wie ein Glob verhält zsh, fishoder csh/ tcshund den Befehl mit einem Fehler abbricht, wenn ein Glob nicht erweitert werden kann, anstatt das falsche Verhalten, das Glob unverändert zu lassen.
Stéphane Chazelas
7

Ein einfacher Weg, dies zu tun, bashist

mv {Foo/*,Foo/.*} Bar/

Damit werden aber auch Verzeichnisse verschoben.

Wenn Sie alle Dateien einschließlich der ausgeblendeten verschieben möchten, aber kein Verzeichnis verschieben möchten, können Sie eine for-Schleife verwenden und testen.

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;

Boris Monat
quelle
4

Ein Weg ist zu benutzen find:

find Foo/ -type f -exec mv -t Bar/ {} \+

Der -type fBefehl find beschränkt sich auf das Suchen von Dateien. Sie sollten die Optionen , und untersuchen -type, um Ihren Befehl so anzupassen, dass er Unterverzeichnissen Rechnung trägt. Find hat eine lange, aber sehr hilfreiche Handbuchseite .-maxdepth-mindepthfind

Steven D
quelle
3
Das verschiebt nur die regulären Dateien Foo/, keine Unterverzeichnisse und andere Dateien.
Gilles
2

Versuchen Sie den Kopierbefehl cp:

$ cp -r myfolder/* destinationfolder

cp -r bedeutet, dass rekursiv kopiert wird, sodass alle Ordner und Dateien kopiert werden.

Mit dem Befehl rmremove können Sie einen Ordner entfernen:

$ rm -r myfolder

Weitere Informationen: Verschieben Sie alle Dateien von einem Verzeichnis in ein anderes .

ucefkh
quelle
2
Nicht das Beste, wenn Sie viele große Dateien verschieben, aber ich denke, es würde funktionieren.
Cory Klein
Vielleicht, wenn Sie einen Punkt anstelle des Sterns verwenden?
Vincent
1

Rsync ist eine weitere Option:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory

Dies funktioniert, weil in rsync der abschließende Schrägstrich sourcedirectory/auf den Inhalt des Verzeichnisses und sourcedirectoryder auf das Verzeichnis selbst verweist.

Der Nachteil dieser Methode ist, dass rsync die Dateien erst nach dem Verschieben aufräumt, nicht das Verzeichnis. So bleibt Ihnen ein leerer Quellenverzeichnisbaum übrig. Problemumgehungen hierzu finden Sie unter:

Dateien verschieben und Verzeichnisse mit rsync löschen?

Während dies für Verschiebevorgänge möglicherweise nicht optimal ist, kann es für Kopiervorgänge äußerst nützlich sein.

Grumbel
quelle
1

Antwort für Bash / Fisch

Hier ist eine Möglichkeit, Wildcards zu verwenden:

.[!.]* ..?*stimmt mit allen versteckten Dateien außer .und überein..

.[!.]* ..?* *wird mit allen Dateien (versteckt oder nicht) außer .und übereinstimmen..

Und um das spezielle Beispiel dieser Frage zu beantworten, brauchen Sie cd foo && mv .[!.]* ..?* * ../bar

Erläuterung

.[!.]*Sucht nach Dateinamen, die mit einem Punkt beginnen, gefolgt von einem beliebigen Zeichen, mit Ausnahme des Punkts, optional gefolgt von einer beliebigen Zeichenfolge. Dies ist nah genug, aber es fehlen Dateien, die mit zwei Punkten wie beginnen ..foo. Um solche Dateien einzuschließen, fügen wir ..?*die Dateinamen hinzu, die mit zwei Punkten beginnen, gefolgt von einem beliebigen Zeichen, optional gefolgt von einer beliebigen Zeichenfolge.

Prüfung

Sie können diese Platzhalter mit den folgenden Befehlen testen. Ich habe sie erfolgreich unter Bash und Fish ausprobiert. Sie scheitern unter sh, zsh, xonsh.

mkdir temp
cd temp
touch  a  .b  .bc  ..c  ..cd  ...d  ...de
ls .[!.]* ..?*
# you get this output:
          .b  .bc  ..c  ..cd  ...d  ...de
# cleanup
cd ..
rm -rf temp
ndemou
quelle
0

Möglicherweise können Sie auch mit Anführungszeichen nach Dateien für den Befehl move suchen und diese anzeigen. Übergeben Sie diese an mv.

Dh für versteckte Dateien

find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden

Damit

mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar

Verschiebt nur ausgewählte versteckte Dateien in Bar:

mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar

Verschiebt alle Dateien in Foo in die Leiste seit dem '.' Der Befehl egrep fungiert als Platzhalter ohne eckige Klammern.

Der ^Charakter stellt sicher, dass die Übereinstimmung am Anfang der Zeile beginnt.

Einige Details zum egrepPattern Matching finden Sie hier .

Verwenden Sie maxdepth 1Stopps, um nicht in Unterverzeichnisse zu gelangen.

user3192145
quelle
0

Inspiriert von dieser Antwort :

Ohne die Dateien zu kopieren ...

rsync -ax --link-dest=../Foo/ Foo/ Bar

Vorsichtsmaßnahmen:

  • --link-destPfad muss absolut oder relativ zu DESTINATION sein ( Bar im Beispiel)

  • Sie müssen /nach SOURCE ( Foo/im Beispiel) einfügen , andernfalls wird der SOURCE-Ordner anstatt dessen Inhalt kopiert.

Palindrom
quelle
0

Ich finde, dass dies gut für Bash funktioniert und es keine Notwendigkeit gibt, die Shell-Optionen zu ändern

mv sourcedir/{*,.[^.]*} destdir/

BEARBEITEN:

Wie G-man feststellte, ist meine ursprüngliche Antwort nicht posix-konform und entspricht in etwa der obigen Antwort von ndemou mit einer Änderung, nämlich der Verwendung der geschweiften Klammer, um Listen von Zeichenfolgen zu erstellen, auf die dann reagiert wird. Dies bedeutet nur, dass Sie nicht cdin das Quellverzeichnis müssen. Eigentlich keine große Veränderung, aber es ist anders.

Beispiel: Nehmen wir an, Sie haben bereits das folgende Layout.

 $ tree -a
.
├── destdir
└── sourcedir
    ├── ..d1
    ├── ..d2
    ├── ..double
    ├── file-1
    ├── file-2
    ├── .hidden-1
    ├── .hidden-2
    ├── ...t1
    └── ...t2

Die ursprüngliche Frage bezog sich nur auf versteckte Dateien mit einem einzigen Punkt. Nehmen wir jedoch an, dass am Anfang des Namens zwei oder mehr Punkte stehen. Sie können einfach einen zusätzlichen Ausdruck in die geschweiften Klammern einfügen. Wir können dann ausführen

mv sourcedir/{*,.[!.]*,..?*} destdir/

Dies wird folgendermaßen erweitert:

mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/

Sie sollten jetzt alle Dateien in destdir sehen :

 $ tree -a
.
├── destdir
   ├── ..d1
   ├── ..d2
   ├── ..double
   ├── file-1
   ├── file-2
   ├── .hidden-1
   ├── .hidden-2
   ├── ...t1
   └── ...t2
└── sourcedir

Sie können mit geschweiften Klammern in bash einige ziemlich coole Dinge tun, mit noch mehr Ergänzungen in 4.x. Schauen Sie sich Bash-Hacker an, um einige nützliche Beispiele zu finden.

cmndr sp0ck
quelle
1
Dies entspricht im Wesentlichen der Antwort von ndemou, mit der Ausnahme, dass Sie geschweifte Klammern hinzugefügt haben (ohne sie zu erklären). Aber (1) Ihre Antwort stimmt nicht mit Dateien überein, deren Namen mit beginnen .., und (2) um POSIX-kompatibel zu sein , sollten Sie !statt verwenden ^; dh  {*,.[!.]*}.
G-Man
@ G-Man, tut mir leid. Sie haben also Recht und ich finde es schlecht, dass Sie die Antwort von ndemou nicht gesehen haben. Sie sind so ziemlich dasselbe. 1. Vielen Dank, dass Sie darauf hingewiesen haben, dass meine Version nicht posix-kompatibel ist. 2. Ich benutze die geschweifte Klammer, um Listen mit Zeichenfolgen zu erstellen, mit denen die Shell dann eine Aktion ausführt. Dies bedeutet auch, dass ich nicht cdin das Quellverzeichnis wechseln muss, um auf die Dateien zuzugreifen oder immer wieder dieselben Dateipfade zu schreiben, um die Pfade zu allen Dateien auszudrücken. Ich werde das Beispiel in Kürze aktualisieren, um den Lesern ein besseres Bild davon zu geben, wovon ich spreche.
cmndr sp0ck
0

Für minimale Linux-Distributionen sollte Folgendes funktionieren. Führen Sie zunächst einen einfachen Move all aus (bei dem die versteckten Dateien fehlen). Dann bewegen Sie alle versteckten Dateien (einschließlich der .und ..die wird nicht tatsächlich bewegt werden).

mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null

Hinweise: Wenn kein sichtbarer Inhalt vorhanden ist, wird beim ersten Befehl eine Fehlermeldung ausgegeben. Der zweite Befehl erzeugt immer einen Fehler, der besagt, dass er sich nicht bewegen kann .und ... Als solches leiten Sie die Fehler einfach weiter /dev/null(wie gezeigt).

Wenn Sie dies als Einzeiler benötigen, kombinieren Sie diese einfach mit einem Semikolon:

mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
BuvinJ
quelle