היום למדתי: הפקודה readarray ב bash

16/12/2022

ל bash יש את הפקודה read שאמורה לקרוא קלט למשתנה, ולדעתי היא הסיבה המרכזית שאנשים לא אוהבים bash. היא תעבוד טוב כשניקח מילה בודדת למשתנה:

ubuntu@primary:~$ read name < <(echo ynon)
ubuntu@primary:~$ echo "$name"
ynon

אבל רק תנסו להעביר משהו שהיא לא אוהבת ואיבדתם אותה. הנה לדוגמה read מוחקת את הרווחים מתחילת השורה, סתם כי מתחשק לה:

ubuntu@primary:~$ read name < <(echo "   one")
ubuntu@primary:~$ echo "$name"
one

ואם בפלט יש כמה שורות, read פשוט תזרוק את כל מה שבא אחרי השורה הראשונה:

ubuntu@primary:~$ read name < <(cowsay hello)
ubuntu@primary:~$ echo "$name"
_______

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

ubuntu@primary:~$ readarray lines < <(echo "   one")
ubuntu@primary:~$ echo "$lines"
   one

וזאת הדוגמה השלישית, שמדפיסה הפעם את כל השורות:

ubuntu@primary:~$ readarray lines < <(cowsay hello)
ubuntu@primary:~$ echo "${lines[@]}"
 _______
 < hello >
  -------
         \   ^__^
          \  (oo)\_______
             (__)\       )\/\
                 ||----w |
                 ||     ||

יותר מזה, בגלל שהפלט נשמר בתור מערך אפשר לגשת לכל שורה ממנו למשל:

echo "${lines[1]}"

ל readarray יש די הרבה אפשרויות להתאמה כולל המתג -t שמוחק את תו ירידת השורה מכל שורת קלט, המתג -n שמאפשר להגביל את מספר השורות שנקרא, המתג -s שמאפשר לדלג על השורות הראשונות.

נ.ב. בטוח שמתם לב לקריאה המשונה עם כל החצים שמאלה. גם אני כמוכם הייתי שמח לכתוב:

ubuntu@primary:~$ cowsay hello | readarray lines

אבל זה לא יעבוד. סימן | פותח Sub Shell, והמערך lines יוגדר באותו Shell פנימי. אם נפעיל פקודה כזאת ואחריה ננסה להדפיס את lines ב Shell שלנו נקבל מערך ריק.