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

בערוץ הבא תמצאו אוסף טיפים שימושיים ב-Bash והכרות עם כלים שונים שעשויים לחסוך מאמץ ועבודה בכתיבת סקריפטים ומימוש אוטומציות.
Download Telegram
אני רוצה לברך את כל תושבי הערוץ
בחג שמח ובשנה טובה מבורכת ועשירה


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

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

$ cat test.sh

key="value"
myvar="key"

echo "\${key} = ${key}"
echo "\${myvar} = ${myvar}"
echo "\${!myvar} = ${!myvar}"


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

$ bash test.sh
${key} = value
${myvar} = key
${!myvar} = value


מה היה לנו כאן?
שני השורות הראשונות דיי ברורות לנו, אנו קוראים למשתנה שמכיל מחרוזת והמחרוזת מודפסת, בשורה האחרונה לעומת זאת מתרחש החלק המעניין, אנו מדפיסים את השם של המשתנה (myvar) עם !, וזה בעצם שולח את באש לחפש אם קיים לה בזיכרון שם של משתנה בשם של המחרוזת (key), במידה והתשובה היא כן אנו נקבל את הערך של אותו משתנה (value) כאילו קראנו למשתנה עצמו.

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

$ cat test.sh
read -p "please enter exist ENV vartiable name: " var
echo "variable name ${var}: ${!var}"

$ bash test.sh
please enter exist ENV vartiable name: SHELL
variable name SHELL: /bin/bash


#indirect_references
#indirect_expansion

@bash_tips
👍1
להעביר מערכים לפונקציה
רמת קושי: #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
פוסט מעולה של ינון פרק
הערות על הפוסט בבקשה בערוץ של ינון
Forwarded from ToCode
# טיפ באש: השתמשו ב null glob כשצריך
את הלולאה הקצרה הזאת כתבתי בסקריפט בלי לחשוב יותר מדי:

#!/bin/bash -e

for json_file in /data/*
do
echo "Importing JSON file $json_file"
python import_json.py "$json_file"
echo "-- Done"
done


ולמה בלי לחשוב? כי אם הסקריפט import_json.py ינסה לפתוח את הקובץ שהוא מקבל לקריאה, והתיקיה ריקה, אנחנו נקבל את השגיאה:

FileNotFoundError: [Errno 2] No such file or directory: '/data/*'


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

# this will print all the files in /etc
$ echo /etc/*

# but this will just print "/data/*"
$ echo /data/*


הפקודה הראשונה באמת תדפיס את כל הקבצים והתיקיות מתוך /etc, והשניה תדפיס פשוט /data/*. כמובן שהמחרוזת שהודפסה מהפקודה השניה אינה באמת שם קובץ ולכן אי אפשר לפתוח אותה.

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

$ shopt -s nullglob
$ echo /data/*


והפעם לא מקבלים שום פלט. בתוך הלולאה אני מקבל בדיוק את ההתנהגות הרצויה:

#!/bin/bash -e

shopt -s nullglob

for json_file in /data/*
do
echo "Importing JSON file $json_file"
python import_json.py "$json_file"
echo "-- Done"
done


הפעם הסקריפט לא ינסה לפתוח קובץ עם השם המוזר /data* ופשוט לא יבצע אף פעם את גוף הלולאה כי באמת אין קבצים שמתאימים לביטוי.
פוסט יפה ומפורט מאוד של טל בן שושן על באש
רמת קושי: #beginners

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

@bash_tips
לחפש כשמכווץ zgrep
רמת קושי: #beginners

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

$ zgrep crash /var/log/syslog*
/var/log/syslog.4.gz ...
/var/log/syslog.5.gz ...
/var/log/syslog.9.gz ...
...


#archives
#zgrep
#grep
#zip

@bash_tips
סומסום היפתח
רמת קושי: #beginners

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

$ code myfile.log

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

$ k get pod/lala -o yaml | code -

כעת העורך מחבר את הstdin לפקודה והתוכן אפילו יכול להתעדכן בזמן אמת
(לא לשכוח Ctrl+C כשרוצים לסגור את החיבור)

$ journalctl -f | code -


#clipboard
#vscode
#code
#stdin

@bash_tips
לרזלב בלי hosts
רמת קושי: #advanced

כל מפתח ואיש סיסטם מכיר את הקובץ /etc/hosts, זהו בעצם הקובץ בו המערכת מחפשת כתובת אינטרנט כלשהיא לפני שהיא פונה החוצה לחפש את הכתובת בשרתי DNS השונים

לצורך התרגיל נריץ לרגע שרת פייתון מקומי בפורט 4444 ונגדיר לו כתובת אינטרנט בקובץ /etc/hosts

הרצת שרת פייתון


$ python3 -m http.server 4444

כעת כל פניה בדפדפן לכתובת 127.0.0.1:4444 תפנה אל התוכן שיש במיקום ממנו הרצנו את השרת

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


במידה ונגדיר בקובץ /etc/hosts שכתובת האתר החמוד שהקמנו היא my.website והיא משוייכת לכתובת הפנימית של המחשב 127.0.0.1, אז כל פניה בדפדפן לכתובת my.website בפורט 4444 תפנה ישירות לאתר המקומי שלנו

$ site="127.0.0.1 my.website"
$ echo "$site" | sudo tee -a /etc/hosts

ובשביל להוכיח שזה באמת עובד ניתן להריץ בקשת אינטרנט בעזרת curl

$ curl my.website:4444
...
<li><a href=".git/">.git/</a></li>
<li><a href=".gitmodules">.gitmodules</a></li>
<li><a href="Dockerfile">Dockerfile</a></li>
...


אין מילים, מדהים לחלוטין

עד לכאן ההקדמה וכעת לטיפ

לא מעט פעמים כל שנרצה הוא רק לוודא שהשירות שלנו מגיב לכתובת האינטרנט שהגדרנו בקוד למרות שאין לנו רשומת DNS קיימת, והצורך להוסיף את הכתובת לקובץ /etc/hosts סתם יוצר סרבול של התהליך

ישנה אופציה קלילה יותר לשייך כתובת אינטרנט לip בצורה זמנית והיא על ידי שימוש ב curl עם הדגל --resolve ולהעביר לו את הביטוי שמחולק בצורה הבאה לשם האתר:מספר הפורט:כתובת הIP

website_name:port:
ip

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

$ curl --resolve \
my.website:4444:127.0.0.1 \
my.website:
4444

כעת הפניה של curl תחזיר לנו את המידע מהשירות שלנו על פי כתובת האינטרנט הזמנית שהגדרנו, למרות שהכתובת לא מופיעה בקובץ ה hosts


#curl
#hosts
#server
#resolve

@bash_tips
👍4
להעתיק
רמת קושי: #beginners

בלא מעט מערכות יש כלי שורת הפקודה שמאפשר להעתיק פלט בטרמינל ישירות לתוך ה clipboard.
בווינדוס למשל ניתן להשתמש ב clip

c:\> dir | clip 

ובמאק יש את פקודת pbcopy

$ echo bla bla bla | pbcopy

מה קורה אם כך בלינוקס?
משתמשי זיש יכולים להשתמש בפקודת clipcopy

$ cat ~/.ssh/id_rsa.pub| clipcopy

משתמשי באש לעומת זאת שרוצים לממש יכולת דומה צריכים להגדיר את ה alias הבא (שזה אגב בדיוק מה שעושה זיש)

$ alias clipcopy="xclip -selection clipboard"

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

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

$ alias clipcopy="tee >(xclip -selection clipboard)"

נ.ב. בכל מה שקשור ללינוקס ישנה תלות של כלי xclip שצריך להיות מותקן במערכת


#copy
#xclip
#clipboard

@bash_tips
👍3
לטעון סביבה
רמת קושי: #advanced

קובץ שמוכר בעולם ה ops הוא .env מדובר על קובץ שבגדול מכיל רשימה של משתני סביבה בהם הסביבה מאותחלת, מספר כלים כדוגמת docker-compose מכירים בקובץ ויודעים לטעון אותו לבד, מה קורה כשאנו רוצים לטעון קובץ .env ישירות לטרמינל?

דוגמה לקובץ .env

$ cat .env
APP_NAME=mytest
DEPLOYMENT_MODE=true
BUNDLE=test
...

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

נוכל לראות זאת בדוגמה שלהלן

$ source .env

$ cat test.sh
#!/bin/bash
declare -p APP_NAME DEPLOYMENT_MODE BUNDLE

$ bash test.sh
test.sh: line 2: declare: APP_NAME: not found
test.sh: line 2: declare: DEPLOYMENT_MODE: not found
test.sh: line 2: declare: BUNDLE: not found


להלן 2 דרכים מעניינות לפתרון
פתרון אפשרי, export

export $(grep -v '^#' .env)

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


פתרון אפשרי נוסף allexport

set -a
source .env
set +a


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

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


#env
#export
#source
#variable
#env_variable
#session

@bash_tips
👍19🔥5
לקפוץ מעל jumpbox

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

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

1. העתקה של המפתח הציבורי שלנו למכונת ה jumpbox
2. העתקת מפתח של מכונת ה jumpbox לשרת אליו אנו רוצים להתחבר

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

נשמע ארוך לא?

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

ssh -J myuser@jumpbox myuser@isolated.server

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

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

#ssh
#jumpbox

@learnlinuxnote
👍10
להטמיע בינרי בסקריפט באש
רמת קושי: #advanced

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

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

כעת נראה איך הרעיון יכול להיות ממומש הלכה למעשה
לצורך העניין כך נראה הסקריפט שלנו

$ cat -n /tmp/installer.sh
1 #!bin/bash
2
3 binary_content=$(awk '/^ARCHIVE_HERE/ {print FNR + 1}' $0)
4
5 tail -n+$binary_content $0 | base64 -d | tar -ztv
6
7 exit 0
8
9 ARCHIVE_HERE
10


מה שקורה כאן הוא כך
שורה 3: עוברת על כל הסקריפט ומחפשת את העוגן שהגדרנו, במקרה שלנו העוגן נמצא בשורה 9, ARCHIVE_HERE, למי שלא מכיר פרמטר $0 הוא בעצם שם הסקריפט

שורה 5: לאחר שאנו יודעים מאיזה שורה מתחיל התוכן הבינרי, אנו שומרים רק את התוכן הבינרי לתוך משתנה, הדבר נעשה על ידי פקודת tail שקוראת תוכן מסוף הקובץ ומקבלת שורה ספציפית מהיכן לקרוא, התוכן עובר ל base64 במקרה שלנו ולכן נקודד אותו חזרה לתוכן רגיל, פקודת tar תציג לנו את המידע שהוטמע בפנים

שורה 9: זהו העוגן שהגדרנו

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


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

$ tar -tvf installer.tar
installer/
installer/req_list
installer/installer.db
installer/execfile


ניתן להשתמש ב cat כדי לשפוך את התוכן הבינרי לקובץ אבל ישנם המון מקומות בהן התוכן עשוי להשתנות ולא להישאר נאמן למקור לכן נעדיף לעבוד עם base64

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

9 ARCHIVE_HERE
10


כעת מהטרמיל אנו מקודדים את הקובץ לbase64, ומשרשרים את הפלט לסוף הסקריפט זה נראה כך

$ base64 installer.tar >> installer.sh

אנו משתמשים באופרטור >> כדי להוסיף את התוכן לסוף הקובץ ולכן השורה הריקה שהשארנו מקודם תתמלא בתוכן החדש

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

$ bash installer.sh
installer/
installer/req_list
installer/installer.db
installer/execfile


ניתן כמובן לשנות את שורה 5 וליצור קובץ ישירות מהתוכן שיוצר השחזור של ה base64

#tar
#binary
#base46
#scripting

@bash_tips
👍12🔥2
installer.sh
415 B
להלן הסקריפט המלא עם התוכן הבינרי
טיפ קצר וחביב להתנהלות בטרמינל
רמת קושי: #beginners

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

לשם כך ישנו הקיצור Alt + Shift + # שכל מה שהוא עושה זה לקחת את הפקודה שרשמנו ולהריץ אותו כהערה כך שלאחר מכן ניתן יהיה לשלוף את ההערה מההיסטוריה ולהריץ אותה כפקודה.


#terminal
#shortcuts
#comments

@bash_tips
👍23
יותר less
רמת קושי: #beginners

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

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

הקשה על !ls יריץ את הפקודה בטרמינל ויחזיר אותנו חזרה לקובץ שפתוח ב less


מומלץ להריץ less --help כדי להכיר אלו עוד אפשרויות ופיצ'רים הכלי מאפשר


תודה לליאור קיסוס האלוף על הטיפ


#less
#vim

@bash_tips
👍12
איך לכתוב באש ומתי
רמת קושי: #beginners

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

לדוגמה

# Use this

if (( my_var > 3 )); then
do_something
fi

if [[ "${my_var}" -gt 3 ]]; then
do_something
fi


# Instead of this
# Probably unintended lexicographical comparison.
if [[ "${my_var}" > 3 ]]; then
# True for 4, false for 22.
do_something
fi


הדף מופיע כחלק מפרויקט רחב יותר של גוגל בשם Google Style Guides שם תוכלו למצוא עוד המון הערות בקשר לשפות אחרות כמו go, python, c וכו'


#shellguide
#scripting
#rules

@bash_tips
👍6
לחלק נכון, awk
רמת קושי: #beginners

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

one two three
one two three
one two three

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

$ cat output | cut -d " " -f2
two
two
two
אחלה, עובד מעולה

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

docker ps | cut -d " " -f 2

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

איך כן?
בכדי לפתור את הבעיה הזאת יהיה קל יותר להשתמש ב awk כדי לפצל פלט

docker ps | awk '{print $2}'

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


#cut
#awk

@bash_tips
👍17🔥3🥰1
לשרשר ולספור PIPESTATUS
רמת קושי: #beginners

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

$ ls /not/exist/path | echo 123
123
ls: cannot access '/not/exist/path': No such file or directory

$ echo $?
0

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

$ ls /not/exist/path | echo 123 | grep -o 2 
ls: cannot access '/not/exist/path': No such file or directory
2

$ declare -p PIPESTATUS
declare -a PIPESTATUS=([0]="2" [1]="0" [2]="0")

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


#pipe
#env_variable
#exit_code

@bash_tips
👍4🔥3
אוטומציה ל telnet
רמת קושי: #advanced

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

$ telnet localhost 25 
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 My Mail Server

התחברנו לשרת ה SMTP דרך telnet ומשלב זה שורת הפקודה (עדין telnet) ממתינה שנשלח פקודות לשירות אליו התחברנו, במקרה שלנו פקודות לשירות SMTP עד שנעביר את הפקודה quit שתסגור את החיבור.

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

יש 2 דרכים עיקריים לביצוע אוטומציה ל telnet
הראשונה היא על ידי כלי אוטומציה של באש בשם expect עליו לא נדבר היום
האופציה השניה היא על ידי העברת ערכים ל stdin של telnet

echo "ehlo test" | telnet localhost 25

להלן דוגמה לסקריפט ששולח מייל על ידי telnet

{
echo "ehlo test"
sleep 1
echo "mail from:meir@any.domain"
echo "rcpt to:fpk1ezqg@my.domain"
echo "data"
sleep 1
echo "subject: bla bla bla"
echo "more bla bla bla"
echo "."
sleep 1
echo "quit"
} | telnet localhost 25

בדוגמה אנו משתמשים ביכולת group command של באש כדי לחסוך כתיבה של תווי \n שנדרשים ל telnet.
כפי שניתן לראות הקוד משתמש ב sleep כדי לצלוח את המשימה, מאחר וכל הקוד מגיע כבלוק אחד של טקסט נדרש לשירות זמן להגיב לפקודות אותם הוא קיבל


#telnet
#scripting

@bash_tips
👍14
לעשות פיל מזבוב fallocate
רמת קושי: #advanced

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

$ fallocate -l 500G fill_half_disk.img

בכדי ליצור קובץ בגודל מסויים אנו משתמשים בדגל -l ומעבירים לו ערך בפורמט K M G וכו' כש 50G הם בעצם 50 ג'יגה בייט

$ du -h fill_half_disk.img 
500.1G fill_half_disk.img


#disk
#fallocate

@bash_tips
👍9🔥3