Befehl Cp: Kopieren von Dateiordnern nach * nix korrekt



In diesem Artikel werden einige nicht offensichtliche Aspekte im Zusammenhang mit der Verwendung von Platzhaltern beim Kopieren, dem mehrdeutigen Verhalten des Befehls cp beim Kopieren sowie Möglichkeiten zum korrekten Kopieren einer großen Anzahl von Dateien ohne Auslassungen und Abstürze erläutert.

Angenommen, 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 Sie diesen Befehl sofort auf:

 cp -a /source/* /target 

Der Schalter -a fügt eine Kopie aller Attribute, Rechte und Rekursionen hinzu. Wenn keine genaue Wiedergabe von Rechten erforderlich ist, reicht der Schalter -r aus.

Nach dem Kopieren stellen wir fest, dass nicht alle Dateien kopiert wurden - Dateien ab einem Punkt wie wurden ignoriert:

.profile
.local
.mc

und dergleichen.

Warum ist das passiert?

Weil Platzhalter die Shell verarbeiten ( bash in einem typischen Fall). Standardmäßig ignoriert bash alle Dateien, die mit Punkten beginnen, da sie als versteckt behandelt werden. Um dieses Verhalten zu vermeiden, müssen wir das Verhalten von bash mit dem folgenden Befehl ändern:

 shopt -s dotglob 

Um diese Verhaltensänderung nach einem Neustart zu speichern, können Sie die Datei wildcard.sh mit diesem Befehl im Ordner /etc/profile.d (Ihre Distribution hat möglicherweise einen anderen Ordner).

Wenn sich keine Dateien im Quellverzeichnis befinden, kann die Shell das Sternchen nicht ersetzen, und das Kopieren schlägt ebenfalls fehl. In dieser Situation gibt es failglob und nullglob . Wir müssen failglob , um zu verhindern, dass der Befehl ausgeführt wird. nullglob nicht, da es eine Zeichenfolge mit Platzhaltern, die keine Übereinstimmungen gefunden haben, in eine leere Zeichenfolge (mit der Länge Null) konvertiert, was einen Fehler für cp .

Wenn sich jedoch Tausende von Dateien und mehr im Ordner befinden, sollte der Ansatz mit Platzhaltern ganz aufgegeben werden. Die Sache ist, bash erweitert Platzhalter in eine sehr lange Befehlszeile wie:

 cp -a /souce/a /source/b /source/c …… /target 

Die Länge der Befehlszeile ist begrenzt, was wir mit dem Befehl herausfinden können:

 getconf ARG_MAX 

Ermitteln Sie die maximale Länge der Befehlszeile in Byte:

 2097152 

Oder:

 xargs --show-limits 

Wir bekommen so etwas wie:

 …. Maximum length of command we could actually use: 2089314 …. 

Lassen Sie uns also überhaupt auf Platzhalter verzichten.

Lass uns einfach schreiben

 cp -a /source /target 

Und hier werden wir auf die Mehrdeutigkeit des cp Verhaltens stoßen. Wenn der Ordner / target nicht vorhanden ist, erhalten wir das, was wir benötigen.

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 die benötigten Dateien enthält und unser Ziel beispielsweise darin besteht, / target Dateien mit Dateien aus / source hinzuzufügen.

Wenn der Quell- und der Zielordner beispielsweise auf dieselbe Weise benannt würden, würden wir von / source nach / home / source kopieren, dann könnten wir den folgenden Befehl verwenden:

 cp -a /source /home 

Und nach dem Kopieren der Dateien in / home / source wären die ergänzten Dateien aus / source.

Dies ist die logische Aufgabe: Wir können Dateien zum Zielverzeichnis hinzufügen. Wenn die Ordner den gleichen Namen haben, sich jedoch unterscheiden, wird der Quellordner im Empfänger abgelegt. Wie kopiere ich Dateien von / source nach / target mit cp ohne Platzhalter?

Um diese schädliche Einschränkung zu umgehen, verwenden wir eine nicht offensichtliche Lösung:

 cp -a /source/. /target 

Diejenigen, die mit DOS und Linux gut vertraut sind, haben bereits alles verstanden: In jedem Ordner befinden sich 2 unsichtbare Ordner "." und "..", die Pseudoordner-Links zu den aktuellen und höheren Verzeichnissen sind.

  • Beim Kopieren prüft cp Existenz und versucht, / target / zu erstellen.
  • Ein solches Verzeichnis existiert und es ist / target
  • Dateien von / source wurden korrekt nach / target kopiert.

Also hängen wir in einem kühnen Rahmen in unserer Erinnerung oder an der Wand:

 cp -a /source/. /target 

Das Verhalten dieses Befehls ist eindeutig. Alles funktioniert fehlerfrei, unabhängig davon, ob Sie eine Million oder gar keine Dateien haben.

Schlussfolgerungen


Wenn Sie alle Dateien von einem Ordner in einen anderen kopieren möchten, verwenden wir keine Platzhalter. Stattdessen ist es besser, cp in Kombination mit einem Punkt am Ende des Quellordners zu verwenden. Dies kopiert alle Dateien, einschließlich versteckter, und schlägt nicht mit Millionen von Dateien oder dem völligen Fehlen von Dateien fehl.

Nachwort


vmspike schlug eine ähnliche Variante des Befehls vor:

 cp -a -T /source /target 

Oz_Alex
 cp -aT /source /target 

ACHTUNG: Der Fall des Buchstabens T wichtig. Wenn Sie es verwechseln, erhalten Sie den kompletten Müll: Die Kopierrichtung ändert sich.

Danksagung:

  • RUVDS.COM Unternehmen für seine Unterstützung und die Möglichkeit, auf seinem Blog auf Habré zu veröffentlichen.
  • Pro Bild TripletConcept . Das Bild ist sehr groß und detailliert, Sie können es in einem separaten Fenster öffnen.

PS Direkte Fehler, die Sie in PM bemerken. Ich erhöhe das Karma dafür.



Source: https://habr.com/ru/post/de471092/


All Articles