exit#
Τερματισμός του προγράμματος με τιμή κατάστασης.
Η exit αποτιμά την EXPR, εκτελεί τον καθαρισμό τέλους προγράμματος (μπλοκ END και καταστροφείς αντικειμένων), και έπειτα εξέρχεται από τη διεργασία με αυτή την τιμή ως κωδικό κατάστασης. Χωρίς όρισμα εξέρχεται με 0 - επιτυχία.
Σύνοψη#
exit EXPR
exit
Τι επιστρέφεται#
Τίποτα. Η exit δεν επιστρέφει στον καλούντα της. Είναι δήλωση με την έννοια της ροής ελέγχου παρότι η γραμματική επιτρέπει να γραφεί μέσα σε έκφραση. Κώδικας μετά από exit στο ίδιο μπλοκ είναι απρόσιτος:
exit 1;
print "never\n"; # dead code
Τιμές κατάστασης και η αποκοπή 8 bit#
Το λειτουργικό σύστημα αποθηκεύει την κατάσταση εξόδου σε 8 bit. Όποιον ακέραιο περάσετε στην exit λαμβάνεται modulo 256 από τον πυρήνα πριν τον δει η γονική διεργασία. Η exit 256 φαίνεται σαν exit 0 στο κέλυφος. Η exit -1 γίνεται 255. Περνάτε μόνο τιμές στο διάστημα 0..255 και αποφεύγετε την έκπληξη.
Οι μόνες παγκοσμίως φορητές τιμές είναι το 0 για επιτυχία και το 1 για γενικό σφάλμα. Άλλοι αριθμοί έχουν συμβάσεις - το εύρος sysexits.h 64..78 σε Unix, συγκεκριμένοι κωδικοί που αναμένονται από τα φίλτρα sendmail, και ούτω καθεξής - αλλά αυτά είναι συμφωνίες μεταξύ του προγράμματός σας και συγκεκριμένου καλούντος, όχι εγγυήσεις της γλώσσας. Η έξοδος με 69 (EX_UNAVAILABLE) λέει σε ένα φίλτρο εισερχομένων αλληλογραφίας sendmail να αναβάλει το μήνυμα· το ίδιο 69 από ένα σενάριο που τρέχει το cron δεν σημαίνει κάτι συγκεκριμένο.
exit 0; # success
exit 1; # generic failure
exit 2; # conventional "misuse" (grep, diff)
exit 77; # conventional "skip" (Automake test)
Καθαρισμός: μπλοκ END και καταστροφείς#
Η exit δεν είναι άμεση κλήση συστήματος. Πριν φύγει η διεργασία, η Perl:
Εκτελεί κάθε μπλοκ
ENDμε αντίστροφη σειρά μεταγλώττισης (LIFO).Καλεί την
DESTROYσε κάθε αντικείμενο του οποίου το refcount πέφτει στο μηδέν καθώς η καθολική καταστροφή διαλύει τα pads, τον πίνακα συμβόλων και τις καθολικές πακέτου.
Και τα δύο είδη καθαρισμού μπορούν να παρατηρήσουν και να αλλάξουν την $?. Η τιμή που περάσατε στην exit τοποθετείται στην $? κατά την είσοδο στη φάση END/DESTROY· όποια τιμή κρατά η $? όταν επιστρέψει ο τελευταίος καθαρισμός είναι η κατάσταση με την οποία εξέρχεται η διεργασία.
END { $? = 0 if $? == 2; } # rewrite "misuse" to success
exit 2; # process actually exits 0
Αυτό περιστασιακά είναι χρήσιμο και τακτικά εκπλήσσει. Αν ένα άρθρωμα που δεν γράψατε εσείς εγκαθιστά μπλοκ END που αγγίζει την $?, ο προσεκτικά επιλεγμένος κωδικός κατάστασής σας μπορεί να φτάσει στο γονικό κέλυφος αλλοιωμένος.
Όταν χρειάζεστε σκληρή, χωρίς όρους έξοδο που παρακάμπτει εντελώς τα END και DESTROY, καλέστε την POSIX::_exit:
use POSIX ();
POSIX::_exit(3); # no END, no DESTROY, status = 3
Καταφύγετε στην _exit σε θυγατρικές διεργασίες μετά από fork όπου ο καθαρισμός ανήκει στον γονέα, και σε χειριστές σήματος όπου η εκτέλεση αυθαίρετου κώδικα Perl δεν είναι ασφαλής.
Η exit δεν είναι η die#
Η exit είναι το λάθος εργαλείο για την αναφορά σφάλματος από μια βιβλιοθήκη ή υπορουτίνα. Ένας καλών ψηλότερα στη στοίβα μπορεί να θέλει να πιάσει την αποτυχία, να την καταγράψει και να συνεχίσει - ένα μπλοκ eval ή ένα περιτύλιγμα Try::Tiny δεν μπορεί να ανακάμψει από exit. Η διεργασία έχει χαθεί.
sub load_config {
my ($path) = @_;
open my $fh, "<", $path
or die "open $path: $!"; # correct - trappable
...
}
# NOT:
# open my $fh, "<", $path or exit 1;
Χρησιμοποιήστε την die για συνθήκες σφάλματος. Κρατήστε την exit για το ανώτατο επίπεδο του προγράμματος όπου έχετε αποφασίσει, ως εφαρμογή, ότι η εκτέλεση τελείωσε.
Η exit μέσα σε eval#
Η exit δεν πιάνεται από την eval. Σε αντίθεση με την die, η οποία ξετυλίγει στην πλησιέστερη eval και θέτει την $@, η exit περνά κατευθείαν πέρα από κάθε πλαίσιο eval στη στοίβα, εκτελεί τα END/DESTROY, και τερματίζει.
eval { exit 5 }; # process exits 5; the eval block
print "after eval\n"; # never runs
Αν γράφετε φιλοξενία πρόσθετων ή λουρί δοκιμών που πρέπει να επιβιώνει από κακή συμπεριφορά κώδικα χρήστη που καλεί exit, δεν υπάρχει σύλληψη σε επίπεδο γλώσσας. Η συμβατική λύση είναι να κάνετε fork, να αφήσετε το παιδί να καλέσει exit, και να ελέγξετε την κατάσταση του παιδιού στον γονέα:
my $pid = fork // die "fork: $!";
if ($pid == 0) {
run_user_code(); # may call exit
exit 0;
}
waitpid $pid, 0;
my $status = $? >> 8;
Παραδείγματα#
Πρόωρη επιστροφή από το πρόγραμμα μετά από προτροπή:
my $ans = <STDIN>;
exit 0 if $ans =~ /^[Xx]/;
Έξοδος με κατάσταση που προέρχεται από θυγατρική διεργασία - εξάγετε το υψηλό byte της $? ώστε το κέλυφος να δει τον ίδιο κωδικό που παρήγαγε το παιδί:
system @cmd;
exit $? >> 8 if $?;
Επανεγγραφή κατάστασης σε μπλοκ END - όποια τιμή κρατά η $? στο τέλος του καθαρισμού είναι η κατάσταση εξόδου που παραδίδεται στον γονέα:
END {
$? = 0 if $? == 2 && $ENV{IGNORE_MISUSE};
}
Παράκαμψη του καθαρισμού σε ένα forked παιδί ώστε οι καταστροφείς του γονέα να μην εκτελεστούν δύο φορές:
use POSIX ();
my $pid = fork // die "fork: $!";
if ($pid == 0) {
exec @cmd;
POSIX::_exit(127); # exec failed; do NOT run parent's END
}
Οριακές περιπτώσεις#
Η
exitχωρίς όρισμα είναιexit 0. Πολλά σενάρια βασίζονται στην πτώση από το τέλος του αρχείου για να πάρουν έμμεσο0· γράφονταςexit;κάνει την πρόθεση ρητή.Μη ακέραιο όρισμα: η
EXPRαποτιμάται σε βαθμωτό περιβάλλον και μετατρέπεται σε ακέραιο. Ηexit "3x"εξέρχεται με3· ηexit "hello"εξέρχεται με0και προειδοποίηση υπόuse warnings.Οι αρνητικές τιμές λαμβάνονται modulo 256 από τον πυρήνα. Η
exit -1εμφανίζεται στο κέλυφος ως255. Περάστε μόνο0..255για να αποφύγετε τον εξαναγκασμό.Οι τιμές πάνω από 255 χάνουν τα υψηλά τους bits. Η
exit 256φαίνεται σαν επιτυχία· ηexit 300φαίνεται σανexit 44. Αν χρειάζεται να μεταφέρετε μεγαλύτερη τιμή, γράψτε την σε αρχείο ή στοSTDERRκαι εξέλθετε με μικρό κωδικό κατάστασης.Τα μπλοκ
ENDμπορούν να ακυρώσουν την κατάστασή σας αλλά όχι την ίδια την έξοδο. Ένα μπλοκENDδεν μπορεί να εμποδίσει τη διεργασία να τερματιστεί - μπορεί μόνο να αλλάξει την$?, και συνεπώς την κατάσταση που βλέπει ο γονέας.Η σειρά καθολικής καταστροφής δεν είναι η αντίστροφη της κατασκευής. Κατά την τελική σάρωση η Perl διασχίζει τις καθολικές πακέτου με σειρά καθορισμένη από την υλοποίηση. Μη βασίζεστε στο ότι ένα
DESTROYθα εκτελεστεί πριν από άλλο· αν η σειρά έχει σημασία, διαλύστε ρητά τα αντικείμενα πριν καλέσετεexit.Μέσα σε μπλοκ
BEGIN, ηexitτερματίζει τη φάση μεταγλώττισης και εξέρχεται από τη διεργασία. Τα μπλοκENDπου έχουν ήδη καταχωρηθεί εκτελούνται· μεταγενέστερος κώδικαςBEGIN/ENDστο αρχείο όχι.Threads: σε πρόγραμμα με πολλαπλά threads διερμηνέα Perl, η
exitτερματίζει ολόκληρη τη διεργασία, όχι μόνο το thread που καλεί. Χρησιμοποιήστεthreads->exitγια έξοδο ανά thread.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
die- εκτόξευση παγιδεύσιμης εξαίρεσης· η σωστή επιλογή για αναφορά σφαλμάτων από υπορουτίναwarn- εκπομπή διαγνωστικού χωρίς τερματισμό· συνδυάζεται μεdieόπως ηprintσυνδυάζεται με τηνexitΜπλοκ
END- κώδικας καθαρισμού που καταχωρείται κατά τη μεταγλώττιση και εκτελείται σε σειρά LIFO σε κάθε έξοδο, συμπεριλαμβανομένης τηςexit EXPRΜέθοδοι
DESTROY- καθαρισμός ανά αντικείμενο που καλείται κατά την καθολική καταστροφή αφού έχουν εκτελεστεί τα μπλοκEND$?- κατάσταση θυγατρικής διεργασίας / τελική κατάσταση εξόδου· ορατή και μεταβλητή από μπλοκENDκαι καταστροφείςPOSIX::_exit- άμεσος τερματισμός που παρακάμπτει ταENDκαιDESTROY· χρησιμοποιήστε σε forked παιδιά και χειριστές σήματος