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

בערוץ הבא תמצאו אוסף טיפים שימושיים ב-Bash והכרות עם כלים שונים שעשויים לחסוך מאמץ ועבודה בכתיבת סקריפטים ומימוש אוטומציות.
Download Telegram
Forwarded from Alex M. Schapelle
לכל אוהבי באש ואוכל :
https://gitlab.com/lpi-devops/bash_cuisine
הכיף הזה לגלות עוד ערוצים עם תוכן איכותי

הקבוצה https://t.me/vim_users
הערוץ https://t.me/vim_tips
👍1
טיפ נהדר של @dank3y והזוית של באש
רמת קושי: #advanced

משתמשי Zsh

אם אתם על הטרמינל כותבים פקודה כלשהי, מעבר לשימוש ב-vi mode של zsh כדי לערוך אותה,
לחיצה על ctrl + e (או מקש אחר לבחירתכם) תביא אתכם ל- vim על מלא בו תוכלו לערוך את הקוד ממש כאילו היה מיני סקריפט שלכם.
כשתסיימו תוכלו לשגר אותו ל-prompt שלכם עם שמירה ויציאה כמו שאתם מכירים.

נדרש רק להוסיף את שתי השורות האלו לקובץ .zshrc שלכם:

autoload edit-command-line; zle -N edit-command-line
bindkey '^e' edit-command-line


משתמשי Bash

ניתן להשתמש בפונקציונליות דומה אין צורך להגדיר שום דבר, קיצור המקשים הוא

Ctrl + X
Ctrl + E


בשני המקרים העורך שיפתח הוא העורך שמוגדר למשתנה הסביבה $EDITOR

#editor

@bash_tips
👍1
חיפוש grep
רמת קושי: #advanced

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

לבצע חיפוש על טקסט ללא רגישות ל case sensitive

$ grep -i "name" file
name: test
Last Name

שימוש בדגלי A / B / C יאפשר לנו להגדיר שלא רק השורה שתואמת את הביטוי תוצג, אלא גם אלו שסביבה, A יחזיר את השורות הבאות לאחר השורה שנמצאה בה התאמה לביטוי, B יחזיר את השורות שקדמו לשורה התואמת לביטוי, C יציג בשווה שורות לפני ואחרי

$ grep -A2 "three" /tmp/test
three
four
five

$ grep -B2 "three" /tmp/test
One
two
three

$ grep -C2 "three" /tmp/test
One
two
three
four
five

הוספת מספרי שורות לתוצאות בהם נמצאה ההתאמה

$ grep -n "three" /tmp/test
3:three

היפוך תוצאות החיפוש, להחזיר רק את מה שאינו תואם לביטוי

$ grep -v "three" /tmp/test
One
two
four
five

בכדי לקבל פונקציולניות מתקדמת ל regex כמו lookbehind, ניתן להשתמש במנוע הregex שתואם את perl, מוכר גם בשם PCRE

$ grep -P

ברירת מחדל grep יחזיר את כל השורה בה נמצא מילה התואמת לביטוי, בכדי לשלוף רק את הרצף שתואם לביטוי ניתן להשתמש בדגל -o

$ grep name Chart.yaml
name: Test

grep -o name Chart.yaml
name

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

$ grep -r "NodePort" sonarqube
sonarqube/k8s/sonarqube-service.yml: type: NodePort
test_env/k8s/backend-service.yml: type: NodePort

בכדי לקבל רק את הנתיב לקובץ שתואם לביטוי, ניתן להשתמש בנוסף בדגל -l

$ grep -rl "NodePort" sonarqube
sonarqube/k8s/sonarqube-service.yml
test_env/k8s/backend-service.yml

וכמובן שאפשר לקבל רק את הקבצים שאינם מכילים את הביטוי על ידי דגל -L

$ grep -rL "NodePort" sonarqube

וכן אתם לא טועים אפשר לממש את אותו הרעיון עם דגל v

$ grep -rlv "NodePort" sonarqube

#grep

@bash_tips
להעביר מידע רגיש read
רמת קושי: #beginners

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

