Liste der Dateien kopieren

35

Ich habe eine Liste von Dateien, die durch Leerzeichen in einer Datei getrennt sind list.txt. Ich möchte sie in einen neuen Ordner kopieren.

Ich habe versucht zu tun:

cp `cat list.txt` new_folder

aber es hat nicht funktioniert.

Wie würdest du das machen?

Aktualisieren:

Vielen Dank für all Ihre sehr interessanten Antworten. Ich habe nicht so viel verlangt :)

Nachdem Sie die oben genannte Lösung ein zweites Mal ausprobiert haben, scheint cpdie Verwendungshilfe gedruckt worden zu sein, da der Ordner new_foldernoch nicht vorhanden war! Entschuldigung, es scheint ein dummer Fehler zu sein ... Wenn ich den Ordner vorher erstelle, funktioniert es.

Ich habe jedoch aus all Ihren Antworten und Lösungen viel gelernt. Vielen Dank, dass Sie sich die Zeit genommen haben, diese zu schreiben.

Klaus
quelle
Lassen Sie mich eines klarstellen: Die Liste enthält alle Dateinamen in einer Zeile, die nur durch ein Leerzeichen getrennt sind. Oder stehen die Namen jeweils in einer eigenen Zeile?
Telemachus
Alles in einem Kalk, durch ein Leerzeichen getrennt. Dougs Lösung hat funktioniert :) Vielen Dank für die Antwort.
Klaus
Das ist lustig ... Ich habe meine Lösung mit einer Zeile getestet, in der jeder Name in einer separaten Zeile stand.
Doug Harris
"es hat nicht funktioniert" ist nicht sehr aussagekräftig. Genau wie hat es nicht geklappt. Es funktioniert gut für mich.
Bis auf weiteres angehalten.
Entschuldigung: es wurde die Hilfe zur Verwendung von CP angezeigt. Siehe mein Update oben.
Klaus

Antworten:

34

Versuchen Sie es mit xargs:

cat list.txt | xargs -J % cp % new_folder

Aktualisieren:

Ich habe dies unter OS X gemacht, das eine andere Version als GNU / Linux-Versionen hat. Das, xargswas von GNU kommt, hat findutils nicht, -Jaber es hat, -Iwas ähnlich ist (wie Dennis Williamson in einem Kommentar hervorhob ). Die OS X-Version von xargs hat beide -Iund -Jein leicht unterschiedliches Verhalten - beide funktionieren für diese ursprüngliche Frage.

$ cat list.txt
one
two.txt
three.rtf

$ cat list.txt | xargs -J % echo cp % new_folder
cp one two.txt three.rtf new_folder

$ cat list.txt | xargs -I % echo cp % new_folder
cp one new_folder
cp two.txt new_folder
cp three.rtf new_folder
Doug Harris
quelle
3
Meine xargshat nicht -Jhat , -Idie die gleiche Sache zu tun scheint. Welche Version von xargsund welches Betriebssystem / welche Distribution haben Sie?
Bis auf weiteres angehalten.
Ich habe dies unter Mac OS X 10.6 (auch bekannt als Schneeleopard) getestet, es ist also jede Version von xargs, die mit dem Betriebssystem geliefert wird. Running xargs --versiongibt eine Verwendungsfehlermeldung zurück. Es ist wahrscheinlich eine BSD-Version von xargs. Die Verwendung von -Iund unterscheiden -Jsich geringfügig. Ich werde meine Antwort mit gut formatierten Beispielen aktualisieren.
Doug Harris
Ja, ich arbeite mit Mac OSX 10.6. Vielen Dank für die Präzision über -Jund -I:)
Klaus
Das ist ein guter Tipp, um mit echo Ihre Befehle zu überprüfen, bevor Sie sie ausführen.
Liam
1
Wie kopiere ich die Dateien, indem ich den obigen Befehl nur mit den erforderlichen Änderungen verwende, und erstelle die Verzeichnisse und Unterverzeichnisse, in denen sie sich befinden, durch Schrägstriche getrennt?
Vicky Dev
54

Überhaupt nicht nötig cat:

xargs -a list.txt cp -t new_folder

Oder mit langen Optionen:

xargs --arg-file=list.txt cp --target-directory=new_folder

Hier sind einige Shell-Versionen. Beachten Sie, dass einige Variablen nicht in Anführungszeichen gesetzt sind oder forSchleifen verwendet werden, da das OP angibt, dass die Dateinamen durch Leerzeichen getrennt sind. Einige dieser Techniken funktionieren nicht bei der Eingabe von Dateinamen pro Zeile, bei der Dateinamen Leerzeichen enthalten.

Bash:

for file in $(<list.txt); do cp "$file" new_folder; done

oder

cp $(<list.txt) new_folder

sh (oder Bash):

# still no cat!
while read -r line; do for file in $line; do cp "$file" new_folder; done; done < list.txt

oder

# none here either
while read -r line; do cp $line new_folder; done < list.txt

oder

# meow
for file in $(cat list.txt); do cp "$file" new_folder; done

oder

# meow
cp $(cat list.txt) new_folder
Bis auf weiteres angehalten.
quelle
noob frage: warum wird in -tgebraucht xargs -a list.txt cp -t new_folder?
Yibo Yang
1
@ YiboYang: Das -tist eine Option von cp. Es kopiert alle Quellargumente in das angegebene Zielverzeichnis. Hier kann das Ziel vor der Quelle angegeben werden, die durch den xargsBefehl hinzugefügt wird .
Bis auf weiteres angehalten.
Dies ist nützlich, aber was ist, wenn list.txt gemischte Dateien und Ordner enthält? In diesem Fall funktioniert der Befehl nicht richtig. Es meldet "Verzeichnis wird ausgelassen ..." und wenn -R für den Befehl cp angegeben ist, wird der Fehler "Kein Verzeichnis" gemeldet, sobald die erste Datei in der Liste gefunden wird.
Bemipefe
7

