מדריך שורת הפקודה - ניתוב קלט ופלט

חלק שביעי בסדרת מדריך שורת הפקודה

Authors
  • Name
    YossiZ
    Published on
    Twitter

טוב, הגיע הזמן למאמר נוסף...

והפעם (כמו שהבטחנו) נדבר על "ניתוב קלט ופלט"

כדאי לחזור לפוסט הקודם ולקרוא שוב על המושגים של "קובץ" ו"קלט ופלט" בהקשר זה. ובקיצור:

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

נקודה נוספת שכדאי להבין הוא שכאשר אנחנו מדברים על "3 קבצים" שפתוחים בברירת מחדל עבור כל תהליך, התהליך לא מקבל "קובץ" אלא "file handle" - ידית עבור קובץ, ה"ידית" הוא מספר שמייצג את הקובץ, וניתן להשתמש בו מול מערכת ההפעלה עבור פעולה עם הקובץ. לשלוש הקבצים האלו יש מספרים ידועים מראש. 0 (קלט), 1 (פלט), 2 (פלט שגיאות).

ניתוב קלט/פלט

בברירת מחדל, 3 הקבצים הנ"ל, או יותר נכון 3 ה"ידיות" הנ"ל כולם מייצגות את אותו קובץ שהוא ה"קובץ" שמייצג את חלון הטרמינל.

ולכן, בברירת מחדל, כל תהליך קורא קלט מתוך חלון הטרמינל וכותב פלט שוב לחלון הטרמינל.

המושג של "ניתוב פלט" הוא לבקש מאת ה-shell לשייך את אחד מ"ידיות" הפלט (1 או 2, או שניהם) לקובץ אחר.

יש כמה "תווים מיוחדים" שמשמשים לצורך ניתוב קלט ופלט' והם: >, <, |, <<.
על | כבר למדנו בפוסט הקודם. הוא התו שמייצר "צינור" ומחבר את הפלט של הפקודה הקודמת לקלט של הפקודה הבאה.

ניתוב פלט בסיסי

ניתוב פלט נעשה על ידי התו > ואחריה שם של קובץ.
כדי לנתב את הפלט של פקודת ls לקובץ בשם out.txt כותבים כך:

ls > out.txt

התוצאה של פקודה זו היא שה-shell פותח את הקובץ out.txt לכתיבה, ומשייך אותו ל"ידית" מס' 1. ואז הוא מריץ את הפקודה ls שכותבת את הפלט לקובץ הנ"ל.

התחביר הנ"ל הוא קיצור של תחביר יותר ארוך:

ls 1> out.txt

בתחביר הארוך אנחנו מציינים בפירוש את המספר של ה"ידית" שנחנו רוצים לנתב לקובץ out.txt. אם משמיטים את המספר, הכוונה למספר 1.

אם נרצה שגם פלט השגיאות ינותב לקובץ נכתוב ככה:

ls 1>out.txt 2>out.txt

אם הנתיב של קובץ הפלט הוא ארוך זה ייצא ארוך למדי ולכן יש קיצור, אפשר ל"שכפל" ידיות. כך זה נראה:

ls > /A/very/long/and/complicated/path/etc/etc 2>&1

הסימון: 2>&1 בסוף אומר, תנתב את 2 לאותו קובץ ש-1 מייצג.

ויש דרך עוד יותר קצרה (זה עובד רק בbash ולא ב-CMD):

ls &> /A/very/long/and/complicated/path/etc/etc

המשמעות של $> היא "תנתב את 1 ו-2 לקובץ זה".

⚠ ניתוב של פלט לקובץ בצורה הנ"ל, ידרוס את התוכן הקודם של הקובץ.

מה נעשה אם לא נרצה לדרוס את התוכן הקודם אלא להוסיף לו?

במקום > נכתוב >>. זה מצרף את הפלט של פקודה זו לתוכן הקודם של הקובץ.

ניתוב קלט

ניתוב קלט עובד בדיוק כמו ניתוב פלט רק הסימון הוא < במקום >.

על מנת להדגים את זה ניקח את הפקודה: findstr (זה ב-CMD, בbash יש grep שדומה לה). פקודה זו קוראת את הקלט שלה ומחפשת שורות שכוללות מחרוזת מסויימת. אם יש שורות כאלה, היא כותבת אותם לפלט שלה.
שימוש לדוגמה, הפקודה (או יותר נכון: ה-pipeline -- רצף פקודות שמועברות בצינור):

dir | findstr abc

פקודת dir פולטת רשימה של קבצים בתיקייה הנוכחית. הרשימה מוזנת לקלט של פקודת findstr שמחפשת בין הקלט שורות שכוללות את המחרוזת abc, ומדפיסה שורות אלו לפלט.

אם נרצה להשתמש בפקודת findstr כדי לחפש מחרוזת בתוך קובץ בשם file.txt, איך נעשה את זה?

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

findstr abc < file.txt

זה גורם ל-shell להריץ את הפקודה במצב ש"ידית" מס' 0 (דהיינו ה"ידית" שמייצגת את הקלט) מצביע על קובץ file.txt.

ℹ אגב, הבאתי את זה רק להדגים ניתוב קלט, אומנם יש דרך אחרת לחפש בתוך קובץ. וזה על ידי הפרמטר: f/ לדוגמה: findstr /f:file.txt abc.
יש דרך אחרת שאנשים רבים משתמשים בה אבל מדובר באריכות ללא צורך: type file.txt | findstr abc כי זה מריץ פעולת type ללא כל צורך.
כנ"ל בלינוקס רואים הרבה: cat file.txt | command xyz כאשר אפשר לכתוב במקום זה: command xyz < file.txt.
זה נקרא UUOC (ר"ת Useless use of cat).
חוץ מזה שמדובר באריכות ללא צורך ויצירת תהליך מיותר, יש עוד הבדל עדין, ראה בכתבה בוויקיפדיה.