תשובה 1:

למידת תכנות: מה ההבדל בין "#! / usr / bin / env bash "ו-" #! / usr / bin / bash ”?

הפעולה שתיאר אונדרוי ווגנר בתשובתו (שמערכת ההפעלה שלו יכולה למצוא את תוכנית הבשורה מבלי לדעת היכן היא מאוחסנת) עובדת במקרה בגלל תופעת לוואי של איך מערכת ה- exec (2) מתקשרת ותוכנית env (1) מיושמים אך תשובתו אינה נכונה לחלוטין בתיאור מה ההבדל.

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

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

לפני שאמשיך, אני צריך להזכיר לך שמאז תחילת התפתחותה בסוף שנות ה -60 / תחילת שנות ה -70, משפחת מערכות ההפעלה יוניקס מכילה כלי תיעוד שימושי ביותר הנקרא דפי האיש; אליו ניגשת פקודה האיש (1). [1] אני ממליץ מאוד להכיר את הכלי הנפלא הזה, אבל האמרה הישנה "גוגל זה חבר שלך" תקפה תמיד.

ראשית, עליכם להבין כיצד מופעלים תוכניות (כלומר עורכים exec (2)) ואז נדון ב- #! מושג (לעיתים קרובות, כפי שארצה בהמשך, נקרא הרעיון 'שיבנג'); ואז סוף סוף מה התוכנית env (1) עושה.

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

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

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

הדבר נכון גם לגבי קובץ התוכנית. אם אנחנו פשוט מקלידים 'פקודה' (במקרה שלך, 'bash') אבל זה יכול להיות 'פיתון' או 'awk' או 'perl' או אחת מתוכנות הפקודה הרבות ש- Unix מספקת.

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

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

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

עם יוניקס, הבתים הראשונים המאוחסנים בתוך הקובץ מזהים את תוכן הקובץ. זה שונה ממערכת הפעלה אחרת של היום, שבאה בעקבות מוסכמה כי תוכן הקובץ נקבע לפי שם הקובץ. לדוגמה, מערכות ההפעלה הישנות של DEC השתמשו בכנס המאוחר (כלומר VMS, TOPs והכי חשוב RT11, שמיקרוסופט תמשיך לחקות ממורשת RT11 → CP / M → DOS).

מכיוון ש- Unix קידדה את "סוג הקובץ" בתוכן הקובץ [3], פירוש הדבר היה כי יישום שיחת המערכת exec (2) בתוך מערכת ההפעלה עשוי להגיע לשיא בכמה בתים הראשונים של הקובץ כדי לקבוע מה לעשות . במקור, מערכת Unix OS נראתה אם מדובר בקובץ 'a.out' שהיה פורמט הקובץ הראשון של UNIX עבור קבצי הפעלה בינאריים של PDP-11. אך החל מסוף שנות השבעים, צוות UC Berkeley יישם / הוסיף תכונה / כנס לשיחת ה- Exec. אם שני הבתים הראשונים היו התווים, # !, הביטים הבאים עד שהקו הראשון יפורסם על ידי מערכת ההפעלה UNIX כשם נתיב חדש של התוכנית לביצוע (2) במקום [4] והקובץ הנוכחי שזה עתה היה שנפתח על ידי UNIX יועבר לתוכנית השנייה כקלט הרגיל שלה [למידע נוסף על קלט / פלט ראו גם: קלט / פלט קובץ C - ויקיפדיה].

הרחבה חדשה זו לקריאת המערכת של UNIX exec (2) אפשרה ליצור סקריפטים להפעלה. זה נוצל גם כאשר פגזים חלופיים הופיעו כמו ה- cc UCB (1) ומאוחר יותר השתמשו בסיבתו של גנו (1) והשיבנג לתמיכה ב"שפות קטנות "כמו awk (1), perl (1), and python (1) ) כשהופיעו.

