exit#
לסיים את התוכנית עם ערך סטטוס.
exit מעריך את EXPR, מריץ ניקוי סוף־התוכנית (בלוקי END והורסי עצמים), ואז יוצא מהתהליך עם הערך הזה כקוד הסטטוס שלו. ללא ארגומנט הוא יוצא 0 - הצלחה.
תקציר#
exit EXPR
exit
מה מקבלים בחזרה#
כלום. exit אינו חוזר לקורא שלו. הוא הוראה במובן של בקרת זרימה למרות שהדקדוק מאפשר לכתוב אותו בתוך ביטוי. קוד אחרי exit באותו בלוק אינו ניתן להגעה:
exit 1;
print "never\n"; # dead code
ערכי סטטוס וקיצוץ ל־8 ביט#
מערכת ההפעלה מאחסנת סטטוס יציאה ב־8 ביט. כל מספר שלם שמועבר ל־exit נלקח מודולו 256 על־ידי הקרנל לפני שתהליך האב רואה אותו. exit 256 נראה כמו exit 0 ל־shell. 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על כל עצם שספירת ההפניות שלו יורדת לאפס כאשר ההריסה הגלובלית מפרקת pads, את טבלת הסמלים, וגלובליים של חבילות.
שני סוגי הניקוי יכולים לצפות ולשנות את $?. הערך שהעברת ל־exit ממוקם ב־$? בכניסה לשלב END/DESTROY; כל מה ש־$? מחזיק כאשר הניקוי האחרון חוזר הוא הסטטוס שאיתו התהליך יוצא.
END { $? = 0 if $? == 2; } # rewrite "misuse" to success
exit 2; # process actually exits 0
זה לפעמים שימושי ותמיד מפתיע. אם מודול שלא כתבת מתקין בלוק END שנוגע ב־$?, קוד הסטטוס שבחרת בקפידה יכול להגיע ל־shell ההורה משונה.
כאשר נדרשת יציאה קשה, ללא תנאי, שעוקפת את 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
אם כותבים מארח plugin או רתמת בדיקות שחייבת לשרוד קוד משתמש שמתנהג בצורה לא־ראויה וקורא ל־exit, אין catch ברמת השפה. הפתרון המקובל הוא לבצע 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]/;
יציאה עם סטטוס שנגזר מתהליך בן - לחלץ את הבית הגבוה של $? כך שה־shell יראה את אותו קוד שהבן ייצר:
system @cmd;
exit $? >> 8 if $?;
לשכתב סטטוס בבלוק END - כל מה ש־$? מחזיק בסוף הניקוי הוא סטטוס היציאה שמועבר לאב:
END {
$? = 0 if $? == 2 && $ENV{IGNORE_MISUSE};
}
לעקוף ניקוי בבן שעבר fork כדי שההורסים של האב לא ירוצו פעמיים:
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.ערכים שליליים נלקחים מודולו 256 על־ידי הקרנל.
exit -1נראה ל־shell כ־255. יש להעביר רק0..255כדי להימנע מהמרה.ערכים מעל 255 מאבדים את הביטים הגבוהים שלהם.
exit 256נראה כמו הצלחה;exit 300נראה כמוexit 44. אם נדרש להעביר ערך גדול יותר, יש לכתוב אותו לקובץ או ל־STDERRולצאת עם קוד סטטוס קטן.בלוקי
ENDיכולים לבטל את הסטטוס שלך אך לא את היציאה עצמה. בלוקENDאינו יכול לעצור את התהליך מלהסתיים - הוא יכול רק לשנות את$?, ולכן את הסטטוס שהאב רואה.סדר ההריסה הגלובלית אינו ההפוך של הבנייה. במהלך הסריקה הסופית Perl עובר על גלובליים של חבילות בסדר שמוגדר על־ידי המימוש. אין להסתמך על כך ש־
DESTROYאחד ירוץ לפני אחר; אם הסדר חשוב, יש לפרק את העצמים במפורש לפני קריאה ל־exit.בתוך בלוק
BEGIN,exitמסיים את שלב ההידור ויוצא מהתהליך. בלוקיENDשכבר נרשמו רצים; בלוקיBEGIN/END/קוד מאוחרים יותר בקובץ אינם.Threads: בתוכנית עם מספר thread של מפרש 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; יש להשתמש בו בבני־תהליך אחרי fork ובמטפלי אותות