Ich hatte hier früher eine peinlich runde Antwort, aber Denis 'Antwort erinnerte mich daran, dass ich das Grundlegendste verpasst hatte. Also habe ich meine ursprüngliche Antwort gelöscht. Aber da niemand diese sehr grundlegende Sache gesagt hat, denke ich, dass es sich lohnt, sie hier zu platzieren.

Die ursprüngliche Frage lautet: "Ich habe eine Textdatei mit einer Liste von durch Leerzeichen getrennten Dateinamen. Wie kann ich diese in ein Zielverzeichnis kopieren?" Auf den ersten Blick mag dies schwierig oder kompliziert erscheinen, da Sie denken, dass Sie die Elemente auf eine bestimmte Weise aus der Datei extrahieren müssen. Wenn die Shell jedoch eine Befehlszeile verarbeitet, teilt sie die Argumentliste zunächst in Token und (hier ist das Bit, das niemand direkt gesagt hat) Leerzeichen in Token auf . (Neue Zeilen trennen auch Token, weshalb Doug Harris 'Test mit einer durch neue Zeilen getrennten Liste dasselbe Ergebnis lieferte.) Das heißt, die Shell erwartet und kann bereits eine durch Leerzeichen getrennte Liste verarbeiten.

Alles, was Sie hier tun müssen, ist, die durch Leerzeichen getrennte Liste (die Sie bereits haben) an die richtige Stelle in Ihrem Befehl zu setzen. Ihr Befehl ist eine Variation davon:

cp file1 file2 file3...file# target

Der einzige Nachteil ist, dass Sie die Liste der Dateien 1 bis # aus Ihrer Textdatei abrufen möchten.

Wie Dennis in seinem Kommentar cpbetont , hätte Ihr ursprünglicher Versuch ( cat list.txt new_folder) bereits funktionieren müssen. Warum? Denn der interne Befehl cat list.txtwird zuerst von der Shell verarbeitet und erweitert. file1 file2 file3...file#Genau das erwartet und wünscht sich die Shell in diesem Teil des Befehls. Wenn es nicht geklappt hat, waren entweder (1) Sie einen Tippfehler oder (2) Ihre Dateinamen irgendwie seltsam (sie hatten Leerzeichen oder andere ungewöhnliche Zeichen).

Der Grund, warum alle Antworten von Dennis funktionieren, besteht einfach darin, dass sie die erforderliche Liste von Dateien für cpdie Bearbeitung bereitstellen und diese Liste dort platzieren, wo sie in den gesamten Befehl gehört. Der Befehl selbst ist wiederum folgendermaßen aufgebaut:

cp list-of-files target_directory

Es ist leicht zu sehen, wie das alles in dieser Version zusammenkommt:

cp $(<list.txt) new_folder

$()Bewirkt, dass die Shell den Befehl in Klammern ausführt und die Ausgabe an dieser Stelle in der größeren Zeile ersetzt. Dann führt die Shell die gesamte Linie aus. Übrigens $()ist eine modernere Version dessen, was Sie bereits mit Backticks gemacht haben (`). Next: <ist ein Dateiumleitungsoperator. Es weist die Shell an, den Inhalt der list.txtStandardeingabe zu sichern. Da das $()Bit zuerst verarbeitet wird, geschieht Folgendes schrittweise:

  1. cp $(<list.txt) new_folder # split line into three tokens: cp, $(<list.txt), new_folder
  2. cp file1 file2 file3...file# new_folder # substitute result of $(<list.txt) into the larger command

Offensichtlich ist Schritt 2 einfach der normale cpBefehl, den Sie wollten.

Mir ist klar, dass ich dieses (vielleicht sehr tote) Pferd sehr oft besiege, aber ich denke, dass es sich lohnt, es zu tun. Wenn Sie genau wissen , wie die Shell einen Befehl verarbeitet, können Sie ihn besser schreiben und erheblich vereinfachen. Es zeigt Ihnen auch, wo sich Probleme wahrscheinlich verstecken. In diesem Fall hätte meine erste Frage an Sie zum Beispiel nach lustigen Dateinamen oder einem möglichen Tippfehler lauten sollen. Akrobatik war nicht erforderlich.

Telemachus
quelle
@Klaus Gern geschehen. Um ehrlich zu sein, ich habe mich am meisten geärgert, als ich Dennis 'Antwort gelesen und gemerkt habe, dass ich den Hauptteil des Problems völlig verpasst habe. Die Lösung, die Sie mögen, ist auch von dort.
Telemachus
Dies ist eine super alte Antwort, aber wenn Sie die Ordnerstruktur neu erstellen müssen, benötigen Sie das --parentsFlag. Sie können eine ausführliche -vAufzeichnung darüber erstellen, was kopiert wurde. Wenn Sie Berechtigungen behalten möchten, benötigen Sie das Flag -aoder -p. Dh cp --parents -av $(<list.txt) new_folder. Dies alles unter der -rVoraussetzung, dass Ihre Dateiliste wirklich alle Dateien enthält. Andernfalls benötigen Sie möglicherweise auch das Flag, um eine Rekursion durchzuführen.
Dhaupin
@dhaupin Tatsächlich gibt das OP an, dass er auf macOS war. Also für was es wert ist, --parentsgibt es die Flagge dort nicht. Ihre (von BSD abgeleitete) Version cpbietet nur kurze Optionen, keine langen Optionen im GNU-Stil. Bei einem BSD-Stil cpist das Flag für rekursives Kopieren Großbuchstaben -Rund nicht Kleinbuchstaben.
Telemachus