Wie verschiebe ich alle Geschwisterordner in einen Ordner?

6

Ich entschuldige mich, dass dies eine so blöde Frage ist, aber ich kann es mir nicht leisten, sie zu vermasseln.

Ich habe eine Reihe von Ordnern wie folgt:

/ users / me / foo / oops1

/ users / me / foo / oops2

/ users / me / foo / oops3

/ users / me / foo / oops4

/ users / me / foo / bar

Leider sind sie nicht einheitlich benannt und es gibt Hunderte von Oops-Ordnern.

Ich wollte alle oops-Ordner in die Leiste kopieren. Gibt es eine einfache Möglichkeit, alle oops-Ordner in die Leiste zu verschieben, die nicht zu einem rekursiven Verschiebungsproblem führen?

Das Kopieren der Dateien dauerte mehrere Stunden. Ich hoffe, dass der Umzug viel schneller sein wird.

Dies ist übrigens auf einem Red Hat Linux Server. Ich habe nur ssh zugang

Ich denke, wenn ich es tue

cd foo
mv * bar

Es wird ein Problem geben.

jgritty
quelle
Wie heißen sie dann? Möchten Sie alles außer Bar in Bar verschieben?
cpast
Richtig. Sie haben verschiedene Namen.
Jgritty

Antworten:

3

Leider weisen sowohl Matts als auch Nicoles Antwort einen schlechten Stil auf und werden *beschädigt , wenn einer der Ordner sogar ein einzelnes Leerzeichen, ein Globbing- Zeichen (wie ) oder eine neue Zeile enthält. Das Laufenfor item in $(ls …) ist ein großer Fehler, den man machen kann, weil er sie früher oder später beißt, und das Iterieren über Dateinamen, die nicht richtig ausgegeben werden, kann alle möglichen Probleme verursachen.

Analysieren Sie niemals die Ausgabe vonls .

Unter Linux gibt es ein Tool zum Suchen von Dateien, die bestimmten Kriterien entsprechen. Es heißt find:

find . -mindepth 1 -maxdepth 1 \
-type d ! -regex ".\/bar$" \
-exec mv '{}' ./bar/ \;

Dadurch werden alle Verzeichnisse im aktuellen Arbeitsverzeichnis verschoben, in die nicht aufgerufen barwurde ./bar/. Dies funktioniert auch, wenn die Verzeichnisnamen Leerzeichen, Zeilenumbrüche oder Zeilenumbrüche enthalten.

Der reguläre Ausdruck .\/bar$stimmt nur mit dem aufgerufenen Verzeichnis überein ./barund wird von negiert !.

slhck
quelle
Dies ist aber auch sehr langsam, da es mvfür jede Datei einmal ausgeführt wird. Und mit so vielen Begriffen bietet es viele Möglichkeiten, einen Fehler zu machen. bashbenötigt und fehlt eine bessere Substitutionseinrichtung, die mit Dateinamen mit Leerzeichen umgehen kann.
Nicole Hamilton
Ja, es wird mveinmal für jeden Ordner ausgeführt , nicht für jede Datei. Ich glaube, \+damit sollte es schneller laufen und alle Ordner in einem Befehl verschieben, obwohl ich nicht weiß, ob das eine größere Beschleunigung verursachen würde. Ich stimme Ihnen zu, dass dies viel einfacher sein sollte, da der einfachste Weg, mit Dateien in Bash umzugehen , leider nie der richtige ist. Ich hatte nur das Gefühl, dass es eine Antwort geben musste, die auf jeden Fall funktionieren würde.
Slhck
Glücklicherweise hat keine der Dateien * oder Leerzeichen, aber dies scheint im Allgemeinen eine bessere Antwort zu sein.
Jgritty
7

Was Sie vorschlagen, ist genau richtig. mvist schlau genug und wird folgendes sagen:

mv: cannot move `bar' to a subdirectory of itself, `bar/bar'

Alle deine oopsx-Verzeichnisse befinden sich jedoch in der Leiste.

Perleone
quelle
Das hat meinen Tag buchstäblich dazu gebracht, dass hahahaha rohe Gewalt manchmal einfach funktioniert! (Ockhams Rasiermesser)
Dai
3

Ja, du hast recht, das wäre ein Problem, denn es *wird auch passen bar; Sie können nicht mvin sich selbst verzeichnen.

Der technisch anspruchsvolle Weg besteht darin, die Befehlsersetzung und eine Schleife mvnur für die Dinge zu verwenden, die nicht vorhanden sind bar. In bashkönnten Sie zum Beispiel so etwas schreiben, aber beachten Sie, dass es fehlschlägt, wenn es auf einen Namen trifft, der ein Leerzeichen enthält.

