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

בערוץ הבא תמצאו אוסף טיפים שימושיים ב-Bash והכרות עם כלים שונים שעשויים לחסוך מאמץ ועבודה בכתיבת סקריפטים ומימוש אוטומציות.
Download Telegram
בחזרה לעתיד pushd, popd, dirs
רמת קושי: #advanced

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

player@playground:~$ cd /tmp
player@playground:/tmp$ cd -
/home/player

מקסים זה נהדר בבקשה עוד
במידה וננסה לקחת עוד שלב ולנסות לחזור ל2 תיקיות אחורה נראה שאנו פשוט חוזרים חזרה לתיקייה /tmp שהיא כרגע תפסה את המקום של התיקייה האחרונה שהיינו בה.

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

▷ /tmp $ cd test 
▷ /tmp/test $ cd dir1
▷ /tmp/test/dir1 $ cd ../dir2
▷ /tmp/test/dir2 $ cd ../dir3
▷ /tmp/test/dir3 $ cd ../dir4
▷ /tmp/test/dir4 $ 1
/tmp/test/dir3
▷ /tmp/test/dir3 $ 3
/tmp/test/dir1
▷ /tmp/test/dir1 $ 4
/tmp/test

זה הזמן להכיר את שלושת החברים pushd, popd, dirs
נערוך הכרות קלה מה תפקידו של כל אחד ואיך הוא עוזר לנו.

לבאש יש רעיון שנקרא Directory-Stack, מדובר על מחסנית אליה ניתן לטעון תיקיות כדי לגשת אליהם מאוחר יותר

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

player@playground:/tmp/test$ pushd dir1
/tmp/test/dir1 /tmp/test
player@playground:/tmp/test/dir1$ pushd ../dir2
/tmp/test/dir2 /tmp/test/dir1 /tmp/test
player@playground:/tmp/test/dir2$ pushd ../dir3
/tmp/test/dir3 /tmp/test/dir2 /tmp/test/dir1 /tmp/test

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

$ dirs -v
0 /tmp/test/dir3
1 /tmp/test/dir2
2 /tmp/test/dir1
3 /tmp/test

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

player@playground:/tmp/test/dir3$ popd
/tmp/test/dir2 /tmp/test/dir1 /tmp/test
player@playground:/tmp/test/dir2$

פקודת dirs
את פקודת dirs כבר פגשנו, היא מציגה את רשימת התיקיות שבמחסנית וכן מאפשרת למחוק את המחסנית על ידי דגל -c

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

player@playground:/tmp/test/dir2$ pushd +2
/tmp/test /tmp/test/dir2 /tmp/test/dir1
player@playground:/tmp/test$ dirs -v
0 /tmp/test
1 /tmp/test/dir2
2 /tmp/test/dir1
player@playground:/tmp/test$ pushd +1
/tmp/test/dir2 /tmp/test/dir1 /tmp/test
player@playground:/tmp/test/dir2$

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

$ alias cd='pushd 1> /dev/null'

ונבדוק איך זה עובד

player@playground:/var$ cd /etc
player@playground:/etc$ cd /var
player@playground:/var$ dirs -v
0 /var
1 /etc
2 /var
3 /var
4 /etc
5 /tmp/test/dir2
6 /tmp/test/dir1
7 /tmp/test

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

player@playground:/var$ alias 1="pushd +1 1> /dev/null"
player@playground:/var$ alias 2="pushd +2 1> /dev/null"
...
player@playground:/var$ 1
player@playground:/var$ 2
player@playground:/tmp/test/dir2$ 3
player@playground:/var$ 4
player@playground:/etc$ 1
player@playground:/tmp/test/dir2$

זהו עובד נהדר

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

#directory_stack
#pushd
#popd
#dirs
#cd
#challenge

@bash_tips
אודות :
רמת קושי: #advanced

כמה טריקים נחמדים שמאפשרת לנו פקודת :
רגע מה? : זאת פקודה?

$ help :
:: :
Null command.

No effect; the command does nothing.

Exit Status:
Always succeeds.

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


חור שחור
טכניקה מוכרת בבאש, ברגע שרוצים להריץ פקודה ולא לקבל את הפלט שלה להפנות את הפלט ל dev/null
עם : עושים זאת כך

