610 likes | 921 Views
תרגול 7. תסריטים ניהול תהליכים ב- UNIX. לי-טל משיח litalma@cs.technion.ac.il נערך והורחב ע'' ודים אייזנברג. תסריטים (קבצי script ). קבצים אשר מכילים סדרה של פקודות shell מהווים מעין תוכניות הכתובות ב שפת ה- shell נכתבים ב קובץ טקסט רגיל ניתן להריץ אותם מספר פעמים אין צורך בהידור
E N D
תרגול 7 תסריטים ניהול תהליכים ב-UNIX לי-טל משיח litalma@cs.technion.ac.il נערך והורחב ע'' ודים אייזנברג
תסריטים (קבצי script) • קבציםאשר מכילים סדרה של פקודות shell • מהווים מעין תוכניותהכתובות בשפת ה-shell • נכתבים בקובץ טקסט רגיל • ניתן להריץ אותם מספר פעמים • אין צורך בהידור • לדוגמא, קובץ טקסט בשם clean echo “Cleaning !” rm *.o mv ex1 ex1.old
הרצת תסריטים • דרך אחת - הפקודה source > source clean • תריץ את התסריט clean • במידה וקובץ clean מכיל את הפקודות מהשקף הקודם: • תודפס הודעה “Cleaning !” • יימחקו כל קבצי אובייקט בתיקייה הנוכחית • שם הקובץ ex1 ישונה לקובץ ex1.old
שפת התסריטים C-shell • שפת התסריטים C-shell היא שפת תכנות לכל דבר • משתנים • כולם מאותו טיפוס - מחרוזת או רשימה של מחרוזות • פעולות אריתמטיות • רק בשלמים • לולאות(while ואחרות) • משפטי תנאי (if else) • הערות: מסימן # ועד סוף השורה • ,goto, switch ודברים אחרים בדומה לשפת C בשביל מה צריך עוד שפת תכנות ??? התשובה בסוף התרגול
ניצול יכולות של C-shell • בכתיבת תסריטים ניתן להיעזר בכל היכולות שלC-shell שלמדנו : • משתנים • Alias Substitution • File name expansion • Command Substitution • backticks `` • I/O redirection • pipelining
לולאות ב- C-shell: repeat • cshell מבצע את הפקודה command בדיוק count פעמים : • שימו לב שכל לולאה של C-shell ניתן להריץ גם ב- command line repeat <count> <cshell command> <repeat 3 echo Congratulations, Shifra ! Congratulations, Shifra ! Congratulations, Shifra ! Congratulations, Shifra ! >
לולאות ב- C-shell: while while (<expression>) <cshell commands> end > source count10 0 1 2 3 4 5 6 7 8 9 # count10 script: @ i = 0 while ($i<10) echo $i @ i++ end
לולאות ב- C-shell: foreach foreach <variable> (<list>) <cshell commands> end • הלולאה מתבצעת מספר פעמים השווה לגודל הרשימה list • בכל איטרציהשל הלולאה, המשתנה variableמקבל ערך אחד מהרשימה לפי הסדר
foreach : דוגמאות # final_vote script set number = 1 foreach name (Itai Yossi Leon EinavShifra) echo for $name send the number $number @ number++ end > source final_vote for Itai send the number 1 for Yossi send the number 2 for Leon send the number 3 for Einav send the number 4 for Shifra send the number 5
foreach : דוגמאות • יצירת העתק של כל קבצי c בתיקייה הנוכחית: foreach FILE (*.c) cp $FILE $FILE.back end
משפטי תנאי (if ... else) • שתי גרסאות: • if עם פקודה אחת, בלי else if (<expression>) <one cshell command> • if עם כמה פקודות ועם אופציה ל-else if (<expression>) then <cshell commands> [else <cshell commands>] endif בגרסה הזאת חייבים then בגרסה הזאת חייבים then וגם endif
דוגמא של if if ($votes_for_yossi > $votes_for_shifra) then echo Yossi won ! else echo Shifra won ! endif
תנאים בתוך משפטי if • השוואת מחרוזות: if ($winner == "Yossi") … • השוואת מספרים: if ($votes > 1000000) … • תנאים מיוחדים ל-C-shell if (-d aaa) ... • משוערך ל-true אם התיקייהבשם aaa קיימת בתוך התיקייה הנוכחית if (-f aaa) ... • משוערך ל-true אם הקובץ בשם aaa קיים בתיקייה הנוכחית (והוא לא תיקייה)
תנאים בתוך משפטי if- התאמת מחרוזות • אופרטור ~= • משוערך ל-true אם המחרוזת בצד שמאל מתאימה לתבנית בצד ימין • התבנית יכולה לכלול סימנים מיוחדים כגון: *,? או[] שמשמעותם תוארה בתרגול הקודם • השלילהשל האופרטור ~= היא ~!
תנאים בתוך משפטי if:התאמה בין מחרוזות • אופרטורים =~, !~ > if (end_with_z =~ *[zZ]) echo match match > if ("no point in string" !~ *.*) echo "no point" no point > if ("point - . - in string" !~ *.*) echo "no point" >
סיכום:אופרטורים בתוך משפטי if • אופרטורים של השוואה • <, >, =<, =>משווים בין מספרים • ==, =!, ~=, ~! משווים בין מחרוזות • ניתן להשתמש באופרטורים ==, =! גם להשוואה בין מספרים אך ההשוואה תתבצע בין המחרוזות שמייצגות את המספרים • למה ישוערכו הביטויים הבאים ? • 8 <= 08 • 8 >= 08 • 8 == 08 • 8 == 8 • 8 != 08 • 8 !~ 08 • 8 =~ 08
סיכום:אופרטורים בתוך משפטי if • אופרטוריםלעבודה עם קבצים ותיקיות : -f,-d • אופרטורים לוגיים להרכבת תנאים • !, &&, || כמו ב-C • ניתן להשתמש בסוגריים כמו ב-C if (($winner == "Yossi") || ($winner == "Einav")) then echo the Bublil family won ! endif
משפטי switch switch (<variable or string>) case <pattern1>: <cshell commands> [breaksw] case <pattern2>: <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
משפטי goto goto <label> • מבצע קפיצה למקום המסומן ב- <label>: • כמו ב-C goto error ... error: ... גם ב C-Shell וגם ב-C שימוש ב-goto נחשב לתכנות רע ! משתמשים במנגנון goto רק כשכל האלטרנטיבות האחרות יותר גרועות
הפקודהprintf printf format strings • מדפיסהאת המחרוזות stringsלפי הפורמט format • הפורמט דומה לפורמט של הפקודה printf ב-C. • הפורמט יכול להכיל תווים רגילים או תווי עריכה • דוגמאות של תווי עריכה: • %s- מדפיסה את המחרוזת המתאימה מתוך הרשימה strings. • - %[-]m[.n]sמדפיסה את המחרוזת המתאימה מרשימת המחרוזות כך שהתוצאה תהיה באורך של mתווים, עם אפשרות להגבלת מספר התווים המודפסים (מתוך המחרוזת הספציפית) ל - n. המחרוזת מיושרת לימין אלא אם משתמשים באופרטור -.
הפקודה printf - דוגמאות > echo $HOME /home/rotics > > printf “My files are in %s\n“ $HOME My files are in /home/rotics > > printf “number is : %10.5s” 123456789a number is: 12345 > > printf “number is : #%-10.3s# %s\n” "123456789a“ xxx number is: #123 # xxx > > printf “My files are in %s\n“ $HOME “my PC” My files are in /home/rotics My files are in my PC שימו לב מה קורה כאשר ישנן יותר מחרוזות ברשימה strings מאשר תווי עריכה(%s)
הרצת תסריטים • ניתן להריץתסריטים בשתי דרכים: • ע''יהפקודה source • התסריט מתבצע בסביבה הנוכחית (ב-shell הנוכחי) • יכול לשנות את משתני הסביבה הנוכחית • ישירות • התסריט מתבצע בסביבה חדשה משלו (ב-shell חדש) • לא יכול לשנות את משתני הסביבה הנוכחית • נהוגלהריץ את התסריטים בדרך השנייה, אלא אם רוצים לשנות את משתני הסביבה הנוכחית
הרצת תסריטים ישירות • לפני שמריצים תסריט בפעם הראשונה חייבים לתת לו הרשאת הרצה > chmodu+xmyscript • אחרי שיש לקובץ הרשאת הרצה, ניתן להריץ אותו בצורה ישירה: > myscript • כמובן המשתנה path צריך להכיל את התיקיה הנוכחית, אחרת צריך להריץ בצורה הבאה: > ./myscript
הרצת קבצי סקריפט • כדי שהshell- הנוכחי יידע איזה shell חדש להפעיל לצורך ביצוע התסריט, יש להוסיף לתסריט שורה ראשונה • במחשבים שונים כתובת ה-shell המריץ יכולה להיות שונה • ניתן לברר מהי באמצעות הפקודה which > which tcsh /bin/tcsh #! /bin/tcsh -f אומר ל-shell לא לבצע תסריטי אתחול ולהתחיל יותר מהר כתובת ה-shell שיריץ את התסריט
תסריטי אתחול • תסריטי אתחול ((setup הם תסריטים מיוחדים אשר מורצים אוטומטית ע"י המערכת בזמנים מסוימים. • .loginמבוצע עם כניסה לחשבון • .cshrcמבוצע בהתחלת הרצה של כל shell(מסוג C-Shell) • נהוג להשתמש בהם • להתאמה אישית של סביבת העבודה. למשל, • אתחול משתני סביבה נחוצים לעבודה • נתינת כינויים לפקודות (alias) • לביצוע משימותשנרצה שיבוצעו בצורה אוטומטית בזמנים של כניסה לחשבון/פתיחת shell חדש
דוגמא לתסריט .cshrc set path = ($path .) alias cdex2 cd ~mtm/public/0809b/ex2 alias gccgcc -Wall -pedantic-errors -Werror set savehist=1000
דוגמא לתסריט .login # 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 # print a warning about Matam assignment set today = `date +%j` set assignment_day = 151 set days_in_this_year = 365 if( $today > $assignment_day) then @ remaining_days = $assignment_day + ($days_in_this_year - $today) else @ remaining_days = $assignment_day - $today endif date echo $remaining_days days until the submission of Matam assignment 2 !
העברת פרמטרים לתסריטים • ניתן להעביר פרמטרים לתסריטים בדומה להעברת פרמטרים לתוכנית C • ב-C ניתן להתייחס לפרמטרים ע''י מערך argv • בתסריט C-Shellניתן להתייחס לפרמטרים בצורה הבאה: • $0- הפקודה עצמה • ${n}או ${argv[n]}- הפרמטר ה-n • $* - רשימת כל הפרמטרים • ${#argv}- מספר הפרמטרים
דוגמא: echo_script #! /bin/tcsh -f echo command: $0 set number = 1 foreachparam ( $* ) echo parameter $number : $param @ number++ end > echo_scriptaaabbbccc command: ./echo_script parameter 1 : aaa parameter 2 : bbb parameter 3 : ccc
קלט בשפת C-Shell : אופרטור $< • אופרטור $< • גורם לשורה שלמה להיקרא מערוץ הקלט הסטנדרטי set line = “$<“ • שורה שלמה אחת תיקרא מערוץ הקלט הסטנדרטי ותושם למשתנה line בתור מחרוזת (כולל רווחים) • נהוג לבצע ישר המרה לרשימה על ידי שימוש ב-() set line = ($<) • השורהמהקלט הסטנדרטי תופרד למילים ותושם למשתנה line בתור רשימה • אחרי הביצוע של השורה הזאת ניתן לבצע פעולות רגילות של C-Shell על רשימות : $line[1], shift, ${#line}, $line[3-]וכו' • אין דרך טבעית וישירה לקרוא מקבצים ב-C-Shell • רק מהקלט הסטנדרטי
חלוקה פונקציונאלית של תסריטים • בשפת C למדנו לחלקתוכניות למודולים ופונקציות • לשיפור קריאות, שימוש חוזר בקוד וכו' • בשפת C-Shellאין פונקציות • מחלקים תסריט ל"התסריט הראשי" שמשתמש ב"תסריטי עזר" • כל "תסריט עזר" הוא תסריט בפני עצמו • ניתן להריץ אותו בנפרד • הוא יכול להשתמש בתסריטים ותוכנות אחרות
תסריטים: העברת פרמטרים • בשורת הארגומנטים helper_scriptaaabbb 17 • ב-pipelineלתוך הערוץ הקלט הסטנדרטי echo aaabbb 17 | helper_script • דרך קובץ זמני echo aaabbb 17 > tmp helper_script < tmp
תסריטים: ערכי חזרה • על ידי backticks set result = `helper_scriptaaabbb 17` • העברה לתסריט אחר ב-pipeline helper_scriptaaabbb 17 | another_script • דרך קובץ זמני helper_scriptaaabbb 17 > tmp
קלט מקבצים • כאמור, איןב-C-shellדרך טבעית וישירה לקרוא קלט מקבצים • הדרך הטבעית היא לקרוא שורות מערוץ הקלט הסטנדרטי על ידי אופרטור $< • לכן משתמשים בשיטה הבאה : • מחלקיםאת משימת קריאת הקלט לשני תסריטים: • "התסריט הראשי" • "תסריט העזר" • התסריט הראשי ישפוך את תוכן הקובץ ב-pipelineלתסריט העזר: cat file | helper_script • או יחבר את הקובץ ישירות לערוץ הקלט הסטנדרטי: helper_script < file • תוכן הקובץ יועבר לערוץ הקלט הסטנדרטי של תסריט העזר • תסריט העזר יקרא מהקלט הסטנדרטי על ידי אופרטור $<
דוגמא • נתון קובץ footballהמכיל נתונים על שערים שהובקעו במשחקי כדורגל. • כל שורה בקובץ מציינת שם של שחקן, מספר השערים שהבקיע במשחק שנערך בתאריך מסוים, שם הקבוצה בה הוא שיחק ושם הקבוצה היריבה. >cat football 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-Aviv Reuven A. 2 12/11/93 Macabi-Haifa Hapoel-Tel-Aviv Eyal Ber. 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. התסריט • יקבל כפרמטר שם מלא של שחקן • ידפיסאת כל השורותשל הקובץ football בהן מופיע שם השחקן • ובנוסף ידפיס את סכום מספר השערים שהוא הבקיע. • לדוגמא, הפלט עבור שורת הקלט AlonMiz. יהיה: > 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
פתרון • בתסריט player לא נוכל לבצע קריאת קלט מהקובץ football • ולכן ניעזר בתסריט אחר בשם calc_total • התסריט playerישפוך את השורות שבהם מופיע השחקן ב-pipeline ל-calc_total • calc_totalיקרא את שורות שבהם מופיע השחקן מערוץ הקלט הסטנדרטי על ידי אופרטור $<
פתרון > cat player #! /bin/tcsh-f grep "$1" football | calc-total בפונט מודגש: התבנית הכללית של עיבוד הקלט > cat calc-total #! /bin/tcsh-f set line = ($<) set sum = 0 while (${#line} != 0) @ sum = $sum + $line[3] echo $line set line = ($<) end echo "total number of goals: $sum"
דוגמא נוספת • עלינו לכתוב תסריט לדירוג שחקנים בשם scores • השמות המלאים של השחקנים מועברים כפרמטרים בשורת הפקודה • הדירוג של כל שחקן ייקבע על פי מספר השערים שהוא הבקיע לפי הנתונים המוכלים בקובץ football • שני שחקנים שהבקיעו מספר זהה של שערים יקבלו דירוג זהה. • התסריט ידפיסעבור כל שחקן את דירוגו,את שמו המלא ואת מספר השערים שהבקיע
תזכורת: קובץ football >cat football 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-Aviv Reuven A. 2 12/11/93 Macabi-Haifa Hapoel-Tel-Aviv Eyal Ber. 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
דוגמא להפעלת התסריט > scores "AlonMiz." "IzakZoh." "Ronen Ha." "Reuven A." 1 AlonMiz. 6 1 Ronen Ha. 6 2 IzakZoh. 4 3 Reuven A. 2
פתרון > cat scores #! /bin/tcsh-f @ i = 1 while ( $i <= ${#argv} ) grep "${argv[$i]}" football | calc_score >>! temp @ i++ end sort -n -k 3 -r temp | calc_place if (-f temp) then rm -f temp endif
פתרון > cat calc_score #! /bin/tcsh-f set line = ($<) set sum = 0 set player_name = ($line[1-2]) while (${#line} != 0) @ sum = $sum + $line[3] set line = ($<) end echo "$player_name $sum" > cat calc_place #! /bin/tcsh-f set line = ($<) set place = 1 @ goals = $line[3] while (${#line} != 0) if ($goals != $line[3]) then @ place++ @ goals = $line[3] endif echo "$place $line" set line = ($<) end
C-shell לעומת C • שפת C-shell היא שפת תסריטים(scripting language) • קיימות שפות תסריטים מתקדמות יותר:Perl, Tcl, PHP, JavaScript, Python, Ruby • מזל טוב! למדתם שפת התסריטים הראשונה שלכם!
C-shell לעומת C • שפת C היא שפת תכנות מערכת(system language) • קיימות שפות תכנות מערכת מתקדמות יותר:C++, Java, C#
יתרונות של C-shell לעומת C • קל להריץ תוכניות אחרות • להעביר פרמטרים • לשלב פלט של תוכניות • לשלב בין תוכניות • יתרון גדול בסביבת Unix שבה יש הרבה תוכניות סטנדרטיות(sort, grep,cut) • עבודה נוחה עם קבצים • עבודה נוחה עם מחרוזות • עבודה נוחה עם משתנים ותסריטי עזר • לא צריך להגדיר טיפוסים, להכריז על משתנים ופונקציות • ניתן לפתחתוכניות בזמן קצר יותר ! • תוכנית שכתובה בשפת תסריטים יכולה להיות פי 5 קצרה יותר מאותה התוכנית שכתובה בשפת C
חסרונות של C-shell לעומת C • השפה פחות בטיחותית - קל להכניס באגים • אין בדיקות טיפוסים • לא חייבים להגדיר משתנים לפני השימוש בהם • לדוגמא, איפה הבאג בקוד הבא ? • מה יודפס בסוף הריצה שלו ? set deposits = ($*) set account_balance = 100 foreach d ($deposits) @ acount_balance = $account_balance + $d end echo $account_balance
חסרונות של C-shell לעומת C • זמן ביצוע של תוכנית שכתובה ב-C-shell יכול להיות פי כמה מאות ארוך יותר לעומת אותה התוכנית שכתובה ב-C
שימוש ב-C-shell לעומת C • משתמשים ב-C-shell כאשר • זמן ביצוע לא קריטי • למשל כאשר המשימה מספיק קטנה כך שזמן הביצוע לא מורגש • איכות התוכנה לא קריטית • או שהתכנית מספיק קטנה כדי שיהיה אפשר למצוא בה את כל הבאגים בצורה קלה • משתמשים ב-C כאשר • זמן ביצוע חשוב • איכות התוכנה היא קריטית