سؤال ما الذي تقوم به "set -e" ، ولماذا يعتبر خطراً؟


لقد ظهر هذا السؤال في اختبار ما قبل المقابلة وهو ما جعلني أشعر بالجنون. هل يمكن لأحد أن يجيب على هذا ويضعني في سهولة؟ لا يتضمن الاختبار إشارة إلى غلاف محدد ولكن الوصف الوظيفي هو unix sa. مرة أخرى السؤال هو ببساطة ...

ما الذي تقوم به "set -e" ، ولماذا يعتبر خطراً؟


142
2018-05-19 16:39


الأصل


هنا موضوع ذو صلة: stackoverflow.com/questions/64786/error-handling-in-bash/... - Stefan Lasiewski


الأجوبة:


set -e يؤدي إلى إنهاء shell إذا أي subcommand أو خط أنابيب بإرجاع حالة غير صفرية.

الإجابة التي كان من المحتمل أن يبحث عنها المحاور هي:

سيكون من الخطر استخدام "set -e" عند إنشاء النصوص البرمجية init.d:

من عند http://www.debian.org/doc/debian-policy/ch-opersys.html 9.3.2 -

كن حذراً من استخدام set -e في البرامج النصية init.d. يتطلب كتابة النصوص البرمجية init.d الصحيحة قبول حالات خروج خطأ مختلفة عند تشغيل daemons بالفعل أو توقفت بالفعل دون إحباط البرنامج النصي init.d ، ومكتبات دالة init.d الشائعة ليست آمنة للاتصال مع set -e سارية المفعول. بالنسبة إلى النصوص البرمجية init.d ، يكون من الأسهل دائمًا عدم استخدام set -e ، ويمكنك بدلاً من ذلك التحقق من نتيجة كل أمر على حدة.

هذا سؤال صالح من وجهة نظر الباحثين لأنه يقيس معرفة عمل المرشحين للبرامج النصية والأتمتة على مستوى الخادم


148
2017-08-09 21:01



العثور على لطيفة. شكر. - egorgry
نقطة جيدة. فإنه سيتم إيقاف عملية التمهيد على شيء قد يكون خطأ من الناحية الفنية ، ولكن لا ينبغي أن يتسبب في توقف البرنامج النصي بأكمله - Matt
على الرغم من أنني أتفق مع stackoverflow.com/questions/78497/...، أعتقد أن هذا النمط يتناسب بشكل جيد مع bash لفحوصات init القصيرة والتسجيل أو تصحيح قرد البيئة الأخرى قبل تنفيذ عبء العمل المستهدف. نستخدم هذه السياسة نفسها لنصوص برنامج REAL الخاص بنا. - joshperry


من عند bash(1):

          -e      Exit immediately if a pipeline (which may consist  of  a
                  single  simple command),  a subshell command enclosed in
                  parentheses, or one of the commands executed as part  of
                  a  command  list  enclosed  by braces (see SHELL GRAMMAR
                  above) exits with a non-zero status.  The shell does not
                  exit  if  the  command that fails is part of the command
                  list immediately following a  while  or  until  keyword,
                  part  of  the  test  following  the  if or elif reserved
                  words, part of any command executed in a && or  ││  list
                  except  the  command  following  the final && or ││, any
                  command in a pipeline but the last, or if the  command’s
                  return  value  is being inverted with !.  A trap on ERR,
                  if set, is executed before the shell exits.  This option
                  applies to the shell environment and each subshell envi-
                  ronment separately (see  COMMAND  EXECUTION  ENVIRONMENT
                  above), and may cause subshells to exit before executing
                  all the commands in the subshell.

للأسف ، لست مبدعًا بما يكفي للتفكير في سبب كونه خطيرًا ، بخلاف "لن يتم تنفيذ بقية النص" أو "ربما يحتمل أن يخفي مشاكل حقيقية".


33
2018-05-19 16:43



