המצגת נטענת. אנא המתן

המצגת נטענת. אנא המתן

שרשור פקודות באמצעות Pipeline עבודה ב- bash כתיבת תסריטים ב- bash

מצגות קשורות


מצגת בנושא: "שרשור פקודות באמצעות Pipeline עבודה ב- bash כתיבת תסריטים ב- bash"— תמליל מצגת:

1 שרשור פקודות באמצעות Pipeline עבודה ב- bash כתיבת תסריטים ב- bash
תרגול מס' 6 שרשור פקודות באמצעות Pipeline עבודה ב- bash כתיבת תסריטים ב- bash

2 Pipeline הרכבת פקודות Pipeline מבוא לתכנות מערכות

3 הרכבת פקודות נניח שברצוננו להדפיס את התוכן של תיקיה המכילה הרבה קבצים
לא נוכל במצב זה לראות את כל הקבצים נוכל להשתמש בהפנית פלט הפקודה ls לקובץ זמני ולאחר מכן שימוש ב-more: > ls -l > tmp > more < tmp > rm tmp מבוא לתכנות מערכות

4 Pipeline כדי לחסוך את הבלגן שבטיפול בקבצים זמניים ניתן להשתמש ב-pipeline המחבר את הפלט של פקודה אחת לקלט של פקודה שניה ישירות כדי לחבר שתי פקודות כך נרשום אותן אחת אחרי השניה כאשר ביניהן מפריד התו ‘|’ על מנת לראות בשלבים את התוכן של תיקיה גדולה נוכל לרשום כעת: > ls -l | more ניתן לשלב מספר תכניות בבת אחת: > command1| command2| command3 command1 stdout command2 stdin stdout command3 stdin מבוא לתכנות מערכות

5 Pipeline - סיכום ניתן להשתמש בתו ‘|’ כדי לחבר את הפלט של תכנית א' עם הקלט של תכנית ב' בעזרת pipeline נוכל להרכיב פקודות מורכבות בעבודה בטרמינל מתכניות פשוטות מבוא לתכנות מערכות

6 תכונות מתקדמות של bash עבודת ה-bash
מבוא לתכנות מערכות

7 משתנים ניתן להציב ערך למשתנה ב-bash על ידי השמה ישירה
> <varname>=<value> אין צורך להכריז על משתנים ב- bash, לאחר ביצוע השמה למשתנה הוא מוגדר אוטומטית ניתן להחליף ערך של משתנה על ידי השמה נוספת אסור לשים רווח בין סימן ההשמה לשם המשתנה והערך אם יהיה כזה רווח ה-Shell ינסה להריץ פקודה ששמה כשם המשתנה ניתן לקרוא משתנים על ידי שימוש באופרטור $, למשל: > echo $<varname> השימוש במשתנה הוא פשוט החלפת הקריאה למשתנה בערך השמור בו מבוא לתכנות מערכות

8 משתנים ניתן לבטל הגדרה של משתנה על ידי הפקודה unset <varname>
< unset my_variable בדרך כלל אין צורך בכך אם מנסים לקרוא משתנה שאינו מוגדר אז לא מודפס כלום ניתן להשתמש ב-{ } כדי לסמן מהו שם המשתנה לאופרטור $ מועיל כאשר השימוש במשתנה צמוד למחרוזת נוספת > a=Hell > echo $ao > echo ${a}o Hello $ao משתנה לא מוגדר, לכן לא מודפס כלום מבוא לתכנות מערכות

