מנפה השגיאות האינטראקטיבי#

פרק זה מכסה את perl -d: הפעלת תוכנית תחת מנפה השגיאות, ה־prompt, פקודות התנועה והבחינה החיוניות, ואוצר המילים של ניווט במחסנית. לאחר פרק זה תוכלו לחקור כל תוכנית רצה באופן אינטראקטיבי.

הקוראים מתחילים מידיעה ש־print / warn עובדים אך אינם מספיקים: צריך לעצור, להסתכל מסביב, להציץ במשתנים, ללכת על מחסנית הקריאות, ואז לחדש. זה מה שהפרק הזה מספק.

הפעלה#

עבור כל סקריפט app.pl, הוסיפו לפניו -d:

perl -d app.pl --verbose input.txt

ארגומנטים לאחר שם הסקריפט מועברים לסקריפט כרגיל.

צורות הפעלה נפוצות:

צורה

תכלית

perl -d script.pl args

ניפוי שגיאות בסקריפט הנתון.

perl -d -e 'CODE'

ניפוי שגיאות בביטוי שורה־אחת.

perl -de 0

ארגז חול REPL אינטראקטיבי.

perl -d:Module script.pl

טעינת Devel::Module כמנפה שגיאות.

perl -d:NYTProf script

profiling באמצעות תוסף NYTProf.

perl -S -d script.pl

חיפוש הסקריפט ב־$PATH.

-d גורם לקומפיילר לפלוט נקודות hook לכל הוראה; הפרשן טוען מראש את perl5db.pl לפני שורת זמן הריצה הראשונה.

לעולם אל תצנרתו קלט ל־perl -d ולעולם אל תשתמשו ב־/dev/stdin - מנפה השגיאות זקוק ל־TTY כדי לקרוא ממנו פקודות. הפעילו מטרמינל אמיתי.

ה־prompt#

Loading DB routines from perl5db.pl version 1.77
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(app.pl:4):     my $key = 'welcome';
  DB<1>

השורה main::(app.pl:4): מציגה את השורה הבאה שעומדת להתבצע - דבר בתוכנית עוד לא רץ. קוד של זמן הידור (BEGIN, use) כבר רץ; ה־prompt הראשון בא לפני הוראת זמן הריצה הראשונה.

DB<1> - המספר הוא מונה פקודות הגדל בכל פקודה. !N מזכיר פקודה מספר N. DB<<N>> עם סוגריים כפולים פירושו שאתם בתוך מנפה שגיאות מקונן (ביטוי אחד שצעדתם לתוכו קרא לביטוי נוסף הניתן לעצירה).

מנפה השגיאות מציג תמיד את השורה שעומדת להתבצע, אף פעם לא את השורה שזה עתה בוצעה.

יציאה#

  DB<1> q

לא quit, לא exit. הקלדת exit מריצה את ה־exit של Perl בתוך ה־eval של מנפה השגיאות, וזה לא אותו דבר. ^D ב־prompt עובד ברוב הטרמינלים.

עזרה#

  DB<1> h              # one-screen summary
  DB<1> h h            # full help (long - use the pager)
  DB<1> h b            # help on one command
  DB<1> |h h           # pipe full help through $ENV{PAGER}

איפה אני?#

v מציג חלון סביב השורה הנוכחית. l מפרט טווח מצוין:

  DB<1> v
1       #!/usr/bin/perl
2       use v5.40;
3
4==>    my $key = 'welcome';
5:      my %data = (
6               'this'    => qw(that),
7               'tom'     => qw(and jerry),
8               'welcome' => q(Hello World),
9               'zip'     => q(welcome),
10      );
  • ==> מסמן את השורה הבאה לביצוע.

  • : מסמן שורות הניתנות לביצוע - ניתן לקבוע breakpoint שם.

  • שורות ללא : אינן ניתנות לעצירה (הערות, שורות ריקות, המשכים של הוראה רב־שורתית).

ניווט:

פקודה

השפעה

v

הצגת חלון סביב השורה הנוכחית.

v LINE

הצגת חלון סביב LINE.

l

פירוט החלון הבא; חזרה מתקדמת.

l LINE

פירוט LINE בלבד.

l MIN-MAX

פירוט טווח.

l SUB

פירוט החלון הראשון של SUB.

-

חלון קודם.

.

החזרת התצוגה לשורה הנוכחית.

f FILE

החלפת תצוגה ל־FILE (regex כנגד %INC).

/PAT/

חיפוש קדימה במקור.

?PAT?

חיפוש אחורה.

תנועה: s, n, Enter, c, r#

ארבע פקודות התנועה החיוניות:

פקודה

השפעה

s

Step - ביצוע ההוראה הבאה; ירידה לתוך תתי־שגרות.

n

Next - ביצוע ההוראה הבאה; פסיחה מעל תתי־שגרות.

<Enter>

חזרה על s או n האחרונים.

c

המשך עד ל־breakpoint הבא או עד הסוף.

c LINE

המשך ל־breakpoint חד־פעמי ב־LINE, ואז עצירה.

c SUB

המשך לשורה הראשונה של SUB.

r

חזרה מה־sub הנוכחי; עצירה אצל הקורא.

  DB<1> s                          # descend into the call
  DB<2> n                          # stay at this level
  DB<3>                            # <Enter> repeats the last motion
  DB<4> c 42                       # run to line 42 once
  DB<5> r                          # pop the current frame

הוראה רב־שורתית צועדת אטומית - s יחיד מבצע השמת hash שלמה רב־שורתית.