אוקיי, אז מה זה קשור ל- env ​​(1) ותופעת לוואי? כפי שתיארתי בעבר exec (2) תומך במחרוזת בשם PATH המשמשת להחלטה באילו שמות נתיבים יש לתלות לפקודה לחפש קובץ הפעלה. במקור, הגדרת מחרוזת זו לא הייתה קלה לביצוע, אך אנשים רבים רצו גמישות מסוימת לעשות זאת. באופן דומה, מערכת ההפעלה רצתה דרך כלשהי להעביר מידע להפעלת תכנות שהייתה ניתנת להגדרה של המשתמש אך לא הייתה חייבת להקליד מחדש בכל פעם שתתחיל תוכנית. אז החל מהמהדורה השביעית של יוניקס הרעיון של התוכנית "סביבה" נוצר ונוצרה סכמה להעברת מחרוזות ASCII לתוכנית שנקראו משתני סביבה שהיו ניתנים להגדרה על ידי המשתמש; עם PATH הוא אחד החשובים ביותר שכן הוא אפשר לעבור מחרוזות של נתיבי שם הקבצים כדי לנסות לבצע את שיחת ה- exec (2) (לפני כן, PATH הוגדר על ידי מערכת ההפעלה והיה קשה יותר לשנות).

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

env EVAR1 = evar1_value .. EVARN = evarn_value תוכנית p1 ... pn

כאשר תוכנית env פועלת היא מוציאה את הסביבה המורשת ממערכת ההפעלה ואז מוסיפה או משנה את המשתנים המופיעים בפקודה ואז היא קוראת לתוכנית exec (2) איתה באמצעות הסביבה החדשה ששונתה.

אז חשבו על מה שקורה; ככל שהפקודה הופכת:

תוכנית env 

או במקרה שלך: env bash

הפקודה env אינה משנה את הסביבה, אלא רק מכריחה את קריאת התוכנית באמצעות exec (2) באמצעות כללי הרחבת שם הנתיב שלה; שכפי שציין אונדרוי פירושו שאם יש לך נתיב עשיר עם המון נתיבים אופציונליים לנסות, אתה יכול למקם bash במקום אחר מאשר / usr / bin [וזה המקום בו פגזים כמו bash התגוררו במקור כשנוצר על ידי פרויקט Gnu] והבינארי ההפעלה bash יימצא על ידי מערכת ההפעלה עבור התוכנית המתקשרת.

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

[1] אחד התיאורים הטובים ביותר למי זה עובד ואיך להשתמש בו מגיע מאוניברסיטת אינדיאנה: שימוש בפקודה האיש של יוניקס כדי לקרוא דפים ידניים. FWIW: לינוקס היא יישום מודרני של יוניקס כפי שתיארתי במקומות אחרים, אך תכונה זו זמינה אפילו כאשר תכונה תת-מערכתית אופציונלית של Windows לינוקס של Windows 10 מופעלת על ידי הקלדה ל- PowerShell כמנהל: Enable-WindowsOptionalFeature -Online -FeatureName Microsoft חלונות-תת-מערכת-לינוקס

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

[3] לפרטים נוספים על דברים כמו הרעיון שמאחורי סוגי קבצים וקסמים, בדוק את הפקודות: "man 5 magic" ו- "man 1 file".

[4] התווים האלה נבחרו מכיוון שבמעטפת יוניקס אם התו הראשון הוא "סימן מספר" (# - או "סימן חשיש" או "סימן לירה"), כל התווים עד שהקו הראשון מתעלמים, נחשבים "הערה", ושלא פעלה על ידי הקליפה.

נערך בתאריך 5/2/2019 כדי לתקן כמה שגיאות הקלדה ולהבהרת שפה. דיסלקסיה- R-Me


תשובה 2:

ההבדל הוא קטן, אך משמעותי.

#! / usr / bin / bash

זה אומר למערכת, "הפעל את ההפעלה של bash שנמצא / usr / bin."

#! / usr / bin / env bash

זה אומר למערכת, "גלה מהסביבה שלך איפה מותקן ההפעלה שלך bash והפעל אותו משם."

במחשב האישי שלי, bash מותקן ב / bin / bash. על ידי שומרי ההפרעה נחשב חיוני מספיק למערכת כדי להיות שם. אם הייתי מנסה להריץ סקריפט עם / usr / bin / bash shebang, זה ייכשל. מצד שני, usr / bin / env פשוט מפעיל את הבסיס שהמערכת שלי יודעת עליו.