בכדי להימנע מהמצב דומה ניתן להשתמש בדגל -s לפקודת read, האופציה הזאת מאפשרת לקבל מידע לתוך משתנה מבלי להציג אותו למשתמש.

$ read -s PASS

[המערכת שומרת כל קלט שנכנס עד שהוא יאושר עם אנטר]

$ echo $PASS
123123123

#read

@bash_tips
Forwarded from V0id
להציג את הקבצים בתקייה הנוכחית עם נתיב אבסולוטי
find "$PWD" -maxdepth 1
כדי להפוך את זה לפשוט יצרתי 'אליאס' בbashrc

function lspwd() {
find "$PWD" -maxdepth 1 -exec ls --color -d {} \;
}
לינוקס וקבצים lsof

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

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

לדוגמה אנו רוצים לקבל מידע על כל תהליך שרץ במערכת

$ lsof 
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root cwd DIR 8,1 4096 2 /
systemd 1 root rtd DIR 8,1 4096 2 /
systemd 1 root txt REG 8,1 1698400 1842178 /usr/lib/
...
...

הרבה מהמידע שמוצג נראה ג'בריש ולא ברור להלן הסבר קצר על שתי עמודות חשובות שישפוך קצת אור על הנושא
עמודת FD מציגה תיאור על הקובץ המדובר (קיצור של File Descriptor)

cwd:  current working directory
err: FD information error
ltx: shared library text (code and data)
Mxx: hex memory-mapped type number xx.
m86: DOS Merge mapped file
mem: memory-mapped file
mmap: memory-mapped device
pd: parent directory
rtd: root directory
txt: program text (code and data)
v86: VP/ix mapped file

לעמודה הזאת יש עוד סוג של מידע שנראה ממש מוזר
99r
104w
113u

ובעצם בא לספר לנו באלו הרשאות נפתח אותו הקובץ על ידי התהליך

r: read 
w: write
u: read & write

עמודת TYPE מציגה את סוג הקובץ עליו אנו מסתכלים, הסוגים הנפוצים

DIR = תיקייה
REG = קובץ רגיל
CHR = קובץ בעל תווים מיוחדים
FIFO = קובץ pipe

אז מה בעצם אפשר לעשות עם פקודת lsof?

תהליך
שימוש בדגל p יאפשר לחקור לאלו קבצים תהליך מסוים ניגש ועם אלו הרשאות

$ lsof -p 1
OMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dumb-init 1 root cwd DIR 0,54 4096 9964742 /
dumb-init 1 root rtd DIR 0,54 4096 9964742 /
dumb-init 1 root txt REG 0,54 54744 9
309915 /u...
dumb-init 1 root mem REG 8,1 9309915 /usr/bin/...
...


פקודה
שימוש בדגל c יאפשר לקבל רק מידע שקשור לפקודה לסויימת

$ lsof -c firefox

תקשורת
שימוש בדגל i יאפשר לראות קבצים ותהליכים פונים לרשת

$ lsof -i        
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
kdeconnec 2292 user 11u IPv6 49368 0t0 UDP *:1716
kdeconnec 2292 user 12u IPv6 49369 0t0 TCP *:1716 (LISTEN)



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

כל התהליכים שמשתמשים בפרוטוקול מסויים ועוברים דרך פורט 80
דרך טווח של פורטים (300-1000)
דומיין מסויים (@whatsapp.com)
וכמובן ניתן ליצור קומבינציות משולבות של פילטרים

$ lsof -i TCP:80 
$ lsof -i UDP:3000-10000
$ lsof -i @whatsapp.com

תאחזר את כל הקבצים אליהם ניגש משתמש מסויים (-u)
כל המשתמשים האחרים חוץ ממשתמש מסויים (^)
אלו קבצים בתיקייה הנוכחית פתוחים על ידי איזה תהליך (+D)

$ lsof -u user
$ lsof -u ^root
$ lsof +D Project/test/

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

@learnlinuxnote
אתר אנטרקטיבי חביב ללימוד באש.
האתר תומך במגוון שפות בניהם גם עברית
רמת קושי: #beginners

Learn the ways of Linux-fu

https://linuxjourney.com/

