ה־switches#

כל חד־שורתי הוא שילוב של תוכנית (המועברת ל־-e או -E) וקומץ של switches העוטפים סביבה התנהגות מובלעת. פרק זה מכסה את ה־switches שאליהם תפנו. כל אחד מצדיק את קיומו בפרקי הפרוגרסיה, ה־regex, וה־numeric שבהמשך.

קוראים המגיעים מ־awk או sed כבר יודעים כיצד נראים איטרציה לכל שורה, פיצול שדות, ועריכה במקום; השאלה היא איזה דגל של pperl מפעיל כל אחד מהם.

-e - הרצת תוכנית הניתנת בשורת הפקודה#

pperl -e 'print "hello\n"'

-e מקבל את מקור ה־Perl כארגומנט. מספר חלקי -e משורשרים יחד; הם מתנהגים כתוכנית אחת עם נקודה־פסיק ביניהם.

pperl -e 'my $x = 41;' -e 'print $x + 1, "\n"'    # 42

השתמשו במרכאות בודדות סביב התוכנית כך שה־shell ישאיר את $_, $1, \n, ו־backticks ללא שינוי. ראו gotchas למה משתבש עם מרכאות כפולות.

-E - -e בתוספת מערך התכונות המודרני#

-E הוא -e עם כל התכונות האופציונליות מופעלות: say, state, fc, אופרטור defined-or //, סמנטיקה של מחרוזות unicode תחת use feature 'unicode_strings', ועוד.

pperl -E 'say "hello"'                    # instead of print "hello\n"
pperl -E 'say "pi = " . (atan2(1,1)*4)'

פנו ל־-E בכתיבת חד־שורתיים חדשים. פנו ל־-e רק כשתאימות העתקה־הדבקה לסקריפטים ישנים מאוד חשובה.

-n - עטיפת לולאת קריאה מובלעת סביב התוכנית#

-n הופך את התוכנית לגוף של לולאה על כל שורה של כל קובץ קלט (או STDIN אם לא ניתן אף אחד). הלולאה היא בדיוק:

while (<>) {
    # your program
}

$_ מחזיק כל שורת קלט, כולל תו השורה החדשה הנגרר. דבר אינו מודפס באופן אוטומטי - אתם מחליטים מה מגיע ל־STDOUT.

# Print lines containing "error"
pperl -ne 'print if /error/' app.log

צורה ארוכה שקולה, מוצגת פעם אחת כדי שההרחבה המכאנית תהיה ברורה:

while (<>) {
    print if /error/;
}

כל מתכון -n שיבוא במדריך זה מסתמך על הרחבה זו - הניחו אותה ללא הצהרה מחדש.

BEGIN { } רץ לפני הלולאה, END { } רץ אחריה. שניהם בלוקים רגילים של Perl ומתחברים עם -n בנקיון.

# Count lines matching a pattern
pperl -ne '$n++ if /WARN/; END { print "$n\n" }' app.log

-p - כמו -n, אבל מדפיס $_ אחרי כל איטרציה#

pperl -pe 's/foo/bar/g' input.txt

הרחבה מכאנית:

while (<>) {
    # your program
} continue {
    print or die "-p destination: $!";
}

פנו ל־-p כשהפלט הוא הקלט (אולי לאחר שינוי). פנו ל־-n כשהפלט הוא סיכום, תת־קבוצה מסוננת, או דבר כלל.

-l - טיפול בסיום שורה#

-l עושה שני דברים בו זמנית:

  1. בקלט, chomp על כל שורה ברגע שהיא נקראת תחת -n / -p. $_ כבר אינו מסתיים ב־"\n".

  2. בפלט, קביעת $\ (מפריד רשומת הפלט) כך שכל print יוסיף "\n".

# Print just the first field of each tab-separated line
pperl -F'\t' -lane 'print $F[0]' table.tsv

ללא -l, או שהייתם כותבים print "$F[0]\n" (שורת חדשה עוברת לתוך התוכנית) או שהייתם מפיקים פלט דבוק.