בשורה שאינה קוראת לתתי־שגרות, s ו־n בלתי ניתנים להבחנה.

הדפסת ערכים: p ו־x#

  DB<1> p $key
welcome

  DB<2> p join ',', sort keys %data
this,tom,welcome,zip

p EXPR מעריך את EXPR בחבילה הנוכחית של התוכנית ומדפיס את התוצאה בהקשר סקלר ואחריה שורה חדשה. p שטוח - עבור הפניה הוא מדפיס HASH(0x...), לא את התוכן.

עבור מבנים, השתמשו ב־x:

  DB<3> x \%data
0  HASH(0x5651f9a82358)
   'this' => 'that'
   'tom' => 'and'
   'welcome' => 'jerry'
   'zip' => 'Hello World'

תמיד העבירו הפניה (x \%h, x \@a) - x %h מבצע dump לרשימה השטוחה של מפתח/ערך, אשר מסתירה את המבנה.

ראו inspecting-state עבור אוצר המילים המלא של הבחינה (V, X, y, m, M, i, בקרות עומק).

מחסנית הקריאות: T, s, r#

T מדפיס backtrace - שרשרת קריאות ה־sub שהובילה לשורה הנוכחית:

  DB<1> T
$ = main::handle_request(ref(HTTP::Request)) called from file 'app.pl' line 47
$ = main::dispatch('GET', '/users/42') called from file 'app.pl' line 19
@ = main::main() called from file 'app.pl' line 12
  • $ - נקרא בהקשר סקלר.

  • @ - נקרא בהקשר רשימה.

  • . - הקשר void.

  • ארגומנטים מוצגים עם קיצוץ בסגנון Data::Dumper; תקרת האורך המדויקת היא האפשרות maxTraceLen.

נווטו במחסנית עם s (לתוך קריאה) ו־r (החוצה מהמסגרת הנוכחית). אין פקודת ״frame up / frame down״: צעדו מחדש אם הלכתם עמוק מדי, או השתמשו ב־b כדי לקבוע breakpoint אצל הקורא וב־c כדי להגיע אליו.

כדי לבחון לקסיקלים של מסגרת חיצונית, השתמשו ב־y LEVEL מ־inspecting-state - היא קוראת דרך PadWalker ומציגה את משתני ה־my של התחום העוטף.

הערכת Perl ב־prompt#

כל דבר שמנפה השגיאות אינו מזהה כפקודה עובר eval כקוד Perl בחבילה DB בתחום הלקסיקלי הנוכחי:

  DB<1> $counter = 0                # mutate state
  DB<2> @ARGV = qw(new args)        # mutate @ARGV
  DB<3> $obj->reset                 # call a method
  DB<4> m/(\w+)/ && p $1            # match against $_

my $x רענן ב־prompt נעלם כאשר הפקודה חוזרת - ל־prompt יש תחום לקסיקלי משלו. השתמשו ב־bareword, ב־our, או שרשרו בשורה אחת:

  DB<1> our $tmp = compute();       # survives
  DB<2> $tmp = compute(); p $tmp    # one-line chain

לאלץ פירוש Perl כאשר ביטוי נראה כפקודת מנפה שגיאות:

  DB<1> ; h EXPR                   # ; prefix forces eval
  DB<2> + h EXPR                   # + prefix works too

Restart ו־rerun#

R מפעיל את התוכנית מחדש באמצעות exec(). היסטוריה, breakpoints, actions, אפשרויות, ושורת הפקודה נשמרים:

  DB<1> R

rerun מבצע מחדש מבלי לעזוב את מנפה השגיאות, ושומר על המצב:

צורה

השפעה

rerun

restart, ללא replay של פקודות קודמות.

rerun -N

restart ו־replay של עד N פקודות אחורה.

rerun N

restart מרשומת היסטוריה N.

הגדרה מחדש של sub באמצע סשן#

הדביקו את כל ה־sub NAME { ... } ב־prompt. או ערכו קובץ חלופי וטענו אותו:

  DB<1> do 'fixed.pl'

קריאות עוקבות משתמשות בהגדרה החדשה. מסגרות מחסנית קיימות ממשיכות עם הגוף הישן.

פקודות עד כה#

פקודה

השפעה

h, h CMD, h h

עזרה: סיכום / פקודה אחת / מלא.

|CMD

צנרת הפלט דרך $ENV{PAGER}.

q

יציאה.

v, v LINE

הצגת המקור סביב הנוכחי / LINE.

l, l LINE, l SUB, l MIN-MAX

פירוט.

.

מעבר לשורה הנוכחית.

-

חלון קודם.

f FILE

החלפת תצוגה ל־FILE.

/PAT/, ?PAT?

חיפוש קדימה / אחורה.

s

step לתוך.

n

step מעל.

<Enter>

חזרה על s / n אחרון.

r

חזרה מה־sub הנוכחי.

c, c LINE, c SUB

המשך / breakpoint חד־פעמי.

p EXPR

הדפסה (הקשר סקלר).

x EXPR

dump (מובנה, העבירו הפניה).

T

backtrace של מחסנית.

R

restart באמצעות exec().

rerun [N|-N]

restart עם replay של היסטוריה.

למידע נוסף#

  • breakpoints - b, מותנים, actions, watches, מטריצת תזמון.

  • inspecting-state - V, X, y, m, M, i, בקרות עומק.

  • tracing - t, AutoTrace, פלט מידע־שורה לקובץ.