Ροή ελέγχου

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:

  1. Εκτελεί κάθε μπλοκ END με αντίστροφη σειρά μεταγλώττισης (LIFO).

  2. Καλεί την 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 παιδιά και χειριστές σήματος