-l מקבל ארגומנט אוקטלי אופציונלי שקובע את $\ לתו אחר: -l012 שומר על שורה חדשה (ברירת המחדל), -l0 קובע את $\ ל־NUL, וכן הלאה. השימוש הנפוץ הוא הצורה ללא ארגומנט.

-a - autosplit ל־@F#

בשילוב עם -n או -p, -a מפצל את $_ על רווחים ושם את השדות ב־@F. הפיצול ברירת מחדל הוא split(' ', $_) - הוא חותך רווחים מובילים ומתייחס לכל רצף של רווחים כמפריד אחד.

# Third column of every line
pperl -lane 'print $F[2]' data.txt

# Reverse column order
pperl -lane 'print "@{[reverse @F]}"' data.txt

@F מתחיל באינדקס אפס. $F[-1] הוא השדה האחרון. scalar @F הוא מספר השדות.

-F - שינוי תבנית הפיצול#

-F sets the delimiter used by -a. The argument is a regex; a literal comma is -F,, a colon is -F:, a tab is -F'\t'.

# Second field of a colon-separated file
pperl -F: -lane 'print $F[1]' /etc/passwd

# Split on any run of commas or semicolons
pperl -F'[,;]+' -lane 'print scalar @F' mixed.csv

-F אינו רומז דבר על -a; אתם עדיין זקוקים ל־-a. הניב הנפוץ -F: -lane הוא פיצול בנקודתיים, chomped, עם @F זמין.

ציטוט של טאב דורש טאב ליטרלי ב־shell או את צורת ה־regex:

pperl -F'\t' -lane 'print $F[0]' data.tsv       # regex form, always safe
pperl -F'	' -lane 'print $F[0]' data.tsv     # literal tab - fragile

-i - עריכת קבצים במקום#

-i משכתב את הקובץ ממנו pperl קורא, מחליף את תוכנו במה ש־-p מדפיס. הפלט של כל הקובץ הולך לקובץ זמני; כשהלולאה מסתיימת, הזמני מחליף את המקור.

# Replace CRLF with LF in every .txt under cwd (no backup)
pperl -i -pe 's/\r\n/\n/g' *.txt

# Same, keeping a .bak copy beside each original
pperl -i.bak -pe 's/\r\n/\n/g' *.txt

השתמשו תמיד ב־-i.bak (או בסיומת אחרת) עד שווידאתם את העריכה מול קובץ מייצג. באג בתוכנית עם -i חשוף הורס את הקלט. ראו gotchas.

ל־-i אין השפעה ללא -p (או prints מפורשים תחת -n): אם דבר אינו מודפס, קובץ ההחלפה ריק.

-M ו־-m - טעינת מודולים לפני הרצת התוכנית#

-Mmodule שקול ל־use module; בראש התוכנית. -Mmodule=sym1,sym2 הוא use module qw(sym1 sym2);.

pperl -MList::Util=sum -lane 'print sum @F' data.txt
pperl -MPOSIX=strftime -le 'print strftime("%F", localtime)'
pperl -MData::Dumper -e 'print Dumper({a=>1, b=>[2,3]})'

ה־-m באות קטנה הוא no strict ולא use ; הוא נדרש לעיתים נדירות בשורת הפקודה.

המודולים הנפוצים ביותר בחד־שורתיים: List::Util (sum/min/max/uniq/any), POSIX (strftime, mktime, fmod), Data::Dumper (לבחון מבנים), JSON::PP (לפענח/לפלוט JSON), Text::CSV (CSV מצוטט), MIME::Base64, Digest::MD5, Digest::SHA, Socket.

-0 - קביעת מפריד רשומת הקלט#

Perl קוראת בדרך כלל שורה בכל פעם. -0NNN קובע את $/ לתו עם הקוד האוקטלי הנתון, ומשנה את משמעות ״רשומה אחת״ עבור <>, <STDIN>, ולולאת -n / -p.

צורות נפוצות:

צורה

מה $/ הופך

השפעה

-0

"\0" (NUL)

קריאת רשומות מופרדות־NUL (תואם ל־find -print0).

-0777

undef

slurp של כל הקובץ כרשומה אחת.

-00

""

מצב פסקה: שורות ריקות מפרידות בין רשומות.

-0NNN

chr(0NNN)

כל בית אוקטלי בודד.

# Count files from find -print0
find . -type f -print0 | pperl -0 -ne '$n++; END { print "$n\n" }'

# Slurp, then run a cross-line regex
pperl -0777 -ne 'print "yes\n" if /BEGIN.*?END/s' text.txt

# Print every paragraph containing "TODO"
pperl -00 -ne 'print if /TODO/' notes.txt

מצב פסקה (-00) מתקשר עם -l: ללא -l, המפריד הריק נשאר מחובר לכל רשומה; עם -l, הוא chomped.

-C - Unicode על stdio ו/או @ARGV#

-C מאפשר טיפול ב־Unicode על זרמים מצוינים. הארגומנט הוא או מספר (bitmask) או מחרוזת של אותיות.

pperl -CSD -ne 'print' input.txt      # stdin, stdout, stderr all UTF-8
pperl -CA  -e  'print $ARGV[0]' äöü   # @ARGV treated as UTF-8
pperl -CSA -nE 'say length'           # S + A

קודי אותיות: I = stdin, O = stdout, E = stderr, S = I+O+E, A = @ARGV, D = קביעת שכבות I/O ברירת מחדל (כולל פתיחות קבצים).

לסשן UTF-8 מלא, -CSD. לעיבוד חד־פעמי של קבצי UTF-8 בעלי שם, -CSAD. ראו gotchas לתסמינים המעידים על כך ש־-C חסר.

טבלת עיון#

כל switch, ההרחבה המכאנית שלו, והפרק בו הוא מופיע לראשונה במתכון.

Switch

מתרחב ל

שימוש ראשון ב

-e CODE

הרצת CODE כתוכנית

progression

-E CODE

-e בתוספת כל התכונות הנוכחיות מופעלות

progression

-n

while (<>) { CODE }

progression

-p

while (<>) { CODE } continue { print }

progression

-l

chomp על הקלט תחת -n/-p; קביעת $\ = "\n" לפלט

progression

-a

Auto-split של $_ ל־@F

progression

-F PAT

שינוי תבנית הפיצול של -a ל־regex PAT

progression

-i[EXT]

עריכה במקום; עם EXT, שמירת גיבוי original + EXT

progression

-M MOD

use MOD; לפני התוכנית

numeric

-M MOD=X

use MOD qw(X);

numeric

-0

$/ = "\0" - רשומות מופרדות־NUL

progression

-00

$/ = "" - מצב פסקה

progression

-0777

$/ = undef - slurp של כל הקובץ

progression

-C

הפעלת Unicode על stdio, @ARGV, ו/או שכבות ברירת מחדל

gotchas

משתנים מיוחדים ש־switches מקימים#

קטלוג קצר; ההגדרות המלאות נמצאות ב־perlvar.

משתנה

תפקיד תחת -n/-p

$_

שורת הקלט הנוכחית (chomped אם -l, גולמית אחרת).

$.

מספר שורת הקלט הנוכחית (אינו מאופס בין קבצים כברירת מחדל).

$/

מפריד רשומת קלט. משפחת -0 משנה אותו.

$\

מפריד רשומת פלט שמוסף על־ידי print. -l קובע אותו ל־"\n".

$,

מפריד שדה פלט שמוכנס בין הארגומנטים של print.

$"

מפריד בין אלמנטי המערך כשמשובץ ב־"@array".

@F

שדות Auto-split תחת -a.

@ARGV

ארגומנטי שורת הפקודה שנותרו; שמות קבצים נצרכים כשמעובדים.

$ARGV

שם הקובץ הנקרא כעת ("-" משמעו STDIN).

לקריאה נוספת#

  • progression מיישם כל switch במתכונים בעלי מורכבות עולה.

  • perlvar מונה כל משתנה מיוחד ש־pperl מגדיר, לא רק אלה ש־switches נוגעים בהם.

  • perlop מכסה את qr//, את אופרטור ה־flip-flop, ואת אופרטור היהלום בו משתמשות לולאות -n / -p.