מילון BASH
`command --help`
בשביל עזרה בחיים...
wsl¶
explorer.exe¶
- כדי להריץ קובץ עם ווינדוז, כמו execution רגיל של הקובץ בווינדוז, נעשה
explorer.exe filename-or-path
- חשוב לשים לב שאם נותנים לו path, הוא צריך אותו בפורמט DOS, כלומר שצריך להריץ [[מחברות קוד/Bash&Linux 🐧/מילון BASH#dos2unix|dos2unix]] על ה-path
clip.exe¶
- כדי להעביר פלט לקליפבורד של ווינדוז
- משתמשים בפייפ
<commands> | clip.exe
misc¶
"#" comment¶
אפשר להשאיר הערות בקוד באמצעות #
this-is-code
# this is a comment
- לפעמים נראה בקבצי קונפיגורציה כל מיני סניפטים של קוד שמוחרגים מההרצה באמצעות # (הם בעצם הערות) - הכוונה היא לתת לנו "אפשרויות מוכנות" (או דוגמאות) להגדרות שאפשר להפעיל ע"י מחיקת ה-#
- למשל, ב-bashrc של אובונטו יש את הקטע הבא:
# some more ls aliases #alias ll='ls -l' #alias la='ls -A` #alias l='ls -CF'
- למשל, ב-bashrc של אובונטו יש את הקטע הבא:
man¶
נותן manual לפקודה, יותר טוב מהלפ.
man <command>
type¶
type <command>
כדי לדעת מאיזה סוג הקומנד.
יש 4 סוגים בגדול: אקסקיוטבר, shell bult-in, shell function (env), alias
which¶
which <executable>
יש לנו כל מיני מקומות עם אקסקיוטבלז ב-path. אם אנחנו רוצים לראות איפה יושב אחד שאנחנו מפעילים (במערכות גדולות יתכנו כפילויות), אנחנו משתמשים ב-which
sleep¶
sleep n
מחכה n שניות ואז עושה exit
history¶
מראה את הפקודות האחרונות, שעולות כשעושים חץ למעלה - היסטוריית הפקודות שלנו נשמרת בכמה שלבים: 1. בתור התחלה, המידע נשמר בקובץ היסטוריה זמני של ה-Session שלנו (לדעתי מקבצי ה-temp של המערכת). 2. כשהסשן נסגר (או כשאנחנו שומרים ידנית), המידע הזמני נשמר ב-home בקובץ בשם .bash_history כברירת מחדל, באש שומר את ה-100 פקודות האחרונות, אפשר לשנות את הערך הזה ב-bashrc
-
כשאנחנו מריצים shell session הוא טוען את קובץ ה-bash_history ומוסיף אותו להיסטוריה "הזמנית", כאשר כל פקודה חדשה תסופח לתחתית הקובץ הזמני ללחוץ על חץ-למעלה נותן לנו את השורה האחרונה בקובץ הזמני, ולאחר מכן כל לחיצה תעלה שורה. ככה, יש לנו גם היסטוריה "רחוקה" וגם היסטוריה "עדכנית" באותו קובץ פעיל
-
הפקודה
history
מאפשרת לנו לטעון, לשמור ולבצע מניפולציות על קבצי היסטוריה: בגדול, אין איך לגעת בהיסטוריה ה-"זמנית" (מעכשיו: פעילה) באופן ישיר. אנחנו יכולים לערוך קבצי היסטוריה ולגרום לה לקרוא אותם:history -r [filename]
: תטען קובץ טקסט כלשהו להיסטוריה הפעילה שלנו. אם לא נכתוב ארגומנט ל-filename, הפקודה תטען מחדש את הקובץ הרגיל, .bash_historyhistory -c
תנקה את ההיסטוריה הפעילה שלנוhistory -w [file]
Writes the current session history to a file.history -a
Appends the current session’s history to the default history file (~/.bash_history
).history -n
Reads new history lines from the file without overwriting existing session history. -
לא לשכוח מ-[[מילון BASH#history expansion#|history expansion]]
חיפוש בהיסטוריה¶
Ctrl+r
כדי להיכנס למצב חיפוש בהיסטוריה אנטר כדי להריץ את הפקודה שנבחרה, Ctrl+r שוב ושוב כדי לדפדף Ctrl+j כדי להעתיק את הפקודה שנבחרה לקומנד ליין ctrl+g or c כדי לצאת מהחיפוש
![[Pasted image 20250124180056.png|500]]
script¶
script pathtofilename
'מקליט' את כל הסשן ומייצא אותו לקובץ שמצוין
אם לא נבחר שם, לקובץ יקראו typescript
/usr/share/dict¶
לא ממש מילון BASH אבל ילך לאיבוד בלינוקס הכללי. בכל מערכת לינוקס יש כמה קבצי מילון! שיושבים ב-path של הכותרת.
זה שימושי למקרה שאנחנו רוצים לחפש מילים מתאימות לאיזשהו צורך.
למשל: אם אנחנו רוצים להשתמש בכדי למצוא פתרונות אפשריים לתשחץ...
grep -i '^..j.r$' /usr/share/dict/words
systemctl¶
- ממשק לשליטה בפונקציות של Systemd (בגדול מנהל התהליכים בלינוקס)
-
כיבוי, השהיה, ואתחול של המחשב (restart):
systemctl suspend
systemctl poweroff
systemctl reboot
-
הפעלה של תהליכים
sudo systemctl enable x
sudo systemctl start x
time¶
- בודק כמה זמן לקח להריץ פקודה מסוימת
- טוב בשביל אופטימיזציה
time ( commands )
לשים לב לרווח אחרי ולפני הסוגריים
fzf¶
- תוכנה, צריך להוריד אותה
- יוצרת תפריטים. ברירת המחדל אם נעשה fzf יהיה לתת את כל הקבצים שתחת ה-path הנוכחי (./)
- בד"כ נרצה לעשות לתוכה pipe עם פקודה שנותנת ערכים מופרדים בשורות (או תו אחר שנגדיר), או שאפשר לתת לה ערך עם האפשרות --query
- הפלט של fzf יהיה הפריט הנבחר
- אפשר להריץ את fzf עם אפשרויות מיוחדות:
- בכל אפשרות כזו, המשתנה
{1}
שווה לערך של השורה המסומנת ב-fzf
- בכל אפשרות כזו, המשתנה
-
fzf --preview 'command'
כדי להגדיר מה נראה בפריוויוfzf --preview 'cat {1}'
בשביל לראות פירוט של קובץ -
fzf --bind '<key>:<command>
fzf --bind 'ctrl-e:accept'
כדי לאשר בחירה עם בינדfzf --bind 'ctrl-e:execute(<command>)
כדי לבצע פקודת של מסוימת עם בינדfzf --bind 'ctrl-e:abort'
לסגור את fzffzf --bind 'ctrl-e:toggle-preview
וכו' -
fzf --query=<string>
להתחיל מחיפוש מסוים fzf --except=<keys>
להגדיר דלימיטר שהוא לא שבירת שורה עבור רשימת הערכיםfzf --multi=<MAX>
כדי לאפשר בחירות מרובות עם טאב או שיפט טאבfzf --filepath-word
כדי שהחיפוש יכבד פאת'ים שנכתוב*- אפשרויות מעניינות ב-
--help
לגבי עיצוב הממשק בדרכים שונות, הגדרת דלימיטרים לקלט ולפלט,
הרשאות¶
id¶
id
נותן מידע בסיסי על היוזר שאנחנו נמצאים עליו
uid = המספר של היוזר, שהוא המזהה שלו לפני שמוצמד לו שם רגיל
gid = primary group id
היוזר עשוי להיות בעוד קבוצות של הרשאות אבל זה הקלאס הבסיסי שלו
groups= יפרט איזה עוד קבוצות יש ליוזר
המידע הזה מגיע מקובץ טקסט. המידע על יוזרים יושב ב-/etc/passwd
והמידע על קבוצות ב-/etc/group
id -g
בשביל הקבוצה של הויזר בלבד
id -gn
בשביל המספר של קבוצה של היוזר
id -n
באופן כללי בשביל לקבל מספר של תכונה של היוזר במקום את הכותרת שלה
chmod¶
כשאנחנו אומרים לשנות את ה-'מוד' של הקובץ, הכוונה היא לשנות את ה-permissions שלו אפשר להפעיל chmod על הקובץ אם אתה הבעלים שלו, או אם אתה הסופריוזר אפשר לציין את השינוי ב-octal numbers או ב-symbolic רפרשנטיישן
אוקטאלי:
![[Pasted image 20250124182731.png|500]]
בגדול, בגלל שכל חלק בהרשאות הוא 3 אותיות (rwx כאשר כל אחד יכול להתחלף ב'-' כדי לסמל שהוא לא פעיל), ובגלל שכל ספרה אוקטאלית מייצגת 3 אותיות בינאריות, אנחנו ממספרים את המצבים השונים האפשריים בטבלה ומצמידים להם ערך מ-0 עד 7 (באוקטאלי יש את כל המספרים שאפשר להרכיב עם הספרות 0-7) ![[Pasted image 20250124183040.png]]
לצורך העניין, chmod 777 pathtofile
יעשה שגם לבעלים, גם לקבוצה שלו וגם לכל השאר יהיו את כל ההרשאות (rwx-rwx-rwx) לקובץ המצויין
סימבולי מציינים את השינוי עם 3 פרמרטרים: 2. על מי הוא חל
![[Pasted image 20250124183345.png|500]]
אם לא מציינים, הטרמינל מניח a
-
מה השינוי
+
אומר שמוסיפים הרשאה-
אומר שמורידים הרשאה=
אומר שההרשאה שנגדיר היא היחידה שתהיה (וכל השאר יימחקו) -
מה ההרשאה שמגדירים בהתאם לפורמט שלמדנו:
r, w, x
בשביל קריאה, כתיבה והרצה בהתאמה
לכן, למשל chmod a+x
אומר "לכולם מתווספת האפשרות לעשות execute לקובץ"
- את הפאת' לקובץ מציינים בסוף, ככה chmod a+w pathtofile
להפוך קובץ ל-Executable: chmod a+x ./filename (בתיקיה של הקובץ) לפעמים +x בלי a, זה לא משנה, שניהם אמורים לתת הרשאת execution לכל סוגי המשתמשים
עוד דוגמאות
![[Pasted image 20250124183723.png|500]]
umask¶
פקודה שקובעת מה ההרשאות שיוגדרו לקבצים כברירת מחדל, כשהם נוצרים
משתמש ב-octal notation (התוויה אוקטלית) כדי להגדיר "mask" של ביטים, שהיא 'הסרה' של ערכים שמגדירה את ההרשאות שיוותרו:
![[Pasted image 20250124184428.png|500]]
הסבר: ה-'מסיכה' בנויה על רצף של 4 שלשות.
ה-000 הראשונים לא משנים כרגע.
השאר הם rwx של היוזר, הקבוצה והשאר כמו שלמדנו
אנחנו מגדירים את umask עם 4 ספרות, שכל אחת היא התייחסות אוקטלית לשלשה בינארית שכזו.
למשל umask 0002
אומר בעצם: "שלוש שלשות בינאריות "ריקות", ועוד אחת במצב 2".
מצב 2, כמו שלמדנו בטבלה למעלה, הוא 010
וזה בעצם מסמן w (הסדר הוא rwx)
המסיכה גורעת הרשאות, ולכן לקובץ שהגדרנו עם umask 0002
בעצם שללנו הרשאות w (כתיבה) עבור ה-others
(בקיצור, בכל מקום ש-1 'פוגע', הערך המתאים עבורו נגרע מההרשאות)
umask
כדי לבדוק מה מוגדר לנו כרגע
umask xxxx
כדי להגדיר מחדש
הסבר על המעבר מבינארי להקסדצימלי/אוקטאלי: העניין הוא איך אנחנו "ממספרים" את האיברים השונים שאפשר לבטא אם יש לנו "תא" של מידע והערכים שלו הם אוקטליים, הוא בעצם יכול להיות כל ספרה מ-0 עד 7 (8 ספרות בסה"כ, אוקטלי). כדי למספר 8 "אפשרויות", כל אחת באופן ייחודי, אנחנו צריכים 3 תאים "בינאריים" 000 001 010 100 011 110 101 111 כל אחד מאלה "מוצמד" לאחד הערכים האוקטליים אותו דבר עם ערכים הקסדצימליים רק לפי base 16: כל "דאטה" שבנויה מרצף של 4 תאים בינאריים (נניח 1010) אפשר לבטא באמצעות אות אחת בסולם ההקסדצימלי, שהיא פשוט האות ש-"הוצמדה" לקומבינציה הספציפית הנתונה. אנחנו משתמשים בערכים הקסדצימליים לבחירת צבעים, כי כל צבע הוא 8 ביטים של r, של g ושל b -- אז מקצרים רצף בינארי של 24 תווים ל-6 תווים הקסדצימליים (24/4)
ומה הסיפור עם השלשה הראשונה?
שמנו לב שזה לא umask xxx
אלא umask xxxx
השלשה הראשונה מאפשרת לנו להגדיר במסיכה כמה הרשאות ייחודיות:
umask 4000
(100 000 000 000)
הרשאה שנקראת setuid bit
היא לא באמת עושה מה שהבינארי שלה אומר (מורידה הרשאות read), אלא מופעלת על קובץ אקסקיטובל כדי לעשות שהוא תמיד ירוץ עם 'effective user id' של הבעלים ולא של היוזר שמפעיל אותו. זה שימושי כדי שתוכנות מסוימות תמיד ירוצו כ-superuser. אנחנו לא רוצים לחלק את ההרשאה הזו בלי סיבה מפורשת.
umask 2000
setguid bit
משמש כדי שההרשאות על תיקיה יהיו לפי הבעלים שלה ולא לפי היוזר שפותח בה קבצים.
זה דווקא שימושי לתיקיות משותפות: נגדיר את ההרשאה של תיקיה להיות setgid bit כדי שכל מי שפועל בתוכה ייצור קבצים עם הרשאות שמתאימות לקבוצה שהתיקיה משויכת אליה, ולא עם ההרשאות הספציפיות שלו
umask 1000
sticky bit
משהו ישן של unix. לא עושה כלום על קבצים. על תיקיה, זה עושה שלא יהיה ניתן למחוק בה קבצים או לשנות להם שמות, אלא אם היוזר הוא הבעלים או הסופריוזר
(בקיצור, ל-000 הראשון ב-umask יש 3 מצבים, 001, 010, 100 שמגדירים את שלושת ההרשאות המיוחדות האלה)
אפשר להגדיר את ההרשאות האלה גם סימבולית, ויש להן ביטוי ב-[[לינוקס - כללי#file attributes#|file attributes]] - ההרשאות setuid ו-setgid שתיהן מסומנות ב-s - ההרשאה sticky bit מסומנת ב-t - שניהם יופיעו במקום x - איך נדע אם s מתייחס ל-setuid או ל-setgid? זה די קל: setuid רק על קבצים ו-setgid פועל רק על תיקיות - עוד הבדל: setuid יהיה על השלשה הראשונה של rwx בעוד ש-setgid יהיה על השלשה האחרונה (אחד מתייחס לבעלים ואחד מתייחס ל-world)
![[Pasted image 20250124191101.png|500]] umask פועל רק לסשן אחד, צריך להשתמש במשתני סביבה כדי לעשות אותו קבוע
su¶
su [-l] [user]
פקודה שמשמשת כדי להתחיל shell session חדש מיוזר אחר, לפי מה שנכתוב
הדגל -l
אומר שאנחנו רוצים לעשות לוגין ליוזר הזה, כלומר להזין ססמה, לטעון את ה-bashrc שלו ולעבור לתיקיית ה-Home שלו
אפשר לכתוב גם su -
(קו בלי l) וזה אותו דבר
אם לא מגדירים יוזר - הטרמינל מניח שאנחנו מדברים על ה-superuser
אפשר לדעת שאנחנו על הסופריוזר כשיש לנו # בסוף של ה-shell prompt במקום $
exit
כדי לצאת בחזרה לסשן הקודם
su -c 'command'
כדי לשלוח קומנד אחד כיוזר אחר בלי להחליף סשן
להשתמש ב-quotes כי אנחנו לא רוצים שהפקודות יתרחבו בטרמינל הזה! רק בטרמינל של היוזר שישגר בפועל את הפקודה (הן יעברו אליו בלי הגרשיים ולכן יתרחבו אוטומטית כרגיל)
איך מגדירים ב-c איזה יוזר?
sudo¶
חשוב להבין ש-sudo זה לא "הפעל כמנהל" במושגים של ווינדוז.
זו פקודה שנועדה בדיוק כדי שיוזרים יוכלו לבצע פעולות מסוימות מבלי להיות המנהלים
ה-admin מגדיר פקודות מסוימות שיוזרים מסוימים יכולים להפעיל עם הרשאות superuser, באמצעות sudo, מבלי שידרשו לססמה של superuser
כש-sudo מבקש ססמה, הוא מבקש את הססמה של היוזר הפעיל, ולא של הסופריוזר!
- לא צריך לעטוף פקודות שעלולות להתרחב בגרשיים, כי sudo לא פותח סשן חדש של הטרמינל
- אפשר לעשות sudo -i
כדי לפתוח סשן חדש של סופריוזר באמצעות sudo
- sudo -l
כדי לראות איזה הרשאות יש עם סודו במערכת
- ההרשאות של sudo מוגדרות ב-[[לינוקס - כללי#/etc/sudoers#|/etc/sudoers]]
(הלינק הזה כולל הסבר על sudo vs su בהיסטוריה של לינוקס)
chown¶
CHange OWNer
מאפשר לנו לשנות את ה-owner של קובץ, ולשנות את ה-group owner של קובץ (הקבוצה שהקובץ שייך לה).
chwon <owner><:group> path-to-file-or-dir
- למשל
chown bob:users log.txt
ישנה את הבעלות על log.txt להיות של היוזר bob ושל הקבוצה users - אפשר לעשות
chown bob: log.txt
, אם שמנו:
אחרי היוזר ולא כתבנו את השם של הקבוצה, ההרשאות ילכו ל-login group של היוזר שציינו (כלומר לקבוצה העיקרית שהוא משתייך אליה) - אפשר לעשות
chown :users log.txt
כדי להגדיר רק את ה-group owner
יש פקודה ישנה בשם chgrp
שמשנה ספציפית את הקבוצה, זה בגלל שבעבר chown שינתה רק יוזר (כבר לא)
groupadd¶
פקודה ליצירת user group חדשה.
sudo groupadd groupname
usermod¶
sudo usermod -a -G groupname usertoadd
-a
אומר append
-G
אומר Group
המשמעות של הפקודה היא "להוסיף את היוזר שצויין לקבוצה שצויינה בקובץ ב-/etc/group
"
passwd¶
משנה ססמה ליוזר שיש לנו גישה אליו
passwd user
אם נכתוב passwd
זה יפעל עלינו
רק הסופריוזר/הרשאות סופריוזר מאפשרים לתת ארגומנט של יוזר אחר
אפשר לקבוע באמצעות הפקודה הזו (כסופריוזר) דברים כמו מס' נסיונות, אקספירציה של הססמה וכו'. (לקרוא ב-man)
shadow-utils¶
הפקודות passwd, addgroup, usermod הן חלק מסויטה בשם שאדו יוטילס הנה עוד פקודות מהסויטה הזו: ![[Pasted image 20250124195907.png|500]]
קבצים ותיקיות¶
ליצור תיקיה - mkdir¶
mkdir path
אפשר גם כמה mkdir dir1 dir2 dir3
ליצור קובץ - touch¶
touch pathtofilename
או בשביל ליצור אותו עם טקסט מסוים מראש:
echo text
למחוק קובץ - rm¶
rm path
rm -rf ~/.local/share/Trash/*
-f, --force Ignore nonexistant files, and never prompt before removing.
-r, -R, --recursive Remove directories and their contents recursively.``
רקורסיבי = למחוק תיקיה ואת כל מה שבתוכה
^ דוגמה לדגלים.
להריץ קובץ¶
פשוט מכוונים את הטרמינל לשם שלו בתיקיה שלו. אם אנחנו בתיקיה, אז ./filename
להעתיק קובץ או תיקיה - cp¶
cp path destination
cp path -r destination
כדי שיהיה רקורסיבי (כל עוד יש מה להעתיק איי גס)
![[Pasted image 20250124010424.png]]
להזיז קובץ ולשנות את שמו - mv¶
- שניהם עם mv
- אם מגיעים להשתמש בזה אז כנראה sudo mv
- sudo mv filepathwithformat destinationpath
- sudo mv filepathandcurrentname samepathwithnewname
- כאשר אנחנו מזיזים קובץ או משנים את שמו כך שתהיה התנגשות בין שני קבצים (אותו שם):
ברירת המחדל היא overwrite בלי לשאול אותנו (אם לא משתמשים בדגל כלשהו)
mv -i
עושה שישאל אותנו לפני שכתובmv -f
עושה שישכתב, כמו ברירת המחדלmv -n
עושה שלא ישכתב ואם יש כפילויות יכשלmv -b
עושה שיגבה שכתובים (ישנה להם את השם)
ניווט:¶
ls¶
ls
- מפרט מה יש בתיקיהls -a
כדי לראות גם קבצים חבויים (מתחילים בנקודה)ls -l
כדי לקבל רשימה בלונג פורמט ![[Pasted image 20250123170117.png]] הכי חשוב שלא כתוב כאן:ls -i
כדי לראות ברשימה את מס' ה-inode של הקבצים. ככה אפשר לראות איזה קבצים הם הארדלינקים שונים של אותו ה-Inode (שכפולים)
הסבר על העמודות ב-long format: ![[Pasted image 20250123170237.png]]
- sudo - מזמן מתאבק סומו
- cd - זה ללכת לתיקיה לפי ה-path
- cd .. - מחזיר אחורה בתיקיה - אפשר עד 3 ברצף ככה: cd ../../..
- pwd - מדפיס את הפאת' הנוכחי בצורתו המלאה
pwd -P
כדי לקבל את ה-physical path, כלומר בלי symbolic links
אפשר גם ls path1 path2
בשביל רשימה נפרדת לכל פאת'
קיצורים:¶
- ~ אומר home/user
- לעשות cd ~ יקח אותי ל/home/tony
- אם אתה מחובר לטרמינל כרוט/אדמין, זה לוקח ל/root
- כאשר משתמשים ב-sudo, ~ לא עובד. צריך להשתמש ב-$HOME
- הבהרה חשובה: זה שאני משתמש עם sudo capabilities לא אומר שאני משתמש בטרמינל כרוט. בשביל להפעיל את זה צריך להיות משתמש עם sudo ולכתוב sudo su או sudo -i.
אז נניח בשביל לפתוח את downloads אני יכול פשוט לעשות ~/downloads
מבחינת ה-, לזכור שכולם חוץ מווינדוז משתמשים בלוכסן שהולך קדימה (ביחס לאנגלית).
-
לעשות . אומר "התיקיה הנוכחית"
- כדי להריץ קובץ, ./filenmame
- לא עובד עם sudo, צריך במקום לעשות $PWD
-
לעשות / אומר root
-
הסיבה שלעשות /home מצליח להפנות ל-home partition ולא ל-root, היא ש-home יושבת בroot בכל מקרה. אם יצרנו partition נפרד בשבילה בעצם יצרנו link - נוכל לראות את home בתוך ה-root partition, אבל להיכנס יעביר אותנו ישר ל-home partition
- לעשות .. אומר parent directory
-
לעשות + או - אומר תיקיה אחת אחורה/קדימה (ביחס להיסטוריה)
-
אפשר להשתמש בקיצורים מס' פעמים או ביחד כדי לנווט בקלות, למשל:
cd ../..
אומר ללכת לתיקיה הקודמת-קודמת. וכו'.
השלמה אוטומטית (completion)¶
- אפשר להקליד חלק מ-Path, ללחוץ TAB ולקבל הצעות לאן להמשיך. זה כמו לעשות ls בלי לשלוח את הפקודה ככה שאפשר פשוט להמשיך לכתוב.
- עובד גם עם יוזרים אחרי ~, עם משתנים אחרי $ ועם הוסטים אחרי @
- כדי שהרמז יצליח חייבת להיות התאמה ![[Pasted image 20250124170137.png]]
programmable completion
חוקים נוספים שמגיעים עם הדיסטרו ולרוב נועדו לתמוך בתוכנות נוספות.
set
כדי לראות את כולם
קיצורי מקלדת¶
![[Pasted image 20250124165430.png|500]]
![[Pasted image 20250124165702.png|500]]
kill = copy yank = paste
file¶
בלינוקס, קובץ לא חייב סיומת של פורמט (וגם קובץ בשם .txt לא חייב להיות קובץ טקסט). כדי לבדוק פורמט של קובץ עושים file pathtofile
עקרון Unix חשוב: everything is a file
symbolic link¶
ידוע גם כקיצור דרך ``
ln -s /Users/jessicawilkins/Music ~/my_music
ELI5: The way data is structured in Linux consists of 3 parts: (1) files, (2) index (called inodes), and (3) raw data. inodes tell your programs which segment of raw data make up a file. Basically it looks like this
File ==> inodes ==> raw data
Hard link is multiple files, same inode. Modify any of hard-linked file change the inodes and raw data, hence change all the files. When the last hard-linked file is deleted there's no more reference to the inode, thus the file is considered deleted. Symbolic link is reference to the file. Like thisSymbolic ==> file ==> inodes ==> raw data
. Modify symbolic link will change the file. However, deleting all symbolic link will not delete the file, but delete the file will delete all the symbolic links.
הארד לינק זה דבר די ישן של unix, יותר מודרני להשתמש בסימבוליק לינק כשאנחנו עושים הארד לינק, אנחנו מוגבלים למערכת הקבצים שלנו (אי אפשר לרפרר לאחת אחרת), ואין הבדל בין הקובץ למה שהוא מרפרר אליו. הלינק הוא פשוט עוד כתובת של המידע. גם הקובץ המקורי הוא בעצם hardlink ל-inode של הקובץ. להוסיף symbolic link זה להוסיף עוד שכבה - אנחנו מרפררים לקובץ שהוא מיקום אחד של ה-inode. לערוך את ה-symlink לא יערוך את הקובץ המקורי, אבל לערוך את הקובץ המקורי ישנה את כל ה-symlinks (ב-ls -l תמיד נראה שלקובץ יש לפחות הארד לינק אחד, כי הקובץ עצמו הוא הארד לינק) בנוסף רק סימבוליק לינק עובד על תיקיות. הארד לינק זה לקבצים בלבד.
stat¶
stat pathtofile
כדי לקבל את כל המידע שיש למערכת על קובץ
stat --format=%A filename
בשביל הרשאות בלבד
stat --format=%F filename
בשביל סוג קובץ בלבד
stat --format=%U filename
בשביל שם הבעלים של קובץ בלבד
stat --format=%G filename
בשביל הקבוצה של הבעלים בלבד
stat --format=%U filename
מאמין שיש עוד הרבה סינונים בפורמט הזה! לשאול את המאן פייג'
xdg-open¶
- מריץ קובץ באמצעות ה-default program
xdg open filename
xdg-mime¶
- כדי לשנות את התוכנה שמריצה סוג מסוים של קבצים (כברירת מחדל)
To change the default app for a specific file type using
xdg-mime
, you can follow these steps: 1. Check the current default application for a file type:xdg-mime query default mime/type
2. Set the default application for a specific file type (e.g., setting VLC as the default for.mp4
files):xdg-mime default vlc.desktop video/mp4
Replacevlc.desktop
with the.desktop
file of your preferred application, andvideo/mp4
with the MIME type of the file. 3. Find the MIME type of a file (if you're unsure):xdg-mime query filetype filename
This command associates the file type with the selected application, and will update your system's default app settings accordingly. 4. Find the current default program for a MIME type: Use the MIME-type pattern like so:xdg-mime query default mime/type
xdg-mime query default application/pdf
- כדי שנוכל להגדיר executable כלשהו כתוכנת default לסוג של קבצים, צריך [[לינוקס - כללי#.Desktop files|ליצור קובץ Desktop עבורו]]
להריץ קובץ¶
- כדי לפתוח קובץ צריך כלי מתאים.
program-name filename
- הכי טוב עם xdg-open בתכלס
- עוד אפשרויות:
ב-WSL, הכי טוב
explorer.exe filename
כדי לתת לווינדוז לפתוח עם ברירת המחדל שלו
גיבוי, ארכוב, הצפנה¶
gzip, gunzip¶
- שתי תוכנות טרמינל שמשמשות כדי לכווץ קבצים לפורמט
.gz
וכדי לחלץ קבצי gzgzip pathtofile
כדי לארכבgunzip pathoffile
כדי לחלץ -
לשים לב לנואנס: אם לקובץ שלנו קראו file.txt, הוא יהפוך ל-file.txt.gz
- וכעושים
gunzip
, הוא מניח כבר לבד את ה-.gz בסוף. אז כדי לחלץ את הארכיון file.txt.gz אפשר פשוט לכתובgunzip file.txt
אם רוצים. ![[Pasted image 20250127020313.png|500]]
- וכעושים
-
אפשר להשתמש בפייפ וב-redirection ביחד עם
gzip
כדי לקחת אאוטפוט של פקודה ולארכב אותו: ls -l /etc | gzip > foo.txt.gz
-
זה יצור ארכיב בשם foo.txt.gz עם כל המידע מ-ls -l על /etc (האם אנחנו נקבל את המבנה תיקיות הזה? או מה מאורכב? לבדוק)
- לאחר בדיקה: זה די משעמם... זה יוצר קובץ טקסט עבור האאוטפוט של
ls -l /etc
ושם אותו בארכיב בשם foo.txt.gz...
- לאחר בדיקה: זה די משעמם... זה יוצר קובץ טקסט עבור האאוטפוט של
-
כדי פשוט לקרוא את התוכן של ארכיון, אפשר להשתמש ב-
gunzip -c pathtofile
כדי לקבל את התוכן באאוטפוט, שאפשר גם לנתב בפייפ ל-less
בשביל הנוחות - יש גם תוכנה בשם
zcat
שעושה אותו דבר כמוgunzip -c
- יש גם תוכנה בשם
zless
שעושה אותו דבר כמו השתיים הקודמות ומראש מנתבת את האאוטפוט ל-less
- לשים לב שאנחנו מכווצים קובץ בודד ל-gz ולא יוצרים ארכיון! ארכיון זה משהו אחר!
bzip2¶
- עוד תוכנת קומפרשן, שיוצרת קבצי
.bz2
- עובדת כמעט זהה ל-[[מילון BASH#gzip, gunzip#|gzip]]
- באה עם
bunzip2
ועםbzcat
לחילוץ הארכיונים - רק
-number
עובד שונה מב-gzip
(לקרוא אם רלוונטי) - יש גם
bzip2recover
שיכולה לנסות לתקן ארכיונים פגומים - שוב, מדובר בכיווץ של קובץ בודד ולא ביצירת ארכיון
tar¶
- כלי UNIX ליצירת ארכיונים
- הפורמט שלהם יהיה
.tar
עבור סתם ארכיב ו-.tgz
עבור ארכיון שכיווצנו עםgzip
- ארכיון כזה כולל רשימת קבצים ו/או היררכיה של תיקיות (כמו zip או rar)
tar mode[options] pathname pathname2...
- לשים לב שנכתוב את ה-options ואת המוד ברצף, בלי
-
, ותמיד נכתוב את המוד לפני האפשרויותtar cf playground.tar ~/playground
אומר שהוא רץ במודc
- יוצר ארכיב; עם האפשרותf
- "אנחנו רוצים לכתוב את שם הארכיון שניצור"; עם שם הארכיוןplayground.tar
עבורf
; ואז עם ה-path לתיקיה שמארכבים, הפעם~/playground
. - הארכיון נוצר ב-working dir
- האפשרויות למוד (עוד ב-man page) ![[Pasted image 20250127023809.png]]
לחלץ קובץ מסוים:
tar xf archive-name-or-path path-in-archive path-in-arhive2...
כדי לחלץ קובץ מסוים או כמה קבצים
- בגרסת ה-GNU של
tar
, שהיא הגרסה הרווחת, אפשר להשתמש ב---wildcards
כדי לאפשר שימוש בגלובים כשמגדירים את הקובץ/קבצים לחילוץ
שווה לשים לב:
- ההרשאות של ארכיון שחולץ יהיו לפי היוזר שחילץ, ולא לפי הקבצים המקוריים
- ה-pathים של tar
הם תמיד רלטיביים ולא אבסולוטיים.
- ~/playground
נניח שארכבנו את הפאת' הזה
- /home/user/playground
זה מתרחב לפאת' הזה
- אם נחלץ את הארכיון, הוא בעצם יצטרך להחזיר את הקבצים ל-folder structure של הארכיון...
- אז מה שהוא יעשה זה לקרוא את הפאת' בלי הסלאש בהתחלה:
home/user/playground
- ובעצם להתחיל את ה-path מהמיקום בו הארכיון מחולץ. לצורך העניין יהיה לנו
- ~/playground/home/user/playground
- זה כמובן שימושי והכרחי, כדי שנוכל לחלץ folder structures בכל מקום במחשב...
- בקיצור לזכור שהחילוץ רלטיבי ל-working directory שלנו (זה בתכלס לא שונה מזיפ וראר)
find playground -name 'file-A' -exec tar rf playground.tar '{}' '+'
דוגמה לשימוש בטאר כפונקציה של פיינד, מציאת קבצים לפי כללים מסוימים וארכוב שלהם
find playground -name 'file-A' | tar cf - --files-from=- | gzip > playground.tgz
אפשר גם באמצעות פייפ, כלומר טאר פועל עם סטנדרט אאוטפוט ואינפוט
- אם מסמנים
-
בפאת' שלtar
עבור ה-filename (כמו שעשינו בדוגמה), זה אומר לו לכתוב את האאוטפוט ל-STDOUT במקום לקובץ (ארכיון)! - האפשרות
--files-from
שגם בשימוש בדוגמה אומרת לו לקרוא רשימה של פאת'ים מקובץ במקום לחפש בפייל סיסטם בעצמו. אפשר גם פשוט-T
. - גם ב-Path של ה-files from השתמשנו ב-
-
, הפעם לא כדי לנתב את האאוטפוט הבא אלא כדי לקלוט את האאוטפוט של הפייפ הראשון כאינפוט - בעצם אמרנו לטרמינל: "תכין קובץ של כל הפאת'ים שאתה מקבל מ-find; תשלח אותו לאאוטפוט; תכין קובץ ארכיון ותשים בו את כל הפאת'ים מ-(אאוטפוט של הפייפ הקודם), ואת הקובץ הזה תשלח לאאוטפוט; ואז תן את האאוטפוט הזה ל-gzip כאינפוט כדי שיכין מהארכיב קובץ tgz
-
הפורמטים tgz ו-.tar.gz הם אותו דבר
-
אפשר גם לתת ל-
tar
את האפשרותz
כדי ליצור gzip אוטומטית, ואתj
כדי ליצור bzip2 אוטומטיתtar czf archivename
אוtar cjf archivename
(דוגמה שכוללת גם מודc
וגם אפשרותf
) -
--checkpoint=100
→ Show progress every 100 files --checkpoint-action=dot
→ Prints a dot (.
) per checkpoint
עם SSH
ssh remote-sys 'tar cf - Documents' | tar xf -
דוגמה לשימוש בטאר עם SSH!
אמרנו בעצם: "תתחבר לרמוט, תשלח לו את הפקודה לקחת את כל התיקיה Documents ולהכין ממנה קובץ tar שהולך לאאוטפוט במקום לקובץ; את האאוטפוט הזה תיקח ל-tar במכונה המקומית, ותשתמש בו כדי לחלץ אותה ב-working directory"
- לשים לב שצריך להשתמש גם בפייפ וגם ב--
בטאר 'המקומי'. זה בגלל שאנחנו גם מעבירים לו את האאוטפוט עצמו, וגם אומרים לטאר "תשתמש באאוטפוט" (אחרת הוא לאו דווקא מחפש להשתמש ב-STDOUT)
zip¶
- תוכנה שמוכרת לנו מווינדוז, היא בעצם גם מכווצת וגם מארכבת באותה פעולה
-
פחות פופולרית מ-
gzip
ומ-tar
בלינוקסzip -r archivename pathtoarchive
כמוrm
, בלי-r
בשביל 'רקורסיביות', נארכב רק את התיקיה בלי התוכן שלה -
לא חייב לכתוב .zip בשם הארכיב
- חשוב לדעת שבניגוד ל-
tar
, אם נגיד ל-zip
ליצור ארכיון שכבר קיים, הוא יעדכן את הקבצים בו בלבד ולא יחליף אותוunzip pathtozip
כדי לחלץ
unzip -l [pathtofile]
כדי להדפיס רשימה של קבצים, או רשימה של קבצים שמתאימים לפאת' כלשהו
unzip pathtozip pathwithinzip
כדי לחלץ קובץ ספציפי
-
אם החילוץ מתנגש עם קובץ קיים, נקבל פרומפט שישאל אותנו אם להחליף
-
אפשר לעשות פייפ לאאופוטים כדי שיהיה האינפוט של
zip
, וככה למשל ליצור ארכיבים לפי תוצאות שלfind
find [arguments] | zip -@ archive-name
ייצור ארכייב בהתאם ל-find
. הדגל-@
הוא המקביל של-
ב-tar
, והוא אומר ל-zip
תשתמש באאוטפוט הסטנדרטי כ-path שממנו אתה יוצר את הארכייב -
לצערנו התוכנה
unzip
לא מקבלת STDIN, ולכן אי אפשר לחלץ מארכיב לפי תוצאות של פקודה אחרת... -
התוכנה
zip
יודעת לקבל STDOUT ולכן אפשר לעשות ארכיב של אאוטפוט של פקודה, כמו עם טאר. נשתמש דווקא ב--
כמו ב-tar
כדי להגיד לה להסתכל על האאוטפוט:ls -l /etc | zip archive-name -
-
התוכנה
unzip
יודעת לשלוח את הפלט שלה ל-STDOUT אם מוסיפים את הדגל-p
unzip -p archive-name | less
כדי לקבל רשימה של ארכייב מסוים ולפתוח עם לס -
זיפ ואנזיפ משמשים בלינוקס בעיקר כדי לתקשר עם ווינדוז, אבל יש להם עוד הרבה אפשרויות ב-man page
rsync¶
- תוכנת טרמינל שהיא הגרסה הפושטית של Rclone
- משמשת כדי לסנכרן בין פאת' מקומי, רמוט פאת' או שרת rsync ככה שהתיקיות יהיו mirrored, ויודע לעשות את זה במינימום פעולות ההעתקה הנדרשות (יעיל)
rsync options source-path destination-path
לפחות צד אחד של הסנכרון (source או destination) חייבים להיות מקומיים - אין סנכרון בין remoteים.
--a
בשביל לשמר file attributes
--v
verbose output בשביל
-delete
כדי למחוק מהיעד קבצים שבר לא קיימים במקור
כותבים /source
או /desination
(עם / בסוף) כדי לא להעתיק את התיקיה, אלא רק את התוכן שלה (מתחילים את הפאת' אחרי התיקיה ולא על התיקיה)
- ה-R עומדת בשביל REMOTE! אפשר להשתמש ב-
rsync
כדי לסנכרן קבצים מרמוטים --rsh=ssh
כדי להגיד לארסינק שהוא מתחבר באמצעות SSH-
remote-name:path-in-remote
נציין לארסינק את השם של הרמוט ביחד עם הפ'את' ברמוט, כמו שעושים עם SSH -
עוד אפשרות היא להשתמש ב-Rsync Server! בעצם, ל-
rsync
יש אפשרות לרוץ כ-Daemon שנועד פשוט לקבל בקשות סנכרון. - זה שימושי כשיש תיקיה שהרבה אנשים צריכים לסנכרן ממנה לעתים קרובות. למשל, כל החבילות הנסיוניות של פדורה יושבות על Rsync Servers שמוחזקים בכל מיני אוניברסיטאות. בטא טסטרים עושים sync עם התיקיות האלה כדי לקבל את כל החבילות הנסיוניות העדכניות ליום ספציפי.
- נכתוב את ה-source path באופן שמרפרר לשרת:
rsync://archive.linux.duke.edu/fedora/linux/development/rawhide/Everything/x86_64/os/
המבנה הוא פרוטוקול (rsync://), שם הרמוט (archive.linux.duke.edu) והפאת' לרפוזיטורי הרלוונטי בתוך הרמוט (/fedora/linux/development/rawhide/Everything/x86_64/os/)
gpg¶
- חבילה של GNU, קיצור ל-GNU Privacy Guard
-
נועדה כדי להצפין קבצים!
gpg -c pathtofile
כדי לייצר קובץ מוצפן שלו. נתבקש להזין ססמה לקובץ. הקובץ ייקרא filename.gpg ואי אפשר לפתוח אותו בלי לעשותו לו decryption`gpg pathtofile`
כדי לפתוח את ההצפנה. נתבקש להכניס ססמה, ו-GPG ייצור אוטומטית קובץ חדש שנקרא באותו שם, רק בלי הסיומת GPG. אם הקובץ כבר קיים (המקור באותה תיקיה), הוא ישאל אם לעשות override או לבחור שם חדש.
gpg -o pathtofile destination/path/filename
כדי להגדיר מראש אאוטפוט -
כדי לפתוח את הקובץ:
gpg -d pathtofile > pathto-destination-file
לא לשכוח את ה-redirection! אחרת סתם נקבל את ה-data של הקובץ כאותוית בטרמינל... -
כדאי לשים לב - כשיוצרים הצפנה, GPG יוצר כל מיני קבצים בשם
.gnupg
בתיקיית הבית שלנו. הם בעצם מכילים את הססמאות שהגדרנו, וככה אפשר לפתוח הצפנות בלי להזין ססמה. במערכת בלי הקבצים האלה - נתבקש להזין. אם אנחנו רוצים להעיף את השמירה הזו מהמערכת שלנו - למחוק את הקבצים האלהrm -r ~/.gnupg*
-
אי אפשר להגדיר את הססמה מראש כ-Argument, אבל אפשר ככה:
echo "your_password" | gpg --batch --yes --passphrase-fd 0 -c /path/to/file
echo "your_password"
: This sends your passphrase to the standard output.--batch
: Tells GPG to run in batch mode, which is useful for automation and prevents interactive prompts.--yes
: Automatically answers "yes" to any prompts (e.g., for overwriting files).--passphrase-fd 0
: Specifies that the passphrase should be read from file descriptor 0 (stdin, which is where theecho
command sends it).
חיפוש¶
כמעט כל הפקודות כאן הן חלק מחבילת [[לינוקס - כללי#GNU#|GNU]] בשם findutils
locate¶
- תוכנת טרמינל פשוטה שמחפשת את כל ה-pathים שמתאימים ל-string כלשהו
- זה אומר שאפשר לחפש שם של קובץ ככה
locate filename
- וזה בגלל ששם הקובץ הוא תמיד הקצה של ה-pathname של הקובץ
- אפשר לחפש גם path מורכב יותר, נניח:
locate bin/zip
- יחפש את הקובץ zip רק ב-pathים שמתחילים בתיקיה bin (אנחנו יכולים להניח שתוכנה תשב בתיקיית bin, וככה צמצמנו את מס' ה-pathים ש-locate צריך לסרוק)
-
לשים לב שכל path שמתחיל ב-query שלנו גם תופס - למשל הפקודה הקודמת תמצא גם את
/bin/ziplock
ואת/bin/zipzip
-
אפשר להשתמש ב-regexp מסוג bre באמצעות
--regexp
וב- ב-regex מסוג ere באמצעות--regex
BRE & ERE -
לוקייט היא בעצם שתי תוכנות,
mlocate
ו-plocate
, שהן דומות אבל יש ביניהן קצת הבדלים. לכל מערכת יש אחת אחרת, ובד"כ הן מחוברות ב-symlink לפקודהlocate
-
אם אנחנו רוצים לדעת אם יש לנו תמיכה ב-regex וב-globs, צריך לקרוא את ה-
man
של הגרסה שלנו. -
הפקודה
locate
מחפשת ב-database של pathים שנוצר ע"י תוכנה אחרת בשםupdatedb
. לרוב המערכות ישcron job
של פעם ביום להריץ אתupdatedb
. - אם אנחנו רוצים לעדכן את ה-database לפני ה-cronjob היומי, נעשה
sudo updatedb
find¶
- תוכנת טרמינל לחיפוש קבצים שהיא קצת יותר מורכבת מ-
locate
- האופרציה הבסיסית ביותר שלה פשוט נותנת רשימת קבצים ב-path, למשל ככה:
-
find ~
פשוט ירשום את כל הקבצים שיש בהום -
בשלב הבא,
find
יודעת לסנן את רשימת הקבצים לפי קריטריונים שונים, שמתחלקים ל-options, tests ו-actions
TESTS¶
find path -type x
בשביל להגדיר סוג של קובץ שאנחנו רוצים לסנן לפיו.
למשל find ~ -type d
כדי לקבל רשימה של כל התיקיות ב-home
![[Pasted image 20250127005741.png]]
find path -name "query"
כדי לסנן את הרשימה לפי שם של קובץ. נניח find ~ -name "*.jpg"
j כדי למצוא את כל הקבצים שמסתיימים ב-.jpg
ב-home.
(אפשר להשתמש בגלובים)
find path -size +/-/nullSIZE
כדי לסנן את הקבצים לפי גודל. אפשר לעשות +
בשביל קבצים גדולים מהערך, -
בשביל קבצים קטנים מהערך, או לא להשתמש בשום אופרטור (null) בשביל למצוא קבצים ששווים לערך בדיוק. למשל find ~ -size +20M
בשביל קבצים ב-home שגדולים מ-20 מגה.
![[Pasted image 20250127010203.png]]
רשימה חלקית של טסטים נוספים (עוד ב-man
) ![[Pasted image 20250127010317.png]]
OPERATORS¶
- יש אפשרות לחבר טסטים שונים של
find
באמצעות אופרטורים לוגיים. - כדי לחבר טסטים, נחבר אותם באמצעות
operator
, ככה למשל אפשר לכתוב: -type f -not -perm 0600
כדי למצוא את כל הקבצים הרגילים שהם לא בהרשאה 0600 (אוקטאלי)- אם רוצים לחבר כמה ביטויים בסוגריים, הסינטקס קצת מוזר. נניח שבנוסף לסינון לעיל, אנחנו רוצים לחבר בפונקציה של OR את הסינון:
type -d -not -perm 0700
כדי למצוא גם תיקיות שההרשאה שלהן היא לא 007 אוקטאלי- נחבר את הסוגריים ב-OR באופן הבא:
find path \( -type f -not - perm 0600 \) -or \( -type d -not -perm 0700 \)
- זה סינטקס קצת מוזר, בהתחלה בקסלאש לפני הסוגריים ואז הפוך בסוף. ועם רווחים לפני הטקסט שבסוגריים ולפני הבקסלאש שבסופן...
- לשים לב שלא היינו צריכים לכתוב
and-
לפניnot-
בסוגריים. זה בגלל **ש-find מניח מראש את ה-and כשאנחנו מוסיפים אופרטור לשרשרת - מה שעשינו לסוגריים עם הבקסלאש זה בעצם להקדים כל סוגר בבקסלאש. המטרה של זה היא, כרגיל, [[מילון BASH#backslash#|להיות escape character]]. לסוגריים יש משמעות בטרמינל, ואנחנו רוצים ש-
find
יקבל אותן באינפוט בלי שישתנו (expansion), כי הוא יודע לעשות להן Parsing משל עצמו. לכן אנחנו כותבים \( -test value -operator -test value \)
(עדיין עם רווח לפני הפקודה...)
![[Pasted image 20250127011342.png]]
- כדאי לשים לב שאם כתבנו
expr1 -operator expr2
- אז expr2 לא בהכרח יתבצע, אלא רק בהתאם לשער הלוגי של האופרטור:
- לצורך העניין, אם אנחנו מחפשים קבצים שהם או a או b, ועבור קובץ מסוים,
find
זיהה שהוא a, יש לנו a=true ולכן הוא לא יבדוק האם b (expr2) הוא true עבור הקובץ או לא. ![[Pasted image 20250127012135.png|500]]
- לצורך העניין, אם אנחנו מחפשים קבצים שהם או a או b, ועבור קובץ מסוים,
ACTIONS¶
-
ל-
find
יש מבחר של פעולות מוגדרות מראש שניתן לבצע על רשימת הקבצים שהתקבלה. ![[Pasted image 20250127012313.png|500]] -
כלומר, אם לא כתבנו פעולה,
find
מניח-print
- כדי לכתוב פעולה אנחנו כותבים אותה כדגל:
find path -test value -operator -test value -ACTION
- כמו בין test queries, גם בין כל טסט/פעולה ובין כל פעולה, התוכנה מניחה
-and
- כלומר, שאם כתבנו את הפעולה בסוף הפקודה כמו למעלה, היא תרוץ רק אם כל הקוניונקציה של האאוטפוט מחזירה TRUE (כל מה שמחובר ב-
AND-
בלתי נראים ) find path -ACTION -test value -operator -test value
ואם נכתוב בהתחלה אז ה-ACTION תרוץ ראשונה, ובלי הכרח שכל החוליות הקודמות בקוניונקציה יחזירו T
-exec command 'currentpath' ';'
כדי להריץ כל פקודה שיש לנו בטרמינל על הרשימה. את הפקודה כותבים אחרי -exec
את ה-path ואת ה-semicolon אנחנו עוטפים בגרשיים כי יש להם משמעות בטרמינל, שאנחנו לא רוצים שתתרחב לפני שהם מגיעים ל-find
כאינפוט.
- לא הבנתי איזה pathname כותבים. בדוגמה בספר זה
- -exec rm '{}' ';'
-
אפשר לעשות
ok-
במקוםexec
(עם אותו סינטקס בהמשך) כדי לבצע את הפעולות אינטרקטיבית, כלומר לקבל פרומפט לאישור לפני כל פעולה שתתבצע בעקבות הפקודה. -
לפעמים אנחנו לא רוצים להריץ את ה-ACTION על כל תוצאה של החיפוש בנפרד, אלא בעצם "לאגור" רשימה של תוצאות החיפוש ולתת את הרשימה כולה כארגומנט להרצה אחת בלבד של הפקודה.
- אפשר לעשות את זה ע"י החלפת ה-
';'
ב-+
(בלי גרשיים), כך שהפקודה תיראה (למשל) ככה: find ~ -type f -name 'foo*' -exec ls -l '{}' +
הפקודה הזו אומרת למצוא את כל הקבצים הרגילים שמתחילים ב-foo, ואז ברגע שיש לנו את הרשימה של כולם, להריץ על כל הרשימה ביחדls -l
OPTIONS¶
- האפשרויות קובעות את ה-scope של החיפוש, משתמשים בהן כדגלים באינפוט בדומה לטסטים ופעולות. הן לא צריכות לקבל ערך. ![[Pasted image 20250127015409.png|500]]
xargs¶
-
פקודה מעניינת שמקבלת אינפוט מ-
standard input
(או הקלדה בטרמינל, או מהקצה המקבל של [[מילון BASH#pipe#|pipe]]), והופכת אותו לרשימת ארגומנטים עבור פקודה (שתבוא אחריו בסינטקס)
command | xargs command2
כדי להפוך את כל האאוטפוט שלcommand
לארגומנט שלcommand2
. דוגמה קונקרטית:find ~ -type f -name 'foo*' -print | xargs ls-l
כדי למצוא את כל הקבצים הרגילים שמתחילים ב-foo, להדפיס רשימה שלהם, ואת הרשימה הזו לתת ל-ls -l
כארגומנט (בשביל שידפיס את הרשימה מחדש בפורמט שלו). -
לטרמינל יש הגבלה של אגרומנטים, אם ניתן לפקודה xarg ארוך מדי הוא פשוט יריץ את המס' המקסימלי האפשרי. אפשר להריץ את
xarg
עם הדגל הבא כדי שיראה את הלימיט:xargs --show-limits
null separation¶
- כשאנחנו משתמשים ב-
find
, או ב-xarg
, יש כל מיני תווים מיוחדים בשמות של קבצים שיכולים לזיין לנו את הרשימה ולהכניס ברייקים איפה שאין ברייקים. - לכן, לשתי הפקודות הללו יש אפשרות להריץ ככה שרק ה-
null character
(ASCII #0) תחשב ל-argument separator (רק היא מסמלת שעברנו לארגומנט הבא). -print 0
בפקודתfind
-
--null
or-0
בפקודתxargs
-
לשים לב ש-null זה לא ספייס! צריך למצוא את התו הבלתי נראה שהמס' שלו ב-ASCII הוא 0
- לא צריך באמת לשים Null בשמות הקבצים שלנו! אנחנו משתמשים באחת מהאפשרויות האלה כדי להתעלם מכל סוג של ריווח או שבירת שורה בשמות הקבצים שאנחנו פועלים עליהם. בין קובץ לקובץ תמיד יהיה מראש null (בלי קשר למה שיש או אין באמצע, בתוך השמות של הקבצים).
regular expressions (regexp)¶
הקדמה¶
- זה תיעוד מקורי שלי (קצת מבלבל לפעמים) של Regexp.
- הסברים ברורים יותר לקרוא כשכותבים, אפשר למצוא ב-Regexp
-
כלים מסורתיים של GNU עובדים עם bre syntax, ואם נותנים להם
e-
אז עם ere syntax דוגמאות בולטות: sed, grep -
בגדול regex דומה לגלובים... זו דרך להגיד לכלים שונים בטרמינל לזהות תבניות בטקסט סטרינגס
-
יש כל מיני אימפלמנטציות מעט שונות של regex אנחנו נתמקד בגרסה המפורטת ב-POSIX STANDARD, שהיא הרווחת בטרמינל
-
כל תו רגיל שנשים ב-string שלנו הוא literal character זה אומר שהתו מסמל את עצמו ושה-regular expression מתאים את הסטרינג לכל סטרינג עם אותם Literal characters שמסודרים באותו הסדר
חוץ מ-literal characters, יש לנו ב-regex גם metacharacters שמשנים את ההגדרה של "התאמה"
^ $ . [ ] { } - ? * + ( ) | \
המטא-תווים לשים לב ש-\ backslash
מיועד להפוך תו מטא ל-Escaped character - לשים לב גם שרוב המטא-תווים הם בעלי משמעות 'מתרחבת' בטרמינל, לכן חייב לעטוף אותם בגרשיים (את כל הסטרינג) כשאנחנו נותנים אותם כאינפוט -
סוגי מטא-תווים והשימוש בהם:
*
& .
- ANY character, any NUMBER of times¶
.
(נקודה):
- עובדת כמו הגלוב *
בבאש הרגיל (גלובים) עם הבדל חשוב:
- בעוד ש-*
בבאש מוצאת תו שרירותי אחד או יותר - נקודה .
ב-Regex מוצאת תו שרירותי אחד בלבד (כולל רווח או שבירת שורה)
- כדי להגיד "תו שרירותי, מס' שרירותי של פעמים" יש לשלב עם *
*
(כוכבית):
- בתכלס זה quantifier (כמתים ב- regex)
- אבל נכתוב עליו בנפרד כי מאוד נפוץ להשתמש בהם יחד...
- *
אומר "מה שבא לפניי, כל מס' של פעמים"
- אז לעשות .*
(נקודה ואז כוכבית) זה המקביל של Regex ל-*
בבאש...
- אם נכתוב ב-regex את הסטרינג `zip*.` - זה יעבוד כמו הגלוב המקביל; אנחנו נמצא כל פריט שיש לו **לפחות 4 תווים,** כאשר השלושה האחרונים הם `zip`.
- לשים לב ש-`.` מתרחבת **לתו אחד לפחות** - וביחד עם כוכבית, **לתו אחד או יותר**
בדוגמה מעל, נמצא גם את `azip` וגם את `abzip`, אבל לא נמצא את `zip`, כי אין לו שום תו שמהווה את `.`.
^
and $
- Anchors¶
^string
ימצא לנו רק תוצאות שמתחילות בסטרינג
string$
יתן לנו רק תוצאות שמסתיימות בסטרינג
^string$
יתן רק תוצאות שמתחילות ונגמרות בסטרינג
^$
יתאים רק ל-blank lines
[]
Bracket Expressions¶
grep -h '[bg]zip'
יחפש לנו קבצים שנקראים או
bzip
או gzip
- אפשר לכלול metacharacters בתוך הסוגריים והם יחשבו חלק מהדיסיונקציה, כתו רגיל
- יוצאי הדופן הם
^
שמסמל שלילה, ו--
שמגדיר טווחים grep -h [^bg]zip
ימצא את כל מה שמסתיים בזיפ ולא מתחיל בבי או ג'י (כלומר, כל מה שבא אחרי^
הוא שלול, לא צריך לשלול כל אות) לשים לב שאות שלולה עדיין מחייבת אות כלשהי (אחרת) - החיפוש הזה לא ימצא אתzip
-
grep -h [a-z]zip
ימצא כל קובץ שהשם שלו הוא אות בטווח שצוין ואחרי זה זיפgrep -h ^[A-za-z0-9]
אפשר לחבר כמה טווחים, בלי רווח, נגיד כאן נמצא את כל מה שמתחיל באות גדולה או קטנה, או במספר -
אם רוצים ש-
-
יהיה חלק רגיל באקספרשן, פשוט לא נשים אותו באמצע, אלא בהתחלה...grep -h [-AZ]
כדי לחפש או דאש, או איי גדולה או זי גדולה
Character Classes¶
הכתיבה של טווח אותיות לא תמיד עובדת באופן צפוי, בגלל סיבות היסטוריות.
כשלינוקס יצא הוא הניח שיש רק ASCII: איפה שתווים 0-31 הם control codes ו-32-63 הם אותיות שניתן להדפיס (כולל פיסוק ומספרים); 64-95 הם אותיות גדולות ועוד כמה סמלים; 96-126 הם אותיות קטנות ועוד כמה סמלים. מערכות שיש להן רק ASCII מסדרות את התווים ככה:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
בעוד שהסידור המילוני (שימצא בקובץ מילון) של התווים הוא כזה:
aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
עם הפופולריזציה של UNIX בעולם, נדרשו עוד תווים כדי לכתוב בעוד שפות; לכן ה-ASCII הורחב ל-8ביט ונוספו לו התווים 128-255, שכללו אותיות עבור שפה נוספת.
נוצר המושג של locale, שהוא character set של 0-255 שמותאם לשפה מסוימת.
ה-locale מוגדר דווקא ע"י קובץ מילון - אז אם כתבנו ב-regex את הטווח [A-Z]
ואנחנו מול קובץ מילון, נקבל טווח מוזר של כל האותיות חוץ מ-a קטנה...
כדי להתגבר על הפאקרי הזה, יש ב-POSIX כמה סטנדרטים לכתיבה של טווחים, שנקראים Character Classes
![[Pasted image 20250127155750.png|500]]
- אפשר לשנות את ה-locale במערכת ל-
posix
כדי לחזור להתוויה המקורית אם רוצים. [[לינוקס - כללי#LANG#|עוד על לשנות את ה-locale בהסבר הזה]]
BRE & ERE¶
- כאן אנחנו נכנסים לפאקרי האמיתי: POSIX מחלק את ה-regex לשני סוגים: basic regular expression (BRE) ו-extended regular expression (ERE).
- כל תוכנה בסטנדרט של POSIX תומכת ב-BRE, אבל רק חלקן תומכות ב-ERE.
- ב-BRE, התווים הבאים בלבד הם מיוחדים (מטא):
^ $ . [ ] *
-
בעוד שב-ERE, התווים הבאים מתווספים למטא:
( ) { } ? + |
-
הקאצ' הוא שב-BRE, שני סוגי הסוגריים (), {} דווקא כן יהיו מיוחדים/מטא אם ניתן להם backslash
- זאת בעוד שב-ERE, באקסלאש לפני כל תו הופך אותו למילולי (מודפס כעצמו)
|
Alteration¶
- שייך ל-ERE, דורש
grep -e
אוegrep
- כמו ש
[xy]
ב-bre regex אומר "או x או y", לעשותgrep -E 'AAA|BBB|CCC'
ב-ere regex אומר "או הסטרינג AAA, או הסטרינג BBB, או הסטרינג CCC" - בקיצור אפשר להשתמש ב-
|
כדי ליצור שרשראות דיסיונקציה של סטרינגים עבור ה-regex query - אם רוצים לשלב שרשרת דיסיונקציה כזו עם עוד regex, שמים אותה בסוגריים:
grep -E '^(AAA|BBB|CCC)'
יתאים רק לפרטים שמתחילים באחד מהסטרינגים
^ Negation¶
-
בשני סוגי ה-regex, אם אנחנו רוצים את המקביל ה-regexי של אופרטור NOT, אנחנו משתמשים ב-
[^query]
כלומר, גם בסוגריים מרובעים וגם בסימן^
, חשוב לזכור שמחוץ לסוגריים מרובעים המשמעות שלה שונה - הוא אומר "בתחילת השורה" -
יש אפשרויות יותר יעילות ל-queryים מסובכים: הכי פשוט זה לחפש באמצעות
grep -v
, הדגלv
הוא בדיוק "הפיכה" של החיפוש מהתאמות לאי-התאמותאפשרות יותר מתקדמת היא להשתמש ב-
awk
באופן הבא:awk '!/query/' file.txt
הסימן!
ב-awk
גם הוא מסמל "NOT"
Quantifiers¶
?
- שייך ל-ERE, דורש
grep -e
אוegrep
- הסימן
?
אומר ב-ere: "מה שקדם ל-?, יכול להיות מותאם או 0 פעמים או פעם 1" - בוא נניח שאנחנו רוצים לקבל מס' טלפון, והוא יכול להיות או nnn-nnnn או (nnn) nnn-nnnn (קידומת אפשרית בסוגריים)
- כדי לכתוב regex query שיחזיר התאמה בשני המקרים, נכתוב ככה:
^\(?[0-9][0-9][0-9]\)? [0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$
- הסבר: אנחנו מתחילים מ-
^
כדי לחפש כל סטרינג שמתחיל בפורמט הנכון (לא חובה...); אנחנו משתמשים ב-\
כדי לכתוב סוגריים בלי שתהיה להם משמעות, ובתוך הסוגריים כותבים שלוש פעמים את הטווח[0-9]
כדי להגיד "כל שלוש ספרות בתוך סוגריים"; כל העסק עטוף גם ב-?
כדי להדגיש שלא חייב להיות חלק כזה ב-string בכלל.למה ה-? הראשון אחרי הסוגר הראשון? נראה לי שזו טעות... לא ממש ברור לי... השערה:
?
אומר בכלל "כל מה שקדם לי הוא אופציונלי" ולא "עוטף", ואז הקוד אומר שאפשר לשים סוגר בהתחלה או שלא, ואז לכתוב שלוש ספרות עם סוגר אחריהן או שלא. -אוקיי, זה היה נכון. עכשיו למה יש ? נפרד עבור הסוגר הראשון? אותה שאלה...
*
- הסימן *
אומר משהו אחר מב-BRE REGEX. הוא דומה ל-?
, אבל מתאים גם עבור 0 הופעות, גם עבור 1 וגם עבור יותר מ-1
- כלומר במקום להגיד "מה שלפני ? יכול לחזור פעם אחת או שבכלל לא", אנחנו אומרים "מה שלפני * יכול לחזור בין 0 לאינסוף פעמים" (וזו תישאר התאמה)
[[:upper:]][[:upper:][:lower:] ]*\.
זה query יפהפה שמחזיר התאמה רק למשפטים שבנויים נכון גרמטית: מתחילים באות גדולה, כוללים איזשהו מיקס של אותיות גדולות וקטנות, ומסתיימים בנקודה.
- אנחנו מסמלים ב-^ "תתאים למה שמתחיל ככה"'; מכניסים רצף של שלושה טווחים לפי הסטנדרטיזציה של POSIX - מתחילים בטווח "אות גדולה" וממשיכים לדיסיונקציה (תחומה בסוגריים מרובעות) של הטווח "אות גדולה" או "אות קטנה"; הסיקוונס הזה מקבל בסופו * כדי להגיד שהוא חוזר בין 0 לאינסוף פעמים, ולאחר שהוא חוזר x פעמים אנחנו מצפים לנקודה, שמקדים אותה באקסלאש כדי שתתפרש כנקודה טקסטואלית. בעצם הגדרנו משפט כ-"סיקוונס שמתחיל באות גדולה, כולל עוד 0 עד אינסוף אותיות גדולות או קטנות ואז מסתיים בנקודה".
+
- הסימן
+
עובד דומה ל-?
ול-*
, אבל אומר "תתאים אם מה שלפני + מופיע לפחות פעם אחת"grep -E '^([[:alpha:]]+ ?)+$
יתאים לכל שרשרת של מילים אלפבתיות (עם אותיות בלבד) שתחומות בסוגריים ומופרדות ברווחים(quite like that)
{}
- הסוגריים {}
יכולות לשמש כ-quantifier גם הן, ולהגדיר בדיוק כמה מופעים של הסטרינג אנחנו רוצים כדי להחשיב את זה להתאמה. יש כמה פורמטים אפשריים:
![[Pasted image 20250127170017.png|500]]
^\(?[0-9]{3}\)? [0-9]{3}-[0-9]{4}$
עוד ניסוח לזיהוי של מספרי טלפון
subexpressions, backreference¶
שימושי במיוחד ל[[מחברות קוד/Bash&Linux 🐧/מילון BASH#sed#|sed]] - בתוכנות מסוימות שתומכות ב-bre, אפשר להשתמש ב-back reference.
אם הסיקוונס n/ מופיע בשדה ה-replacement, כאשר n הוא מספר בין 1-9, ההחלפה תתבצע עבור ה-subexpression התואם **ב-regular expression הקודם** (במקרה של sed, בשדה ה-regexp)
`[0-9]{2}/[0-9]{2}/[0-9]{4}$`
הוא ביטוי regex שילכוד תאריכים בפורמט MM/DD/YYYY
מה אם אנחנו רוצים להחליף אותם בפרמוט אחר של אותו המידע? נעשה:
`([0-9]{2})/([0-9]{2})/([0-9]{4})$`
כל חלק ב-regex שעטוף בסוגריים רגילות `()` ניתן לרפרור ב-regex הבא כ-subexpression
`\3-\1-\2`
בשדה ההחלפה יבוא אותנו ל- `YYYY-MM-DD`
- נחדד:
מגדירים את ה-subexpressions באמצעות עטיפתם בסוגריים
()
ב-regex הראשון משתמשים ב-subexpressions ע"י כתיבה שלn/
ב-regex הבא כאשר n הוא מס' ה-subexpression (ממוספרים לפי סדר הכתיבה)
נואנסים¶
-
חשוב לדעת ש-grep מתאימה ל-query כל פריט שמכיל אותו, בעוד ש-
find
מתאימה ל-query רק פריטים שתואמים לו בדיוקgrep "^pattern"
בשביל תוצאות שמתחילות במשהו מסוים
אינפוט/אאוטפוט וסינונים¶
exit status¶
-
לכל פקודה שרצה יש סטטוס יציאה שמשקף את ההצלחה שלה. הסטטוס הוא ערך בין 0 ל-255. exit status 0 = הצליחה exit status 1+ = נכשלה תוכנות מסוימות נותנות ערך 1 לכל כישלון; אחרות משתמשות בערך מדויק יותר בין 1 ל-255 כדי לאפיין את השגיאה.
-
זה מה שההתניות השונות משתמשות בו כדי להשתמש בפקודה כתנאי
- אפשר לרפרר לסטטוס היציאה האחרון ע"י
$?
לולאת if למעשה אומרת "תריץ מה שבסוגריים, ואם בסוף$?
שווה ל-0, תעשה את הפקודות הבאות:"
true, false¶
- פקודות שפשוט אומרים לטרמינל שעכשיו
$?
(exit status) יהיה שווה ל-0 או ל-1 בהתאם - שימושי כדי ליצור שורה מסוימת בסקריפט, שאם היא רצה, היא מגדירה את ה-exit status באופן מסוים
- במילים אחרות, לולאת if אומרת
if true
ו-`if false'
redirect operators¶
>, >>
Output Redirection¶
מנתבים את הפלט של הפקודה שלפניהם למקור אחר. למשל קובץ.
echo "Hello World" > output.txt
הולך למחוק את output.txt ולכתוב אליו hello world. כלומר משכתב את הקובץ
echo "Hello again" >> output.txt
הולך להוסיף את Hello World בתחתית של הקובץ, מתחת לתוכן הקיים אם יש כזה. כלומר, מוסיף לקובץ.
(מדובר באאוטפוט [[#אינפוט/אאוטפוט וסינונים#STDERR & STDOUT|STDERR]] בלבד - כלומר הפלט הסטנדרטי של פקודות)
<
Input Redirection¶
מעביר פאת' מסוים להיות הקלט של פקודה (שנכתבת ראשונה, לפי כיוון החץ)
למשל sort < input.txt
יפעיל פקודת sort על הטקסט שב-input.txt
&>, 2>&1, 2>
Redirecting Output & Errors¶
&>
עובד כמו [[#>, >>
Output Redirection|רידיירקט]] אבל מדפיס גם [[#אינפוט/אאוטפוט וסינונים#STDERR & STDOUT|STDERR וגם STDOUT]]
2>&1
הוא כמעט אותו דבר, אבל במקום לכוון את שני הסטרימים באותה פקודה, הוא פשוט אומר "2 הולך לאן ש-1 הולך"
אפשר גם פשוט <2
או <<2
כדי להגיד "2 הולך ל-(פאת') (כתוספת או כשכתוב)", כמו שמוסבר ב- [[#אינפוט/אאוטפוט וסינונים#STDERR & STDOUT|STDERR וגם STDOUT]]
כל הפקודות עובדים גם כ-> וגם כ-<
<(...), >(...)
Angel Parenthesis\process substitution¶
-
שילוב של סוגריים עגולות
(...)
ושל רידירקציה עם `` -
יש לנו את האפשרות לקחת ערך של subshell operation (כל מה שבסוגריים) ולנתב את האאוטפוט שלו, כ-file descriptor, כלומר כערוץ חדש של אינפוט/אאוטפוט: השימוש בזה מאפשר לנו להשתיל פקודות בתוך פקודות, בדומה לשימוש ב-pipe
|
, אבל גם במקומות שלא ניתן להפעיל בהם pipe - כמו בארגומנטים של פקודה:sort <(ls path) <(laspath2) <(lspath3)
היא למעשה שקולה ל:
sort "$(ls path)" "$(ls path2)" "$(ls path3)"
אבל מאפשרת לנו לשלוט בערכי הפונקציות באמצעות 3 ערוצי פלט/קלט נפרדים. -
לעתים נצטרך לעשות
command < <(read)
, כאשר הפקודה לא לוקחת target file כארגומנט, אלא רק באמצעות רידיירקט (ה> של ה-angel parenthesis לא נחשב). -
שימוש נפוץ הוא בשילוב עם
read
ועם לולאה כדי לתרגם אינפוטים למשתנים נפרדים בקלות:לשים לב לשימוש המיוחד ב#!/bin/bash # pro-sub: demo of process substitution while read -r attr links owner group size date time filename; do cat << _EOF_ Filename: $filename Size: $size Owner: $owner Group: $group Modified: $date $time Links: $links Attributes: $attr _EOF_ done < <(ls -l --time-style="+%F %H:%m"| tail -n +2)
()>
כאשר אנחנו מזינים אותו ללולאה: הוא נרשם כאילו הוא מתייחס לפקודהdone
(בשורה האחרונה של הלולאה). -
חשוב לזכור שה-File Descriptor הוא קובץ הקובץ הזה מקבל Path בסגנון של
/dev/fd/63
אז עבור פקודה שמקבלת filepath, אפשר להשתמש ב-Process substitution, למשלcat
אבל עבור פקודה כמוecho
שמקבלת סטרינג - הביטוי פשוט יחזיר את הערך של הפאת'...
<<, <<- <<<
Here Documents/Strings¶
<<
Here Document:¶
-
מאפשר לנתב לפקודה אחת מספר שורות כאינפוט
cat << TOKEN This is a multi-line input passed to cat. TOKEN
The content between<< EOF
andEOF
is passed tocat
as input. אפשר לבחור כל סטרינג להיות ה-TOKEN (מחליט מתי נגמר האינפוט שנעביר לפקודה) -
התרחבויות עובדות כרגיל, אבל אפשר לעטוף את ה-TOKEN במרכאות בודדות כדי לגרום לו שלא להרחיב $ וכו' (אחרת צריך Escape Backslash כדי לכתוב אותם):
cat << 'TOKEN' Thi$-will-not-expan\d;
_EOF_
הוא השם המקובל לטוקן אם אין צורך אחר -
הוריאציה
->>
עושה שה-Here doc יתעלם מאינדנטציה (רווחים שמקדימים שורה) אם הם נוצרו באמצעות tabs - אם spaces זה לא עובד (יש תוכנת המרה, לחפש במחברת)
<<<
Here string:¶
חידוד: כל מה שכתבתי כאן נכון, אבל לא כתוב במפורש למה זה טוב: אז אני מחדד,
>>>
זה סופר שימושי כדי לתת משתנה כאינפוט לפקודה שלוקחת רק קבצים כאינפוטים. הדוגמה הכי קלה זה grep - אם אני רוצה לעשות grep על ערך של משתנה, זה פשוט מסודר יותר (ולדעתי חסכוני יותר) מלעשות echo ואז פייפ לתוך grep
-
מאפשר לנתב לפקודה אחת שורה אחת בלבד כאינפוט אפשר לעשות echo עם פייפ (|), אבל אפשר גם פשוט ככה:
grep "pattern" <<< "This is a test string"
The string"This is a test string"
is passed as input togrep
to search for"pattern"
. (לשים לב ש-path הוא לא string!) יתרון של השימוש ב-HERE DOCUMENT: הטרמינל מתעלם מגרשיים. אפשר לכתובecho "hello"
והטרמינל ידפיס"hello"
כאילו הן חלק רגיל בסטרינג. -
מאפשר לחבר פקודות בלי ליצור Subshell החיסרון המרכזי של פייפים
|
הוא שהם יוצרים subshell בכל פעם שאנחנו פותחים אחד (הפייפ בעצם פותח סשן חדש שמקבל כאינפוט את האאוטפוט של הסשן המקורי, וכך הלאה עם כל פייפ.)אם אנחנו עובדים עם פקודה שמגדירה משתנים עבור ה-shell session שלנו - למשל
read
, לעשות משהו כמוecho "option" | read
יחזיר לנו blank בערך של$REPLY
, וזה בגלל ש-read רצה ב-subshell משלה, וה-subshell לעולם לא יכולה להשפיע על ה-parent shell שלה. השורהread <<< option
תעבוד ותחזיר לנו "option" ב-$REPLY
|
pipe¶
חשוב לזכור שכשאשר אנחנו משתמשים בפייפ, אנחנו פותחים subshell ובעצם מנתבים את כל הפלט שקודם לו אל ה-subshell החדשה. לא תמיד נרצה לעשות את זה, ובכל אופן כדאי לזכור.
command | command 2
מנתב את הפלט של הרישה ישירות לקלט של הסיפה
כך אנחנו עורכים סינון בתהליכים רצים למשל:
ps aux | grep query
עוד דוגמה: `ls -l | grep ".txt" יגרום ל-grep לחפש קבצי טקסט בפלט של ls -l
filter¶
נהוג להשתמש בדאבל פייפ כדי ליצור 'פילטרציה'
למשל ls /bin /usr/bin | sort | less
יעשה לנו רשימות של שני הפאת'ים, יעשה להם סורט (הפילטר) ואז יתן את הפלט ל-less כדי שנוכל לקרוא אותו
mkfifo
Named Pipe¶
-
הפקודה נועדה ליצור קבצי
fifo
, שהם בעצם קובץ שמתפקד כפייפ - כלומר, מקבל קלט מפקודות, ומייצא אותו כפלט עבור פקודות. אם פייפ מחייב אותנו לשים פקודות אחת אחרי השניה, משני הצדדים שלו, הקובץ מאפשר לנו לעשותcommand1 > pipe_name
ואז בסקריפט או בטרמינל סשן אחר:command2 < pipe_name
כאשר התוצאה תהיה כמו לעשות command1 | command2, רק בין תהליכים נפרדים: כלומר, ברגע ש-command1
תרוץ,command2
תרוץ מיד כאילו קיבלה את הפלט של 1 בפייפ. > האם command2 תרוץ ככה ברגע שהיא תרוץ, לפי הסדר של הסקריפט שלה, או מידית כש-1 רצה?הקובץ נקרא named pipe כי הוא בעצם פייפ שאנחנו מגדירים ועושים בו שימוש מחוץ לסקריפט נתון.
-
הסיבה שהוא נקרא fifo היא שהקובץ הזה הוא למעשה text buffer, שיודע איפה לשבץ אינפוטים חדשים, ואילו אאוטפוטים לייצא בכל פעם, לפי היגיון של first in - first out.
-
הקובץ הזה הוא למעשה גרסה פשוטה מאוד של ארכיטקטורת קליינט-שרת בקשות 'נרשמות' בצד אחד של הפייפ, ותשובות 'מודפסות' בצד השני של הפייפ. לכל בקשה יש תשובה מתאימה, וזהו הפרוטוקול לפיו אנחנו מושכים ורושמים מידע.
-
יצירה של קובץ fifo:
mkfifo <pipename>
הקובץ אכן נוצר במערכת שלנו - אם נעשה לוls -l
נוכל לראות p בהתחלה של סטרינג ההרשאות שלו - זה מסמן שהוא named pipe.
כל עוד אין פקודה בצד השני של שימוש ב-named pipe - הפקודה שלנו תשאר קפואה, בהמתנה לערך. כלומר, הטרמינל או הסשן שלנו יהיה 'חסום' עד שאכן יתאפשר לו לחבר את הפייפ.
flags¶
בגדול שני הסוגים נקראים flag והם פשוט נועדו לסמן אפשרויות, אין פה חוקים מורכבים. השורה השלישית מעניינת: אם רוצים לגעת בקובץ שמתחיל ב'-', משתמשים ב'--' כדי לסמן שנגמרו ה-flagים. לכל פקודה יש פלאגים משלה, -f לא תמיד יעשה אותו דבר. בד"כ -v יהיה verbose, ו--help יעשה... הלפ.
Symbol | Purpose | Examples |
---|---|---|
- |
Short option (single letter) | ls -l -a is the same as ls -la |
-- |
Long option (full word) | ls --all , tar --create --file=archive.tar |
-- (without argument) |
End of options indicator | rm -- -file (removes a file named -file ) |
echo¶
בגדול משתמשים בזה כדי שהאאוטפוט יהיה לפי מה שבא אחרי echo יכול להיות סתם string כמו היי עולם יכול להיות PATH$ כדי לדעת איזה תיקיות נכללות בפאת' (לוודא מה זה בדיוק אומר... אני יודע שאפשר להריץ דברים מהפאת' לא?)
echo -e
כדי להתייחס ל-[[מילון BASH#Escape Sequences & Characters|Backslash Escaped Characters]] (אחרת ה-shell מתעלם ומדפיס אותם כמילוליים)
- כדי להדפיס new line (שורה ריקה):
\n
echo -e "\n"
אפשר גם באמצע הטקסט כמובן, בכל מקום שיופיע בתוך הסטרינג - תשבר שורה.
printf¶
-
דומה ל-echo אבל יותר מומלץ - לחקור ולהרחיב יותר קונסיסנטי במערכות שונות, תומך כברירת מחדל ב-Escape Characters חייב להשתמש בגרשיים (בניגוד ל-echo) הספר שלי אומר שהוא בעיקר שימושי בסקריפטים (כי אין STDIN), כדי לפרמט tabular data
-
חשוב לדעת שהיא לא מקבלת STDIN, אז לא עושים איתה פייפים
- המבנה הכללי:
printf [-v var] "format" arguments
- הפלט הולך ל-STDOUT אלא אם משתמשים בדגל -v var
, ואז הפלט הולך לערך של משתנה var¶
printf "line1\nline2\n"
אאוטפוט:
line 1
line 2
(אם לא שמים שבירת שורה בסוף ה-path שבתחילת כל טרמינל יהיה על אותה שורה של line 2...)
-
הסיפור עם "FOAMAT" ו-ARGUMENTS הוא כזה:
בגדול, "FORMAT" הוא הטקסט שיודפס, ו-ARGUMENTS הם ערכים שנגדיר עבור משתנים שישמשו אותנו ב-FORMAT
המשתנים של
printf
נקראים conversion specifications והם מפורמטים עם%
ואחריו אות
![[Pasted image 20250130015006.png|500]]
-
נניח שעשינו
printf "...%s"
אנחנו מגדירים אותו בסוף הפקודה כ-ARGUMENT, ונותנים string במקרה הזהprintf "goodbye%s" hello
יחזיר:goodbyehello
-
צריך לתת ARGUMENT ייחודי לכל conversion specificer, לפי סדר ההופעה שלהם בקוד אם נעשה פעם אחת 380, ונשתמש ב-4 specifiers, רק הראשון מביניהם יקבל את 380. אם כולם צריכים לקבל 380 צריך לסגור את הפקודה ב-380 380 380 380
-
אפשר לתת רכיבים נוספים ל-conversion specifiers: בגדול הפורמט הוא
%[flags][width][.percision]conversion-specifier
יש באמת יותר מדי אפשרויות לחרא הזה. אני שם פה את הפרטים:
![[Pasted image 20250130015807.png|500]] ![[Pasted image 20250130015820.png|500]]
file descriptor (FD)¶
-
המספר שמוצמד לסטרימים שונים ב-shell 0 זה STDIN 1 זה STDOUT 2 זה STDERR (error)
-
אפשר ליצור FDים חדשים באמצעות רידירקציה אנחנו עושים
2
כדי לקרוא/לכתוב ל-STDERR אז נעשה3/4/5
כדי לקרוא/לכתוב ל-FD חדש (שנוצר אוטומטית)
STDERR & STDOUT¶
לטרמינל בעצם יש שני "סטרימים" של output, כברירת מחדל שניהם מופיעים על הטרמינל
- STDOUT (1) - אאוטפוט של פקודות
- STDERR (2) - הערות, שגיאות וכו' לגבי פקודות
- אפשר להתייחס לסטרימים האלה בפקודות ולנתב אותם: הם נקראים פשוט 1 ו-2 בהתאמה
- כל פקודה ששולחים לטרמינל מקושרת מראש ל-STDOUT שלה
- המשמעות היא למשל ש- command > /path/to/file
תשלח את האאוטפוט של הפקודה לקובץ Log שנגדיר בעצמנו.
- לשים לב שהפקודה לא קשורה לסטרים שלה אם זה לא ממש אחריה בסינטקס. כלומר, כדי לאחד למשל את הסטרימים לאאוטפוט יחיד ולהוציא ל-log, לא עושים 2>1
. עושים 2>&1
כדי שלטרמינל יהיה ברור שלא מדובר בקובץ אלא בסטרים מס' 1
- גם לא עושים &2>&1
, כי בפעם הראשונה, כשזה מיד אחרי הפקודה, זה לא רלוונטי
(מקווה שהבנתי נכון - לא חותם על המשמעות של ה-& ולמה רק בפעם השניה שמים אותו)
- גם האינפוט של פקודות הוא סטנדרטי: STDIN (סטנדרט אינפוט)
/dev/null¶
אם אנחנו רוצים לנתב אאוטפוט כלשהו לטיזינבי, כלומר לא רוצים לעשות איתו כלום, אפשר לעשות נניח
command 2> /dev/null
זה מקום שמיועד להיות 'bit bucket', כלומר סתם מקום לשים בו שיט חסר שימוש
grep¶
לקחים מניסיון: תמיד כדאי לעשות grep -E כי פחות דברים דורשים אסקייפים (למשל {} של כמתים לא דורשות ב-ERE) כשעושים סוגריים של דיסיונקציה או השמטה (
[]
, לא צריך לעשות אסקייפים בתוכן, אפילו לא לסוגר מרובע נוסף). לא ממש אפשר לשלב -o ו-v -- ה-v מחריג את כל השורה שבה הוא מוצא התאמה, אז o לא יעשה כלום... (במקום זה לעשות sed ולהחליף את התבנית שרוצים לגזור בכלום...)
[[מילון BASH#regular expressions (regexp)#|כל query של grep הוא למעשה regex]]
לשים לב שב-grep כמו ב-sed וכו', כל הארגומנט שאנחנו נותנים לו (regex-query בדוגמאות) עטוף ב-
''
grep [options] regex-query [file...]
המבנה הבסיסי
- לתת filepath יבצע את החיפוש על קובץ
- אפשרויות:
- האפשרות הכי חשובה היא
o-
שמאפשרת לנו לקבל באאוטפוט רק את התחום של ההתאמה (ולא כל השורה) (משום מה זה צריך להיות הflag הראשון אם שמים כמה ברצף) - חשוב -
-q
כדי להשתיק את האאוטפוט לטרמינל בסקריפט - לרוב עדיף להשתמש ב-
v-
מאשר לנסות ליצור שלילה ב-regex - עוד אפשרות סופר חשובה:
-F
כדי לבטל regexp
![[Pasted image 20250127135638.png|500]]
-
אפשר לחפש בטווח של קבצים ע"י שימוש בגלובים ב-file path, ככה:
grep bzip dirlist*.txt
הולך לחפש את הסטרינגbzip
בכל קובץ ששמו מתחיל ב-dirlist
ונגמר ב-.txt
-
החיפוש הוא case sensitive
command | grep "pattern" יביא את כל התוצאות שמכילות את ה-pattern בשם
command יכול להיות ls או משהו כזה
grep "error" filename.txt
יביא את כל השורות בקובץ שכוללות את error (או כל pattern אחרת)
ps aux | grep "firefox"
יראה לנו את כל התהליכים שרצים עם המילה firefox
אפשרויות:¶
אפשר להוסיף לכל use case בהתאם:
grep -i
בשביל שלא יהיה case sensitive
grep -n
בשביל תוצאות עם מס' השורה (אם מחפשים בקובץ)
grep -v
בשביל להפוך את החיפוש (רק תוצאות שלא כוללות את pattern)
egrep¶
- רוב השנים,
grep
תמך רק ב-bre regexp, וכדי להשתמש ב-regex מסוג ere, הייתה לנו את התוכנהegrep
- אבל, בגרסת ה-GNU הנוכחית של
grep
אפשר לעשותgrep -e
כדי להשתמש ב-ERE regex
zgrep¶
עם zgrep
אפשר לבצע חיפוש בתוך קבצים דחוסים מסוג gz (סינטקס זהה ל-grep, נותנים את ה-gz ב-filepath)
Sort¶
מסדרת את הקלט לפי פרמטר שמגדירים ב-flag
![[Pasted image 20250111035848.png]]
-m
כל ארגומנט הוא קובץ לפני סידור. התוכנה תחבר את כל הקבצים לקובץ אחד שהיא תעשה לו סורט.
ממיין רק רשימות שבנויות בפורמט הבא:
data=item1\nitem2\nitem3
אם יש לנו מבנה אחר אפשר לנסות להמיר:
data="banana apple cherry"
echo $data | tr ' ' '\n' | sort`
- יש אפשרויות לכוון אותו לעמודות מסוימות בטבלה, לחלקים מסוימים בדאטה וכו' - לא היה לי כוח לקרוא עד הסוף.
עושים sort path.txt
tabular data¶
יכול להיות שזה רחב מ-sort ויעבור מקום בהמשך
- בוא נניח שאנחנו רוצים לעשות sort
לפי משקל קובץ לטבלה של ls -l
- הפלט של ls l
הוא טבלת דאטה: tabular data
- בטבלה כזו, כל שורה היא record ולכל record יש מספר שדות - fields
- אפשר לתת ל-sort
ערך שנקרא key field על מנת שישמש כ-sort key
- במילים אחרות, אפשר להגיד לו על איזה מספר של field להסתכל ב-table
sort -k fieldnumber
למשל
sort -nrk 5
-n
כדי לסדר מספרית
-r
כדי לסדר בסדר יורד
-k 5
כדי לסדר לפי הערכים של שדה מספר חמש
(במקרה של ls -l
מדובר במשקל של הפריט)
- כל string שמפורד ברווח או בטאב הוא field חדש מבחינת sort
tony man
הוא רקורד עם שני שדות - טוני ומן
sort --key=number[option]
זה עוד סינטקס אפשרי
sort --key=2n
למשל כדי לחפש בשדה מספר שתיים עם האפשרות אן - כלומר סידור מספרי
- ומה אם הקובץ שלנו משתמש ב-field separator אחר? לא רווח או טאב? אז
sort
נותן לנו להגדיר מה הוא ה-field separator באינפוט:sort -t 'fieldseparator'
אם למשל זה קובץ /etc/passwd, שמופרד ע"י:
, נעשה:sort -t ':' -k 7 /etc/passwd
בדוגמה הזו אנחנו מחפשים בשדה השביעי שנוצר ע"י הפרדות של נקודותיים
multi-key sort¶
אפשר לסדר לפי מספר sort keys שונים ע"י שימוש ב--k
מספר פעמים.
בנוסף לזה, הערך של ה-sort key יכול להיות טווח של מספר שדות
sort --key=start,end
כדי להגדיר טווח
sort --key=1,3
כדי להתחיל בשדה הראשון ולסיים בשלישי. באמצע נעבור בשני.
sort -k 1,3
מניח שאפשר גם ככה
- בנוסף, אפשר להגיד ל-
sort
לפעול עם offset - כלומר להסתכל רק על תו מסוים ב-string שמרכיב את ה-field, או על טווח של תווים:sort -k 3.7
כדי לסדר לפי התו השביעי בשדה השלישיsort -k 3.7nbr -k 3.1nbr -k 3.4nbr distros.txt
כדי לעשות multi key sort על מספרי התווים המפורטים בשדה 3, כולם עם האפשרויות n, b ו-r; היעד שמסדרים הוא קובץ הטקסט.
shuf¶
- פקודה חמודה שמערבבת את סדר האותיות במילה - שימושי ליצרת ססמות למיניהן
shuf <target>
uniq¶
מנקה כפילויות מרשימות
ls /usr/bin | sort | uniq | less
כדי להדפיס רשימה של יוזר בין, לסדר אותה, להוריד כפילויות ולקרוא את האאוטפוט עם less
uniq -d
כדי לקבל רשימה של כפילויות במקום להסיר אותן
- חשוב לזכור ש-
uniq
עובד רק על רשימות שעברו sort, במובן שהוא מוחק כפילויות רק כשהן סמוכותלא ינקה כלום.a b c a b c
בלבד יחזיר לנו:a a b b c c
a b c
![[Pasted image 20250127184339.png|500]]
nl¶
- ממספר שורות, תוכנה ארכאית, עובדת כמו
cat -n
- מקבל מס' ארגומנטים
cat argument argument
כאשר כל ארגומנט יכול להיות קובץ או STDIN - מה שמייחד את
nl
הוא תמיכה ב-markup ארכאי (פרמוט 'תגים' שמתלבש על טקסט - marks it up) שפותח אפשרויות מספור נוספות - השפה בנויה על logical pages, שבנויים כמו HTML - יש להם header, body, footer
- בכל page כזה המספור יכול להתחיל מחדש, ויכול לקבל חוקיות שונה.
-
השפה מבדילה בין החלקים באמצעות המארקאפ המשונה הבא, שאנחנו מוסיפים לקובץ שעליו נפעיל את הפקודה
\:\:\:
- ההתחלה של ה-header\:\:
ההתחלה של ה-body\:
- ההתחלה של ה-footer- כל אחד צריך להופיע בשורה נפרדת משלו
- ברירת המחדל היא למספר את body בלבד! ולא למספר את החלקים האחרים.
-
יש כל מיני אפשרויות לפקודה שמשנות את אופן המספור ואת הפורמט שלו, מתוך ה-man: ![[Pasted image 20250130011912.png]]![[Pasted image 20250130011921.png]]
fold¶
- מפרמט טקסט לשורות באורך אחיד
- מקבלת אחד או יותר קבצי טקסט, ו/או STDIN
fold -w 12 file.txt
הולך לסדר את הקובץ כך שכל שורה תהיה בת 12 תווים, כולל רווחים ברירת המחדל היא 80 תוויםfold -s
כדי שהפקודה לא תשבור מילים אלא תפעיל את השבירה בסיום המילה הקרוב ביותר לאורך המוגדר
fmt¶
- תוכנת טרמינל לפרמוט פסקאות. יכולה לעשות כמו
fold
ועוד הרבה יותר -
השימוש הבסיסי:
fmt -w widthnumber fileorSTDIN
כדי לפרמט שורה לאורך של widthnumber תוויםכברירת מחדל,
fmt
משמר בפסקה שלנו: רווחים בין מילים, שורות ריקות, אינדנטציה (רווחים בהתחלה איי גס)fmt -cw
כדי למחוק אינדנטציות -
כשאנחנו עושים fold עם
fmt
, יש לו הרבה פרמטרים חכמים שהוא עובד לפיהם: הוא משתדל לשבור בדיוק על סוף המשפט, לא ישבור משפט ממש בהתחלה או ממש בסוף, משתדל לשבור בסימני פיסוק - ה-
fm
קורא את כל הקובץ לפני שהוא מחליט איך לקפל אותו
![[Pasted image 20250130012855.png|500]]
-
fmt -p
הוא הכי מעניין הוא בעצם אומר ל-fmt לפרמט רק שורות שמתחילות בסימן כלשהו, ולפרמט כך שהסימן יהיה בהתחלה של כל שורה באאוטפוטזה שימושי למשל כשרוצים לפרמט את ה-width של הערות בקוד בלבד - מתחילות ב-#
fmt -w 40 -p '# '' sourcefile.txt
wslpath¶
- ממיר path בפורמט ווינדוז ל-path בפורמט לינוקס ולהיפך
wslpath -w "path"
בשביל להמיר מלינוקס לווינדוזwslpath -u "path"
כדי להמיר מווינדוז ללינוקס לשים לב שהפלט שלwslpath
משמיט את הגרשיים! עבור "path/path" נקבל בחזרה path\path וכו' - שימושי למשל כדי להעביר פאת'ים ממערכת WSL ל-
explorer.exe
כדי להריץ קובץ עם ווינדוז
Escape Sequences & Characters¶
- מה שנקרא Backslash Escaped Characters הן בעצם אפשרויות פירמוט לטקסט שנעזרות ב-/ כדי לתת פקודות כמו לשבור שורה, ליצור טבלה וכו'. ![[Pasted image 20250118203325.png]]
With -e, escape sequences are interpreted:
echo -e "Line1\nLine2"
Output:
Line1
Line2
Adding tabs and alerts:
echo -e "Column1\tColumn2\tColumn3\a"
Output: Column1 Column2 Column3 (and an alert sound)
**לא כל טרמינל מקבל את האסקייפים!!! נניח אצלי זה לא עובד... זה תמיד עובד אבל ב-printf.
sleep 10; echo -e "Time's up\a"
טיימר פשוט עם התראה
הנה דוגמה לשימוש ב-conversion specifiers וב-escape characters כדי לפרמט דף HTML קצר עם printf
:
printf "<html>\n\t<head>\n\t\t<title>%s</title>\n\t</head>\n\t<body>\n\t\t<p>%s</p>\n\t</body>\n</html>\n" "Page Title" "Page Content" <html> <head> <title>Page Title</title> </head> <body> <p>Page Content</p> </body> </html>
חידוד חשוב: בד"כ, ה-backslash escaped characters משתמשות ב- כדי להגיד "כאן אתה לא פשוט מדפיס טקסט, אלא קורה משהו מיוחד" יש לנו גרסאות מיוחדות של escaped characters, למשל כשאנחנו [[לינוקס - כללי#shell prompt#|מגדירים את ה-shell prompt]], במקרים האלה ה-backslash אומר משהו כמו "כאן אתה לא סתם מדפיס (אפילו אם אנחנו בתוך גרשיים) אלא עושה פונקציה מיוחדת בהתאם לאות שאחרי ה-backslash"
IFS¶
-
משתנה סביבתי שמשפיע על איך שה-shell מפרידה בין מילים באינפוט שהיא מקבלת המשמעות היא Internal Field Separator, ותווים שהוא כולל נחשבים דילימיטרים להפרדה בין מילים. כברירת מחדל, הוא יכלול רווח, טאב ו-newline character
-
אפשר לשנות את הערך של
IFS
כחלק מסקריפט, בשביל לאפשר לפקודה/פונקציה שצריכה לקבל מס' ארגומנטים בצורה של מילים נפרדות (למשל:Read
) לקרוא אינפוט שמופרד באמצעים לא שגרתיים. למשל, עבור עיבוד של הקובץ/etc/passwd
, או של המשתנה$PATH
- שמפרידים ערכים באמצעות ":
" - נשתמש בשורה הבאה כדי לאפשר הפרדה של הערכים:IFS=":"
-
לרוב לא נרצה להוסיף דילימיטר מוזר באופן קבוע ולכן עדיף להגדיר את
IFS
נקודתית עבור פקודה מסוימת, באמצעות "variable before command" (ניתן להגדיר באופן זמני משתנה אחד עבור פקודה, מגדירים אותו באופן סטנדרטי באותה השורה עם הפקודה, לפניה. כתוב על זה בקובץ, ניתן לקרוא עוד.)
eval¶
- מבצעת פשוטה שהיא לכאורה די פשוטה:
- מקבלת רשימה של ארגומנטים
- מאחדת אותם ל-string אחד
-
מעבירה את הסטרינג כאאוטפוט ל-shell, ואומרת ל-shell להריץ את הסטרינג
-
כחלק משלב 2, הפקודה תבצע shell extensions (תרחיב פרמטרים, פ'אתים ו-tilde) בשונה מהרחבה רגילה, כאן היא תתבצע 'עד הסוף', כלומר עד שאין ערכים שניתן להרחיב, ולא פעם אחת בלבד (ה-default של ה-shell בשאר הזמן). ניתן להדגים את זה ככה:
str=111; cmd="echo $str" היא פקודה שתחזיר 111. אם נריץ אותה **ואז נעשה**
str=222, הערך של cmd יישאר
echo 111, וזה בגלל **שהמשתנה מוגדר פעם אחת** בהתאם לערך שהתרחב כשהוא הוגדר. אם היינו רוצים "לעכב" את ההתרחבות, כדי שידפיס **ערך עדכני** של str, **לא נוכל לעשות ככה:**
str=111; cmd='echo $str' כי אז האאוטפוט יהיה$str
... הבעיה היא שה-shell לא תרחיב את $str פעם נוספת לאחר שתקבל את הפקודהecho $str
. וזה בגלל שה-shell מרחיבה כל דבר פעם אחת פר 'תנועה' (שימוש), ולא יותר. על מנת להרחיב פרמטר, פאת' וכו' עד למיצוי ההרחבות האפשריות, נשתמש בתכונה הזו שלeval
- בין שלב 1 לשלב 2, היא מרחיבה עד הסוף.
עריכה וקריאה¶
לערוך טקסט עם nano¶
nano path/file
כל המקשים שמראים ^ ליד אות, זה אות+ctrl כדי לשמור: write out (לרוב O^) ואז exit (לרוב X^)
tee¶
יודע להציג טקסט ולכתוב אותו בו-זמנית
tail -f /path/to/rclone.log > /path/to/tail_output.log
היא פקודה שתכתוב את הטקסט ללוג בלבד בגלל שכל האאוטפוט מכוון לקובץ. כדי להציג את המעקב אחר ה-log ובו-זמנית לכתוב אותו לקובץ אחר, יש להשתמש ב-pipe עם tee באופן הבא:
tail -f /path/to/rclone.log | tee /path/to/tail_output.log
וכמובן אפשר סתם להציג טקסט מקבצים וכו' באמצעות tee
דיוק: tee יודעת לקבל סטנדרט אינפוט, ולהוציא אותו גם ל-standard output וגם לקובץ באותו זמן. היא שימושית כדי לחלץ דאטה מה-Pipeline שלנו תוך כדי שאנחנו ממשיכים לעבוד עליו.
למשל ls /usr/bin | tee ls.txt | grep
כדי לייצא לקובץ את האאוטפוט של ls אבל גם להעביר אותו ל-grep כדי לבצע סינון (שלא חל על הייצוא כי הוא בא לפני)
tail¶
לעומת cat שקורא את כל הקובץ בנקודה מסוימת בזמן, tail מראה לך את השורה (או כמה שורות) האחרונה בקובץ בזמן אמת (ממשיך לרוץ). שימושי כדי לעקוב אחרי logים, לרוב בשילוב עם grep כלשהו.
tail -f /path/to/rclone.log
כדי לעקוב אחרי קובץ
tail -n <number> path
כדי להראות את הנאמבר שורות האחרונות
fail -f -n 5 path
אפשר כמובן ביחד
head¶
head -n <number> path
מראה את ה-איקס שורות הראשונות של הקובץ בלבד
head -n 5 path
בשביל החמש הראשונות וכן הלאה
cat¶
צריך לזכור לא להשתמש ב-Cat כדי לתת אינפוט ל-Grep... אפשר לעשות Grep -x query path-to-file ולהריץ אותו ישר על קובץ... זו טעות של טירונים.
cat filename.txt
This will print the contents of filename.txt
to the terminal.
-
Concatenating Multiple Files
cat file1.txt file2.txt
This will display the contents of bothfile1.txt
andfile2.txt
one after the other. -
Redirecting Output to a New File
cat file1.txt file2.txt > combined.txt
This will combine the contents offile1.txt
andfile2.txt
and save them tocombined.txt
. Ifcombined.txt
already exists, it will be overwritten. -
Appending to a File
cat file1.txt >> file2.txt
This will append the contents offile1.txt
to the end offile2.txt
. -
Creating a File with cat
cat > newfile.txt
Then type the content of the file and pressCtrl+D
to save and exit. -
Displaying Line Numbers
cat -n filename.txt
This will display the contents offilename.txt
with line numbers at the beginning of each line. -
Suppressing Blank Lines The
-s
option suppresses repeated empty lines. If there are multiple blank lines in the file, it will only show one blank line:cat -s filename.txt
-
Displaying Non-Printable Characters The
-v
option allows you to display non-printable characters, which can be useful for debugging or viewing control characters:cat -v filename.txt
אפשר לחבר מלא קבצים עם glob, נניח cat movie.mpeg.0* > movie.mpeg
אם יש לנו מלא קבצים בשם movie.mpeg.001, 002, 003...
cat -A
כדי לראות גם non-printing characters
^text
אומר שזה tab
text $
מסמל את סוף השורה האמיתי, כאן יש לנו trailing spaces
שימושי לנושא של [[לינוקס - כללי#Text files#linefeed vs carriage return#|פורמט טקסט של DOS לעומת UNIX]]
less¶
less path
קורא את כל הקובץ במסך חדש. ניתן לניווט עם מקשי וים
יוצאים מ-less (ומהרבה דברים נוספים בטרמינל) בלחיצה על q
זה אחלה כדי לקרוא קובץ בלי לזהם את הטרמינל
less -n path
כדי להראות מספרי שורות
less -X path
כדי שלא ירד מהמסך ב-q
less +F path
כדי שיעקוב אחרי שינויים כמו tail -f!!!
- ב-less
יש [[מילון BASH#Vim#|vim search]] מובנה, לוחצים /
ומקלידים regex כלשהו. תומך ERE
Command | Action |
---|---|
Down arrow , Enter , e , or j |
Move forward one line. |
Up arrow ,y or k |
Move backward one line. |
Space bar or f |
Move Forward one page. |
b |
Move Backward one page. |
/pattern |
Search forward for matching patterns. |
?pattern |
Search backward for matching patterns. |
n |
Repeat previous search. |
N |
Repeat previous search in reverse direction. |
g |
Go to the first line in the file. |
Ng |
Go to the N-th line in the file. |
G |
Go to the last line in the file. |
p |
Go to the beginning of fthe ile. |
Np |
Go to N percent into file. |
h |
Display help. |
q |
Exit less . |
### awk | |
כמו grep ועוד כמה - זה לא חלק מ-bash. זה Unix shell tool שיכול להיות די שימושי לבאש. | |
כלי עוצמתי שמאפשר לנו לחפש, לחלץ ולערוך טקסט מתוך דאטה מסוימת. יודע לעשות | |
- Pattern Matching: Processes only the lines of input that match a given pattern. | |
- Field Extraction: Allows you to extract specific fields (columns) from a line of text. | |
- Text Transformation: Modifies text based on conditions or manipulations. | |
- Arithmetic Operations: Can perform calculations on numerical data. |
awk 'pattern {action}' file
Pattern = התנאי שבוחרים שורות לפי (לא חובה)
Action= פעולות לבצע על השורות שנבחרו
file = פאת' לדאטה שעובדים עליה
awk '{print $1, $3}' file.txt
להדפיס עמודות 1 ו-3
awk '/error/ {print $0}' file.txt
להדפיס רק מה שכתוב עליו error
`echo -e "10 20\n30 40" | awk '{print $1 + $2}'
מחבר את 10 ו-20, 30 ו-40
אפשר להשתמש ב-awk עם [[מילון BASH#pipe|pipe]] כדי לבצע אותו על האאוטפוט של הרישה
`zypper packages --orphaned | awk '/^i/{print $3}'
/^i/
: Matches lines that start with the letter i
.
{print $3}
: Prints the third column (package name).
This extracts the names of orphaned packages from the zypper
output.
Vim¶
אני קורא את 'the linux terminal 6th edition' והספר החליט שצריך ללמוד קצת על vi ועל vim - POSIX (הסטנדרט של הלינוקס טרמינל) דורש שיהיה vi - vi(m) keys - כיום רוב המערכות באות עם VIm שהוא שדרוג גדון/ל -Vi, והן מקשרות את הפקודה Vi ל-Vim באמצעות alias או sym link
לצאת ולהיכנס¶
כשאנחנו ב-Vim, אנחנו יכולים לכתוב פקודות. Enter
כדי לשגר את הפקודה.
:q
לצאת
:q!
לצאת אם הוא עושה לך בעיות
:wq
לצאת ולשמור
:w filename.txt
כדי לשמור בשם
ZZ
בנורמל מוד גם שומר ויוצא
vim pathtonewfile.txt
כדי להריץ עם קובץ חדש
(זו דווקא פקודת bash ולא פקודת vim)
פונקציות עריכה בסיסיות בסיסיות¶
- כשרק פותחים קובץ, אנחנו על
normal mode!
זה אומר שכל מקש הוא פקודה ושאנחנו נעשה מלא בלאגן אם נתחיל להקליד. - כדי לכתוב, צריך ללחוץ
i
ולעבור ל-INSERT MODE
ESC
כדי לצאת מאינסרט מוד- כדי לתת פקודה, אנחנו צריכים להיות על
normal mode
(כלומר לא על אינסרט) ואז ללחוץ:
(נקודותיים). - כדי לשמור את הקובץ עושים
:w
(כתיבה) - ב-vi רגיל קומנד מוד נקרא ex mod
-
קיצורים ב-
normal mode
: ![[Pasted image 20250125010136.png]] -
הסיבה שזה עם האותיות זה כי פעם לא תמיד היו לך חצים במקלדת
-
אפשר להוסיף מספר לפני כמעט כל פקודה כדי להריץ אותה n פעמים ברצף, למשל
6l
יקח אותנו ימינה שישה צעדים -
ב-
normal mode
, לוחציםu
בשביל לעשות undo לשינוי האחרון שביצענו (קונטרול זי) - הספר טוען שבאמצעות
i
(כניסה לאינסרט מוד) אי אפשר ללכת לסוף השורה כדי לעשות append לטקסט. אני רואה שאצלי כן אפשר... אבל בכל אופן אפשר ללחוץA
(גדולה) כדי ללכת לסוף של שורה ולעשות append לטקסט באינסרט מוד. ואפשר לעשותa
קטנה כדי לעשות append לטקסט רווח אחד אחרי איפה שעמדנו במקור. - אפשר להשתמש ב-
o
אוO
(גדולה/קטנה) כדי לפתוח שורה חדשה - קטנה זה מתחת לשורה הנוכחית, וגדולה זה מעל. - אפשר למחוק באמצעות
x
, אוnumber x
כמו שלמדנו, כדי למחוק number תווים - עוד פקודת מחיקה היא
d
, גם לפניה אפשר לשים מספר, ואחריה תמיד תבוא אות נוספת שתגדיר חוקיות למחיקה
![[Pasted image 20250125011619.png|500]]
- כשאנחנו משתמשים ב-
d
אנחנו למעשה עושים cut, כלומר שהמידע שמחקנו נשמר ב-paste buffer (קליפבורד). - אפשר להשתמש ב-
p
כדי להדביק אחרי העכבר וב-P
גדולה כדי להדביק "רגיל" (אחרי העכבר). -
אפשר להשתמש גם ב-
y
כדי לעשות "yank" (קופי, במקום הפייסט של d) ![[Pasted image 20250125012008.png|500]] -
משום מה, אם עושים
p
כשנמצאים עלG
(תחילת השורה האחרונה) זה מדביק בשורה חדשה למטה... (זה בעצם לא משנה איפה נמצאים, להעתיק שורה מדביק שורה חדשה) -
אפשר לחבר שורות - אבל לא באופן שאנחנו מכירים. Vim לוקח את השורות שלו ברצינות ואי אפשר למחוק את התו הראשון בשורה כדי לחבר אותה עם הקודמת (כמו ברוב עורכי הטקסט). במקום, צריך להשתמש ב-
J
גדולה. - אם אנחנו על Line 3 ועושים
J
, אנחנו נחבר אליה את זו שמתחתיה. כלומר, נקבלLine 3 Line 4
בשורה אחת
חיפוש והחלפה¶
בשורה ספציפית:
- אפשר לעשות f
כדי לחפש אות בתוך השורה הנוכחית ולקפוץ אליה (נגיד f a
כדי לקפוץ לאות a)
- אפשר לבצע את אותה קפיצה שוב באמצעות ;
בכל הקובץ
- אפשר לחפש string (ולא רק אות בודדה) בכל השורות בקובץ באמצעות /
ואז ה-string
- זה כבר החיפוש שאנחנו מכירים מ-vimium ומעוד תוכנות
- אפשר לבצע את אותה קפיצה שוב באמצעות n
- אפשר להשתמש ב-regexp בחיפוש הזה - תומך BRE
find & replace על כל הקובץ
- את זה עושים באמצעות command mode
(לוחצים :
ומקלידים)
![[Pasted image 20250125013045.png|500]]
- אפשר gc בסוף במקום g כדי שיבקש מאיתנו confirmations. שולטים בהם ככה:
![[Pasted image 20250125013205.png]]
פעולות על קבצים מרובים¶
vi(m) file1 file2 file3
כדי לפתוח מספר קבצים
אנחנו נראה רק את הקובץ הראשון
:bn
כדי לעבור לקובץ הבא
:bp
כדי לחזור לקודם
- וים לא מרשה לעבור קובץ אם לא שמרנו קודם. כדי להתעלם ולעבור בכל זאת, עושים את הפקודה עם סימן קריאה בסוף, למשל :bn!
:buffers
כדי להציג רשימת קבצים בתחתית
:buffer filenumber
כדי לעבור לקובץ שעל באפר במספר שאנחנו מציינים
(הפקודות bn ו-bp הן קיצורים ל-buffer next ו-buffer previous)
:e filename
כדי להוסיף קובץ לאחר שכבר פתחנו אחד או כמה
(את שם הקובץ או את ה-Path המלא אליו? מה ה-Path של וים?)
- אפשר לעשות את כל הפעולות של yank ושל d "בין קבצים", כלומר להעתיק, לעבור קובץ, להדביק וכו'
- אפשר להשתמש ב-
:r filename
כדי להכניס מתחת ל-cursor שלנו את כל התוכן של filename (שוב, האם זה שם או path???)
clear¶
מנקה את הטרמינל מאאוטפוטים קודמים
concat¶
מחבר רשימות יחדיו
concat foo.txt bar.txt > foobar.txt
יש לי man concat בטרמינל אבל גם ג'יפיטי וגם מייקרוסופט מתעקשים שאין פקודה כזו... אפשר לחבר רשימות גם עם cat...
sed¶
לשים לב שב-sed כמו ב-grep, כל ה-expression (ארגומנט, וואטאבר) שניתן לפקודה עטוף ב-
''
אלא אם משתמשים במשתנים! אם אנחנו צריכים ש-$var'
יתרחב לנו ב-query, נעטוף הכל דווקא בגרשיים כפולות"
.
המשמעות היא Stream EDitor - יודע לקחת אאוטפוט של פקודות ולעשות עליו פעולות, קצת דומה ל-awk - תוכנה מורכבת שנכתבו עליה ספרים שלמים... - היא יודעת לקבל STDIN או שם של קובץ script עם פקודות בתוכו. בעצם כל מה שמהווה פלט של פקודה. - היא מחילה את הכלל שנותנים לה על כל שורה בפלט בנפרד ![[Pasted image 20250119193916.png]]
- התוכנה
sed
יודעת מה הם המשתנים שלה, ולכן מאפשרת להשתמש בכל תו כדלימיטר! נהוג להשתמש ב-/
אבל זה יכול להיות כל תו אחר כל עוד האפשרויות מפורמטות נכון. - אפשר לתת לכל פקודה של
sed
"כתובת" שמפרטת על איזה שורה לבצע את הפעולה. ברירת המחדל אם לא מציינים היא על כל השורות. - האפשרות בסוף (איפה שלרוב יש g) קובעת על איזה חלק של השורה נפעל. g אומר על כל התאמה. ברירת המחדל היא רק על ההתאמה הראשונה.
sed 1s/front/back
ישנה את פרונט לבק רק בשורה הראשונה של האאוטפוט -
יש די הרבה דרכים מעניינות לפרמט את הכתובת: ![[Pasted image 20250128033203.png|500]]
-
אם משתמשים ב-
-p
כדי פשוט להדפיס טווח מסוים, חייב להשתמש ב--n
כדי לבטל את ההדפסה כברירת-מחדל של כל השורות באאוטפוט -
פקודות עריכה בסיסיות ל-
sed
: ![[Pasted image 20250128033529.png|500]]
שימוש נכון ב-sed s
¶
- הפורמט הבסיסי של
sed s
הואs/regexp/replacement/
-
הפקודה
sed s/b/B
תחליף רק את ה-b הקטנה הראשונה בכל שורה אם אנחנו רוצים להחליף כל הופעה של regex ב-replacement, נשתמש ב-/g
, כך:sed s/b/B/g
-
שימושי מאוד עבור
sed s
- שימוש ב-[[מחברות קוד/Bash&Linux 🐧/מילון BASH#regular expressions (regexp)#subexpressions, backreference#| regexp subexpressions]] -
יש כלים מורכבים יותר מ-
sed
, שהם כבר ממש שפות תכנות עצמאיות: מדובר ב-[[מחברות קוד/Bash&Linux 🐧/מילון BASH#awk#|awk]] וב-perl
פרל היא מאוד רחבה ומשמשת גם לכתיבה ב-web ו-awk חזקה מאוד במניפולציה של tabular data
עוד אפשרויות חשובות¶
-
יש
sed -i
(דגל i, לא לבלבל עם הפעולהi/...
) - זה אומר ל-sed
לבצע את כל השינויים על הקובץ שסיפקנו לו, במקום לייצא לאאוטפוט -
אפשר לתת ל-
sed
כמה פעולות יחד, מופרדות ב-;
sed -i 's/lazy/laxy/; s/jumps/jimps/' foo.txt
זה יגיד לסד לבצע את שתי ההחלפות הבאות על הקובץ פו, ולשמור אותן ישר על הקובץ
wc¶
wc pathtofile
כדי לראות כמה שורות, מילים ובייטים יש בקובץ
wc -l
כדי לספור שורות בלבד (טוב כדי לדעת כמה פריטים יש ברשימה)
command | wc -l
זו דרך פופולרית לספור פרטים באאוטפוט של פקודה
גלובים:¶
-
? - אומר "תו לא ידוע", זה קצת מבלבל אבל בגדול זה placeholder.
אם נגיד אני רוצה לפרט את כל הקבצים בתיקיה שהם txt ושיש להם 4 אותיות בשם, אני עושה ls *.txt???? אפשר גם לדעת חלק מהאותיות: ls system*????.txt ימצא את כל מה שיש לו 4 אותיות ומתחיל בsystem (והוא מסמך טקסט). -
כוכבית * - המשמעות היא any string ואפשר לשחק עם זה בכל מיני דרכים ![[Pasted image 20250105135032.png]]
![[Pasted image 20250124005850.png]]
![[Pasted image 20250124005956.png]]
קבצים חבויים:
לעשות
echo .*
יתן לנו את כל הקבצים החבויים, אבל גם את התיקיה הנוכחית ואת התיקיית אם שלה, שהן.
ו-..
. כדי לקבל תוצאה בלעדיהן, צריך לעשותecho .[!.]*
, שזו תוצאה שמתרחבת לכל קובץ שמתחיל בנקודה ולאחריו בא לפחות תו אחד.ls -A
נותן לנו את התוצאה הנכונה בקלות
cut¶
- פקודה שיודעת לחלץ חלק משורת טקסט ולהוציא את האאוטפוט ל-STDOUT
- יכולה לקבל כמה קבצים או STDIN ![[Pasted image 20250127185350.png|500]]
cut -f fieldnumber path\to\file
כדי לחתוך שדה מסוים בטבלה, שמופרד ברווחים או ב-^
טאבים
cut -c rangestart-rangeend
כדי לחתוך את התווים בריינג' הזה של כל שורה
cut -c 7-10
כדי לחתוך את התווים השביעי עד העשירי בכל שורה
(אם מדובר בתאריכים שרשומים ככה MM/DD/YYYY - מדובר בשנה בלבד בכל שורה)
cut -c9-
כדי לחתוך מהאות התשיעית עד סוף השורה בכל שורה
- אפשר להקדים פקודת -f
לקאט (בחירת שדה) בפקודת -d
כדי לבחור delimiter שאינו רווח או טאב (delimiter הוא התו שמסמל מעבר שדה)
cut -d ':' -f 1 /etc/passwd
כדי לחלץ את השדה הראשון של כל שורה בקובץ
(הקובץ מפורמט עם :
בין שדה לשדה)
expand¶
- אם יש לנו טקסט שמפורמט עם tabs (
field1^field2^field3$
) - אנחנו יכולים להפעיל עליו
cut
באמצעות שדות בלבדcut -f
- כדי להפעיל
cut -c
במקום - אנחנו צריכים להחליף כל non-printable character מהסוג של tab^
ברווח - כדי ליצור הפרדה של fields שניתן לספור כתווים. expand sourcefile
כדי להפוך טקסט עם טאבים לטקסט עם רווחים במקום- הפקודה
expand
מקבלת גם STDIN - יש פקודה מקבילה
unexpand
שעושה את ההיפך - הופכת רווחים לטאבים - שתיהן שייכות ל
-GNU coreutils
paste¶
- תוכנת טרמינל שמקבלת כאינפוט: ריבוי אגרומנטים של file paths ו/או STDIN
- ומוציאה כאאוטפוט: חיבור של הטבלאות שבהם.
- לא מדובר ב-append לכל טבלה ככה שהן מופיעות אחת אחרי השניה, אלא בהוספה של עמודות כך שטבלה אחת תכיל את השדות של שתי הטבלאות (או יותר)
- למשל טבלה עם עמודות abc וערכים בכל עמודה; וטבלה עם עמודות abc וערכים בכל עמודה; תהפוך לטבלה אחת עם abcdef עמודות בהתאם
paste filepath filepath
צריך לנתב לקובץ או שזה יוצא לטרמינל
join¶
- דומה ל-
paste
במובן שהוא מוסיף עמודות לקבצי טקסט - אבל שונה באופן שהוא פועל:
join
קשור ל-relational databases, שהם מבנים בהם מספר טבלאות עם shared key משולבות כדי להגיע לתוצאה הרצויה - אז בגדול
join
מחברת דאטה ממגוון קבצים לפי shared key field - הסבר: כדי שנוכל לחבר שתי טבלאות במגוון דרכים, צריך שיהיה להן שדה אחד שהוא זהה, במובן שהוא מחזיק ערכים מאותו הסוג והמפתח. לא חייב שכל הערכים יהיו קיימים בשתיהן, אבל נניח שבשתיהן יש שדה NUMBER ובשתיהן יש שורה שהערך שלה עבור NUMBER הוא 1 - אז מבחינת ה-relational database מדובר בשורות 'תואמות'.
- אז נניח דוגמה כזו: בטבלה אחת יש מס' לקוח, שם פרטי ושם משפחה; בטבלה שניה יש מס' הזמנה, מס' לקוח, כתובת רחוב, פרטי הזמנה, מועד הזמנה; על ידי התאמת הערך המשותף "מס' לקוח", אנחנו יכולים לשלב את שתי הטבלאות, כדי ליצור למשל טבלה שמכילה: שם פרטי, שם משפחה, פרטי הזמנה, מועד הזמנה.
- כדי ש-
join
תעבוד כהלכה - הטבלה צריכה להיות sorted לפי ה-shared key fieldjoin table1.txt table2.txt
כאשר לטבלאות יש שדה משותף, יוצר חיבור של כל השדות לפי השדה המשותף, - הפקודה
join
רק מחברת את כל הערכים, ואז אפשר לגזור מההאוטפוט שלה טבלה חדשה עם ערכים ספציפיים בלבד - חשוב לדעת: הפקודה
join
מתייחסת ל-whitespace כ-delimiter באינפוט, אבל מדפיסה באאוטפוט את הדילימיטר כ-single space. ב-man join
יש הסבר איך לציין דלימיטר אחר לשדות.
tac¶
tac filepath1 filepath2...
- מחזירה פלט כמו של
cat
אבל ליטרלי הפוך - במובן שהשורה האחרונה תודפס ראשונה, וכן הלאה
- שימושי כדי להפוך קבצי log - כדי שהשורה העדכנית ביותר שלהם תופיע בראש הרשימה
rev¶
- מקבלת string והופכת את סדר התווים שלו
- יכולה לקבל קובץ או STDIN
- למה לעזאזל זה שימושי? למשל כדי להסיר נקודות ממשפטים בקובץ. תחשוב על זה: אין לדעת אחרי כמה תווים תופיע הנקודה בכל שורה. אבל אנחנו יכולים לדעת שהנקודה היא התו הראשון בכל שורה אם נהפוך את כל התווים. אז כדי להעיף את הנקודות נעשה rev לקובץ, נעשה
cut -c 1
כדי להעתיק כל שורה החל מהתו השני לקובץ חדש, ואז נעשה rev לקובץ החדש כדי לחזור לסדר התווים הנכון. - אפשר לוותר על קבצים ולעשות את כל התהליך הזה ב-shell stream, בפייפ די פשוט:
rev | cut -c number | rev
comm¶
- פקודה שמשווה בין קבצי טקסט, מראה שורות שיש להם במשותף ושורות ייחודיות לכל קובץ
comm file1 file2
מחזירה אאוטפוט עם שלושה שדות: a זה שורות שייחודיות לקובץ הראשון b זה שורות שייחודיות לקובץ השני c זה שורות משותפות אפשר לעשותcomm -n
ולציין מספרים: 1, 2 ו-3 בשביל abc בהתאמה כל מספר שציינו "מושתק" - כלומר מושמט מהטבלה של האאוטפוטcomm -12
כדי להדפיס את c בלבדcomm -2
כדי להדפיס את a ואת c בלבד וכו'
diff¶
- בדומה ל-
comm
', משווה בין אוסף של קבצים. אבל מדובר בכלי מורכב יותר: הוא יודע לבדוק source trees - כלומר להשוות folder structures על הקבצים שבהם; הוא יודע לשמור diff file, ידוע גם כ-patch, שפקודות כמוpatch
יכולות להשתמש במידע שבו כדי להמיר קובץ מגרסה אחת לאחרת שלו.
diff file1 file2...
כדי להשוות קבצים -
האאוטפוט קצת מיוחד: הוא בעצם מסביר איך להגיע מהקובץ הראשון לקובץ השני. השינויים בין הקבצים מחולקים לקבוצות של change commands שהמבנה שלהן הוא
range operation range
. כלומר, איזה טווח בקובץ 1 צריך לעבור איזה שינוי כדי להפוך לאיזה טווח בקובץ 2. מפרמטים ככה: ![[Pasted image 20250128025123.png|500]] -
כשאומרים לנו לתת
range
, הכוונה היא לרשימה מופרדת בפסיק של שורת ההתחלה ושורת הסיום. נניח1,3
בשביל טווח שהוא משורה 1 עד שורה 3 - הפורמט הזה הוא סטנדרט ה-POSIX, אבל הוא לא הכי נוח, לכן יש עוד אפשרויות:
diff -c file1 file2...
יציג את ההבדלים בפורמט context - האאוטפוט של context ימנה את הקבצים המשווים, ואז יציג כל קובץ עם ribbon אחר, כאשר כל פריט באאוטפוט יהיה ציון של השורות הרלוונטיות מוקפות ב-ribbon של הקובץ המתאים, עם שינויים מפורטים בפורמט הבא: ![[Pasted image 20250128025517.png|500]]
diff -u file1 file2...
יציג את הדברים בפורמט unified
- האאוטפוט דומה לשל context אבל יותר מתומצת: הוא מונה את הקבצים, ואז בכל פריט עוטף בשטרודלים @
את טווחי השורות הרלוונטיים לכל הבדל בין קובץ 1 לקובץ 2, עם סימון של מינוס או פלוס כדי להגיד איפה השינוי נוסף ואיפה הוא נגרע.
- מתחת, נקבל פירוט של השינוי.
![[Pasted image 20250128025757.png|500]]
patch¶
- משמשת כדי לקחת קובץ אאוטפוט של
diff
ולהשתמש במידע שבו כדי להמיר קובץ מגרסה ישנה לגרסה חדשה יותר - מקרה שימוש לדוגמה: כשמישהו כותב עדכון לקרנל של לינוקס, זה לא הגיוני שישלח למפתחים האחרים את כל הקבצים של הקרנל בגרסה שהוא יצר. הם עובדים על אותו בסיס. אז הוא שולח להם diff file של השינוי בין האפסטרים של הקרנל לגרסה המעודכנת שהוא כתב, ומפתחים אחרים יכולים להריץ אותו עם פקודת
patch
כדי לעדכן את הקרנל שלהם לגרסה שהבחור כתב. - יש המלצה רשמית של GNU לגבי איך להכין קובץ diff במטרה לעדכן איתו קובץ:
diff -Naur old_file new_file > diff_file
הקבצים יכולים גם להיות תיקיות. - כדי להריץ את העדכון, אנחנו פשוט עושים
patch < diff_file
(הוא צריך שיהיה לו את הקבצים כפאת'ים, או להיות באותה תיקיה עם הקבצים ולקבל את השמות שלהם) - גם לא צריך לכתוב לו איך יקרא הקובץ המעודכן - יש לו את השמות מתועדים ב-diff file
tr¶
- נועד לבצע טרנסליטרציה בקבצים - כלומר, להחליף סוג מסוים של תווים בסוג אחר של תווים.
- נניח, להעביר את כל האותיות מ-lowecase ל-uppercase
tr find-range replace-range
tr a-z A-Z
כדי להחליף כל אות קטנה בגדולה - מקבל STDIN ומחזיר STDOUT
- יכול לקבל בערכים שלו: או רשימה בלי דלימיטר
ABCD
; או טווחA-Z
; או עם POSIX CHARACTER CLASS[ :upper: ]
- לזכור לגבי [[מחברות קוד/Bash&Linux 🐧/מילון BASH#regular expressions (regexp)#Character Classes#|character classes וכל החרא של POSIX|]]
tr find-range replace-range < source-file > destination-file
אפשר לציין קובץ לחפש בו וקובץ לייצא אליו אאוטפוט
tr -d find-range
כדי פשוט למחוק טווח כלשהו
tr -d '\r' < dos_file > unix_file
לדוגמה - מוחק carriage return
מקבצים שמפורמטים עבור DOS. (ה-/r הוא ה-carriage return, אנחנו משתמשים כאן בערך אבסולוטי ולא בטווח - אבל זה נופל באפשרות הראשונה לאינפוט, כלומר רשימה - תחמנו איבר עם גרשיים).
- דוגמה מעניינת: יש שיטה ל-"הצפנה" של טקסט בשם ROTI13: העיקרון שלה היא לקחת כל תו ולהזיז אותו 13 מקומות למעלה; מאחר שיש 26 אותיות באלף-בית, לבצע ROTI13 בפעם השניה פשוט יחזיר את הטקסט לצורה המקורית.
- אפשר לבצע ROTI13 עם
tr
באופן הבא: tr a-zA-Z n-za-mN-ZA-M
- בעצם אמרנו ל-
tr
לקחת כל תו בטווח של a-z או של A-Z ולהחליף אותו בטווח n-z (אן היא האות ה-13) או a-m (החצי הראשון של הטווח, לאחר שביצענו את הקפיצה) או N-Z ו-A-M (הצורות הגדולות) - אני יכול להבין איך
tr
מבין את "ההיפוך" של המספור באמצע הרשימה - ברגע שנגמרים לו הטווחים להצמיד ל-a-z באמצעות n-z הוא עובר ל-a-m. - אבל איך הוא יודע לבד להחליף לפי הקייס?
- אני מניח שזה לפי מתי שנגמרים לו הערכים - כלומר להחליף את a-z דרש ממנו את כל הערכים של n-z ו-a-m, ואז הוא עובר ל-N-Z ו-A-M וממצה אותם רק ברגע שהוא החליף את הערכים של A-Z
tr -s find-value
יכול למחוק מופעים חוזרים של הערך שהוא מקבל
נקרא -s
כי הוא עושה "squeeze"
rs -s ab
למשל ימחק כל מופע חוזר של אייבי, עד שישאר מקסימום אחר
aaabbbccc
יחזיר abccc
- כדי שהניקוי יעבוד, המופעים של הפרטים ברשימה (ה-value הוא רשימה בדוגמה הזו) חייבים להיות סמוכים.
aspell¶
- תוכנה אינטרקטיבית לבדיקת איות
- קדמה לה
ispell
שיכולה להחליף אותה לא רע - בד"כ היא משמשת תוכנות אחרות (זה ה-spellchecker של המערכת), אבל ניתנת גם לשימוש עצמאי בקומנד ליין
-
יודעת לבדוק טקסט, HTML, סי ו-CPP ועוד
aspell check textfile
-
התוכנה כאמור אינטרקטיבית: תסמן לנו טעויות, תתן הצעות לתיקון, ותתן אפשרויות לפעולה בעקבות ההצעות
-
כברירת מחדל,
aspell
יוצר קובץ גיבוי לאחר השמירה, עם הגרסה המקורית ששלחנו לו. הוא קורא לקובץ textfile.bak ניתן להגיד לו שלא ליצור גיבוי עם הדגל--dont-backup
-
אם אנחנו רוצים שיתעלם מ-HTML TAGS (שיסומנו לרוב כשגיאות), נעשה
aspell -H
- ה-
aspell
מתעלם אוטומטית מכתובות מייל ומ-URLים. אפשר לשנות את זה באפשרויות שלו - נחסוך את זה מפה, אפשר לחפש ב-man aspell
split¶
csplit¶
sdiff¶
groff¶
קשור [[מחברות קוד/Bash&Linux 🐧/לינוקס - כללי#Document Formatting Systems|לפרמוט טקסט באמצעות roff]]
- ה-groff
היא האימפלמנטציה של פרמוט markup מסוג roff
שקיימת ברוב המערכות כיום
- היא אוספת מגוון אפשרויות של roff
ל-macro packages שמאפשרות שימוש קל בהן
mandoc היא מאקרו-פקג' שאחראית על הפרמוט של דפי man
אנחנו יכולים לדמות פקודת man command
על ידי הצבעה על ה-manpage file הרלוונטי ושימוש בפקודת groff עם mandoc, ככה:
zcat /usr/share/man/man1/ls.1.gz | groff -mandoc -T ascii
החלק של -T ascii קובע את ה-output driver של הפקודה. אנחנו רוצים ASCII Characters
ברירת המחדל היא PostScript
החלק של zcat נועד פשוט לקבל כא#אוטפוט לפייפ את התוכן של ה-gz file
tbl¶
- ה-
tbl
היא תוכנה נוספת שגורמת ל-groff לפרמט טבלאות לפי שפת ה-markup שלtbl
groff -t
כדי להפעיל אותה- להבדיל מ-
groff -T driveroutputformat
- היא פועלת על קבצי .tbl
-
אפשר לתאר איפה מתחילה ונגמרת הטבלה ואיך יוצג כל חלק בה - לעשות גוגל אם צריך...
-
אם נשתמש ב-PostScript output נוכל לראות את הטבלה הרבה יותר יפה מאשר בטרמינל!
bc¶
-
קיצור של base calculator - התוכנה יודעת להמיר מספרים (סטרינג של ספרות ללא רווחים) מבסיסים שונים. בסיס הוא כמות הספרות שקיימות בשיטת הספירה שלנו, כלומר, הספרות שמהן ניתן להרכיב מספרים, כולל 0. בסיס 2 הוא ספירה בינארית: יש לנו 0 ו-1, לכן 0 תהיה הספרה הראשונה, ו-1 תהיה הספרה השניה. לא לשכוח שהמחשבון ממיר מספרים ולא ספרות - 111 לא יהפוך ל-222 (המרה של כל אחד בנפרד), אלא ל-7, מאחר ש-111 הוא הצירוף השביעי שניתן להרכיב מספרות בינאריות, כשמתחילים מ-0 וממשיכים ל-1 ואז ל-01 ואז ל-11 וכן הלאה.
file_octal=$(echo "ibase=2; obase=8; $file_binary" | bc)
המרה של מספר בינארי למספר אוקטאליbc ibase=num obsase=num target
כאשר i אומר input (או STDIN או משהו שנציין ב-targer), ו-o אומר output (הבסיס של תוצאת ההמרה) -
אפשר להריץ את bc כמחשבון אינטרקטיבי באמצעות הדגל
-q
אחרי שמריצים עם קיו, אפשר לעשות למשל2 + 2
ולקבל את התשובהquit
כדי לצאת מהמחשבון
bc scripts:
- התוכנה bc
למעשה פועלת על קבצים או אינפוטים שכתובים בשפת הסקריפטים שלה, שהיא C-like
כשאנחנו כותבים לה את הסינטקס הבסיסי של obase, ibase וכו' אנחנו למעשה כותבים בשפה הזו.
- נשתמש בדגל
-q
כדי להשתיק את ההודעה על זכויות היוצרים באאוטפוט -
את הסקריפט אפשר לתת ל-bc גם בצורה של redirection
<
או בצורה של here string>>>
-
יסודות השפה: לקובץ הסקריפט נקרא name.bc
כדי לפתוח הערה עושים
/*
היא יכולה להמשיך כמה שורות, וסוגרים אותה ידנית ב:
*/
(זה כמו ב-C)
כדי לבצע חישובים פשוט כותבים a + b וכך הלאה - bc תחזיר את התשובה
טוב, אלה מעט מאוד יסודות. הספר ציין באקראי גם שיש פקודה של
scale = num
שקובעת כמה אפסים יהיו לנו לפני הנקודה (האם נראה 1 או 01 או 001 וכן הלאה). כדאי לציין כאן שהאופרטורים המתמטיים נכתבים שונה מב-shell ויותר דומה לשפת C - אם רוצים אי פעם לעשות חישובים מורכבים יחסית, לבדוק באינטרנט איך עובדת השפה של bc...
פקודות, משתנים, קונפיגורציה¶
$() פלט כמשתנה¶
command $()
מבצע את הפקודה על משתנה 'ספונטני' שהוא האאוטפוט של הפקודה בסוגריים
למשל sudo zypper remove $(zypper packages --orphaned | awk '/^i/{print $3}')
כדי לעשות remove לתוצאה של: "זיפר, תפרט איזה חבילות לא-דרושות יש | awk, תלך לכל השורות שמתחילות ב-i (installed), ותדפיס את עמודה 3" (התוצאה תהיה כל הטקסט בכל עמודה 3 עבור כל שורה שמתחילה ב-i, ואז זיפר יבצע על הרשימה הזו remove)
.bashrc¶
נמצא ב-
~/.bashrc
כדי להוסיף PATH ל-$PATH מוסיפים לקובץ:
export PATH="Path/To/Path:$PATH"
כדי לטעון מחדש את ההגדרות עושים: reload ~/.bashrc
(אפשר להריץ קבצים מתיקיות שנמצאות ב-path, ע"י כתיבת השם שלהם)
variables¶
global variables¶
-
משתנים שמשותפים לכל התוכנה/סקריפט, משתנים "רגילים"
-
לבאש לא אכפת איזה סוג של דאטה יושב במשתנה שלנו, הוא מתייחס להכל כ-string בהמשך לזה, הערך של המשתנה יכול לכלול כל ביטוי שהוא טקסט, או שיכול להתרחב מתוך טקסט (כל expansion יכולה להגדיר משתנה, כמובן...)
x=$(command)
מגדיר לנו משתנה לפי התוצאה של פקודה (זה שימושי גם לעוד דברים, לא רק להגדרת משתנה)כדי לבצע חישובים על משתנה נשתמש במה שהכרנו כ-[[מילון BASH#Arithmetic expansion|Aritmethic Expansion]], ככה:
x=$((5 * 7))
בנוסף אפשר להשתמש ב-Escape sequences כמו
\n
בשביל newline ו-\t
בשביל טאב
צריך להוציא את ההסבר המלא מ-GPT בגדול, לא צריך להכריז על משתנה. עושים myvar = "..." ואז כדי להשתמש בערך של myvar, עושים $myvar
-
הטרמינל מאוד chill לגבי משתנים, אם עשינו $var ולא הגדרנו את var, הוא פשוט יוצר את var ללא ערך! כלומר שלעשות
echo $var
לא יחזיר שגיאה, אלא פשוט יחזיר אאוטפוט ריק. -
יש חוקים לגבי השם של משתנה: הוא יכול לכלול רק אותיות, מספרים וקו תחתון (אי אפשר להשתמש בדאש במקום...) האות הראשונה חייבת להיות אות או קו תחתון, כלומר, לא מספר. אסור להשתמש ברווחים!!! או בסימני פיסוק כמובן
-
בגדול, בתכנות, יש הבדל בין סוגי משתנים: constant הוא משתנה שמחזיק ערך קבוע, variable אמיתי הוא משתנה שמחזיק ערך שמשתנה לפעמים גם כאן, באש הוא צ'יל ולא מבקש מאיתנו להגדיר. הקונבנציה היא להשתמש בשמות עם אותיות uppercase בשביל קבועים, ולהשתמש בשמות עם אותיות lowercase עבור משתנים אמיתיים
-
משתנים יכולים להכיל זה את זה!
TITLE="text $HOSTNAME"
-
יש לנו אופציה לעטוף שם של משתנה בקוד בסוגריים מסולסלות כדי לנתק אותו מהקונטקסט שלו אם אנחנו רוצים לקרוא לקובץ בשם של המשתנה x עם הספרה 1 בסוף, כלומר x1, לא נוכל לעשות
touch $x1
, זה ידפיס לנו את המשתנה x1 שהוא ריק/לא קיים; נעשה במקוםtouch ${x}1
וזה יעבוד אז לשים לב שהדולר בא לפני הסוגריים - כמו תמיד עם משתנים, כדי להגיד "הערך של..."
local variables, local¶
- הם משתנים שתקפים רק ל-Shell function מסוימת בקוד, ולא לכל התוכנה. זה נוח כדי ליצור הפרדה ולהימנע מחפיפה בשמות.
-
הפקודה
local
מגדירה אותם, ככה:foo=1 funct_1 () { local foo=2 echo "$foo" } funct_1 echo $foo
-
בדוגמה הזו, האאוטפוט של
funct1
יהיה 2, בעוד שהאאוטפוט של ה-echo
בשורה האחרונה יהיה 1 - עוד [[Bash Scripting#shell functions|בקובץ הסקריפטינג]]
variable before command¶
-
ה-shell מאפשר לנו להגדיר משתנה אחד לפני כל פקודה, כדי ליצור עבורה סביבה מותאמת, שבה למשתנה יש ערך חדש. הדוגמה הקלסית היא
IFS
- לפעמים נרצה שיפריד מילים באמצעות:
, או משהו אקזוטי אחר. לא נרצה שיתייחס ל-:
כדילימיטר בין פקודות באופן שוטף, ולכן נעשה ככה:IFS=":" read P1 P2 P3 P4 <<< "/etc/psswd"
(עושים לקובץ שמפריד ערכים עם:
רידיירקט לתוךread
כדי שתקבל ממנו ארבעה ערכים.)בגלל שהגדרת המשתנה קורית באותה שורה עם הפקודה read (באופן שלא היה תקין עם כל פקודה אחרת: הן הרי אמורות להיות מופרדות בשורה, או מחברות עם אופרטור) -- ה-shell יודע שזו הגדרה זמנית שלו, ולאחר הקריאה של הקובץ, IFS יחזור לערך הקודם שלו.
-
הצורה הכללית:
VAR="VALUE" <command> <command-arguments/options>
declare¶
-
אמנם לא חייב, אבל אפשר להכריז על משתנים כדי להגדיר אותם קצת (בקושי משתמשים בזה)
declare -r VAR=value
יעשה שהמשתנה שלנו הוא read only, ואז הוא בעצם constant... (קבוע)declare -i
יעשה את המשתנה שלנו integer (מספר) בלבד -
הפקודות declare -u ו-declare -l משמשות ל-Case Conversion כלומר, כדי להמיר אותיות ב-Uppercase ל-Lowercase ולהיפך. אם 'הצגנו' משתנה באמצעות אחת מהפקודות האלה, לא משנה איזה ערך הוא יקבל, הוא ינרמל אותו לאפרקייס/לוארקייס בהתאם.
-
אפשר לעשות
declare -a name
כדי ליצור מערך בשם name
environment variables¶
המשתנים הסביבתיים הם משתנים שה-shell מגדיר מחדש באופן יחסי בכל מערכת שהוא רץ עליה, והם מאפשרים לו "מגע עם הסביבה שלו". הם מוגדרים מראש עבור כל סשן ב-bashrc, ואפשר להכריז עליהם ספונטנית עבור סשן מסוים שרץ.
המבנה הכללי שלהם הוא key=value
printenv
- להראות את המשתנים הקיימים
אפשר לעשות printenv VARIABLE
בשביל ערך של משתנה ספציפי (אפשר כמובן גם echo $VAR
)
- אפשר להריץ תוכנה עם ערך ייחודי לאחד המשתנים הסביבתיים
- למשל, הרוחב של שורה ב-
man
נקבע ע"י משתנה סביבתי בשם MANWIDTH - כדי לשנות אותו בהרצה מסוימת של
man
נעשהMANWIDTH=75 man command
- למשל, הרוחב של שורה ב-
declare¶
והדרך להכריז עליהם עבור סשן בודד היא declare -x <KEY>=<VALUE
כדי לבטל משתנה סביבתי נעשה עם פלוס על האיקס:
declare +x <KEY>
וכדי לקבל רשימה של כל המשתנים הסביבתיים שאנחנו הגדרנו אפשר לעשות גם
declare [-p]
לא יודע במה זה עדיף על printenv
אפשר לעבוד עם גם export
, הנוהג הוא שזו הפקודה לשים בקובץ bashrc
export¶
export <KEY>=<VALUE>
כדי להגדיר משתנה סביבתי
export -n <KEY>
כדי לבטל
export [-p]
כדי לקבל רשימה שלהם
חידוד: יש גם export PATH
, פשוט אומר שאנחנו רוצים שהתוכן של PATH יהיה זמין ל-child processes של הטרמינל שבו הפקודה רצה. לכן, אם למשל אנחנו עושים export ~/exp
אנחנו בעצם אומרים "מעכשיו כל מה שהטרמינל הזה מריץ יודע לקרוא מ-PATH".
special variables¶
- הם לא משתנים סביבתיים, כי הם לא משתנים קבועים שה-shell טוען בכל פעם שהוא רץ. הם משתנים מסשן לסשן.
דוגמה טובה היא
BASH_VERSION
שיתן לנו את הגרסה המתאימה לסשן בכל פעם. עוד שימושיים:$$
מחזיר את ה-PID של התהליך שהריץ אותו$RANDOM
יחזיר מספר אקראי, אבל מתוך טווח די קטן במונחים של מחשב.
useful environment variables¶
![[Pasted image 20250124235558.png|500]]
$HOME
- ~/
זו תמיד התיקיה ש-cd
בלי argument יוביל אליה
$pwd
- path to working directory -
$GLOBIGNORE
מכיל רשימה של פאטרנים שבאש מתעלם מקבצים שמתאימים להם בשם
$path
זה כמובן איפה שבאש מחפש פקודות
$EXECIGNORE
מחריג תבניות של פיילניימז מלהיספר כפקודות בתיקיות path
$PPID
פרוסס איידי של כל השלז
$BASHPID
פרוסס איידי של הטרמינל הנוכחי בלבד
בכל מקרה, בכל סוגי המשתנים, **בכל מקרה, בכל סוגי המשתנים, לא מכריזים עם $!
כותבים $varname
(עם הדולר בהתחלה) רק כשרוצים לרפרר לערך של משתנה שכבר הוגדר
חידודים ספציפיים:
PWD
pwd
זהה ל-echo $pwd
אבל שונים מ-bin/pwd
הראשונים רצים עם -L בברירת מחדל
השני רץ עם -P
בכל אופן אפשר לתת את הארגומנט השני
Options:
-Lprint the value of
$PWDif it names the current working directory
-P`
print the physical directory, without any symbolic links
source¶
-
משמשת כדי להריץ סקריפט ב-Shell Session הנוכחי כשאנחנו מריצים סקריפט, באש פותח Subshell חדש ונותן לו את הסקריפט כאינפוט. אם אנחנו רוצים לשחק עם משתנים של הסשן הנוכחי, או לעשות כל דבר שדורש מגע עם הסשן הנוכחי שלנו, הפקודה
source
בעצם מזינה את הסקריפט כאינפוט לסשן הנוכחי -
אם רוצים לטעון מחדש קבצי מערכת, יש
reload path
אבל יש גםsource path
למשלsource ~/.bashrc
-
במקום לכתוב
source
אפשר גם פשוט לעשות.
(נקודה)
לזכור: כשאנחנו "טוענים" תוכנות, ה-shell פשוט מקבלת את הקוד שלהן כאינפוט, כאילו כתבנו לה את כל הפקודות שבקובץ מיד ברגע שהפעלנו את ה-shell...
set¶
-
משמשת להגדרה של משתנים המייצגים shell options או positional parameters מפעילה הגדרות שונות שיפעלו ב-shell session באופן גורף, כלומר, בסקריפט הן יפעלו לכל אורך הסקריפט. רובן קשורות לדיבאגינג ואאוטפוטים. להסתכל ב-(קישור לכתיבה מתגוננת).
-
יש הדורשים להשתמש ב-e, u ו-o pipefall ביחד, אבל כיום הרוב בדעה שאין סיבה להשמש בהן בכלל - הסיבה היא שיש פקודות שצריכות להחזיר exit non 0 בכל מיני מצבים, אז כדי שה-setים יפעלו, היה צורך ליישם כל מיני חוקים מיוחדים (מתי הכישלון "נחשב" ומתי לא) - החוקים האלה לא עקביים ולא אפקטיביים באיתור באגים אמתיים. (הדברים האלה קיימים בבאש כי זו דרישה של POSIX במטרה לקדם קוד יציב).
set -e¶
- יפסיק את הסקריפט אם כל פקודה שהיא מחזירה non zero exit status, חוץ מכמה יוצאי דופן הכרחיים (?)
set -u¶
- יעצור את הסקריפט ברגע שמופיע משתנה שלא הוכרז לפני כן (קיבל ערך)
set -o PIPEFAIL¶
יעצור את הסקריפט אם החוליה האחרונה בכל פייפ שהוא נכשלת
set -o vi¶
מפעיל Vim Keys בטרמינל
אפשר להוסיף את set -o vi
ל-bashrc כדי שיפעל תמיד
ברירת המחדל היא דווקא מקשי emacs, והפקודה היא set -o emacs
alias¶
alias name='string'
כדי ליצור 'פקודה' חדשה, למשל
alias rclonemount = 'rclone mount gdrive:/ ~/bigbro'
unalias name
כדי לבטל אליאס
alias
בלי אגרומנט כדי לקבל רשימה של כל האליאסים שהגדרנו
אליאס מתאפס כל טרמינל סשן, לכן עושים משתנים סביבתיים
אם יש משהו שאנחנו משתמשים בו עם הגדרה מסוימת לעתים קרובות, אפשר להשתמש ב-alias
למשל alias ls='ls -la'
date¶
פקודה שמשמשת כדי להדפיס את התאריך...
המבנה הוא date +'specifiers'
כשאלה הן האפשרויות (יש עוד):
- לשים לב שיש רווח רק לפני הפלוס
- %Y
→ Full year (e.g., 2025
)
- %m
→ Month (e.g., 01
for January)
- %d
→ Day (e.g., 31
)
- %H
→ Hour (24-hour format, e.g., 14
)
- %M
→ Minutes (e.g., 45
)
- %S
→ Seconds (e.g., 59
)
- כשאנחנו רוצים את התאריך ב-string, נרצה את הערך של הפקודה כ-string, ולא את הפקודה עצמה, אז נעשה (למשל) ככה:
$(date + '%Y-%m-%d')
basename¶
- משתנה שעובד דומה ל-date, יודע לקחת את השם של קובץ בלי ה-Path שלו
$(basename path)
מערכים¶
בסיס: - משתנים שמחזיקים ערך יחיד נקראים scalar variables, בעוד שמערך (array) הוא משתנה שמחזיק ריבוי של ערכים מערכים הם חלק מהותי בכל שפת תכנות, והתמיכה של ה-shell בהם היא די מינימלית.
- בגדול, מערך הוא כמו קובץ אקסל כל תא בו מכונה element, והוא מכיל ערך יחיד למיקום שלו במערך נקרא index או subscript כמות ה-'צירים' שיהיו לנו בטבלה נקראים dimensions - ה-'מימדים' של הטבלה (זה עובד כמו ב-'מימדים' של גרף: בקובץ אקסל יש לנו 2 'מימדים': גובה ורוחב; מערך תלת-מימדי יכלול גם 'ציר z'.) ה-shell תומכת רק במערכים חד-מימדיים, כלומר, בשורה/טור יחידים של ערכים, בלי שזו תהיה 'טבלת אקסל' של ממש. (פשוט רצף כלשהו של ערכים). מערכים באופן כללי הם תכונה של bash 2.0 והם לא תואמים ל-narrow posix shell.
- החיסרון במערכים, והסיבה שהם יחסית אנדרייטד בבאש, היא שהרבה תוכנות GNU מהותיות לא תומכות בהם...¶
יצירה ושימוש:
-
כדי ליצור מערך יש לנו שתי דרכים:
- לתת לו ערך ולהכריז עליו באותו זמן:
a[1]=something
אומר "האיבר הראשון במערך a שווה ל-something" לסימון[1]
קוראים גם ה-subscript - לעשות לו declare -a
הפקודה
declare -a a
תיצור מערך בשם a
- לתת לו ערך ולהכריז עליו באותו זמן:
-
כדי לתת ערך למערך שוב יש כמה דרכים:
- לתת ערך יחיד:
באמצעות הסינטקס
arrayname[subscript]=value
אפשר לתת לאיבר בודד במערך ערך יחיד. יש לשים לב שהאיבר הראשון במערך הוא איבר מס' 0 ולא מס' 1. - לתת מספר ערכים:
באמצעות הסינטקס
arrayname=(value1 value2 value3 value4 value5)
אפשר לתת למערך מס' דינמי של ערכים - וכל אחד ישוייך לאיבר נפרד במערך (כאשר הראשון ילך ל-0, השני ל-1, וכן הלאה)(כלומר, אם משתנה מקבל כמה איברים מופרדים ברווח, בתוך סוגריים עגולות - הוא מערך!)
אפשר גם להחליט איזה ערך הולך לאיזה איבר באמצעות סינטקס כזה:
arrayname=([0]=value1 [2]=value2 [1]=value3)
- ליצור את איבר 100 לא יצור את 0-99
בשפות תכנות רבות, אם נגדיר את האיבר ה-100 במערך (לדוגמה), איברים 0-99 יווצרו אוטומטית כמשתנים ריקים, וניתן יהיה להתייחס אליהם בקוד (will be initialized).
זה לא ככה ב-bash, ואם נגדיר רק את
array[100]
, איברים 0-99 לא קיימים במערך.
פעולות על מערכים:
- אפשר לבצע כל מיני פעולות ברמת המערך - החל מפעולות 'פילטר' (כמו באקסל) ועד לשינוי הערכים.
-
ה-subsets
[@]
ו-[*]
מתייחסים לכל האיברים ביחד כשהם מוצמדים לשם המערך הבדל ביניהם הוא כמו ההבדל בין*$
ו-@$
עבור positional parameters: כלומר: ללא גרשיים שניהם יתנו לנו רשימה של כל מילה במערך שלנו בנפרד (כך שאחרי כל רווח תבוא שבירת שורה - גם אם זה רווח בתוך איבר ש-'תחום' ב-""
) אך כשהם עטופים בגרשיים"
הכוכבית תתן לנו רשימה 'שטוחה' של כל המילים מכל הערכים, בעוד שהשטרודל יתן שורה נפרדת לכל איבר שתחום ב-""
כמעט תמיד נעדיף את @ כדי לשמור על המשתנים שלנו מלהתערבב קצת קשה להסביר את זה בכתב, הנה תמונה: -
הקידומת
#
תתן לנו expansion של מס' האיברים במערך (כמו שהיא תתן את מס' האותיות עבור string רגילה)${#a[@]}
זה הסינטקס${#a[100]}
בעוד שזה, כידוע, יתן את האורך של האיבר המאה באותיות -
כדי לבדוק אילו איברים קיימים במערך: (כזכור, ליצור את 100 לא יוצר את 0-99 אוטומטית, לכן יכולים להיות 'רווחים' במערך:) נשתמש באחד מאלה:
${!array[*]}
${!array[@]}
כאשר ההבדל בין@
ל-*
הוא אותו דבר כמו עבור # (כמו גם בפרמטרים מיקומיים, נעדיף לרוב את@
). -
כדי לעשות append (לספח) למערך:
נשתמש ב-=+
נניח שעשינו כברarray=(a b c)
ואנחנו רוצים להוסיף איברים 4-6 שהם e d f. נעשה:array+=(d e f)
:'slice' - סינון מערכים
- יש צורה מיוחדת של parameter expansion שלמעשה מאפשרת להדפיס טווח מסוים של איברים מתוך המערך
הסינטקס קצת מורכב:
arr=(0th 1st 2nd 3rd 4th) echo "${arr[@]:2:3}" --- 2nd 3rd 4th
הסבר: הסינטקס :2:3
אומר "תדפיס שלושה איברים החל מהאיבר השני" (התצוגה מתהפכת כאן, הסדר הנכון הוא זה שרואים בקודבלוק)
- אפשר להשתמש במינוס בערך הפרמטר כדי למספר את האיברים מהסוף להתחלה:
[me@linuxbox ~]$ echo "${arr[@]: -2:2}" 3rd 4th
הסבר: הלכנו לאיבר השני מהסוף, וממנו ספרנו 2 קדימה, כך שלמעשה חילצנו את שני האיברים האחרונים. (פעמיים מינוס שתיים היה סופר מהשני מהסוף, וגם סופר לכיוון הנגדי). חשוב לזכור שהספירה "כוללת את האיבר", במובן שאם הלכנו ל-3rd בדוגמה למעלה, וספרנו ממנו 2 קדימה, למעשה ספרנו אותו + את 4th.
לשים לב שמשום מה צריך רווח לפני שמשתמשים במינוס! (לא הבנתי אם זה רק כשמשתמשים אחרי ה-prompt, או שיש צורך לשים רווח לפני כל שימוש במינוס.)
- אפשר להשתמש בהתרחבות הזו כדי ליצור מערכים חדשים:
arr2=("${arr[@]:2:3}")
סידור מערכים עם sort
- אין דרך מובנית לעשות sort לאיברים של מערך, צריך לעשות להם echo ולהריץ על האאוטפוט sort...
a_sorted=($(for i in "${a[@]}"; do echo "$i"; done | sort)) echo "Sorted array: " "${a_sorted[@]}"
הסבר: נתון מערך a; על מנת לסדר אותו ולשמור כמערך חדש בשם a sorted, יצרנו לולאת for עבור @ של a (כל האיברים, מופרדים כמילה/שורה לפרמטר) - הרצנו echo עבור כל אינפוט וניתבנו את הכל ל-sort באמצעות pipe.
דרכי שימוש נפוצות: - התאמה בין לולאת for למערך:
for i in {0..23}; do hours[i]=0; done
שורה כזו בעצם יוצרת משתנה i
עבור כל מס' בין 0 ל-23, ואז עבור כל משתנה כזה, יוצרת איבר מתאים במערך hours.
- שילוב עם פקודת
read
בד"כ נשתמש ב-read באופן כזה:while read line -r
כאשר בכל איטרציה של הלולאה, read מגדירה את line. דרך נוספת, עם שימושים אחרים, היא לתת ל-read את הדגל-a
, שאומר "כל אינפוט שתקרא מקבל איבר משלו במערך":read -a array <<< "value1 value2 value3"
mapfile¶
- פקודה חדשה יחסית שקוראת STDIN ישירות לתוך מערך
mapfile -options arrayname
אפשרויות:mapfile -t -n 32767 words < "$WORDLIST"
לדוגמה ייצור מערך בן 32767 איברים בשם 'words' עם הערכים שיקבל
unset¶
- פקודה שמשמשת למחיקת מערכים:
לתת למערך ערך ריק לא מאפס את האיברים שלו!
arrayname=
לא עובד, כי כל התייחסות למערך בלי פרמטר היא בגדר התייחסות לאיבר 0 (ראשון) של הפרמטר. (=blank
פשוט יאפס את איבר 0 בלבד).
unset <arrayname>
- ניתן למחוק גם איברים בודדים:
`unset '
[subscript]'
לשים לב שחייבים '...'
כדי שערך האיבר לא יתרחב ב-shell!
Associative arrays מערכים אסוציאטיביים¶
-
החל מבאש 4.0, ניתן ליצור מערכים שהאינדקסים שלהם אינם מספרים אלא strings כלומר, במקום שיהיו לנו איברים שממוספרים ב: 1,2,3 וכו', יהיו לנו סטרינגס שהם למעשה 'שמות התאים' של האיברים השונים. זה מבנה נתונים שנקרא 'key-value' ונטען בחוברת שהוא בנוי כמו מילון (? לחשוב על זה)
-
כדי ליצור מערך אסוציאטיבי, אי אפשר פשוט לתת לו ערך כמו למערך רגיל, אלא יש צורך להכריז עליו:
declare -A colorscolors["red"]="#ff0000"colors["green"]="#00ff00"colors["blue"]="#0000ff"
לשים לב שזה הדגל -A
ולא -a
! אות A גדולה = מערך אסוציאטיבי
השימוש באיברים במערך כזה הוא בדיוק כמו השימוש באיברים במערך רגיל:
echo ${colors["blue"]}
- אפשר להשתמש במערכים אסויצאיטיביים כדי "לזייף" מערכים מרובי מימדים:
נגדיר שני טווחים, נניח x ו-y, ונגדיר משתנה address שהוא "x, y" עבור כל ערך אפשרי של x ושל y.
כל משתנה כזה הוא "משבצת", ונוכל למספר אותן ע"י הזנת המשתנים שיצרנו לתוך מערך מסוג
[multi_array[$address
. כך, נקבל טבלה ממוספרת, ונוכל לעבוד על המשבצות שלה לפי המספור שלהן בטבלה. או שאפשר לעשותfor (( var; var; var ))
.
רידירקציה, לולאות, סקריפטים¶
[[Bash Scripting]]
כל פקודת הרצה מתייחסת ל-exit status (הצלחה\כישלון...) של הפקודה שקודמת לה מידית!
&, &&, line break:¶
-
&
אומר "להמשיך מיד לפקודה הבאה" וזו הסיבה שאם הוא מגיע בסוף פקודה או סקריפט, הוא משחרר את הטרמינל -
&&
אומר "להמשיך לפקודה הבאה ברגע שהקודמת סיימה לרוץ, ובתנאי שהיא הצליחה", לשים לב שלא ניתן להתקדם מפקודות שממשיכות לרוץ ברקע (rclone mount למשל) - הן יתקעו אותנו אם נשים && -
פקודות שמופרדות בשורה הן שונות משני אלה: הטרמינל ימשיך לפקודה הבאה ברגע שהקודמת סיימה לרוץ, ובהתעלם מההצלחה שלה.
-
אם נריץ פקודה עם
&
בסוף ככה שהיא ממשיכה לרוץ ב-background, נקבל אאוטפוט בסגנון הבא:[1] XXXXX
זו בעצם הדרך של הטרמינל להגיד: התחלנו job מס' [n] וה-PID שלו הוא xxxx (אפשר לראות את זה ב-ps
) אפשר לראות את כל ה-jobs עם jobs
semicolon ;¶
command ;
עובד כמו && אבל לא מתחשב בהצלחה או כישלון, פשוט ממשיך ברגע שהפקודה הקודמת מסיימת לרוץ
double pipe ||¶
command ||
עובד הפוך מ &&, ממשיך הלאה רק אם הפקודה נכשלת
Grouping Brackets {}
()
¶
curly brackets {}¶
{ command1; command2; command3; }
:הסינטקס הרגיל
- הופך את כל הפקודות שבסוגריים (מופרדות כרגיל ברווחים) ל-Group Command - פריט יחיד בכל הנוגע ל-Redirection
-
יש להפריד עם
;
כדי להגיד ל-shell שלא מדובר בארגומנטים אלא בפקודות נוספות...{ command-a & command-b}
הופך את הפקודות לבלוק אחד מבחינת סטטוס יציאה. המשמעות היא שלשים && אחרי הבלוק הזה יתנה את ההמשך בהצלחה של שתי הפקודות, וכן הלאה. -
[[Bash Scripting#shell functions|פקודות של פונקציות]] הן תמיד בתוך סוגריים כאלה
-
עדיף על סוגריים עגולות במקרה בו אנחנו לא צריכים subshell! צורך פחות זיכרון.
(...)
normal / single round brackets¶
-
דומה ל-
{}
, די שקול ברוב המקרים, אבל יש הבדל: הסוגריים המעוגלות יוצרות Subshell שמריץ את הפקודות שבתוכן ב-shell session נפרד. הסוגריים המסולסלות מריצות את הפקודות כ-group בתוך ה-shell session הנוכחיאם נעשה:
echo $(cd ~/ && ls) && cd
נקבל את ה-ls של home, ואז את ה-cd שהיינו עליו ב-shell. זה בגלל שה-cd הראשון שוגר ב-session נפרד (של הסוגריים), ולא השפיע לנו על ה-cwd בסשן הראשי.בעוד שאם נעשה:
echo ${ cd ~/; ls; } && cd
זה ישפיע לנו על ה-cd בסשן הראשי, ובהכרח נקבל פעמיים את הפאת' של home -
באופן כללי חיבור פקודות זה שימושי מאותן סיבות כמו בלוגיקה ובמתמטיקה... אם עשיתי:
if [[ ! (command1 && command2) ]]
אז!
יהפוך את ה-exit status של הקוניונקציה של command 1 ו-2 אבל אם עשיתי:if [[ ! command1 && command2 ]]' אז בעצם נמשיך ל-command 2 רק במקרה ש-command 1 נכשלה, כי
!` פועל רק עליה, והופך בין 0 ל-1 ב-exit status -
להשתמש ב-Groupings חכם זה לעשות:
{ command-a; && commandb; } && { command-a; && commandb; }
וכו'... כדי ליצור היררכיה של 'התניות' באמצעות קוניונקציות, או גם פייפים!||
parenthesis 'x', "x"
¶
[[מילון BASH#פקודה בודדה באמצעות ssh#|לקוח מתוך כאן]]
יש לזכור את העיקרון -
'command'
בגרשיים עוברת כ-string ולא כפקודה (ללא expansion). אבל ה-string היא ללא הגרשיים - ואז הפקודה הופכת ל-command
. - אז אם אנחנו צריכים להעביר פקודות להוסט, נעטוף אותן בגרשיים כדי שיקראו כ-string ע"י המערכת המקומית בשלב הראשון, ואז יעברו כפקודות בלי גרשיים כאינפוט להוסט.ssh remote-name 'ls * > dirlist.txt'
יעביר את הפלט של ה-ls לקובץ dirlist *ב-root של ה-host, כי הפקודה עברה במכונה כסטרינג, ואז אל ההוסט בלי הגרשיים,, כלומר כ-command!
### backslash \
בסוף שורה אומר לבאש להתעלם מה-Line break
command \
&& command 2
#! shebang¶
-
כשיש לנו #! זו לא הערה אלא שיבנג. הוא אומר לקרנל (למה לקרנל ולא ל-shell?) עם איזה interpreter הוא קורא את הסקריפט.
#!/bin/bash
הוא המיקום של השל שלנו, באש...חשוב להבדיל מ-
#!/bin/sh
שהוא המיקום של ה-symlink ל-default shell שלנו. בד"כ הוא מקושר לבאש, אבל לפעמים הוא מקושר ל-POSIX Shell/Narrow Shell
PS2 Shell Prompt ">"¶
- כשאנחנו מקבלים את STDOUT בטרמינל, בכל שורה חדשה יהיה "<" בהתחלה
- זה בעצם prompt (טקסט מקדים) שמוצמד לכל פלט של PS2 (המשתנה שמכיל את STDOUT)
- השימושיות תתברר בהמשך
read¶
בגדול read היא הדרך שלנו לעבד STDIN. פקודה שיכולה לקבל או argument ו-option או קובץ/פייפ ו-option בד"כ תבדוק אם יש ערך ל-$1, ואם אין, נעשה
read
למטרה שמגיעה מ-STDIN.הרבה פעמים משתמשים ב-
command | while read line
כדי לעבד שורות מאאוטפוט, אחת אחרי השניה; זה בגלל שכשהיא מקבלת אינפוט, read פועלת על כל שורה בנפרד (כשנגמרות - מחזירה 1) (כמו שלמדנו, הגדרנו רק את משתנה line, אז הוא יקבל את כל המילים - וכל שורה היא "אינפוט" נפרד! )
מקבל אינפוט מהמשתמש דרך הטרמינל, או מקובץ, ושומר אותו במשתנה או במשתנים.
read var1 var2 var3'
מגדיר את המשתנים
ובאינפוט, כל מילה הולכת למשתנה לפי הסדר: hello I'm Tony = var1(hello), var2(I'm), var3(Tony)
אם יש יותר מילים ממשתנים - כל המילים העודפות נשמרות על המשתנה האחרון
ואם אין ערך למשתנה - הוא מקבל "" (blank)
משתמשים ב-$ כדי לרפרר למשתנה, כמו תמיד...
echo "Please enter your name: "
read name
echo "Hello, $name"
אפשר להשתמש בדגל p-
כדי להציג הודעה תוך כדי שמבקשים אינפוט:
read -p "Enter your name: " name
echo "Hello, $name"
אפשר להשתמש בדגל -a
כדי להפוך את המשתנים למערך, ואז רק צריך לתת שם למערך, ויהיו בו פריטים כמספר המשתנים.
echo "Enter three numbers separated by space: "
read -a numbers
echo "The numbers are: ${numbers[0]}, ${numbers[1]}, ${numbers[2]}"
- אפשר להשתמש בדגל
-s
כדי לקבל אינפוט "שקט" (שלא יודפס על המסך, כמו כשמקלידים ססמה ל-sudo) - אפשר להשתמש בדגלים
-e
ו--i
כדי להגדיר ברירת מחדל במקרה שהיוזר לא נותן ערך חדשread -p "Enter your name: " -i "John Doe" name
אפשר להשתמש בדגל-r
כדי להדפיס באקסלאשים כרגיל! כברירת מחדל, read דווקא מתייחס ל-escape characters (לעומת [[מילון BASH#echo#|echo]] שפועל הפוך) יש גם-t
בשביל טיימר,-A
בשביל מערך אסוציאטיבי (??) ועוד, לא נשמעים הכי שימושיים, אפשר לגגל אם צריך
אם לא הוגדר שום משתנה ל-read, הכל נשמר אוטומטית על המשתנה $REPLY
control structures\control flow statements¶
dos2unix¶
- כשכותבים סקריפט בתוכנת ווינדוז, למשל VS CODE, אנחנו מקבלים carriage return character שונה מב-unix; לכן, יש צורך לפרמט מחדש את הקובץ.
dos2unix filename
כדי לפרמט מחדש
function, return¶
- הפקודה
function
פותחת הגדרה של Shell Function והפקודהreturn
סוגרת פונקציה כדי לסיים את הפקודות שלה ולחזור לשורה שבה היא קיבלה call (אחת אחריה ליתר דיוק) - מתועד יותר באריכות [[Bash Scripting#shell functions|בקובץ הסקריפטינג]]
- חשוב לזכור ש-return מחזירה אותנו לאיפה שה-call התבצע!!!
conditionals¶
if, then, else¶
-
מיועד כמובן כדי ליצור branchים בתוכנה (אם קורה א' תעשה ככה, אם קורה ב' תעשה ככה)
if argument-command; then
command2else
command3
fi
-
מה שמעניין ב-bash זה שגם התנאים של הלולאה, מה שמופיע ב-argument command, הם פקודה. איך מתנים פקודות בפקודה? זה קל למי שמקשיב: לכל פקודה יש [[מילון BASH#exit status|exit status]] שנוצר עם סיום ההרצה שלה, בהתאם להצלחה או לכישלון שלה; פקודת
if
אומרת למעשה "אם הערך של הפקודה בסוגריים הואtrue
, ו-else
אומרת "אם הערך שלה הואfalse
". -
אם סיפקנו מספר פקודות - ההתקדמות של
if
תהיה לפי ה-exit status של האחרונה ביניהן - Test conditions (like file or string checks):
if [ ... ]; then
- Commands that return an exit status:
if command; then
שימוש בפקודה כהתניה בפועל: - אם שמנו משהו כמו grep נגיד בהתניה של if - היא תחזיר true אם יש לה ערכים בסוף (אם הייתה התאמה אחת לפחות), ובמקרה אחר לא (סטטוס יציאה 1+). זה נכון להמון פקודות.
היפוך הערך של ההתניה - כדי לקבל ערך "TRUE" רק אם ה-exit status הוא דווקא 1+ (FALSE), אפשר להשתמש בפקודת ה-if ישירות (לא לכל פקודה יש מקבילה ל-grep -v "שהופכת" את האאוטפוט).
`if ! echo "$var1" | grep "^hello$"; then`
הסיפה של if תופעל כאן אך ורק אם **אין** התאמה מדויקת ל-hello. בגלל שיש !
case¶
- לולאה לא בסיסית, אבל חשובה
-
בהרבה מקרים, יש לנו בחירה בין כמה אפשרויות עבור תוכנה, ואם היינו בונים אותה עם if, היינו צריכים לעשות מספר "תאים" של if else if
-
במקום זה,
case
היא 'multiple choice compound' - היא מאפשרת בחירה בין כמה אפשרויות, באופן הבא:case <string-or-var> in value) commands more commands ;; value) commands more commands ;; value) commands more commands ;; esac
-
אם אין לנו כמה שורות של פקודות, נעשה:
value) commands ;;
-
ה-case תחפש את הערך של
<string-or-var>
לפני אחת מהסוגריים - ואם יש התאמה, תתריץ את כל הפקודות החל מאחרי הסוגר ועד ל-;; ה-esac
הוא פשוט ההפך מ-case... אנחנו בעצם בונים "רשימה", יחסית מסודרת ויזואלית, של אפשרויות שונות להתאמה, ופקודות שהן יריצו. -
הסוגר מסמל את הסוף של ה-pattern שנתאים כנגדה אפשרויות ל-pattern:
- כמו שניתן לראות בתמונה, גלובים עובדים ב-case
-
בנוסף לזה, אפשר להשתמש ב-
|
(סימן של פייפ, אבל ב-case זה לא פייפ -) כדי להגיד "או pattern-a, או pattern-b" (וכך הלאה):q|Q) echo "you typed q" ;;
כדי ללכוד גם אות גדולה וגם קטנה, למשל. -
עד באש 4.0, case ידעה למצוא התאמה אחת בלבד פר אינפוט מאז 4.0, אפשר להשתמש ב-
;;&
במקום ב-;;
רגיל כדי להגיד לבאש: "בדוק את ההתאמה הזו, בצע את הפקודות אם היא מתקיימת, ואז תמשיך לבדוק את ההתאמה הבאה"המשמעות היא שכל טסט שנסיים ב-
;;&
הוא לא אקסלוסיבי ויאפשר לבדוק את האינפוט כנגד עוד תבניות (case שכולו כאלה הוא פשוט case שמתאים את כל מה שאפשר)
test, [ ... ]
, [[ ... ]]
(square brackets), (( ... ))
(double rounded brackets)¶
test & [ ... ]
¶
- הפקודה
test
שקולה לפקודה[ ... ]
- הפקודה הכי נפוצה יחד עם
if
וכו' - מאוד שימושית - היא בעצם נועדה לתת ללולאות התניות "רגילות" יותר מפקודות - כלומר פשוט לבדוק את ערך האמת של ביטוי (במקום exit status של פקודה "אמתית") - כאשר ה-exit status של
test
יהיה בהתאם לערך האמת הזה. עושיםtest expression
או פשוט:[ expression ]
לשים לב שיש רווח מכל צד של הסוגריים המרובעות. -
מעניין לדעת שזו פקודה מובנית ב-bash, אבל היא קיימת גם כתוכנה ב-
/usr/bin
כדי שנוכל להשתמש בה עם shells נוספים המבנה הלוגי של התוכנה מעניין:]
היא הפקודה... היא מקבלת ארגומנטים נוספים לאחר מכן, זו הסיבה שיש לנו רווחים בשולי הסוגריים, והיא גם דורשת ש-]
תהיה הארגומנט האחרון שלה (הסוגריים מתהפכות כאן, הכוונה היא כמובן לפתיחה בהתחלה ולסגירה בסוף). -
ה-
test
תומכת במגוון רחב של expressions בתוך הסוגריים, הנה רשימה חלקית, יש עוד ב-man page
תכונות של קבצים: ![[Pasted image 20250202230402.png|500]]
השוואות בין strings: ![[Pasted image 20250202234055.png|500]]
השוואות בין מספרים:
![[Pasted image 20250202234333.png|500]]
[[ ... ]]
(Double Brackets)¶
-
גרסה מודרנית יותר של
test
ושל[ ... ]
שתומכת ב-Regex (זו דרך לעשות Regex בתוךif
למשל) -
אפשר לשים בסוגריים את כל הסינטקס הרגיל של
test
, ובנוסף אפשר להשתמש ב-=~
(קשה להבין פה: זה סימן שווה קודם ואחריו הסלסול.) -
האופרטור
=~
משווה בין string שניתן לו לבין regular expression שיבוא אחרי האופרטור מדובר ב-ERE, והפקודה מחזירה 0 (true) אם יש התאמה[[ "hello" =~ 'ello' ]]
יחזיר 0 - true -
בנוסף, רק
[[ ]]
יודעת לתמוך ב-pathname expansion כלומר שרק איתה אפשר לעשות:if [[ $FILE == foo.* ]]
-
בהמשך לנקודה האחרונה, בסוגריים מרובעות-כפולות ועגולות-כפולות לא צריך לעשות escape characters זה בגלל ש-
[[...]]
ו-((...))
הן תוכנות shell שייחודיות לבאש בעוד שה-test
הקלסי הוא חלק מהסינטקס של כל POSIX Shell/Narrow Shell (הם command arguments)לדעתי זה הופך את הכתיבה ליותר קלה שאין אסקייפים...
(( ... ))
Double Round Integer Brackets¶
- עוד תוספת של bash ל- test &
[ ... ]
הקלסיים - נועדו לבצע בדיקות של ערך אמת על אינטגרים (מספרים)
- האופרטורים שמשתמשים בהם הם כאלה שמחזירים ערך אמת:
>, <, ==
ועוד כמה - בתוך סוגריים כפולות, לא חייב לתת $ לפני שם של משתנה זה בגלל שאותיות לא קיימות בתוך הסוגריים גם ככה, אז הסוגריים תמיד יבדקו אותן כמשתנה
אופרטורים לשילוב ביטויים¶
-
כל ה-Compounds שתחת הכותרת הזו (test וכל הסוגריים) מאפשרים לחבר ביטויים באמצעות שלושה אופרטורים:
AND, OR, NOT
-
ב-
test
ו-[ ... ]
כותבים אותם:-a
AND-o
OR!
NOT -
ב-
[[ ... ]]
ו-(( ... ))
כותבים אותם:&&
AND||
OR!
NOT
Loops¶
- לולאות נועדו כדי לחזור על שורות קוד מסוימות, בתנאים מסוימים או עד שמשהו מפסיק אותן. אם לחשוב על זה, הרבה פעולות שאנחנו עושים במציאות בנויות בערך ככה: "לחתוך גזר, אם זה הגזר האחרון - להפסיק לחתוך, אם זה לא הגזר האחרון - לחזור להתחלה" הכוונה היא לפעולות שהן חזרתיות, ומתבצעות עד להשגה של יעד מסוים... ולפעולות כאלה נשתמש בלולאות:
while, until¶
While:
# count from 1-5 and print each step
variable=1
while [[ "$count" -le 5 ]]; do
echo "$count"
count=$(( count + 1 ))
done
echo "Finished"
-
הסינטקס הכללי הוא:
- (אבל לזכור ש-while <commands>; do commands done
;
שקול לשבירת שורה, אז אפשר לפרמט את השורות איך שרוצים, כל עוד מוסיפים;
בהתאם) -
עובד דומה ל-
if
- הפקודות ימשיכו לרוץ כל עוד סטטוס היציאה של התנאי הוא 0 (True) בדוגמה שלמעלה, המשתנהcount
מגיע לערך 6 והתנאי שלwhile
מתחיל להחזיר 1 (False). לכן הסקריפט עובד.
- לאחר שהתנאי מפסיק להתקיים, הקוד ממשיך מהשורה שאחרי done
¶
Until
- נכתבת בדיוק כמו while
, ועושה את ההפך ממנה
כלומר, until
מריצה את הפקודות שלה עד שהתנאי מחזיר 0 (True)
בדוגמה שלמעלה אפשר היה להשתמש ב-until
ולבדוק האם המשתנה גדול מ-5, במקום להשתמש ב-while
ולבדוק אם הוא קטן/שווה ל-6
הבחירה בין השתיים לרוב קשורה לשיקולים של בהירות - מה שיותר אינטואיטיבי.
רידירקציה ללופ
-
לולאות מקבלות STDIN. אז אפשר לעשות:
done < file.txt
(רידירקציה בסוף הלולאה) כדי שתבצע את הפקודות בהתניה שלה על STDIN מקובץ. -
עם
>
בדוגמה הבאה, הלולאה תפעל כל עוד read פועלת על הקובץ ומחזירה exit status 0. כלומר, היא תפעיל את commands על כל שורה ב-file.txt, עד שיגמרו השורות, ואז היא תחזיר 1 (או משהו אחר שאינו 0), והלולאה תישבר.while read ...; do commands done < file.txt
-
עם
|
(פייפ) בדוגמה הבאה, הלולאה מקבלת STDIN מפייפ, ותפעל כל עוד read מקבלת ערך. כלומר, commands יופעל על כל שורה באאוטפוט של הפייפ לזכור ש-pipe פותח subshell - משתנים שהלולאה תגדיר לא יישמרו בסופהcat file.txt | while read...; do commands done
-
האפשרות הזו מאוד דומה למה שעושים באמצעות לולאת
for
, ולכן היא לא נחשבת לולאה 'בסיסית'
break, continue¶
- כדי לצאת מיד מלופ, ולהמשיך לשורה שאחרי סוף הלופ, משתמשים ב-
break
- כדי לדלג על האיטרציה הנוכחית של הלופ (לדלג ע
-
ל כל הפקודות שמתחת), ולקפוץ להתחלה של האיטרציה הבאה (לחזור להתחלה של הלופ) - משתמשים ב-
continue
טכניקה נפוצה היא לבנות תוכנת shell ככה שכולה מתקיימת בתוך לופ, בשביל שהיציאה ממנה תהיה באמצעות הממשק שלה בלבד (באמצעות קוד של התוכנה שמוביל ל-
break
') -
while true; do
היא הצורה הכי קלה להיכנס ללופ נצחי (לזכור ש-true
היא פקודה שמחזירה תמיד סטטוס יציאה 0...) -
כאשר אנחנו בונים לולאות להרבה אפשרויות שונות, תמיד כדאי לשים בסוף הפקודה של כל אחת מהאפשרויות
return
, פשוט כדי שבאש אפילו לא יקרא את המשך הבדיקה, ויעבור מיד להמשך הסקריפט. (ובאופן כללי,return
מאפשרת לקפוץ לסוף הלולאה, ויכולה לחסוך קריאה של שורות שהופכות למיותרות לאחר תנאי כלשהו)
for¶
- נועדה לבצע פעולה חוזרת על רשימה של פריטים
- יש כמה צורות לסינטקס:
- הבסיסית:
for variable in <...>; do <commands> done
- כאשר variable הוא משתנה שיקבל את הערך של הפריט שהלולה פועלת עליו בכל פעם, ו -
...
כולל רשימה של פריטים. - אפשר להשתמש ברשימת הפריטים בטווח
{A...D}
או בגלובים*.txt
התרחבות שנכשלת תחזיר את עצמה כ'מילולית', כלומר שה-* יודפס. לכן כדאי להוסיף קוד שיוודא אם ההתרחבות עבדה. - אם לא מספקים ל-for רשימה, ברירת המחדל היא לרוץ על כל positional parameter שקיבל ערך (=על האינפוטים שאחרי הפקודה)
- בלולאת for שהיא זמנית מאוד, נהוג להשתמש ב-
i
ואז ב-j,k,l כמשתנים (אם יש for בתוך for) - זה מבוסס על השפה העתיקה Fortan שבה האותיות האלו היו integers כברירת מחדל, לעומת כל השאר שהיו real (סוג אחר של ערך מספרי). (עדיף לתת שם נורמלי, אבל המשתנה של for לרוב לא 'ימשיך הלאה').
- וצורה מבוססת C: (קיימת בגרסאות חדשות יותר של באש, מבוססת על הסינטקס של הלולאה בשפת C) אם אני מבין נכון - הצורה הזו היא לערכים מספריים בלבד
for (( <conditions>; <end-conditions>; <end-of-loop-commands> )); do
commands
done
<conditions>
while <end-conditions>; do
commands
end-of-loop-commands
done
select¶
סלקט היא בסה"כ פקודה די חלשה. היא לא חוסכת הרבה הקלדה לעומת לולאה רגילה של while, והיא מגבילה לחלוטין את המראה של התפריט; היתרון היחיד שלה הוא ההדפסה של הפרטים הטכניים ל-error במקום ל-output, כמו שמפורט בנקודה האחרונה.
-
תוכנת shell חביבה ליצירה של תפריטי בחירה התוכנה רצה כ-loop, כלומר מריצה את הבחירה שוב ושוב, עד שאומרים לה
break
בתנאים מסוימים. -
סינטקס:
select <var> in [string..;] do commands; done
<var>
הוא שם המשתנה שיחזיק את ערך הבחירה[string..;]
היא רשימה של פריטים, מופרדים (בשורות נפרדות או עם דלימיטרים ביניהן) או שהיא ערך פקודה/משתנה, למשל:select option in $(cat file)...
;
מגיע בסוף הרשימה, לפניdo
, קצת כמו עםwhile
אוif
commands
הן כל הפקודות שנרצה להריץ לאחר שהבחירה התבצעה (לא לשכוח שצריך ברייק כדי לצאת מהתפריט)done
מכריז על סוף הלופ -
שימוש:
- האאוטפוט של
select
יציג את כל אחת מהאפשרויות בשורה נפרדת, עם מספר לפני, ככה:number) string
- היוזר יחזיר אינפוט של מס' בהתאם לבחירה שלו, וה-string של ה-number שהוא הזין תהיה הערך של
$var
- האאוטפוט של
-
הפקודה לא שולחת את ערך הבחירה, את האפשרויות או את התפריט עצמו ל-STDIN במקום, היא שולחת אותם ל-STDER (סטרים 2) מה שהיא כן שולחת לאאוטפוט זה את האאוטפוט של הפקודות שהיא מריצה לאחר הבחירה. זה מאפשר לנו לכתוב סקריפט שמתחיל ב-select, ואז לעשות רידירקציה לאאוטפוט המשמעותי שלו, שרץ לאחר הבחירה - ולא לכלול פרטים טריביאליים כמו ההדפסה של התפריט, הבחירה של המשתמש וכו'.
script-with-select > outputfile.txt
Positional Parameters¶
-
כמו שכבר הכרנו, כל משתנה $1, $2 וכו' מחזיק את הערך של האינפוט הראשון, השני וכן הלאה שסקריפט קיבל לאחר השם שלו/הפקודה שלו הם מגיעים עד
$9
ואז אפשר לכתוב אותם עם סוגריים מסולסלות:{11}$
וכך הלאה אם הם לא קיבלו ארגומנט, הם blank -
המשתנה $0 תמיד יחזיק את ערך הפקודה הראשונה שהכנסנו לקומנד ליין - כלומר, את הפאת' של התוכנה או הסקריפט שהרצנו
-
המשתנה $# שווה ל- מס' ה-positional parameters שהערך שלהם אינו ריק -- כלומר, הוא תמיד יכיל את מס' הארגומנטים שקיבלנו אחרי הפקודה עצמה (כמה ערכים יש החל מ-$1)
-
אפשר להשתמש ב-positional parameters גם כחלק מפונקציות, כדי שסקריפט יוכל לעשות להן call ביחד עם ערך מסוים, ולהריץ אותן על הערך ($1 יהיה מה שבא אחרי שקראנו לפונקציה, לא $1 שהסקריפט עצמו קיבל) לשים לב ש-$0 דווקא יכלול את ה-path של הסקריפט המקורי שקרא לפונקציה, ולא את שם הפונקציה או את הפאת' שלה (כמו שהיינו מצפים).
-
$*
מתרחב לרשימה של כל ערכי הפרמטרים המקומיים, כך שכל אחד הוא מילה נפרדת. אם נקיף אותו בגרשיים, הוא יתרחב לסטרינג מוקפת גרשיים שכוללת את כל ערכי הפרמטרים המיקומיים, מופרדים בתו הראשון של משתנה ה-IFS (לרוב ספייס). (זה אומר שאם יש לנו רווחים בתוך הפרמטר - נקבל אותו בצורה של כמה מילים מופרדות) -
$@
עובד דומה: יתן לנו רשימה של כל הפרמטרים, החל מ-1 כמילים נפרדות וכשהוא מוקף בגרשיים, יחזיר כל פרמטר מיקומי כמילה נפרדת (כאילו היו לה גרשיים - בניגוד ל-$*
, כאן פרמטרים עם רווח ישארו "מאוחדים" (נניח, יעברו לפקודה אחרת כארגומנט אחד) -
בקיצור, הראשון נותן את כל הפרמטרים כסטרינג אחד והשני נותן כל פרמטר כסטרינג בפני עצמו - כמעט תמיד נעדיף את
$@
כדי לשמור על האינטגריטי של כל פרמטר כעצמאי
shift¶
-
באש עצמו משתמש רק ב-positional parameters אחת עד תשע. (לא בטוח שנכון, אנחנו עובדים עם shift פשוט כדי שנוכל לבנות סקריפט שירוץ על כל מס' של פרמרטרים) אז מה נעשה אם אנחנו צריכים שהסקריפט יעבד 100 אינפוטים? (נניח, יקבל רשימת קבצים מפקודה אחרת כארגומנט?) נשתמש בפקודה shift, שמזיזה את כל האינפוטים משתנה אחד "אחורה"
-
ברגע שהפעלנו את shift, משתנה $3 יהפוך ל-$2, משתנה $2 יהפוך ל-$1, ו-$1 ימחק, כי $0 לעולם לא משתנה. אז אם קיבלנו 10 ארגומנטים, נוכל לכתוב תוכנה שתרוץ רק על $1, ושתמשיך לקרוא אותו כל עוד $# גדול מ-0. לאחר כל קריאה, היא תסיים בפקודה shift. כך למעשה לא צריך יותר מאת $1 כדי לעבד את כל האינפוטים.
getopts¶
בפועל משתמשים ב-getopts בשילוב עם case כדי לתרגם פרמטרים לשורות קוד שירוצו... בעצם יהיה לנו while loop עבור getopts שזורם לתוך case שיגדיר מה קורה בעקבות כל דגל. - לא לבלבל עם getopt (בלי s) - בגדול פקודות שהפרמטרים שלהן הם flags עובדות לפי התבנית של getopts (תוכנת ה-flags בקיצור)
-
נותנת לנו עוד גישה לעיבוד של פרמטרים - כשעושים לה call, ה-getopt מעבירה את הערך של $1 למשתנה שנגדיר, ומעלה ב-1 את הערך של משתנה בשם $OPTIND (שמתחיל מ-1), כך שהערך שלו יצביע על הפרמטר המיקומי הבא (בעצם, אפשר להגיד שהיא תמיד מעבירה את OPTIND, כאשר OPTIND הוא הפרמטר המיקומי המתאים למספר שהוא מקבל, וכאשר הוא עולה ב-1 עם כל שימוש ב-getopt)
-
הסינטקס קצת מבלבל: מתחילים מ-
getopts
אחריה אנחנו מגדירים איזה פרמטרים יכולים להיות, מה שמכונהoptstring
אחרי אנחנו מגדירים אתvar
, שהוא המשתנה שיקבל את הערך של הפרמטרים שהגדרנו, אם הם קיימים לפעמים דגל צריך ארגומנט: נניח שהדגל -o צריך filepath - אז ה-filepath שהיוזר יכניס יישמר במשתנהOPTARG
אחריvar
אפשר לתת ארגומנטים נוספים: -
הגדרת ה-
optstring
: - ה-optstring בנויה מאותיות בודדות, שכל אחת מהן תפורש כהפעלה של אפשרות אם היא תופיע כדגל אחרי הפקודה
-x
- אם דגל צריך ארגומנט, נשים
:
אחרי האות - אם אנחנו רוצים להשתיק שגיאות שקשורות לפרמטרים לא קיימים/ארגומנטים לא טובים לפרמטרים, אז נתחיל את optstring עם
:
(רק לפני האות הראשונה וזה משתיק את כולן, אחרת לא היה הבדל בין s:m כ-"ל-s יש ארגומנט" ו-"את m משתיקים"). -
כמו שאנחנו יודעים, אינפוט ששם כמה פרמטרים תקניים תחת
-
אחד (נגידls -la
) הוא תקין עבור getoptsgetopts :f:ih opt
: מגדיר 3 אותיות כפרמטרים, מתוכן f דורשת ארגומנט. כל השגיאות הקשורות בפרמטרים מושתקות. -
אז איך היא רצה בפועל? כדי לחדד, בדוגמה לעיל, getopts תתחיל מלבדוק את $1 ולראות אם הוא כולל - (דאש) ואחריו את אחד הפרמטרים שהוגדרו לה. אם כן - היא תחזיר את הערך שלו (בלי דאש) ל-
var
ואת הארגומנט שלו, אם קיים, ל-OPTARG
הפקודה תחליף את המונה של
OPTIND
ל-+1 מהערך הקודם, ובפעם הבאה שתרוץ, היא תעבד את $2. (או 3 אם כבר עשינו את 2...)הפקודה מחזירה exit status 0 כל עוד יש לה פרמטר תקין לעבד לכן אפשר לעשות:
while getopts <getopts commands>; do
והלולאה תמשיך עד שנסיים לעבד את הפרמטרים שהוזנו. -
ארגומנטים אחרי
var
: בגדול getopts רצה על פרמטרים מיקומיים, אבל היא יכולה לעבד גם כל ארגומנט שניתן לה אחרי var (הגדרת המשתנה של הפלט) - אם נתנו לה ארגומנט, היא תחפש פרמטרים בארגומנט במקום באינפוט של הטרמינל -
אאוטפוטים מיוחדים: ה-getopts תחזיר
?
כאשר היא קיבלה - (דאש) עם אות שלא הוגדרה כפרמטר (או אולי כל אינפוט שהוא לא פרמטר)והיא תחזיר
;
כאשר חסר ארגומנט לדגל שהגדרנו שמקבל ארגומנטבשני המקרים, האות שאחראית לשגיאה תודפס למשתנה
OPTARG
-
USE CASE: יש לנו למעשה שתי אלטרנטיבות לעיבוד פרמטרים: או getopts או while+shift חשוב לזכור ש-getopts לא תומכת ב-long format (--help במקום -h נניח), בעוד שדי קל להגדיר פורמט כזה עם whife+shift ולעומת זאת, getopts דורשת פחות קוד ותומכת בשילוב דגלים (-la וכו')
trap¶
-
פקודה שמגדירה עבור סקריפט מה הוא יעשה כאשר הוא רץ ומקבל signal יציאה כלשהו למדנו על הסיגנלים השונים שתהליכים יכולים לקבל, כמו SIGINT ו-SIGTERM. כשהסקריפט שלנו רץ, הוא בגדר תהליך. לכן, כדאי שנגדיר עבורו תנאים שונים להתנהלות במקרה והוא מקבל סיגנלים. לצורך העניין, אם הסקריפט שלנו יוצר קבצים זמניים, נרצה שהוא ימחק אותם לא רק כשהוא מסיים לרוץ בהצלחה, וגם אם המחשב נכבה באמצע או שהתהליך נעצר מכל סיבה אחרת.
-
סינטקס:
trap <argument> signal signal ...
כאשרargument
הן הפקודות שירוצו ו-signal ...
הם רשימת הסיגנלים שזה חל לגביהם. -
הנוהג הוא לציין פונקציה ב-command argument כדי לא לכתוב את כל הפרוטוקול בתוך הסינטקס של trap... פשוט כדי שיהיה מסודר יותר.
-
הפקודה תומכת בשני סיגנלים מיוחדים שהם לא בילט-אין ב-shell: מדובר ב-ERR שמתייחס לכל מצב של יציאה מהסקריפט עם סטטוס יציאה שאינו 0, ו-EXIT שמתייחסת לכל מצב שבו הסקריפט מסיים לרוץ. (לצורך העניין, הפקודות שנגדיר עבור ERR יודפסו בכל פעם שיש לנו סיום בשגיאה, והפקודות שנגדיר עבור EXIT יודפסו בכל פעם שהסקריפט יסיים לרוץ, מכל סיבה שהיא.
-
בכל מקרה חשוב לזכור שאם הגדרנו סקריפט עבור סיגנל מסוים, הסיגנל כבר לא יסגור את התהליך באופן אוטומטי; אם אנחנו רוצים שהתהליך ייסגר לאחר ביצוע הפקודות שהגדרנו, יש לסיים עם
exit
.
mktemp¶
-
תוכנת shell שנועדה לייצר temp files ושאר קבצים עם רכיבים אקראיים בשם. הסיבה שנרצה רכיבים אקראיים בתבנית השמות של ה-temp files שלנו היא כדי להימנע מהתנגשות עם קבצים אחרים במערכת, וכדי להימנע ממתקפות temp race (שבהן, אני מעריך, מריצים משהו על המחשב שלך באמצעות שינוי השם שלו לקובץ temp רווח שתכנה כלשהי תקרא).
-
שימוש:
tempfile=($mktemp /temp/progream.$$.XXXX
כל x שנשתמש בו מתרגם לספרה אקראית הפרמטר$$
מתרחב ל-PID של התוכנה שמריצה אותו הפקודה רק מחזירה את השם כאאוטפוט לכן הפכנו את האאוטפוט שלה לערך של משתנה tempfile (כך שנוכל לעשות touch $tempfile, נניח).
wait¶
-
פקודה שנועדה לאפשר asynchronous execution של סקריפטים ע"י סקריפטים אחרים הכוונה היא להרצה 'לא מסונכרנת' של סקריפטים מרובים, אבל השם מבלבל כי הפקודה מסייעת לנו דווקא לסנכרן את הפעילות שלהם.
נניח שיש parent script ובתוכו יש פקודה שמריצה סקריפט נוסף - ה-child script כברירת מחדל הסקריפטים ירוצו סימולטנית מהנקודה שה-child התחיל לרוץ. אז מה אם אנחנו רוצים להשתמש בסקריפט חיצוני כמו בפונקציה? כלומר 'לזמן' אותו, לחכות שיסיים לרוץ, ורק אז להמשיך להריץ את parent script? בדיוק למטרה הזו יש את
wait
... -
שימוש:
wait <pid>
הרפרור לסקריפט שנחכה לו הוא ע"י ה-PID שלו, כך שניתן לחכות לסיום של כל תהליך ולא רק של תהליך שהסקריפט עצמו הריץ. אם אכן מדובר ב-child script, לעתים קרובות נשתמש בפרמטר$!
ב-parent, מיד אחרי שנריץ את ה-child. הפרמטר מתרחב ל-QPID של התהליך האחרון שהתחיל לרוץ ברקע ולכן להשתמש ב-wait !$
בעצם אומר לחכות שה-child יסיים. (מתחילים מ-wait, הפקודה מתהפכת בעברית...)
תהליכים וחלונות¶
ps aux¶
`ps aux | grep
הפקודה
ps aux
היא למעשהps a+u+x
a = תראה תהליכים של כל היוזרים
u = תראה מידע מפורט
x = תראה גם תהליכים שלא נשלטים ע"י שום טרמינל פעיל
כן צריך לשים לב שהשימוש לא זהה לגמרי:
ps aux
זה סינטקס של BSD
ps -a -u -x
זה סינטקס של POSIXהדגל
-u
ב-POSIX אומר "תהליכים של יוזר ספציפי" ומצופה מאיתנו לצרף אליו ארגומנט של היוזר המדובר (אז בקיצור aux זה שלוש אפשרויות אבל לא מקביל ל-a -u -x)![[Pasted image 20250124202551.png|300]]
ps
מראה תהליכים שרצים בשל הנוכחי בלבד
ps -e
מראה את כל התהליכים
ps -ef
נותן פירוט יותר מלא על כל התהליכים
ps aux
ו-ps -ef
- אותו דבר. בעבר אחד היה לפוסיקס ואחד לביאסדי. כיום שניהם עובדים.
[[לינוקס - כללי#תהליכים|על המידע שרואים ב-ps]]
top¶
יותר טוב מ-ps aux בלהראות יפה את התהליכים השונים אבל משום מה לא חבר טוב של grep (איטי ומפספס תהליכים)
(תיקון: שונה מ-ps
בכך שהוא מראה תמונת מצב מתעדכנת של התהליכים, ולא תמונה קפואה)
top
top | grep <keyword>
טופ מראה גם מידע כללי על המערכת בראש האאוטפוט:
![[Pasted image 20250124202825.png|300]]
nohup¶
להריץ פקודה ברקע (בלי טרמינל פתוח)
כמו שלמדנו על [[מילון BASH#kill - להרוג תהליכים|hangup signal]], בעצם כשתוכנה מקבלת את הסיגנל שהטרמינל שהפעיל אותה "ניתק" (נסגר), היא הרבה פעמים תיסגר גם.
nohup יעשה שהיא לא תיסגר כשהטרמינל שלה מנתק.
-
nohup (command)
-
כל ההודעות שקשורות לפקודה הזו יירשמו בקובץ nohup.out
-
הקובץ ישמר בתיקיה שממנה ניתנה הפקודה, או ב-home במקרה שאין הרשאות כתיבה לתיקיה הזו
-
אפשר לשלוח את האאוטפוט לקובץ אחר באמצעות פקודה כמו
nohup rclone sync /local/folder remote:/remote/folder > /path/to/custom_output.log 2>&1 &
(כדי להבין שווה לקרוא את [[#STDERR & STDOUT]])
-
command &
-
הסמל של AND בסוף יגרום לפקודה לרוץ ברקע, כלומר משחרר לך בחזרה את הטרמינל. אבל, לסגור אותו יהרוג את הפקודה.
-
אם עושים גם NOHUP וגם & בסוף, גם נקבל את הטרמינל וגם נריץ את הפקודה ברגע
kill - להרוג תהליכים¶
kill (pid)
כדי לסגור תהליך
הרבה תהליכים יתעלמו מהסיגנל הרגיל, אפשר להגדיר kill -9 PID
כדי לשלוח סיגנל 9, שהורג תמיד.
killall <process name>
כדי לסגור את כל מה שהשם שלו מתאים לתבנית
-e
כדי שיעבוד על התאמות מדויקות בלבד
-I
כדי שיתעלם מהקייס
-i
כדי שישאל לפני החיסול
-g
כדי לחסל את כל התהליכים בקבוצה (של האחד שמתאים לחיפוש)
-s
כדי לבחור איזה signal יישלח
סיגנלים של kill
חיסול של תהליך באמצעות kill או killall הוא למעשה שליחה של סיגנל מסוים לתהליך הזה. יש כמה סוגים.
kill -signal PID
כדי לשלוח סיגנל מסוים
kill -l
כדי לקבל פירוט של כולם
SIGHUP
מחסל ומיד מתחיל מחדש
SIGKILL
הורג וזהו
kill -s SIGHUP <process ID>
-
חשוב לדעת שגם Ctrl+c זה סיגנל (INT - interrupt) וגם Ctrl+Z (TSTP - Terminal Stop)
-
הדפאולט סיגנל, אם לא מציינים עבור kill, הוא
term
(terminate)
![[Pasted image 20250124205026.png]]
![[Pasted image 20250124205429.png]]
-
HUP הוא ההפך מ nohup
-
לשים לב שהבדל חשוב שקיים בין חלק מהסיגנלים הוא האם הם נשלחים לתוכנה או לקרנל. לתוכנה זה עדין יותר, לקרנל זה "נגמרו הוויכוחים"
-
רק ה-Owner והסופריוזר יכולים לשלוח סיגנלים של kill לתהליך
killall¶
משמשת כדי לשלוח Kill signals לכמה תהליכים במקביל
killall [-u user] [-signal] processname
חייב להיות סופריוזר
killall -u tony *
להרוג את כל התהליכים של טוני
killall -TSTP rclone
לעשות סטופ לכל התהליכים שנקראים rclone
jobs, fg -- לפקודה שנפתחה מהטרמינל הנוכחי¶
jobs
כותב איזה תהליכים יש ברקע שרצו מהטרמינל הנוכחי ושאין להם nohup. לא עובד עם Nohup.
fg %(jobnumber)
מחזיר את מס' התהליך שנבחר ל-foreground. ואז אפשר לעשות לו ctrl+c ולעצור אותו.
Ctrl+Z - להקפיא פקודה¶
כמו שאפשר להרוג פקודה עם Ctrl+C, אפשר להקפיא פקודה ולהעביר אותה ל-background באמצעות Ctrl+Z
- כמו כשנעשה &, אנחנו נקבל אאוטפוט עם מס' הג'וב שעבר לרקע
bg - להמשיך פקודה ברקע¶
-
נניח שהרצנו את
xlogo
(חלון X11 גנרי) ועשינו לו Ctrl+Z כדי להקפיא ולהזיז לרקע (שחררנו את הטרמינל). -
איך מחזירים את הפקודה לפעולה? אפשר לעשות
fg %jobnumber
כמו שלמדנו, ואז נקבל אותו שוב פעיל ב-foreground (תופס לנו את הטרמינל) -
או שאפשר לעשות
bg %jobnumber
כדי להחזיר את התוכנה לפעולה ברקע ולשחרר לעצמנו את הטרמינל
nice¶
פקודה לניהול סדר העדיפויות של תהליכים במעבד
לכל תהליך יש niceness, שזה כמה הוא "חביב" מבחינת ניצול משאבים
ככל שתהליך פחות נחמד, העדיפות שלו גבוהה יותר
ה-niceness נמדדת ממינוס 20 (הכי פחות נחמד, הכי גבוה בעדיפות) עד 19 (הכי נחמד, הכי נמוך בעדיפות)
nice -n <value> process-name
כדי להריץ תהליך עם niceness מסוים, למשל:
nice -n 19 cpu-hog
כדי להריץ את סיפיו-הוג במקסימום נחמדות
הברירת מחדל היא בד"כ niceness = 0
renice¶
בהמשך ל-nice, זו פקודה שמאפשרת לשנות את הפריוריטי של תהליכים לאחר שהם התחילו
renice -n <value> PID
power settings¶
אפשר להשתמש בטרמינל כדי לעשות halt, poweroff, reboot ו-shutdown
sudo reboot
לריבוט
sudo shutdown -option <timer>
בשביל כל השאר
האפשרויות: -h ל-halt
-r ל-reboot
-s ל-shutdown
-p ל-poweroff
הטיימר יכול להיות now
או נניח 50s
או 60m
עוד פקודות תהליכים¶
![[Pasted image 20250124210353.png]]
free¶
מדפיסה מידע לגבי שימוש בזיכרון.
שדות מעניינים:
- השדה buffers מראה "באפרים" של כתיבה וקריאה מחומרה איטית, שבמקום להיעשות בזמן-אמת, נעשות על זיכרון וירטואלי/זמני שנערם עד שהחומרה עובדת/אוגר ממנה מידע בזמן שהיא עובדת.
journalctl¶
ה-Log הכי טוב לעקוב אחריו כדי לראות מה המערכת עושה בגדול.
הגרסה הידנית זה לעשות tail -f /var/log/syslog
במערכות מודרניות שיש להן systemd אפשר לעשות פשוט journalctl -f
(שניהם אולי עם סודו)
חבילות¶
Zypper¶
[[Gnome 47 & OpenSUSE#Zypper|כאן]]
OPI¶
נותן לנו לחפש חבילות ב-AUR
חיפוש: ``opi aur package-name
להתקין ולשדרג package file¶
אם הורדנו .deb או .rpm, לא צריך את ה-GUI, אפשר להתקין באמצעות ה[[לינוקס - כללי#Packaging System|לואו-לבל טול]] שלנו.
לשים לב שבאופן הזה לא יהיה dependency resolution - אם הכלי שלנו יזהה dependency חסרה הוא יצא עם exit code error
dpkg -i package_file
בדביאן
rpm -i package_file
בפדורה וכו'
כדי לשדרג גרסה של חבילה באמצעות קובץ:
dpkg -i package_file
(אותו דבר)
rpm -U package_file
(שוב מבקשים ממני לכתוב את השם ולא את ה-path... מניח שזה עובד אם אתה על התיקיה הנכונה)
מידע נוסף על חבילות (לואו-לבל)¶
dpkg -l
או rpm -qa
כדי לקבל רשימה של כל החבילות (מהלואו-לבל טול)
dpkg -s packagename
או rpm -q packagename
כדי לבדוק אם חבילה מותקנת...
כדי לבדוק על קובץ מסוים, איזו חבילה התקינה אותו:
dpkg -S file_name
או rpm -qf file_name
רשת¶
בדיקות IP¶
- Display External IP:
curl ifconfig.me
w (who)¶
w
נותן מידע אודות יוזרים במערכת
ping¶
ping hostaddress
שולח Packet בשם ICMP ECHO_REQUEST, שכברירת מחדל מכשירי רשת מגיבים אליו, וכך ניתן לאמת את החיבור.
לעתים רשתות חסומות ל-packet הזה מטעמי אבטחה, נפוץ שה-firewall מוגדר כך שהמחשב יתעלם מהן.
ping linuxcommand.org
לדוגמה כדי לבדוק חיבור
שולח packets ב-interval מוגדר עד שהוא עושה timeout או שמפריעים לו
בסוף ping
כותב סיכום - רשת שפועלת כראוי היא כזו שרושמת 0 percent packet loss
traceroute¶
תוכנת טרמינל, לפעמים במקומה יש את tracepath
הדומה.
נכתבת ככה traceroute hostaddress
מדפיסה לנו את ה-"hops" שהחיבור צריך לעבור מה-local system ל-host address, כלומר את כל התחנות שבדרך.
-
כל תחנה היא בעצם ראוטר שאנחנו עוברים - אנחנו מתחברים לראוטר ראשון וממנו "מנותבים" x פעמים מראוטר לראוטר.
-
נראה מידע על כל ראוטר, ואיפה שהמידע מוסתר נראה כוכביות במקום
-
לפעמים להריץ
traceroute -T
או-I
יעזור לנו לראות מידע של ראוטרים שמציגים כוכביות
ip¶
תוכנת טרמינל, מאפשרת לנו להשתמש במגוון יכולות רשת של הקרנל, מחליפה את ifconfig
הישנה.
ip address show
כדי לראות את כל ה network interfaces שלנו
network interface הם החיבורים השונים שלנו לרשת.
loopback interface הוא חיבור רשת וירטואלי שהמחשב משתמש בו כדי "לתקשר עם עצמו"
en הוא חיבור אית'רנט
'wl הוא חיבור אלחוטי
-
חשוב לחפש ב-interfaces:
-
- את הביטוי
state UP
שאומר שהממשק פועל
- את הביטוי
-
כתובת ip תקנית בשדה
inet
-
במערכות שמשתמשות ב-DHCP, השדה
inet
מאשר גם שה-DHCP פועל
ip route show
כדי לראות את ה routing table
-
לקרוא על זה בהזדמנות
-
DEFAULT הוא הערך לכל כתובת שלא צוינה במפורש
ip [-options] object [command]
ftp¶
תוכנת טרמינל קלסית, נקראת על שם הפרוטוקול שהיא פועלת עליו: file transfer protocol
התוכנה ftp
משמשת כדי לתקשר עם ftp servers
, שהם hostים שמחזיקים קבצים שניתן להוריד באמצעות החיבור.
כש-ftp מעביר קבצים, הוא שולח שמות משתמשים וססמאות ב-cleartext
, כלומר בלי שום הצפנה.
לכן, כיום יש בשימוש כמעט רק שרתי anonymous ftp, שניתן להתחבר אליהם באמצעות השם anonymous ואיזושהי ססמה. (הם מוצפנים וכו' ומיועדים שתיכנס אליהם בלי להכניס credentials שאתה באמת מזוהה איתם).
ftp fileserveraddress
כדי להתחבר לשרת
נתבקש להכניס name
- מקובל כאמור לשים anonymous
נתבקש לשים password
יש שרתים שיקבלו blank, יש שרתים שירצו ססמה בפורמט של מייל: אפשר לעשות user@example.com
cd path/in/ftp
לרוב קבצים ישבו ב-cd pub/something
אפשר להשתמש בפקודת ls
כדי לראות מה יש במקומות שונים בשרת
get filename
כדי להוריד מהתיקיה שאנחנו נמצאים עליה בשרת
הקובץ ילך ל-working directory האחרונה במערכת המקומית
bye, quit, exit
מסיים את החיבור וסוגר את ftp
lftp¶
תוכנה שהיא שדרוג של ftp, עובדת מאוד דומה אבל יש לה עוד הרבה אפשרויות
curl¶
באופן כללי, מורידה את העמוד הראשון של ה-URL שנספק לה ונותנת אותו כ-standard output
יכולה לקבל גם כמה urlים
תומכת בפרוטוקולים רבים כמו http, https, ftp, imap, pop3, sftp ועוד
curl URLaddress
השימוש הבסיסי
![[Pasted image 20250126021710.png|500]]
איך curl מורידה לנו קבצים במקרים מסוימים?
wget¶
עוד תוכנת טרמינל להורדה של קבצים. תומכת ב-web וב-ftp.
אפשר להוריד קבצים מרובים.
השימוש הבסיסי זהה ל-curl:
wget URLaddress
כדי להוריד את העמוד הראשון
- הרבה אפשרויות מיוחדות שאין ב-curl
ssh¶
מערכות UNIX ניתנות לניהול מרחוק כבר הרבה זמן. בהתחלה, לפני האינטרנט, היה אפשר להשתמש ב-remote host באמצעות rlogin
ו-telnet
- שתיהן חלקו את הבעיה של ftp
והעבירו מידע רגיש ללא הצפנה. לכן בעידן המודרני יש לנו את ssh
- secure shel
הפרוטוקול החדש פותר שתי בעיות עיקריות:
-
הוא מאמת שה-host הוא מי שהוא טוען שהוא (ומונע man in the middle attacks)
-
הוא מצפין את כל התקשורת בין ה-local וה-remote host
-
ברוב המערכות של לינוקס יש אימפלמנטציה של ssh בשם
OpenSSH
, שמגיעה מ-OpenBSD Project. -
ל-OpenSSH יש חבילות client (שנועדו להתחבר להוסטים) וחבילות server (שנועדו להיות הוסט ולקבל חיבורים) - כדי לקבל חיבורים צריך לוודא שיש לך את
OpOpenSSH-server
-
כדי לקבל חיבורים, אם יש לך פיירוול, צריך לאפשר חיבורים נכנסים בפורט TCP 22
-
כשנוצר חיבור SSH, למעשה נוצר encrypted tunnel בין הלוקאל והרמוט. התעלה הזו היא תומכת בהעברה של פקודות בין שתי המכונות, ובסוגים נוספים של network traffic, ולמעשה מהווה VPN (Virtual Private Network) בין שתי המכונות.
-
דוגמה מעניינת לשימוש בזה: X11 הוא display server. אפשר להריץ תוכנה במכונה אחת ולקבל את הפלט (חלון עם ממשק גרפי) במכונה ששלחנו ממנה את הפקודה להוסט.
ssh hostaddress
כדי להתחבר לרמוט הוסט
בחיבור הראשון הוא יכתוב לנו שהוא לא יכול לאמת את האותנטיות. זה בגלל שהוא לא מכיר את ההוסט. נעשה y
ונכניס ססמה. אחרי שמתחברים אנחנו על remote shell session עד שנכניס את הפקודה exit
.
- מזינים רק ססמה כי ssh מניח שהיוזרניים הוא השם של היוזר שמפעיל את הפקודה. אם אנחנו רוצים להתחבר עם יוזרניים אחר, נעשה ככה
ssh username@hostaddress
ואז נכניס את הססמה.
- לפעמים נקבל התראה כזו, על כך ש-ssh לא הצליח לאמת את ה-Host Key
![[Pasted image 20250127001318.png|500]]
-
סיבה אפשרית אחת היא שיש man in the middle attack (מישהו התלבש על ההוסט). זה לא מאוד פופולרי כיום כי כולם יודעים ש-ssh מזהיר מזה. אפשרות יותר סבירה היא שההוסט השתנה מאז הביקור האחרון (עבר עדכון מערכת או משהו נניח).
-
אם החלטנו שזה לא המצב, אפשר להתעלם מהאזהרה באמצעות
ssh-keygen -f "/home/me/.ssh/known_hosts" -R "remote-name"
- זו למעשה דרך אוטומטית למחוק את ה-Host Key הלא-תקין מ-
-
~/.ssh/known_hosts
-
באזהרה שנקבל כתוב ה-path תחת הכותרת
offending key in
, וכתוב שם גם באיזו שורה הוא נמצא, ככה:path/to/host_file:42
בשביל שורה 42, למשל. -
לאחר שנמחק את ה-Host Key שכבר לא עובד, ssh יוכל לקבל אותנטיקציה חדשה מההוסט
פקודה בודדה באמצעות ssh¶
- לא חייב להתחבר לרמוט הוסט, אפשר גם לשלוח לו פקודה יחידה, שהאאוטפוט שלה יודפס על המערכת המקומית.
ssh remote-name command
אפשר גם להשתמש ב-redirectים וב-pipeים על האאוטפוט של הרמוט הוסט, וזה יפעל ברמת המערכת המקומית. למשל:
`ssh remote-name 'ls *' > dirlist.txt
יכין רשימת ls של כל הקבצים ברמוט הוסט, וידפיס אותה לקובץ dirlist שנמצא ב-working directory המקומית! ולא בהוסט.
-
כדי לתחום אילו פקודות הולכות ל-host ואילו יקרו על המכונה שלנו - משתמשים בגרשיים.
-
יש לזכור את העיקרון -
'command'
בגרשיים עוברת כ-string ולא כפקודה (ללא expansion). אבל ה-string היא ללא הגרשיים - ואז הפקודה הופכת ל-command
. -
אז אם אנחנו צריכים להעביר פקודות להוסט, נעטוף אותן בגרשיים כדי שיקראו כ-string ע"י המערכת המקומית בשלב הראשון, ואז יעברו כפקודות בלי גרשיים כאינפוט להוסט.
ssh remote-name 'ls * > dirlist.txt'
יעביר את הפלט של ה-ls לקובץ dirlist *ב-root של ה-host, כי הפקודה עברה במכונה כסטרינג, ואז אל ההוסט בלי הגרשיים,, כלומר כ-command!
WSL to Linux SSH¶
- בגדול זה מדריך לאיך להתחבר לנייח שלי מהנייד שלי...
- על ההוסט:
- מוודאים שיש לנו את openssh-server
- בודקים את האייפי שלנו באמצעות
hostname -I
(המספרים הוא לרשת מקומית, הארוך הוא לרשת ציבורית - שמים אותו בתוך[]
כשמתחברים) - עושים
sudo service ssh start
(כי אין לנו systemd בשביל systemctl) - כשנרצה לסגור את ה-SSH (פרצה להאקרים...) נעשה
sudo service ssh stop
- על המחשב שמתחבר:
- עושים את ה-
ssh username@ip
, מכניסים ססמה ושלום על ישראל - אם נכנסים מ-tmux session ל-tmux session, כדי לצאת פשוט להרוג את הסשן במחשב שהתחברנו ממנו...
scp & sftp¶
- נכללים בחבילות של [[מילון BASH#ssh#|OpenSSH]] ומיועדים לאפשר העברה והעתקה של קבצים באמצעות הפרוטוקול
scp¶
-
הפקודה
scp
עובדת די דומה ל-cp
, רק שצריך לציין גם את ההוסט של ה-path, ולהפריד בין שם ההוסט ל-path בנקודותיים:
-
scp remote-name:path/to/file remote-name:path/to/destination
-
(נתבקש להזין ססמה להוסט)
-
קיצורי דרך הולכים למכונה המקומית, למשל כדי להעתיק קובץ ל-working directory המקומי:
-
scp remote-name:pathtofile .
-
כמו עם
ssh
, אנחנו יכולים להשתמש בשם משתמש שאינו היוזרניים שלנו באמצעות@
, ככה: -
scp username@remote-name:path/to/file remote-name:path/to/destination
sftp¶
-
חבילה שמחליפה את
ftp
ועושה אותו דבר ב-encrypted tunnel במקום ב-cleartext -
לא צריכה שלהוסט יהיה ftp server, רק שיהיה לו חיבור ssh ואפשר להשתמש בו כמו ב-ftp (להעביר ממנו קבצים)
-
sftp remote-name
כדי להתחבר -
זה יבקש מאיתנו ססמה
-
כמו שלמדנו עם [[מילון BASH#ftp#|ftp]], ננווט עם פקודות כמו
cd, ls
וכו', נוריד קובץ עםget filename
ונסיים את הסשן עםbye
מערכות קבצים/devices¶
[[לינוקס - כללי#Filesystem Tree#|הקדמה]]
mount¶
הפקודה mount
משמשת כדי לעשות mount ל-file systems
אם נשתמש בה בלי ארגומנט, נקבל רשימה של mounter devices עם קצת מידע עליהן.
כשאנחנו רוצים לעשות mount ל-mountpoint חדש, אנחנו פשוט צריכים לדאוג שהתיקיה הזו תהיה קיימת. למשל mkdir /mnt/flashdrive
mount -t vfat device-name path-to-mountpoint
הדגל -t
משמש כדי לפרט את סוג מערכת הקבצים - במקרה הזה vfat
שזה אותו דבר כמו לכתוב FAT32
l.
ה-device-name
זה השיט שנראה ככה בערך /dev/sda1
וכו'
ה-path-to-mountpoint
זו התיקיה שיצרנו, שממנה מתחיל ה-file tree של ה-device
פקודה שלמה לדוגמה:
mount -t btrfs /dev/sdc /mnt/flash
לעשות mount ל-Image file¶
אם יש לנו קובץ iso שאנחנו רוצים לעשות לו mount כאילו הוא device:
משתמשים בהגדרה
-o loop
ובפורמט מערכת הקבצים iso9660
למשל ככה mount -t iso9660 -o loop image.iso /mnt/iso_image
הפורמט הוא למעשה:
mount -t iso9660 -o loop name-of-iso-file path/to/mount/point
כמו שרגיל לאחרונה, לא path אלא שם הקובץ. להיות על ה-directory הנכונה!
umount¶
כדי לעשות unmount ל-storage device נעשה umount devicename
(הכוונה לשמות שנראים ככה /dev/sdc
וכו')
למה עושים unmount?
כי הכתיבה והקריאה מ-devices נעשית באמצעות buffer: במקום להיות עסוק כל היום בקריאה וכתיבה מחומרה איטית, המחשב שומר את האינטרקציות שלו עם ה-device בזיכרון זמני, שהוא הבאפר. כשאנחנו עושים
umount
אנחנו בין היתר אומרים למחשב לרוקן את ה-buffer הזה כדי שנוכל לנתק את המכשיר. אם לא נעשה את זה, אנחנו עלולים לגרום ל-File system corruption. [[מילון BASH#free|עוד מידע, פקודת free]]
lsblk¶
נותנת רשימה של כל ה-block devices (אחסון) שמחוברות למערכת, mounted או לא.
זו דרך לבדוק שם של device, בנוסף לדרך שמפורטת [[לינוקס - כללי#devices|כאן]]
ברגע שיש לנו את השם, הדרך לרפרר ל-device היא /dev/name - זה בגלל שהקבצים של ה-device יושבים ב-/dev בשם של ה-device
parted¶
תוכנת טרמינל שמאפשרת ליצור partition schemes ו-file systems (לפרמט דיסקים בקיצור)
sudo parted /dev/name
כדי להתחיל
חייב לרפרר ל-device בשלמותה, בלי מס' ה-partition (אם יש לנו /dev/name1
ו-/dev/name2
למשל)
אחרי שהתחלנו:
print
כדי לקבל את הפרטישן לייאאוט הנוכחי של הדבייס
rm partition-number
כדי למחוק פרטישן לפי המספר
(לפני שעושים חלוקה חדשה חייב למחוק את כל הפרטישנז, אם יש רק אחת למשל אז rm 1
mkpart
כדי ליצור פרטישן חדשה
נישאל את השאלות הבאות:
(parted) mkpart
Partition type? primary/extended? primary
File system type? [ext2]? ext4
Start? 1
End? 120000
התשובות הן לדוגמה. מה שחשוב לשים לב אליו זה start ו-end, מדובר בהתחלה ובסיום של הפרטישנז על הדיסק לפי קפיצות של 1mb כאשר מתחילים ב-0 ומסיימים בסך ה-mb שיש לדיסק.
בדוגמה שאנחנו משתמשים בה, כדי ליצור עוד פרטישן שמתחילה מיד לאחר שהראשונה מסתיימת, נעשה ככה:
(parted) mkpart
Partition type? primary/extended? primary
File system type? [ext2]? ntfs
Start? 120001
End? 240000
(הפעם יצרנו ntfs, כנראה לשימוש בווינדוז)
quit
כדי לצאת מפארטד
mkfs¶
נועד כדי לייצר file system מסוים על disk partition - בעצם לפרמט את הפרטישן
sudo mkfs -t file-system-format -L file-system-name /dev/name
למשל:
sudo mkfs -t ext4 -L EXT4_Disk /dev/sdd1
כברירת מחדל, הפקודה תעשה גם bad block checking, שזה דבר שלוקח הרבה זמן. כדי לוותר, נעשה:
sudo mkfs -t file-system-format --quick -L file-system-name /dev/name
ה-LABEL שניתן למערכת הקבצים (אחרי -L
יהיה השם של ה-mountpoint, כאשר הלייבל/הפרטישן בעצם תהיה תיקיה חדשה ב-mountpoint הכללי שהוגדר ל-device)
fsck¶
קיצור של File System Check
למערכת יש רוטינה של בדיקת file system integrity באמצעות התוכנה הזו
-
הערך האחרון ב-fstab קובע את הסדר של הבדיקה, מה שיש לו 0 לא נבדק
-
הפקודה גם מנסה לתקן בעיות באמצעות lost+found
sudo fsck /dev/name
ה-device צריכה להיות unmounted
- אם במהלך ה-boot זוהה file system corruption, לרוב המערכת תנתב אותנו ל-fsck לפני כל דבר אחר
dd¶
אנחנו רגילים לחשוב על הדאטה שלנו בצורה של תיקיות וקבצים, אבל אפשר גם לחשוב על כל block device כאוסף גדול של data blocks
לכן, אפשר להשתמש ב-dd כדי להעתיק devices ולהעביר את המידע שבהן
dd if=input_file of=output_file [bs=block_size [count=blocks]]
מה שבסוגריים לא חובה.
לעתים קוראים ל-dd
גם destroy disk
, כי זו פקודה מאוד עצמתית שקל לטעות בה, אז לשים לב לכתיבה נכונה. (במציאות זה data definition
)
דוגמה - להעתיק USB DRIVE אחד לשני (עותק מושלם):
sudo dd if=/dev/sdb of=/dev/sdc
אפשר (ומומלץ) לפרק את הפקודה לשני חלקים: העתקה של המידע לקובץ חיצוני, והעתקה של הקובץ ל-Drive השני. משתמשים בקובץ img או בקובץ iso
ככה:
sudo dd if=/dev/sdb of=flash_drive.img
ואז ככה
sudo dd if=flash_drive.img of=/dev/sdc
(הוא מראש מניח שאנחנו משתמשים ב-file, ולהשתמש מיד ב-device name זה הקיצור דרך, לא להיפך)
לכתוב CD-ROM באמצעות dd¶
-
נניח שיש לנו דיסק של אובונטו שאנחנו רוצים לייצא ממנו קובץ ISO
-
dd if=/dev/cdrom of=ubuntu.iso
-
עובד בשביל data dvd, לא עובד בשביל audio CD! בשביל לחלץ מידע מדיסקים של מוזיקה אפשר לבדוק את הפקודה
cdrdao
genisoimage¶
תוכנת טרמינל שיודעת להפוך תיקיית קבצים שלמה ל-ISO IMAGE
נשים את כל הקבצים של ה-CD בתיקיה מסוימת ונריץ
genisoimage -o cd-name.iso -R -J path/to/cd/directory
-R
מפעיל את Rock Ridge extensions, משהו שמספק מטאדאטה
-J
מפעיל Joilet extensions - מאפשר שמות ארוכים בווינדוז???
בעבר, כל מה שקשור ל-CDROM ו-DVD התבצע באמצעות חבילה בשם
cdr-tools
שכללה אתmkisofs
ואתcdrecord
.היוצר שינה משהו ברשיונות והם כבר לא מתאימים ל-GNU
אז קהילת הלינוקס יצרה שני פורקים שיחליפו את הכלים האלה:
wodim
ו-genisoimage
wodim¶
- משמש כדי למחוק דאטה מדיסק שניתן לשכתוב, נראה גם "blanking it"
wodim dev=/dev/name blank=[fast]
כותבים את fast
בלי הסוגריים. יש עוד אפשרויות לסוג ה-blanking (המחיקה) שיתבצע. פאסט זה המהיר והרגיל.
-
בנוסף יכול לכתוב דאטה על דיסק שניתן לשכתוב:
-
wodim dev=/dev/name image-file-name.iso
-
יש מלא אפשרויות נוספות כמו
disc-at-once
אוtrack-at-once
, לקרוא אתman wodim
אם מעניין
sha256sum¶
פרוטוקול לבדיקת integrity של קבצי image. נניח שהורדנו iso של לינוקס כלשהו ואנחנו רוצים לראות שהקובץ אינו פגום - נשתמש בזה.
זו בעצם תוכנה מחודשת לתוכנה בשם md5sum
שהייתה בשימוש בעבר.
-
ה-checksum הוא בעצם ביטוי של הדאטה של הקובץ בערכים הקסדצימליים.
-
שינוי קטן במבנה הבינארי של הדאטה ייצור שינוי משמעותי בערך ההקסדצימלי של ה-checksum
-
כשאנחנו מורידים קובץ IMAGE כלשהו, נחפש אם סיפקו לנו קובץ checksums
-
אם כן, הוא יראה למשל ככה:
7a04b54830004e945c1eda6ed6ec8c57ff4b249de4b331bd021a849694f29b8f *linuxmint-22-cinnamon-64bit.iso
78a2438346cfe69a1779b0ac3fc05499f8dc7202959d597dd724a07475bc6930 *linuxmint-22-mate-64bit.iso
55e917b99206187564029476f421b98f5a8a0b6e54c49ff6a4cb39dcfeb4bd80 *linuxmint-22-xfce-64bit.iso
אפשר לראות פה את ערך ה-checksum התקין עבור כל קובץ
- עכשיו צריך להוציא את ה-checksum העדכני של הקובץ הרלוונטי ולבדוק אם הוא מתאים בדיוק.
sha256sum -b name-of-image-file.iso
הדגל -b
מסמל ל-sha256sum שאנחנו בודקים קובץ בינארי ולא txt
-
אפשר גם לבקש ממנו להשוות בשבילנו את ה-checksum עם מה שנמצא בקובץ:
-
sha256sum -c --ignore-missing name-of-checksum-file.txt
הדגל -c
אומר לו לבצע את ה-check שמדובר עליו (כנגד הקובץ)
הדגל --ignore-missing
אומר לו לבדוק רק קבצים שקיימים בתיקיה שלנו (הקובץ checksum מכיל כמה sums והוא כותב לנו את השם של כל אחד אחרי ה-*
. אנחנו רוצים שיבדוק קובץ שקיים אצלנו, ושיתעלם מקובץ שלא קיים)
לא לגמרי הבנתי איך sha256sum יודע איפה הקבצים שהוא צריך להשוות לקובץ הטקסט... אני מניח שהכוונה היא שהם יושבים באותה תיקיה. אבל לא בטוח שהבנתי נכון.
חידודים: קודם כל, כן, הוא יודע כי ה-checksum file והקובץ שנבדק יושבים באותה תיקיה.
שנית כל: הפרמוט של קובץ ה-checksum מאוד פשוט:
checksumstring *filename
ואם יש עוד קבצים, בשורות חדשות.
du¶
du -s
מדפיס רשימה של כל הפאת'ים בדיסק וכמה מקום הם תופסים
אפשר לעשות לזה pipe ל-sort ואז למשל ל-head בשביל הטופ x ערכים (נניח לפי משקל)
du -s /usr/share/* | sort -nr | head
לא לשכוח שסורט עם דגל אן מסדר לפי גודל מספרי, אז משקל במקרה שלנו
הדפסה¶
pr¶
- מפרמט קובץ או STDIN להדפסה, מאפשר להוסיף header margin ו-footer margin
זה הפורמט
pr -l pagelength(lines) -w pagewidth(columns) sourcefile.txt
![[Pasted image 20250201161931.png|500]]
ps2pdf¶
- ממיר קבצי PostScript לקבצי PDF ככה:
ps2pdf originalfile.ps desiredfilename.pdf
-
הפקודה היא חלק מחבילת
ghostscript
שמותקנת על רוב מערכות הלינוקס -
בלינוקס יש הרבה תוכנות המרה שאפשר למצוא על ידי חיפוש של כל התוכנות שנקראות
x2x
אוxtox
ב-/usr/bin/*
CUPS¶
-
ללינוקס כיום יש את CUPS - Common Unix Printing System שמספקת תוכנות ניהול הדפסה ודרייברים, ואת Ghostscript שמתפקדת כמפרש PostScript ואחראית על ה-RIP
-
בקיצור סויטת תוכנות הדפסה
-
מארגנת את ההדפסה לפי Print Queue שכולל jobs ו-users, מבוסס על הדפסה בימי קדם, כשהייתה למשרד מדפסת מרכזית שכולם שלחו אליה הדפסות
-
עבודות (jobs) נחשבות ב-'חניה' (parked) עד שהן מועברות להדפסה (spooled)
-
הכל ממודל לפי שתי מערכות הדפסה מימי קדם, כשהייתה לנו רק הדפסה מרכזית: מערכת אחת היא ברקלי Berkeley, ואחרת היא System V
lpr & lp¶
-
השיטה שלנו לשלוח הדפסות ל-CUPS
-
יש גם
lpr
וגםlp
שהן מאוד דומות -
output | lpr
שולח להדפסה למדפסת שהיא ברירת המחדל שלנו -
lpr -P printer-name
שולח למדפסת אחרת שנבחר -
lpstat -a
יכתוב לנו איזה מדפסות המערכת מכירה -
הרבה פעמים אפשר להשתמש בפיצ'ר מוכר של לשלוח ל-pdf במקום להדפסה אמתית. צריך לבדוק ב-
lpstat
אם המערכת מאפשרת; אם לא, אפשר להתקיןcups-pdf
כדי שתהיה לנו אפשרות (המטרה היא גם ליצור pdf, אבל בעיקר לקבל preview להדפסה)
![[Pasted image 20250201162256.png|500]]
- ל-
lp
יש אפשרויות קצת יותר מתקדמות:
![[Pasted image 20250201162348.png|500]]
a2ps¶
-
תוכנה שממירה כל דבר ל-PostScript, במקור נועדה להמיר ASCII
-
היא לא שולחת ל-STDOUT אלא שולחת למדפסת של המערכת... אז היא לא באמת תוכנת המרה כמו שהיא תוכנת הדפסה
![[Pasted image 20250201162626.png|500]]
-
יש עוד הרבה אפשרויות ב-man page
-
יש גם את
enscript
שעובדת דומה אבל רק עם text input
lpstat¶
-
נותנת לנו מידע על הפעילות (זמינות וכו') של מדפסות מוכרות למערכת
-
lpstat -a
זה הרגיל -
lpstat -s
בשביל קצת יותר מידע
![[Pasted image 20250201163012.png|500]]
- עוד אפשרויות ב-man
lpq¶
-
lpq
מראה לנו את הקיו הנוכחי של המדפסת שהיא ברירת המחדל -
מעניין אם אפשר לראות של עוד מדפסות
lprm & cancel¶
-
שתי תוכנות שנועדו לבטל print jobs, ולהסיר אותן מהקיו
-
lprm
היא לברקלי סטייל -
cancel
היא ל-System V -
cancel number-of-printjob
-
lpq
יעבוד על הדפאולט -
שתי התוכנות יכולות לבטל עבודות לפי כל מיני סינונים - לקרוא ב-man page
קומפילציה¶
make¶
-
פקודה שמריצה הוראות של קובץ makefile, שיצרנו בתוך תיקיה של סורס קוד, אחרי שהרצנו את קובץ ה-
configue
באמצעות./configure
ויצרנו את ה-makefile -
כתבתי הסבר מפורט על קומפילציה ועל make [[לינוקס - כללי#תהליך הקומפילציה|בקובץ הכללי, 'תהליך הקומפילציה']]
טרמינולוגיה (לא פקודות)¶
Exit Gracefully¶
"Exit gracefully" refers to the process of closing or terminating a program, process, or system in a controlled, orderly manner, ensuring that it does not leave any unfinished tasks, errors, or data inconsistencies behind. The goal is to stop operations in such a way that the system remains stable, and no damage occurs to files or resources.
argument¶
המבנה הכללי של פקודה:
command -options arguments
ה-argument הוא ה-item שהפקודה פועלת עליו (בהתאם לפקודה ולדגלים/אפשרויות שנבחרו עבורה)
End of Life¶
אם עושים control + d זה בעצם מסמל לטרמינל שהסטנדרט אינפוט שלו הסתיים.
אם נניח נעשה cat
בלי ארגומנט, הוא יחכה שנקליד לו אינפוט.
אפשר לכתוב דברים, ואז לעשות ctrl + d כדי לאותת לו שסיימנו (הוא ידפיס את הטקסט)
expansion¶
כשאנחנו עושים אנטר לפקודה, יש רכיבים שעוברים מיד "הרחבה" והופכים לטקסט אחר.
ככה למשל עם כוכבית, שמסמלת כידוע "כל תו"
אם נעשה echo *
זה לא ידפיס כוכבית, אלא ידפיס את כל הקבצים המתאימים ב-working dir
לאופן שבו גלובים 'מתרחבים' קוראים pathname expansion
קבצים חבויים:
לעשות
echo .*
יתן לנו את כל הקבצים החבויים, אבל גם את התיקיה הנוכחית ואת התיקיית אם שלה, שהן.
ו-..
.כדי לקבל תוצאה בלעדיהן, צריך לעשות
echo .[!.]*
, שזו תוצאה שמתרחבת לכל קובץ שמתחיל בנקודה ולאחריו בא לפחות תו אחד.
ls -A
נותן לנו את התוצאה הנכונה בקלות
Tilde expansion
זה איך ש-~ הופך ל-home
אפשר גם ~user בשביל ה-home של יוזר ספציפי
Arithmetic expansion¶
חידוד: כשלעצמו, ביטוי בתוך
((...))
לא צריך $ בהתחלה. לכתוב את הסוגריים כשלעצמן זה כמו לכתוב פקודה, שיכולה לעשות שני דברים: 1. לבצע פעולה אריתמטית (אם נכתוב ((a++)), אז נוסיף 1 ל-a 2. להחזיר סטטוס יציאה 1/0 (אמת/שקר לאופרטורים בינאריים, ומס' חיובי/שלילי לתוצאות שאינן בינאריות) רק כשאנחנו רוצים 'לרפרר' לתוצאה אנחנו צריכים להשתמש ב-$ למשל לפני echo או כאשר מגדירים משתנה לפי התוצאה.
שימוש בסיסי:
$((expression))
מתרחב לתוצאה של הביטוי המתמטי.
![[Pasted image 20250124021643.png]]
למשל echo $(($((5**2)) * 3))
יחזיר פשוט 75
לא תומך בשברים - אם נעשה חילוק שהתוצאה שלו לא שלמה נקבל integer (חילוק עם שארית) - אפשר לקבל את השארית עם % כמו שכתוב בטבלה
בסיסים:
- אפשר לפרמט את המספרים שאנחנו משתמשים בהם באמצעות בסיסים שונים (מספר 'רגיל' הוא אינטגר Integer, 'בסיס 10' - יש לנו אוקטאליים שהם בסיס 7, ועוד)
(הפרמוט הוא פשוט באיך שנכתוב את המספר)
פעולות:
- יש Unary Operators שהם +, - ו-~, בכנות, לא הבנתי מה הם עושים
- יש את כל פעולות המתמטיקה הרגילות:
לגבי % (שארית) - אם עושים a % b אנחנו נקבל את שארית החלוקה של a ו-b. שימושי למשל כדי לבדוק אם השארית 0 ולהפסיק ש-b כפולה של a.
השוואה:
- כדי לבדוק אם a שווה בערכו ל-b, נשתמש ב-'שווה-שווה' ==
הסיבה היא ש-'שווה' בודד הוא תמיד assignment:
אם נעשה למשל if (( var = 5 ))
, מה שיקרה זה שבתור התניה, אנחנו קובעים ש-var=5, וכל משתנה חיובי מחזיר 0/true (כשלעצמו), לכן ההתניה מקבלת true.
**חשוב לזכור שרק ב-test הישן **(`[...]`) אפשר להשתמש ב-`=` בודד להשוואה בין משתנים** (כי הוא מאוד ישן וחורג מהנורמה, שהיא == עבור השוואה)
לוגיקה
- אופרטורים לוגיים משמשים גם למתמטיקה, מדובר בכל אופרטור שמחזיר true or false (האאוטפוט יהיה באקסיט קוד 1 או 0 בהתאם)
~
מעניין ה-ternary opetator (האחרון ברשימה) - הוא לקוח משפת C והוא בעצם נוסחה לוגית קצרה שנכתבת כאופטרור עצמאי: אם הביטוי הראשון הוא true, אז תבצע את הביטוי השני; אם הביטוי הראשון false אז תבצע את הביטוי השלישי.
חשוב לשים לב שמדובר בלבצע את הביטוי השני או השלישי, כלומר, ניתן לבדוק ערך אמת עבור אופרטורים לוגיים, או לבצע שינוי בערך של משתנה מספרי.
((a<1?++a:--a))
בעצם יעשה toggle
אם a קטן מ-0, הוא יוסיף 1 ל-a; אם a גדול מ-0, הוא יחזיר אותו ל-0 (פעולה אחת ל-'הדלקה' ו-'כיבוי'.)
כדי לתת בביטוי 2 או 3 פקודה של assignment:
אי אפשר לכתוב פשוט a=b (לא ברור למה)
יש לכתוב בתוך סוגריים נוספות, ככה:
expr1?(a=b):(a=c)
אפשרויות Assingment - כמו שעושים "משתנה = ערך", ישנם עוד אופרטורים להגדרת משתנה:
~
חשוב לשים לב להבדל בין parameter++ ו-++parameter
הסינטקס הזה לקוח משפת C, וגם שם זה עובד ככה:
parameter++ מחזיר את המשתנה ואז מעלה אותו באחת
++parameter מעלה אותו באחת ואז מחזיר את המשתנה
echo $((parameter++))
יתן לנו את הערך של המשתנה ורק אז יעלה אותו באחת
echo $((++parameter))
יעלה את המשתנה באחת ורק אז ידפיס אותו
(עובד אותו דבר עם המינוסים)
פעולות על ביטים:
brace expansion¶
echo one-{A,B,C}-two
יתרחב ל-
one-A-two one-B-two one-C-two
לרישה קוראים premable ולסיפה קוראים postscript
אפשר לשים string עם quotes, ספרה או אות
בלי unquoted whitespace
אפשר גם לעשות zero padding:
{Z..A}
בשביל כל האותיות בסדר הופכי (מ-Z ל-A)
{01..15}
בשביל כל הספרות מ-01 עד 15
{001..15}
בשביל כל הספרות מ-001 עד 015
שימושי ליצירת קבצים ותיקיות
נגיד בא לי מלא תיקיות לפי שנה וחודש:
mkdir {2001..2010}-{01..12}
ייצור תיקיה לכל שנה וחודש
אז חשוב לזכור שאם עושים command {range}-{range}
אנחנו נקבל את כל ההצלבות האפשריות של הריינג'!
parameter expansion¶
- האופן שבו
$var
מתרחב לערך של המשתנה (הרגיל או הסביבתי) -
להקליד לא נכון את השם סתם יחזיר ערך ריק
-
נשתמש בגרשיים כדי לדאוג שהפרמטר יתרחב בצורתו המקורית לפעמים אנחנו רוצים להשתמש בפרמטר בתוך string גדול יותר, ורוצים שיתרחב כאילו היו לו גרשיים. כל פרמטר אפשר להציג לבאש כשהוא מוקף בסוגריים מסולסלות - נניח
$1
ו-${1}
הם שקולים מבחינתו. לכן, במקום לעשות:echo ""$1" was selected"
(שזו צורה לא נכונה - הגרש הראשון נסגר מיד עם השני...) נעשה:echo "{1} was selected
ואז באש יבין את 1 כמוקף בגרשיים בפני עצמו, וגם את הסטרינג כמוקף בגרשיים
אפשרויות להרחבת פרמטרים:
- אפשר להגדיר ברירת מחדל לפרמטר באמצעות
:=
נניח שאנחנו רוצים להדפיס את פרמטר $1, ואם הוא ריק, להדפיס "null" אז עושים ככה:${parameter:=<default>}
-
(אם 1 ריק, אז הביטוי יתרחב ל-default, ובנוסף, הערך של 1 יהפוך ל-default) לא עובד על positional parameters
-
אפשר להגדיר error output לפרמטר ריק באמצעות
:?
${parameter:?output}
יתרחב כרגיל אם יש ערך ל-parameter, ואם לא, הסקריפט יצא עם קוד 1, וידפיס אתoutput
ל-STDER -
אפשר להגדיר אאוטפוט שיחליף את הפרמטר דווקא כשיש לו ערך, באמצעות
:+
${parameter:+substitution}
ידפיס את substitution בכל מקרה בו יש ערך ל-parameter, ולא ידפיס כלום/ידפיס את הפרמטר (הינו הך) כשהפרמטר ריק -
יש שתי פקודות זהות שנועדו להדפיס את כל המשתנים שעונים לדפוס מסוים (כל המשתנים המתאימים שהוגדרו בסביבה של ה-shell):
${!prefix*}
${!prefix@}
(* ו-@ מתפקדים כאן כגלובים? מעניין אם אפשר לחפש*suffix
(כוכבית בהתחלה)
עוד אפשרויות לפרמטרים שהם סטרינגס:
-
${#parameter}
ידפיס מס' לפי כמות האותיות בערך הפרמטר אם הפרמטר הוא*
, זה ידפיס את מס' ה-positional parameters -
${parameter:offset:length}
ידפיס סטרינג רק החל מאות מסוימת בה אפשר לעשותparameter:5
כדי פשוט להתחיל מהאות החמישית אוparameter:5:10
כדי 'לחתוך' מהאות החמישית עד האות העשירית אפשר לעשותparameter:-5
כדי להתחיל מהאות החמישית מהסוף -
${parameter#pattern}
יסיר מההרחבה את התבנית שנגדיר מתוך הסטרינג אפשר ורצוי להשתמש בגלובים כדי להגדיר את ה-pattern#
יסיר את ההתאמה הקצרה ביותר אפשר לעשותparameter##pattern
כדי להסיר את ההתאמה הארוכה ביותר ואפשר לעשות%
או%%
במקום הסולמית, כדי להסיר את ההתאמות מהסוף ולא מההתחלה
Case conversion:
- מיועד כדי להדפיס פרמטר בצורה מנורמלת לתבנית מסוימת של lowercase & uppercase
command substitution¶
[[מילון BASH#$() פלט כמשתנה#|מדובר על פלט כמשתנה]]
בגדול אפשר להרחיב אלמנט מסוים כך שיהפוך לפלט של פקודה
echo $(ls)
יהפוך ל echo <output of ls>
סטנדרט ישן יותר לפעולה הזו שנתמך ב-Bash הוא פשוט להשתמש בגרשיים בודדות
echo 'ls'
history expansion¶
!88
יורחב להיות הפקודה ה-88 בהיסטוריה של באש
אפשר לבדוק את ההיסטוריה [[מילון BASH#history#|ככה]]
![[Pasted image 20250124180303.png|500]]
quotes¶
אנחנו משתמשים בגרשיים כדי להימנע מהתרחבויות לא רצויות של מרכיבים בקוד
echo $100
echo I want this space
לא יעבדו כי הטרמינל ירחיב או יתעלם בהתאם.
double quotes
-
נועד כדי לקשור טקסט עם רווחים, פקודות וכו' ל-ARGUMENT יחיד
-
במובן הזה קצת הופכי ל-single quote - אנחנו כותבים אותו כדי לאחד טקסט ככה שהוא יעבוד, עם פקודות והתרחבויות והכל, במקום לשמור אותו string
מתעלם מכל התווים המיוחדים חוץ מ$, ו-'
כלומר: הרחבת פרמטרים, אריתמטיקה ו-command substiution עדיין עובד
אבל כל השאר לא
echo "you can have spaces.txt"
single quotes
מבטלים את כל התווים המיוחדים, בגדול נועד כדי לוודא שמה שנכתוב יתפרש פשוט כ-text string
echo 'even $ or \ won't work here'
Compound¶
-
גם בתכנות וגם במתמטיקה, מדובר על אופרטור שפועל על שני איברים או יותר
-
לצורך העניין,
[[ ... ]]
(Double Brackets), אוinteger brackets
(( ... ))
Shell sessions¶
-
בכל פעם שאנחנו מריצים את באש, בעצם קורים כמה דברים:
-
אנחנו פותחים Terminal Emulator, שהיא תוכנה גרפית שיודעת לקבל אינפוט מ-command line ולהציג אאוטפוט על text buffer.
לתוכנה הזו יש קצת פקודות CLI משלה, שנועדו לתפעול הבסיסי שלה (לסייר בקבצים, לטעון תוכנה, לשנות הגדרות וכו')
-
אנחנו טוענים באמצעותו Shell Program: במקרה שלנו מדובר ב-Bash, אבל יש גם zsh, fish, narrow/posix shell ועוד
-
כשתוכנת ה-shell רצה (לפחות במקרה של Bash), היא למעשה יוצרת Shell Session:
היא טוענת את קבצי המערכת שלה, את קבציה הגדרות שלנו, מגדירה את המשתנים הסביבתיים, קוראת את ה-pathים עם כל התוכנות והסקריפטים שלנו, וכו' - ומקבלת תצורה שמשקפת את המצב הנוכחי של הקבצים האלה.
- מכאן ואילך, כל תהליך שה-shell תריץ יהיה Sub Shell חדש.
כלומר Shell session עצמאי, שיורש את כל התכונות שלו מה-Parent Shell, שזה ה-Session שהריץ אותו.
-
זו הסיבה שלהריץ תהליך חדש מתוך ה-Shell הנוכחי שלנו לא ירענן את bashrc עבור אותו תהליך. התהליך יורש את הסביבה של ה-Parent Shell שלו.
-
פייפים
|
, סוגריים עגולות()
ועוד כל מיני פקודות מריצים את האינפוט שלהם ב-Sub Shell Session, ולכן הקוד ששייך לאינפוט שלהם לא ישפיע על משתנים ב-Session שאנחנו עובדים ממנו -
באופן כללי: ה-Subshell לעולם לא יכול להשפיע על התכונות של ה-Parent Shell - זה יחס היררכי.
-
הפוך דווקא אפשרי: הפקודה
export
מייצאת ערך מסוים לכל ה-Subshells של הסשן שהריץ אותה.
זו הסיבה שאנחנו שמים export למשתנים ב-bashrc, אנחנו רוצים שיגררו גם ל-child processes שלנו.
אבל אפשר גם להגדיר משתנה ולעשות export var
(או לעשות export var=value
ולחסוך שורה), וכך לשנות את הערך של המשתנה var
בכל ה-Subshells בזמן אמת
- באופן כללי, כשאנחנו מריצים סקריפט, הוא רץ ב-Subshell
אם הסקריפט שלנו צריך להגדיר משתנים ב-Parent Shell, הוא צריך לרוץ על ה-Parent.
כדי להריץ סקריפט על ה-Shell session הנוכחי נשתמש בפקודה source
הפקודה source scriptname
תהיה חייבת להיכתב ב-session הנוכחי, כלומר, היא לא יכולה להיות חלק מהסקריפט (להריץ סקריפט מיד פותח סשן חדש).
פיתרון אפשרי זה להכניס בסקריפט פקודה ליצור alias של source scriptname
בפעם הראשונה שהוא רץ... (כמו שעשיתי עם historyfinder)