530 likes | 809 Views
תרגול מס' 6. שרשור פקודות באמצעות Pipeline עבודה ב- C-Shell כתיבת תסריטים ב- C-Shell. Pipeline. הרכבת פקודות Pipeline. הרכבת פקודות. נניח שברצוננו להדפיס את התוכן של תיקיה המכילה הרבה קבצים לא נוכל במצב זה לראות את כל הקבצים
E N D
תרגול מס' 6 שרשור פקודות באמצעות Pipeline עבודה ב-C-Shell כתיבת תסריטים ב-C-Shell
Pipeline הרכבת פקודות Pipeline מבוא לתכנות מערכות - 234122
הרכבת פקודות • נניח שברצוננו להדפיס את התוכן של תיקיה המכילה הרבה קבצים • לא נוכל במצב זה לראות את כל הקבצים • נוכל להשתמש בהפנית פלט הפקודה ls לקובץ זמני ולאחר מכן שימוש ב-more: > ls -l > tmp > more < tmp > rmtmp מבוא לתכנות מערכות - 234122
Pipeline • כדי לחסוך את הבלגן שבטיפול בקבצים זמניים ניתן להשתמש ב-pipeline המחבר את הפלט של פקודה אחת לקלט של פקודה שניה ישירות • כדי לחבר שתי פקודות כך נרשום אותן אחת אחרי השניה כאשר ביניהן מפריד התו ‘|’ • על מנת לראות בשלבים את התוכן של תיקיה גדולה נוכל לרשום כעת: > ls -l | more • ניתן לשלב מספר תכניות בבת אחת: > command1| command2| command3 command1 command2 command3 stdout stdin stdout stdin מבוא לתכנות מערכות - 234122
Pipeline - סיכום • ניתן להשתמש בתו ‘|’ כדי לחבר את הפלט של תכנית א' עם הקלט של תכנית ב' • בעזרת pipeline נוכל להרכיב פקודות מורכבות בעבודה בטרמינל מתכניות פשוטות מבוא לתכנות מערכות - 234122
עבודה ב-C-Shell מהו C-Shell? תכונות מתקדמות של C-Shell עבודת ה-C-Shell מבוא לתכנות מערכות - 234122
Shell • Shell (קליפה) הוא כינוי לתוכנה המקשרת בין המשתמש לבין גרעין מערכת ההפעלה • בדרך כלל המונח בשימוש עבור shell טקסטואלי • כאשר אנו מתחברים ל-stud נפתחת shell ברירת המחדל עבור מחשב זה -C-Shell • דוגמאות נוספות ל-shell: • bash (ברירת המחדל ברוב הפצות הלינוקס) • powershell (shell מתקדם עבור windows) • מלבד מנשק בסיסי לביצוע פקודות ה-Shellמקל עלינו את העבודה בעזרת תכונות מתקדמות, לדוגמה ההשלמה האוטומטית המתבצעת ע"י לחיצה על Tab מבוא לתכנות מערכות - 234122
C-Shell • נשתמש בגרסה מורחבת של C-Shell הקרויה tcsh (Tenex C-Shell) • במחשבים בהם זהו אינו Shell ברירת המחדל ניתן להפעילו פשוט על ידי הרצת הפקודה tcsh • ניתן להשתמש בפקודה הבאה כדי לקבל את שם ה-Shell הנוכחי ב-Unix > echo $0 tcsh • עבודת ה-Shell מתבצעת על ידי קבלת פקודה מהמשתמש, ביצוע החלפות טקסט בפקודה בהתאם לתכונות ה-Shell ולבסוף שליחת הפקודה המעובדת למערכת ההפעלה • ה-Shell יאפשר לנו להגדיר קיצורים, לחזורעל פקודות, להתייחס למספר קבצים בנוחות ולהגדיר משתניםאשר נוכל להשתמש בהם בפקודות מבוא לתכנות מערכות - 234122
הפקודה echo • במקרים רבים נרצה להדפיס לפלט מחרוזת, לשם כך ניתן להשתמש בפקודה echo • הפקודה echoמדפיסה את הפרמטרים שקיבלה > echo [-n] [words] • -n: מדפיס ללא ירידת שורה > echo Hello world! Hello world! מבוא לתכנות מערכות - 234122
נתינת כינויים לפקודות - alias • הפקודה alias מאפשרת להגדיר קיצורים ב-Shell > alias <new name> <command + parameters> • לאחר הרצת הפקודה נוכל לרשום את הפקודה <new name> כקיצור לפקודה <command> עם הפרמטרים שהוספנו. • כדי לבטל aliasניתןלהשתמש בפקודהunalias <alias> • ה-Shell יבדוק בשלב עיבור הפקודה האם המילה הראשונה היא alias ואם כן יבצע החלפה מתאימה < alias llls -l > ll -rw-r--r-- 1 user staff 0 Nov 13 15:14 a.c > alias cdex2 cd ~/mtm/ex2 > cdex2 > alias GCC gcc -std=c99 -Wall -Werror -pednatic-errors > GCC hello.c -o hello > unalias GCC > GCC hello.c -o hello GCC: Command not found. מבוא לתכנות מערכות - 234122
Filename Expansion • ניתן לרשום בפקודה תבנית המתייחסת למספר קבצים. במקרה זה C-Shell יחליף את מחרוזת התבנית בפקודה ברשימת הקבצים המתאימים לתבנית • הסימן * מתאים למחרוזת כלשהי (כולל ריקה) • הסימן ? מתאים לתו כלשהו יחיד • ניתן להתייחס למספר תווים אפשריים על ידי שימוש ב-[ ] • ניתן לרשום את התווים האפשרייםאחד אחרי השני במפורש • ניתן לרשום טווח של תווים, למשל a-z • ניתן להתייחס למספר מחרוזות שונות בעזרת { } • אפשרות זו אינה מתחשבת בקבצים קיימים <ls axb.c a3b.c cab.txt a4b.txt > echo files: * files: axb.ca3b.c cab.txt a4b.txt > echo The source files are *.c The source files are axb.c a3b.c > echo a[0-9]b.* a3b.c a4b.txt > echo a3b.{c,txt} a3b.c a3b.txt מבוא לתכנות מערכות - 234122
משתנים • ניתן להציב ערך למשתנה ב-C-Shell על ידי הפקודה set > set <varname>=<value> • אין צורך להכריז על משתנים ב-C-Shell, לאחר ביצוע השמה למשתנה הוא מוגדר אוטומטית • ניתן להחליףערך של משתנה על ידי פקודת set נוספת • ניתן לקרוא משתנים על ידי שימוש באופרטור $, למשל: > echo $<varname> • השימוש במשתנה הוא פשוט החלפת הקריאה למשתנה בערך השמור בו מבוא לתכנות מערכות - 234122
משתנים • ניתן לבטל הגדרה של משתנה על ידי הפקודה unset <varname> < unset my_variable • בדרך כלל אין צורך בכך • אם מנסים לקרוא משתנה שאינו מוגדר מתקבלת שגיאה > echo $blahblah blahblah: Undefined variable. • ניתן להשתמש ב-{} כדי לסמן מהו שם המשתנה לאופרטור $ • מועיל כאשר השימוש במשתנה צמוד למחרוזת נוספת > set a=Hell > echo $ao ao: Undefined variable. > echo ${a}o Hello מבוא לתכנות מערכות - 234122
משתנים - רשימות • ניתן לשמור במשתנה יחיד רשימהשל מחרוזות על ידי שימוש בסוגריים > set list=(1 2 3) • קריאת משתנה תחליף אותו בתוכן כל הרשימה (הסוגריים אינם נשמרים) > echo $list1 2 3 • ניתן לגשת לאיבר יחיד בעזרת אופרטור [ ] • מספור האינדקסים מתחיל מ-1! • חריגה מהטווח הרשימה תגרום לשגיאה > echo $list[1]1 • ניתן לגשת לתחומים מהרשימה > echo A:$list[-2] B:$list[2-] C:$list[1-2]A:1 2 B:2 3 C:1 2 • ניתן לקבל את מספר האיברים ברשימה בעזרת $#<varname> > echo $#list3 מבוא לתכנות מערכות - 234122
משתנים - רשימות • לא ניתן לשמור ב-C-Shell רשימות מקוננות > set list[1]=(1 2) set: Syntax error • ניתן לשמור מחרוזות המכילות רווחים בעזרת שימוש בגרשיים כפולים > set list=(Matam "Hello world" 17) > echo $#list : $list 3 : Matam Hello world 17 > echo $list[2] Hello world • השמת מחרוזות לרשימה ללא גרשיים תגרום לאיבוד הרווחים המדויקים שהיו בין המילים > set str=" Very crazy spaces " > set list=($str) > echo $list Very crazy spaces מבוא לתכנות מערכות - 234122
משתנים - רשימות • ניתן להתייחס למשתנה רגיל כאל רשימה בעלת איבר יחיד > set a=Hello > echo $a[1] Hello > set str="Hello world" > echo $str[2] str: Subscript out of range. > set list=(Hello world) > echo $str[2] world • מה קורה בפקודה הבא? מדוע? כיצד יש לתקן אותה? > set list=$list מבוא לתכנות מערכות - 234122
משתנים - ערכים מספריים • בניגוד לשפת C, למשתנים ב-C-Shell אין טיפוס. כל המשתנים הם מסוג רשימה של מחרוזות • הפקודה @ מבצעת פעולות חשבוניות על מחרוזת המכילות ערכי מספרים חוקיים ומציבה את התוצאה למשתנה • המשתנה יכול להיות לא מוגדר לפני הפקודה (כמו ב-set) > @ n = 3 + 4 > echo $n 7 > set a = 5 > @ b = 7 > @ sum = $a + $b > echo $sum 12 מבוא לתכנות מערכות - 234122
משתנים - פעולות חשבוניות • ניתן לבצע את הפעולות הבאות בעזרת @: • פעולות חשבוניות פשוטות: +, -, * ו-/ • השמות: = • הגדלות והקטנות: +=, -=, -- ו-++ (אין משמעות ל-pre ו-post) • ניתן להוסיף סוגריים, שימו לב שהאסוציאטיביות אינה סטנדרטית • הפקודה @ רגישה לרווחים, הקפידו לשיםרווח בין כל מספר לאופרטור • עבור פעולות ההשמה לא חובה להוסיף רווח • אם מנסים לבצע פעולות על ערכים לא מספרייםתתקבל שגיאה • ניתן לבצע פעולות חשבוניות רק על מספרים שלמים > @ mistake = 3 - 4 + 5 > echo $mistake -6 > @ n = 3+4 @: Badly formed number. > set str=Hello > @ n = 3 + $str @: Badly formed number. > @ n = 3.3 @: Badly formed number. למה צריך רווח אחרי ה-@? מבוא לתכנות מערכות - 234122
היסטוריה • C-Shell שומר את הפקודות האחרונות שהתבצעו ומאפשר ביצוען מחדש • הדרך הכי פשוטה לגשת להיסטוריה היא על ידי שימוש ב-↑ ו-↓ • ניתן לראות את הפקודות האחרונות שבוצעו על ידי הפקודה history • ניתן לבצע את האחרונה על ידי !! • ניתן לבצע את פקודה מספר על ידי ! • ניתן לבצע את הפקודה האחרונה שהתחילהב-<string> על ידי !<string> • מספר הפקודות שיישמרו מוגדר על ידיהמשתנה history > history 1 17:20 set a = 3 2 17:21 set b = 4 3 17:22 @ n = $b + $a 4 17:24 echo $n 5 17:28 history > !4 echo $n 7 > !! echo $n 7 > !set set b = 4 החלפות המתבצעות בגלל גישה להיסטוריה מודפסות בזמן ביצוען ולפני ביצוע הפקודה מבוא לתכנות מערכות - 234122
Command Substitution • ניתן "לשרשר" פקודות על ידי שימוש בגרשיים הפוכים ` • באנגלית: backticks או backquotes • C-Shell יבצע תחילה את הפקודה בתוך ` ` ויחליף אותה בטקסט שהודפס על ידיה > echo The length of $str is `echo -n $str | wc -c` The length of Hello is 5 > grep cow `cat farms_list.txt` farm1:3 farm2:2 > set a ="there are `ls | wc -l` files in `pwd` " > echo $a there are 662 files in /usr/bin farms_list.txt farm1 farm2 מבוא לתכנות מערכות - 234122
סוגי גרשיים • גרשיים כפולים, " ", משמשים לשמירה על רווחים • בתוך גרשיים כפולים לא תתבצענה החלפות עבור תבניות של שמות קבצים > echo "*.c" : *.c *.c : a.chello.c • משתמשים ב-" " כאשר יש צורך לשמור מחרוזות שלמות במדויק > set sentence="The dingo ate your baby" • גרשיים בודדים ' ', מונעים את כל החחלפות בתחומם > echo lets make some '$$$' lets make some $$$ • גרשיים הפוכים (backticks) מבצעים command substitution מבוא לתכנות מערכות - 234122
סוגי גרשיים • התוצאה המוחזרת מהפעלת פקודה ב-backticks מוחזרת כרשימה • עבור שימוש רגיל ב-backticksכל רווח, טאב או ירידת שורה יפרידו בין איברים ברשימה המתקבלת • אם ה-backticksבתוך " " רק ירידת שורה תפריד בין איברים > set a = `cat lines` > echo $#a 4 > echo 1:$a[1] 2:$a[2] 1:a 2:b > set a = "`cat lines`" > echo $#a 2 > echo 1:$a[1] 2:$a[2] 1:a b 2:c d line a b c d מבוא לתכנות מערכות - 234122
עבודת ה-shell • עבודת ה-Shell מתבצעת בלולאה: • הצגת prompt • המתנה לפקודה • עיבוד הפקודה עד לקבלת פקודה פשוטה • ביצוע הפקודה • לשם כך C-Shell מנהל מבני נתונים פנימיים אשר שומרים את ההיסטוריה, המשתנים וה-aliasesשהוגדרו • הטיפול בפקודה מתבצע בשלושה שלבים עיקריים • ניתוח הפקודה: הפקודה מופרדת למילים על פי רווחים וטאבים. התווים |,< ו-> מפרידים בין פקודות • עיבוד הפקודה:ביצוע החלפות מחרוזות הפקודה עד לקבלת פקודה פשוטה • ביצוע הפקודה: שליחת הפקודה הפשוטה שהתקבלה על ידי מערכת ההפעלה מבוא לתכנות מערכות - 234122
עיבוד הפקודה • בשלב זה מבצע C-Shell החלפות במחרוזת הפקודה עד לקבלת פקודה פשוטה: • אם הפקודה מכילה שימוש בפקודות קודמות (ע"י שימוש בסימן !) מתבצעת החלפה מההיסטוריה ומודפסת שורת הפקודה שנבחרה מההיסטוריה • אם המילה הראשונה בפקודה הינה aliasמתבצעת החלפה לפי ה-alias המוגדר • החלפת ביטויים המתחילים ב-$ בערכי המשתנים המתאימים • החלפת תבניות של שמות קבצים ברשימת הקבצים המתאימה • החלפת פקודות המופיעות בתוך גרשיים הפוכים בתוצאת הפקודה • אם באחד השלבים מתרחשת שגיאה העיבוד ייעצר ותודפס הודעה מתאימה מבוא לתכנות מערכות - 234122
ביצוע הפקודה • לאחר שהתקבלה פקודה סופית על C-Shell להפעיל את הפקודה המתאימה, הפקודות מתחלקות שני סוגים: • פקודות פנימיות של ה-Shell, למשל cd, set, unset, @... • פקודות חיצוניות - שמות קבצי הרצה, למשל ls, gcc, cat, sort... • אם שם הפקודה מתאים לפקודה פנימית היא תיבחר • אחרת ה-Shell יחפש בכל התיקיות המופיעות במשתנה pathקובץ הרצה בשם המתאים • אם נרצה לאפשר ל-Shell להריץ תכניות מהתיקיה הנוכחית ללא שימוש ב-‘.’ניתן להוסיף את התיקיה הנוכחית ל-path. • ניתן להשתמש בפקודה whichכדי לגלותאיזו תכנית תופעל עבור שם פקודה מסוים > set path=($path .) > hello Hello world! > which hello /usr/username/progs/hello > which gcc /usr/bin/gcc < which cd cd: shell built-in command. מבוא לתכנות מערכות - 234122
עבודה ב-C-Shell - סיכום • ל-C-Shell מגוון תוכנות מתקדמות המאפשרות למשתמש מתקדם לבצע פעולות מסובכות בקלות • ניתן להתייחס למספר קבצים בבת אחת על ידי שימוש בתבניות • ניתן להגדיר כינויים לפקודות ופרמטרים שכיחים בעזרת alias • ניתן לקרוא לפקודות שהתבצעו בעבר הקרוב בעזרת ההיסטוריה • ניתן לשמור ערכים במשתנים ולנצלם לפקודות ב-C-Shell • כל המשתנים ב-C-Shell הם מסוג רשימות של מחרוזות • ניתן להשתמש ב-` ` כדי לבצע החלפת פקודה בפלט שלה בשורות פקודה ב-C-Shell • כל התכונות של C-Shell מבוצעות על ידי החלפת מחרוזות פשוטה בשלב עיבוד הפקודה מבוא לתכנות מערכות - 234122
תסריטים הרצת תסריטים מבני בקרה ב-C-Shell דוגמאות השוואה בין C ו-C-Shell מבוא לתכנות מערכות - 234122
אוטומטיזציה • נניח (מקרה היפותטי לחלוטין) שברשותנו קבצי בדיקה ופלט לתכנית שלנו וברצוננו לבדוק את נכונות התכנית מול קבצים אלו • צריך לכתוב 3 פקודות לכל בדיקה • גם עם שימוש במנגנון ההיסטוריה הרצת הבדיקותמעיקה ולוקחת הרבה זמן מיותר • הפתרון:אוטומטיזציהשל הרצת הפקודות. ניצור קובץ אשר יכיל "תסריט" לפיו יורצו כל הפקודות לפי הסדר > (mtm_rentals< test1.in >! tmpout) >&! tmperr > diff expout1 tmpout > diff experr1 tmperr מבוא לתכנות מערכות - 234122
הרצת תסריט בעזרתsource • ניתן להריץ קובץ המכיל פקודות C-Shell (להלן תסריט - script) על ידי הפקודה source • הפקודות יבוצעו ב-Shell הנוכחי כאילו נכתבו בשורת הפקודה אחת אחרי השניה > source run_tests Running test 1 Running test 2 Running test 3 run_tests echo Running test 1 (mtm_rentals< test1.in >! tmpout) >&! tmperr diff expout1 tmpout diff experr1 tmperr echo Running test 2 (mtm_rentals < test2.in >! tmpout) >&! tmperr diff expout1 tmpout diff experr1 tmperr echo Running test 3 (mtm_rentals < test3.in >! tmpout) >&! tmperr diff expout1 tmpout diff experr1 tmperr מבוא לתכנות מערכות - 234122
תסריטי אתחול • בהתחברות של משתמש למערכת מורץ התסריט .login אשר בתיקית הבית של המשתמש • בפתיחת C-Shell חדש מורץ התסריט .cshrc • הרצות תסריטי האתחול מתבצעות באמצעות source, ולכן הן משפיעות על מצב ה-Shell .cshrc .login set path = ($path .) set savehist=1000 alias llls-l alias cdex2 cd ~mtm/public/1011a/ex2 alias GCC gcc-std=c99 -Wall \ -pedantic-errors -Werror # welcome message echo ------ Welcome `whoami` !-------- echo You are in `pwd` directory of \ `hostname` echo OS is `uname -s` # echo disk usage is `du -sh | cut -f1` echo `who | wc -l` users are logged in echo Today is `date` מבוא לתכנות מערכות - 234122
הרצת תסריט כקובץ הרצה • ניתן להריץ תסריט כפקודה: • בתחילת התסריט יש להוסיף את השורה #!/bin/tcsh -f • #! מסמן ל-Unix שהשורה הראשונה בקובץ מגדירה את התכנית לביצוע שאר הפקודות בקובץ • /bin/tcshהוא שם התכנית לביצוע הפקודות, במקרה שלנו C-Shell • -fמונע מה-Shell להריץ תסריטי אתחול • בנוסף יש להוסיף הרשאת ריצה לקובץ • כעת ניתן להריץ את התסריט כמו תכנית רגילה • בניגוד להרצה באמצעות פקודת source התסריט יבוצע בתהליך Shell חדש אשר יסתיים בסוף ריצת התסריט מבוא לתכנות מערכות - 234122
הרצת תסריט כקובץ הרצה • נמיר את תסריט הרצת הבדיקות שלנו לקובץ הרצה: • בעיה חדשה: התסריטמתחיל להסתבך, הוספתבדיקות נוספות משכפלתקוד בתסריט ולא נוחה (ייתכנו אלפי בדיקות) • פתרון: נשתמש במבני בקרה (תנאים ולולאות) בדומה לשפת C > chmoda+xrun_tests > ./run_tests Running test 1 Running test 2 Running test 3 run_tests #!/bin/tcsh -f echo Running test 1 (mtm_rentals < test1.in >! tmpout) >&! tmperr diff expout1 tmpout diff experr1 tmperr echo Running test 2 (mtm_rentals < test2.in >! tmpout) >&! tmperr diff expout1 tmpout diff experr1 tmperr echo Running test 3 (mtm_rentals < test3.in >! tmpout) >&! tmperr diff expout1 tmpout diff experr1 tmperr מבוא לתכנות מערכות - 234122
while • ניתן ליצור לולאות whileב-C-Shell: while (<expression>)<command1><command2>...end • הפקודות בגוף הלולאה יבוצעו כל עוד <expression> ממשיך להתקיים • לולאות while כמו שאר מבני הבקרה ניתנות לביצוע ישירותמהטרמינל > set i=1 > while ($i <= 3) while? echo $i while? @ i++ while? end 1 2 3 > ./run_tests Running test 1 Running test 2 Running test 3 run_tests #!/bin/tcsh -f set i=1 while ($i <= 3) echo Running test $i (mtm_rentals < test$i.in \ >! tmpout) >&! tmperr diff expout$itmpout diff experr$itmperr end מבוא לתכנות מערכות - 234122
foreach • לולאת foreach משמשת למעבר על רשימה בצורה נוחה foreach <varname> (<list>) <command1> <command2> ...end • <varname> הוא שם המשתנה שיכיל בכל פעם איבר מהרשימה • <list> היא רשימה של מחרוזות run_tests #!/bin/tcsh -f foreach test (test*.in) echo Running $test (mtm_rentals < $test >! tmpout) >&! tmperr diff expout_$test tmpout diff experr_$test tmperr end > ./run_tests Running test1.in Running test2.in Running test3.in מבוא לתכנות מערכות - 234122
if • ניתן להגדיר ב-C-Shell משפטי תנאי בשתי גרסאות • בשורה יחידה ללא else: if (<expression>) <command> • עבור בלוקים של פקודות (עם אפשרות ל-else): if (<expression>) then[commands] [else[more commands] ]endif מבוא לתכנות מערכות - 234122
ביטויים אפשריים ב-if ו-while • השוואת מחרוזותעל ידי == ו-=! • השוואת ערכים מספריים על ידי =>, =<, >, < • אם אחד הפרמטרים לאופרטור אינו ערך מספרי תתקבל שגיאה • התנאי -f <filename>בודק האםקיים קובץ בשם <filename> • התנאי -d <filename>בודק האםקיימת תיקיה בשם <filename> • ניתן להשתמש בסוגריים עבור קדימויות • ניתן להשתמש בפעולות חשבוניות עלערכים מספריים כמו +, -, * ו-/ • ניתן להשתמש באופרטורים לוגייםלהרכבת תנאים ||, && ו-! > set str1=Hello > if ($str1 == Hello) echo yes yes > if (7 < 20) echo yes yes > if (0 == 00) echo yes > if (0 <= 00) echo yes yes >if (-f a.txt) echo file exists > cat > a.txt Hello world! > if (-f a.txt) echo file exists yes > mkdirmtm > if ( !(-f b.txt && -d mtm) ) echo yes yes מבוא לתכנות מערכות - 234122
התאמת מחרוזות • האופרטור ~= מאפשר התאמת מחרוזת לתבנית • הארגומנט השמאלי הוא מחרוזת רגילה • הארגומנט הימני הוא תבנית אשר יכולה לכלול את הסימנים *, ? ו-[ ] כמו שתואר עבור תבניות של שמות קבצים • האופרטור ~! הוא השלילה של ~= > if (ends_with_z =~ *[zZ]) echo match match > if ("no point in string" !~ *.*) echo no point no point > if ("point - . - in string" !~ *.*) echo no point > set file = test4.in > if ($file =~ test*.in) echo test file test file מבוא לתכנות מערכות - 234122
switch • ניתן ליצור מבנה switchב-C-Shell: switch (<string>) case <pattern1>: <cshell commands> [breaksw] ... case <pattern_n>: <cshell commands> [breaksw] [default: <cshell commands>]endsw • הכללים ב-switch מקבלים תבניותוההתאמה מתבצעת כמו עבור אופרטור ~= • אם כמה כללים מתאימים ייבחר הכלל הראשוןשמתאים switch($c) case "[a-z]": echo small letter breaksw case "[A-Z]": echo big letter breaksw case "[0-9]": echo digit breaksw case '$': echo dollar sign breaksw default: echo neither letter nor digit endsw מבוא לתכנות מערכות - 234122
goto • ניתן להשתמש במשפטי goto כמו ב-C goto <label> ... <label>: ... • שימוש במשפטי goto הוא תכנות רע (ללא קשר לשפת התכנות) ולא נהוג להשתמש בהם • השימוש ב-goto יוצר קוד "ספגטי" קשה להבנה מבוא לתכנות מערכות - 234122
העברת פרמטרים בשורת הפקודה • כמו ב-C ניתן לגשת לפרמטרים המועברים בשורת הפקודה לתסריט • המשתנה argvמכיל את רשימת הפרמטרים לתסריט • argv[1] הוא הפרמטר הראשון (ולא שם התסריט) • דרך נוחה יותר לגשת לפרמטר ה-nהיא על ידי $n • $* תוחלף ברשימת כל הפרמטריםלתסריט • $0 תוחלף בשם התסריט echo_script #!/bin/tcsh -f echo command: $0 set number = 1 foreachparam ( $* ) echo parameter $number : $param @ number++ end > echo_scriptaaabbb ccc command: echo_script parameter 1 : aaa parameter 2 : bbb parameter 3 : ccc איך ניתן לדעת את מספר הפרמטרים שהתקבלו? מבוא לתכנות מערכות - 234122
קריאת קלט • ניתן לקרוא שורה מהקלט הסטנדרטי על ידי $< • הביטוי $<יוחלףעל ידי C-Shell בשורת קלט שתיקלט מהקלט הסטנדרטי • בד"כ נשתמש בסוגריים כדי לשמור את כל שורת הקלט • ניתן גם להשתמש במרכאות כדי לשמור עלהרווחים בשורה, כלומר "$<" > set input=$< Hello > echo $input Hello < set line=$< Hello world > echo $line Hello <set line=($<) Hello world > echo $line Hello world מבוא לתכנות מערכות - 234122
עבודה עם קבצים • לא ניתן ב-C-Shellלכתוב ולקרוא מקבצים בצורה ישירה כמו ב-C • כדי לאפשר עבודה עם קבצים נשתמש בהפניות קלט/פלט ותסריטי עזר > cat > file.txt The dingo ate your baby > main_script The first line is: The dingo ate your baby main_script auxiliary_script #!/bin/tcsh -f cat file.txt | auxiliary_script #!/bin/tcsh -f set line=($<) echo "The first line is:" echo "$line" מבוא לתכנות מערכות - 234122
חלוקה פונקציונלית של תסריטים • מאחר ולא ניתן להגדיר פונקציות ב-C-Shell נחלק את הקוד שלנו לתסריטים שונים בקבצים נפרדים • שימו לב שניתן להשתמש ב-C-Shell כדי לערבב תסריטים עם תכניות שנכתבו בשפות שונות בקלות - מכאן מגיע כוחן של שפות תסריטים - scripting languages • ניתן להעביר פרמטרים לתסריטי עזר • בעזרת פרמטרים בשרות הפקודה • בעזרת pipeline • בעזרת קבצים זמניים • ניתן לקבל ערכים חזרה מתסריטי עזר • בעזרת פלט מתסריט העזר מבוא לתכנות מערכות - 234122
העברת והחזרת ערכים • החזרת ערכים מתסריטי העזר יכולה להתבצע בעזרת • שימוש ב-backticks set result = `helper_script` • העברה לתסריט אחר ב-pipeline helper_script | another_script • דרך קובץ זמני helper_script > temp • העברת פרמטרים לתסריטי עזר יכולה להתבצע בדרכים הבאות • בשורת הפקודה helper_script $arg1 $arg2 • בעזרת pipeline echo $arg1 $arg2 | helper_script • דרך קובץ זמני echo $arg1 $arg2 > temp helper_script < temp מבוא לתכנות מערכות - 234122
דוגמה • כתבו תסריט בשם search אשר מקבל מחרוזת ושמות קבצים ומדפיס את כל השורות המופיעות בקבצים הללו המכילות את המחרוזת המבוקשת • אם מתקבל שם תיקיה, ייבדקו כל הקבצים תחת התיקיה הזו רקורסיבית > search Blue scene35.txt scene35.txt:37: LAUNCELOT: Blue. scene35.txt:55: GALAHAD: Blue. No yel-- Auuuuuuuugh! > search swallow scene*.txt scene1.txt:50: GUARD #1: But then of course African swallows are not migratory. scene1.txt:54: GUARD #2: Wait a minute -- supposing two swallows carried it together? scene35.txt:63: BEDEMIR: How do know so much about swallows? > search cow farms farms/animals/animals.txt:8: cow farms/farm1.txt:2: cow Betsy farms/farm1.txt:3: slim cow Dazy farms/farm1.txt:4: fat cow Burger farms/farm1.txt:5: two cows Dartsy & Teo farms/farm2.txt:2: cow Leni farms/farm2.txt:4: cow Oreo מבוא לתכנות מערכות - 234122
פתרון • לא ניתן לקרוא את הקבצים ישירות, לכן נחלק את הפתרון לשני תסריטים: • התסריט הראשי search יפעיל את התסריט המשני על כל קובץ • התסריט הנוסף search_in_file יקבל את תוכן הקובץ בקלט הסטנדרטי וידפיס את השורות המתאימות search search_in_file #!/bin/tcsh-f foreachf ($argv[2-]) if (-f $f) then cat $f | search_in_file"$1"$f endif if (-d $f) then search "$1" $f/* endif end #!/bin/tcsh -f setline = "$<" setn=1 while("$line" != "") if("$line" =~ *"$1"*) then echo ${2}:${n}: "$line" endif @ n++ setline = "$<" end מבוא לתכנות מערכות - 234122
דוגמה נוספת • נתון קובץ בשם football.txt המכיל נתונים על שערים שהובקעו במשחקי כדורגל • כל שורה בקובץ מציינת שם של שחקן, מספר השערים שהבקיע במשחק שנערך בתאריך מסוים, שם הקבוצה בה הוא שיחק ושם הקבוצה היריבה • ברצוננו לכתוב תסריט בשם player אשר יקבל כפרמטר שם של שחקןוידפיס את כל השורות עבורומהקובץ football.txt ואת סכוםמספר השערים שהבקיע football.txt AlonMiz. 2 23/10/93 Macabi-Haifa Macabi-Tel-Aviv IzakZoh. 1 12/11/93 Macabi-Tel-Aviv Hapoel-Beer-Sheva Ronen Ha. 3 27/12/93 Hapoel-Tel-Aviv Macabi-Tel-AvivReuven A. 2 12/11/93 Macabi-Haifa Hapoel-Tel-Aviv EyalBer. 1 20/11/93 Macabi-Haifa Macabi-Tel-Aviv IzakZoh. 1 12/11/93 Macabi-Tel-Aviv Hapoel-Haifa AlonMiz. 2 26/10/93 Macabi-Haifa Beitar-Jerusalem IzakZoh. 2 12/12/93 Macabi-Tel-Aviv Macabi-Hiafa AlonMiz. 2 23/12/93 Macabi-Haifa Macabi-Pet-Tikva Ronen Ha. 3 27/11/93 Hapoel-Tel-Aviv Macabi-Haifa > player "AlonMiz." AlonMiz. 2 23/10/93 Macabi-Haifa Macabi-Tel-Aviv AlonMiz. 2 26/10/93 Macabi-Haifa Beitar-Jerusalem AlonMiz. 2 23/12/93 Macabi-Haifa Macabi-Pet-Tikva Total number of goals: 6 מבוא לתכנות מערכות - 234122
פתרון • לא נוכל לקרוא את הקובץfootball.txt ישירות מתוך playerולכן ניעזר בתסריט עזר • נשתמש בתסריט search שכתבנומקודם כדי לקבל רק את השורותהרלוונטיות • ניצור את התסריט calc_total אשר יקבלאת השורות הרלוונטיות לשחקן וידפיסאת השורות וסכום השערים calc_total #!/bin/tcsh -f setline = ($<) setsum = 0 while($#line!= 0) @ sum = $sum + $line[4] echo $line[2-] setline = ($<) end echo"total number of goals: $sum" התבנית הכללית של עיבוד קלט התבנית הכללית של עיבוד קלט התבנית הכללית של עיבוד קלט player #!/bin/tcsh -f search "$1"football.txt | calc_total מבוא לתכנות מערכות - 234122
דוגמה שלישית • כתבו תסריט לדירוג שחקנים בשם best_player אשר יקבל רשימה של שמות שחקנים בשורת הפקודה וידפיס את שם השחקן שהבקיע את מרב הגולים • אם קיימים מספר שחקנים שהבקיעו את מרב הגולים יודפסו שמות כל השחקנים • לכל שחקן יש להדפיס את שמו ומספר הגולים שהבקיע > best_player "AlonMiz." "IzakZoh." "Ronen Ha." "Reuven A." AlonMiz. 6 Ronen Ha. 6 מבוא לתכנות מערכות - 234122
פתרון best_player calc_score print_best max #!/bin/tcsh -f setline = ($<) while ($#line> 0) if ($line[3] == $1) then echo $line endif setline = ($<) end #!/bin/tcsh -f setmax = 0 setline= ($<) while ($#line > 0) if($line[3] > $max) then setmax = $line[3] endif setline = ($<) end echo $max #!/bin/tcsh -f @ i = 1 while ( $i <= $#argv ) search "$argv[$i]" football.txt | calc_score >>! temp @ i++ end cat temp | print_best`cat temp | max` if (-f temp) rm -f temp #!/bin/tcsh -f setline = ($<) setsum = 0 setplayer_name = ($line[2-3]) while($#line!= 0) @ sum+= $line[4] setline = ($<) end echo$player_name$sum מבוא לתכנות מערכות - 234122