Εντολή cp: αντιγράψτε τους φακέλους αρχείων σωστά στο *nix

Εντολή cp: αντιγράψτε τους φακέλους αρχείων σωστά στο *nix

Αυτό το άρθρο θα αποκαλύψει ορισμένα μη προφανή πράγματα που σχετίζονται με τη χρήση του wildcards κατά την αντιγραφή, διφορούμενη συμπεριφορά εντολών cp κατά την αντιγραφή, καθώς και μεθόδους που σας επιτρέπουν να αντιγράψετε σωστά έναν τεράστιο αριθμό αρχείων χωρίς παράβλεψη ή συντριβή.

Ας υποθέσουμε ότι πρέπει να αντιγράψουμε τα πάντα από το φάκελο /source στον φάκελο /target.

Το πρώτο πράγμα που μου έρχεται στο μυαλό είναι:

cp /source/* /target

Ας διορθώσουμε αμέσως αυτήν την εντολή σε:

cp -a /source/* /target

Κλειδί -a θα προσθέσει αντιγραφή όλων των χαρακτηριστικών, δικαιωμάτων και θα προσθέσει αναδρομή. Όταν δεν απαιτείται ακριβής αναπαραγωγή των δικαιωμάτων, αρκεί ένα κλειδί -r.

Μετά την αντιγραφή, θα διαπιστώσουμε ότι δεν αντιγράφηκαν όλα τα αρχεία - αρχεία που ξεκινούν με μια τελεία όπως:

.profile
.local
.mc

και τα παρόμοια.

Γιατί συνέβη αυτό;

Επειδή οι χαρακτήρες μπαλαντέρ επεξεργάζονται από το κέλυφος (bash σε μια τυπική περίπτωση). Από προεπιλογή, το bash θα αγνοήσει όλα τα αρχεία που ξεκινούν με τελείες, καθώς τα αντιμετωπίζει ως κρυφά. Για να αποφύγουμε αυτή τη συμπεριφορά θα πρέπει να αλλάξουμε συμπεριφορά bash χρησιμοποιώντας την εντολή:

shopt -s dotglob

Για να διασφαλίσετε ότι αυτή η αλλαγή συμπεριφοράς θα συνεχιστεί μετά από μια επανεκκίνηση, μπορείτε να δημιουργήσετε ένα αρχείο wildcard.sh με αυτήν την εντολή στον φάκελο /etc/profile.d (Ίσως η διανομή σας έχει διαφορετικό φάκελο).

Και αν δεν υπάρχουν αρχεία στον κατάλογο προέλευσης, τότε το κέλυφος δεν θα μπορεί να αντικαταστήσει τίποτα στη θέση του αστερίσκου και η αντιγραφή θα αποτύχει επίσης με ένα σφάλμα. Υπάρχουν επιλογές ενάντια σε αυτήν την κατάσταση failglob и nullglob. Θα χρειαστεί να ρυθμίσουμε failglob, το οποίο θα αποτρέψει την εκτέλεση της εντολής. nullglob δεν θα λειτουργήσει, καθώς μετατρέπει μια συμβολοσειρά με χαρακτήρες μπαλαντέρ που δεν βρήκαν ταίριασμα σε μια κενή συμβολοσειρά (μηδενικό μήκος), η οποία για cp θα προκαλέσει σφάλμα.

Ωστόσο, εάν υπάρχουν χιλιάδες αρχεία ή περισσότερα στον φάκελο, τότε η προσέγγιση με χαρακτήρες μπαλαντέρ θα πρέπει να εγκαταλειφθεί εντελώς. Γεγονός είναι ότι bash επεκτείνει τους χαρακτήρες μπαλαντέρ σε μια πολύ μεγάλη γραμμή εντολών όπως:

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

Υπάρχει ένα όριο στο μήκος της γραμμής εντολών, το οποίο μπορούμε να μάθουμε χρησιμοποιώντας την εντολή:

getconf ARG_MAX

Ας πάρουμε το μέγιστο μήκος της γραμμής εντολών σε byte:

2097152

Ή:

xargs --show-limits

Παίρνουμε κάτι σαν:

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

Λοιπόν, ας κάνουμε χωρίς χαρακτήρες μπαλαντέρ εντελώς.

Ας γράψουμε

cp -a /source /target

Και εδώ ερχόμαστε αντιμέτωποι με ασάφεια συμπεριφοράς cp. Εάν ο φάκελος /target δεν υπάρχει, τότε θα λάβουμε αυτό που χρειαζόμαστε.

Ωστόσο, εάν υπάρχει ο φάκελος προορισμού, τότε τα αρχεία θα αντιγραφούν στο φάκελο /target/source.

Δεν μπορούμε πάντα να διαγράψουμε τον φάκελο /target εκ των προτέρων, καθώς μπορεί να περιέχει αρχεία που χρειαζόμαστε και στόχος μας, για παράδειγμα, είναι να συμπληρώσουμε τα αρχεία στο /target με αρχεία από το /source.

Εάν οι φάκελοι προέλευσης και προορισμού είχαν το ίδιο όνομα, για παράδειγμα, αντιγράφαμε από το /source στο /home/source, τότε θα μπορούσαμε να χρησιμοποιήσουμε την εντολή:

cp -a /source /home

Και μετά την αντιγραφή, τα αρχεία στο /home/source θα συμπληρωθούν με αρχεία από το /source.

Αυτό είναι ένα λογικό πρόβλημα: μπορούμε να προσθέσουμε αρχεία στον κατάλογο προορισμού εάν οι φάκελοι έχουν το ίδιο όνομα, αλλά εάν είναι διαφορετικοί, τότε ο φάκελος προέλευσης θα τοποθετηθεί μέσα στον προορισμό. Πώς να αντιγράψετε αρχεία από το /source στο /target χρησιμοποιώντας cp χωρίς χαρακτήρες μπαλαντέρ;

Για να ξεπεράσουμε αυτόν τον επιβλαβή περιορισμό, χρησιμοποιούμε μια μη προφανή λύση:

cp -a /source/. /target

Όσοι είναι εξοικειωμένοι με το DOS και το Linux έχουν ήδη καταλάβει τα πάντα: μέσα σε κάθε φάκελο υπάρχουν 2 αόρατοι φάκελοι "." και «..», που είναι σύνδεσμοι ψευδοφακέλων προς τους τρέχοντες και ανώτερους καταλόγους.

  • Κατά την αντιγραφή cp ελέγχει την ύπαρξη και προσπαθεί να δημιουργήσει το /target/.
  • Ένας τέτοιος κατάλογος υπάρχει και είναι /target
  • Τα αρχεία από το /source αντιγράφονται στο /target σωστά.

Κρεμάστε το λοιπόν σε ένα έντονο πλαίσιο στη μνήμη σας ή στον τοίχο:

cp -a /source/. /target

Η συμπεριφορά αυτής της εντολής είναι ξεκάθαρη. Όλα θα λειτουργούν χωρίς σφάλματα, ανεξάρτητα από το αν έχετε ένα εκατομμύριο αρχεία ή κανένα.

Ευρήματα

Εάν χρειάζεται να αντιγράψετε όλα αρχεία από τον ένα φάκελο στον άλλο, δεν χρησιμοποιούμε χαρακτήρες μπαλαντέρ, είναι καλύτερα να τους χρησιμοποιήσουμε cp σε συνδυασμό με μια τελεία στο τέλος του φακέλου προέλευσης. Αυτό θα αντιγράψει όλα τα αρχεία, συμπεριλαμβανομένων των κρυφών, και δεν θα αποτύχει με εκατομμύρια αρχεία ή καθόλου αρχεία.

Επίλογος

vmspike πρότεινε μια έκδοση εντολών με παρόμοιο αποτέλεσμα:

cp -a -T /source /target

Oz_Alex

cp -aT /source /target

ΣΗΜΕΙΩΣΗ: θήκη επιστολών T έχει το νόημα. Αν το μπερδέψετε, θα πάρετε εντελώς σκουπίδια: η κατεύθυνση αντιγραφής θα αλλάξει.
Ευχαριστώ:

  • Εταιρείες RUVDS.COM για υποστήριξη και την ευκαιρία να δημοσιεύσετε στο ιστολόγιό σας στο Habré.
  • Ανά εικόνα Τριπλή έννοια. Η εικόνα είναι πολύ μεγάλη και λεπτομερής, μπορεί να ανοίξει σε ξεχωριστό παράθυρο.

PS Στείλτε τυχόν σφάλματα που παρατηρήσετε σε προσωπικό μήνυμα. Αυξάνω το κάρμα μου για αυτό.

Εντολή cp: αντιγράψτε τους φακέλους αρχείων σωστά στο *nix

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο