Wie kopiere ich einen Ordner mit cp auf idempotente Weise rekursiv?
On Dezember 1, 2020 by adminWenn ich
cp -R inputFolder outputFolder
verwende, lautet das Ergebnis kontextabhängig :
- Wenn
outputFolder
nicht vorhanden ist, wird dies der Fall sein erstellt werden und der geklonte Ordnerpfad lautetoutputFolder
. - Wenn
outputFolder
vorhanden ist, wird der erstellte Klon erstelltoutputFolder/inputFolder
Dies ist schrecklich , da ich ein Installationsskript erstellen möchte und der Benutzer es versehentlich zweimal ausführt, hat er outputFolder
das erste Mal erstellt, und beim zweiten Ausführen wird das gesamte Material ausgeführt erneut erstellt werden in outputFolder/inputFolder
.
- Ich möchte immer das erste Verhalten: Erstellen Sie einen Klon neben dem Original (als Geschwister).
- Ich möchte
cp
verwenden, um portabel zu sein (z MINGW nichtrsync
ausgeliefert) - Ich habe
cp -R --parents
überprüft, aber dadurch wird der Pfad bis zum Verzeichnisbaum neu erstellt (so Der Klon ist nichtoutputFolder
, sondernsome/path/outputFolder
) -
--remove-destination
oder--update
falls 2 nichts ändert, werden die Dinge dennoch inoutputFolder/inputFolder
Is kopiert Es gibt eine Möglichkeit, dies zu tun, ohne zuerst die Existenz des outputFolder
zu überprüfen (wenn der Ordner nicht vorhanden ist, dann …) oder rm -rf outputFolder
zu verwenden ?
Was ist die vereinbarte, tragbare UNIX-Methode, um dies zu tun?
Kommentare
- Verwandte Themen: Wie kann verhindert werden, dass
mv
eine Sammlung von Dateien in eine einzige reguläre Datei verschiebt? - Einige dieser Optionen sind nicht verfügbar ‚ t POSIX, daher sind diejenigen, die Sie ausprobiert haben, ‚ nicht sehr portabel. Wenn Sie mit ein wenig mangelnder Portabilität leben können, warum nicht
rsync
verwenden? - Wenn Sie ‚ t nicht verwenden Wenn Sie
cp
verwenden müssen, ist das Piping zwischen zweitar
-Befehlen eine gute und zuverlässige Methode zum Kopieren von Bäumen. - @R .. können Sie ein Beispiel geben? @muru Ich ‚ möchte, dass dies in MINGW funktioniert, in dem
rsync
nicht ausgeliefert wird. - Mit GNU tar ,
tar -C input -cf - . | tar -C output -xf -
funktioniert.-C
ändert das Arbeitsverzeichnis, ist jedoch keine Standardoption. Wenn es also ‚ nicht unterstützt wird, müssen Sie die beiden Teere ausführen die richtigen Arbeitsverzeichnisse, z( cd input && tar -cf - . ) | ( cd output && tar -xf - )
Wenn Sie jedoch ‚ mit Windows arbeiten, würde ich nur die Antwort von roaima ‚ verwenden .
Antwort
Verwenden Sie stattdessen Folgendes:
cp -R inputFolder/. outputFolder
Dies funktioniert genauso wie beispielsweise cp -R aaa/bbb ccc
: Wenn ccc
nicht existiert, ist es “ s erstellt als Kopie von bbb
und seinem Inhalt; Wenn jedoch ccc
bereits vorhanden ist, wird ccc/bbb
als Kopie von bbb
und dessen Inhalt erstellt
Für fast jede Instanz von bbb
ergibt sich das unerwünschte Verhalten, das Sie in Ihrer Frage festgestellt haben. In dieser speziellen Situation ist bbb
jedoch nur .
, sodass aaa/bbb
wirklich aaa/.
, was wiederum nur aaa
ist, aber unter einem anderen Namen. Wir haben also diese beiden Szenarien:
-
ccc
existiert nicht:Der Befehl
cp -R aaa/. ccc
bedeutet“ccc
erstellen und den Inhalt vonaaa/.
inccc/.
, dh kopieren Sieaaa
inccc
. -
ccc
existiert:Der Befehl
cp -R aaa/. ccc
bedeutet“ Kopieren des Inhalts vonaaa/.
inccc/.
, dh kopieren Sieaaa
inccc
.
Kommentare
- Huh, das ‚ ist neu für mich, aber es scheint zu funktionieren! Ist dies irgendwo dokumentiert?
- Ich ‚ habe die
inputFolder/.
anstelle voninputFolder
und tatsächlich funktioniert es für mich unter Windows / Git Bash. (Es funktioniert jedoch nicht nur mit einem abschließenden/
, ich brauche auch den Punkt nach dem Schrägstrich).Ich habe +1 gegeben, da es ‚ interessant ist, obwohl es ‚ wahrscheinlich etwas zu schwierig ist, es im öffentlichen Code zu verwenden 🙂 - @IlmariJaronen ‚ muss nicht explizit dokumentiert werden. Folgen Sie der Erklärung und Sie ‚ werden sehen, wie einfach “ den Regeln “ folgt
Antwort
Kopieren Sie den Ordner nicht, sondern nur den Inhalt:
## Create the target directory. The -p suppresses error messages ## if the directory already exists mkdir -p outputFolder ## Copy the contents recursively, this will not recreate the parent cp -R inputfolder/* outputfolder/
Auf diese Weise stellen Sie beide sicher, dass das Zielverzeichnis beim ersten Ausführen des Skripts erstellt wird, und vermeiden das Problem beim zweiten Ausführen.
Chris Down weist sehr korrekt darauf hin, dass in bash Dateien übersprungen werden, deren Name mit einem .
beginnt. Um dies zu vermeiden Sie können shopt -s dotglob
ausführen, bevor Sie den obigen Befehl ausführen.
Beide -p
für mkdir
und -R
für cp
werden von POSIX definiert, daher sollte dies perfekt portierbar sein.
Kommentare
- Hinweis: ‚ kopiert keine Dateien, die mit
.
beginnen. In bash können Sie dafürdotglob
verwenden. - Beachten Sie, dass diese Methode wahrscheinlich fehlschlägt, wenn die Anzahl der Verzeichniseinträge im Eingabeordner groß ist, da die Glob-Erweiterung kann die maximale Befehlszeilenlänge überschreiten.
Antwort
Versuchen Sie es mit -T
Option auf cp
. Dies ist in GNU coreutils cp
Version 8.22 vorhanden. es kann außerhalb davon nicht portierbar sein.
Kommentare
- Ja, es scheint, dass dies genau das ist, was ich wollte:
cp -T
(cp --no-target-directory
). unix.stackexchange.com/questions/94831/… Leider meine Version voncp
ist viel älter. - +1 Wird erst heute verwendet.
-u
ist eine großartige Option zum Hinzufügen, um es faul zu machen.
Antwort
Sie können auch rsync
verwenden:
rsync -uav inputFolder/ outputFolder/
(beachten Sie die Schrägstriche, insbesondere nach dem ersten )
Antwort
Sie können die -t
Option von Befehl als:
cp -R inputFolder -t outputFolder
Wenn der Zielordner nicht vorhanden ist, wird ein Fehler ausgegeben:
cp: failed to access ‘outputFolder’: No such file or directory
Hinweis über dem Befehl kopiert inputFolder
zusammen mit seinem Inhalt (und nicht nur dem Inhalt darin)
, wenn Sie möchten Um nur den Inhalt von inputFolder
zu kopieren, wird es etwas schwierig (da Sie bei der Verwendung von Shell Globbing bei Verwendung von Sternchen * vorsichtig sein müssen)
cp -R -t outputFolder/ -- inputFolder/*
Wenn der Zielordner nicht vorhanden ist, wird ein Fehler ausgegeben:
cp: failed to access ‘outputFolder’: No such file or directory
funktioniert mit cp (GNU coreutils) 8.23
Antwort
Meiner Meinung nach gibt es nichts Einfacheres und Tragbareres als rm -rf outputFolder
. Also bleibe ich immer dabei. Ich verstehe, dass Ihre Frage anders ist, aber ich denke, dass dies die beste Vorgehensweise ist.
Kommentare
- Dies schlägt fehl, wenn bestimmte Berechtigungen oder Eigentümer vorhanden waren auf das Ziel, das gehalten werden musste. Oder wenn es sich um einen Symlink handelt.
- Die Frage möchte, dass das Ergebnis von
cp
dasselbe ist, sowohl wenn das Verzeichnis nicht existiert als auch wenn es existiert. Also, wovon redest du? - Der vom OP angegebene Befehl
cp
behält keine ‚ Berechtigungen (oder Zeitstempel).
Schreibe einen Kommentar