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

בערוץ הבא תמצאו אוסף טיפים שימושיים ב-Bash והכרות עם כלים שונים שעשויים לחסוך מאמץ ועבודה בכתיבת סקריפטים ומימוש אוטומציות.
Download Telegram
פקודת השמה ו 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
סימניות בטרמינל 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
לפרמט את היסטוריה
רמת קושי: #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
Forwarded from shahar
למצוא את הדרך
רמת קושי: #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
לטעון סביבה
רמת קושי: #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
לשרשר ולספור 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