#tools

@bash_tips
Bash Tips
Photo
באשיזם? shellcheck
רמת קושי: #advanced

באשיזם שמעתי מישהו קורא לזה, זאת בערך המקבילה של באש לפייתוניק קוד, הרעיון הוא לכתוב קוד קריא ויפה שעובד עם השפה. בהקשר הזה כדאי להכיר לינטר לshell (באש זיש דש וכו') המוכר בעולם בשם shellcheck.

מדובר על כלי שיציג הערות על הקוד לפני שאנו פוגשים אותם בטרמינל כשגיאות, shellcheck יחסית מוכר ויש לו פלאגינים כמעט לכל IDE / Editor שקיים (בתמונה), במידה ומשתמשים בIDE תוכלו לראות את השגיאות כבר בעורך, מי שמתעקש להריץ בדיקות מהטרמינל (CI?) זה נראה כך

$ shellcheck deploy.sh

In deploy.sh line 3:
eval $(aws ecr get-login --region ap-southeast-2 --no-include-email)
^-- SC2046: Quote this to prevent word splitting.

For more information:
https://www.shellcheck.net/wiki/SC2046 -- Quote this to prevent word splitt...

במידה ואנו רוצים להחריג התנהגות מסוימת במקום ספציפי בקוד אף על פי שהיא אינה קבילה מבחינת shellcheck, ניתן להוסיף הערת disable עם מספר השגיאה מעל השורה הבעייתית

# shellcheck disable=SC2046
eval $(aws ecr get-login --region ap-southeast-2 --no-include-email)

במידה ורוצים להתעלם מאותה שגיאה לכל אורך הפרויקט ניתן להריץ את shellcheck בצורה הבאה

$ shellcheck -e SC2046 deploy.sh

#shellcheck

@bash_tips
לפתוח במקום goto
רמת קושי: #beginners

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

$ nano +198 myscript.sh

$ vi +198 myscript.sh

#editor

@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 יוצג כמות שהוא

$ 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
לקבל 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
מניפולציה על מערכים
רמת קושי: #advanced

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

$ myvar=my_username:my_password

$ echo ${myvar^^}
MY_USERNAME:MY_PASSWORD

$ echo ${myvar//my/your}
your_username:your_password



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

$ users_auth=(admin:1234356)
$ users_auth+=(myuser:456789)
$ users_auth+=(writer:00001)

$ echo ${users_auth[@]}
admin:1234356 myuser:456789 writer:00001

$ echo ${users_auth[@]/:*}
admin myuser writer

$ echo ${users_auth[@]/*:}
1234356 456789 00001


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

#array
#parameter_expansion

@bash_tips
להחריג תווים $
רמת קושי: #advanced

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

$ echo "name='version'"
name='version'

$ echo 'name=\'version\' '
> ^C



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

$ echo $'name=\'version\''
name='version
'

מקום נוסף שזה בא ליידי ביטוי

$ echo $'first line \nsecond line'
first line
second line


נושא זה נקרא ANSI-C
למי שרוצה להרחיב את הקריאה על כך

#echo
#ansi_c

@bash_tips
אתר חביב שמסביר בצורה מעט ויזואלית איך פקודות ופרמטרים מורכבים בבאש עובדים
רמת קושי: #beginners

https://explainshell.com

#tools

@bash_tips
להעביר מספר שורות לקובץ (א)
רמת קושי: #advanced

לא מעט פעמים נרצה שהסקריפט שלנו יצור קובץ בעל תוכן מסויים, להלן מספר אפשרויות

שימוש ב Heredoc
פקודת cat וtee יודעות לקבל קלט וליצור ממנו קובץ, הסינטקס בנוי בצורה כזאת
בלוק שמתחיל באיזו מילה שתבחרו, במקרה שלנו EOL, ומופנה אל ה stdin של הפקודה בעזרת >>.
כל הטקסט שבתוך הבלוק יכתב אל הקובץ שעליו אנו מכריזים בשורה הראשונה.
זה נראה כך

$ cat << EOF > myfile.sql
first line
second line
EOF

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

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

#cat
#heredoc

@bash_tips