העברת מידע בין תהליכים ()>
רמת קושי: #advanced
הטיפ הבא מניח ידע בהפניות וערוצים
שימוש ב pipe
צורת העבודה עם באש מורכבת מאוסף של כלים קטנים שמשרשרים אותם ביחד כדי לקבל תוצאה מרשימה שיותר, לשם כך הכלי העיקרי שלנו הוא שימוש ב pipe (
שימוש ב Process Substitution
קיימת אפשרות נוספת להעביר פלט של פקודה אחת לפקודה אחרת והוא על ידי שימוש בהחלפת הקונטקסט לתהליך.
היכולת הזאת מאפשרת לנו לבצע
העברת פלט של פקודות לפקודות אחרות שעובדות רק עם קבצים
ועוד יכולת קריטית נוספת שנראה בטיפ הבא
#pipe
#redirection
#named_pipe
#process_substitution
@bash_tips
רמת קושי: #advanced
הטיפ הבא מניח ידע בהפניות וערוצים
שימוש ב pipe
צורת העבודה עם באש מורכבת מאוסף של כלים קטנים שמשרשרים אותם ביחד כדי לקבל תוצאה מרשימה שיותר, לשם כך הכלי העיקרי שלנו הוא שימוש ב pipe (
|
)$ echo "(5 + 5) * 1000" | bc
10000
מה שבעצם מתרחש כאן הוא היכולת של באש להעביר פלט של פקודה אחת לפקודה אחרת. אם נרצה להסביר את הפעולה הזאת בשפה היותר טכנית, באש מפנה את ה stdout של הפקודה הראשונה ל stdin של הפקודה שמגיע לאחר הpipe.שימוש ב Process Substitution
קיימת אפשרות נוספת להעביר פלט של פקודה אחת לפקודה אחרת והוא על ידי שימוש בהחלפת הקונטקסט לתהליך.
$ more <(ls /bin)
מה בעצם קורה מתחת למכסה המנוע? התהליך הראשון רץ בסביבה משלו ואת התוכן הוא מעביר לnamed pipe, שזה שקול בערך לכתיבה לקובץ, ולאחר מכן הנתיב "לקובץ" המדובר עובר לפקודה הבאה.$ less <(ls /bin)
/proc/self/fd/11 is not a regular file (use -f to see it)
$ cat <(ls /bin)
[
2to3-2.7
411toppm
7z
...
$ less < <(ls /bin)
<less open with the relevant content>
כפי שניתן לראות ישנן פקודות שיודעות לקרוא תוכן ישירות מ named pipe וישנן כאלה שלא, בכדי "להמיר" את התוכן לפקודות שאינן תומכות בקריאה ישירות מ named pipe ניתן להפנות את הפלט אל ה stdin של הפקודה בעזרת >
(כפי שקורה בדוגמה האחרונה).היכולת הזאת מאפשרת לנו לבצע
העברת פלט של פקודות לפקודות אחרות שעובדות רק עם קבצים
ועוד יכולת קריטית נוספת שנראה בטיפ הבא
#pipe
#redirection
#named_pipe
#process_substitution
@bash_tips
לעבד stderr בלי לאבד את קוד היציאה
רמת קושי: #advanced
הטיפ הבא מניח ידע בהפניות וערוצים
לאחר שראינו שניתן להעביר פלט של פקודות מאחת לשניה כדי לעבד אותן, כדאי שנכיר בעובדה שניתן לעבד אך ורק פלט שמועבר על ידי ה stdout ואילו פלט של stderr יוצג כמות שהוא
בכדי לפתור את הבעיה הזאת אנו יכולים לחבר בין הערוצים ולהפנות את ה stderr אל stdout בצורה הבאה.
אם כך הכל מדהים, היכן הבעיה?
הבעיה עם צורת העבודה הזאת היא שאנו מאבדים את קוד היציאה של התוכנית.
הפתרון Process Substitution
בכדי לפתור את הבעיה הזאת נוכל להשתמש בקונספט שראינו בטיפ הקודם רק בצורה ההפוכה.
$
הטיפ הבא שימושי מאוד כשעובדים עם כלים המאפשרים הרצת פקודות ad hoc כמו דוקר, ורוצים לעבד את המידע מבלי לפגוע בפלט הגולמי
#exit_code
#redirection
#process_substitution
@bash_tips
רמת קושי: #advanced
הטיפ הבא מניח ידע בהפניות וערוצים
לאחר שראינו שניתן להעביר פלט של פקודות מאחת לשניה כדי לעבד אותן, כדאי שנכיר בעובדה שניתן לעבד אך ורק פלט שמועבר על ידי ה stdout ואילו פלט של stderr יוצג כמות שהוא
$ ls /not_exist_path | grep -Po "cannot access"
ls: cannot access '/not_exist_path': No such file or directory
הסיבה לכך היא שpipe מעביר אך ורק את ה stdout ולא את ה stderr.בכדי לפתור את הבעיה הזאת אנו יכולים לחבר בין הערוצים ולהפנות את ה stderr אל stdout בצורה הבאה.
$ ls /not_exist_path 2>&1 | grep -Po "cannot access"
cannot access
אם כך הכל מדהים, היכן הבעיה?
הבעיה עם צורת העבודה הזאת היא שאנו מאבדים את קוד היציאה של התוכנית.
$ ls /not_exist_path 2>&1 | grep -Po "cannot access"
cannot access
$ echo $?
0
ברגע שהפקודה הראשונה נכשלת היא לא יוצאת משרשור הפקודות שהעברנו לה אלא מעבירה את הפלט לפקודה הבאה שהיא בתורה מבצעת את התפקיד שלה נהדר ולכן הסטטוס שיחזור יהיה 0 כפי שמחזירה הפקודה האחרונה ואנו נאבד את קוד השגיאה של הפקודה הראשונה.הפתרון Process Substitution
בכדי לפתור את הבעיה הזאת נוכל להשתמש בקונספט שראינו בטיפ הקודם רק בצורה ההפוכה.
$
ls /not_exist_path &> >(grep -Po "cannot access")
cannot access
$ echo $?
2
מה שבעצם קורה כאן הוא שאנו מאחדים את שני הערוצים לערוץ אחד אבל מבצעים את פעולת ההמשך שלנו בקונטקסט אחר, בסאב שאלל ולכן קוד היציאה של הפקודה הראשונית נשאר אותו הדבר.הטיפ הבא שימושי מאוד כשעובדים עם כלים המאפשרים הרצת פקודות ad hoc כמו דוקר, ורוצים לעבד את המידע מבלי לפגוע בפלט הגולמי
#exit_code
#redirection
#process_substitution
@bash_tips
לוגים, הקדמה 1 tee
רמת קושי: #beginners
פקודת
נראה עוד דוגמה
רגע מה קורה למה הקובץ לא מכיל את הודעת השגיאה שפקודת ls החזירה?
הסיבה היא ש pipe מעביר רק stdout ולכן כדי להשתמש ב tee בצורה יעילה כדאי לשרשר את stderr לstdout על ידי 2<&1
אם נחזור לדוגמה הקודמת אז הפקודה צריכה להראות כך
חשוב לציין שבכל הרצה הפקודה תדרוס את הקובץ מחדש, בכדי להוסיף תוכן לקובץ מבלי לדרוס אותו כל פעם מחדש ניתן להשתמש בדגל -a
#tee
#redirection
@bash_tips
רמת קושי: #beginners
פקודת
tee
עושה דבר מאוד פשוט ומאוד שימושי, הפקודה מפצלת פלט כך שיכתב גם למסך וגם לקובץ.$ echo 123 | tee myfile
123
$ cat myfile
123
נראה עוד דוגמה
$ ls /not_exist | tee myfile
ls: cannot access /not_exist: No such file or directory
$ cat myfile
$
רגע מה קורה למה הקובץ לא מכיל את הודעת השגיאה שפקודת ls החזירה?
הסיבה היא ש pipe מעביר רק stdout ולכן כדי להשתמש ב tee בצורה יעילה כדאי לשרשר את stderr לstdout על ידי 2<&1
אם נחזור לדוגמה הקודמת אז הפקודה צריכה להראות כך
$ ls /not_exist 2>&1 | tee myfile
ls: cannot access /not_exist: No such file or directory
$ cat myfile
ls: cannot access /not_exist: No such file or directory
חשוב לציין שבכל הרצה הפקודה תדרוס את הקובץ מחדש, בכדי להוסיף תוכן לקובץ מבלי לדרוס אותו כל פעם מחדש ניתן להשתמש בדגל -a
#tee
#redirection
@bash_tips
לוגים, הקדמה 2 exec
רמת קושי: #advanced
פקודת
רגע מה???, למה שמישהו ירצה לעזאזל להריץ פקודת באש על פקודת exec במקום להריץ ישירות על באש את הפקודה הרצויה?
פקודת
מה שבעצם קורה הוא שexec לא פותח תהליך חדש אלא מתלבש על התהליך הקיים ויוצא כשהוא מסיים (בקשר לזה עוד בהערה).
פקודת
הרצת
הרצת
כפי שניתן לראות לאחר שהרצנו
נ.ב. שימוש בexec עם פרמטר יוצר בעצם את הרצף הבא
מאחר ו
#exec
#redirection
@bash_tips
רמת קושי: #advanced
פקודת
exec
כמו שהיא נשמעת היא פקודת באש שמריצה פקודות באש מתוך באשbash >> command
bash >> exec >> command
רגע מה???, למה שמישהו ירצה לעזאזל להריץ פקודת באש על פקודת exec במקום להריץ ישירות על באש את הפקודה הרצויה?
פקודת
exec
יודעת לנהל את הפלט של הסקריפט ממש כמו שנריץ בטרמינל עצמו, במילים אחרות אפשר לומר שזה כמו הרצה של באש מתוך הסקריפט.מה שבעצם קורה הוא שexec לא פותח תהליך חדש אלא מתלבש על התהליך הקיים ויוצא כשהוא מסיים (בקשר לזה עוד בהערה).
פקודת
exec
עובדת בשני צורות אחת עם פרמטר והשניה בלי פרמטר,הרצת
exec
עם פרמטר (פקודה) תגרום לכך שרק הפקודה שהועברה כפרמטר תרוץ תחת exec
.$ exec ls > myfile.log
הרצת
exec
בלי פרמטר תגרום לכך שכל מה שיכתב לאחר מכן ירוץ תחת exec
, אם אנו חוזרים לאנלוגיה ממקודם אז זה כמו לפתוח באש חדש מתוך באש, כל מה שנריץ ירוץ בעצם בתוך המעטפת החדשה שיצרנו.$ ls
1.txt 2.txt 3.txt
$ exec > myfile.log
$ ls
$ cat myfile.log
$ 1.txt 2.txt 3.txt
כפי שניתן לראות לאחר שהרצנו
exec
פקודת ls
כבר לא מחזירה פלט לטרמינל אלא ישירות לקובץ.נ.ב. שימוש בexec עם פרמטר יוצר בעצם את הרצף הבא
bash >> exec >> ls >> exit
מאחר ו
exec
משתלט בעצם על התהליך שכבר רץ הלא הוא באש ולא יוצר תהליך חדש משל עצמו אז כשהוא מסיים לרוץ הוא מחזיר קוד יציאה וסוגר את התהליך עליו הוא השתלט, זוהי בעצם הסיבה למה טרמינלים עפים וחיבורי ssh נסגרים.#exec
#redirection
@bash_tips
להעביר שגיאות ב pipe
רמת קושי: #beginners
דבר קטן וחשוב שכדאי להכיר
כולנו מכירים את השימוש ב pipe בבאש, להעביר פלט של פקודה אחת לפקודה אחרת, מה שלא כולם יודעים זה שpipe מעביר רק stdout ולא stderr
כפי שרואים השגיאה הודפסה ישירות לטרמינל ופקודת wc לא קיבלה שום פלט (ערך 0)
איך כן?
בכדי להעביר גם את stderr וגם את stdout דרך ה pipe צריך להריץ את ה pipe בצורה הבאה עם
#pipe
#redirection
@bash_tips
רמת קושי: #beginners
דבר קטן וחשוב שכדאי להכיר
כולנו מכירים את השימוש ב pipe בבאש, להעביר פלט של פקודה אחת לפקודה אחרת, מה שלא כולם יודעים זה שpipe מעביר רק stdout ולא stderr
$ ls /not_exist | wc -l
ls: cannot access /not_exist: No such file or directory
0
כפי שרואים השגיאה הודפסה ישירות לטרמינל ופקודת wc לא קיבלה שום פלט (ערך 0)
איך כן?
בכדי להעביר גם את stderr וגם את stdout דרך ה pipe צריך להריץ את ה pipe בצורה הבאה עם
&
$ ls /not_exist |& wc
1 9 50
#pipe
#redirection
@bash_tips