לעבד 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
לקבל
פקודה חביבה ממש שמגיעה כחלק bash builtin היא
הפקודה מאפשרת לתחום ריצה של פקודות אחרות לזמן מוגדר, כך שאם פקודה מסויימת לא מפסיקה לרוץ, פקודת timeout תוודא שהיא לא תשתיק את שאר הסקריפט לעד
בדוגמה הראשונה timeout הוא 3 שניות ולכן הפקודה מפסיקה לרוץ לאחר 3 שניות ומחזירה סטטוס קוד 124
בדוגמה השניה פקודת sleep מסיימת לפני תום הtimeout ולכן היא יוצאת עם סטטוס קוד 0
הפקודה מבחינת ערכים עובדת בצורה דומה מאוד ל sleep כך שטיים האוט יכול גם להיות 10m
משהו נוסף, כדאי מאוד לעבור על ה help הקצר של הפקודה
#timeout
#sleep
#exit_code
@bash_tips
timeout
רמת קושי: #beginnersפקודה חביבה ממש שמגיעה כחלק bash builtin היא
timeout
.הפקודה מאפשרת לתחום ריצה של פקודות אחרות לזמן מוגדר, כך שאם פקודה מסויימת לא מפסיקה לרוץ, פקודת timeout תוודא שהיא לא תשתיק את שאר הסקריפט לעד
$ timeout 3 sleep 5
$ echo $?
124
$ timeout 5 sleep 3
$ echo $?
0
בדוגמה הראשונה timeout הוא 3 שניות ולכן הפקודה מפסיקה לרוץ לאחר 3 שניות ומחזירה סטטוס קוד 124
בדוגמה השניה פקודת sleep מסיימת לפני תום הtimeout ולכן היא יוצאת עם סטטוס קוד 0
הפקודה מבחינת ערכים עובדת בצורה דומה מאוד ל sleep כך שטיים האוט יכול גם להיות 10m
משהו נוסף, כדאי מאוד לעבור על ה help הקצר של הפקודה
#timeout
#sleep
#exit_code
@bash_tips
לכתוב תנאים
רמת קושי: #beginners
כתיבה של תנאי בבאש יכולה להתבצע במספר דרכים, התנאי הפשוט נראה בצורה הבאה בה הביטוי ממוקם בין סוגריים
התנאי בודק את הביטוי ואם הוא true מה שבתוך התנאי יתממש.
חשוב לציין, תנאי בבאש לא מחזיר true או false אלא 0 ששוה בעצם לtrue ו 1 ששוה ערך ל false. התנהגות זו שונה מרוב שפות התכנות והסיבה לכך היא שרוב העבודה בבאש היא שימוש בהרבה תוכניות קטנות לבצע מטלה גדולה יותר כך שהתנאי בעצם בודק את הסטטוס קוד שהתוכנית מחזירה, סטטוס קוד 0 שווה לתוכנית שהסתיימה בהצלחה.
(למען הנוחות מכאן והלאה אתייחס ל 0 כ true ו 1 כ false)
קיצורים רבותיי
ישנה דרך מקוצרת לכתוב תנאי
מה שקורה פה הוא שאנו מריצים ביטוי שיחזיר לנו true או false, במידה והוא יחזיר true אז הוא ימשיך לקוד הבא, במידה וביטוי שלנו החזיר false מה שנמצא לאחר ה
הטריק הזה כמובן יעבוד גם בצורה ההפוכה על ידי שימוש ב
מה לא לעשות?
הדרך הקצרה לפעמים היא הדרך הכואבת וזה נכון גם במקרה הזה, בעוד ששימוש בתנאי רגיל יחזיר תמיד סטטוס קוד 0 וזה לא משנה אם הביטוי החזיר true או false
$
$
שימוש בתנאי מקוצר מחזיר סטטוס קוד 1 במידה והביטוי החזיר false
$
$
$
1
זה כבר הופך להיות בעיה של ממש, במיוחד אם הסקריפט משולב כחלק מה pipeline.
#if
#exit_code
#conditions
@bash_tips
רמת קושי: #beginners
כתיבה של תנאי בבאש יכולה להתבצע במספר דרכים, התנאי הפשוט נראה בצורה הבאה בה הביטוי ממוקם בין סוגריים
if [[ 1 -eq 1 ]]
then
echo "I'm in"
fi
התנאי בודק את הביטוי ואם הוא true מה שבתוך התנאי יתממש.
חשוב לציין, תנאי בבאש לא מחזיר true או false אלא 0 ששוה בעצם לtrue ו 1 ששוה ערך ל false. התנהגות זו שונה מרוב שפות התכנות והסיבה לכך היא שרוב העבודה בבאש היא שימוש בהרבה תוכניות קטנות לבצע מטלה גדולה יותר כך שהתנאי בעצם בודק את הסטטוס קוד שהתוכנית מחזירה, סטטוס קוד 0 שווה לתוכנית שהסתיימה בהצלחה.
(למען הנוחות מכאן והלאה אתייחס ל 0 כ true ו 1 כ false)
קיצורים רבותיי
ישנה דרך מקוצרת לכתוב תנאי
[[ 1 -eq 1 ]] && echo "do it"
מה שקורה פה הוא שאנו מריצים ביטוי שיחזיר לנו true או false, במידה והוא יחזיר true אז הוא ימשיך לקוד הבא, במידה וביטוי שלנו החזיר false מה שנמצא לאחר ה
&&
לא יבוצע.הטריק הזה כמובן יעבוד גם בצורה ההפוכה על ידי שימוש ב
||
כך שהמשך הקוד יתבצע רק עם הביטוי יכשל.מה לא לעשות?
הדרך הקצרה לפעמים היא הדרך הכואבת וזה נכון גם במקרה הזה, בעוד ששימוש בתנאי רגיל יחזיר תמיד סטטוס קוד 0 וזה לא משנה אם הביטוי החזיר true או false
$
cat /tmp/test.sh
#!/bin/bash
if [[ 1 -eq 0 ]]
then
echo "I'm in"
fi
echo $?
$
bash /tmp/test.sh
$ echo $?
0שימוש בתנאי מקוצר מחזיר סטטוס קוד 1 במידה והביטוי החזיר false
$
cat /tmp/test.sh
#!/bin/bash
[[ 1 -eq 0 ]] && echo "Do it"
$
bash /tmp/test.sh
$
echo $?
1
זה כבר הופך להיות בעיה של ממש, במיוחד אם הסקריפט משולב כחלק מה pipeline.
#if
#exit_code
#conditions
@bash_tips
לשרשר ולספור
הזכרנו בעבר ששימוש ב pipe מתסיר את הקוד יציאה של הפקודה שרצה לפני הpipe
לדוגמה הפקודה הבאה תחזיר קוד יציאה 0 למרות שהפקודה הראשונה נכשלה
#pipe
#env_variable
#exit_code
@bash_tips
PIPESTATUS
רמת קושי: #beginners הזכרנו בעבר ששימוש ב pipe מתסיר את הקוד יציאה של הפקודה שרצה לפני הpipe
לדוגמה הפקודה הבאה תחזיר קוד יציאה 0 למרות שהפקודה הראשונה נכשלה
$ ls /not/exist/path | echo 123בכדי לקבל את הקוד יציאה של כל פקודה שהורצה ב pipe ניתן להשתמש במשתנה הסביבה PIPESTATUS, מדובר על משתנה סביבה מסוג מערך שמכיל קוד יציאה של כל פקודה שהורצה ב pipe
123
ls: cannot access '/not/exist/path': No such file or directory
$ echo $?
0
$ ls /not/exist/path | echo 123 | grep -o 2ניתן לראות אם כן שבעוד ששני הפקודות האחרונות יצאו בקוד 0, הפקודה הראשונה שנכשלה יצאה בקוד שגיאה
ls: cannot access '/not/exist/path': No such file or directory
2
$ declare -p PIPESTATUS
declare -a PIPESTATUS=([0]="2" [1]="0" [2]="0")
#pipe
#env_variable
#exit_code
@bash_tips