לעבוד עם טווח, cut
רמת קושי: #beginners
פקודת cut מאפשרת לבחור תווים או עמודות מהטקסט על ידי אינדקס או טווח
מהם עמודות אם כך?
זהו בעצם החלק השימושי באמת בפקודה, עמודות הן כל קטע טקסט שנחליט, ברגע שנגדיר עם d (delimiter)- שתו מסויים הוא זה שמפצל את הטקסט, כל הטקסט הופך להיות כעין טבלה דמיונית שאפשר לבחור ממנה מידע על פי מיקום העמודה, וטוב מראה עיניים אז...
דגל -d מקבל תו אחד בלבד, כשרוצים לפצל לפי רווח ניתן לגרגש את הרווח, הטריק הזה לצערנו לא יעבוד עם תווי שורה חדשה, טאב וכו'
@bash_tips
רמת קושי: #beginners
פקודת cut מאפשרת לבחור תווים או עמודות מהטקסט על ידי אינדקס או טווח
$ echo ABCDEFG | cut -c 3
C
$ echo ABCDEFG | cut -c 3-5
CDE
$ echo ABCDEFG | cut -c 1,3,5
ACE
$ echo ABCDEFG | cut -c 3-
CDEFG
מה היה לנו כאן? דגל c- (characters) מקבל תו/מערך/טווח מתוך טקסט ומחזיר אותו, בדוגמה האחרונה אפשר לראות איך מגדירים את הטווח עד סוף הטקסט מבלי לתת אינדקס ספציפי, צורה העבודה של תווים עובדת כמעט אחד לאחד עם עמודות, מה שמוביל לשאלה הבאהמהם עמודות אם כך?
זהו בעצם החלק השימושי באמת בפקודה, עמודות הן כל קטע טקסט שנחליט, ברגע שנגדיר עם d (delimiter)- שתו מסויים הוא זה שמפצל את הטקסט, כל הטקסט הופך להיות כעין טבלה דמיונית שאפשר לבחור ממנה מידע על פי מיקום העמודה, וטוב מראה עיניים אז...
$ cat users
name,user id,telegram account
coco,5635634356,no
roni,996873823,yes
tom,7424743356,yes
$ cut -f 1 -d , users
name
coco
roni
tom
$ cut -f 2 -d , users
user id
5635634356
996873823
7424743356
יש לנו קובץ בשם users שמכיל מידע בתצורת CSV (פסיקים שמפרידים בין ערכים), הגדרנו חלוקה לפי תו פסיק ומשם ניתן לבחור איזה עמודה להציג עם ידי העברת אינדקס העמודה לדגל -fדגל -d מקבל תו אחד בלבד, כשרוצים לפצל לפי רווח ניתן לגרגש את הרווח, הטריק הזה לצערנו לא יעבוד עם תווי שורה חדשה, טאב וכו'
$ echo "Good Morning" | cut -f 1 -d ' '
Good
$ echo "Good\nMorning" | cut -f 1 -d '\n'
cut: the delimiter must be a single character
Try 'cut --help' for more information.
וגם כאן כמו בדוגמאות שבתחילת הפוסט, ניתן לבחור מספר עמודותcut -f 1,3,5 -d ' '
רצףcut -f 3-5 -d ' '
או מעמודה מסויימת עד העמודה האחרונהcut -f 3- -d ' '
#cut@bash_tips
לפרמט את היסטוריה
רמת קושי: #beginners
כלי מוכר בלינוקס מאפשר לראות את ההיסטוריה של הפקודות שהורצו על מכונה או משתמש מסויים על ידי הרצה של פקודת
למה לפרמט?
הבעיה עם הפלט של פקודת history הוא שאין לנו מושג איזו פקודה הורצה מתי אלא רק רשימה ממוספרת, ולא מעט פעמים זהו מידע מעניין שעשוי לתת לנו יותר מרמז למה דברים מוזרים מתרחשים במכונה.
לפרמט
בכדי להציג שעה ותאריך לכל פקודה בהיסטוריה צריך להגדיר את המשתנה הגלובלי
הערות
* לכל הדואגים עדין אפשר להריץ !258.
* כמו שאנו מכירים בכדי לגרום להתנהגות הזאת להישאר קבועה, פשוט להכניס את הexport לbashrc ולעשות source.
#history
#env_variable
@bash_tips
רמת קושי: #beginners
כלי מוכר בלינוקס מאפשר לראות את ההיסטוריה של הפקודות שהורצו על מכונה או משתמש מסויים על ידי הרצה של פקודת
history
למה לפרמט?
הבעיה עם הפלט של פקודת history הוא שאין לנו מושג איזו פקודה הורצה מתי אלא רק רשימה ממוספרת, ולא מעט פעמים זהו מידע מעניין שעשוי לתת לנו יותר מרמז למה דברים מוזרים מתרחשים במכונה.
לפרמט
בכדי להציג שעה ותאריך לכל פקודה בהיסטוריה צריך להגדיר את המשתנה הגלובלי
HISTTIMEFORMAT
ונקבל רטרואקטיבית את הזמנים בהם הורצו הפקודות$ export HISTTIMEFORMAT="%d/%m/%y %T "
$ history
256 11/06/21 11:05:32 init 0
257 11/06/21 11:05:32 su user -
258 11/06/21 11:05:32 ls
259 11/06/21 11:05:32 python
260 11/06/21 11:05:32 rm users
...
הערות
* לכל הדואגים עדין אפשר להריץ !258.
* כמו שאנו מכירים בכדי לגרום להתנהגות הזאת להישאר קבועה, פשוט להכניס את הexport לbashrc ולעשות source.
#history
#env_variable
@bash_tips
שימוש חוזר בהיסטוריה
רמת קושי: #beginners
אם כבר בהיסטוריה עסקינן אז סימן קריאה ומספר השורה יריץ את שורה המצויינת בהיסטוריה שוב
בכדי להריץ את הפקודה האחרונה שכתבתם שוב או כדי להעביר אותה כפרמטר ניתן להשתמש ב!!
#history
#operations
@bash_tips
רמת קושי: #beginners
אם כבר בהיסטוריה עסקינן אז סימן קריאה ומספר השורה יריץ את שורה המצויינת בהיסטוריה שוב
$ history
100 ls
101 ls -lah
102 tree
...
$ !102
.
├── [
├── a2p
├── addr2line
├── alias
בכדי להריץ את הפקודה האחרונה שכתבתם שוב או כדי להעביר אותה כפרמטר ניתן להשתמש ב!!
abc@abc-home:~$ apt install aaa
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?
abc@abc-home:~$ sudo !!
sudo apt install aaa
[sudo] password for
abc
:
#history
#operations
@bash_tips
לוגים, הקדמה 1 tee
רמת קושי: #beginners
פקודת
נראה עוד דוגמה
רגע מה קורה למה הקובץ לא מכיל את הודעת השגיאה שפקודת ls החזירה?
הסיבה היא ש pipe מעביר רק stdout ולכן כדי להשתמש ב tee בצורה יעילה כדאי לשרשר את stderr לstdout על ידי 2<&1
אם נחזור לדוגמה הקודמת אז הפקודה צריכה להראות כך
חשוב לציין שבכל הרצה הפקודה תדרוס את הקובץ מחדש, בכדי להוסיף תוכן לקובץ מבלי לדרוס אותו כל פעם מחדש ניתן להשתמש בדגל -a
#tee
#redirection
@bash_tips
רמת קושי: #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
לוגים, הקדמה 2 exec
רמת קושי: #advanced
פקודת
רגע מה???, למה שמישהו ירצה לעזאזל להריץ פקודת באש על פקודת exec במקום להריץ ישירות על באש את הפקודה הרצויה?
פקודת
מה שבעצם קורה הוא שexec לא פותח תהליך חדש אלא מתלבש על התהליך הקיים ויוצא כשהוא מסיים (בקשר לזה עוד בהערה).
פקודת
הרצת
הרצת
כפי שניתן לראות לאחר שהרצנו
נ.ב. שימוש בexec עם פרמטר יוצר בעצם את הרצף הבא
מאחר ו
#exec
#redirection
@bash_tips
רמת קושי: #advanced
פקודת
exec
כמו שהיא נשמעת היא פקודת באש שמריצה פקודות באש מתוך באשbash >> command
bash >> exec >> command
רגע מה???, למה שמישהו ירצה לעזאזל להריץ פקודת באש על פקודת exec במקום להריץ ישירות על באש את הפקודה הרצויה?
פקודת
exec
יודעת לנהל את הפלט של הסקריפט ממש כמו שנריץ בטרמינל עצמו, במילים אחרות אפשר לומר שזה כמו הרצה של באש מתוך הסקריפט.מה שבעצם קורה הוא שexec לא פותח תהליך חדש אלא מתלבש על התהליך הקיים ויוצא כשהוא מסיים (בקשר לזה עוד בהערה).
פקודת
exec
עובדת בשני צורות אחת עם פרמטר והשניה בלי פרמטר,הרצת
exec
עם פרמטר (פקודה) תגרום לכך שרק הפקודה שהועברה כפרמטר תרוץ תחת exec
.$ exec ls > myfile.log
הרצת
exec
בלי פרמטר תגרום לכך שכל מה שיכתב לאחר מכן ירוץ תחת exec
, אם אנו חוזרים לאנלוגיה ממקודם אז זה כמו לפתוח באש חדש מתוך באש, כל מה שנריץ ירוץ בעצם בתוך המעטפת החדשה שיצרנו.$ ls
1.txt 2.txt 3.txt
$ exec > myfile.log
$ ls
$ cat myfile.log
$ 1.txt 2.txt 3.txt
כפי שניתן לראות לאחר שהרצנו
exec
פקודת ls
כבר לא מחזירה פלט לטרמינל אלא ישירות לקובץ.נ.ב. שימוש בexec עם פרמטר יוצר בעצם את הרצף הבא
bash >> exec >> ls >> exit
מאחר ו
exec
משתלט בעצם על התהליך שכבר רץ הלא הוא באש ולא יוצר תהליך חדש משל עצמו אז כשהוא מסיים לרוץ הוא מחזיר קוד יציאה וסוגר את התהליך עליו הוא השתלט, זוהי בעצם הסיבה למה טרמינלים עפים וחיבורי ssh נסגרים.#exec
#redirection
@bash_tips
לוגים, על exec וניתוב פלט
רמת קושי: #advanced
באש היא שפת סקריפט שתפקידה בגדול זה להפוך תהליכים לאוטומטים, אבל לא משנה כמה נתאמץ להגן על הקוד שלנו עדין נרצה שיהיה לנו לוג שיציג את מה שעבר על הסקריפט ואם אפשר אז להכניס ללוג כמה שיותר פלט רלוונטי ופחות פלט שהוא קשקוש מוחלט.
המשימה: יצירת לוג אינפורמטיבי
פתרון 1
הפתרון הראשון שמיד יעלה לנו לראש הוא ליצור איזה פונקציה שעושה echo לכל מה שנעביר לה לתוך קובץ, משהו שנראה כך
אוקי נראה אחלה, איפה הבעיה?
הבעיה היא שכרגע המצב הוא שרק מתי שנקרא לפונקציית הלוגר היא תכתוב נתונים לקובץ הלוג, מה שאומר שכמעט לכל פקודה שאריץ אצטרך לאסוף את הפלט שלה.
וזה עוד לא החלק הבאמת בעייתי, מה קורה אם לדוגמה פקודה מסויימת נכשלת ומחזירה שגיאה? בגלל שלא קראנו לפונקציית הלוגר הפלט לא יכתב ללוג וזה ממש חבל כי זה בדיוק הפלט שהיינו רוצים שיופיע.
אם כך נשנה מעט את המשימה שלנו
המשימה: יצירת לוג אינפורמטיבי אוטומטי
פתרון 2
אז מה שאנו מחפשים בעצם היא יכולת גלובלית יותר לתפוס את כל הפלט של הסקריפט, איך נעשה את זה? הדרך הפשוטה היא פשוט לאסוף את הפלט בזמן שאנו קוראים לסקריפט
מצד שני אם היינו יכולים לקרוא לסקריפט בצורה כמו זאת מהסקריפט עצמו זה היה יכול להיות נהדר.
פתרון 3
שימוש פקודת exec אותה ראינו בפוסט הקודם, אם נחשוב על הבעיה הקודמת שהיתה לנו בפתרון 2 נוכל לראות איך שימוש בכלי "חיצוני" כחלק מהסקריפט יכול לעזור לנו.
מה שלא ממש צויין בטיפ הקודם הוא שפקודת exec תוכל גם לנתב את הפלט עבורנו, וכל עוד לא נעביר לה פרמטר exec ינתב את הפלט של הסקריפט כולו.
אתגר בקצה
אחלה אם כן יש לנו פתרון נהדר, היכן עוד נוכל לשפר אותו?
כמו שאנו מכירים כל לוג אמור להכיל עוד פרטים מעבר לפלט, שעה ותאריך לדוגמה, או כל דבר אחר שנרצה שהלוג יכיל, מן הסתם נרצה שלפני שהפלט יכתב לקובץ הלוג שהוא יעבור תהליך כלשהו כדי שהלוג יהיה קריא ומועיל וכו'
איך נוכל לגרום לפלט להיות בפורמט של לוג?
מוזמנים לשלוח רעיונות
#process_substitution
#logging
#exec
#tee
@bash_tips
רמת קושי: #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
עוד קצת
רמת קושי: #beginners
הכרנו לא מזמן
להעביר פלט אחד למספר פקודות על ידי שימוש ב process substitution, לא מדובר כאן על עיבוד פלט ושרשור הלאה, אלה על העברה של פלט גולמי למספר תהליכים שונים (הנה קמח, אני רוצה פיצה ובורקס)
ליצור מספר קבצים בעלי תוכן מסויים, כמובן שניתן רק להוסיף את התוכן על ידי שימוש בדגל -
כתיבת מידע לקובץ בעל הרשאות רוט
(תודה ל @tomer על הטיפ!
#tee
#process_substitution
@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
מילוי קלט אינטרקטיבי
רמת קושי: #beginners
ישנן 2 דרכים עיקריות להעביר פרמטרים לסקריפט, האחת על ידי העברת הפרמטרים בעת קריאה לסקריפט
וישנה הדרך האנטרקטיבית בה הסקריפט רץ ובשלב מסויים ממתין לקלט מהמשתמש
בעוד שהרצת סקריפט שמצפה לקלט אינטרקטיבי עשויה להיות ידידותית למשתמש, זה לא יהיה יעיל בכלל כשמדובר על הרצה כחלק מתהליך CI אוטומטי כזה או אחר.
בכדי להתגבר על בעיה זו ניתן ליצור קובץ שמכיל את כל הנתונים שהסקריפט הולך לבקש ולשרשר אותם לסקריפט בעזרת pipe, בא נראה איך הקוד של הסקריפט בעצם נראה
כפי שניתן לראות בשורה הראשונה של הפלט אנו רואים כביכול ששום ערך לא עבר אל המשתנים, הפלט הזה מגיע כחלק מה input. מיד לאחר מכן בשורה הבאה בא אנו רואים שפקודת print אכן מדפיסה את הערך שהעברנו למשתנים.
אז מה יצא לנו
העברת נתונים לסקריפט בצורה אוטומטית? יש
מיסוך המידע שהעברנו לסקריפט? יש
#parameters
#interactive
@bash_tips
רמת קושי: #beginners
ישנן 2 דרכים עיקריות להעביר פרמטרים לסקריפט, האחת על ידי העברת הפרמטרים בעת קריאה לסקריפט
$ myscript.sh username passwor
dוישנה הדרך האנטרקטיבית בה הסקריפט רץ ובשלב מסויים ממתין לקלט מהמשתמש
$ ./myscript.sh
Welcome to my awesome script
Enter your username:
בעוד שהרצת סקריפט שמצפה לקלט אינטרקטיבי עשויה להיות ידידותית למשתמש, זה לא יהיה יעיל בכלל כשמדובר על הרצה כחלק מתהליך CI אוטומטי כזה או אחר.
בכדי להתגבר על בעיה זו ניתן ליצור קובץ שמכיל את כל הנתונים שהסקריפט הולך לבקש ולשרשר אותם לסקריפט בעזרת pipe, בא נראה איך הקוד של הסקריפט בעצם נראה
$ cat my_interactive_script.py
#!/usr/bin/python3
user = input('Enter username: ')
pwd = input('Enter password: ')
print(f'\nusername: {user}, password: {pwd}')
סקריפט פשוט שמצפה ל2 קלטים מהמשתמש.
כך נראה הקובץ שמכיל את הפרטים אותם אנו רוצים להעביר לסקריפט
$ cat account_details
myusername
mypassword
כעת נשרשר את קובץ נושא הפרטים לסקריפט בצורה הבאה
$ cat account_details | my_interactive_script.py
Enter username: Enter password:
username: myusername, password: mypa
sswordכפי שניתן לראות בשורה הראשונה של הפלט אנו רואים כביכול ששום ערך לא עבר אל המשתנים, הפלט הזה מגיע כחלק מה input. מיד לאחר מכן בשורה הבאה בא אנו רואים שפקודת print אכן מדפיסה את הערך שהעברנו למשתנים.
אז מה יצא לנו
העברת נתונים לסקריפט בצורה אוטומטית? יש
מיסוך המידע שהעברנו לסקריפט? יש
#parameters
#interactive
@bash_tips
לרוץ כ root
רמת קושי: #beginners
טיפ חביב שלמדתי, הפקודה שלנו בלינוקס כדי להחליף משתמש היא su, אם כן כשאנו רוצים לשנות לroot מה שנרצה להריץ זה
ההתנהגות שראינו ככל הנראה אינה נכונה לכל המערכות אלא להפצות מבוססות אובונטו, הסיבה לכך היא שבאותן הפצות root מגיע ללא סיסמה מוגדרת ולכן אי אפשר לעשות אליו לוגין אלא אם כן משתמשים ב
#sudo
#su
@bash_tips
רמת קושי: #beginners
טיפ חביב שלמדתי, הפקודה שלנו בלינוקס כדי להחליף משתמש היא su, אם כן כשאנו רוצים לשנות לroot מה שנרצה להריץ זה
$ su rootהפתעה, מסתבר שזה עובד על כל משתמש אחר אבל על root זה לא עובד
Password:
su: Authentication failure
ההתנהגות שראינו ככל הנראה אינה נכונה לכל המערכות אלא להפצות מבוססות אובונטו, הסיבה לכך היא שבאותן הפצות root מגיע ללא סיסמה מוגדרת ולכן אי אפשר לעשות אליו לוגין אלא אם כן משתמשים ב
sudo
, אם כן user@home ~ $ sudo su rootוזה אכן יעבוד לאחר אימות של
root@home ~
sudo
דרך קצרה יותר לעשות את זה היא user@home ~ $ sudo bash#bash
root@home ~ $
#sudo
#su
@bash_tips
Forwarded from shahar
למצוא את הדרך
רמת קושי: #beginners
כאשר אנחנו מריצים פקודה כגון
$
כיצד המערכת יודעת מה זה curl, ואיפה הבינארי של curl נמצא?
משתנה הסביבה PATH הוא זה שנותן לנו להריץ פקודות ללא צורך בציון הנתיב המלא לבינארי שאנו מנסים להריץ, הוא הסיבה שאנחנו לא צריכים לכתוב
הדרך שבה PATH עובד הוא שאם מוגדר לנו
ואנחנו מנסים להריץ משהו שנקרא curl, אז המערכת תחפש את הבינארי curl קודם בfoo ואחר"כ בbar, במידה והיא מצאה בfoo את הבינארי, המערכת תריץ את curl שבתוך foo, ואפילו לא תחפש את curl בתוך bar.
במידה ולא נמצא שום בינארי בתוך התקיות המצויינות בPATH המערכת תזרוק שגיאה שתגיד:
אפשרי להוסיף תקיות משלנו ע"י לשים שורה כזאת בתוך .bashrc
ככה אנחנו יכולים להוסיף לPATH תקיות מבלי לפגום בשימוש הסדיר של המערכת
#env_variable
#path
@bash_tips
רמת קושי: #beginners
כאשר אנחנו מריצים פקודה כגון
$
curl example.com
כיצד המערכת יודעת מה זה curl, ואיפה הבינארי של curl נמצא?
משתנה הסביבה PATH הוא זה שנותן לנו להריץ פקודות ללא צורך בציון הנתיב המלא לבינארי שאנו מנסים להריץ, הוא הסיבה שאנחנו לא צריכים לכתוב
/usr/bin/curl example.com
הדרך שבה PATH עובד הוא שאם מוגדר לנו
PATH="/foo:/bar"
ואנחנו מנסים להריץ משהו שנקרא curl, אז המערכת תחפש את הבינארי curl קודם בfoo ואחר"כ בbar, במידה והיא מצאה בfoo את הבינארי, המערכת תריץ את curl שבתוך foo, ואפילו לא תחפש את curl בתוך bar.
במידה ולא נמצא שום בינארי בתוך התקיות המצויינות בPATH המערכת תזרוק שגיאה שתגיד:
curl: command not found
אפשרי להוסיף תקיות משלנו ע"י לשים שורה כזאת בתוך .bashrc
export PATH="/path/to/my/scripts/dir:$PATH"
ככה אנחנו יכולים להוסיף לPATH תקיות מבלי לפגום בשימוש הסדיר של המערכת
#env_variable
#path
@bash_tips
shahar
למצוא את הדרך רמת קושי: #beginners כאשר אנחנו מריצים פקודה כגון $ curl example.com כיצד המערכת יודעת מה זה curl, ואיפה הבינארי של curl נמצא? משתנה הסביבה PATH הוא זה שנותן לנו להריץ פקודות ללא צורך בציון הנתיב המלא לבינארי שאנו מנסים להריץ, הוא הסיבה שאנחנו…
זה המקום להגיד תודה רבה לשחר @bananabun על הפוסט ועל אלו שעוד יגיעו אחריו.
מצאתם משהו חביב בבאש? סתם איזו התנהגות של מעניינת של באש שכדאי להיות מודעים אליה?
מוזמנים לשלוח טיפים לערוץ והרחיב את הידע של כולנו
@bash_tips
מצאתם משהו חביב בבאש? סתם איזו התנהגות של מעניינת של באש שכדאי להיות מודעים אליה?
מוזמנים לשלוח טיפים לערוץ והרחיב את הידע של כולנו
@bash_tips
שבאנג!
רמת קושי: #beginners
כאשר אנחנו מריצים סקריפט שכתבנו ע"י:
בברירת המחדל המערכת תריץ את הקובץ באמצעות bash (יש כמה מקרים שבהם זה לא קורה, אבל זה מחוץ לscope של הפוסט), והדרך לשנות את ההתנהגות הדיפולטיבית היא שימוש במשהו שנקרא shebang, הshebang תמיד יופיע בתחילת הקובץ והוא יראה כך:
אפשרי להסתכל על זה בצורה הבאה:
אם יש לנו קובץ ששמו הוא "cool_script" והתוכן שלו הוא:
ואנחנו מריצים אותו ע"י:
מה שבעצם מורץ מאחורי הקלעים זה:
הshebang הוא דבר מאד שימושי, ויש אותו בכל מקום במערכת, לדוגמה יש המון פקודות במערכת שהן בעצם סקריפטים של באש\פייטון\פרל\וכו', והדרך שבה המערכת יודעת כיצד להריץ כל קובץ זה באמצעות אותו shebang.
אפשרי גם לקחת את הshebang צעד אחד קדימה ולשלב בפנים ארגומנטים. דוגמה שימושית היא הshebang:
אשר תגרום לסקריפט להדפיס כל דבר שהוא עושה (עוזר לדיבוג).
עוד "סוג" של shebang נפוץ הוא הshebang:
ההבדל בין ה"סוגים" הוא שהאחד תמיד ישתמש באותו הבינארי אשר יהיה בדיוק באותו המקום. בעוד שהשני הוא דינאמי, מאחר והוא משתנה בהתאם לPATH שלנו, אפשרי להסתכל עליו כמשהו ששווה בערך ל:
על פניו נראה שenv תמיד יהיה עדיף, אבל יש לו חיסרון אחד, וזה שאי אפשר להעביר לו ארגומנטים, מה שאומר שמשהו כמו:
לא יעבוד, ולכן צריך להשתמש בכל אחד מה"סוגים" ע"פ צורך
קרדיט: תודה לשחר @bananabun האלוף!
#shebang
#execute_script
@bash_tips
רמת קושי: #beginners
כאשר אנחנו מריצים סקריפט שכתבנו ע"י:
$ ./some_ambiguous _script
בברירת המחדל המערכת תריץ את הקובץ באמצעות bash (יש כמה מקרים שבהם זה לא קורה, אבל זה מחוץ לscope של הפוסט), והדרך לשנות את ההתנהגות הדיפולטיבית היא שימוש במשהו שנקרא shebang, הshebang תמיד יופיע בתחילת הקובץ והוא יראה כך:
#!/path/to/interpreter
אפשרי להסתכל על זה בצורה הבאה:
אם יש לנו קובץ ששמו הוא "cool_script" והתוכן שלו הוא:
#!/usr/bin/python3
print("This script was executed via python3")
ואנחנו מריצים אותו ע"י:
$ ./cool_script
מה שבעצם מורץ מאחורי הקלעים זה:
$ /usr/bin/python3 cool_script
הshebang הוא דבר מאד שימושי, ויש אותו בכל מקום במערכת, לדוגמה יש המון פקודות במערכת שהן בעצם סקריפטים של באש\פייטון\פרל\וכו', והדרך שבה המערכת יודעת כיצד להריץ כל קובץ זה באמצעות אותו shebang.
אפשרי גם לקחת את הshebang צעד אחד קדימה ולשלב בפנים ארגומנטים. דוגמה שימושית היא הshebang:
#!/bin/bash -x
אשר תגרום לסקריפט להדפיס כל דבר שהוא עושה (עוזר לדיבוג).
עוד "סוג" של shebang נפוץ הוא הshebang:
#!/usr/bin/env foo
ההבדל בין ה"סוגים" הוא שהאחד תמיד ישתמש באותו הבינארי אשר יהיה בדיוק באותו המקום. בעוד שהשני הוא דינאמי, מאחר והוא משתנה בהתאם לPATH שלנו, אפשרי להסתכל עליו כמשהו ששווה בערך ל:
#!$(which foo)
על פניו נראה שenv תמיד יהיה עדיף, אבל יש לו חיסרון אחד, וזה שאי אפשר להעביר לו ארגומנטים, מה שאומר שמשהו כמו:
#!/usr/bin/env bash -x
לא יעבוד, ולכן צריך להשתמש בכל אחד מה"סוגים" ע"פ צורך
קרדיט: תודה לשחר @bananabun האלוף!
#shebang
#execute_script
@bash_tips
להעביר שגיאות ב pipe
רמת קושי: #beginners
דבר קטן וחשוב שכדאי להכיר
כולנו מכירים את השימוש ב pipe בבאש, להעביר פלט של פקודה אחת לפקודה אחרת, מה שלא כולם יודעים זה שpipe מעביר רק stdout ולא stderr
כפי שרואים השגיאה הודפסה ישירות לטרמינל ופקודת wc לא קיבלה שום פלט (ערך 0)
איך כן?
בכדי להעביר גם את stderr וגם את stdout דרך ה pipe צריך להריץ את ה pipe בצורה הבאה עם
#pipe
#redirection
@bash_tips
רמת קושי: #beginners
דבר קטן וחשוב שכדאי להכיר
כולנו מכירים את השימוש ב pipe בבאש, להעביר פלט של פקודה אחת לפקודה אחרת, מה שלא כולם יודעים זה שpipe מעביר רק stdout ולא stderr
$ ls /not_exist | wc -l
ls: cannot access /not_exist: No such file or directory
0
כפי שרואים השגיאה הודפסה ישירות לטרמינל ופקודת wc לא קיבלה שום פלט (ערך 0)
איך כן?
בכדי להעביר גם את stderr וגם את stdout דרך ה pipe צריך להריץ את ה pipe בצורה הבאה עם
&
$ ls /not_exist |& wc
1 9 50
#pipe
#redirection
@bash_tips
לאגד ולכווץ, tar
רמת קושי: #beginners
פקודת tar נותנת לנו את האפשרות ליצור ארכיונים (archives) של מידע, וגם את האפשרות לחילוץ המידע. או "בשפת העם", tar נותנת לנו גישה לייצג תיקיות וקבצים בפורמט של קובץ בודד.
כדי להכין קובץ tar (שלפעמים מכנים אותו "tarball"):
$
$
בגלל שהמטרה העיקרית של tar היא לאפשר לכווץ תיקיות, המפתחים של tar הכניסו בפנים את האפשרות לכווץ את ה tarball עם אלגוריתמים נפוצים כגון Bzip, Zstd ועוד. כך שבמקום לכתוב:
$
$
$
#tar
#archives
#compression
@bash_tips
רמת קושי: #beginners
פקודת tar נותנת לנו את האפשרות ליצור ארכיונים (archives) של מידע, וגם את האפשרות לחילוץ המידע. או "בשפת העם", tar נותנת לנו גישה לייצג תיקיות וקבצים בפורמט של קובץ בודד.
כדי להכין קובץ tar (שלפעמים מכנים אותו "tarball"):
$
tar -c -f output.tar path/to/dir/
כדי לחלץ את המידע:$
tar -x -f output.tar
הסיבה לכך שtar כלכך שימושי, היא שכיווץ פועל על קבצים ולא על תיקיות, מה שאומר שכן אפשרי לכווץ את קובץ הtar.בגלל שהמטרה העיקרית של tar היא לאפשר לכווץ תיקיות, המפתחים של tar הכניסו בפנים את האפשרות לכווץ את ה tarball עם אלגוריתמים נפוצים כגון Bzip, Zstd ועוד. כך שבמקום לכתוב:
$
tar -c -f output.tar path/to/file path/to/dir && gzip output.tar
אפשר לכתוב:$
tar -z -c -f output.tar.gz path/to/file path/to/dir
וכדי לחלץ את ה tarball המכווץ אפשר לעשות:$
tar -z -x -f output.tar.gz
קרדיט: תודה לשחר @bananabun האלוף על הפוסט.#tar
#archives
#compression
@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
לכתוב תנאים - הרחבה
רמת קושי: #beginners
מספר דרכים לכתוב תנאי בבאש, להלן קצת סדר
סוגריים עגולים כפולים (( ))
סוג תנאי שעובד רק על מספרים ומתאים לבדיקת פעולות חשבוניות.
פקודה הבודקת ביטויי השוואה ממש כמו if, מחזירה true ל0 וfalse לכל מה שאינו 0
פקודה המבצעת בדיוק את את אותן פעולת שמבצעת פקודת test, ההבדל היחידי בין השניים הוא שפקודת test תגיב לדגלי
חשוב לשים לב שמשתמשים ותיקים עלולים לתהות מה ההבדל בין
ובכן, בעוד הראשון הוא לעתים פקודה בפני עצמה (מקבילה ל־
$
למשל, במקום
אופרטור =~ מה חשוב לדעת?
חשוב רק לציין שבמידה ומשתמשים באופרטור ההשוואה
$
קרדיט: תודה רבה לתומר @tomer מקבוצת @linux_il על הפוסט! (אז מה אם הוא השתנה מעט)
למי שלא מכיר קבוצת לינוקס ישראל היא אחת הקבוצות היותר טובות והיותר פעילות בטלגרם (כל עוד לא מדברים על קאלי).
#[
#if
#test
#regex
#conditions
@bash_tips
רמת קושי: #beginners
מספר דרכים לכתוב תנאי בבאש, להלן קצת סדר
סוגריים עגולים כפולים (( ))
סוג תנאי שעובד רק על מספרים ומתאים לבדיקת פעולות חשבוניות.
if (( 1 == 1 )); thenפקודת test
...
פקודה הבודקת ביטויי השוואה ממש כמו if, מחזירה true ל0 וfalse לכל מה שאינו 0
test 1 -ne 0סוגרים מרובעים בודדים [ ]
test string1 = string2
test -n string
...
פקודה המבצעת בדיוק את את אותן פעולת שמבצעת פקודת test, ההבדל היחידי בין השניים הוא שפקודת test תגיב לדגלי
--help, ו --version
if [ 1 -ne 0 ]סוגריים מרובעים כפולים [[ ]]
if [ string1 = string2 ]
if [ -n string ]
חשוב לשים לב שמשתמשים ותיקים עלולים לתהות מה ההבדל בין
[
ל [[
. ובכן, בעוד הראשון הוא לעתים פקודה בפני עצמה (מקבילה ל־
test
) $
whereis [
[: /usr/bin/[ /usr/share/man/man1/[.1.gzהשנייה היא רק פקודה מובנית ב־shell ונותנת לנו יכולות מתקדמות יותר.
למשל, במקום
-eq
כדי לבחון שיוויון, אפשר להשתמש בסימן שיוויון נורמלי. if [[ 1 -eq 1 ]]
לעומתif [[ 1 = 1 ]]
וברמת העיקרון אפשר גם לוותר על תחימה במרכאות של מחרוזות שכוללות תו רווח כי ה־shell יצליח להבין איך להתמודד עם זה.if [ -f "$filename" ]
לעומתif [[ -f $filename ]]
כבונוס, ישנו את האופרטור החשוב =~ המאפשר להשתמש בביטויים רגולריים ישירות מתנאי ההשוואה, וכך לחסוך ביטויים לוגיים מורכבים.אופרטור =~ מה חשוב לדעת?
חשוב רק לציין שבמידה ומשתמשים באופרטור ההשוואה
=~
יש הבדל בין משתנה העטוף בגרשיים (להלן מגורגש) לכזה שאינו, ברגע שמעבירים לתנאי משתנה מגורגש הביטוי מחפש את כל מחרוזת הטקסט שבמשתנה בצורה גולמית ולא מנסה להשוות את המשתנה כביטוי regex$
cat file.txt
111+.*pdf{}[]$$
[[ $(cat file.txt) =~ "pdf{}" ]] && echo match
match$
[[ $(cat file.txt) =~ pdf{} ]] && echo match
$ echo $?
1מצד אחד זה מאפשר לנו לבדוק התאמה של תת מחרוזות שמכילות תווים מיוחדים בצורה גולמית, מצד שני מי שלא מכיר את צורת התנהגות זו עשוי לבזבז זמן ולתהות מדוע דברים אינם מתנהגים כמצופה.
קרדיט: תודה רבה לתומר @tomer מקבוצת @linux_il על הפוסט! (אז מה אם הוא השתנה מעט)
למי שלא מכיר קבוצת לינוקס ישראל היא אחת הקבוצות היותר טובות והיותר פעילות בטלגרם (כל עוד לא מדברים על קאלי).
#[
#if
#test
#regex
#conditions
@bash_tips
שימוש בsed עם extended regex
רמת קושי: #beginners
טיפ חביב וקצרצר בקשר ל sed, המבנה הבסיסי של הפקודה מתבסס על ביטוי regex ואז הוראה מה נרצה לבצע לכל דבר שתואם לביטוי, העניין הוא שsed ברירת מחדל אינו משתמש בתצורה המורחבת של regex.
בכדי לאפשר extended regex לsed ניתן להשתמש בדגל
#regex
#extended_regex
@bash_tips
רמת קושי: #beginners
טיפ חביב וקצרצר בקשר ל sed, המבנה הבסיסי של הפקודה מתבסס על ביטוי regex ואז הוראה מה נרצה לבצע לכל דבר שתואם לביטוי, העניין הוא שsed ברירת מחדל אינו משתמש בתצורה המורחבת של regex.
בכדי לאפשר extended regex לsed ניתן להשתמש בדגל
-E
או -r
$ sed -E 's/something_(aaa|bbb|ccc)//g#sed
#regex
#extended_regex
@bash_tips
עושים שיפט
רמת קושי: #advanced
אנו מכירים את צורת העברת פרמטרים לסקריפט באש, כל פרמטר מקבל מספר וניתן לגשת לפרמטרים לפי האינדקס שלהם על ידי $
לדוגמה אנו רוצים לבנות סקריפט שמדפיס את כל הפרמטרים שהוא מקבל, לשם כך נשתמש ב $*
פקודת shift היא כלי שמגיע כחלק מ bash builtin ומה שהיא נותנת זה "להזיז" את הפרמטרים מספר צעדים קדימה כך שהפרמטר הראשון יוסר מהרשימה ומה שהיה לפני כן במשתנה $2 יהפוך להיות $1
הטריק כמובן יעבוד גם על פונקציות
#shift
#scripting
#function
#parameters
@bash_tips
רמת קושי: #advanced
אנו מכירים את צורת העברת פרמטרים לסקריפט באש, כל פרמטר מקבל מספר וניתן לגשת לפרמטרים לפי האינדקס שלהם על ידי $
$ cat test.shלעיתים צורת העברה של פרמטרים לפי אינדקס יוצרת לנו בעיה, כי לא תמיד נרצה להעביר את כל הפרמטרים
echo $1
echo $2
echo $3
$ bash test.sh one two three
one
two
three
לדוגמה אנו רוצים לבנות סקריפט שמדפיס את כל הפרמטרים שהוא מקבל, לשם כך נשתמש ב $*
$ cat test.shמה קורה אם אנו רוצים שהפרמטר הראשון יהיה הוראה להדפיס את התוכן כ base64 וששאר הפרמטרים יודפסו כרגיל? אם ננסה את הפתרון ממקודם פשוט נדפיס גם את ההוראה בעצמה כחלק מהטקסט
echo "$*"
$ bash test.sh one two three
one two three
$ bash test.sh base64 one two threeפתרון אפשרי הוא לקחת את המערך של הפרמטרים ולהעביר את כל הפרמטרים חוץ מהפרמטר הראשון, ואת הפרמטר הראשון לשמור במשתנה נפרד
base64 one two three
action=$1דרך נקייה יותר לעשות את אותו הדבר היא להשתמש בפקודת shift
echo "${*:2}"
פקודת shift היא כלי שמגיע כחלק מ bash builtin ומה שהיא נותנת זה "להזיז" את הפרמטרים מספר צעדים קדימה כך שהפרמטר הראשון יוסר מהרשימה ומה שהיה לפני כן במשתנה $2 יהפוך להיות $1
$ cat test.shאם ניקח את הפתרון הזה לבעיה שהצגנו מקודם אפשרי יהיה לפתור את בעיית הפרמטרים בצורה הבאה
shift 1
echo $1
echo $2
echo $3
$ bash test.sh one two three
two
three
action=$1משתנה action מקבל את ההוראה אותה אנו רוצים להעביר לסקריפט, ואז אנו "מוחקים" אותו מרשימת הפרמטרים ומעבירים את שאר הפרמטרים הלאה.
shift 1
echo "${*}"
הטריק כמובן יעבוד גם על פונקציות
#shift
#scripting
#function
#parameters
@bash_tips
מפות ומערכים
רמת קושי: #beginners
בעבר דיברנו על מערכים וההפתעות שאנו עשויים להיתקל בהן, ישנם מספר דרכים ליצור מערכים בצורה בטוחה, זוהי הדרך ליצור מערך של שורות מקובץ .
פקודת
כברירת מחדל הפקודה טוענת את התוכן שלה למשתנה סביבה בשם
במידה ונעביר שם של משתנה התוכן יכניס למשתנה אותו העברנו
כפי שניתן להעביר קובץ, ניתן גם להעביר תוכן של משתנה למערך על ידי שימוש ב here-string
#array
#mapfile
#readarray
@bash_tips
רמת קושי: #beginners
בעבר דיברנו על מערכים וההפתעות שאנו עשויים להיתקל בהן, ישנם מספר דרכים ליצור מערכים בצורה בטוחה, זוהי הדרך ליצור מערך של שורות מקובץ .
פקודת
mapfile
והמקבילה שלה בבאש readarray
, הן בעצם אותו כלי שכל תפקידו זה לקבל תוכן מה stdin וליצור מערך לפי מספר השורות שיש בתוכן.כברירת מחדל הפקודה טוענת את התוכן שלה למשתנה סביבה בשם
MAPFILE
וצורת הפעולה שלה נראית כך.
$ mapfile < myfile
$ echo ${MAPFILE[@]}
one
two
three
במידה ונעביר שם של משתנה התוכן יכניס למשתנה אותו העברנו
$ mapfile mylist < myfile
$ echo ${mylist[@]}
one
two
three
כפי שניתן להעביר קובץ, ניתן גם להעביר תוכן של משתנה למערך על ידי שימוש ב here-string
$ mapfile mylist <<< "$myvar"
$ echo ${mylist[@]}
one
two
three
#array
#mapfile
#readarray
@bash_tips
מערכים ומפות read
רמת קושי: #beginners
בפוסט הקודם דיברנו על פקודת mapfile / readarray ואיך יהיה נכון יותר ליצור מערך של שורות מקובץ מבלי לבצע פעולות שלא אליהן התכוונו, מה אם מה שאנו צריכים זה ליצור מערך של מילים משורה בודדת?
את פקודת read ראינו בפוסטים קודמים, הפקודה מאפשרת לקבל ערכים מה stdin למשתנה, בצורתה הפשוטה הפקודה מעבירה את הקלט כמחרוזת, עם זאת ניתן לקבל את הקלט כמערך על ידי שימוש בפרמטר -a
חשוב לשים לב, הפקודה תיקח רק את השורה הראשונה שהועברה אליה ותפצל אותה למערך, ולכן במידה ומעבירים מחרוזת של מספר שורות כדאי להתשמש ב read while כפי שראינו בעבר, ולפצל את השורה כפי שראינו זה עתה.
#read
#array
@bash_tips
רמת קושי: #beginners
בפוסט הקודם דיברנו על פקודת mapfile / readarray ואיך יהיה נכון יותר ליצור מערך של שורות מקובץ מבלי לבצע פעולות שלא אליהן התכוונו, מה אם מה שאנו צריכים זה ליצור מערך של מילים משורה בודדת?
את פקודת read ראינו בפוסטים קודמים, הפקודה מאפשרת לקבל ערכים מה stdin למשתנה, בצורתה הפשוטה הפקודה מעבירה את הקלט כמחרוזת, עם זאת ניתן לקבל את הקלט כמערך על ידי שימוש בפרמטר -a
$ myline="one two three"
$ read -a mylist <<< "${myline}"
$ declare -p mylist
declare -a mylist='([0]="one" [1]="two" [2]="three")'
חשוב לשים לב, הפקודה תיקח רק את השורה הראשונה שהועברה אליה ותפצל אותה למערך, ולכן במידה ומעבירים מחרוזת של מספר שורות כדאי להתשמש ב read while כפי שראינו בעבר, ולפצל את השורה כפי שראינו זה עתה.
#read
#array
@bash_tips