كيف تخرج إذا فشل الأمر؟
-
26-09-2019 - |
سؤال
أنا noob في وضع القذيفة. أرغب في طباعة رسالة والخروج من البرنامج النصي في حالة فشل الأمر. لقد حاولت:
my_command && (echo 'my_command failed; exit)
لكنها لم تعمل. يستمر في تنفيذ التعليمات التي تلي هذا السطر في البرنامج النصي. أنا أستخدم Ubuntu و Bash.
المحلول
محاولة:
my_command || { echo 'my_command failed' ; exit 1; }
أربعة تغييرات:
- يتغيرون
&&
ل||
- يستخدم
{ }
بدلاً من( )
- تقديم
;
بعدexit
و - مسافات بعد
{
و قبل}
نظرًا لأنك تريد طباعة الرسالة والخروج فقط عندما يفشل الأمر (يخرج بقيمة غير صفرية) ، فأنت بحاجة إلى أ ||
ليس &&
.
cmd1 && cmd2
سوف يركض cmd2
متى cmd1
تنجح (قيمة الخروج 0
). بينما
cmd1 || cmd2
سوف يركض cmd2
متى cmd1
يفشل (قيمة الخروج غير صفرية).
استخدام ( )
يجعل الأمر بداخلهم يعمل في قشرة فرعية ودعوة أ exit
من هناك يجعلك تخرج من القشرة الفرعية وليس قذيتك الأصلية ، ومن ثم يستمر التنفيذ في قشرة الأصلية.
للتغلب على هذا الاستخدام { }
التغييرات الأخيرة مطلوبة من قبل باش.
نصائح أخرى
غطت الإجابات الأخرى السؤال المباشر جيدًا ، ولكن قد تكون مهتمًا أيضًا باستخدام set -e
. مع ذلك ، أي أمر يفشل (خارج سياقات محددة مثل if
الاختبارات) سوف يتسبب في إحباط البرنامج النصي. لبعض البرامج النصية ، إنه مفيد للغاية.
إذا كنت تريد هذا السلوك لجميع الأوامر في البرنامج النصي الخاص بك ، فما عليك سوى إضافة إضافة
set -e
set -o pipefail
في بداية البرنامج النصي. يخبر هذا الزوج من الخيارات مترجم Bash بالخروج عندما يعود الأمر برمز خروج غير صفري.
هذا لا يسمح لك بطباعة رسالة خروج ، رغم ذلك.
لاحظ أيضًا ، يتم تخزين حالة خروج كل أمر في متغير Shell $؟ ، والتي يمكنك التحقق منها مباشرة بعد تشغيل الأمر. تشير الحالة غير الصفر إلى الفشل:
my_command
if [ $? -eq 0 ]
then
echo "it worked"
else
echo "it failed"
fi
لقد اخترقت المصطلح التالي:
echo "Generating from IDL..."
idlj -fclient -td java/src echo.idl
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi
echo "Compiling classes..."
javac *java
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi
echo "Done."
تسبق كل أمر مع صدى إعلامي ، واتبع كل أمر مع ذلك
if [ $? -ne 0 ];...
خط. (بالطبع ، يمكنك تحرير رسالة الخطأ هذه إذا كنت تريد.)
قدمت my_command
تم تصميمه بشكل قانوني ، بمعنى آخر يعود 0 عندما ينجح ، ثم &&
هو بالضبط عكس ما تريد. انت تريد ||
.
لاحظ أيضا ذلك (
لا يبدو لي على حق في باش ، لكن لا يمكنني المحاولة من حيث أنا. أخبرني.
my_command || {
echo 'my_command failed' ;
exit 1;
}
يمكنك أيضًا استخدام ، إذا كنت تريد الحفاظ على حالة خطأ الخروج ، ولديك ملف قابل للقراءة مع أمر واحد لكل سطر:
my_command1 || exit $?
my_command2 || exit $?
هذا ، ومع ذلك لن يطبع أي رسالة خطأ إضافية. ولكن في بعض الحالات ، سيتم طباعة الخطأ بواسطة الأمر الفاشل على أي حال.
ال trap
يتيح Shell Buildin الإشارات الصيد ، وغيرها من الشروط المفيدة ، بما في ذلك تنفيذ الأوامر الفاشلة (أي حالة عودة غير صفرية). لذلك إذا كنت لا ترغب في اختبار حالة الإرجاع بشكل صريح لكل أمر واحد يمكنك قوله trap "your shell code" ERR
وسيتم تنفيذ رمز shell في أي وقت يعيد الأمر حالة غير صفرية. علي سبيل المثال:
trap "echo script failed; exit 1" ERR
لاحظ أنه كما هو الحال مع الحالات الأخرى من اصطياد الأوامر الفاشلة ، تحتاج خطوط الأنابيب إلى معاملة خاصة ؛ ما سبق لن يصطاد false | true
.
تعمل الوظائف التالية فقط على صدى الأخطاء في حالة فشل الأمر:
silently () {
label="${1}"
command="${2}"
error=$(eval "${command}" 2>&1 >"/dev/null")
if [ ${?} -ne 0 ]; then
echo "${label}: ${error}" >&2
exit 1
fi
}