Filehandles, αρχεία, κατάλογοι

rename#

Αλλάζει το όνομα ενός αρχείου.

Η rename ζητά από το λειτουργικό σύστημα να επαναδέσει τη διαδρομή OLDNAME στο NEWNAME. Σε ένα σύστημα αρχείων POSIX αυτή είναι μια μοναδική ατομική λειτουργία καταλόγου: αφού επιστρέψει με επιτυχία η κλήση, το NEWNAME παραπέμπει στο αρχείο που πριν ήταν προσπελάσιμο ως OLDNAME, και το OLDNAME δεν υπάρχει πλέον. Είναι η ίδια πρωτογενής λειτουργία που χρησιμοποιεί η εντολή κελύφους mv όταν πηγή και προορισμός βρίσκονται στο ίδιο σύστημα αρχείων.

Σύνοψη#

rename OLDNAME, NEWNAME

Τι επιστρέφεται#

1 σε επιτυχία, 0 σε αποτυχία με την $! ορισμένη στο errno που επέστρεψε η υποκείμενη κλήση συστήματος rename(2). Ελέγχετε πάντα την τιμή επιστροφής - μια σιωπηρή αποτυχία εδώ αφήνει το σύστημα αρχείων σε κατάσταση που το υπόλοιπο πρόγραμμα δεν αναμένει:

rename $tmp, $final
    or die "rename $tmp -> $final failed: $!";

Ατομικότητα και ο κανόνας του ίδιου συστήματος αρχείων#

Η rename είναι ατομική μόνο όταν τα OLDNAME και NEWNAME επιλύονται στο ίδιο σύστημα αρχείων. Μέσα σε αυτό το σύστημα αρχείων, καμία ενδιάμεση κατάσταση δεν είναι ποτέ ορατή: μια άλλη διεργασία που διαβάζει τον κατάλογο βλέπει είτε το παλιό όνομα είτε το νέο, ποτέ και τα δύο και ποτέ κανένα από τα δύο. Γι” αυτό η κανονική ιδιωματική φράση «γράψε ένα αρχείο με ασφάλεια» γράφει σε προσωρινό αρχείο στον ίδιο κατάλογο και μετά το μετονομάζει στη θέση του:

open my $fh, ">", "$path.tmp" or die "open: $!";
print $fh $data;
close $fh or die "close: $!";
rename "$path.tmp", $path
    or die "rename: $!";

Διασυστηματικά η κλήση αποτυγχάνει με EXDEV ("Invalid cross-device link") και τίποτα δεν μετακινείται. Η εντολή συστήματος mv καλύπτει αυτό υποχωρώντας σε copy-then-unlink· η rename όχι. Για φορητή διασυσκευική μετακίνηση, χρησιμοποιήστε move από το File::Copy, που εκτελεί η ίδια την υποχώρηση αντιγραφή-και-unlink.

Παραδείγματα#

Μετονομασία μέσα σε κατάλογο:

rename "draft.txt", "final.txt"
    or die "rename: $!";

Ατομική αντικατάσταση αρχείου - γράψτε σε αδελφικό προσωρινό αρχείο και κατόπιν μετονομάστε:

my $tmp = "$path.$$.tmp";
open my $fh, ">", $tmp or die "open $tmp: $!";
print $fh $content;
close  $fh             or die "close $tmp: $!";
rename $tmp, $path     or die "rename $tmp -> $path: $!";

Ανιχνεύστε την διασυσκευική περίπτωση και υποχωρήστε σε File::Copy::move:

use Errno qw(EXDEV);
use File::Copy qw(move);

unless (rename $src, $dst) {
    if ($! == EXDEV) {
        move($src, $dst) or die "move: $!";
    }
    else {
        die "rename: $!";
    }
}

Μετονομάστε κάθε .log σε έναν κατάλογο σε .log.old:

for my $f (glob "*.log") {
    rename $f, "$f.old"
        or warn "rename $f: $!";
}

Οριακές περιπτώσεις#

  • Το NEWNAME υπάρχει ήδη: συντρίβεται σιωπηρά. Η rename δεν ρωτά, δεν προειδοποιεί και δεν αρνείται. Αν ο στόχος είναι κανονικό αρχείο, αποσυνδέεται ως μέρος της λειτουργίας· αν είναι κατάλογος η κλήση αποτυγχάνει με ENOTDIR ή EISDIR ανάλογα με το αν το OLDNAME είναι κατάλογος. Για να πάρετε σημασιολογία «αρνήσου να επικαλύψεις», ελέγξτε πρώτα με -e (και αποδεχθείτε ότι ο έλεγχος είναι επιρρεπής σε κούρσα - δεν υπάρχει φορητή renameat2(RENAME_NOREPLACE) εκτιθέμενη μέσω της ίδιας της rename).

  • Διασυστηματική (EXDEV): αποτυγχάνει, αφήνει αμφότερες τις διαδρομές άθικτες. Χρησιμοποιήστε File::Copy::move όταν ο προορισμός μπορεί να βρίσκεται σε άλλο mount.

  • Ανοιχτά filehandles: στο Linux (και στο POSIX γενικά) η μετονομασία αρχείου που είναι τη στιγμή εκείνη ανοιχτό είναι εντάξει. Το ανοιχτό filehandle εξακολουθεί να δείχνει στο ίδιο inode· οι επόμενες αναγνώσεις και εγγραφές μέσω του continue να λειτουργούν. Νέα ανοίγματα χρησιμοποιούν το νέο όνομα.

  • Κατάλογοι: η μετονομασία καταλόγου επιτρέπεται, αλλά μόνο όταν το NEWNAME δεν υπάρχει ή είναι κενός κατάλογος. Η μετακίνηση καταλόγου σε υποκατάλογο του εαυτού του αποτυγχάνει με EINVAL.

  • Δικαιώματα: η rename χρειάζεται δικαίωμα εγγραφής + εκτέλεσης τόσο στον γονικό κατάλογο της πηγής όσο και του προορισμού, όχι στο ίδιο το αρχείο. Η αποτυχία εμφανίζεται ως EACCES ή EPERM.

  • Κατάλογοι με sticky bit (/tmp): αν ο γονικός του προορισμού έχει το sticky bit ορισμένο, πρέπει να είστε ιδιοκτήτης είτε του αρχείου πηγής είτε του γονικού του προορισμού· αλλιώς η κλήση αποτυγχάνει με EPERM ακόμη και όταν ο κατάλογος είναι εγγράψιμος από όλους.

  • Συμβολικοί σύνδεσμοι: η rename δρα στον ίδιο τον σύνδεσμο, ποτέ στον στόχο του. Η rename "link", "other" μετονομάζει τον symlink· το αρχείο στο οποίο δείχνει μένει ανέγγιχτο.

  • Τελική πλαγιοκάθετος στο OLDNAME: πολλοί πυρήνες το απορρίπτουν με ENOTDIR όταν η πηγή δεν είναι κατάλογος. Μη βασίζεστε στο ότι η συμπεριφορά της τελικής πλαγιοκαθέτου είναι φορητή.

  • Μετονομασία ίδιας διαδρομής: η rename $p, $p πετυχαίνει και δεν κάνει τίποτα (συμπεριφορά που απαιτεί το POSIX) εφόσον το $p υπάρχει.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • unlink - αφαιρεί αρχείο κατ” όνομα· το αντίστοιχο αποδόμησης για τη δημιουργία ενός μέσω rename στη θέση του

  • link - δημιουργεί επιπλέον όνομα hard-link για ένα υπάρχον αρχείο χωρίς να αφαιρέσει το αρχικό

  • symlink - δημιουργεί συμβολικό σύνδεσμο· σημειώστε ότι η rename σε symlink μετακινεί τον σύνδεσμο, όχι τον στόχο του

  • File::Copy - φορητές move και copy που χειρίζονται τη διασυστηματική (EXDEV) περίπτωση που η rename δεν μπορεί

  • $! - errno μετά από αποτυχημένη rename· συγκρίνετε με σταθερές από το Errno (EXDEV, EACCES, ENOENT, …)