قناع حقيقي / مشاكل أخرى ، نعم ، أعتقد أنني يمكن أن نرى ذلك ... كنت تكافح من أجل التوصل إلى مثال على كونها خطرة ، وكذلك ... - cpbills
هناك manpage ل set! أنا دائما في نهاية المطاف في builtin(1). شكر. - Jared Beck
كيف لي أن أعرف أن الوثائق ل set هو أن يدخل في man 1 bash؟؟ وكيف يمكن لأي شخص أن يجد -e الخيار ل set الكلمة في صفحة دليل كبير جدا؟ أنت غير قادر على ذلك /-e ابحث هنا - Blauhirn
Blauhirn باستخدام help set - Blauhirn


وتجدر الإشارة إلى أن set -e يمكن تشغيله وإيقافه لعدة مقاطع من النص البرمجي. ليس من الضروري أن يكون جاهزًا لتنفيذ النص بأكمله. يمكن أن يكون ممكنا حتى مشروط. ومع ذلك ، أنا لا أستخدمه على الإطلاق منذ أن أتعامل مع الخطأ الخاص بي (أو لا).

some code
set -e     # same as set -o errexit
more code  # exit on non-zero status
set +e     # same as set +o errexit
more code  # no exit on non-zero status

من الجدير بالذكر أيضا أن هذا من صفحة باش رجل صفحة على trap الأمر الذي يصف أيضا كيف set -e وظائف في ظل ظروف معينة.

ال                 لا يتم تنفيذ اعتراض ERR إذا كان الأمر الذي فشل هو جزء من                 قائمة الأوامر فورًا بعد أو حتى كلمة رئيسية ،                 جزء من الاختبار في بيان if ، جزء من أمر تم تنفيذه                 في قائمة &&& أو، أو إذا كانت قيمة الإرجاع للأمر موجودة                 معكوس عبر! هذه هي نفس الشروط التي تطاع بها                 خيار errexit.

لذلك هناك بعض الشروط التي بموجبها الحالة غير الصفر لن تتسبب في الخروج.

أعتقد أن الخطر في عدم فهم متى set -e يبدأ اللعب وعندما لا يعتمد عليه بشكل غير صحيح تحت بعض الافتراضات غير الصحيحة.

من فضلك انظر أيضا BashFAQ / 105 لماذا لا تحدد -e (أو set-o errexit ، أو trap ERR) القيام بما كنت أتوقع؟


19
2018-05-19 22:39



في الوقت الذي ينحرف فيه عن السؤال قليلاً ، فإن هذه الإجابة هي بالضبط ما أبحث عنه: أطفئه لجزء صغير فقط من البرنامج النصي! - Stephan Bijzitter


ضع في اعتبارك أن هذا اختبار لمقابلة عمل. قد تكون مكتوبة الأسئلة من قبل الموظفين الحاليين ، وربما تكون خاطئة. هذا ليس بالضرورة سيئًا ، والجميع يخطئ ، وغالباً ما تجرى أسئلة المقابلة في زاوية مظلمة بدون مراجعة ، ولا يخرج منها إلا أثناء المقابلة.

من المحتمل تمامًا أن "لا تميز" - لا تفعل شيئًا قد نعتبره "خطيرًا". لكن مؤلف هذا السؤال قد يعتقد خطأً أن "مجموعة -e" خطيرة ، بسبب جهلها أو انحيازها. ربما قاموا بكتابة سيناريو شبيه بالعربة ، وقصفت بشكل فظيع ، وكانوا يعتقدون خطأ أن "مجموعة -e" كانت هي السبب ، في حين أنهم في الواقع أهملوا كتابة تدقيق الأخطاء الصحيح.

لقد شاركت في 40 مقابلة عمل على الأرجح خلال العامين الماضيين ، وأحياناً يطرح القائمون على المقابلة أسئلة خاطئة ، أو لديهم إجابات خاطئة.

أو ربما كان سؤالًا خداعيًا ، والذي سيكون أعرجًا ، ولكن ليس غير متوقع تمامًا.

أو ربما هذا هو تفسير جيد: http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg473314.html


13
2018-05-19 17:03



