מדריך sed

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

משמעות השם sed היא Stream Editor, ותפקידו של sed בהתאם: הוא עורך טקסט שמקבל את הקלט שלו בתור זרם (מקובץ או מ Pipeline) ועורך את הטקסט שמגיע לפי הוראות שהעברנו מראש. במדריך זה אספר על סד, קודם התיאוריה ואז דרך דוגמאות.

1. איך sed עובד

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

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

בואו נראה קצת פקודות כדי לכתוב את התוכניות הראשונות שלנו:

  1. הפקודה p מדפיסה את השורה.
  2. הפקודה d מוחקת את השורה.
  3. הפקודה s מחליפה טקסט לפי ביטוי רגולארי.
  4. הפקודה w כותבת את השורה לקובץ.
  5. הפקודה r מוסיפה טקסט שמגיע מקובץ אחר.

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

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

sed 1d

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

# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/local/bin/pwsh

והנה התוצאה של אותו sed:

$ sed 1d shells

# Ftpd will not allow users to connect who are not using
# one of these shells.

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/local/bin/pwsh

קיבלתי את כל תוכן הקובץ פרט לשורה הראשונה.

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

$ sed '2,$d' shells
# List of acceptable shells for chpass(1).

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

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

$ sed '/^#/d' shells

/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
/usr/local/bin/pwsh

2. הפעלת sed כדי לשנות קבצים In Place

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

בשביל המשחק אני יוצר באותה תיקיה 5 עותקים של הקובץ shells בשמות shells1, shells2, shells3, shells4 ו shells5:

$ cat shells > shells{1..5}
$ rm shells

עכשיו אשתמש ב sed כדי למחוק את כל השורות שמתחילות בסולמית מכל 5 הקבצים במכה אחת:

$ sed -i'' '/^#/d' shells*

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

$ sed -i'.bak' '/^#/d' shells*

3. הפעלת sed על קלט מפקודה אחרת

בהיותו Stream Editor, סד יכול לעזור לנו גם בתוך Pipelines כדי לשנות את הטקסט לפני שממשיכים לפקודה הבאה. בואו ניקח עוד דוגמה הפעם עם קובץ שמכיל alias-ים בפורמט של csh, כלומר התוכן הבא:

alias c cowsay
alias ll ls -l

קראתי לו csh_aliases. בעזרת sed אני יכול לקרוא את השורות מהקובץ, לשנות את הפורמט של כל שורה כך שיתאים ל sh ולהפעיל אותה. פקודת ה sed שאני צריך היא s שהיא פקודת ההחלפה לפי ביטוי רגולארי. ב s משתמשים עם הפורמט הבא:

sed 's/regexp/replacement/'

אז במקרה שלנו בשביל להחליף את הפורמט של ה alias-ים נוכל לכתוב:

$ sed -r 's/alias (\w+) (.*)/alias \1="\2"/' csh_aliases

alias c="cowsay"
alias ll="ls -l"

המתג -r אומר ל sed להשתמש בתחביר החדש לביטויים רגולאריים (חדש זה במרכאות כאן. ישר משנות ה-80), מה שמאפשר לנו לכתוב סוגריים בלי סימן \ לפניהם ואת ה +. השימוש ב \1 ו \2 בחלק של ההחלפה מתייחס לטקסט שנתפס בסוגריים בחלק של הביטוי הרגולארי.

ואני יכול להמשיך את ה pipeline עם tr כדי לאחד את כל הפלט לשורה אחת ואת כל זה לשלוח ל eval כדי ליצור את כל ה alias-ים אצלי ב shell:

$ eval $(sed -r 's/alias (\w+) (.*)/alias \1="\2"/' csh_aliases | tr '\n' ';' )

עכשיו שיש לנו מושג בסיסי איך sed עובד בואו נראה עוד כמה דוגמאות לתוכניות sed שאולי יתנו לכם רעיונות לשימוש בו בחיי היום יום.

4. דוגמה: יצירת קבצי תקציר מאוסף של קבצים

זוכרים את 5 העותקים של הקובץ shell שהיו לי? אני יוצר אותם מחדש אבל הפעם אני רוצה ליצור מכל אחד מהם קובץ "תקציר". התקציר מכיל רק את 3 השורות הראשונות מהקובץ המקורי. ראינו כבר איך להדפיס את 3 השורות הראשונות עם d ויהיה מעניין לראות את המשלימה שלה, הפקודה p עושה את אותו דבר:

$ sed -n '1,3p' shells1

בדרך כלל sed מדפיס כל שורה שהוא סיים לעבוד עליה, אבל המתג -n גורם לו לדלג על ההדפסה. הפקודה p מדפיסה שורה ולכן מה שהתוכנית אומרת זה "תדפיס את שורות 1 עד 3". מאחר וביטלנו את ההדפסה האוטומטית אלה השורות היחידות שיודפסו.

אבל אני רוצה ללכת עוד צעד קדימה - אני רוצה להפעיל את זה על כל הקבצים, ולשמור את התוצאות לקבצים חדשים. בשביל לשמור את התוצאה לקובץ חדש אני משתמש בפקודת w של sed:

$ sed -n '1,3wshells1.summary' shells1

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

$ for f in shells*; do; sed -n "1,3w${f}.summary" "$f"; done

5. דוגמה: הוספת שורת פתיחה Shbang לסקריפטים

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

#!/bin/bash

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

$ sed -i.bak '1i\#!/bin/bash' *.sh

תיקח את כל הקבצים בתיקייה שיש להם סיומת sh, תשמור לכל אחד מהם גיבוי עם הסיומת .bak ותוסיף בתחילת כל קובץ את שורת ה Shbang.

6. איפה לומדים עוד

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

  1. דף העזרה של sed: https://linux.die.net/man/1/sed

  2. רשימה של דוגמאות מוסברות לשימוש יצירתי ב sed: https://www.pement.org/sed/sed1line.txt

  3. המדריך הרשמי של gnu sed, גירסה חדשה ומעודכנת יותר של sed עם אינסוף יכולות: https://www.gnu.org/software/sed/manual/sed.html