לדלג לתוכן

סקריפטי bash

עם bash אנחנו יכולים גם לכתוב סקריפטים.
- הסיומת המקובלת של סקריפטי bash היא sh.
הריצו nano ./script.sh כדי לפתוח nano על קובץ בשם script.sh
- כתבו את הbash script שלכם, הנה דוגמה לסקריפט:

echo "Hello!";
sleep 3;
echo "Bye!";

שימו לב שאתם כותבים נקודה-פסיק אחרי כל שורה כדי להפריד בין הפקודות.
- כדי להריץ את הסקריפט קודם הוסיפו לו הרשאת ריצה עם chmod +x ./script.sh
- הריצו את הסקריפט בדיוק כמו שאתם מריצים קובץ הרצה, באחד הדרכים הבאות:
1. כתבו את הנתיב המלא של הקובץ הרצה, home/amitp/script.sh/
2. בתוך תקייה מסויימת (נניח בhome/amitp/) הריצו עם נקודה- script.sh/.
3. העבירו את הסקריפט לתקייה שנמצאת בPATH, או ששנו את PATH ואז הריצו את הסקריפט ישירות: script.sh
נסו אותם!

"שבנג" - #!

  • אם תריצו את הסקריפט בתוך הטרמינל, אז bash ידע איך להריץ את הסקריפט. אבל אם תנסו להריץ את הסקריפט לא מתוך bash (כלומר מתוך קוד שכתבתם), אז הסקריפט לא ירוץ- ותצטרכו להריץ את הסקריפט עם הפקודה "bash" ישירות: bash /home/amitp/script.sh
  • אם תרצו להריץ את הקובץ ישירות, מבלי להוסיף לו בהתחלה את הפקודה bash. תוכלו להשתמש בפיצ'ר ה"שבנג" של לינוקס, הוסיפו לסקריפט שלכם בשורה הראשונה את השורה הבאה:
    ```bash

!/bin/bash

echo "Hello!";
sleep 3;
echo "Bye!";

זה אומר ללינוקס כשהוא מנסה להריץ את הקובץ להריץ אותו עם הפקודה "bash" שנמצאת בנתיב "/bin/bash".
- בנוסף נוכל לעשות זאת גם לסקריפטי פייתון שלנו, (התקינו פייתון 3 עם `sudo apt install python3`), הריצו `which python3` כדי למצוא את הנתיב המלא של פייתון3, והזינו אותו:
  הריצו `nano main.py`
```python
#!/bin/python3

print("Hello World!")

- נסו להריץ את הסקריפט פייתון ממש ישירות. main.py

בסקריפטי bash, כאשר נזין משתנים סביבה חדשים עם export (בדיוק כמו שעשינו עד עכשיו) לפני ריצת הסקריפט- אז המשתנים האלה יועברו לסקריפט. לעומת זאת אם נזין משתני סביבה בלי export, ישירות. הן לא יועברו לסקריפטים שאנחנו מריצים.
- כלומר ריצת הbash הבא, לא תעשה כלום:

a=1
echo "echo $a;" > script.sh
chmod +x script.sh
./script.sh

- לעומת הסקריפט הבא:
export a=1
echo "echo $a;" > script.sh
chmod +x script.sh
./script.sh

פה יודפס 1.

לרוב בתוך סקריפטי bash אנחנו נציב משתנים בלי export, וגם בתוך shell- אלה אם כן יש סיבה מיוחדת להשתמש בexport. כל פעם שאתם מציבים משתנה חדש בbash חשבו האם הוא צריך להיות גלובלי לכולם או לא, כנראה שבדרך כלל התשובה תהיה לא.

#!/bin/bash

x=5;
echo $x;

  • בbash האופרטור ()$, משמש כדי לריץ אקספרשן (ביטוי) באש, בדומה לפייתון.
    #!/bin/bash
    
    x=$(ls -la);
    echo x;
    echo $(which ls);
    
  • בbash האופרטור (())$, משמש כדי לחשב ביטויים מתמטים ממש כאקספרשן, בדומה לפייתון.
    #!/bin/bash
    
    echo $((5+5));
    

