In diesem Artikel werden einige nicht offensichtliche Dinge im Zusammenhang mit der Verwendung von enthüllt Platzhalter Beim Kopieren mehrdeutiges Befehlsverhalten cp beim Kopieren sowie Methoden, mit denen Sie eine große Anzahl von Dateien korrekt kopieren können, ohne dass es zu Sprüngen oder Abstürzen kommt.
Nehmen wir an, wir müssen alles aus dem Ordner /source in den Ordner /target kopieren.
Das erste, was mir in den Sinn kommt, ist:
cp /source/* /target
Korrigieren wir diesen Befehl sofort wie folgt:
cp -a /source/* /target
Schlüssel -a fügt das Kopieren aller Attribute und Rechte hinzu und fügt Rekursion hinzu. Wenn keine exakte Reproduktion der Rechte erforderlich ist, reicht ein Schlüssel aus -r.
Nach dem Kopieren werden wir feststellen, dass nicht alle Dateien kopiert wurden – Dateien, die mit einem Punkt beginnen, wie zum Beispiel:
.profile
.local
.mc
und dergleichen.
Warum ist das passiert?
Da Platzhalter von der Shell verarbeitet werden (bash im typischen Fall). Standardmäßig ignoriert Bash alle Dateien, die mit einem Punkt beginnen, da es sie als versteckt behandelt. Um dieses Verhalten zu vermeiden, müssen wir unser Verhalten ändern bash mit dem Befehl:
shopt -s dotglob
Um sicherzustellen, dass diese Verhaltensänderung nach einem Neustart bestehen bleibt, können Sie mit diesem Befehl im Ordner eine wildcard.sh-Datei erstellen /etc/profile.d (Vielleicht hat Ihre Distribution einen anderen Ordner).
Und wenn im Quellverzeichnis keine Dateien vorhanden sind, kann die Shell den Stern durch nichts ersetzen und auch das Kopieren schlägt mit einem Fehler fehl. Es gibt Optionen gegen diese Situation failglob и nullglob. Wir müssen einstellen failglob, wodurch verhindert wird, dass der Befehl ausgeführt wird. nullglob wird nicht funktionieren, da es einen String mit Platzhaltern, der keine Übereinstimmung gefunden hat, in einen leeren String (Null-Länge) konvertiert, was z cp wird einen Fehler verursachen.
Befinden sich jedoch Tausende oder mehr Dateien im Ordner, sollte auf den Platzhalter-Ansatz ganz verzichtet werden. Die Sache ist die bash erweitert Platzhalter zu einer sehr langen Befehlszeile wie:
cp -a /souce/a /source/b /source/c …… /target
Es gibt eine Begrenzung der Länge der Befehlszeile, die wir mit dem Befehl herausfinden können:
getconf ARG_MAX
Lassen Sie uns die maximale Länge der Befehlszeile in Bytes ermitteln:
2097152
Или:
xargs --show-limits
Wir bekommen so etwas wie:
….
Maximum length of command we could actually use: 2089314
….
Verzichten wir also ganz auf Wildcards.
Lass uns einfach schreiben
cp -a /source /target
Und hier stehen wir vor einer Mehrdeutigkeit des Verhaltens cp. Wenn der Ordner /target nicht existiert, erhalten wir, was wir brauchen.
Wenn der Zielordner jedoch vorhanden ist, werden die Dateien in den Ordner /target/source kopiert.
Wir können den Ordner /target nicht immer im Voraus löschen, da er möglicherweise benötigte Dateien enthält und unser Ziel beispielsweise darin besteht, die Dateien in /target durch Dateien aus /source zu ergänzen.
Wenn der Quell- und der Zielordner denselben Namen hätten, wir würden beispielsweise von /source nach /home/source kopieren, könnten wir den folgenden Befehl verwenden:
cp -a /source /home
Und nach dem Kopieren würden die Dateien in /home/source durch Dateien aus /source ergänzt.
Dies ist ein logisches Problem: Wir können Dateien im Zielverzeichnis hinzufügen, wenn die Ordner den gleichen Namen haben. Wenn sie jedoch unterschiedlich sind, wird der Quellordner im Zielverzeichnis abgelegt. Wie kopiere ich Dateien mit cp ohne Platzhalter von /source nach /target?
Um diese schädliche Einschränkung zu umgehen, verwenden wir eine nicht offensichtliche Lösung:
cp -a /source/. /target
Wer sich mit DOS und Linux auskennt, hat bereits alles verstanden: In jedem Ordner befinden sich 2 unsichtbare Ordner „.“ und „..“, bei denen es sich um Pseudo-Ordner-Links zum aktuellen und höheren Verzeichnis handelt.
Beim Kopieren cp prüft die Existenz und versucht, /target/ zu erstellen.
Ein solches Verzeichnis existiert und es ist /target
Dateien von /source werden korrekt nach /target kopiert.
Hängen Sie es also in einem fetten Rahmen in Erinnerung oder an die Wand:
cp -a /source/. /target
Das Verhalten dieses Befehls ist klar. Alles funktioniert fehlerfrei, egal ob Sie eine Million Dateien haben oder gar keine.
Befund
Wenn Sie kopieren müssen alle Um Dateien von einem Ordner in einen anderen zu verschieben, verwenden wir keine Platzhalter, es ist besser, sie stattdessen zu verwenden cp kombiniert mit einem Punkt am Ende des Quellordners. Dadurch werden alle Dateien kopiert, auch die versteckten, und es wird nicht fehlschlagen, wenn es sich um Millionen oder gar keine Dateien handelt.
Nachwort
vmspike schlug eine Befehlsversion mit einem ähnlichen Ergebnis vor: