דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
yossizY

yossiz

@yossiz
אודות
פוסטים
6.1k
נושאים
124
קבוצות
0
עוקבים
26
עוקב אחרי
0

פוסטים

פוסטים אחרונים הגבוה ביותר שנוי במחלוקת

  • מדריך: שורת הפקודה
    yossizY yossiz

    הבהרות

    הבהרה1: נא לסלוח על טעויות כתיב והחלפות זכר לנקבה וכדו', עברית היא לא שפת אם שלי
    הבהרה2: יש הרבה שורות פקודה, נשתדל לא להתמקד בשום אחד מהם אלא לדבר על דברים שקשורים לכולם
    הבהרה3: אין צורך בשום ידע מוקדם, חוץ מלדעת איפה נמצא כפתור ההפעלה של המחשב...
    הבהרה4: אין שום התחייבות להמשיך את הסדרה, זה על בסיס זמן פנוי וחשק...
    הבהרה5: למען הסדר הטוב, פתחתי עוד נושא לתגובות, נא להגיב שם. כאן אני מתכוון להעלות המשכים לסדרה.
    הבהרה6: בל"נ לא יהיו עוד הבהרות ומיד ניגש לענין...

    הקדמה: שורת הפקודה מהו

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

    שורת הפקודה = סביבה מבוסס טקסט שבה מריצים תוכנות (לרוב, פקודות לא אינטראקטיביות), (CMD ב-Windows ו-DOS (ז"ל) או Powershell בווינדוס, bash, sh, וכו' בלינוקס, וכו')

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

    רכיבים של שורת פקודה

    • מקום לקלט (input) - כאן מזינים את הפקודות.
    • מקום לפלט (output) - כאן מקבלים תוצאות. (בד"כ זה אותו חלון של הקלט)
    • PROMPT (הנחיה?) - רמז ויזואלי שהסביבה מוכן לקבל קלט. כאשר פקודה רצה, הסמן המהבהב נמצא בשורה בפנ"ע בלי PROMPT לפניה (לפעמים יש פלט של הפקודה שרצה, לפעמים לא). כאשר הפקודה מסתיימת, ושורת הפקודה מוכנה לקבל עוד פקודה, מודפס שוב שורת ה-PROMPT ואח"כ סמן מהבהב, זה סימן שאפשר להתחיל לכתוב עוד פקודה.
      זה נראה משהו כזה בווינדוס:
    C:\Users\yossi>_
    

    (למה כתוב נתיב ב-PROMPT? נגיע לזה יותר מאוחר).

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

    הרכיבים: קלט, פלט, וחישוב
    הפקודה מקבלת קלט עושה עם זה חישוב ומחזירה את הפלט. (לא תמיד חייבים כל הרכיבים).

    קלט

    יש כמה דרכים להכניס קלט לפקודה

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

    דוגמא:

    echo "Hello, World!"
    

    echo הוא שם הפקודה. פקודה זו לוקחת את הפרמטרים ופולט אותם החוצה, בלי להפעיל עליהם שום חישובים.
    "Hello, World!" הוא פרמטר שהפקודה מקבלת.
    הפלט:

    Hello, World!
    

    אפשר להזין יותר מפרמטר אחד. וכל פרמטר יכול להכיל יותר ממילה אחת. בד"כ רווח מחלק בין פרמטרים, אם כותבים גרשיים מסביב למילים זה מחבר אותם לפרמטר אחד. הפקודה echo יכולה לקבל יותר מפרמטר אחת. לפי"ז הייתי יכול לכתוב:

    echo Hello, World!
    

    ואז זה היה מתורגם לפקודה עם 2 פרמטרים - "Hello," ו-"World!". במקרה שיש יותר מפרמטר אחד, הפקודה echo פולט אותם החוצה עם רווח ביניהם, ונקבל אותו פלט.
    אמנם, מה יקרה אם נכתוב:

    echo "Hello,       World!"
    echo Hello,       World!
    

    הפלט יהיה:

    Hello,       World!
    Hello, World!
    

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

    עוד דרכים להזנת קלט:

    • קבצים
    • משתני סביבה

    פלט

    • טקסט מודפס בחלון שורת הפקודה
    • פעולה שקורה (למשל כיבוי המחשב)
    • קבצים
    • קוד (מספר) שהתוכנה מחזירה - (return code)
    • ....

    ההמשך יבוא... (אולי כן, ואולי לא...)


  • מדריך: שורת הפקודה
    yossizY yossiz

    משתני סביבה

    מה זה "משתנה"?

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

    msg yossi שלום Yossi!
    msg yossi שלום Dovid!
    ....
    ....
    

    (הפקודה msg מקבל 2 פרמטרים: שם המשתמש שיראה את ההודעה, ותוכן ההודעה. שם המשתמש במקרה זו הוא yossi והתוכן הוא "שלום פלוני!")

    או אני יכול לכתוב את הפקודה פעם אחת עם משתנים, שם ה"משתנה" הוא רק עוגן, וה-shell ממלא בכל פעם את הערך של המשתנה בזמן הרצה.

    (משתנים ב-CMD כותבים מסובבים ב-%-ים. התו % הוא תו מיוחד רק במקרה שהוא סובב משתנה שקיים במערכת. כדי לכתוב % בלי שיתורגם כתו מיוחד כותבים ^%. (דרך אגב, טכניקה זו לכתוב תו לפני תו מיוחד כדי שלא יתורגם בצורה מיוחדת, נקרא escaping - מילוט) אין צורך (וגם לא יעזור) לעשות מילוט ל-% הראשון אלא לשני.)

    למשל אכתוב:

    msg %username% שלום %ploni%!
    

    עכשיו ה-shell יבדוק עם יש משתנה מוגדר בשם "USERNAME", ותמיד יש כזה כי זה משתנה שמוגדר אוטומטי ע"י המערכת, וערכו הוא שם המשתמש הפעיל - בדוגמא שלנו "yossi". ה-shell ימחוק את השם של המשתנה ובמקום זה ימלא את הערך "yossi".

    עכשיו ה-shell יעבור לבדוק עם יש משתנה בשם PLONI. מכיון שאין, נצטרך להגדיר אחד כזה. ב-CMD עושים את זה כך:

    set PLONI=Dovid
    

    אם עכשיו נריץ את הפקודה - התוצאה:
    48a83b44-f3e1-4612-93fc-2f8601cef566-image.png

    משתני סביבה

    משתנה שמוגדר כ"משתנה סביבה" הוא משתנה ששייך לתהליך וכל התהליכים הבנים יקבלו אותו בירושה מהאבא. ב-CMD, כל המשתנים הם משתני סביבה. אם תגדיר משתנה, ואז תריץ פקודה - המשתנה יהיה מוגדר גם בתהליך של הפקודה שרצה. ב-bash יש 2 סוגים, משתנה רגיל, ומשתנה סביבה.

    אפשר לראות (וגם לערוך) משתני סביבה של תהליך בתוכנת Process Hacker
    a42ea64d-b4ec-4e46-83a5-9a67dbdd46e6-image.png
    אפשר לראות משתני הסביבה של תהליך CMD ע"י הפקודה set בלי פרמטרים.

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


  • אפשר לעשות קישור למלל מסויים בדף, הידעתם?
    yossizY yossiz

    אתם בכרום וחבריו? מצויין!
    לחצו על לינק זה

    שמתם לב?
    זה לוקח אותך ישירות לכותרת "תורני" וליתר בהירות, המילים צבועים בצבע צהוב יפה (?)

    תמיד ידענו שאפשר לעשות לינק לאלמנט בדף שיש לו ID על ידי הוספת ה-ID אחרי ההאש (#). מעתה (מכרום 80) אפשר לקשר לכל מלל בדף שתרצה, רק תוסיפו את זה להאש: :~:text=XXXX

    📜 תיעוד מלא: https://github.com/WICG/ScrollToTextFragment/#text-fragments

    תיעוד קצר בעברית מדוברת

    מבנה הקישור:

    • קודם כל, הכתובת של הדף, ואז -
    • האש - # (מסמן שכל הבא אחריו הוא כתובת של אלמנט בתוך הדף)
    • :~: (מסמן שכל הבא אחריו הוא חיפוש מלל)
    • text=1-,2,3,-4
      במקום 1,2,3,4 יש 4 פרמטרים שאפשר למלאות
      • קידומת (מילים שחייבים להופיע לפני המלל המסומן)
      • תחילת הסימון
      • סוף הסימון
      • סיומת (מילים שחייבים להופיע אחרי המלל המסומן)
    • אפשר להוסיף עוד איזורים מסומנים על ידי ‎&text=1,2,3,4

    דוגמאות:

    • https://netfree.link/wiki/נטפרי#:~:text=נטפרי ⬅ מסמן את המופע הראשון של המילה נטפרי
    • https://netfree.link/wiki/נטפרי#:~:text=נטפרי,סינון ⬅ מסמן מהמופע הראשון של המילה נטפרי עד המופע הבא של המילה סינון
    • https://netfree.link/wiki/נטפרי#:~:text=לספק-,נטפרי,סינון ⬅ מחפש את המופע הראשון של המילה נטפרי שמגיעה מיד אחרי המילה לספק ומסמן ממנה עד המופע הבא של המילה סינון
    • https://netfree.link/wiki/נטפרי#:~:text=לספק-,נטפרי,סינון,-חיפוש ⬅ מחפש את המופע הראשון של המילה נטפרי שמגיעה מיד אחרי המילה לספק ומסמן ממנה עד המופע הבא של המילה סינון שמיד אחריו נמצא המילה חיפוש
    • https://netfree.link/wiki/נטפרי#:~:text=נטפרי הינו,רווח&text=המערכת,נטפרי. ⬅ סימונים מרובים, מסמן את הקטע הראשון והשלישי

    אפשר להשמיט פרמטרים
    דוגמאות:

    • https://netfree.link/wiki/נטפרי#:~:text=סינון,-קבצי ⬅ רק הפרמטרים 2 ו-4
    • https://netfree.link/wiki/נטפרי#:~:text=סינון,קבצי ⬅ רק פרמטרים 2 ו-3

    קידוד נכון של תווים מיוחדים

    יש תווים שלא תקינים ב-URL וחייבים לקודד אותם.
    אם אתם רוצים לחפש פסיק ושלא יתורגם בצורה מיוחדת כמפסיק בין פרמטרים אפשר גם לקודד אותו
    הקידוד נקרא urlencode ויש כמה אתרים שמספקים ממשק נוח לקדד טקסט לקידוד זה.


    ידעתי כבר מזמן שיש כזו הצעה על הפרק, מה שהביא את זה לתשומת ליבי היום היא העובדה שכנראה גוגל התחילו לשים קישורים כאלה בתוצאות החיפוש
    דוגמה:
    b5d8bfa9-208b-4293-868e-d7c79f9998ab-image.png


  • מדריך לרג'יסטרי - Windows-Registry
    yossizY yossiz

    הקדמה

    מה זה הדבר הזה "הרג'יסטרי"?
    הרג'יסטרי הוא סוג של מסד נתונים, DB, בעגה המקצועית אפשר להגדיר אותו כ-key value store. כלומר, מקום אחסון עבור רשומות בצורה של key = value (מפתח = ערך). כלומר לכל רשומה ב-DB יש שם (ה"מפתח") וערך (value).
    בעבר היו שומרים מידע כזאת בקבצי ini או קבצי תצורה אחרות.
    יש אמנם כמה מאפיינים ייחודיים לרג'יסטרי שמעניקים לו התאמה מיוחדת לאחסון של הגדרות מערכת.

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

    מבנה הרג'יסטרי

    הרג'יסטרי בנויה בצורה היררכית כמו עץ. יש ענפים ויש עלים, הענפים הם מפתחות/תקיות והעלים הם הערכים.
    בראש ההיררכיה יש 5 מפתחות שורש (root keys). מתחתם יש עוד מפתחות וערכים.
    מפתח רגיסטרי = תקייה
    ערך רג'יסטרי = מפה (associative array) של name = value
    לכל ערך יכול להיות כמה רשומות של name = value.
    לכל ערך מותר גם רשומה אחת אנונימי בלי שם. בעורך הרג'יסטרי זה מופיע כ-(default)
    (כן כן, המינוחים פה קצת מבלבלים...)
    לכל רשומה יש גם כן סווג של סוג הדאטה שהוא מכיל.
    הנפוצים הם:

    • REG_SZ = מחרוזת (string, מחרוזת של תווים)
    • REG_DWORD = מספר
    • REG_BINARY = דאטה בינארי
    • REG_MULTI_SZ = רשימה של כמה מחרוזות
    • REG_EXPAND_SZ = מחרוזת שיכול לכלול משתני סביבה

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

    • HKEY_CURRENT_USER משקף את התוכן של תקיית המשתמש הנוכחי שנמצא מתחת ל-HKEY_USERS‏.
    • HKEY_CLASSES_ROOT הוא שילוב של התוכן של HKCU\Software\Classes ו-HKLM\Software\Classes.
    • HKEY_CURRENT_CONFIG אודה ולא אבוש שלא ברור לי לגמרי מה מטרתו.

    השניים האחרים שהם העקריים הם:

    • HKEY_LOCAL_MACHINE שמקבץ תחתיו את ההגדרות שנוגעות למחשב בכללות.
    • HKEY_USERS שמתחתיו יש תקייה לכל משתמש במערכת עם ההגדרות המיוחדות למשתמש ההוא (חשוב לדעת שתתי תקייה אלו נטענים רק במקרה שהמשתמש מחובר).

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

    • הגדרות המשתמש (HKCU) נמצא בקובץ ‎%userprofile%\ntuser.dat‎
    • הגדרות המערכת (HKLM) נמצאים בתקיית: C:\Windows\System32\config.

    ממשקי גישה לרג'יסטרי

    ווינדוס מספקת כמה ממשקים לרג'יסטרי

    • regedit = עורך גרפי
    • reg = פקודה שאפשר להריץ בשורתהפקודה ובתוך סקריפטים
    • קבצי REG = אפשר לשלב לעדכן או למחוק ערכים מהרג'יסטרי על ידי הרצת קבצי REG
    • ממשק עבור תוכנות (API בלע"ז). כמובן כל הממשקים האחרים משתמשים ב-API הזו מתחת לשטח

    רכיבי ווינדוס העקריים שמשתמשים ברג'יסטרי

    שירותי מערכת
    שירותים הם תהליכים שרצים בלי התערבות משתמשים. בווינדוס, המילה "שירותים" כוללת גם כן דרייברים. כל ההגדרות הנוגעות לשירותי מערכת מאוחסנים בנתיב: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

    הגדרות קרנל או רכיבי ליבה אחרים HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
    ועוד ב-HKEY_LOCAL_MACHINE\SYSTEM

    הגדרות תוכנה
    הגדרות ברמת מערכת: HKEY_LOCAL_MACHINE\SOFTWARE
    הגדרות ברמת משתמש: HKEY_CURRENT_USER\Software
    עבור תוכנות 32 סיביות:
    HKLM\SOFTWARE\WOW6432Node
    HKCU\SOFTWARE\WOW6432Node

    הגדרות רכיבי COM
    אל תשאל מה זה רכיבי COM... זה סיפור מורכב ביותר. אבל יש חלקים נרחבים של מערכת ווינדוס שבנויים על טכנולוגיית COM, וכדי שזה יעבוד צריך את החלק הזה של הרג'יסטרי...
    HKEY_CLASSES_ROOT
    גם שיוכי קבצים לתוכנות נמצאים (בעיקר) שם (אל תשאלו למה...).

    הגדרות לוח הבקרה ועוד
    HKEY_CURRENT_USER\Control Panel

    מדיניות קבוצתיות (GPO)
    בכמה מקומות מתחת לתקייות בשם policies. לדוגמה: HKLM\Software\Microsoft\Windows\CurrentVersion\Policies (מדיניות ווינדוס לכלל המערכת),
    HKCU\Software\Microsoft\Windows\CurrentVersion\Policies (מדיניות ווינדוס למשתמשים מסויימים),
    HKCU\Software\Policies, HKLM\SOFTWARE\Policies (מדיניות תוכנות אחרות)

    מציאת מיקום הגדרה ברג'יסטרי

    הנה מגיע החלק החשוב...
    א. חובה להיות מיומן בחיפושי גוגל... רוב המידע נמצא כבר שמה
    ב. procmon,
    ג. procmon,
    ד. ושוב procmon... 🙂

    ולקינוח:

    עריכת רגיסטרי לא מקוון

    אפשר לערוך הגדרות רג'יסטרי גם על מערכת "מתה"
    מייבאים את ה-hives לתוך עורך הרג'יסטרי במערכת "חיה" על ידי בחירת התפריט File -> Load Hive.
    חשוב לדעת איך עושים את זה כאשר רוצים לערוך הגדרות של מערכת הפעלה מתוך סביבת הריקוברי של ווינדוס

    לעוד פרטים טכניים מומלץ לקרוא את הכתבה בוויקיפידיה האנגלי
    יש שאלות? אשמח לנסות לתת מענה. (הרבה יותר קל לענות על שאלה ספציפית מאשר לכתוב סקירה על כל הנושא...)


  • מדריך: שורת הפקודה
    yossizY yossiz

    פקודות פנימיים לעומת פקודות חיצוניים

    פקודות מגיעות ב2 טעמים - פנימי וחיצוני.
    פקודה חיצונית הוא תוכנה מהמחשב - לדוגמא אם נכתוב בשורת הפקודה notepad זה יריץ את הכתבן מהנתיבC:\Windows\notepad.exe. אבל יש גם פקודות שממומשות ע"י ה-shell עצמה. נזכיר, ש-shell = סביבה שמתוכה מריצים פקודות. ה-shell הוא גם תוכנה וחלק מהפקודות ממומשות על ידה בלי צורך להריץ תוכנה חיצונית.
    למשל, בכל ה-shellים, יש פקודה cd לשינוי תקייה נוכחי, פקודה זו חייבת להיות פקודה פנימית כי אין דרך לתוכנה חיצונית לשנות את התקייה הנוכחית לתהליך האב שלה. אם נכתוב ב-bash או ב-CMD את הפקודה (הפנימית) help נקבל רשימה של פקודות פנימיות. (ב-CMD, הרשימה כולל ג"כ פקודות חיצוניות, ב-bash לא).

    למה חשוב לדעת אם זה פנימי או חיצוני? שאלה טובה... (ב-bash, העזרה המובנית הוא רק לפקודות פנימיות, ב-CMD כמו ב-CMD המצב יותר מסובך...)

    תווים מיוחדים

    כמו שכבר הזכרנו בפוסט הראשון, הדרך להריץ פקודה הוא - לכתוב את שם הפקודה, ואח"כ פרמטרים. הפרמטרים מועברים לפקודה ע"י ה-shell. בד"כ הפרמטרים לא עוברים עיבוד ע"י ה-shell, אלא מועברים כמו שנכתבו. זה נכון כאשר אין תווים מיוחדים, כאשר יש תווים מיוחדים, תווים אלה יש להם משמעות מיוחדת ל-shell והם לא מועברים לפקודה אלא מתורגמים ע"י ה-shell. לכל shell יש כללים משלו מה נחשב לתו מיוחד, ואיזה פעולה כל תו יעשה. למשל ב-bash נחשב רווח כתו מיוחד, כאשר ה-shell פוגש ברווח, זה אומר לו: כאן סוף פרמטר, התו הבא שאינו רווח מתחיל פרמטר שני. משום כך לא משנה כמה רווחים תשים בין המילים, הפקודה תמיד יקבל את המילה שלפני הרווחים כפרמטר 1, והמילה שאח"כ כפרמטר 2, והרווחים נבלעים ע"י ה-shell.
    ב-CMD כמו ב-CMD המצב יותר מסובך... כל מה שמגיע אחרי הפקודה מועבר לפקודה (כולל כל הרווחים). עכשיו הפקודה עצמה יכול לבחור עם לעבד את הפרמטרים בעצמו (עם הכללים שהוא ירצה לייצר לעצמו) או להעביר את המחרוזת לווינדוס לעבד אותו לפי כללים ידועים.
    רוב הפקודות מעבירים את המחרוזת לעיבוד לפי הכללים הידועים. ובהם תקף הכלל הנ"ל שרווח מפסיק בין הפרמטרים, וגרשיים מחבר.
    תוכנות שנכתבו ב-C (שפת תיכנות ישישה ומכובדת) יעברו עיבוד אוטומטי ע"י ה-CRT (סביבת ההרצה של C - בעיקרון של ווינדוס שכבת תאימות עבור שפת C). (יש גם אפשרות לכתוב ב-C בלי לכלול את ה-CRT, אבל זה שייך ל"תכנות אקסקלוסיבי"...) התוכנה יכולה לבחור בכל זאת להתעלם ולהשתמש במחרוזת המקורית.

    איך מעבירים רווח לפקודה שמשתמש ברווח כתו מיוחד? למשל אם נרצה למחוק קובץ בשם c:\new file1.txt, אם נכתוב כך:

    del c:\new file1.txt
    

    נקבל תשובה

    Could Not Find c:\new
    Could Not Find C:\WINDOWS\system32\file1.txt
    

    כלומר שהקובץ new (פרמטר 1) לא נמצא, והקובץ file1.txt (פרמטר 2) לא נמצא. אנחנו צריכים לכתוב בפרמטר אחד את כל שם הקובץ, אבל שם הקובץ כולל רווח - שמחלק בין פרמטרים? בשביל זה יש עוד תו מיוחד ". הגרשיים מחברים כל מה שבתוכם לפרמטר אחד.

    del "c:\new file.txt"
    

    ד. א. כאשר ניסיתי כמה פקודות לצורך כתיבת הפוסט, מתברר ש-notepad משתמש במחרוזת המקורית, כולל רווחים. למעט רווחים בסוף המחרוזת (שגם מועברים לתוכנה אבל נמחקים ע"י notepad).
    echo משתמש במחרוזת המקורית. כנ"ל cd. כנ"ל start. (לכל אחד ייתכנו הבדלים עדינים בדרך שהם מתרגמים את המחרוזת שהם מקבלים).

    תווים מיוחדים ב-CMD

    כמו שהזכרנו, ב-CMD יש תווים שהתוכנה יכולה לבחור אם הם יחשבו כתווים מיוחדים או לא. יש תווים שהם מיוחדים מיוחדים... והם לא יועברו לתוכנה בשום פנים, ואלו הם:
    < > ^ | & ו-enter. (אולי יש יותר?)
    איך כותבים תווים אלו בלי שיתורגמו באופן מיוחד ע"י CMD ויועברו ישירות לפקודה? כותבים ^ לפני התו: ^| ^< ^> ^^ ^& ו- ^+enter.
    התו ", גם כן מיוחד קצת... כי תו מיוחד אחר (חוץ מ-enter) שמגיע אחרי ה" הפותח ולפני ה" הסוגר כבר לא נחשב כתו מיוחד.
    אני מאמין שיש עוד כמליון ואחד פרטים לגבי טיפול בתווים מיוחדים ב-CMD... מי שמכיר מוזמן לכתוב באשכול התגובות.


  • איך שואלים שאלות בפורום
    yossizY yossiz

    @yossiz אמר בעזרה ב...:

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

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

    ובכן,
    א) אני בן אדם ולא תמיד עושה דברים רק על פי שכל... נראה לי שכולם מכירים את המאפיין המוזר הזה של בני אדם.

    ב) נראה לי שצריך להבחין בין שאלות לבקשת טובות. שאלות - הוגנות, בקשת טובות - לא כל כך. שימו לב שבקשות לא הוגנות גם לא מזמינות תשובות איכותיות, אז כדאי להכיר את הצורות:

    נקח לדוגמה צורך מסויים שמחייב כתיבת סקריפט.

    • אפשר לפתוח נושא על הצורך עצמו: "איך מטפלים בבעיה XYZ?". זו לטעמי שאלה לגיטימית לחלוטין. הבעיה מאוד מוגדרת וספיציפית. השואל לא יודע מה הפתרון, והוא מבקש עצות מהציבור.
    • או אפשר להחליט שהתשובה היא כתיבת סקריפט, אבל הבעיה היא שהשואל הרי לא יודע לכתוב סקריפט אז בוא נבקש מאחרים שיעשו את העבודה בשבילי. ואז מגיע פוסט בסגנון: "אני צריך סקריפט שעושה XYZ. למי יש? דחוף!" זו בקשת טובות, והיא לא הוגנת לטעמי. אתה לא מבקש עצה או פתרון, אלא מבקש שאחרים יעשו בשבילך עבודה שאתה לא מסוגל לעשות.

    לפעמים הקו שמפריד בין שאלה לגיטימית לבקשת טובות נראה לפום ריהטא כקו די דק. אפשר לשאול "איך אני עושה XYZ בתוך סקריפט?" והכוונה היא לשאול שאלה ולהחכים וללמוד מהתשובות ולא לבקש מאחרים שיעשו בשבילך עבודה. או אפשר לשאול אותה שאלה בדיוק והכוונה היא למצוא פראייר שיעשה בשילך את העבודה בחינם. אבל אחרי מעט התבוננות ניתן בד"כ להבחין בין שתי הצורות בקלות על ידי מדידת רוחב השאילה. כלומר, אם השאלה היא מאוד ספציפית ניתן להניח שמדובר בשאילת לימוד. אבל אם השאלה מאוד רחבה "בנה בשבילי תוכנה שתתקן את כל העולם!" אז ניתן להניח די בוודאות שמדובר בבקשת טובות.

    לסיכום, הפורום לא נועד לבקש טובות מהציבור אלא לבקש עצות, ידיעות, או דברי חכמה וכדומה.
    כמובן שמותר גם לבקש טובות, הלא חסד הוא אחד מהעמודים שעליהם העולם עמוד. אבל גם בבקשת טובות יש צורה, לא לכתוב "אני חייב דחוף XYZ! מי מתנדב בשבילי? דחוף מאוד מאוד! אה, וכמעט שכחתי, תודה מראש." וד"ל. וגם לדאוג לשמור על צביון הפורום שרוב הפוסטים יהיו שאלות ולא בקשות טובות. ובנוסף לתת את הדעת על גודל הטובה, האם זה משהו שאפשר לענות במחשבה של שנייה, או האם זה משהו שמצטרך השקעה של חצי שעה?


  • מדריך: שורת הפקודה
    yossizY yossiz

    (למרות שכתבתי מראש שאני לא רוצה להתמקד על מימוש מסויים של שורת פקודה, אני רואה שיש יותר מדי הבדלים דקים בין המערכות ומכיון שרוב השימוש של מבקרי הפורום הוא בווינדוס, לכן מכאן והלאה, אם לא צויין אחרת מדובר ב-CMD - שורת הפקודה של ווינדוס)

    איזה פקודות ניתן להריץ משורת הפקודה?

    התשובה היא: כל תוכנה (קובץ EXE) שקיימת במערכת (או בדיסק חיצוני) + פקודות מובנות (ראה למעלה הסבר על פקודות מובנות/פנימיות).

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

    בווינדוס (בניגוד ללינוקס) קיים דגל (ביט בינארי) בתוך קבצי EXE שאומר למערכת ההפעלה "הלו, אני מיועד לשימוש בסביבה השחורה של שורת הפקודה". זה גורם לווינדוס להתייחס לתוכנה בצורה שונה. זה מתבטא בכמה דברים.
    א) לחיצה כפולה על התוכנה תמיד יפתח אוטומטית חלון שחור של CMD, (מכיון שכנ"ל אין טעם להריץ אותו מבלי שיהיה לה מקום לפלוט אליו טקסט). ברוב המקרים פתיחת החלון האוטומטי לא עוזר למשתמש מכיון שהחלון נסגר אוטומטית ברגע שהתוכנה מסיים את פעולתה, ואתו נעלם כל הפלט של התוכנה. החכם עיניו בראשו, יפתח מראש חלון פקודה ויריץ את התוכנה מתוך שורת הפקודה.
    ב) גם בהרצה מתוך שורת הפקודות (על ידי כתיבת שם התוכנה ולחיצת אנטר) ווינדוס מבחינה בין השתיים. בהרצת הסוג הגרפי, השליטה יחזור מיד ל-shell אחרי הרצת הפקודה. זה ניכר על ידי הדפסה חוזרת של ה-PROMPT (מה זה PROMPT? אפשר לקרוא עליו בפוסט הראשון של הסדרה). זה אומר למשתמש: "אני מוכן לקבל עוד פקודות". לעומת זאת, בסוג הטקסטואלי, בעת ריצת התוכנה, חלון הפקודות נמצא בשליטת התוכנה, זה מתבטא בזה שאי אפשר להזין עוד פקודות, מה שמצויין על ידי חיסרון שורת ה-PROMPT לפני הסמן המהבהב. זאת כדי לתת אפשרות לתוכנה להדפיס מידע לחלון.

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

    איך מריצים תוכנה XXX מתוך שורת הפקודה?

    (לקבל את התשובה המתומצתת, ראה סוף הפוסט)

    קודם כל, נסביר למה יש צורך לפעמים להריץ תוכנה דוקא מתוך שורת הפקודה?

    אם התוכנה פולטת טקסט לשורת הפקודה, אז חייבים להריץ אותה מתוך שורת הפקודה אחרת לא נוכל לצפות בפלט. גם אם אין פלט (או שאנחנו לא מעוניינים לצפות בפלט), עדיין יש מקרים שאנחנו רוצים להעביר מידע מסויים לתוכנה על ידי פרמטרים, [במקרה כזאת ניתן להריץ את התוכנה גם מתוך תיבת ההפעלה (windows+r)].

    עכשיו נסביר מה קורה כאשר מכניסים פקודה לשורת הפקודה:

    כמו שכתבנו למעלה (ואוו, כבר עברה שנה!) פקודות מגיעות בשני טעמים - פקודות פנימיות ופקודות חיצוניות. הפנימיות הם אלו שה-shell (מתרגם הפקודות) בעצמו מממשת (לדוגמה cd), כלומר, אם נריץ את הפקודה (זוכרים עדיין איך? פשוט כותבים את שם הפקודה ולאחריה הפרמטרים ואנטר לקינוח) ה-shell שמאזין לקלט מסתכל במילה הראשונה (שם הפקודה) ומבין שהפקודה מופנית אליו, ואז הוא קורא ומעבד את שורת הפקודה ומגיב בהתאם.
    פקודה חיצונית היא פקודה שלא מובנית בתוך תוכנת ה-shell, ה-shell מקבל את הקלט, בודק את שם הפקודה, ואופסס... הוא לא מזהה את הפקודה. ניקח לדוגמה את הפקודה: notepad (כתבן). אם נריץ חיפוש על קובץ ה-EXE של תוכנת CMD, נגלה שהמרוזת "notepad" לא נמצא בתוך הקובץ CMD.EXE בשום צורה שהיא. ובכל זאת CMD יודעת איך לטפל בפקודה.
    ההתנהגות של ה-shell עבור כל פקודה שהיא לא מכירה הוא לחפש את מערכת הקבצים עבור קובץ עם שם זהה לשם הפקודה, אם הוא מוצא קובץ כזאת הוא מריץ אותה עם הפרמטרים שהוזנו.

    אבל זה הרי ברור שאי אפשר לחפש את כל מליוני הקבצים במערכת הקבצים כדי למצוא תוכנה עם שם "notepad".
    התשובה היא ש-CMD מחפש רק בכמה נתיבים מוגדרים מראש. באיזה נתיבים?
    א) לפני הכל, בספריה הנוכחית. (ומה היא ה"ספריה הנוכחית"? ראה מסגרת.)
    קודם, CMD יחפש קובץ עם שם זהה לשם הפקודה. אם זה לא נמצא, ינסה CMD למצוא קובץ עם שם זהה לפקודה פלוס אחת מתוך כמה סיומות מוגדרות. בד"כ רשימת הסיומות יכלול: EXE BAT CMD VBS ועוד כמה. ניתן לשלוט על הרשימה באמצעות משתנה הסביבה: PATHEXT.

    ב) במידה ולא נמצאה שום קובץ מתאים בתקייה הנוכחית, יתחיל CMD לחפש בתוך רשימה מוגדרת של נתיבים נוספים. ניתן לשלוט על רשימת הנתיבים באמצעות מתשנה הסביבה PATH. להדפיס את ה-PATH הנוכחי, תריצו את הפקודה: set PATH. זה מדפיס רשימה של נתיבים שמובדלים באמצעות תו ;.

    הספריה הנוכחית - (Working Directory)

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

    תוכנת CMD ככל תהליך אחר, גם כן רצה בתוך סביבה שכוללת בין השאר גם כן "ספריה נוכחית". אפשר לראות מהי הספריה הנוכחית בטקסט ה-PROMPT.

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

    עכשיו נחזור לענות על השאלה שהצבנו בכותרת של חלק זה: איך מריצים תוכנה XXX מתוך שורת הפקודה?

    התשובה, לאור הנ"ל היא:

    • אם הפקודה היא מובנית/פנימית - כותבים את שם הפקודה
    • אם הפקודה היא חיצונית - אם הפקודה ממומשת על ידי תוכנה שנמצא בספריה הנוכחית או על ידי תוכנה שנמצא בתוך רשימת הנתיבים שב-PATH - אז ניתן להריץ אותה על ידי כתיבת שם קובץ ה-EXE (עם או בלי הסיומת - בתנאי שהסיומת היא מאלו שנמצאים ברשימת PATHEXT).
    • אם לא מתקיימים אף אחד מהתנאים הנ"ל, חייבים להביא ל-CMD את הנתיב המלא לקובץ, זה יכול להיות נתיב מלא שמתחיל משם הכונן (לדוגמה: c:\windows\system32\notepad.exe), או נתיב חלקי שמתחיל מהספריה הנוכחית (לדוגמה, נגיד שהספריה הנוכחית היא c:\users\yossi והקובץ נמצא בהורדות, נכתוב Downloads\XXXX)

    ⚠ במערכות לינוקס, אי אפשר להריץ תוכנה מתוך הספריה הנוכחית בלי לציין בפירוש ‎./XXXכלומר, נקודה, סלאש, ואז שם התוכנה (נקודה תמיד מציינת את הספריה הנוחכית), זה נכון גם אם הספריה הנוכחית הוא במקרה בתוך ה-PATH. בנוסף אי אפשר להשמיט את סיומת הקובץ ובד"כ אין סיומות לקבצי תוכנה. בנוסף חייבים לתת לקובץ התוכנה הרשאות ריצה (קבצים שהותקנו באמצעות מנהל החבילות של המערכת יקבלו את ההרשאה אוטומטית, קבצים שהורדו מהאינטרנט למשל, צריך לתת להם הרשאות ריצה על ידי הפקודה: chmod +x XXXX).


  • מדריך לשימוש בסיסי בתוכנת Procmon
    yossizY yossiz

    מה זה Procmon?

    Procmon ‏(Process Monitor) היא תוכנת ניטור שניתן לנטר באמצעותה אירועים במערכת ווינדוס.
    זה שימושי מאוד לדיבוג תקלות.
    איזה אירועים אפשר לנטר?

    • קבצים: פתיחה, סגירה, כתיבה, קריאה, מחיקה, ועוד
    • מפתחות רג'יסטרי: פתיחה, סגירה, כתיבה, קריאה, מחיקה, ועוד
    • רשת: אירועי רשת, חיבור, ניתוק, האזנה, שליחה, קבלה ועוד
    • תהליכים: הרצת תהליך, טעינת DLL, יצירת thread, סיום תהליך/thread ועוד

    כל אירוע מלווה בשלל מידע שימושי. מזהה תהליך, מזהה thread, צילום של ה-stack (מאוד שימושי!) ועוד.
    יש אפשרויות מתקדמות לסינון האירועים

    מאיפה מורידים?

    https://docs.microsoft.com/en-us/sysinternals/downloads/procmon
    התוכנה היא קובץ אחד (שמכילה בתוכה: גירסת x64 של התוכנה, וכן גירסאות x68 ו-x64 של הדרייבר שהתוכנה צריכה. התוכנה חולצת מתוכה את הקבצים הנצרכים בזמן ריצה!). אין צורך בהתקנה.

    הרצה

    קליק כפול על קובץ התוכנה, אם נתבקש נאשר הרצה כמנהל - אי אפשר להריצו בלי הרשאות ניהול- וזהו, אנחנו בפנים!
    (בהרצה ראשונה צריך לאשר את תנאי השימוש).
    הערה: אם אתה מבין מה זה stack trace וברצונך לעשות בו שימוש כדאי שתגדיר גם debugging symbols בתפריט options ‏> ‏configure symbols...‎

    החלון הראשי

    כך נראה החלון הראשי בפתיחה הראשונה:
    bbe444e1-23f4-4534-92b9-48fbb6fb1c78-image.png
    נשים לב לאיזור העיקרי - זה מכיל רשימה של אירועים. הרשימה הולכת וגדלה כל שנייה בעוד אלפי אירועים!
    בשורת המצב כתוב מספר האירועים שהוקלטו, וכמה מתוכם מוצגים:
    3ec62d90-b746-4b1d-86d2-12850b2210ed-image.png
    אז דבר ראשון נפסיק את ההקלטה לפני שהמספר יגיע למאות מליונים!
    לחיצה על fdaed507-8ea4-4413-9963-e81676c76f2b-image.png מפסיק את ההקלטה. לחיצה נוספת יתחיל אותה שוב.

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

    • Time of Day: זה "השעה:דקה:שנייה.מילי שנייה" של האירוע
    • Process Name: שם התהליך שגרם לאירוע
    • PID: מזהה התהליך (לפעמים יש כמה תהליכים עם אותו שם. אפשר להבחין ביניהם על ידי המזהה)
    • Operation: זה סוג האירוע. האייקון מצביע על הסוג הכללי (רג'יסטרי, קובץ, תהליך, או רשת). הטקסט מצביע על הסוג הפרטי, פתיחת קובץ קריאת קובץ וכו' וכו' (יש עשרות...)
    • Path: הנתיב של ה{קובץ, מפתח רג'יסטרי} או ה-IP + פורט + כיוון של תעבורת הרשת.
    • Result: תוצאת הפעולה. SUCCESS = הצלחה. אם לא הצליח, כתוב קוד השגיאה.
    • Detail: פרטים נוספים משתנים לפי סוג הפעולה.

    נעבור בקצרה על האייקונים בסרגל:

    • fa70531b-8bd8-4b86-9827-2b64cf7a9a23-image.png פתיחת הקלטה שנשמרה
    • 418e3be9-9ec0-405c-9771-c65b3f1274e6-image.png שמירת הקלטה
    • c24642be-40d6-43ce-af98-cc1be5940817-image.png התחל/עצור הקלטה
    • 0ff24ec4-aa92-46bb-a3c4-105567661c4f-image.png הפעל השבת גלילה אוטומטי של הרשימה
    • 1378f7ac-93a7-4cad-9b68-05e9fded0d24-image.png נקה רשימה
    • 1230f81b-c687-4699-ac65-a55ceb4fb8a3-image.png הגדרת סינון
    • b66923d5-159f-4163-9032-88cdd70619e4-image.png הגדרת סימון שורות לפי תנאים
    • c29520f6-77d1-4d74-b182-8ace382a5e8d-image.png אפשר לגרור את האייקון על גבי חלון של תוכנה וזה יוסיף את מזהה התוכנה ההוא לסנן הפעיל
    • e7e7ecf5-5f9b-4270-9eec-effdc341efc8-image.png פותח חלון עם רשימת התהליכים שהיו פעילים בעת ההקלטה
    • d0b3b632-b05a-451a-a986-ca6f39e2462c-image.png חיפוש תיבה ברשימה
    • 4ccf0ccb-095f-4def-b61c-cdfa3a2a4610-image.png פותח את הנתיב של השורה הנוכחי
    • 511884cc-9245-4262-aae3-5cd31fa526a2-image.png הפעלה/השבתה של סוגי אירועים: רג'יסטרי, קובץ, רשת, תהליך, profiling (לא נדבר על profiling בהדרכה זו)

    סינון

    עכשיו נגדיר מסנן. נלחץ על e77437b0-089a-4f4f-922b-e2d432942a99-image.png

    בברירת מחדל מוגדרים כבר כמה מסננים. מומלץ להשאיר אותם.
    לכל מסנן יש 4 שדות:
    10acba35-9e84-4a8c-9882-6d9bee6ec297-image.png

    1. הראשון הוא בחירת השדה לפיו נסנן. יש המון אופציות. העקריים הם

      • Process Name: לסנן לפי שם התהליך
      • PID: לפי מזהה תהליך במקרה שיש כמה תהליכים של אותו תוכנה
      • Operation: לסנן לפי אירוע
      • Path: סינון לפי נתיב קובץ/מפתח רג'יסטרי
    2. בחירת סוג תנאי לפיו נסנן:

      • is/is not: הערך המלא תואם/לא תואם לתנאי
      • less than/more than: על שדות של מספרים הערך שוה יותר/פחות מהערך של התנאי
      • begins with/ends with: הערך מתחיל ב/מסתיים בהערך של התנאי
      • includes/excludes: הערך של התנאי נמצא/לא נמצא איפשהו בערך של השדה
    3. פה נמלא את הערך של התנאי, כלומר שהתוכנה יבדוק את השדה שבחרנו ב-① מול מה שנכתוב כאן ולפיו יקבע אם התנאי מתקיים או לא. האופציות פה משתנות לפי מה שבחרנו בשדה ①. לדוגמה, אם ב-① בחרנו Operation, כאן נוכל למלאות אחד מהאירועים הזמינים, התפריט מתמלא עם הרשימה הזמינה של אירועים אפשריים. אם בחרנו בשדה ① Path, נמלא פה נתיב או חלק מנתיב (לפי מה שבחרנו בשדה ②)

    4. כאן נבחר אם קיום התנאי יגרום לשורה להופיע (include) או לא להופיע (exclude).

    הערה: אף פעם לא עמדתי על צורת ההרכבה של תנאים מרובים... האם זה OR או AND או האם אפשר לחבר חלק ב-OR וחלק ב-AND (לא נראה לי אפשרי, הלוואי...)... ניסוי וטעיה פשוט אמור להביא את התשובה... אם מישהו מתנדב לבדוק אשמח!

    דוגמה

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

    • נפתח את הגדרות המערכת על הדף של רקע שולחן עבודה.
    • נפתח את procmon ונגדיר סינון כמו בתמונה:
      • לחיצה על reset כדי לאפס את הסינוןן לברירת המחדל
      • נגדיר סינון על שדה path שהנתיב יכלול את המילה "wallpaper" (טפט). סביר להניח שאם הגדרוות רקע שמורות ברג'יסטרי או בקובץ כלשהו שהנתיב יכלול את המילה הזאת.
      • אחרי הגדרת סינון צריך ללחוץ "add" להוסיף אותו לרשימה.
      • נעשה עוד סינון על אירוע שכול את המילה set או write. זה יכלול רק פעולות של כתיבה לקובץ (WriteFile) או למפתח רג'יסטרי (RegSetValue). זה יוריד אלפי אלפים של שורות של קריאה. אנחנו מעוניינים רק בכתיבה ולא בקריאה.
        54e39cfc-5b31-4a39-8b0d-09d47284b8e9-image.png
      • אישור
    • עכשיו מתחיל ההקלטה
    • נעבור לחלון ההגדרות ונשנה רקע שולחן העבודה. נפסיק את ההקלטה.
    • נסתכל על הרשימה - והנה הסוד מתגלה לעינינו...
      HKCU\Control Panel\Desktop\Wallpaper

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

    הערה: במדריך זה כסינו רק שימוש בסיסי בתוכנה. מומלץ מאוד לעבור על קובץ העזרה, וגם לקרוא בבלוג של יוצר התוכנה עוד דוגמאות לשימוש בתוכנה (בד"כ הדוגמאות נמצאים בפוסטים שהכותרת שלהם מתחיל במילים ‎"The case of..."‎).

    בהצלחה!


  • ניתוח חולשת PwnKit
    yossizY yossiz

    ניתוח חולשת PwnKit

    הקדמה

    ביום שלישי השבוע פירסמו חברת Qualys על חולשה ברכיב נפוץ בהרבה הפצות לינוקס שמאפשר לכל משתמש במערכת לקבל הרשאות רוט. החולשה קיבלה את השם PwnKit - הרכבה של שם הרכיב הפגיע (Polkit) והמילה Pwn שהוא סלנג לפריצה.

    מה שמעניין, לדעתי, בחולשה זו יותר מחולשות אחרות שמתפרסמות יום יום, זה העובדה שלמרות שמדובר בחולשה מסוג memory corruption כאשר בד"כ חולשות מסוג זה הם קשים יותר להבנה למי שלא עמוק בתחום, כאן אפשר עם קצת מאמץ להבין את החולשה והמימוש של האקפלויט מא' עד ת'. תעיד על זה העובדה שאפשר למצוא נכון להיום כ-80 פרוייקטים בגיטהאב שעוסקים בחולשה זו.

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

    רקע

    setuid bit

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

    אחת מהמשתנים המרכזיים שמשפיעים על ההחלטה אם לאפשר או לסרב, זה "מה רמת ההרשאות של התהליך שמבקשת גישה?"

    במערכות *NIX (שם כללי לסוגי היוניקס למיניהם, כולל לינוקס), לכל תהליך מוצמד מזהה של היוזר שמריץ את התהליך, וזה קובע את רמת ההרשאות של התהליך.

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

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

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

    מנגנון זה הוא חרב פיפיות, מצד אחד זה מאפשר למשתמש רגיל לנהל את המחשב, מצד שני אנחנו לא רוצים לתת אפשרות לתהליך לא רצוי להסלים הרשאות. לשם כך, יש הרבה בדיקות וגדרים בתוך הקוד של sudo שמוודא שרק מי שמורשה יכול להשתמש בו. מכיון שכן, הקוד של כל בינארי שיש לו את ה-setuid bit חייב להיות מאוד מאובטח, ובלי באגים.

    משתני סביבה "מסוכנים"

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

    כאשר אנחנו מריצים תוכנה עם ה-setuid bit אנחנו רוצים שליטה מלאה על הקוד שרץ, ולא רוצים להריץ קוד אקראי בצורה לא מבוקרת. לשם כך, לפני הרצת התוכנה, מערכת ההפעלה "מנקה" את משתני הסביבה של התהליך, ומאפשרת רק משתני סביבה "מאובטחים" ולא "מסוכנים".

    Polkit ופקודת pkexec

    לא ניכנס יותר מדי לפרטים מה זה בדיוק polkit, רק נאמר שזה מנגנון נוסף בדומה ל-sudo שמאפשר לתהליכים להסלים הרשאות עבור פעולות מסויימות בצורה מבוקרת.

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

    מכיון שהפקודה צריכה להסלים הראשות, יש לפקודה את ה-setuid bit.

    אם רק נמצא באג בבדיקות אלו, נוכל לקבל הרשאות רוט!

    נמשיך כעת לחולשה עצמה!

    (מכאן והלאה דרוש קצת הבנה בתכנות)

    החולשה

    argc & argv

    כידוע, פקודות שמורצים במערכת הפעלה יכולים לקבל פרמטרים ששולטים על פעולת הפקודה. זה עובד בצורה כזו שמי שמריץ את הפקודה (בד"כ ה-shell, אבל זה יכול להיות כל תהליך) מבקש ממערכת ההפעלה להריץ תהליך חדש (פונקציית execve). פוקנציה זו מקבלת שלוש ארגומנטים, הראשון הוא נתיב לקובץ ה-exe של הפקודה. השני זה מערך של מחרוזות כאשר האבר האחרון במערך זה הוא NULL pointer, כל אבר במערך זה מצביע על מחרוזת של פרמטר שאתה רוצה להעביר לפקודה. זה נקרא argv (כלומר arg vector כאשר vector זה שם נרדף למערך). השלישי זה מערך נוסף של מחרוזות שנקרא envp שמכילה את משתני הסביבה שאתה רוצה להגדיר עבור התהליך.

    המילים "מערך של מחרוזות" טעונים ביאור, כי מי שמשתמש בשפות "נורמליות" יבין את הדברים בצורה לא נכונה. ביוניקס, וכל API/ABI מבוססת שפות C/C++ הכוונה במילים אלו הוא כזה:

    קודם כל נקדים כמה מושגים בסיסיים:

    מצביע (pointer) = unsigned int (= מספר חיובי) בגודל של מספר הסיביות של המעבד, שמצביע על כתובת במרחב הזכרון של התהליך

    NULL pointer = מצביע עם הערך של 0, זה מסמן "משהו שלא קיים".

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

    מחרוזת = "מצביע" (כנ"ל) על איזור בזכרון שמאחסנת רצף של 0 או יותר תווים, ואחריהם NULL (בייט עם הערך 0) שזה מסמן את סוף המחרוזת

    ובכן מה זה "מערך של מחרוזות"?

    מתרגמים את זה ככה: תעביר מצביע שמצביע על רצף של מצביעים כאשר המצביע האחרון הוא NULL, וכל אחד ממצביעים אלו מצביעים על רצף של תווים שאחריהם מגיע תו 0.

    מערך הפרמטרים מקובל לקרוא לו argv (vector זה שם נרדף למערך) וזו הצורה להעביר ארגומנטים לתהליכים.

    מערכת ההפעלה לוקחת המערכים אלו ומעתיקה אותם למרחב הזכרון של התהליך החדש.

    פונקציית main

    בתהליך החדש, הפונקציה הראשית (שנקרא בד"כ main) מקבלת כארגומנטים שני פיסות מידע, א) argc - זה int שערכו הוא מספר הפרמטרים שבתוך argv ב) argv שזה כנ"ל מצביע על מערך של מצביעים למחרוזות.

    argv[0]

    מקובל שהמחרוזת הראשונה במערך argv זה תמיד שם הקובץ של ה-exe. וכן הוא באמת כאשר מריצים תהליך דרך ה-shell או בדרכים מקובלות אחרות. אבל חשוב להבין שזו רק מוסכמה. אפשר בהחלט להריץ תהליך כאשר המחרוזת הראשונה זה "foobar" או NULL. (במקרה של NULL, ה-argc יהיה 0, ו-argv יצביע על מערך עם אבר אחד שערכו הוא 0)

    הקוד הפגיע

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

    435 main (int argc, char *argv[])
    436 {
    ...
    534   for (n = 1; n < (guint) argc; n++)
    535     {
    ...
    568     }
    ...
    610   path = g_strdup (argv[n]);
    ...
    629   if (path[0] != '/')
    630     {
    ...
    632       s = g_find_program_in_path (path);
    ...
    639       argv[n] = path = s;
    640     }
    

    מה אנחנו רואים פה?

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

    בשורה 435 יש הצהרה על פונקצית ה-main שמקבלת שני ארגומנטים (כנ"ל). מדלגים על כמה שורות לא קשורות, ובשורה 534 המתכנת רוצה לטפל בדגלים שמגיעים לפני הפקודה עצמה. אז הוא עובר בלולאה על הפרמטרים, בגוף הלולאה (לא מופיע פה) יש תנאי עצירה על הפרמטר הראשון שלא מתאים לשום דגל. מה שחשוב להבין הוא שכאשר יוצאים מהלולאה, הערך של n שווה לפרמטר הראשון שלא מתאים לשום דגל, כאשר זה יכול להיות גם ה-NULL שמסמן את סוף הפרמטרים. (כך חשב לעצמו המתכנת. האומנם זה נכון? נראה בהמשך...).

    שוב נדלג על כמה שורות לא מעניינות, ונגיע לשורה 610, ובו המתכנת מעתיק את המחרוזת שעליה מצביע argv[n] והוא מקבל חזרה מצביע שיצביע על המיקום של המחרוזת המועתקת. שוב מדלגים עד שורה 629 ובה אנחנו בודקים אם התו הראשון המחרוזת לא / (כלומר זה לא נתיב אבסוטלוטי, אלא נתיב יחסי או שם של פקודה בלי נתיב) ואז נצטרך לחפש ב-PATH אם קיימת פקודה עם שם זה. בשורה 632, המשתנה s מצביעה על מחרוזת חדשה שמכילה את הנתיב לפקודה ש-g_find_program_in_path מצאה. בשורה 639 (כנראה אחרי כמה בדיקות) המצביע s נכנסת ל-argv[n] במקום במצביע הקודם.

    בשורות הבאות כנראה התוכנה תבדוק אם להריץ או לא את הפקודה שמאוכסנת במחרוזת זו.

    הבאג

    איפה הבאג פה?

    תחשבו לעצמכם מה יקרה אם הערך של argc הוא אפס. הרי אפשר להריץ תוכנה עם מערך מחרוזות ריקה כנ"ל. מה יהיה הערך של n במקרה כזה? הוא יהיה 1. כי בתחילת הלולאה איתחלנו אותו ל-1, וגוף הלולאה לא הרצנו כי התנאי n < argc לא התקיים, אז n נשאר 1.

    על מה יצביע argv[n]? הוא יצביע על הערך שאחרי סוף המערך. כי הרי argv[0] יצביע על הערך היחיד שנמצא במערך שזה ה-NULL pointer ו-argv[1] יגלוש מחוץ למערך לערך הבא.

    ומה באמת נמצא שם? בד"כ מערכת ההפעלה שמה שם את המערך envp שנתקלנו בו למעלה בתיאור של פונקציית execve.

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

    אם עקבת עד כאן, אז א) כל הכבוד! וב) הבנת איך קיבלנו את היכולת לשלוט על אחד ממשתני הסביבה של התהליך באמצעות באג זה.

    בפוסט הבא (בעז"ה אם יהיה כח) ננסה להסביר איך אפשר לנצל עובדה זו להריץ תוכנה אקראית כרוט.


  • מדריך: שורת הפקודה
    yossizY yossiz

    טוב, הגיע הזמן לעוד פוסט...

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

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

    • "קובץ" בהקשר של ה-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 מייצג.

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

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

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

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

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

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

    ניתוב קלט

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

    להדגים את זה ניקח את הפקודה: findstr (זה ב-CMD, בבאש יש 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).
    חוץ מזה שהוא אריכות ללא צורך והשרצת תהליך מיותרת, יש עוד הבדל עדין, עיין בכתבה בוויקיפידיה.


  • מדריך: שורת הפקודה
    yossizY yossiz

    Pipes (צינורות)

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

    קבצים

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

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

    קלט ופלט

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

    1. הקלט (stdin או standard input), זה קובץ או כל דבר אחר שמדמה את הממשק של קובץ. זה פתוח לקריאה בלבד והפקודה קוראת מתוכה את הקלט שלה.
      כאשר מריצים קלט מתוך טרמינל, הקלט מחובר לטרמינל, כלומר הטרמינל מדמה ממשק של קובץ כאשר פעולת קריאה על ה"קובץ" מביא את הקלט שהמתשמש רושם בטרמינל.

    ℹ מה קורה כאשר פקודה מבקשת לקרוא מתוך הטרמינל ואין עדיין קלט להזין לו? הפקודה נעצרת עד שיש למערכת ההפעלה קלט להזין לו או עד ל-timeout שניתן להגדיר (ליתר דיוק ה-thread שביקש את הקלט נעצר).

    1. הפלט הרגיל (stdout או standard output), זה קובץ או כל דבר אחר שמדמה ממשק של קובץ. זה פתוח לכתיבה בלבד והוא הפלט ברירת המחדל עבור פלט רגיל של תוכנה.
      בברירת מחדל זה הטרמינל שמדמה ממשק של קובץ כאשר "כתיבה" ל"קובץ" מופיע בטרמינל.
    2. פלט השגיאות (stderr או standard error), זה קובץ או כל דבר אחר שמדמה ממשק של קובץ. זה פתוח לכתיבה בלבד והוא הפלט ברירת המחדל עבור לוגי שגיאות של תוכנה.

    ℹ למה יש שתי קבצים לפלט? כי לפעמים אנו רוצים לנתב את הפלט הרגיל למקום אחד ושגיאות למקום שונה

    הנ"ל הם קבצי ברירת המחדל, כל תוכנה יכולה לפתוח עוד קבצים גם כן. אבל קבצים אלו תמיד קיימים כי ה-shell פותח אותם עבור תוכנה.

    ⚠ התיאור הנ"ל על קלט ופלט מדוייק לגבי מערכות הפעלה ממשפחת UNIX, (לינוקס, מאק, BSD וכו'). בווינדוס המצב קצת שונה, למרות זאת חלק גדול מהדברים עדיין תקפים והשימוש ב-pipes דומה

    PIPE

    על פי הנ"ל נבוא להסביר מה זה pipe.

    Pipe הינה "קובץ" ווירטואלי (כלומר שאין קובץ מקביל בדיסק הקשיח, ובד"כ אין לו שם או נתיב במערכת הקבצים), שמדמה צינור, כל מה "ששופכים" (= פעולת כתיבה) בצד אחד יוצא (= הוא זמין לפעולות קריאה) כמות שהוא בצד השני. צד אחד של ה-pipe תמיד פתוח רק לכתיבה והצד השני רק לקריאה.
    דבר זה מאפשר שירשור פקודות בצורה שהפלט של פקודה א' נהיה הקלט של פקודה ב' וכן הלאה.

    זה מנגנון עוצמתי במיוחד שמאפשר בניית פקודות מורכבות מאוד.

    דוגמה

    ניקח כדוגמה את המקרה שהזכרנו בתחילת דברנו, חיפוש אם קובץ מסויים קיים בתיקייה.
    לצורך זה נשתמש בשתי פקודות, הראשון פולטת רשימה של קבצים שנמצאים בתקייה, השנייה מחפשת אם מחרוזת מסויימת קיימת בתוך הקלט של הפקודה.
    לצורך הביצוע נייצר pipeline (= מחרוזת של פקודות שמחוברות על ידי pipe) שנראה כך:

    Bash:

    ls folder1 | grep filename
    

    CMD:

    dir folder1 | findstr filename
    

    ה-pipeline שלנו מורכבת משתי פקודות: ls או dir ו-grep או findstr
    הראשון פולט רשימה של כל הקבצים שנמצאים בתקייה שמזינים בפרמטר של הפקודה (folder1) והשני מחפש בקלט של עצמו מחרוזת (filename) שהגדרנו לו בפרמטר הראשון.
    הפקודות מחוברות באמצעות תו | שמסמל pipe.

    כאשר ה-shell מריץ את הפקודות קורה התהליך הבא:

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

    הפקודה השנייה תדווח לנו אם המילה שביקשנו נמצאה בתוך רשימת הקבצים שהפקודה הראשונה הוציאה.

    בפוסט הבא נדבר קצת בעז"ה על ניתוב קלט ופלט.


  • למה אסור להשתמש ברכבת בעל 256 זוגי גלגלים בשווייץ?
    yossizY yossiz

    בשווייץ יש תקנה שאסור שיהיה לרכבת בדיוק 256 זוגי גלגלים

    התוכלו לנחש למה?

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

    ציטוט מתוך ספר שמדווח על התופעה:

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

    c516fbc6-0e2d-47b8-a13c-fdf26599503c-image.png
    bf51edd8-d18a-40e6-857c-a7777919b86f-image.png


  • שיתוף: 🔖 סימניה להורדת תוסף כרום
    yossizY yossiz

    סימניה להורדת קבצי CRX מחנות כרום.
    מפעילים את הסימניה, מכניסים מזהה של תוסף (לדוגמה: aapbdbdomjkkjkaonfhkkikfgjllcleb) או כתובת של תוסף בחנות (לדוגמה: https://chrome.google.com/webstore/detail/google-translate/aapbdbdomjkkjkaonfhkkikfgjllcleb) וזה מוריד את התוסף בשבילך.

    javascript:id = prompt("הכנס מזהה או כתובת התוסף"); (id = /[a-z]{32}/.exec(id)) ? window.open("https://update.googleapis.com/service/update2/crx?response=redirect&acceptformat=crx3&prodversion=38.0&testsource=download-crx&x=id%253D"+id[0]+"%2526installsource%253Dondemand%2526uc"): alert("מזהה או כתובת לא חוקי")
    

  • מדריך: שורת הפקודה
    yossizY yossiz

    שרשור פקודות

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

    קוד יציאה

    אחד מהדרכים שבהם תהליכים מתקשרים עם הסביבה הוא על ידי החזרת "קוד יציאה" בסיום ההרצה. קוד היציאה הוא ערך מספרי. יש מוסכמות שונות במערכות הפעלה שונות לגבי מה מספרים שונים מייצגים ומה הגודל המקסימלי של המספרים. אבל יש משהו אחד ששווה לכל המערכות הפופולאריות וזה שמספר 0 מייצג הצלחה ומספר אחר מייצג כשלון. למה? פשוט כי יש דרך אחד שבו ניתן להצליח ויש מליון דרכים שבהם ניתן להיכשל.

    ב-CMD ניתן לקבל את קוד היציאה של הפקודה האחרונה במשתנה %errorlevel%. בבאש ניתן לקבלו במשתנה ‎$?‎.

    שרשור בסיסי

    ניתן להשתמש בקוד היציאה של תהליך כדי לשרשר תהליכים בצורות שונות.

    • הרץ את הפקודה השנייה רק אם הראשונה הצליחה
    command1 && command2
    
    • הרץ את הפקודה השנייה רק אם הראשונה לא הצליחה
    command1 || command2
    

    ℹ קוד היציאה של השרשור הוא קוד היציאה של הפקודה האחרונה בשרשור, ייתכן שההתנהגות של ביטויים לוגיים ב-JS (למי שמכיר) הושפע מה-shell

    • הרץ את הפקודה הראשונה ואח"כ את השנייה בכל מקרה
    • CMD
    command1 & command2 
    
    • bash
    command1; command2
    

    If

    עוד דרך להשתמש בקוד היציאה כדי להשפיע על הפקודות הבאות הוא השימוש בביטוי "if" (=אם).

    דוגמאות ב-CMD:

    • אם קוד היציאה של command1 שווה (EQU) 0 (כלומר הצליחה) הרץ command2 אחרת הרץ command3:
    command1
    IF %ERRORLEVEL% EQU 0 (command2) ELSE (command3) 
    
    • אם קוד היציאה של command1 הוא בין 10 ל-20 הרץ command2:
    command1
    IF %ERRORLEVEL% GTR 10 (
       IF  %ERRORLEVEL% LEQ 20 (
         command2
       )
    )
    

    ℹ התחביר של CMD הוא פרימיטיבי קשה ומסורבל לעומת bash או powershell. יש אתר מצויין שמתעד אותו: https://ss64.com/nt ניתן ללמוד משם הכל. אבל אין צורך להכיר את כל הפינות של השפה, מספיק להכיר מלמעלה את היכולות ואז לבדוק במקרה הצורך באתר הנ"ל. אני השתמשתי בו עבור הדוגמאות הנ"ל.

    דוגמאות ב-bash:

    • אם קוד היציאה של command1 שווה 0 (כלומר הצליחה) הרץ command2 אחרת הרץ command3:
    if command1; then command2; else command3; fi
    
    • אם קוד היציאה של command1 הוא בין 10 ל-20 הרץ command2:
    command1
    if [[ $? -gt 10 && $? -le 20 ]]; then command2; else command3; fi
    # או
    if [ $? -gt 10 -a $? -le 20 ]; then command2; else command3; fi
    # או
    if [ $? -gt 10 ] && [ $? -le 20 ]; then command2; else command3; fi
    # או
    if (( $? > 10 && $? <= 20 )); then command2; else command3; fi
    

    ℹ ב-CMD הביטוי if בוחן את התוצאה של ביטוי בוליאני (ביטוי שתוצאתה הינו true או false), ב-bash ביטוי if תמיד בוחן קוד יציאה של פקודה. יש לצורך זה כמה פקודות "מיוחדות" כמו ], ‏[[ ... ]], ‏(( ... )) ו-test. פקודות אלו מקבלות ביטוי בוליאני ומחזירים קוד יציאה של 0 במידה והתוצאה היא true וקוד יציאה של 1 במידה והתוצאה false.

    ⚠ למי שמכיר שפות תכנות: שימו לב, ביטוי if ב-bash עובד בדיוק הפוך מבכל שפות התכנות. קוד יציאה של 0 נחשב כהצלחת מבחן ה-if וקוד לא אפסי נחשב ככשלון.

    בפוסט הבא בעז"ה נרחיב על pipes.


  • "חידה מתמטית פשוטה" או "למה אין לי אינטואיציה מתמטית בריאה?"
    yossizY yossiz

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

    שים לב, שיעור התפו"א לא השתנה - רק המים
    בהתחלה היה 1ק"ג תפו"א וכך בסוף
    רק שבהתחלה ה-1 ק"ג הזה היה 1% מהמשקל הכולל
    אח"כ זה נהיה 2%
    אז תשאל את עצמך, "1 ק"ג הוא 2% אחוז של מה?"
    והתשובה היא 50 ק"ג.
    הוי אומר, 50 ק"ג מים התאדו כדי להגיע להרכב החדש.

    לרוב אנשים האינטואיציה אומרת ששינוי מספרי קטן בהרכב נובע מפעולה קטנה.

    טוב, אז עכשיו צריך ללכת לעבודה, לעבוד על האינטואיציה השגויה שלנו.
    אתה יודע כמה החלטות אתה עושה יומיומי על סמך אינטואיציה?
    עד כמה ניתן לסמוך עליו?


  • צלילה לעומק TS: טייפ X לא זהה ל-union של כל הערכים האפשריים שהטייפ כולל
    yossizY yossiz

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

    מכיון שאני כותב את הפוסט בהמשכים אשמח אם התגובות יהיו בנושא נפרד

    התוכנית:

    • קורס מזורז ב-TS
    • קטעי הקוד המוקשים לכאורה
    • התשובה

    מקווה שיהיה קל לקריאה ולתועלת

    ובכן, אעביר אותך קורס מזורז מאוד ב-TS:

    מה זה טייפ

    דרך אחת להסתכל על טייפ הוא ככה:
    👈 טייפ הוא סט (set - כן, ההוא מתורת הקבוצות...) של ערכים.
    לדוגמה:

    • הטייפ number מייצג את הסט שכולל בתוכו את כל המספרים
    • הטייפ 1 מייצג סט שכולל בתוכו ערך אחד: המספר 1, כמו"כ כל ערך ב-JS הוא גם שם של טייפ שכולל חבר אחד - הערך הזה בעצמו
    • הטייפ { foo: string; bar: number } מייצג את הסט שמכיל כל האובייקטים האפשריים שמכילים שדה foo מסוג string ושדה bar מסוג number
    • הטייפ never מייצג סט ריק. סט בלי חברים.
    • הטייפ unknown מייצג את הסט של כל הערכים האפשריים. "סט סטי הסטים". הסט הכי גדול ביקום הטייפים. לכן אין הרבה מה לעשות עם ערך מסוג unknown כי אתה לא יודע איזה פעולות מותרים לעשות איתו.

    דרך נוספת לחשוב על טייפים:
    👈 הטייפ של הערך אומר לנו איזה פעולות מותרות על הערך
    למשל:

    • הטייפ number אומר לנו שמותר לעשות פעולת חיבור וחיסור על ערך זה עם מספרים אחרים
    • הטייפ string אומר לנו שמותר לנו לקרוא לפונקציה בשם startsWith על הערך שלנו
      וכן הלאה

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

    מתמטיקה עם טייפים:

    TS נותן שני כלים אריתמטיים לבניית טייפים מורכבים מטייפים אחרים:

    חיבור - UNION

    האופרטור | ב-TS עושה את פעולת החיבור באריתמטיקה של טייפים
    למשל:

    • טייפ 1 | 2 מייצג חיבור של שני הסטים 1 ו-2. התוצאה היא סט (טייפ) שכולל שני חברים, 1 ו-2
    • string | number מחבר את שני הסטים והתוצאה היא סט גדול שכולל בתוכו כל המחרוזות האפשריים וכל המספרים האפשריים
    • חיבור עם never (להזכירכם: זהו הסט עם 0 חברים) הוא כמו פעולת חיבור מספרי של מספר כלשהו עם 0. הפעולה לא משנה את הערך המקורי.

    חיסור - INTERSECTION

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

    • { foo: string } & { bar:number } לוקח את הסט שכולל כל האובייקטים האפשריים שיש להם שדה foo מסוג string, וכן את הסט שכולל כל האובייקטים האפשריים שיש להם שדה bar מסוג number, והוא מחזיר סט של כל האובייקטים האפשריים שחברים בשתי הקבוצות: דהיינו אובייקטים שיש להם גם שדה foo וגם שדה bar
    • פעולת & unknown לא עושה כלום כי כל ערך אפשרי נמצא בתוך סט ה-unknown

    תכנות עם טייפים

    TS נותן כלים יותר משוכללים לבניית טייפים על ידי "תכנות"

    פונקציות - GENERICS

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

    • פונקציה שמקבל נוסח תפילה ופולט את הטייפ של היהודי עם נוסח תפילה זו:
    // הצהרת טייפ שכולל כל נוסחאות התפילה האפשריים
    type Nusach = 'Ashkenaz' | 'Sefarad' | 'Edot Hamizrach'
    
    // הצהרת טייפ גנרי שמקבל נוסח תפילה ומחזיר טייפ של יהודי שמתפלל בנוסח הנ"ל
    type Jew<T extends Nusach> = {
      name: string
      nusach: T
    }
    
    // ערך עם שדה שם ושדה נוסח 
    const aJew = {
        name: 'Zundel',
        nusach: 'Ashkenaz'
    }
    
    // נסיון השמה למשתנה מסוג Jew<'Sefarad'>
    // TS מתריע על אי התאמה בין הטייפ לערך
    const test: Jew<'Sefarad'> = aJew
    

    השורה האחרונה תפלוט שגיאה, כי טייפ מסוג Jew<'Sefarad'> לא יכול להתפלל נוסח אשכנז

    מילת המפתח extends

    בדוגמה דלעיל נתקלנו לראשונה (בקורס הזה) במילת המפתח extends, ב-TS הכוונה של extends הוא (לפי צורת החשיבה שהצגנו בתחילת דברינו) שהטייפ שבצד שמאלי כולו חבר בסט שמיוצג על ידי הצד הימני.
    ובדוגמה הנ"ל: T extends Nusach הכוונה הוא שהפרמטר T רק מקבל טייפים שהם חברים בסט Nusach
    אם ננסה ליצור יהודי כזה: Jew<'foo'> נקבל שגיאה שהמחרוזת foo הוא לא חבר בקבוצת Nusach

    נפגוש שוב את המילה extends בהמשך

    תנאים

    התחביר לכתיבת תנאי ב-TS:

    T extends U ? V : W
    

    שימו לב לנקודות הבאות:
    בתכנות רגיל אנחנו מורגלים לבדיקת המון דברים בתנאים, וכן לשלוט על פעולות מגוונות על ידי תנאים אלו
    ב-TS לעומת זאת:

    • הפרט היחיד שאפשר לבדוק בתנאי הוא extends - כלומר, חברות של הצד השמאלי בצד הימני
    • הדבר היחיד שאתה יכול לתלות בתנאי הזה הוא הטייפ של התוצאה של הביטוי

    דוגמה לשימוש בתנאי ופונקציה ביחד:

    type LabelOf<T> = T extends { label: string } ? T['label'] : 'no name' 
    

    Index Signatures

    אפשר לתאר את ה-shape של אובייקט בלי לפרט בדיוק את השם של השדות, במקום זה כותבים את הטייפ של המפתחות והטייפ של הערכים
    לדוגמה:

    type X = {
      [key: string]: number
    }
    

    הכוונה בהצהרה זו הוא שמדובר באובייקט שיש בו מפתחות מסוג string וערכים מסוג number

    לולאות - Mapped Types

    TS לוקח את התחביר הזה שלב נוסף קדימה באמצעות mapped types
    בתחביר זה אפשר לעבור בלולאה על כל הערכים האפשריים הכלולים במפתח (key) ולקבוע את הטייפ של הערך עבור אותו מפתח לפי כל לוגיקה שתבחר
    דוגמה:

    type MyMap<T> = {
        [K in keyof T]: K extends `${string | undefined}foo${number}` ? string : number
    }
    
    type Test = MyMap<{ foo1: any, a_foo2: any, bar3: any }>
    

    keyof

    כאן אנחנו נתקלים לראשונה במילת המפתח keyof:
    זה אופרטור שמחזיר union של כל שמות השדות של האופרנד שלו
    למשל: keyof {foo:any, bar:any} שווה ל-'foo' | 'bar'

    ה"פונקציה" (יותר מקובל לקרוא לו generic type) MyMap מקבל פרמטר T (מכיון שלא הגבלנו אותו על ידי מילת המפתח extends - הוא יכול להיות מכל סוג שהוא), ומחזיר אובייקט שיש לו אותם שדות של האובייקט המקורי, אבל אם התבנית של שם השדה מתאים לתבנית מחרוזת אופציונלית + foo + מספרי כלשהו, אז הערך של השדה חייב להיות string, אחרת הערך חייב להיות number

    יותר מקובל ושימושי להשתמש ב-mapped types עם תנאי שבודק את הטייפ של ה_ערך_ של האובייקט המקורי במקום תנאי שבודק את הטייפ של ה_מפתח_ של האובייקט המקורי. עושים את זה על ידי אינדוקס ככה:

    type MyMap<T> = {
        [K in keyof T]: T[K] extends X ? Y : Z
    }
    

    נראה דוגמה שימושית לזה מיד בקטע הבא

    דוגמה אחרונה: Omit

    בוא נבדוק את ההבנה שלך על ידי הדוגמה הבאה.
    (ההגדרות Exclude ו-Omit מגיעים מובנים ב-TS)

    // type Omit<T, K extends keyof any> = { [P in Exclude<keyof T, K>]: T[P]; }
    // type Exclude<T, U> = T extends U ? never : T
    
    type MyObject = {
        id: number
        foo: string
        bar: number
    }
    
    type MyObjectWithoutId = Omit<MyObject, 'id'>
    

    טוב, התעייפתי לבינתיים, אמשיך בעז"ה בהזדמנות הבאה...


  • מדריך: שורת הפקודה
    yossizY yossiz

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

    השלמה בנושא File handles (המכונים גם File descriptors)

    רקע

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

    מימוש בווינדוס ולינוקס

    הזכרנו שלכל תהליך שה-shell מריץ קיימות בברירת מחדל 3 ידיות לקבצים. מספרי הידיות הם 0,1 ו-2 והם מייצגות את הקבצים של הקלט/פלט/ושגיאות.
    במערכות מבוססות לינוקס מספרים אלו באמת מייצגות את הידית של מערכת ההפעלה. אפשר לראות את זה על ידי הפקודה:

    lsof -a -p $$ -d0,1,2
    

    זה מראה את הידיות 0,1,2 של ה-shell עצמו.
    והתוצאה אמורה להיות משהו כמו זה:

    COMMAND   PID      USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    bash    16104 yossizahn    0u   CHR  136,2      0t0    5 /dev/pts/2
    bash    16104 yossizahn    1u   CHR  136,2      0t0    5 /dev/pts/2
    bash    16104 yossizahn    2u   CHR  136,2      0t0    5 /dev/pts/2
    

    הנתיב ‎/dev/pts/2 מכיל את הקובץ שמייצג את חלון הטרמינל (ע"ע PTY)

    ℹ הסבר הפקודה כאן; אגב, אתר מגניב, לא?
    המשתנה $$ מייצגת את ה-PID של ה-shell עצמו

    אם נבצע ניתוב פלט על ידי פקודה כזו:

    exec 2> ~/error.log 
    

    נקבל טבלת ידיות כזה:

    COMMAND  PID      USER   FD   TYPE DEVICE SIZE/OFF   NODE NAME
    bash    3460 yossizahn    0u   CHR  136,2      0t0      5 /dev/pts/2
    bash    3460 yossizahn    1u   CHR  136,2      0t0      5 /dev/pts/2
    bash    3460 yossizahn    2w   REG    8,0        0 519201 /home/yossizahn/error.log
    

    והנה הידית עם מזהה (FD = File Descriptor)‏ 2 באמת פונה לקובץ error.log.

    ℹ הפקודה exec עם ניתוב גורם לנתב את הפלט של ה-shell עצמו. עיין help exec.
    פקודת help נותנת עזרה על פקודות "מובנות" או "פנימיות".
    ➕ בונוס: תלמדו את הייעוד של פקודת exec ותסבירו למה היא חייבת להיות פקודה מובנית/פנימית ולא פקודה חיצונית

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

    ניתן לראות את הידיות של תהליך בכלי הנפלא process hacker.

    ככה נראה רשימת הידיות של תהליך CMD שהרצתי:
    19a96ca7-bb06-4df1-a11b-afba86f99eb1-image.png

    [סיננתי את הרשימה להראות רק ידיות מסוג File]

    אפשר לראות שאין שם ידיות עם המספר 0,1,2. אז איפה הם?

    התשובה היא שלשם תאימות עם מנגנון זה שמקובל בשורות פקודה של מערכות הפעלה, יש מטהדאטה נוסף שמוצמד לתהליך (ה-PEB) שכולל בתוכו את המידע שממפה ידיות ה-native-ים לידיות 0,1,2.

    לא מצאתי בינתיים דרך פשוטה להסתכל במיפוי הזה.

    אבל יש דרך לא פשוטה... 🙂

    בא ננסה ביחד!
    ⚠ החלק הבא למתקדמים בלבד...

    • נפתח את תוכנת windbg ונבחר מתוך התפריט attach to process.
      5c0510fb-8ca2-467f-b70d-fc664ca85f6c-image.png
    • ברשימת התהליכים נבחר את התהליך שנרצה לקבל מידע עליו.
      9169c634-74b3-44a6-b4a9-4fd40742f448-image.png
      [אפשר לסנן את הרשימה לפי שם התהליך]
    • עכשיו נריץ את הפקודה הבאה בחלון command:
    dt _peb @$peb
    

    ℹ פקודת dt מציג דאטה בצורה יפה (dump בלע"ז), הפרמטר ‎_peb אומר להציג את זה כמבנה מסוג ‎_peb. הפרמטר ‎@$peb מתורגם לכתובת של מבנה ה-PEB.

    • נקבל dump של מבנה ה-PEB. מתוך זה נבחר את התת אובייקט: ProcessParameters.
      למזלינו windbg מספיק חכם לדעת איך לתרגם את האובייקט הזה, והוא מציג אותו כקישור שבלחיצה עליו מורצת אוטומטית הפקודה שתעשה dump עליו:
      48e63683-45e7-487d-9e6b-58e65808be3f-image.png

    • בפלט של הפקודה, סמוך לתחילת הרשימה נראה את המיפוי של הקלט,פלט,ופלט שגיאות:
      c2d451a3-89ea-4846-834d-f4026af35990-image.png

    כל שורה הוא סוג הפלט/קלט עם ערך של הידית שמשוייך אליו.

    עכשיו אפשר לחזור ל-process hacker ולקבל את הנתיב של הקובץ לפי המזהה.

    (נראה לי שבדיבוג ב-user mode אין דרך פשוטה לקבל את הנתיב של הקובץ מ-windbg, (רק בדיבוג קרנל אפשר) אבל יש דרך מסובכת מאוד, עיין כאן)

    טוב, נראה לי שקצת נסחפתי... 🙂 בפוסט הבא נחזור שוב לנושאי שורת הפקודה


  • הסבר על פורום תכנות המצומצם
    yossizY yossiz

    @dovid אמר בהסבר על פורום תכנות המצומצם:

    תכלס כיום כמעט אין סיבה להצטרף לפורום המצומצם

    @dovid מאוד לא אהבתי לקרוא את הדברים.
    אני לא יודע להצביע באמת על תועלת ספציפית שהשואל הזה יקבל מהצטרפות לפורום הסגור, אם בכלל,
    אבל הדברים מאוד צרמו לי כי אני אישית קיבלתי המון תועלת (גם מהפורום הכללי אבל עוד יותר) מהאנשים שפעילים ותורמים בפורום הסגור, ההצטרפות לפורום תחומים היווה עבורי סוג של מפנה בחיי כאשר לפני כן לא היה לי שום חברה/קהילה בתחום המחשבים/תכנות, ואחרי ההצטרפות (כמובן רק במשך כמה שנים) יצא לי להכיר הרבה(!) אנשים איכותיים מאוד! רק דרך הפורום (כמובן שהמילה "הרבה" ביחס למצרך נדיר לא מייצג מאות... אבל הרבה ביחס לנדירות).
    בעיני פורום זה הוא מכרת זהב עבור מי שמחפש חברה איכותי, מצרך מאוד נדיר ברחבי האינטרט (גם ב"אינטרנט החרדי" אם אפשר לקרוא לזה כך)


  • ניתוח חולשת PwnKit
    yossizY yossiz

    פרק ג - סיכום ולקחים

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

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

    למתכנתנים

    הלקח למתכנתים ברור:

    • תשתמשו בשפות בטוחות. בשפה אחרת באג זה היה נשאר באג, ולא היה מגיע לכדי חולשה.
    • תבדקו את ההנחות הסמוייות בקוד שלכם, בקוד הזה יש הנחה סמוייה שתמיד יש לפחות ארגומנט אחד במערך argv. הנחה שהתבררה כשגויה.
    • גם קוד נפוץ כזה שנמצא כבר בפרודקשיין 12 שנים חשוף לבאגים כאלו. אל תמעיטו בהערכת היצירתיות של התוקפים, והסיכוי לבאגים בקוד שלכם.

    למתעניינים בסייבר

    נהנית מהמאמר? אולי אתה אוהב את תחום הסייבר?
    תוכל להפיק מכאן כמה לקחים:

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

    אם יש לך מה להוסיף או להעיר, אשמח מאוד לשמוע בתגובות. תודה רבה!

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


  • האנטומיה של שאילתת SQL
    yossizY yossiz

    אני רוצה לשתף קצת מה שלמדתי לאחרונה על שאילתות SQL. המדריך מיועד למתחילים, למה? כי גם אני מתחיל...
    למה אני כותב אותה? א) כי זה עוזר לי ללבן את הנושא. ב) אולי יהיו פה ושם נקודות שגם הותיקים לא הכירו. או שאצליח להאיר את הנושא מזווית שלא חשבו עליו.

    הקדמה ל-SQL ולמדריך

    המדריך מדבר על האנטומיה של שאילתות SQL. אני לא הולך להסביר את הצורה שבה שומרים נתונים בטבלאות ויוצרים חיבורים בין טבלאות. אני לא הולך לדבר על המון נושאים לא פחות חשובים אחרים שקשורים ל-SQL.

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

    טיפת תחביר

    התחביר של שאילתת SQL נראה כך:
    SELECT <עמודות...>
    FROM <טבלאות...>
    WHERE <תנאים>
    GROUP BY <ביטוי>
    HAVING <תנאים>
    ORDER BY <ביטוי>
    OFFSET <מספר>
    LIMIT <מספר>
    (נראה לי שבשני החלקים הנ"ל יש שינויים בין המנועים)
    ; (לסיום המשפט)

    כמה נקודות (בלתי אפשרי להקיף פה את הכל, אני רק כותב כמה נקודות):

    • השפה הינה case insensitive, (לא מבדילה בין אותיות גדולות לקטנות). אפשר לכתוב SeLecT גם כן.
    • שמות הטבלאות והעמודות הם בברירת מחדל case insensitive. תבדקו את התיעוד של המנוע שלכם לגבי יצירת עמודות שהם case sensitive ואיזכורם. ב-postgres אם שם העמודה הינה case sensitive צריך להזכיר את שם העמודה והטבלה בתוך גרשיים (לא ככה: "Table.Column" וגם לא ככה: 'Table.Column' או ככה: 'Table'.'Column' אלא ככה: ‎"Table"."Column"‎ - כן כן, מגעיל... בשנות השמונים או השבעים לא ידעו לעשות תחבירים אלגנטיים כנראה...).
    • לא כל החלקים חיוביים. בעיקרון אפשר להשמיט את הכל חוץ מה-SELECT. כל השאר הם אופצינאליים לפחות בחלק מהמקרים. חלק מהם הם חיוביים במקרים מסויימים. (עזרתי מאוד, לא? הכללים הם הגיוניים ולא קשים לניחוש אחרי שאתה מכיר את המבנה של השאילתה שנרחיב עליו בקטע הבא).

    השאילתה הלוגית

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

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

    סדר הפעולות היא כזאת:

    • FROM - בחירת טבלה גולמית (כולל חיבורים עם טבלאות אחרות).
    • WHERE - סינון השורות
    • GROUP BY - קיפול של כמה שורות לתוך שורה אחת
    • HAVING - שוב סינון על השורות המקופלות
    • SELECT - בחירת עמודות מתוך התוצאה של השלבים הקודמים (כולל יצירת עמודות חדשות שמחושבות מהתוצאה של השלבים הקודמים)
    • DISTINCT - מחיקת כפלויות
    • UNION - חיבור תשובות משאילתה אחרת
    • ORDER BY - מיון השורות
    • OFFSET דילוג לשורה מסויימת
    • LIMIT - מחיקת השורות מה-limit והלאה.

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

    עכשיו נפרט קצת על כל שלב.

    FROM - בחירת טבלה גולמית

    כמה נקודות:

    • שלב זה אופציונאלית. אם משמיטים את השלב הכוונה היא שאנחנו רוצים שהמנוע יחזיר טבלה חדשה יש מאין. צריך להשמיט גם את כל השלבים עד שלב ה-SELECT כי כולם הם פעולות על הטבלה הגולמית - שלא קיימת במקרה זו.
      אפשר להשתמש ב-SELECT ערטילאית כמו סוג של echo או console.log כדי לקבל את הערך של ביטוי. לדוגמה SELECT 20+4;‎ מחזיר טבלה של 1×1 עם הערך 24. או SELECT sqlite_version();‎ ב-sqlite מחזיר טבלה של 1×1 עם הערך של הגירסה של המנוע.
    • ה-FROM מקבלת כל ביטוי שמחזיר טבלה.
      ביטויים שמחזירים טבלאות:
      • שם של טבלה, לדוגמה FROM "SomeTable"‎
      • פונקציה שמחזירה טבלה, לדוגמה FROM generate_series(1,100)‎ (הפונקציה generate_series ב-postgres מחזירה טבלה - [תיעוד])
      • שאילתה שמחזירה טבלה, דוגמה: FROM (SELECT * FROM "SomeTable")
      • ביטוי שמחזירה טבלה משולב עם עוד ביטוי שמחזירה טבלה באמצעות JOIN

    JOIN - חיבור כמה טבלאות ביחד

    אפשר לחבר כמה טבלאות ביחד על ידי פעולת JOIN.
    התחביר של JOIN:

    • <טבלה> (ביטוי שמחזיר טבלה, כנ"ל)
    • JOIN (עם פירוט של סוג ה-JOIN)
    • <טבלה> (ביטוי שמחזיר טבלה, כנ"ל)
    • ON <תנאי> (או USING <עמודה>)

    הביטוי מחזיר טבלה חדשה שמשלב את שתי הטבלאות המקוריות לפי התנאים שהצבת.

    יופי, קיבלנו את הטבלה הגולמית, עכשיו נעבור לסינון

    WHERE - סינון שורות

    התחביר של WHERE:

    • WHERE <תנאי>

    זהו!
    מהו התנאי? זה ביטוי שמחזיר ערך בוליאני (TRUE או FALSE).
    המנוע מעביר את כל השורות דרך התנאי ומוחקת את השורות שלהם הביטוי מחזירה FALSE. כאשר בתוך הביטוי אפשר להזכיר את הערכים של השורה שמועברת דרכה.
    דוגמאות:

    • WHERE 1 - תמיד מחזיר TRUE
    • WHERE "SomeColumn" = 25‎‎
    • WHERE some_condition() AND another_condition OR something_else()‎

    בקיצור הביטויים הם עוצמתיים מאוד, אפשר להוסיף כאן לוגיקה מסובכת

    אפשר להשמיט לגמרי את ה-WHERE ואז לא מתבצעת סינון

    GROUP BY - קיפול כמה שורות לתוך שורה אחת

    התחביר:
    GROUP BY <ביטוי שמחזיר עמודה>
    הפעולה: פעולה זו מקפלת כמה שורות לתוך שורה אחת, מעתה ולהלן לא תוכל לקבל את הערך של שורה ספציפית מתוך השורות המקופלות אלא ערך של פונקציה שמסכמת את כל הפריטים ביחד. לדוגמה סך כולל על ידי פונקציית SUM או ממוצע על ידי פונקציית AVG. או הכי גדול או הכי קטן על ידי פונקציות MIN ו-MAX.

    HAVING - שוב סינון

    HAVING פועל בדיוק כמו WHERE אלא שכאן אפשר לסנן לפי התוצאה של סיכום השורות שמתקבל על ידי פונקציה מסכמת שמורצת על כל השורות המקופלות באותה שורה.

    SELECT - בחירת או יצירת עמודות לטבלה הסופית

    סוף סוף קיבלנו את הדאטה הגולמית שאותה אנחנו רוצים להציג, אחרי כל המניפלציות. בשלב זה אתה מגדירים את העמודות שאנחנו רוצים להציג מתוך הדאטה.
    אפשר לבחור עמודות קיימות, או אפשר לייצר עמודות חדשות.
    לדוגמה: SELECT "SomeColumn", "AnotherColumn", "SomeColumn" * 50 / 2 - בחרנו שתי עמודות קיימות, ויצרנו עמודה שלישית שמחושבת מתוך העמודה הראשונה.

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

    DISTINCT - מחיקת כפילויות

    אחרי שבחרנו את העמודות נוכל להעביר את התוצאה דרך עוד סינון אחרון אחרון. הסינון הזה מוחקת שורות כפולות לפי עמודה שאתה בוחר.

    UNION - חיבור לתשובות של שאילתה אחרת

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

    ORDER BY - מיון

    ניתן למיין את התוצאות לפי עמודה שאתה בוחר.

    LIMIT ו-OFFSET

    אחרי שיש לנו את כל הדאטה ממויין אפשר להגביל את התשובה לחלק קטן מכלל השורות על ידי LIMIT ו-OFFSET.

    קרדיטים:

    • https://jvns.ca/blog/2019/10/03/sql-queries-don-t-start-with-select/
    • https://blog.jooq.org/2016/12/09/a-beginners-guide-to-the-true-order-of-sql-operations/

    מקוה שלמדתם משהו.

  • 1 / 1
  • התחברות

  • אין לך חשבון עדיין? הרשמה

  • התחברו או הירשמו כדי לחפש.
  • פוסט ראשון
    פוסט אחרון
0
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום