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

glob#

Επεκτείνει ένα μοτίβο ονόματος αρχείου σε στιλ κελύφους στη λίστα διαδρομών που ταιριάζουν.

Η glob παίρνει μια συμβολοσειρά μοτίβου όπως "*.c" ή "src/**/*.pm" και επιστρέφει τα ονόματα αρχείων στον δίσκο που ταιριάζουν, στο ίδιο στιλ που θα παρήγαγε ένα κέλυφος Unix. Σε περιβάλλον λίστας επιστρέφει όλα τα ταιριάσματα ταυτόχρονα· σε βαθμωτό περιβάλλον λειτουργεί ως επαναλήπτης με κατάσταση, επιστρέφοντας ένα ταίριασμα ανά κλήση και undef όταν η λίστα εξαντληθεί. Χωρίς όρισμα, η glob επεκτείνει το μοτίβο στο $_.

Σύνοψη#

glob EXPR
glob
<PATTERN>

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

Σε περιβάλλον λίστας, μια (πιθανώς κενή) λίστα ονομάτων αρχείων. Κενή λίστα σημαίνει ότι το μοτίβο δεν ταίριαξε - αυτό δεν είναι σφάλμα και δεν ορίζει το $!.

Σε βαθμωτό περιβάλλον, η glob είναι επαναλήπτης: κάθε κλήση επιστρέφει το επόμενο ταίριασμα, και μετά το τελευταίο ταίριασμα μία ακόμη κλήση επιστρέφει undef. Η κατάσταση του επαναλήπτη είναι ανά σημείο κλήσης, οπότε δύο βρόχοι while (my $f = glob ...) σε διαφορετικές πηγαίες θέσεις δεν παρεμβαίνουν ο ένας στον άλλον.

my @mp3  = glob "*.mp3";            # list context
while (my $f = glob "*.mp3") { }    # scalar context, iterator

Καθολική κατάσταση που επηρεάζει#

  • $_ - διαβάζεται όταν η glob καλείται χωρίς όρισμα.

  • Η ίδια η glob δεν ορίζει το $! σε «μηδέν ταιριάσματα». Η μη ύπαρξη ταιριάσματος αποτελεί νόμιμη κενή λίστα, όχι αποτυχία.

  • Όταν μια έκφραση glob χρησιμοποιείται ως συνθήκη βρόχου while ή for, η Perl εκχωρεί έμμεσα το αποτέλεσμα στο $_ και ελέγχει για οριστική τιμή, όχι για αληθή - έτσι ένα όνομα αρχείου "0" εξακολουθεί να κρατά τον βρόχο σε εκτέλεση.

Η συντόμευση <...> και πώς την επιλέγει η Perl#

Το <*.c> είναι εναλλακτική σύνταξη για το glob("*.c"). Η μορφή με γωνιώδεις αγκύλες μοιράζεται έναν αναγνώστη με το <FH> (readline)· ο αναλυτής αποφασίζει ποια από τις δύο εννοούσατε κατά τη μεταγλώττιση με βάση το τι βρίσκεται ανάμεσα στις γωνιώδεις αγκύλες:

  • Bareword που θα μπορούσε να είναι filehandle (<STDIN>, <FH>) → readline.

  • Ένα απλό βαθμωτό (<$fh>) → readline σε εκείνο το handle.

  • Οτιδήποτε μοιάζει με μοτίβο (<*.c>, <"*.txt">, <${dir}/*>) → glob.

Η ονομασμένη συνάρτηση glob είναι μονοσήμαντη και πιο εύκολα αναζητήσιμη. Προτιμήστε την σε νέο κώδικα· καταφεύγετε στο <...> μόνο για τα πιο σύντομα μοτίβα μιας χρήσης.

my @txt = <"*.txt">;                # same as glob '"*.txt"'
my @txt = glob "*.txt";             # recommended

Οι λευκοί χαρακτήρες διασπούν το μοτίβο#

Η glob διασπά το όρισμά της σε λευκούς χαρακτήρες και χειρίζεται κάθε τμήμα ως ξεχωριστό μοτίβο. Τα αποτελέσματα συνενώνονται:

my @sources = glob "*.c *.h";       # all .c OR .h files
my @all     = glob ".* *";          # every entry in cwd

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

my @spacey = glob '"*e f*"';        # files with "e f" in the name
my @spacey = glob q("*e f*");       # same, q() for clarity
my @spacey = <"*e f*">;             # same via the shortcut form

Παρεμβολή μεταβλητής σε μοτίβο με κενά:

my @spacey = glob "'*${var}e f*'";
my @spacey = glob qq("*${var}e f*");

Αν ο κανόνας διάσπασης σε λευκούς χαρακτήρες σας μπερδεύει, χρησιμoποιήστε απευθείας την bsd_glob του File::Glob - παίρνει το μοτίβο κατά λέξη.

Επέκταση αγκίστρων χωρίς wildcard#

Αν οι μόνοι ειδικοί χαρακτήρες είναι μη κενά άγκιστρα, η glob δεν αγγίζει καθόλου το σύστημα αρχείων: απλώς απαριθμεί το Καρτεσιανό γινόμενο των εναλλακτικών. Αυτό είναι χρήσιμο για παραγωγή συνδυασμών συμβολοσειρών:

my @pairs = glob "{apple,tomato,cherry}={green,yellow,red}";
# apple=green, apple=yellow, apple=red,
# tomato=green, tomato=yellow, tomato=red,
# cherry=green, cherry=yellow, cherry=red

Το File::Glob - η μηχανή και οι επιλογές της#

Η glob υλοποιείται πάνω από την bsd_glob του File::Glob. Η εισαγωγή των ετικετών του αρθρώματος ρυθμίζει τη συμπεριφορά για ολόκληρη τη μονάδα μεταγλώττισης:

  • :nocase - αντιστοίχιση χωρίς διάκριση πεζών-κεφαλαίων.

  • :case - επιβολή αντιστοίχισης με διάκριση πεζών-κεφαλαίων (η προεπιλογή στα περισσότερα συστήματα αρχείων Unix).

  • :globally - αντικαθιστά τον πυρηνικό τελεστή glob με την bsd_glob ώστε κάθε glob(...) και <...> στο αρχείο να υιοθετεί τις επιλογές σας.

use File::Glob qw(:globally :nocase);
my @txt = glob "readme*";           # README, readme.txt, Readme.md

Καλέστε την bsd_glob απευθείας όταν χρειάζεστε σημαίες ανά κλήση ή όταν θέλετε να παρακάμψετε τον κανόνα διάσπασης σε λευκούς χαρακτήρες:

use File::Glob qw(bsd_glob GLOB_TILDE GLOB_BRACE);
my @files = bsd_glob("~/docs/*.{md,rst}", GLOB_TILDE | GLOB_BRACE);

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

Εμφανίστε κάθε αρχείο πηγαίου κώδικα Perl στον τρέχοντα κατάλογο:

my @perl_files = glob "*.pl *.pm";

Επαναλάβετε σε αρχεία MP3 ένα ένα - χρήσιμο όταν η λίστα μπορεί να είναι μεγάλη και δεν θέλετε να την υλοποιήσετε στη μνήμη:

while (my $song = glob "*.mp3") {
    process($song);                 # one filename per iteration
}

Τα αναδρομικά μοτίβα δεν είναι ενσωματωμένα· το * δεν διασχίζει το /. Διατρέξτε το δέντρο με File::Find ή συνδυάστε την glob με ρητή διέλευση:

my @all_c;
for my $dir (glob "src/*") {
    push @all_c, glob "$dir/*.c" if -d $dir;
}

Χρησιμοποιήστε τη μορφή επαναλήπτη σε συνθήκη while - το αποτέλεσμα εκχωρείται στο $_ και ελέγχεται για οριστική τιμή, οπότε ονόματα αρχείων όπως "0" δεν τερματίζουν τον βρόχο:

while (<*.log>) {
    unlink $_ if -M $_ > 30;        # older than 30 days
}

Αντιστοίχιση χωρίς διάκριση πεζών-κεφαλαίων για ολόκληρο αρχείο:

use File::Glob qw(:globally :nocase);
my @readmes = glob "readme*";

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

  • Μηδέν ταιριάσματα: επιστρέφει την κενή λίστα. Καμία προειδοποίηση, κανένα $! δεν ορίζεται. Αν χρειάζεστε «το μοτίβο έπρεπε να ταιριάξει», ελέγξτε ο ίδιος το scalar @files.

  • glob χωρίς όρισμα: χρησιμοποιεί το $_. Μια γυμνή glob μέσα σε while (<>) σπάνια είναι αυτό που θέλετε - το μοτίβο θα είναι οποιαδήποτε γραμμή εισόδου μόλις διαβάσατε.

  • Το while (glob ...) εκχωρεί στο $_ και ελέγχει την οριστική τιμή: ένα όνομα αρχείου "0" είναι ψευδές σύμφωνα με τους συνηθισμένους κανόνες της λογικής τιμής, αλλά ο βρόχος εξακολουθεί να εκτελείται επειδή η συνθήκη είναι defined $_. Αυτό ταυτίζεται με τον κανόνα για την readline στην ίδια θέση.

  • Wildcards και λευκοί χαρακτήρες: ο κανόνας διάσπασης σε λευκούς χαρακτήρες σημαίνει ότι το glob "a b" αναζητά τα a και b ως δύο μοτίβα, όχι την κυριολεκτική συμβολοσειρά "a b". Χρησιμοποιήστε εσωτερικά εισαγωγικά ή την bsd_glob όταν το όνομα αρχείου νόμιμα περιέχει κενά.

  • Κρυφά αρχεία: ένα προπορευόμενο . δεν ταιριάζει με το * - χρειάζεστε ρητό τμήμα .* (glob ".* *") για να συμπεριλάβετε dotfiles. Αυτό ταυτίζεται με τη σημασιολογία glob κελύφους, όχι τη σημασιολογία regex.

  • Επέκταση tilde: το glob "~/foo" λειτουργεί επειδή το File::Glob επεκτείνει το ~ εξ ορισμού. Καλώντας το μέσω της bsd_glob χωρίς το GLOB_TILDE στις σημαίες, λαμβάνετε ένα κυριολεκτικό ~.

  • Παρεμβολή μέσα σε <...>: το <$var/*.c> παρεμβάλλει το $var σε χρόνο εκτέλεσης. Η χρήση της μορφής με γωνιώδεις αγκύλες δεν σας απαλλάσσει από τους συνηθισμένους κανόνες διπλών εισαγωγικών της Perl.

  • Ασάφεια γωνιωδών αγκυλών: το <FOO> είναι ανάγνωση handle, το <$foo> είναι ανάγνωση handle, το <*.c> είναι glob. Το <$foo/*.c> - ένα βαθμωτό συν χαρακτήρες μοτίβου - είναι glob. Η επίλυση γίνεται κατά τη μεταγλώττιση· οι αλλαγές στο $foo σε χρόνο εκτέλεσης δεν την επανακρίνουν.

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

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

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

  • opendir - ανοίγει ένα handle καταλόγου για πιο λεπτομερή διέλευση από αυτή που σας δίνει η αντιστοίχιση μοτίβων

  • readdir - διαβάζει εγγραφές από ένα handle καταλόγου μία τη φορά· συνδυάστε με opendir όταν χρειάζεστε κάθε εγγραφή (περιλαμβανομένων εκείνων που η glob κρύβει, όπως τα dotfiles) ή πληροφορίες τύπου αρχείου

  • readline - η άλλη σημασία του <...>· μοιράζεται τη σύνταξη γωνιωδών αγκυλών αλλά διαβάζει γραμμές από filehandle

  • File::Glob - η υποκείμενη υλοποίηση· χρησιμοποιήστε την bsd_glob απευθείας για σημαίες ανά κλήση και για να παρακάμψετε τον κανόνα διάσπασης σε λευκούς χαρακτήρες

  • $_ - προεπιλεγμένη πηγή μοτίβου για γυμνή glob, και η μεταβλητή στην οποία εκχωρείται έμμεσα όταν η glob χρησιμοποιείται ως συνθήκη βρόχου while/for