$ : ls /tmp
$ : ls /tm

שימו לב שהיא מעבירה גם את stderr וגם את stdout כך שגם שגיאות לא יוצגו


שרשור פעולות
ראינו מקודם שניתן להריץ פקודות בלי לקבל את הפלט שלהם, כשמכניסים את זה לסקריפט אפשר להשתמש ברעיון הזה בצורה הבאה
$ cat test.sh
: "${1} ####"
printf '%s\n' "#### ${_}"

bash test.sh Title
#### Title ####

שלב א' מבוצעת פעולה על התוכן שהועבר לסקריפט והתוצאה נשמרת בזיכרון
שלב ב' אנו ממשיכים לעשות מניפולציה על התוכן שבזיכרון על ידי שימוש במשתנה _


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

$ echo 1234 > myfile.log
$ du myfile.log
4 myfile.log

$ : > myfile.log
$ du myfile.log
0 myfile.log


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

: << 'DOC'

your code block here

and here

and here

DOC

ברוב המקרים ישנה צורה נוחה ונעימה יותר לבצע את אותן הפעולות, בכל אופן מידי פעם עדין נתקלים בסקריפט שמכיל קוד דומה.
#heredoc
#touch
#null
#true

@bash_tips
לשרשר פקודות && \
רמת קושי: #beginners

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