+1 أنا في نفس القارب ، والكثير من المقابلات "الفنية" التي كنت أتعامل معها كانت مضللة قليلاً على الأقل. - cpbills
رائع. حسن العثور على قائمة debian. +1 لجهل أسئلة المقابلة. أتذكر جوابا netback مرة واحدة منذ كنت متأكدا 100 ٪ كنت على حق. قالوا كلا. ذهبت إلى البيت وغوغل ، كنت على حق. - egorgry


set -e لإخبار bash ، في نص برمجي ، بالإنهاء عندما يعرض أي شيء قيمة إرجاع غير صفرية.

أستطيع أن أرى كيف سيكون ذلك مزعجًا ، وعاجيًا ، وغير متأكد من خطورة ، ما لم تكن قد فتحت أذونات على شيء ما ، وقبل أن تتمكن من تقييدها مرة أخرى ، توفي النص الخاص بك.


9
2018-05-19 16:46



ذلك مثير للاهتمام. لم أفكر في أذونات فتح في السيناريو الذي يموت قبل الأوان ولكن يمكن أن أرى أن تعتبر خطرة. الجزء الممتع من هذا الاختبار هو أنه لا يمكنك استخدام أي مواد مرجعية مثل الرجل أو جوجل ، وإذا كنت لا تستطيع الإجابة بشكل كامل لا تجيب على الإطلاق. - egorgry
هذا سخيف فقط ، وأود أن تعيد النظر في هذا صاحب العمل ... مزاح (نوع من). من الجيد أن يكون لديك قاعدة قوية من المعرفة ، ولكن نصف أعمال تكنولوجيا المعلومات هي معرفة / أين / للعثور على المعلومات ... نأمل أن يكونوا أذكياء بما يكفي لوضع ذلك في الاعتبار عند تسجيل المتقدمين. على ملاحظة جانبية ، أرى / لا / استخدم من أجل set -eفي الواقع ، إنها تتحدث عن الكسل لتجاهل الخطأ في نصوصك النصية ... لذلك ضع في اعتبارك ، مع صاحب العمل هذا أيضًا ... إذا استخدموه كثيرًا ، كيف تبدو نصوصه ، سيكون حتما للحفاظ على ... - cpbills
نقطة ممتازة @ cpbills. كما أنني لا أرى أي استخدام للمجموعة في سيناريو ، وربما كان السبب في ذلك هو ما جعلني أشعر بالضيق الشديد. أود نشر جميع الأسئلة لأن بعضها جيد بالفعل وبعضها أحمق وعشوائي مثل هذا. - egorgry
لقد رأيت ذلك في العديد من وظائف نظام كرون ... - Andrew


set -e إنهاء البرنامج النصي في حالة مصادفة رمز إنهاء غير صفري ، باستثناء حالات معينة. لتلخيص أخطار استخدامه في بضع كلمات: فهو لا يتصرف كيف يعتقد الناس أنه يفعل ذلك.

في رأيي ، ينبغي اعتباره كاختراق خطير يستمر في الوجود لأغراض التوافق فقط. ال set -e لا يتحول بيان shell من لغة تستخدم رموز الأخطاء إلى لغة تستخدم تدفق تحكم تشبه الاستثناءات ، ولكنها فقط تحاول بشكل سيئ محاكاة هذا السلوك.

غريغ Wooledge لديه الكثير ليقوله عن مخاطر set -e:

في الوصلة الثانية ، هناك أمثلة مختلفة لسلوك غير بديهي وغير متوقع set -e.

بعض الأمثلة على سلوك غير عادي من set -e (بعضها مأخوذ من رابط الويكي أعلاه):

  • مجموعة-
    س = 0
    دعونا س + + +
    echo "x is $ x"
    ما ورد أعلاه سوف يسبب البرنامج النصي قذيفة للخروج قبل الأوان ، لأن let x++ يعيد 0 ، والذي يعالج من قبل let الكلمة الأساسية كقيمة كاذبة وتحويلها إلى رمز إنهاء غير صفرية. set -e يلاحظ هذا ، وينهي البرنامج النصي بصمت.
  • مجموعة-
    [-d / opt / foo] && echo "تحذير: foo مثبت بالفعل. سيتم الكتابة فوق". > & 2
    صدى "تثبيت foo ..."
    

    الأعمال المذكورة أعلاه كما هو متوقع ، طباعة تحذير إذا /opt/foo موجود بالفعل.

    مجموعة-
    check_previous_install () {
        [-d / opt / foo] && echo "تحذير: foo مثبت بالفعل. سيتم الكتابة فوق". > & 2
    }
    
    check_previous_install
    صدى "تثبيت foo ..."
    

    ما سبق ، على الرغم من الاختلاف الوحيد هو أنه تم إعادة تشكيل خط واحد في وظيفة ، سينتهي إذا /opt/foo غير موجود. هذا لأن حقيقة أنها عملت أصلا هو استثناء خاص ل set -eسلوك. متى a && b إرجاع غير صفرية ، يتم تجاهلها من قبل set -e. ومع ذلك ، والآن بعد أن تكون إحدى الدالات ، يكون رمز إنهاء الدالة مساويًا لرمز الإنهاء الخاص بهذا الأمر ، وستؤدي الدالة التي تظهر غير صفرية إلى إنهاء البرنامج النصي بدون مطالبة.

  • مجموعة-
    IFS = $ '\ n' read -d '' -r -a config_vars <config
    

    ما ورد أعلاه سوف يقرأ المصفوفة config_vars من الملف config. كما قد ينوي المؤلف ، فإنه ينتهي مع وجود خطأ إذا config مفقود. كما قد لا تنوي المؤلف ، فإنه ينهي بصمت إذا config لا ينتهي في سطر جديد. إذا set -e لم تستخدم هنا ، ثم config_vars سيحتوي على جميع أسطر الملف سواء انتهت أم لا في سطر جديد.

    مستخدمو Sublime Text (وغيرها من برامج تحرير النصوص التي تتعامل مع الخطوط الجديدة بشكل غير صحيح) ، حذار.

  • مجموعة-
    
    should_audit_user () {
        مجموعات المجموعات المحلية = "$ (groups" $ 1 ")"
        للمجموعة في مجموعات $؛ فعل
            إذا كانت ["$ group" = audit] ؛ ثم اعاد 0 فاي
        فعله
        العودة 1
    }
    
    if should_audit_user "$ user"؛ ثم
        مسجل "بلاه"
    فاي
    

    قد يتوقع المؤلف هنا بشكل معقول أنه إذا لسبب ما للمستخدم $user غير موجود ، ثم groups يفشل الأمر ثم إنهاء البرنامج النصي بدلاً من السماح للمستخدم بإجراء بعض المهام غير المراجعة. ومع ذلك ، في هذه الحالة set -e الإنهاء لا يسري أبدًا. إذا $user لا يمكن العثور عليه لسبب ما ، بدلا من إنهاء البرنامج النصي ، should_audit_user ستقوم الدالة بإرجاع البيانات غير صحيحة كما لو set -e لم يكن ساري المفعول.

    هذا ينطبق على أي وظيفة استدعت من جزء الشرط من if بيان ، بغض النظر عن مدى تداخل عميق ، بغض النظر عن المكان الذي يتم تعريفه ، لا يهم حتى إذا قمت بتشغيل set -e داخله مرة أخرى. عن طريق if في أي نقطة يعطل تماما تأثير set -e حتى يتم تنفيذ كتلة الشرط بشكل كامل. إذا لم يكن المؤلف على دراية بهذا الشرط ، أو لا يعرف مجموع مكالماته بالكامل في جميع المواقف المحتملة التي يمكن فيها استدعاء وظيفة ، فعندئذ سيكتبون رمز عربات التي تجرها الدواب والإحساس الزائف بالأمان المقدم من قبل set -e سيكون جزئيا على الأقل لإلقاء اللوم.

    حتى لو كان المؤلف على دراية كاملة بهذا الشرط ، فإن الحل هو كتابة الكود بنفس الطريقة التي يكتب بها المرء دون set -e، مما يجعل التحول بشكل فعال أقل من عديم الفائدة ؛ ليس فقط على المؤلف أن يكتب رمز التعامل مع الأخطاء اليدوية كما لو كان set -e لم تكن سارية المفعول ، ولكن وجود set -e ربما خدعوهم في الاعتقاد أنهم ليسوا مضطرين لذلك.

