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

בערוץ הבא תמצאו אוסף טיפים שימושיים ב-Bash והכרות עם כלים שונים שעשויים לחסוך מאמץ ועבודה בכתיבת סקריפטים ומימוש אוטומציות.
Download Telegram
אפשר להדפיס תוכן כל קובץ על ידי פקודת cat
$ cat myfilecat
one
two
three

הפקודה מאפשרת לשרשר כמה קבצים לקובץ אחד על ידי
$ cat file1 file2 > file3

אופציית שירשור הקבצים עובדת על עוד פורמטים כמו zip ו mp3.

במידה ונרצה להדפיס קובץ מהסוף להתחלה אפשר להשתמש בפקודת tac (כן, למישהו יש הומור)
$ cat myfilecat
one
two
three

$ tac myfilecat
three
two
one

עכשיו לחלק המעניין, מה לדעתכם יקרה אם נשתמש בtac על קובץ mp3?
פקודת sed להשתמש ב ! במקום \

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

הקובץ שלי מכיל את הטקסט הפשוט הבא
$ cat test.txt 
my path is /tmp/test/hello

שימוש בsed מאפשר להחליף טקסט קיים בקובץ ולשמור אותו.
בדוגמה הבאה אני מחליף את המילה hello ב aaa
זה נראה כך
$ sed 's/hello/aaa/g' test.txt 
my path is /tmp/test/aaa

הסינטקס פשוט וקריא, בתחילה אני אומר איזה מילה אני בוחר ולאיזה מילה אני רוצה להחליף. הבעיה מתחילה כשרוצים להחליף תווים מיוחדים למשל אני רוצה להחליף את תו / ל //
זה נראה משהו כזה
$ sed 's/\//\/\//g' test.txt
my path is //tmp//test//hello
לא כיף

במקום לסבול אפשר להשתמש בסינטקס הבא שמחליף את תווי הבקרה בתו אחר
$ sed 's!/!//!g' test.txt
my path is //tmp//test//hello

אז מה היה פה בעצם? החלפנו את השימוש בתו הבקרה / לתו !, הסינקטס קריא יותר וניתן להבנה בקלות גם לבני אנוש
Forwarded from Yuval Meshorer
יש לי עוד אחד חמוד שלא ראיתי פה:

כתבתם קובץ ושכחתם להוסיף לו סיומת? בטח תשתמשו ב-mv, אז תעשו את זה נכון:

$ touch file
$ mv file file.txt
OR
$ touch file
$ mv file{,.txt}


מה שזה עושה זה "מפרק" את הארגומנט למה שבא לפני עם התוספת ובלי:

$ echo a{,b}
a ab
$ echo a{,b,c}
a ab ac
$ echo a{b,}
ab a
$ echo {b,}a
ba a
$ echo {,b}a
a ba
פקודת declare לחיפוש משתנים וערכים במערכת

רוצים לדבג סקריפט ולראות מה type של משתנה מסויים?
ניתן לעשות זאת על ידי שימוש בפקודת declare -p

$ text='some text here'
$ echo $text
some text here
$ declare -p text
declare -- text="some text here"
$ arr=($text)
$ declare -p arr
declare -a arr=([0]="some" [1]="text" [2]="here")

כפי ששמתם לב התשובה שחוזרת כוללת את התווים
declare --
או
declare -a
, זוהי הדרך בה הפקודה מחזירה את היצוג של הערך, אומר שאין הגדרה מסויימת לערך (בבאש אין ערך מוגדר למשתנה על פי תוכן) סימון -a אומר לנו שמדובר על array

לפקודה יש שימוש עיקרי בהגדרת type של משתנים לפני השימוש בהם ואת זה תקראו בהרחבה בגוגל.

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

$ declare | grep some
arr=([0]="some" [1]="text" [2]="here")
text='some text here'

$ declare | grep snap
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
XDG_DATA_DIRS=/usr/share/plasma:/usr/local/share:/usr/share:/var/lib/snapd/desktop
להחסיר מידע לא רלוונטי בפקודת df

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

המידע שהפקודה מחזירה הינו בביטים שפה שפחות בהירה לרובנו, בכדי להציג את נפח האחסון בצורה דבורה אנו מוסיפים את הדגל df -h והתוצאות חוזרות ב mb / gb וכו' איזי פיזי עד כאן כולנו מכירים.

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

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

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

בכדי להעביר פלט של פקודה כאילו הוא קובץ כל שיש לעשות הוא להריץ את הפקודה בצורה הבאה (some_command)>, הסוגריים תוחמות את הפקודה והאופרטור > מעביר את הפלט (stdout) של הפקודה בסוגריים כקלט (stdin) לפקודה שהורצה, למשל הפקודה הלא שימושית הבאה שפשוט תעביר קלט לפקודת cat
cat <(df -h)

אותו רעיון יעבוד לנו גם עם פקודת diff במידה ונעביר את הפלט של הפקודות שלנו כאילו הן קלט/קריאה מקובץ נוכל להשתמש ב diff להשוואות תוצאות של פקודות
diff <(df -h -x ext4) <(df -h)
הצגת פלט קריא בפקודת diff

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

