צפריר:
לא ברור לי למה נדרש כאן process substitution.
זה לא "נדרש" - יש דרכים שונות להעביר פלט של פקודה אחת לקלט של פקודה אחרת (הלולאה במקרה שלפנינו), ו-process substitution הוא אחת מהן. אפשרות נוספת היא להשתמש ב-pipe, ואפשר להשתמש גם ב-command substitution. יש גם את הדרך בסקריפט המקורי של queency, קרי לכתוב את הפלט של הפקודה הראשונה לקובץ, ולקרוא אותו על ידי הפקודה השנייה.
היתרון בשתי הדרכים הראשונות (command substitution ו-pipe) היא שהיצירה של הפלט (על ידי הפקודה הראשונה) וקריאתו (על ידי הפקודה השנייה) נעשות בצורה אסינכרונית. למשל, הלולאה תקרא ותעבד שורה מהפלט של locate ברגע שהשורה זמינה.
בשתי הדרכים האחרונות שציינתי הקריאה של פלט הפקודה הראשונה תעשה רק לאחר שהוא יהיה כולו מוכן. יש לזה שני חסרונות עיקריים: ראשית, כמו שציינתי, צריך להמתין עד שכל הפלט מוכן ורק אז להתחיל לעבד אותו. זה איטי יותר (במקום לעשות דברים במקביל הם נעשים "בטור") ובנוסף, אם הסקריפט אמור להיות אינטראקטיבי, יש פגיעה ב"חווית המשתמש" - צריך לבהות במסך עד שהפקודה הראשונה תסתיים. שנית, אם הפקודה הראשונה מבצעת משהו שמשתמש בהרבה זיכרון - למשל, קוראת קובץ שלם ומכינה ממנו פלט - כל הפלט של הפקודה הראשונה יישמר בזיכרון ורק אז יעובד על ידי הפקודה השנייה. זה מגדיל את השימוש בזיכרון. אם עובדים אסינכרונית, צריך לשמור בזיכרון רק את הנתונים הזמניים - למשל את השורה שעובדים עליה.
שימוש ב-pipe דומה (מבחינת התהליך שקורה) לשימוש ב-process substitution, אבל באפשרות השנייה יש במקרים מסויימים יותר גמישות או מרחב אפשרויות יותר גדול - למשל, אפשר להעביר יותר מפלט אחד לפקודה. הנה דוגמה קצרה, בלי להרחיב:
קוד
sort <(echo hello) <(echo world)
או שאולי לא הבנתי את ההערה שלך?
בכל אופן, הנה סקריפט קצר שמדגים את האפשרויות השונות (פרט לכתיבה לקובץ וקריאה ממנו).
קוד
#!/bin/bash
my_cmd()
{
for i in $(seq 10); do
echo $i
sleep 1
done
}
echo 'process substitution (asynchronous):'
while read line; do
echo 'line:' $line
done < <(my_cmd)
echo 'using pipe (asynchronous too):'
my_cmd | while read line; do
echo 'line:' $line
done
echo 'command substitution (synchronous):'
for line in $(my_cmd); do
echo 'line:' $line
done
הרי מורצת כאן פקודה והפלט שלה מתקבל ללולאה כקלט. כלומר: הלולאה מורצת בתת תהליך שהקלט שלו הוא שפלט של הפקודה האמורה.
וכן. הלולאה מורצת בתת תהליך. זה אומר שאם היא משנה ערך של משתנה, זה לא ישפיע מחוץ ללולאה.
בדוגמאות שנתתי, וגם בסקריפט המקורי, הלולאה לא מתבצעת ב-subshell אלא ב-shell הראשי (זה שבו רץ הסקריפט). מכאן גם נובע ששינוי של משתנה בתוך הלולאה יראה גם מחוץ לה.
מה שרץ ב-subshell זו הפקודה שהפלט שלה מועבר ב-pipe או באמצעות process substituiton.