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

בערוץ הבא תמצאו אוסף טיפים שימושיים ב-Bash והכרות עם כלים שונים שעשויים לחסוך מאמץ ועבודה בכתיבת סקריפטים ומימוש אוטומציות.
Download Telegram
Bash Tips
bash_tips-stop_recursion.sh
רקורסיה $0 $$, ושני אתגרונים בקצה
רמת קושי: #advanced

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

$ cat test.sh
echo "$0"

$ ./test.sh
./test.sh

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

$ cat test.sh
echo "$0 | $$"
sleep 20
$0

$ ./test.sh
./test.sh | 101394
./test.sh | 101395
./test.sh | 101396
...

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

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

אתגרונים אתגרונים
ועכשיו לשני אתגרים קטנים שתשתגעו עליהם.

1. איך לגרום לסקריפט החדש שרץ ($0) להחליף את מספר התהליך שלו מבלי להיות תת תהליך של התהליך המקורי ובכך לגרום לסקריפט המקורי להגיע לנקודת סיום ולשחרר את הזיכרון.

2. איך לסגור את הסקריפט הפשוט הבא (הקובץ המצוטט בערוץ) כשאתם מריצים אותו ברקע כך

$ ./bash_tips-stop_recursion.sh &


תוכן הקובץ
$ batcat bash_tips-stop_recursion.sh
───────┬────────────
│ File: test.sh
───────┼────────────
1 │ #!/bin/bash
2 │
3 │ echo "$0 | $$"
4 │ sleep 1
5 │ $0


מוזמנים לשתף בתגובות מה דגתם

#challenge
#arguments
#bash_pid


@bash_tips
להעביר מערכים לפונקציה
רמת קושי: #advanced

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

$ cat test.sh
myFunc(){
echo $1
echo $2
}
myFunc one two

$ bash test.sh
one
two

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

myFunc(){
echo $1
echo $2
}
myList=(one two)
myFunc ${myList[@]}

$ bash test.sh
one
two

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

myFunc(){
echo ${@}
echo $2
}
myList=(one two)
myFunc ${myList[@]} new_parameter

$ bash test.sh
one two new_parameter
two

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

פתרון 1: העברת מחרוזות
הפתרון הראשון הוא פשוט להעביר את המערך כמחרוזת ואז בפונקציה עצמה ליצור מערך חדש על ידי העברה של המחרוזת ל read כפי שראינו בעבר.

myFunc(){
read -r -a arr1 <<< ${1}
read -r -a arr2 <<< ${2}
declare -p arr1 arr2
}
arr1=(aaa bbb ccc)
arr2=(ddd eee fff)

myFunc "${arr1[*]}" "${arr2[*]}"

$ bash test.sh
declare -a arr1=([0]="aaa" [1]="bbb" [2]="ccc")
declare -a arr2=([0]="ddd" [1]="eee" [2]="fff")

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

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

$ cat test.sh
myFunc(){
func_arr1=( "${!1}" )
func_arr2=( "${!2}" )
declare -p func_arr1 func_arr2
}

arr1=("aaa" "bbb space" "ccc")
arr2=("ddd" "eee" "fff")
myFunc arr1[@] arr2[@]

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

$ bash test.sh
declare -a func_arr1=([0]="aaa" [1]="bbb space" [2]="ccc")
declare -a func_arr2=([0]="ddd" [1]="eee" [2]="fff")

#read
#array
#function
#arguments
#indirect_references

@bash_tips