הרצה של פקודת diff -y תציג את שני הקבצים במקביל כך שהשינויים מוצגים בצורה בהירה יותר זה נראה כך
נעים להכיר Zsh (Z Shell) המוכר בפי העם זיש.

למי שלא מכיר את Zsh מדובר על מעטפת ללינוקס מקבילה ל Bash.
מה היתרון של Zsh? זיש פשוט ידידותי יותר למשתמש ומתיימר להיות כלי עבודה יעיל יותר.

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

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

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

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

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

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

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

journalctl --follow
ברגע שמשתמשים בדגל --follow כל מידע שמערכת רושמת מוצג מיד למסך בלי צורך לגלול, זה סתם נחמד לראות איך דברים באמת עובדים במערכת אבל זה בהחלט נח יותר לעבודה בזמן פתרון בעיות.
להרחיב את יכולות Bash על ידי shopt

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

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

באש שומרת לעצמה כלי הגדרה הקרוי shopts, הרצה של הפקודה תציג לכם רשימה נאה של אפשרויות שרובן אינן מאופשרות.
ההרצה הבאה תפעיל את הפיצ'ר הגאוני autocd שמאפשר כניסה לתיקיות רק על ידי רישום השם שלהם בלי להקיש cd כל פעם (s like set-).
shopt -s autocd

והפקודה הבאה שתשלול מהפיצ'ר את החירות שלו (u like unset-)
shopt -u autocd

תיעוד לכל האפשרויות תוכלו למצוא בלינק הבא, הנה כמה שתרצו להכיר

autocd - כניסה אוטומטית לתיקיות
histappend - שמירת פקודות להיסטוריה מכל חלונות הטרמינל שפתוחות
globstar - הפעלת פקודות גם בתתי היררכיה