קלט בסקריפטי bash

  • אפשר להעביר לסקריפטי bash כמו כל תוכנה program argurments, וכדי לגשת אליהם, ניגשים לפי המספר של הprogram argument בדרך הבאה:

    #!/bin/bash
    
    echo $1;
    echo $2;
    echo $3;
    

    אם נריץ את הסקריפט הבא כך: !!!! script.sh hello world/.
    הפלט של הסקריפט יהיה:
    hello
    world
    !!!!
    

  • בנוסף אפשר להשתמש בפקודה המובנת read כדי לקבל קלט מהמשתמש בדומה לפונקציה input בפייתון:

    #!/bin/bash
    
    read my_var;
    echo $my_var;
    

    כאשר המשתנה my_var יכיל את הקלט שהגיע מהמשתמש, ואז המשתנה יודפס על המסך עם echo.

תכנות סטנדרטי עם bash

גם בbash כמו כל שפת תכנות, וכמו השפות שלמדנו עד כו (פייתון, באצ', פאוורשל) קיים תנאים, לולאות, מערכים ופונקציות:

1. תנאים (Conditions)

תנאים ב-Bash מאפשרים לנו לבצע בדיקות לוגיות ולהתנהג בהתאם לתוצאות הבדיקה. הפקודה הנפוצה ביותר לתנאים היא if.

מבנה בסיסי של תנאי:

if [ תנאי ]; then
    # קוד לביצוע אם התנאי מתקיים
elif [ תנאי נוסף ]; then
    # קוד לביצוע אם התנאי הנוסף מתקיים
else
    # קוד לביצוע אם אף תנאי לא מתקיים
fi

שימו לב, ביטויים בולייאנים בbash הם קצת מוזרים, ודומים לpowershell. ראו דוגמה למטה:

דוגמה:

age=20

if [ $age -ge 18 ]; then
    echo "You are an adult."
else
    echo "You are not an adult."
fi

כאשר -ge זה greater equal, או בעברית- גדול שווה.

2. לולאות (Loops)

לולאות ב-Bash משמשות לחזרה על פעולה מסוימת מספר פעמים או עד שהתנאי מפסיק להתקיים.

סוגי לולאות:

  • לולאת for: חוזרת על קוד עבור כל פריט ברשימה.

    for i in 1 2 3 4 5; do
        echo "Number: $i"
    done
    

  • לולאת while: חוזרת על קוד כל עוד התנאי מתקיים.

    count=1
    while [ $count -le 5 ]; do
        echo "Count: $count"
        count=$((count + 1))
    done
    

  • התנאי -le הוא קיצור של less equal שזה תרגום של קטן שווה.

  • לולאת until: חוזרת על קוד עד שהתנאי מתקיים. (בדיוק הפוך מwhile)

    count=1
    until [ $count -gt 5 ]; do
        echo "Count: $count"
        count=$((count + 1))
    done
    

3. מערכים (Arrays)

מערכים ב-Bash הם אוסף של פריטים הנגישים על פי אינדקס.

יצירת מערך:

my_array=(one two three)

גישה לאיבר במערך:

echo ${my_array[0]}  # מדפיס "one"

הדפסת כל האיברים במערך:

echo ${my_array[@]}

הוספת פריט למערך:

my_array+=(four)

אורך המערך:

echo ${#my_array[@]}

4. פונקציות (Functions)

פונקציות ב-Bash מאפשרות להגדיר קוד שניתן לקרוא לו מספר פעמים במקומות שונים.

הגדרת פונקציה:

function greet() {
    echo "Hello, $1!"
}

קריאה לפונקציה:

greet "World"

- שימו לב שפונקציה נקראת ממש כמו פקודה, בדומה לpowershell.

פונקציות יכולות להחזיר ערכים באמצעות return:

function add() {
    return $(($1 + $2))
}

add 3 4
result=$?
echo "Result: $result"

פונקציות עם משתנים גלובליים:

total=0

function add_to_total() {
    total=$(($total + $1))
}

add_to_total 5
echo "Total: $total"

קבצי קונפיגורציה בbash

נחזור קצת אחורה כמה שיעורים: אז אם אנחנו מגדירים משתני סביבה עם export, אז איך bash מכיר בכל המשתני סביבה? איפה הן מוגדרים?
- לכל משתמש בלינוקס קיימת תקיית בית, כמו שבווינדוס התקייות האלה נמצאות בתוך C:\Users, בלינוקס התיקיות נמצאות בתוך home/, הריצו ls -la /home.
- שימו לב שאפשר לגשת לתייקית הבית שלכם הפשטות עם הנתיב /~.
- בכל תקיית משתמש, קיים קובץ קונפיגורצית bash משלו, שרץ כאשר פותחים shell מסוג bash חדש עם המשתמש שלו. קיימים כמה קבצים כאלה, ולרוב הם מתחילים ב.
- בנוסף גם קיים קובץ כללי כזה לכל המערכת שנמצא ב etc/profile/, או etc/bash.bashrc/, או ` - הקבצים שעלולים להיות קבצי קונפיגורציה של bash נמצאים בתקיית הבית ונקראים: -.bash_login-.bash_profile-.profile-.bashrc-.bash_logout` - רץ בסיום החיבור באש

פקודת source

  • בדרכים שציינתי למעלה כדי להריץ סקריפי bash, יווצר פרוסס חדש (job חדש) לסקריפ bash, ולמשל כל המשתנים שנגדיר בלי export, לא יועברו לסקריפט ועוד הגדרות שהגדרנו לshell.
  • לפעמים אנחנו נרצה להריץ את הסקריפט bash כיאלו שזה בshell שלנו, ולא בפרוסס נפרד- ובשביל זה קיימת הפקודה source, שמריצה את הסקריפט bash שורה אחרי שורה, ממש בjob שלנו.
    source script.sh
    
  • בנוסף כקיצור לsource אפשר להריץ את זה גם ככה:
    . script.sh
    
  • למשל, כאשר אנחנו מריצים את הסקריפט activate כשאנחנו מנסים לתחבר לvenv שלנו בפייתון- נשתמש בפקודה source, כי רוב הקוד שרץ בסקריפט, מטרתו לשנות לנו הגדרות בshell שלנו- אז הוא צריך לרוץ כיאלו היה רץ אצלנו בshell ולא בshell נפרד.

היסטוריה בbash

בbash נשמרת ההיסטוריה של הsession הנוכחי בקובץ. כדי לבדוק איפה הקובץ הזה נשמר, הדפיסו את הenvrionment variable הבא: echo $HISTFILE הוא מכיל את הנתיב לקובץ שבו נשמרת כל ההיסטוריה. אפשר לקרוא את הקובץ באמצעות cat $(echo $HISTFILE). וגם באמצעות הפקודה history שעושה זאת בשבילנו.
- אם היינו רוצים למחוק את ההיסטוריה, היינו יכולים לעשות unset לHISTFILE, או למחוק את כל התוכן בקובץ היסטוריה.

סוגים שונים של shell.

  • אז כמו שיש bash, יש עוד המון סוגי shell-ים, הנה כמה shell-ים מוכרים בלינוקס:
  • השל bash: השל המוכר ביותר, נמצא ברוב הדיסטרוים היום.
  • השל sh: גרסא מצומצמת יותר של bash, נפוצה בלינוקסים ישנים ולינוקסים מצומצמים.
  • השל busybox: נפוץ במחשבים בקטנים במיוחד, מדובר על shell מצומצם ביותר שמכיל המון פקודות חיצוניות מוכרות בתוכו כמו ps, ls וכו. מדובר על תוכנה אחת שמכילה את כל הבינארים שצריך (כל התוכנות החיצוניות) בשביל shell מתפקד.
  • השל zsh: שיפור של bash, עם עוד פיצ'רים מאוד נחמדים. מומלץ לקרוא עליו
  • השל fish: מתחרה של zsh, עם פיצ'רים מגניבים, מומלץ לקרוא גם עליו.