mv $(for i in *; do if [ $i != "bar" ]; then echo $i; fi; done) bar

Aber ehrlich gesagt bin ich faul. Ich würde mvaus dem Weg räumen, dann mvalles hinein und es dann zurück bewegen. Sie verschieben nur Links zum Dateisystem, nicht zum Dateiinhalt. Das geht also schnell. Dies hat auch den Vorteil, dass Sie arbeiten können, wenn Sie Namen mit Leerzeichen haben.

cd foo
mv bar ../bar.save
mv * ../bar.save
mv ../bar.save bar
Nicole Hamilton
quelle
Ihr Skript funktioniert nicht, wenn eines der Verzeichnisse ein Leerzeichen, ein Zeilenumbruchzeichen oder eine neue Zeile enthält. Ein Verzeichnis mit dem Namen "foo baz"würde beispielsweise als angezeigt mv foo baz barund anschließend fehlschlagen.
Slhck
Ja, ja, ich merke, dass Sie immer darauf hinweisen. Sie müssen das auf einer Makrotaste haben. Aber (a) wenn Sie Leerzeichen in den Namen haben, wissen Sie wahrscheinlich, dass (b) dies ein Problem ist bash, das behoben werden sollte (es ist in meiner C-Shell behoben ), (c) dies ist ein guter Grund dafür den zweiten weg, den ich eigentlich empfohlen habe.
Nicole Hamilton
Es gibt wahrscheinlich Hunderte von Bash-Skripten für Super User, die diese unbedeutenden Mängel aufzeigen. Hier sollten wir lernen, wie man etwas erreicht und an seine Bedürfnisse anpasst. Aus der Erfahrung des OP würde ich nicht sagen, dass sie wissen, dass ein Platz an erster Stelle ein Problem ist. Zumindest sollten Sie solche Annahmen in Ihrer Antwort explizit erwähnen (ich würde dann auch die Ablehnung entfernen). Vielleicht könnten Sie Ihren Beitrag bearbeiten, um das zu klären. Es ist auch kein Problem der Shell an sich , es ist nur ein Problem, wenn der falsche Ansatz verwendet wird.
Slhck
Ich habe auch mit erfahrenen Anwendern unter Unix und Linux gesprochen , bei denen die Richtlinien für "defekte" Bash-Skripte gleich sind. Bearbeiten, um zu verbessern, oder Abstimmen / Kommentieren, um auf Mängel hinzuweisen. Bitte nimm es nicht persönlich - wir sind nicht so viele Benutzer hier, die Antworten mit Shell-Skripten posten. Ich habe es zufällig bemerkt.
Slhck
1
Es stimmt zwar, dass *übereinstimmen bar, ist es nicht ein Problem , da ‚mv‘ / ist der Kern intelligent genug , um diese Instanz zu erkennen. Es ist also kein Problem, sondern eine gute Möglichkeit, dies zu tun (es sei denn, Sie möchten bestimmte Verzeichnisse herausfiltern, aber das ist eine andere Frage)
JvO
1

Wenn Sie sich sicherer fühlen, können Sie dies in BASH tun:

for item in `ls -d | grep -v "^bar$"`; do mv $item bar; done;
Matt
quelle
2
Was ist mit versehentlich zusammenpassendem Barf, Barfly oder Bark? Verwenden Sie, grep -v '^bar$'um nur "bar" zu entsprechen.
Perleone
1
Zustimmen. Besser mit "^ bar $". Danke fürs bemerken. Ich habe die Antwort aktualisiert.
Matt
1
Laufen ls -dgibt dir nur .das aktuelle Arbeitsverzeichnis. Sind Sie sicher, dass dies funktioniert? Hast du den Befehl ausprobiert? Siehe: Wie liste ich Ordner mit Bash-Befehlen auf? - Außerdem schlägt dieses Skript fehl, wenn in einem der Verzeichnisse ein Leerzeichen, ein Zeilenumbruch oder ein abschließendes Zeichen enthalten ist.
Slhck
-1: Wie von @slhck hervorgehoben, funktioniert diese Antwort nicht. Und die Antwort von @Perleone ist besser.
Adrian Pronk
-1

cd in foo

mv -t bar oops[[:digit:]]

der allgemeineren

mv -t bar oops*
WikiWitz
quelle
haha sorry für Tippfehler
WikiWitz
2
Sie werden aber nicht wirklich Hoppla genannt.
Jgritty