למשל פקודה כמו זאת ls **/*.py תעלה תוצאות גם מתיקיות בעומק 5 בהיררכיה


.
Deleted Account
טיפ שימושי נוסף שהיה צריך להישלח מזמן בעבר דברנו על אפשרות להריץ את הפקודה האחרונה שהרצנו על ידי שימוש ב!! ישנה אפשרות להעביר את הפרמטר האחרון שהעברנו לפקודה על ידי !$ דוגמה >> /tmp$ mkdir test >> /tmp$ cd !$ cd test >> /tmp/test$ במקום להכניס את השם של…
לקבל את כל הפרמטרים עם *!

בעבר כתבתי על שימוש ב $! כדי להעביר את הפרמטר האחרון שהשתמשתי בו בפקודה מסוימת לפקודה חדשה.

הבעיה מתחילה כשיש רשימה של פרמטרים במידה ונריץ $! נקבל רק את הפרמטר האחרון ולא את כל רשימת הקבצים שהזנו

$ touch app.js index.html internal.css
$ echo !$
internal.css

במידה ונרצה לקבל את כל הפרמטרים נוכל להריץ *!
והחלק שבאמת כיף הוא שאפשר להכניס את זה כחלק מפרמטרים אחרים

$ touch app.js index.html internal.css
$ zip test.zip !*
zip test.zip app.js index.html internal.css
updating: app.js (stored 0%)
updating: index.html (stored 0%)
updating: internal.css (stored 0%)
לקבל שמות קבצים עם cut

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

לדוגמה הנתיב אל הקובץ שלי הוא זה
/tmp/some file.py
ואני מעוניין לקבל רק את שם הקובץ
זוהי הפקודה אותה אריץ ולהלן ההסבר.

echo " /tmp/some file.py" | rev | cut -d/ -f1 | rev

הפקודה cut חותכת טקסט לפי תו שמגדירים לה עם d- במקרה שלנו מדובר על תו /, אנו בוחרים איזה "איבר" להציג על ידי דגל f- ואת האינדקס אותו אנו רוצים, f1- יבחר את המילה הראשונה שלפני ה/ f2- יבחר את השניה וכן על זה הדרך.

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

$ echo "/tmp/some file.py" | rev
yp.elif emos/pmt/

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

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

אם יש משהו שמשתמשי Bash חייבים לזכור הוא שלעולם אבל לעולם לא פונים למשתנה רק עם שמו, תמיד לעטוף אותו "בגרשיים כפולות".

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

אבל מה זה לעזאזל IFS?
המשתנה שאחראי במערכת על הערך שמפריד בין פרמטרים קרוי IFS שהוא קיצור של internal field separator, ברירת מחדל של הערך הוא רווח, טאב ושורה חדשה (דבר שאפשר לשנות כמו כל השמה למשתנה).

$ printf %s "$IFS" | od -vtc -to1
0000000 \t \n
040 011 012
0000003


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

נכון אפשר להגדיר את את IFS שיפצל על פי שורה חדשה אבל היי למה לא לעבוד קל
למצוא עזרה

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

הפקודה man ישנה יחסית והיא מבוססת על פקודות more | less שיודעות לקחת טקסט ארוך ולחלק אותו לתצוגה על המסך, ומאפשרת לחפש טקסט על ידי / וכתיבת הביטוי החיפוש.

פקודה פונקציונלית יותר היא info שאפשרת קריאה רציפה יותר של תוכן פתיחה של לינקים ומעבר בין אזורים דומים בתיעוד כך שניתן לקבל תמונה מקיפה יותר על דברים, עוד על הפקודה בתיעוד :-) .

ישנם פקודות בסיסיות שלא תמצאו להן תיעוד לא עם man ולא עם info
$ man fg
No manual entry for fg

הסיבה היא שהן פקודות שהן build in של bash, בשביל לקרוא תיעוד על הפקודות הללו יש את פקודה help שגם היא איך לא פקודה מובנת של bash.
$  help fg
fg: fg [job_spec]
Move job to the foreground.

Place the job identified by JOB_SPEC in the foreground, making it the
current job. If JOB_SPEC is not present, the shell's notion of the
current job is used.

Exit Status:
Status of command placed in foreground, or failure if an error occurs.

פקודות build in הן פקודות שזמינות גם אם המערכת ריקה לגמרי ושום כלי אחר לא זמין לה, בין הפקודות אפשרי למצוא את cd, shopt, fg, history ועוד, ניתן לראות את הרשימה המלאה על ידי הרצה של
help -d

@bash_tips
לסלול נתיב עם readlink

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

החלק המעניין הוא שאפשר להעביר לפקודה נתיב מרובה סלאשים כפולים והוא ימיר אותו לנתיב תקין, זה נראה כך.
$  readlink -m ///tmp///123//Bswap_HPBake/
/tmp/123/Bswap_HPBake

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

@bash_tips
לאחד ניתובים עם <&

קונספט שרץ בלינוקס אומר שיש כמה ערוצי תקשורת למכונה
0 = stdin - ערוץ בו עובר הקלט למכונה
1 = stdout - ערוץ אליו נשלח הפלט הסטנדרטי
2 = stderr - ערוץ אליו נשלחות השגיאות

המיפוי הזה מיוצג הרבה מהמקרים על ידי תווי redirection בצורה הבאה
< stdin
> stdout
2> stderr
עד כאן הכל ידוע ומוכר
כשכותבים סקריפט הרבה פעמים נרצה לשמור שגיאות במידה והן קיימות על ידי ה-redirection

$ ls directory_that_not_exist 2> error.log

או שנרצה שיוצג למסך רק פלט רלוונטי למשימה שלנו ולזרוק לפח את שאר התוכן שמגיע מהstdout של פקודות אחרות

$ ls /tmp/ /directory_that_not_exist > /dev/null

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

$ ls /tmp/ &> /dev/null

@bash_tips
👍1
עדכון:
1 באפריל שמח לכולם

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

הפוסט המקורי
פיצ'ר חדש
command brace expansion

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

$ touch deploy_{DEV,PROD}.yml
deploy_DEV.yml
deploy_PROD.yml

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

$ {mkdir,cd} my_new_directory
mkdir my_new_directory
cd my_new_directory

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

@bash_tips
אפשר להמשיך yes

פקודה נחמדה בשם yes מאפשרת לנו להעביר את הערך yes כשמשתמשים בפקודות ששואלות את המשתמש אם הוא מאשר משהו או לא [Y/N]
דוגמה טובה תמחיש את העניין

$ yes | sudo apt-get install ffmpeg

בשלב הזה שהפקודה ממתינה לקלט מהמשתמש יועבר לה הערך yes

After this operation, 2,489 kB of additional disk space will be used.
Do you want to continue? [Y/n]


@bash_tips
לקבל סטטוס הרצה עם ?$ echo

כשמריצים פקודות בטרמינל קל לנו לראות אם הפקודה הצליחה או נכשלה, כשאנו מריצים את הפקודה דרך סקריפט ואנו רוצים חיווי אם התהליך שהרצנו הסתיים בהצלחה אפשרי להשתמש ב echo ?$ ולפי זה לקבוע את המשך ריצת הסקריפט
$ ls /opt/
brother containerd CyberGame
$ echo $?
0
$ ls /aaa
ls: cannot access '/aaa': No such file or directory
$ echo $?
2

סטטוס 0 מייצג תוכנית שהסתיימה בהצלחה סטטוס 1 או 2 מייצגים תוכנית שנכשלה, סטטוס ריק מייצג תוכנית שלא רצה.

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

$ [ 44 -eq 44 ]; echo $?
0
$ [ 44 -eq 60 ]; echo $?
1


@bash_tips
קיצורים ל-Default values

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

exist_variable="some text here"

תעביר את הפלט 123 אם המשתנה לא קיים

$ echo ${not_exist_variable:-123}
123

תעביר את הערך 123 אם המשתנה כן קיים
$ echo ${exist_variable:+123}
123

השמת ערך למשתנה אם הוא לא קיים

$ echo ${exist_variable:=123}
some text here
$ echo ${not_exist_variable:=123}
123

מחזיר ערך כשגיאה אם המשתנה לא קיים

$ echo ${not_exist_variable:?"variable not set"}
bash: not_exist_variable: variable not set


@bash_tips