שרשור פקודות ב- Bash

מספר דרכים לשרשור פקודות ב- Bash:

  1. הרצת סקריפט שמכיל את הפקודות אחת אחר השניה (כל פקודה בשורה נפרדת).
    – כל הפקודות ירוצו באותו ה- shell (גם אם הן מצליחות וגם אם לא)
  2. הרצת הפקודה: cmd1;cmd2;cmd3
    – הפקודות מופרדות ע"י ';' ורצות אחת אחר השניה
    – כל פקודה ממתינה לסיום הפקודה הקודמת כשכל פקודה רצה ב- shell אחר (קראו את התגובות)
  3. הרצת הפקודה: (cmd1;cmd2;cmd3)
    – כמו 2 רק שכל הפקודות רצות באותו ה- shell ברקע (קראו את התגובות)
  4. הרצת הפקודה: cmd1 && cmd2 && cmd3
    -בהתחלה תרוץ הפקודה cmd1, אם תצליח תרוץ הפקודה cmd2 ואם לא תצליח לא תורץ אף פקודה נוספת.
    – '&&' שונה מ- ';' בכך שבשימוש ב- ';' הפקודות תמיד רצות אחת אחר השנייה (ללא תלות בתוצאות ההרצה הקודמת)
  5. ניתן להשתמש בסקריפט ולבדוק אם כל פקודה הצליחה או לא
    – ניתן לדעת אם פקודה הצליחה או לא ע"י בדיקת הערך של '?$'. אם '?$' מחזיר 0 הפקודה הצליחה ואם מחזיר כל ערך אחר הפקודה נכשלה.
    – ניתן לבצע בדיקות נוספות ומתוחכמות יותר ע"י שימוש ב- || (שמשמעותו 'או') או ב-  && ('וגם')
  6. שימוש ב- & (הרצה ברקע): cmd1 & cmd2 & cmd3
    כל הפקודות ירוצו במקביל אך זאת שתסיים ראשונה תציג את הפלט ראשונה (אם יש פלט)

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

9 תגובות בנושא “שרשור פקודות ב- Bash”

  1. 1 ו־2 הם אותו דבר. בשניהם הפקודה רצה באותו ה־shell . כמובן שהרצה של פקודה חיצונית תיצור תהליך נפרד. אולם אם הפקודה היא פונקציה או פקודה פנימית של bash היא לא תיצור תהליך חדש.

    דווקא | כופה יצירה של תהליך בן: כל התהליכים שבצנרת חייבים להיות בנים מכיוון שצריכים לשנות להם את ה־fie descriptors . לכן, לדוגמה:

    a=1
    true | a=2
    echo $a

    ידפיס 1 ולא 2 .

    && מיועד להריץ פקודה רק אם פקודה אחרת הצליחה.
    || מיועד להריץ פקודה רק אם פקודה אחרת נכשלה.

    כלומר:

    cmd1 && cmd2

    cmd3 || cmd4

    מקביל ל:

    if cmd1; then cmd2; fi
    if ! cmd3; then cmd4; fi

  2. צפריר, תודה (השכלתי מהתשובה).

    בקשר ל- '|': זה קצת מבלבל כי '|' משתמש גם כ- pipe, כלומר שהפלט של פקודה אחת משמש כקלט של פקודה אחרת (כך שנראה שהתשובה של תומר איננה נכונה)

  3. כמוכן, ה־| בכלל לא מתיימר להבטיח הרצה של פקודות אחת אחרי השניה. להפך: פקודות שמורות לרוץ במקביל בצנרת.

    ‎$ (echo 1: before sleep; sleep 2; echo 1: after sleep)>/dev/tty | (echo 2: before sleep; sleep 2; echo 2: after sleep)
    2: before sleep
    1: before sleep
    1: after sleep
    2: after sleep

    לעומת פקודות שמופרדות ב';' (כלומר מורצות אחת אחרי השניה):

    ‎$ (echo 1: before sleep; sleep 2; echo 1: after sleep)>/dev/tty ; (echo 2: before sleep; sleep 2; echo 2: after sleep)
    1: before sleep
    1: after sleep
    2: before sleep
    2: after sleep

  4. נדיר מאד לתקן את צפריר…

    1 ו-2 הם לא אותו דבר; 1 ו-3 הם אותו דבר. בשלושתם, כל הפקודות מתבצעות באותו ה-shell, ובאף אחד מהם הן לא ברקע; ההבדל בין 2 לבין האחרים הוא שב-1 ו-3, ה-shell הזה הוא shell מיוחד שנפתח לצורך הרצת הפקודה, ואילו ב-2 הפקודות מורצות בתוך ה-shell ה"רגיל", האינטראקטיבי.
    [code]
    $ a=1;echo $a
    1
    $ (a=2; echo $a); echo $a;
    2
    1
    $ cat temp.sh
    a=3
    echo $a
    $ sh temp.sh ; echo $a
    3
    1
    [/code]
    בפירוט יותר — הרצת פקודות בתוך סוגריים, כמו בתוך סקריפט, יוצרות סביבה חדשה, ששינויי משתנים בה לא משפיעים בחוץ; בלי הסוגריים, הם כן משפיעים. הרצה ברקע לא קשורה לסוגריים.

    אגב, אפקט שימושי במיוחד של ה"אי-השפעה" הזו הוא לגבי שינויי תיקיה; אם בתוך רצף הפקודות שבסוגריים נכללת גם cd, היא תשפיע על הפקודות שלאחריה, אולם בסוף הרצף תיקיית-העבודה לא תשתנה.

  5. בקשר ל- '|': זה קצת מבלבל כי '|' משתמש גם כ- pipe, כלומר שהפלט של פקודה אחת משמש כקלט של פקודה אחרת (כך שנראה שהתשובה של תומר איננה נכונה)

    אני מודע לנושא ה-redirection, רק הכנתי לך פתיחה למאמר הבא בסדרה. 🙂

  6. שי
    תודה על התגובה. הדוגמא שסיפקת מאוד ברורה (הייתה לי הרגשה, כשכתבתי את הפוסט, שאחכים מהתגובות, וכך באמת קרה… 🙂 )
    בכל מקרה: הכנסתי בפוסט הפניות לתגובות.

כתיבת תגובה

האימייל לא יוצג באתר.