/tmp/test $ mkdir aa && cd aa
/tmp/test/aa $ cd ..
/tmp/test $ mkdir aa && cd aa
mkdir: cannot create directory `aa': File exists

כפי שניתן לראות לאחר שקיבלנו את השגיאה שהתיקייה כבר קיימת, פקודת ההמשך שהיא cd לא התרחשה.

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


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

mkdir test &&\
touch test/docker_{login,build,push_sha}.sh &&\
chmod +x docker*

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


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

הסיבה לכך היא שאחרי תו ה \&& שמפצל את השורה, אסור שיהיה רווח מפני שבאש מצפה לשורה חדשה שמכילה פקודה וכשהיא נתקלת ברווח היא מנסה להריץ את הרווח כשורה חדשה שמכילה פקודה

$ cat main.sh
test/docker_login.sh &&\
test/docker_build.sh &&\
test/docker_push_sha.sh

$ bash -x main.sh
+ test/docker_login.sh
filename: docker_login.sh
+ ' '
main.sh: line 1: : command not found

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

#lists_of_commands
#special_characters

@bash_tips
📢ערוץ Python Tips
רוצים לשפר את הידע שלכם בפייתון? להבין דברים לעומק יותר? ללמוד דברים חדשים?

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


קישור לערוץ: t.me/python_israel
Forwarded from ToCode
# טיפ יוניקס - מחיקת תיקיה עם מינוס בשם שלה
לריילס יש כלי שורת פקודה מעולה שמאפשר ליצור פרויקטים וקבצים חדשים דרך שורת הפקודה (כן אני יודע שהיום לכולם כבר יש כזה. עדיין ריילס היו שם קודם). בכל מקרה בשביל ליצור יישום ריילס חדש אנחנו פשוט רושמים משורת הפקודה:

rails new hello-world


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

rails new --help


וכאן מתחילות הבעיות.

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

rails new --hlep


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

$ ls -l

drwxrwxr-x 2 ynon ynon 4096 Aug 31 20:57 --hlep


אין בעיה חשבתי אני יודע rm פשוט אמחק את התיקיה ואנסה שוב. אבל יוניקס חשב אחרת:

$ rm -rf --hlep

rm: unrecognized option '--hlep'
Try 'rm ./--hlep' to remove the file '--hlep'.
Try 'rm --help' for more information.


הבעיה שהפקודה rm (כמו גם הרבה פקודות יוניקס אחרות) היתה בטוחה ש --hlep הוא בעצם אחד המתגים ולא שם הקובץ ולא הבינה מה אני רוצה ממנה.

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

$ rm -rf -- --hlep
פקודת השמה ו export

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

myvar="some text here"
export my_another_var="another text here"

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

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

/tmp/tests $ myvar="some text here"
/tmp/tests $ bash echo_myvar.sh

/tmp/tests $

בשלב הראשון אני מכריז על משתנה בסשן בשלב השני אני מריץ סקריפט, הסקריפט רץ תחת הסשן שלי אבל כ sub process.

מצד שני אם נשתמש ב export

/tmp/tests $ export myvar="another text here"
/tmp/tests $ bash echo_myvar.sh
another text here
/tmp/tests $

שימוש ב export יורש את כל סביבת הסשן הנוכחי ומעביר אותו אל תת התהליך. כמובן שלאחר שהמשתנה הוכרז עם export כל פקודת השמה של ערך למשתנה בתהליך הראשי ישפיע על התוכן בתתי התהליכים.

#export
#variable
#env_variable
#session
#sub_process

@bash_tips
בוט התגובות שהיה קיים עד היום בערוץ הוסר והערוץ עבר להשתמש ביכולת המובנת של טלגרם להגיב על הודעות בערוצים, תכונה חדשה שנכנסה בגרסת טלגרם 7.1 מוזמנים לעדכן
לראות את זה קורה watch
רמת קושי: #beginners

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

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

$ watch 'ls -l | grep yoni'

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

$ watch -d ls

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

$ watch -d -n 1 date


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

$ watch -d cat mylog

#watch

@bash_tips
סימניות בטרמינל CDPATH
רמת קושי: #beginners

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

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

user@home /etc $ cd Videos
/home/user/Videos
user@home ~/Videos $ cd gimp
/tmp/gimp
user@home /tmp/gimp $

אז איך עושים את זה בעצם, אנו מעבירים רשימה של מיקומים למשתנה CDPATH והמערכת תתעדף את התיקיות שבאותם המיקומים. כמו שאנו מכירים באש אוהבת נקודותיים (:) כחוצץ בין ערכים והמקרה כאן אינו שונה.

export CDPATH='~:/var/log:/tmp:'

הגדרנו 3 מיקומים במערכת על ידי חוצץ של :
1. תיקיית הבית (~)
2. תיקיית /var/log
3. תיקיית /tmp
כעת ברגע שנרצה להיכנס לאחת מהתיקיות שנמצאות במיקומים שברשימה נוכל פשוט להיכנס אליה מבלי להקליד את הנתיב המלא

user@home /tmp/gimp$ cd Videos
/home/user/Videos
user@home ~/Videos$ cd hp
/var/log/hp
user@home /var/log/hp$ cd Projects
/home/user/Projects

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

user@home /tmp/gimp$ cd P <TAB> <TAB
Pictures/ Projects/

מ ו ש ל ם !

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

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

$ echo $CDPATH
~:/var/log:

user@home /tmp$ tree -d -L 1
/tmp
├── Downloads
├── gimp
...

user@home /tmp$ cd Downloads/
/home/user/Downloads
user@home ~/Downloads$

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

user@home /tmp$ cd .Downloads/
Downloads/
user@home /tmp/Downloads$

#cdpath
#favorite
#env_variable

@bash_tips
להשוות ולפלטר comm
רמת קושי: #advanced

פקודת comm הינה קיצור של compare, פקודה להשוואת רשימות, זה יכול להיות שורות תוכן מקבצים או לפלט של פקודה זאת או אחרת, שימוש הפקודה על קבצים הוא די פשוט קריאה לפקודה ושני הקבצים להשוואה, במידה ונרצה להשוות פלט של פקודה נוכל להשתמש <() כפי שראינו בעבר עם פקודת diff

$ comm file1 file2
$ comm <(ls olddir/) <(ls newdir/)

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

$ touch old/{01..10}
$ touch new/{01..11..2}
$ comm <(ls old) <(ls new)
01
02
03
04
05
06
07
08
09
10
11


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

$ comm -23 <(ls old/ | sort) <(ls new/ | sort)
02
04
06
08

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

$ comm -12 <(ls old/ | sort) <(ls new/ | sort)
01
03
05
07

כפי שאולי שמתם לב לפני שהעברתי את התוכן להשוואה אני מעביר אותו דרך sort וזאת נקודה חשובה. בלי שהשורות יהיו חופפות מבחינת המיקום בתוכן, פקודת comm לא תייצר השוואה נכונה.
(ונכון מספרים זאת לא הדוגמה הכי מוצלחת להדגים sort 😌)

#comm
#diff

@bash_tips
קבוצות תווים Character classes
רמת קושי: #beginners

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

באש מספקת לנו מספר אופציות להשתמש בregex לשימושים שנצרכים לעיתים קרובות בלא לכתוב regex, היכולת הזאת בשפה של באש נקראת Character classes והיא נראית כך [[:alpha:]], לדוגמה.

$ echo "Have a nice day :-)" | tr -d "[[:alpha:]]"
:-)

ביטוי שבוחר את כל האותיות וכפי שניתן לראות כל האותיות נבחרו ונמחקו.
אם נתבונן נראה שכל האותיות נמחקו אבל הרווחים נשארו, והסיבה לכך היא שהורדנו רק אותיות ולא את הרווחים, בשביל להסיר גם את הרווחים ניתן להשתמש בביטוי [:space:] שתופס רווחים.

$ echo "Have a nice day :-)" | tr -d "[[:alpha:][:space:]]"
:-)

במידה ונרצה להפוך את הביטוי ניתן לעשות זאת על ידי ^

$ echo "1 1 root root $" | tr -d "[^[:alpha:]]"
rootroot

בעבר מספיק היה להשתמש בסוגריים מרובעות פעם אחת בשביל לממש את הביטוי לדוגמה [:print:], בגרסאות החדשות יותר של gnu צריכים להכפיל את הסוגריים למימוש הביטוי, וכמובן ניתן להשתמש ביותר מביטוי אחד בתוך סוגריים כפי שראינו לעיל [[:alpha:][:space:]].

להלן רשימה חלקית של הביטויים

[:alpha:] == אותיות
[:digit:] == מספרים
[:space:] == תוים לבנים
[:blank:] == רווחים וטאבים
[:punct:] == תווים מיוחדים
[:alnum:] == [:alpha:][:digit:]
[:graph:] == [:alnum:][:punct:]
[:print:] == [:alnum:][:punct:][:space:]
[:xdigit:] == Hex

#character_classes
#grep
#sed
#regex
#tr

@bash_tips
👍1
נענים לאתגר
רמת קושי: #advanced

האתגר הבא מבוסס על סיפור אמיתי, כמו רוב הטיפים בערוץ 😊.

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

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

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

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

2. להצליח להתגבר על קבצים ששם הזמר נמצא בסוף שם הקובץ.

מוזמנים לפרסם את הפתרונות שלכם בתגובות בערוץ גם אם הם חלקיים
בהצלחה לכולם
#challenge

@bash_tips
צינורות ושמות mkfifo
רמת קושי: #advanced

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

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

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

מספר דרכים בכדי ליצור named pipe

$ mkfifo mypipe
$ mknod mypipe p
$ ls -la
prw-rw-r-- 1 user user 0 אוק 24 23:01 mypipe
...

אנו יוצרים "קובץ" בתיקייה הנוכחית בשם mypipe (מסומן עם p) אליו נוכל לשלוח איזה מידע שנרצה, פעולת הכתיבה לא תסתיים עד שהצד השני יקרא את התוכן ולכן נרצה להריץ את הפקודה ברקע כדי לא לעצור את התהליך.

$ echo "Sending data through mypipe" > mypipe &
[1] 10839

$ cat < mypipe
[1] + 10839 done echo "Sending data through mypipe" > mypipe
Sending data through mypipe

או אם רוצים להאזין לכל תוכן שמועבר בלי שיסגר ה pipe

$ tail -f mypipe

סגירת ה named pipe היא כמו כל קובץ פשוט למחוק עם rm


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

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

mkfifo /tmp/logpipe
while true
do
read record </tmp/logpipe
echo $(date): "$record" >>/tmp/app.log
done

#mkfifo
#named_pipe

@bash_tips
Bash Tips
פקודת sed להשתמש ב ! במקום \ פקודה מוכרת בעולם הלינוקס היא sed פקודה שמאפשרת לבצע מניפולציות על טקסט מבלי לפתוח עורך טקסט הקובץ שלי מכיל את הטקסט הפשוט הבא $ cat test.txt my path is /tmp/test/hello שימוש בsed מאפשר להחליף טקסט קיים בקובץ ולשמור אותו.…
רמת קושי: #advanced

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

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

$ echo sed is cool | sed 's|cool|great|g'
sed is great

$ echo sed is cool | sed 's#cool#great#g'
sed is great

$ echo sed is cool | sed 's_cool_great_g'
sed is great

$ echo sed is cool | sed 's^cool^great^g'
sed is great

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

$ echo sed is cool | sed 'swcoolwgreatwg'
sed is great

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

$ echo sed is cool | sed 'slcoo\llgreatlg'
sed is great


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

$ echo sed is not cool | sed '\|not|d'

#sed
#bre

@bash_tips
להיות פרודוקטיבי rename
רמת קושי: #advanced

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

$ rename 's/.txt/.log/' *.txt
$ rename 's/_/ /' *.pdf
$ rename 's/[[:punct:]]/ /' *.pdf

אנו מגדירים על אלו קבצים הפקודה תתבצע (*.txt), ועל אותם הקבצים חל ביטוי ההחלפה ( 's/.txt/.log/' ).

לא סגורים על איך השינוי שאנו הולכים לעשות יראה בסופו של דבר? בעזרת הדגל -n ניתן להשתמש בפקודה על "יבש" ורק אז להריץ אותה באמת.

$ rename -n 's|log|txt|' *.log
rename(10.log, 10.txt)
rename(1.log, 1.txt)
rename(2.log, 2.txt)
rename(3.log, 3.txt)
...

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

נ.ב. ימים אחרונים לאתגר ולאחר מכן אפרסם פתרון אפשרי.
#rename

@bash_tips
Bash Tips
מילונים / מערכים אסוציאטיבים ובאש מאז הגרסאות האחרונות של באש יש אובייקט חדש שמוכר מכל שפת תכנות נפוצה הלא הוא מילון/מערך אסוציטיבי, ניתן להגדיר אותו על ידי שימוש ב declare שדיברנו עליו בעבר $ declare -A my_dict $ my_dict=(["First Name"]="Yossi" ["Last Name"]="Cohen")…
מפתחות וערכים
רמת קושי: #advanced

כפי שראינו בעבר הגדרה של מערך נראית כך

$ declare -A my_array
$ my_array=([first]="test here" [second]="more text here")

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

$ echo "${my_array[first]}"
test here
$ echo "${my_array[second]}"
more text here

אפשרות נוספת שבאש מאפשרת לנו היא לרוץ רק על הערכים על ידי שימוש ב @ במקום מפתח

$ for i in "${my_array[@]}"; do
echo $i
done

test here
more text here

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

$ for i in "${!my_array[@]}"; do
echo $i
done

first
second

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

$ echo "${#my_array[@]}"
2


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

נ.ב. ימים אחרונים לאתגר ולאחר מכן אפרסם פתרון אפשרי.
#array

@bash_tips
לקבץ פקודות ותת מעטפת
רמת קושי: #advanced

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

לדוגמה
הקוד הבא לא ישרשר את שני המילים לקובץ test אלא ידפיס אחד למסך ואחד לקובץ המדובר

$ echo first; echo second > /tmp/test
first
$ cat /tmp/test
second

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

$ (echo first echo second) > /tmp/test
$ cat /tmp/test
first
second

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

השמה בתת מעטפת

$ (a=1; b=2; c=3; echo $a-$b-$c)
1-2-3
$ echo $a-$b-$c
--

השמה במעטפת הראשית

$ {a=1; b=2; c=3; echo $a-$b-$c}
1-2-3
$ echo $a-$b-$c
1-2-3

#subshell
#grouping_commands

נ.ב. ימים אחרונים לאתגר ולאחר מכן אפרסם פתרון אפשרי.

@bash_tips
רמת קושי: #advanced

פוסט נהדר של ינון פרק
אני מדביק כאן את הלינק לפוסט כי הדיון בתגובות פשוט מעניין

https://t.me/c/1217780911/5892

#cal
#ncal

@bash_tips