بعض عيوب أخرى من set -e:

  • يشجع قانون قذرة. يتم نسيان معالجات الأخطاء تمامًا ، على أمل أن كل ما فشل سيبلغ عن الخطأ بطريقة معقولة. ومع ذلك ، مع أمثلة مثل let x++ أعلاه ، هذا ليس هو الحال. إذا كان البرنامج النصي يموت بشكل غير متوقع ، فإنه عادةً ما يكون بصمت ، مما يعوق تصحيح الأخطاء. إذا كان النص لا يموت وتوقعت منه (راجع النقطة السابقة) ، عندها يكون هناك خطأ أكثر دقة وخبثاً على يديك.
  • إنه يقود الناس إلى شعور زائف بالأمن. انظر مرة أخرى ifنقطة نقطية.
  • الأماكن التي تنتهي فيها shell غير متسقة بين الأصداف أو إصدارات shell. من الممكن كتابة برنامج نصي بطريق الخطأ الذي يتصرف بشكل مختلف على نسخة قديمة من bash بسبب سلوك set -e بعد أن تم تعديلها بين تلك الإصدارات.

set -e هي قضية مثيرة للجدل ، وبعض الناس على بينة من القضايا المحيطة بها توصي ضدها ، في حين أن البعض الآخر مجرد التوصية بالحرص في حين أنها نشطة لمعرفة المزالق. هناك العديد من newbies قذيفة برنامج نصي الذي يوصي set -eعلى جميع البرامج النصية كجميع لظروف الخطأ ، ولكن في الحياة الحقيقية لا يعمل بهذه الطريقة.

set -e ليس بديلا عن التعليم.


6
2018-04-27 23:06





أود أن أقول أنه أمر خطير لأنه لا يمكنك التحكم في تدفق النص الخاص بك بعد الآن. يمكن إنهاء البرنامج النصي طالما أن أيًا من الأوامر التي يستخدمها البرنامج النصي تقوم بإرجاع قيمة غير صفرية. لذلك كل ما عليك القيام به هو القيام بشيء يغير سلوك أو إخراج أي من المكونات ، ويمكنك إنهاء البرنامج النصي الرئيسي. قد يكون الأمر أكثر من مشكلة في النمط ، لكنه بالتأكيد له عواقب. ماذا لو كان من المفترض أن يقوم هذا السيناريو الرئيسي بوضع بعض العلم ، ولم يكن ذلك بسبب إنهائه في وقت مبكر؟ كنت في نهاية المطاف يخطئ بقية النظام إذا افترض أن العلم يجب أن يكون هناك ، أو العمل مع قيمة افتراضية أو غير متوقعة قديمة.


2
2018-05-19 18:07



أتفق تماما مع هذه الإجابة. ليست كذلك متأصل خطيرة ، لكنها فرصة للخروج المبكر غير المتوقع. - pboin
ما ذكرني به هذا هو بروفيل C ++ الخاص بي الذي كان دائماً يسحب النقاط من واجباتي لعدم وجود نقطة دخول واحدة / نقطة خروج واحدة في البرنامج. اعتقدت أنه كان مجرد شيء "مبدأ" ، ولكن هذه المجموعة من الأعمال التجارية بالتأكيد تشرح كيف ولماذا يمكن أن تخرج الأمور تماما عن السيطرة. في النهاية ، تتعلق البرامج بالسيطرة والحتمية ، ومع الإنهاء المبكر ، فإنك تتخلى عن كليهما. - Marcin


كمثال أكثر واقعية على @ ماركن الجواب الذي عضني شخصيا ، تخيل أنه كان هناك rm foo/bar.txt خط في مكان ما في البرنامج النصي الخاص بك. عادة لا صفقة كبيرة إذا foo/bar.txt لا يوجد في الواقع ومع set -e تقديم الآن سينتهي البرنامج النصي الخاص بك في وقت مبكر هناك! وجه الفتاة.


0
2018-06-22 19:00