exec#
Εγκατάλειψη αυτού του προγράμματος και εκτέλεση άλλου στην ίδια διεργασία.
Η exec αντικαθιστά την τρέχουσα εικόνα διεργασίας με ένα άλλο πρόγραμμα. Δεν επιστρέφει σε επιτυχία - η εκτέλεση συνεχίζεται στο νέο πρόγραμμα, με το ίδιο id διεργασίας, ανοιχτά filehandles υποκείμενα στη σημαία close-on-exec, και όποιο περιβάλλον ίσχυε. Επιστρέφει ψευδές (και θέτει την $!) μόνο όταν ο στόχος δεν μπόρεσε να εκτοξευθεί και εκτελέστηκε άμεσα παρά μέσω του κελύφους. Καταφύγετε στην system όταν θέλετε το παιδί να εκτελεστεί και ο έλεγχος να επιστρέψει.
Σύνοψη#
exec LIST
exec PROGRAM LIST
exec { PROGRAM } LIST
Τι επιστρέφεται#
Τίποτα, σε επιτυχία - η διεργασία έχει αντικατασταθεί και αυτός ο διερμηνέας Perl έχει χαθεί. Σε αποτυχία η exec επιστρέφει ψευδές και αφήνει την αιτία στην $!. Η αποτυχία είναι ανιχνεύσιμη μόνο για τη διαδρομή άμεσου exec· όταν το όρισμα παραδίδεται στο κέλυφος, ένα πρόγραμμα που λείπει αναφέρεται από το ίδιο το κέλυφος και η exec εξακολουθεί να θεωρείται ότι «πέτυχε» στην εκτόξευση του /bin/sh.
exec '/usr/bin/vi', $file
or die "couldn't exec vi: $!";
Επειδή η exec κανονικά δεν επιστρέφει, η Perl εκπέμπει προειδοποίηση υπό use warnings αν εμφανίζεται σε περιβάλλον κενού ακολουθούμενη από άλλη δήλωση που δεν είναι die, warn ή exit. Είτε χειριστείτε την αποτυχία ενσωματωμένα με or die, είτε τυλίξτε την κλήση σε μπλοκ για να σιωπήσετε την προειδοποίηση:
exec('foo') or die "couldn't exec foo: $!";
{ exec('foo') }; die "couldn't exec foo: $!";
Κέλυφος ή όχι κέλυφος - ο κανόνας της μονής συμβολοσειράς#
Η exec επιλέγει μεταξύ δύο μηχανισμών εκτόξευσης με βάση τη μορφή της LIST:
Δύο ή περισσότερα ορίσματα → η
execκαλεί τηνexecvp(3)άμεσα με τη λίστα. Δεν εμπλέκεται κέλυφος, καμία ερμηνεία μετα-χαρακτήρων, κανένας διαχωρισμός σε λέξεις.Ακριβώς ένα όρισμα → η
execσαρώνει αυτή τη μοναδική συμβολοσειρά για μετα-χαρακτήρες κελύφους. Αν βρεθούν, ολόκληρη η συμβολοσειρά περνά στο/bin/sh -cγια ανάλυση. Αν δεν βρεθούν, η συμβολοσειρά διαχωρίζεται σε λευκούς χαρακτήρες και παραδίδεται απευθείας στηνexecvp.
Ο κανόνας έχει σημασία τόσο για ορθότητα όσο και για ασφάλεια. Μια συμβολοσειρά ενός ορίσματος που περιέχει κενό αλλά καθόλου μετα-χαρακτήρες διαχωρίζεται σε λέξεις και εκτελείται άμεσα - κάτι που συχνά είναι αυτό που θέλετε. Μια συμβολοσειρά ενός ορίσματος που περιέχει |, >, $, ;, χαρακτήρες glob ή εισαγωγικά περνά μέσω του κελύφους, και το κέλυφος θα επεκτείνει ευχαρίστως μπαλαντέρ, θα ερμηνεύσει μεταβλητές και θα διαχωρίσει με βάση το $IFS.
exec '/bin/echo', 'Your arguments are:', @ARGV; # direct execvp
exec "sort $outfile | uniq"; # pipeline → shell
exec "ls /tmp"; # no metachars → split + execvp
Για να εξαναγκάσετε τη διαδρομή χωρίς κέλυφος ακόμη και με μία λογική εντολή, χρησιμοποιήστε τη μορφή έμμεσου αντικειμένου που περιγράφεται στη συνέχεια.
Μορφή έμμεσου αντικειμένου - ορισμός του argv[0], παράκαμψη του κελύφους#
Η τοποθέτηση ενός μπλοκ ή βαθμωτού πριν την LIST (χωρίς κόμμα) λέει στην exec δύο πράγματα ταυτόχρονα: εκτέλεσε αυτό το πρόγραμμα, και πέρασε εκείνα τα ορίσματα ως argv. Το πρώτο στοιχείο της LIST γίνεται το argv[0] - το όνομα που βλέπει το παιδί για τον εαυτό του - το οποίο δεν χρειάζεται να ταιριάζει με τη διαδρομή του προγράμματος.
exec { '/bin/echo' } 'echo', 'hi'; # argv[0] is "echo"
my $shell = '/bin/csh';
exec $shell '-sh'; # login-shell convention: argv[0] = "-sh"
exec { '/bin/csh' } '-sh'; # same, more direct
Η μορφή έμμεσου αντικειμένου αντιμετωπίζει πάντα την LIST ως λίστα πολλαπλών τιμών, ακόμη και αν έχει ένα μόνο στοιχείο. Αυτό απενεργοποιεί εντελώς τη σάρωση μετα-χαρακτήρων:
my @args = ('echo surprise');
exec @args; # one element → shell scan → /bin/sh -c 'echo surprise'
exec { $args[0] } @args; # always direct execvp, "echo surprise" is argv[0]
Στη δεύτερη μορφή δεν υπάρχει πρόγραμμα στον δίσκο κυριολεκτικά ονομαζόμενο echo surprise, οπότε η execvp αποτυγχάνει, η exec επιστρέφει ψευδές, και η $! κρατά την αιτία. Αυτή είναι η ασφαλής συμπεριφορά: ο καλών μπορεί να αποφασίσει τι θα κάνει, αντί να εκτελεί το κέλυφος κάτι απροσδόκητο.
Καθολική κατάσταση που επηρεάζει#
$!- τίθεται σε αποτυχία στοerrnoαπό την υποκείμενη κλήσηexecvp(3). Έχει νόημα μόνο όταν ηexecπράγματι επιστρέφει.$?- μένει αμετάβλητη από την ίδια τηνexec, αλλά μια αποτυχημένη προσπάθεια μέσω κελύφους μπορεί να αφήσει την κατάσταση εξόδου του κελύφους ορατή σε μια περικλείουσαsystem.Τα ανοιχτά filehandles της διεργασίας, το περιβάλλον (
%ENV), ο τρέχων κατάλογος εργασίας, ηumask, οι διαθέσεις σημάτων και τα όρια πόρων μεταφέρονται όλα στο πρόγραμμα αντικατάστασης - ηexecαντικαθιστά το πρόγραμμα, όχι τη διεργασία.
Παραδείγματα#
Εκτέλεση προγράμματος με ρητή λίστα ορισμάτων, άμεση execvp:
exec '/usr/bin/git', 'status', '--short'
or die "exec git: $!";
Σκόπιμη παράδοση γραμμής εντολής στο κέλυφος, με χρήση μετα-χαρακτήρων:
exec "find . -name '*.tmp' -print0 | xargs -0 rm"
or die "exec pipeline: $!";
Ορισμός διακριτού argv[0] ώστε η γραμμή ps του παιδιού να αναγνωρίζει τον ρόλο του:
exec { '/usr/local/bin/worker' } 'worker[queue=email]', @flags
or die "exec worker: $!";
Fork-and-exec - το κλασικό μοτίβο για εκτόξευση παιδιού χωρίς αντικατάσταση του εαυτού σας:
my $pid = fork // die "fork: $!";
if ($pid == 0) {
exec '/usr/bin/gzip', '-9', $file
or die "exec gzip: $!";
}
waitpid $pid, 0;
Εγγύηση της διαδρομής χωρίς κέλυφος όταν η λίστα ορισμάτων συναρμολογήθηκε από δεδομένα:
my @cmd = build_command(); # may contain one element or many
exec { $cmd[0] } @cmd
or die "exec $cmd[0]: $!";
Οριακές περιπτώσεις#
Δεν επιστρέφει ποτέ σε επιτυχία. Οποιοσδήποτε κώδικας μετά από σκέτη
execείναι προσβάσιμος μόνο σε αποτυχία. Υπόuse warnings, μια επόμενη δήλωση εκτός τωνdie,warnήexitπυροδοτεί προειδοποίηση - υπαινιγμός της Perl ότι πιθανώς εννοούσατεsystem.Παγίδα μονού ορίσματος. Η
exec $cmdόπου το$cmdπροήλθε από είσοδο χρήστη αποτελεί διάνυσμα έγχυσης κελύφους αν το$cmdπεριέχει μετα-χαρακτήρες. Χρησιμοποιήστε τη μορφή έμμεσου αντικειμένου ή περάστε μια προ-διαχωρισμένη λίστα.Ενταμίευση εξόδου. Η Perl προσπαθεί να εκκενώσει handles ανοιγμένα για έξοδο πριν παραδώσει τον έλεγχο στο νέο πρόγραμμα, αλλά αυτό δεν εξασφαλίζεται σε κάθε πλατφόρμα. Αν έχετε εκκρεμή έξοδο σε μη εκκενωμένο handle, θέστε την
$|στο επιλεγμένο handle - ή καλέστε τη μέθοδοautoflushσε κάθεIO::Handle- πριν τηνexec.Μπλοκ
ENDκαιDESTROY. Ηexecδεν εκτελεί μπλοκEND, και δεν καλείDESTROYστα αντικείμενά σας. Η εικόνα διεργασίας αντικαθίσταται· καθαρισμός σε επίπεδο Perl δεν συμβαίνει ποτέ. Οτιδήποτε χρειάζεται καθαρό τερματισμό (προσωρινά αρχεία, αφαίρεση lockfile, εκκένωση καταγραφών) πρέπει να συμβεί πριν τηνexec.Close-on-exec. Τα filehandles με τη σημαία
FD_CLOEXECορισμένη κλείνουν από τον πυρήνα κατά τη διάρκεια τηςexecvp· τα υπόλοιπα μένουν ανοιχτά. Ελέγξτε το μεfcntlή με το κατώφλι filehandle συστήματος$^F.Η αποτυχία μέσω κελύφους είναι αόρατη. Όταν η
execδρομολογείται μέσω/bin/sh -c, ένα στοχοπρόγραμμα που λείπει αναφέρεται από το κέλυφος και η ίδια ηexecέχει ήδη αντικατασταθεί από το/bin/sh. Ο κώδικας Perl σας δεν θα δει επιστροφή αποτυχίας.Λίστα ενός ορίσματος χωρίς μετα-χαρακτήρες εξακολουθεί να διαχωρίζεται σε λευκούς χαρακτήρες και να περνά στην
execvp- οπότε ηexec "ls /tmp"είναι άμεσο exec του/bin/lsμε ένα όρισμα, όχι κλήση κελύφους.Κενή
LISTείναι σφάλμα κατά την εκτέλεση· δεν υπάρχει πρόγραμμα προς εκτέλεση.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
system- εκτέλεση προγράμματος και αναμονή του· σχεδόν σίγουρα αυτό που θέλατε αν ηexecβρίσκεται στην κορυφή του αρχείουfork- συνδυασμός με τηνexecστο παιδί για εκτόξευση προγράμματος χωρίς αντικατάσταση του γονέαwait- συλλογή ενός παιδιού που παράγεται απόfork+execdie- τερματισμός του τρέχοντος προγράμματος με σφάλμα· ο ιδιωματικός σύντροφος τουexec ... or die$!- λόγος σφάλματος που τίθεται όταν αποτυγχάνει το άμεσο exec$|- σημαία αυτόματης εκκένωσης· θέστε πριν τηνexecώστε καμία ενταμιευμένη έξοδος να μη χαθεί όταν αντικαθίσταται η εικόνα διεργασίας