Bash Tips
985 subscribers
14 photos
4 files
45 links
רוצים להשתמש בלינוקס אבל לא ממש מכירים את הכלים שהיא מספקת לעבודה?

בערוץ הבא תמצאו אוסף טיפים שימושיים ב-Bash והכרות עם כלים שונים שעשויים לחסוך מאמץ ועבודה בכתיבת סקריפטים ומימוש אוטומציות.
Download Telegram
לוגים, הקדמה 1 tee
רמת קושי: #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
לוגים, על exec וניתוב פלט
רמת קושי: #advanced

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


המשימה: יצירת לוג אינפורמטיבי

פתרון 1
הפתרון הראשון שמיד יעלה לנו לראש הוא ליצור איזה פונקציה שעושה echo לכל מה שנעביר לה לתוך קובץ, משהו שנראה כך

logger() {
echo "${@}" | tee myscript.log
}

מה שיש לנו פה זאת פונקצייה פשוטה בשם logger שמדפיסה כל מה שהיא מקבלת לקובץ myscript.log


אוקי נראה אחלה, איפה הבעיה?
הבעיה היא שכרגע המצב הוא שרק מתי שנקרא לפונקציית הלוגר היא תכתוב נתונים לקובץ הלוג, מה שאומר שכמעט לכל פקודה שאריץ אצטרך לאסוף את הפלט שלה.

וזה עוד לא החלק הבאמת בעייתי, מה קורה אם לדוגמה פקודה מסויימת נכשלת ומחזירה שגיאה? בגלל שלא קראנו לפונקציית הלוגר הפלט לא יכתב ללוג וזה ממש חבל כי זה בדיוק הפלט שהיינו רוצים שיופיע.

אם כך נשנה מעט את המשימה שלנו
המשימה: יצירת לוג אינפורמטיבי אוטומטי

פתרון 2
אז מה שאנו מחפשים בעצם היא יכולת גלובלית יותר לתפוס את כל הפלט של הסקריפט, איך נעשה את זה? הדרך הפשוטה היא פשוט לאסוף את הפלט בזמן שאנו קוראים לסקריפט

$ myscript.sh 2>&1 | tee myscript.log

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


פתרון 3
שימוש פקודת exec אותה ראינו בפוסט הקודם, אם נחשוב על הבעיה הקודמת שהיתה לנו בפתרון 2 נוכל לראות איך שימוש בכלי "חיצוני" כחלק מהסקריפט יכול לעזור לנו.
מה שלא ממש צויין בטיפ הקודם הוא שפקודת exec תוכל גם לנתב את הפלט עבורנו, וכל עוד לא נעביר לה פרמטר exec ינתב את הפלט של הסקריפט כולו.

exec &> >(tee myscript.log)

מה שיש לנו כאן זוהי בעצם הכרזה בסקריפט שכל פלט שמגיע מהפקודות לאחר הכרזה זו (stderr & stdout) יופנה אל פקודת tee על ידי שימוש ב process_substitution שהיא בתורה תכתוב את התוכן גם לקובץ וגם למסך, וכמו בעבר בכדי להימנע מכלים שיש להם מידע שאינו רלוונטי ללוגים תמיד נוכל להשתיק פלט על ידי הפניה שלו אל /dev/null


אתגר בקצה
אחלה אם כן יש לנו פתרון נהדר, היכן עוד נוכל לשפר אותו?
כמו שאנו מכירים כל לוג אמור להכיל עוד פרטים מעבר לפלט, שעה ותאריך לדוגמה, או כל דבר אחר שנרצה שהלוג יכיל, מן הסתם נרצה שלפני שהפלט יכתב לקובץ הלוג שהוא יעבור תהליך כלשהו כדי שהלוג יהיה קריא ומועיל וכו'

איך נוכל לגרום לפלט להיות בפורמט של לוג?
מוזמנים לשלוח רעיונות


#process_substitution
#logging
#exec
#tee

@bash_tips
עוד קצת tee בבקשה
רמת קושי: #beginners

הכרנו לא מזמן את פקודת tee וראינו שהיא יודעת לנתב ולשכפל פלט בודד למספר נתיבים שונים, הנה עוד כמה דברים חביבים שניתן לעשות בעזרת tee


להעביר פלט אחד למספר פקודות על ידי שימוש ב process substitution, לא מדובר כאן על עיבוד פלט ושרשור הלאה, אלה על העברה של פלט גולמי למספר תהליכים שונים (הנה קמח, אני רוצה פיצה ובורקס)

$ echo "date" | tee >(ssh host1) >(ssh hos
t2)


ליצור מספר קבצים בעלי תוכן מסויים, כמובן שניתן רק להוסיף את התוכן על ידי שימוש בדגל -a

$ date | tee {1..10}.
txt


כתיבת מידע לקובץ בעל הרשאות רוט
(תודה ל @tomer על הטיפ!)

$ sudo echo aaa > /root/test
bash: /root/test: Permission denied

$ echo aaa | sudo tee /root/test
aaa
$ sudo cat /root/test
a
aa


#tee
#process_substitution

@bash_tips