9 משתנים - מערכים ניתן לשמור במשתנה יחיד מערך של מחרוזות על ידי שימוש בסוגריים > arr=(1 2 3) קריאת משתנה שקולה לקריאת האיבר הראשון (אינדקס 0) מהרשימה > echo $arr 1 קריאת כל המערך מתבצעת על ידי שימוש ב-[*] ובסוגריים מסולסלים: > echo ${arr[*]{ 1 2 3 > echo $arr[*] 1[*] ניתן לגשת לאיבר יחיד בעזרת אופרטור [ ] ניתן להוסיף איברים חדשים למערך בשיטה זו > arr[3] = 4 > echo ${arr[*]{ כאשר מאתחלים מערך בסוגריים, ההפרדה נעשית באמצעות הרווח מבוא לתכנות מערכות

10 משתנים - מערכים ניתן לקבל את מספר האיברים במערך בעזרת {#<varname>[*]}$: > echo ${#arr[*]} 4 ניתן לגשת לתחומים של איברים במערך > echo A:${arr[*]:0:2} A:1 2 > echo B:${arr[*]:1} B:2 3 4 > echo C:${arr[*]:2:1} C:3 המספר הראשון מציין את אינדקס ההתחלה של התחום המספר השני מציין את מספר האיברים בתחום אם הוא אינו מופיע יודפסו כל האיברים החל מהאינדקס המבוקש מבוא לתכנות מערכות

11 משתנים - מחרוזות ניתן לשמור מחרוזות המכילות רווחים בעזרת שימוש בגרשיים כפולים > list=(Matam "Hello world" 17) > echo ${#list[*]} : ${list[*]} 3 : Matam Hello world 17 > echo ${list[1]} Hello world קריאת משתנה שערכו מכיל רווחים תגרום לאיבוד הרווחים המדויקים שהיו בין המילים קודם לכן > str=" Very crazy spaces " > echo $str Very crazy spaces רשימות מקוננות: לא ניתן לשמור רשימה שלמה כאיבר של רשימה. העלמת הרווחים נוחה מאוד לעיבוד מחרוזות, השמה לרשימה תיפטר מכל הבלגן ותאפשר לעבור על רשימת המילים בצורה מסודרת. מבוא לתכנות מערכות

12 משתנים - מחרוזות ניתן להשתמש בגרשיים כפולים כדי לשמור על הרווחים בזמן ההחלפה > echo "$str" Very crazy spaces ניתן לקבל את מספר התווים במשתנה ע"י שימוש ב-#, בדומה לקבלת אורכו של מערך > echo ${#str} 29 רשימות מקוננות: לא ניתן לשמור רשימה שלמה כאיבר של רשימה. העלמת הרווחים נוחה מאוד לעיבוד מחרוזות, השמה לרשימה תיפטר מכל הבלגן ותאפשר לעבור על רשימת המילים בצורה מסודרת. מבוא לתכנות מערכות

13 משתנים - מערכים ניתן להתייחס למשתנה רגיל כאל רשימה בעלת איבר יחיד
> a=Hello > echo ${a[0]} Hello > str="Hello world" > echo ${str[1]} > list=(Hello world) > echo ${list[1]} world בעזרת unset נוכל לבטל את הרשימה או איבר אחד מתוך הרשימה > unset list[1] > echo ${list[*]} Hello כדי למחוק את כל הרשימה נבצע הפקודה: unset list אם עושים unset לאיבר באמצע הרשימה האיבר נמחק, גודל הרשימה קטן, אבל האינדקסים של האיברים לא משתנים מבוא לתכנות מערכות

14 משתנים - חישוב ביטויים בניגוד לשפת C, למשתנים ב-bash אין טיפוס. כל המשתנים הם מסוג מערך של מחרוזות ניתן להחליף ביטוי אריתמטי בערכו על ידי $((<expression>)) הערך המספרי של המחרוזות ישמש בחישוב הביטוי משתנים יוחלפו בערכם (גם ללא $) אם אחד הארגומנטים אינו מספר, ערכו יהיה 0 בחישוב משתנה שאינו מוגדר, או ערכו אינו מספר יחושב כ-0 > echo $((3 + 4)) 7 > n=$((3 * 7 + 4)) > echo $n 25 > a=5 > b=7 > sum=$(($a + $b)) > echo $sum 12 > echo $(( Hello )) > a=4 > echo $(( 2 + a )) 6 > str="Hello world!" > num=17 > echo $(( $str * $num )) מבוא לתכנות מערכות

15 משתנים - פעולות חשבוניות
ניתן לבצע פעולות חשבוניות שונות בדומה לשפת C: פעולות חשבוניות פשוטות: +, -, * ו-/ השמות: = הגדלות והקטנות: =+, =-, -- ו-++ ניתן לבצע פעולות חשבוניות רק על מספרים שלמים ניתן להשתמש גם בפקודה let כדי לבצע פעולה חשבונית נוח כאשר רוצים להשתמש ב-++ ואין צורך בערך ההחזרה פעולות נוספות אפשריות אך לא מועילות במיוחד בד"כ: ==, =!, =*, =/ ועוד... > let n=3+4 > let n++ > echo $n 8 > $((n++)) -bash: 8: command not found Bash מנסה לבצע פקודה בשם "8" ונכשל מבוא לתכנות מערכות

16 היסטוריה Bash שומר את הפקודות האחרונות שהתבצעו ומאפשר ביצוען מחדש הדרך הכי פשוטה לגשת להיסטוריה היא על ידי שימוש ב-↑ ו-↓ ניתן לראות את הפקודות האחרונות שבוצעו על ידי הפקודה history ניתן לבצע את האחרונה על ידי !! ניתן לבצע את פקודה מספר 𝑛 על ידי !𝒏 ניתן לבצע את הפקודה האחרונה שהתחילה ב-<string> על ידי !<string> ניתן לבצע את הפקודה האחרונה שמכילה <string> על ידי !?<string> אפשר להחליף str1במחרוזת str2בפקודה האחרונה ע"י ^str1^str2^ . > history :20 a=3 :21 let b=4 :22 n=$((b + a)) :24 echo $n :28 history > !4 echo $n 7 > !! > !let let b=4 > ls /it/is/avery/long/path > ^ls^cat^ cat /it/is/avery/long/path החלפות המתבצעות בגלל גישה להיסטוריה מודפסות בזמן ביצוען ולפני ביצוע הפקודה למען הדיוק: השימוש ב-! (על שלל האפשרויות השונות) מבצע החלפת מחרוזות (בדומה לכל שאר המנגנונים של bash) ולכן ניתן לעשות שם שימוש מורכב יותר במנגנון, למשל: > wc -l a.txt > head b.txt –n+`!wc | cut -f1 -d" "` כאשר מתבצעת החלפה כתוצאה משימוש ב-! תודפס ההחלפה שנבחרה למסך לפני ביצוע הפקודה מבוא לתכנות מערכות

17 Command Substitution ניתן "לשרשר" פקודות על ידי שימוש בגרשיים הפוכים `
באנגלית: backticks או backquotes Bash יבצע תחילה את הפקודה בתוך ` ` ויחליף אותה בפלט שלה Command substitution allows the output of a command to replace the command itself. Command substitution occurs when a command is enclosed as follows: 1. $(command) or 2. `command ` Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting. When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by ‘$’, ‘`’, or ‘\’. The first backquote not preceded by a backslash terminates the command substitution. When using the $(command) form, all characters between the parentheses make up the command; none are treated specially. Command substitutions may be nested. To nest when using the backquoted form, escape the inner backquotes with backslashes. If the substitution appears within double quotes, word splitting and filename expansion are not performed on the results. farm1 farm2 farms_list.txt > echo The length of $str is `echo -n $str | wc -c` The length of Hello is 5 > grep –c cow `cat farms_list.txt` farm1:3 farm2:2 > a="there are `ls | wc -l` files in `pwd` " > echo $a there are 662 files in /usr/bin מבוא לתכנות מערכות

18 סוגי גרשיים גרשיים כפולים, " ", משמשים לשמירה על רווחים
גרשיים כפולים, " ", משמשים לשמירה על רווחים משתמשים ב-" " כאשר יש צורך לשמור מחרוזות שלמות במדויק > sentence="The dingo ate your baby" בתוך גרשיים אלו לא מתבצעות החלפות של תבניות בשמות הקבצים המתאימים > echo "*.c" : *.c *.c : main.c app.c hello.c גרשיים בודדים ' ', מונעים את כל ההחלפות בתחומם > echo lets make some '$$' lets make some $$ גרשיים הפוכים (backticks) מבצעים command substitution Single Quotes Enclosing characters in single quotes (‘'’) preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash. Double Quotes Enclosing characters in double quotes (‘"’) preserves the literal value of all characters within the quotes, with the exception of ‘$’, ‘`’, ‘\’, and, when history expansion is enabled, ‘!’. The characters ‘$’ and ‘`’ retain their special meaning within double quotes. The backslash retains its special meaning only when followed by one of the following characters: ‘$’, ‘`’, ‘"’, ‘\’, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ‘!’ appearing in double quotes is escaped using a backslash. The backslash preceding the ‘!’ is not removed. The special parameters ‘*’ and have special meaning when in double quotes. מבוא לתכנות מערכות

19 עבודת ה-shell עבודת ה-Shell מתבצעת בלולאה:
הצגת prompt המתנה לפקודה עיבוד הפקודה עד לקבלת פקודה פשוטה ביצוע הפקודה לשם כך Bash מנהל מבני נתונים פנימיים אשר שומרים את ההיסטוריה, המשתנים וה-aliases שהוגדרו הטיפול בפקודה מתבצע בשלושה שלבים עיקריים ניתוח הפקודה: הפקודה מופרדת למילים על פי רווחים וטאבים. התווים |,< ו-> מפרידים בין פקודות עיבוד הפקודה: ביצוע החלפות מחרוזות הפקודה עד לקבלת פקודה פשוטה ביצוע הפקודה: שליחת הפקודה הפשוטה שהתקבלה לביצוע על ידי מערכת ההפעלה אילו מבני נתונים שלמדנו בקורס מתאימים ל-bash? ההיסטוריה מתאימה לשמירה ברשימה המשתנים מתאימים לקבוצה (כאשר הם מזוהים לפי שמם) ה-aliases גם מתאימים לקבוצה (שוב, השם ייחודי לכל alias) מבוא לתכנות מערכות

20 עיבוד הפקודה בשלב זה מבצע bash החלפות במחרוזת הפקודה עד לקבלת פקודה פשוטה: אם הפקודה מכילה שימוש בפקודות קודמות (ע"י שימוש בסימן !) מתבצעת החלפה מההיסטוריה ומודפסת שורת הפקודה שנבחרה מההיסטוריה אם המילה הראשונה בפקודה הינה alias מתבצעת החלפה לפי ה-alias המוגדר החלפת ביטויים המתחילים ב-$ בערכי המשתנים המתאימים החלפת תבניות של שמות קבצים ברשימת הקבצים המתאימה החלפת פקודות המופיעות בתוך גרשיים הפוכים בתוצאת הפקודה מבוא לתכנות מערכות

21 ביצוע הפקודה לאחר שהתקבלה פקודה סופית על bash להפעיל את הפקודה המתאימה, הפקודות מתחלקות שני סוגים: פקודות פנימיות של ה-Shell, למשל cd, let, unset,... פקודות חיצוניות - שמות קבצי הרצה, למשל ls, gcc, cat, sort... אם שם הפקודה מתאים לפקודה פנימית היא תיבחר אחרת ה-Shell יחפש בכל התיקיות המופיעות במשתנה path קובץ הרצה בשם המתאים, אם נרצה לאפשר ל-Shell להריץ תכניות מהתיקיה הנוכחית ללא שימוש ב-‘.’ ניתן להוסיף את התיקיה הנוכחית ל-PATH. התיקיות מופרדות ע"י סימן ":" . ניתן להשתמש בפקודה which כדי לגלות איזו תכנית תופעל עבור שם פקודה מסוים החיפוש ב-path מתבצע לפי סדר ההופעה בו ניתו כמובן לרשום שמות מלאים של שם קובץ כדי להריץ תכנית. כך למשל הפקודה ./unsetתחפש קובץ הרצה בתיקיה הנוכחית בשם unset ולא תפעיל את הפקודה הפנימית unset. > PATH=${PATH[*]}:. > hello Hello world! > which hello ./hello > which gcc /usr/bin/gcc < which cd Which: no cd in (…content of PATH…) מבוא לתכנות מערכות

22 עבודה ב-Bash - סיכום ל-Bash מגוון תוכנות מתקדמות המאפשרות למשתמש מתקדם לבצע פעולות מסובכות בקלות ניתן להתייחס למספר קבצים בבת אחת על ידי שימוש בתבניות ניתן להגדיר כינויים לפקודות ופרמטרים שכיחים בעזרת alias ניתן לקרוא לפקודות שהתבצעו בעבר הקרוב בעזרת ההיסטוריה ניתן לשמור ערכים במשתנים ולנצלם לפקודות ב-Bash כל המשתנים ב-bash הם מסוג רשימות של מחרוזות ניתן להשתמש ב-` ` כדי לבצע החלפת פקודה בפלט שלה בשורות פקודה ב- bash כל התכונות של bash מבוצעות על ידי החלפת מחרוזות פשוטה בשלב עיבוד הפקודה מבוא לתכנות מערכות

23 הרצת תסריטים מבני בקרה ב-bash דוגמאות השוואה בין C ו-bash
מבוא לתכנות מערכות

24 אוטומציה נניח (מקרה היפותטי לחלוטין) שברשותנו קבצי בדיקה ופלט לתכנית שלנו וברצוננו לבדוק את נכונות התכנית מול קבצים אלו צריך לכתוב 3 פקודות לכל בדיקה גם עם שימוש במנגנון ההיסטוריה הרצת הבדיקות מעיקה ולוקחת הרבה זמן מיותר הפתרון: אוטומטיזציה של הרצת הפקודות. ניצור קובץ אשר יכיל "תסריט" לפיו יורצו כל הפקודות לפי הסדר > mtm_rentals < test1.in > tmpout 2> tmperr > diff expout1 tmpout > diff experr1 tmperr מבוא לתכנות מערכות

25 הרצת תסריט בעזרתsource
ניתן להריץ קובץ המכיל פקודות Bash (להלן תסריט - script) על ידי הפקודה source הפקודות יבוצעו ב-Shell הנוכחי כאילו נכתבו בשורת הפקודה אחת אחרי השניה echo Running test 1 mtm_rentals < test1.in > tmpout 2> tmperr diff expout1 tmpout diff experr1 tmperr echo Running test 2 mtm_rentals < test2.in > tmpout 2> tmperr diff expout2 tmpout diff experr2 tmperr echo Running test 3 mtm_rentals < test3.in > tmpout 2> tmperr diff expout3 tmpout diff experr3 tmperr run_tests > source run_tests Running test 1 Running test 2 Running test 3 אין צורך להדר קבצי תסריט, אלו קבצי טקסט פשוטים. מאחר והפקודות יורצו ב-Shell הנוכחי השפעתיהן יופיעו בו. למשל משתנה שיוגדר בתסריט יישאר מוגדר בסופו. לכן ניתן למשל להגדיר aliases ושינויים ל- PATHבתוך תסריט אשר מורץ באמצעות source מבוא לתכנות מערכות

26 תסריטי אתחול בהתחברות של משתמש למערכת מורץ התסריט .login אשר בתיקית הבית של המשתמש בפתיחת Shell חדש של Bash מורץ התסריט .bashrc הרצות תסריטי האתחול מתבצעות באמצעות source, ולכן הן משפיעות על מצב ה-Shell המשתנה savehist קובע את גודל ההיסטוריה שתישמר בין הרצות של ה-Shell. כך למשל נשמרות פקודות מהפעם הקודמת שהתחברתם ל-stud. # 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` .login PATH=$PATH:. alias ll="ls -l" alias cdex2="cd ~mtm/public/1011a/ex2" alias GCC="gcc -std=c99 -Wall \ -pedantic-errors -Werror" .bashrc מבוא לתכנות מערכות

27 הרצת תסריט כקובץ הרצה ניתן להריץ תסריט כפקודה: #!/bin/bash
בתחילת התסריט יש להוסיף את השורה #!/bin/bash #! מסמן ל-Unix שהשורה הראשונה בקובץ מגדירה את התכנית לביצוע שאר הפקודות בקובץ /bin/bash הוא שם התכנית לביצוע הפקודות, במקרה שלנו Bash בנוסף יש להוסיף הרשאת ריצה לקובץ כעת ניתן להריץ את התסריט כמו תכנית רגילה בניגוד להרצה באמצעות פקודת source התסריט יבוצע בתהליך Shell חדש אשר יסתיים בסוף ריצת התסריט את מיקום bash במחשב ניתן למצוא בעזרת הפקודה which bash כמו שנלמד בתרגול 6 הסימן #! מאפשר הרצה באמצעות כל תכנית שהיא, כך למשל תוכלו לרשום את שם קובץ ההרצה של תרגיל הבית ובהמשך הפקודות לרשום פקודות עבורו לפי השפה שהוגדרה. #!/usr/s02/user/mtm/ex2 item add blah 20 20 report items מבוא לתכנות מערכות

28 הרצת תסריט כקובץ הרצה נמיר את תסריט הרצת הבדיקות שלנו לקובץ הרצה:
#!/bin/bash echo Running test 1 mtm_rentals < test1.in > tmpout 2> tmperr diff expout1 tmpout diff experr1 tmperr echo Running test 2 mtm_rentals < test2.in > tmpout 2> tmperr diff expout2 tmpout diff experr2 tmperr echo Running test 3 mtm_rentals < test3.in > tmpout 2> tmperr diff expout3 tmpout diff experr3 tmperr run_tests נמיר את תסריט הרצת הבדיקות שלנו לקובץ הרצה: בעיה חדשה: התסריט מתחיל להסתבך, הוספת בדיקות נוספות משכפלת קוד בתסריט ולא נוחה (ייתכנו אלפי בדיקות) פתרון: נשתמש במבני בקרה (תנאים ולולאות) בדומה לשפת C > chmod a+x run_tests > ./run_tests Running test 1 Running test 2 Running test 3 בדרך כלל יהיו עשרות-אלפי בדיקות להרצה. אי אפשר להמשיך לשכפל קוד בתסריט. מבוא לתכנות מערכות

29 מבני בקרה Bash מאפשרת שימוש במבני בקרה (למשל while ו-if) בתסריטים ובשורת הפקודה מבני הבקרה משתמשים בתנאים בדומה למבני הבקרה שבשפת C השוואת ערכי מספרים השוואת מחרוזות ועוד... נעבור על מספר מבני בקרה ותנאים שימושיים > for ((i = 1; $i < 10; i++ )); do > if (($i % 3 == 0)); then > echo 3 divides $i > fi > done 3 divides 3 3 divides 6 3 divides 9 מבוא לתכנות מערכות

30 while ניתן ליצור לולאות while ב-bash: run_tests
while <expression>; do <command1> <command2> ... done הפקודות בגוף הלולאה יבוצעו כל עוד <expression> ממשיך להתקיים לולאות while כמו שאר מבני הבקרה ניתנות לביצוע ישירות מהטרמינל התו \ גורם ל-Shell להתעלם מירידית השורה שבאה אחריו ומאפשרת שבירת שורות גדולות (כמו במאקרו ב-C ושורות ב-makefile) התו ; מסמן סוף פקודה ומאפשר כתיבת פקודה חדשה באותה השורה. ניתן היה גם לכתוב: while <expression> do <command1> <command2> ... done #!/bin/bash i=1 while (( i <= 3)); do echo Running test $i mtm_rentals < test${i}.in \ > tmpout 2> tmperr diff expout${i} tmpout diff experr${i} tmperr let i++ done run_tests > i=1 > while (( i <= 3)); do > echo $i > let i++ > done 1 2 3 > ./run_tests Running test 1 Running test 2 Running test 3 מבוא לתכנות מערכות

31 for לולאת for משמשת בדומה לשפת C למעבר נוח יותר על תחום מספרים
#!/bin/bash for ((i = 1; i <= 3; i++)); do echo Running test$i mtm_rentals < test${i}.in > tmpout 2> tmperr diff expout$i tmpout diff experr$i tmperr done run_tests > ./run_tests Running test1.in Running test2.in Running test3.in מבוא לתכנות מערכות

32 for שימוש נוסף ב-for הוא מעבר על על איברי מערך:
for <varname> in <array> ; do <command1> <command2> ... done <varname> הוא שם המשתנה שיכיל בכל פעם איבר מהרשימה <array> הוא רשימה של מחרוזות העדיפו להשתמש בשיטה זו על פני שימוש מפורש באינדקסים הרשימה יכולה להיות {1..10} המספרים 1 עד 10 או למשל {e..y} ואז יודפסו התווים מ e עד y מבוא לתכנות מערכות

33 if ניתן להגדיר ב-bash משפטי תנאי בשתי גרסאות
if <expression>; then <command1> <command2> fi ניתן להוסיף else ופקודות אשר יתבצעו אם התנאי אינו מתקיים if <expression>; then <commands> else <commands> fi > i=1 > if (( $i > 0 )); then > echo POSITIVE > else > echo NEGATIVE > fi POSITIVE מבוא לתכנות מערכות

34 ביטויים אפשריים ב-if ו-while
קיימות מספר אפשרויות לכתיבת התנאים בלולאות ומשפטי תנאי ניתן לרשום תנאים בתוך [[ ]]: האופרטורים > ו-< משווים מחרוזות (לפי סדר לקסיקוגרפי) האופרטור == מאפשר התאמת מחרוזת לתבנית ניתן לבצע השוואת על ערכי מספרים בעזרת דגלים כגון -eq, -gt, -le חשוב להקפיד על תו הרווח בין הסוגריים לתוכן התנאי כדי למנוע שגיאות ב-bash -eq מתרגם את המחרוזת למספרים, דבר אשר גורם לאיבוד של רווחים בתחילה/סוף משתנה ומשנה את בסיס המספר אם יש ערך המציין זאת בתחילת המחרוזת (למשל, אפסים מובילים אומרים שהמספר הוא בבסיס 8) > str1=Hello > if [[ $str1 == Hello ]]; then echo true; fi true > if [[ hello == Hello ]]; then echo true; fi > if [[ 11 < 7 ]]; then echo true; fi > if [[ 11 -le 7 ]]; then echo true; fi > if [[ 11 -eq 11 ]]; then echo true; fi > if [[ 0 -eq Hello ]]; then echo true; fi זו אינה השוואת ערכים מספריים עבור ערך שאינו מייצג מספר משתמשים ב-0 לחישוב מבוא לתכנות מערכות

35 התאמת מחרוזות בתוך תנאי מהצורה [[ ]], האופרטור == מאפשר התאמת מחרוזת לתבנית הארגומנט השמאלי הוא מחרוזת רגילה הארגומנט הימני הוא תבנית אשר יכולה לכלול את הסימנים *, ? ו-[ ] כמו שתואר עבור תבניות של שמות קבצים ניתן להשתמש בגרשיים כפולים "" על מנת לבטל את המשמעות המיוחדת של התווים הללו ניתן להשתמש ב- ^ עבור שלילה של תו מסוים. האופרטור =! הוא השלילה של אופרטור ההתאמה == המשמעות של = ו-== זהה > end_with_z="some string with z" > if [[ "$end_with_z" = *[zZ] ]]; then echo match; fi match > if [[ "this string starts with t" = t* ]]; then echo true; fi true > if [[ "this string doesn't start with t" = [^t]* ]]; then echo true; fi > file=test4.in > if [[ $file = test*.in ]]; then echo test file; fi test file > if [[ "string doesn't start with t" != t* ]]; then echo true; fi מבוא לתכנות מערכות

36 ביטויים אפשריים ב-if ו-while
בתוך [[ ]] ניתן להשתמש בתנאים מועילים נוספים, למשל: התנאי -f <filename> בודק האם קיים קובץ בשם <filename> התנאי -d <dirname> בודק האם קיימת תיקייה בשם <dirname> ניתן לבדוק תנאים מורכבים יותר: ניתן להשתמש באופרטורים &&, ||, ו-! כמו בשפת C הקפידו להשאיר רווח אחרי ! כדי להימנע משגיאות בגלל מנגנון ההיסטוריה ניתן להשתמש בסוגריים כדי לקבוע את הקדימויות > if [[ -f a.txt ]]; then echo file exists; fi > cat > a.txt Hello world! file exists > mkdir mtm > if [[ ! (-f b.txt && -d mtm) ]]; then echo yes; fi yes מבוא לתכנות מערכות

37 ביטויים אפשריים ב-if ו-while
ניתן להגדיר תנאי בתוך (( )) בתוך (( )) האופרטורים ==, =!, > ו- < מתייחסים לערכים מספריים אין צורך לרשום $ לפני שם משתנה ניתן לבצע פעולות חשבוניות תנאים המוגדרים בעזרת (( )) מתנהגים כמו ביצוע פעולות חשבוניות בעזרת (( ))$ > if (( 11 < 7 )); then echo true; fi > i=5 > if (( i >= 0 && i <= 10 )); then echo true; fi true > if [[ 11 -eq 11 ]]; then echo true; fi > if (( 0 == Hello )); then echo true; fi > if (( ++i == 6 )); then echo true; fi מבוא לתכנות מערכות

38 העברת פרמטרים בשורת הפקודה
כמו ב-C ניתן לגשת לפרמטרים המועברים בשורת הפקודה לתסריט הפרמטר ה-n לתסריט נקרא פשוט n, וניתן לקרוא אותו על ידי $n $* יוחלף ברשימת כל הארגומנטים לתסריט אם ייתכנו רווחים בתוך הארגומנטים ניתן להשתמש כדי לשמור על מספר האגומנטים הנכון $0 יוחלף בשם התסריט $# יוחלף במספר הארגומנטים #!/bin/bash echo command: $0 echo $# arguments let number=1 for param in $*; do echo parameter $((number++)) : $param done echo_script > echo_script aaa bbb ccc command: echo_script 3 arguments parameter 1 : aaa parameter 2 : bbb parameter 3 : ccc מבוא לתכנות מערכות

39 פונקציות ניתן להגדיר ב-bash פונקציות בצורה כזו:
function <name> { <commands> } פונקציה חייבת להכיל לפחות פקודה אחת השימוש בפונקציה יכול להתבצע רק אחרי הגדרתה אפשר להעביר לפונקציה ארגומנטים הפונקציה משתמשת בהם בדומה לשימוש בארגומנטים המועברים לתסריט הפונקציה אינה יכולה לגשת לארגומנטים של התסריט שקרא לה מבוא לתכנות מערכות

40 פונקציות כדי ליצור משתנה מקומי בפונקציה יש להכריז עליו תחילה עם local:
#!/bin/bash function surprise { local a=surprise_a b=surprise_b } a=original_a b=original_b echo $a $b surprise using_local > using_local original_a original_b original_a surprise_b מבוא לתכנות מערכות

41 ביטוי זה יוחלף בסכום הרצוי
פונקציות ניתן "להחזיר" ערכים מפונקציה בעזרת command subsitution (backticks): #!/bin/bash function sum { local result=0 for num in $*; do let result+=$num done echo $result } n=`sum $*` echo $n sum_numbers > sum_numbers 15 ביטוי זה יוחלף בסכום הרצוי מבוא לתכנות מערכות

42 קריאת קלט ניתן לקרוא שורה מהקלט הסטנדרטי על ידי read <flags> <variable name> השורה תיקלט לתוך שם המשתנה שהוגדר הדגל -a יחלק את השורה לפי מילים לתוך מערך הביטוי read יוחלף על ידי bash בשורת קלט שתיקלט מהקלט הסטנדרטי > read line Hello world > echo $line > read -a line Hello > echo ${line[*]} מבוא לתכנות מערכות

43 עבודה עם קבצים דרך פשוטה לקריאת קובץ היא על ידי שימוש בהפניית קלט ושימוש ב-read: דרך פשוטה לקרוא קובץ שורה אחר שורה היא כך: > cat hello.txt Hello world! > read line < hello.txt > echo $line #!/bin/bash counter=0 while read line; do echo $line let counter++ done < "$1" echo $counter lines_counter > cat lines.txt first line second line > lines_counter lines.txt first line 2 מבוא לתכנות מערכות

44 חלוקה פונקציונלית של תסריטים
שימו לב שניתן להשתמש ב-bash כדי לערבב תסריטים עם תכניות שנכתבו בשפות שונות בקלות מכאן מגיע כוחן של שפות תסריטים - scripting languages ניתן להעביר פרמטרים לתסריטי עזר בעזרת פרמטרים בשרות הפקודה בעזרת pipeline בעזרת קבצים זמניים ניתן לקבל ערכים חזרה מתסריטי עזר בעזרת פלט מתסריט העזר מבוא לתכנות מערכות

45 העברת והחזרת ערכים החזרת ערכים מתסריטי העזר יכולה להתבצע בעזרת
שימוש ב-backticks 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 פרמטרים המועברים בשורת הפקודה ייקראו מהתסריט שקיבל אותם על ידי גישה לפרמטרים של שורת הפקודה. מידע המועבד דרך pipeline ייקרא בתסריט העזר על ידי קראיה מהקלט הסטנדרטי שלו בכל מקרה, החזרת הערכים מתבצעת על ידי הדפסה בתסריט העזר. מומלץ לא להעביר פרמטרים דרך קבצים זמניים, שיטה זו פחות עמידה לבאגים ומושפעת ממצב הקבצים בספריה )קל גם בטעות לשכוח קבצים זמניים בלי למחוק אותם בסוף הריצה) מבוא לתכנות מערכות

46 exit ניתן להשתמש בפקודה exit על מנת לצאת מה-shell הנוכחי ולהחזיר ערך יציאה נבחר: exit [status] ערך בררת המחדל הוא 0 – ומייצג "הצלחה" של התוכנית. כל ערך אחר (מספר שלם) אמור לייצג כישלון. בכל רגע נתון ערך היציאה האחרון שמור במשתנה $? כל תוכנית אמורה לסיים את ריצתה עם ערך יציאה (עבור תוכנית שנכתבה ב-C זהו אותו ערך שפונקציית ה-main מחזירה). #!/bin/bash echo "hi" exit 1 echo "bye" example_script > ./example_script hi > echo $? 1 מבוא לתכנות מערכות

47 דוגמה כתבו תסריט בשם 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 מבוא לתכנות מערכות

48 פתרון נכתוב תסריט בשם search search
התסריט ישתמש בפונקצית עזר הקוראת קובץ ומוצאת את השורות המתאימות בעזרת התאמת מחרוזות #!/bin/bash function search_file { n=1 while read line; do if [[ $line = *"$1"* ]]; then echo “${2} : ${n} : $line” fi let n++; done < "$2" } for file in ${*:2}; do if [[ -f "$file" ]]; then search_file "$1" $file if [[ -d "$file" ]]; then search "$1" $file/* done search שימו לב לשימוש במרכאות: $1 מופיע במרכאות תמיד כי זו מחרוזת חיפוש והיא עלולה להכיל יותר ממילה אחת! ללא המרכאות המחרוזת "Hello world" תועבר כשני פרמטרים ל-search_in_file ונקבל באג. מבוא לתכנות מערכות

49 דוגמה נוספת football.txt
Alon Miz. 2 23/10/93 Macabi-Haifa Macabi-Tel-Aviv Izak Zoh. 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 /11/93 Macabi-Haifa Macabi-Tel-Aviv Izak Zoh. 1 12/11/93 Macabi-Tel-Aviv Hapoel-Haifa Alon Miz. 2 26/10/93 Macabi-Haifa Beitar-Jerusalem Izak Zoh. 2 12/12/93 Macabi-Tel-Aviv Macabi-Hiafa Alon Miz. 2 23/12/93 Macabi-Haifa Macabi-Pet-Tikva Ronen Ha. 3 27/11/93 Hapoel-Tel-Aviv Macabi-Haifa football.txt נתון קובץ בשם football.txt המכיל נתונים על שערים שהובקעו במשחקי כדורגל כל שורה בקובץ מציינת שם של שחקן, מספר השערים שהבקיע במשחק שנערך בתאריך מסוים, שם הקבוצה בה הוא שיחק ושם הקבוצה היריבה ברצוננו לכתוב תסריט בשם player אשר יקבל כפרמטר שם של שחקן וידפיס את כל השורות עבורו מהקובץ football.txt ואת סכום מספר השערים שהבקיע > player "Alon Miz." Alon Miz. 2 23/10/93 Macabi-Haifa Macabi-Tel-Aviv Alon Miz. 2 26/10/93 Macabi-Haifa Beitar-Jerusalem Alon Miz. 2 23/12/93 Macabi-Haifa Macabi-Pet-Tikva Total number of goals: 6 מבוא לתכנות מערכות

50 פתרון נשתמש בתסריט search שכתבנו מקודם כדי לקבל רק את השורות הרלוונטיות נכתוב פונקצית עזר בשם calc_total אשר תקרא את השורות מהקלט הסטנדרטי שלה ותסכום את מספר הגולים של השחקן תוך כדי הדפסתן #!/bin/bash function calc_total { sum=0 while read -a line; do let sum+=${line[6]} echo ${line[*]:4} done echo "total number of goals: $sum" } search "$1" football.txt | calc_total player מבוא לתכנות מערכות

51 דוגמה שלישית כתבו תסריט לדירוג שחקנים בשם best_player אשר יקבל רשימה של שמות שחקנים בשורת הפקודה וידפיס את שם השחקן שהבקיע את מרב הגולים אם קיימים מספר שחקנים שהבקיעו את מרב הגולים יודפסו שמות כל השחקנים לכל שחקן יש להדפיס את שמו ומספר הגולים שהבקיע > best_player "Alon Miz." "Izak Zoh." "Ronen Ha." "Reuven A." Alon Miz. 6 Ronen Ha. 6 מבוא לתכנות מערכות

52 פתרון best_player #!/bin/bash # Sums the goals from lines in
# the correct format function sum_goals { local sum=0 while read -a line; do let sum+=${line[6]} done echo $sum } # Sums all the goals of target player function sum_player_goals { ./search "$1" football.txt | sum_goals best_player max_goals=0 for player in do goals=`sum_player_goals "$player"` if (( goals > max_goals )); then max_goals=$goals fi done if (( goals >= max_goals )); then echo "$player" $max_goals תכנון נכון יותר של בחירת תסריטי העזר יכולה לאפשר לנו להשתמש בתסריטים מהסעיף הקודם כאן, בתרגול 1 ראינו כלים סטנדרטיים של Unix שמאפשרים לנו פתרון נוח יותר של בעיות כאלו. מבוא לתכנות מערכות

53 השוואה בין bash ל-C Bash היא שפת תסריטים - scripting language
שפות תסריטים נוספות: Perl, Tcl, Python, Ruby. C היא שפת תכנות מערכת - system programming language שפות מערכת נוספות: C++, Java, C#. מבוא לתכנות מערכות

54 השוואה בין bash ל-C יתרונות של bash על C: חסרונות של bash לעומת C:
עבודה נוחה עם מחרוזות ומשתנים נוח "להדביק" תכניות קיימות (עוד על כך בתרגול 7) קוד קצר משמעותית לחלק מהמשימות אין קומפיילר - לא צריך להכריז על דברים חסרונות של bash לעומת C: אין קומפיילר - אין בדיקות מאפשר באגים מסוכנים איטית (לעתים פי כמה מאות) נבחר ב- bash עבור מטלות פשוטות וקצרות שזמן הביצוע שלהן לא קריטי הבאג בקוד הוא בגלל איות לא נכון של המילה account בהשמה, רשום acount_balance עם c אחת בלבד. כתוצאה מכך ההפקדות לא מתבצעות לחשבון. שגיאה מסוכנת כזו בכלל לא תתקמפל ב-C. Benchmark comparisons of tcl and perl to C read deposits account_balance=100 for d in ${deposits[*]}; do acount_balance=$((account_balance + d)) done echo $account_balance מבוא לתכנות מערכות

55 bash- סיכום כדי לחסוך ביצוע חוזר וידני של פעולות ניתן ליצור תסריטים המכילים רצף פקודות שימושי ולהריצם בעזרת source או הפיכתם לקובץ הרצה ב-bash קיימים מבני הבקרה while , for ו if המאפשרים כתיבת קוד מתקדם בתסריטים ניתן לגשת לפרמטרים לשרות הפקודה של תסריט בדומה לתכנית ב-C כדי לקרוא מהקלט הסטנדרטי ב-bash נשתמש בפקודה read ניתן לחלק תסריטים לפונקציות ולהעביר מידע ביניהן ע"י קריאת טקסט בפונקציה וכתיבתו לפלט נוח להדביק תסריטים ביחד בעזרת pipeline ו-command substitution כדי לפתור בקלות בעיות נשתמש ב-bash עבור מטלות פשוטות שאינן דורשות חישובים רבים, עבור שאר המטלות נמשיך להשתמש ב-C מבוא לתכנות מערכות


הורד את "ppt "שרשור פקודות באמצעות Pipeline עבודה ב- bash כתיבת תסריטים ב- bash

מצגות קשורות


מודעות Google