বাশ স্ক্রিপ্টে, কোনও নির্দিষ্ট শর্ত দেখা দিলে আমি কীভাবে পুরো স্ক্রিপ্ট থেকে প্রস্থান করব?


717

আমি কিছু কোড পরীক্ষা করার জন্য বাশে একটি স্ক্রিপ্ট লিখছি। যাইহোক, কোডগুলি সংকলন প্রথম স্থানে ব্যর্থ হলে পরীক্ষাগুলি চালানো নির্বোধ বলে মনে হয়, সেক্ষেত্রে আমি কেবল পরীক্ষাগুলি বাতিল করব।

কিছুটা লুপের ভিতরে পুরো স্ক্রিপ্টটি মোড়ানো না করে এবং ব্রেক ব্যবহার না করে আমি কি এমন উপায় করতে পারি? ডান ডুন ডুন গোটোর মতো কিছু ?

উত্তর:


808

এই বিবৃতি চেষ্টা করুন:

exit 1

1উপযুক্ত ত্রুটি কোডগুলি দিয়ে প্রতিস্থাপন করুন । বিশেষ অর্থ সহ প্রস্থান কোডগুলিও দেখুন ।


4
@ সিএমসিডিগ্রাগনকাই, সাধারণত যে কোনও শূন্য কোড কার্যকর হবে। আপনার যদি বিশেষ কোনও প্রয়োজন না হয় তবে আপনি কেবল 1ধারাবাহিকভাবে ব্যবহার করতে পারেন । যদি স্ক্রিপ্টটি অন্য স্ক্রিপ্ট দ্বারা চালিত হয় তবে আপনি নির্দিষ্ট অর্থ সহ নিজের স্ট্যাটাস কোডের সেটটি সংজ্ঞায়িত করতে চাইতে পারেন। উদাহরণস্বরূপ, 1== পরীক্ষা ব্যর্থ হয়েছে, 2== সংকলন ব্যর্থ হয়েছে। লিপিটি যদি অন্য কোনও কিছুর অংশ হয় তবে আপনাকে সেখানে ব্যবহৃত অনুশীলনগুলির সাথে মেলে কোডগুলি সামঞ্জস্য করতে হতে পারে। উদাহরণস্বরূপ, যখন অটোমেক দ্বারা চালিত টেস্ট স্যুটের অংশ হয়, কোডটি 77কোনও পরীক্ষার বাদ পড়ে চিহ্নিত করতে ব্যবহৃত হয়।
মিশা গার্নি

21
না এটি উইন্ডোটিও বন্ধ করে দেয়, কেবল স্ক্রিপ্ট থেকে প্রস্থান করবেন না
টনি লেইগ

7
@ টনিলিগ ব্যাশের "উইন্ডো" ধারণাটি নেই, আপনার বিশেষ সেট আপ - যেমন টার্মিনাল এমুলেটর - যা করে তা নিয়ে আপনি সম্ভবত বিভ্রান্ত হয়ে পড়েছেন।
মাইকেল ফুকারাকিস

3
@ টনিলিঘ যদি এটি "উইন্ডো" বন্ধ করে থাকে তবে আপনি exit #কোনও স্ক্রিপ্টের পরিবর্তে কমান্ডটি কোনও ফাংশনের ভিতরে রেখে দিচ্ছেন । (যার ক্ষেত্রে return #পরিবর্তে ব্যবহার করুন))
জেমি

1
@ সেভিনিয়ার্থস 0 এর অর্থ এটি সফল হয়েছিল, সুতরাং exit 0স্ক্রিপ্টটি প্রস্থান করুন এবং 0 টি ফিরে আসুন (অন্যান্য স্ক্রিপ্টগুলি বলছেন যা এই স্ক্রিপ্টটির ফলাফল এটি সফল হতে পারে)
ভিক্টর গ্যালিসন

689

সেট-ই ব্যবহার করুন

#!/bin/bash

set -e

/bin/command-that-fails
/bin/command-that-fails2

স্ক্রিপ্টটি প্রথম লাইনের পরে ব্যর্থ হয় যা ব্যর্থ হয় (ননজারো প্রস্থান কোড ফেরত দেয়)। এই ক্ষেত্রে, কমান্ড-যে-ব্যর্থ 2 চালিত হবে না।

আপনি যদি প্রতিটি একক কমান্ডের রিটার্নের স্থিতি পরীক্ষা করে দেখেন তবে আপনার স্ক্রিপ্টটি দেখতে এমন হবে:

#!/bin/bash

# I'm assuming you're using make

cd /project-dir
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
    exit 1
fi

সঙ্গে সেট -e এটি দেখতে কেমন হবে:

#!/bin/bash

set -e

cd /project-dir
make

cd /project-dir2
make

কোনও কমান্ড ব্যর্থ হয় যা পুরো স্ক্রিপ্টটি ব্যর্থ করে দেয় এবং আপনি exit দিয়ে পরীক্ষা করতে পারেন এমন একটি প্রস্থান স্থিতি ফিরিয়ে আনবে ? । যদি আপনার স্ক্রিপ্টটি খুব দীর্ঘ হয় বা আপনি প্রচুর স্টাফ তৈরি করে থাকেন তবে আপনি যদি সর্বত্র রিটার্নের স্ট্যাটাসের চেক যোগ করেন তবে এটি বেশ কুশ্রী হয়ে উঠবে।


10
সঙ্গে set -eআপনি এখনও করতে করতে কিছু স্ক্রিপ্ট বাঁধন ছাড়া ত্রুটিযুক্ত কমান্ড প্রস্থান: command 2>&1 || echo $?
অ্যাডোব

6
set -eযদি কোনও পাইপলাইন বা কমান্ড কাঠামো অ-শূন্য মান দেয় তবে স্ক্রিপ্টটি বাতিল করতে হবে। উদাহরণস্বরূপ foo || barকেবলমাত্র উভয়ই ব্যর্থ হবে fooএবং barঅ-শূন্য মানের ফিরে আসবে। সাধারণত আপনি যদি set -eশুরুতে যুক্ত করেন তবে একটি ভাল লিখিত বাশ স্ক্রিপ্ট কাজ করবে এবং সংযোজনটি একটি স্বয়ংক্রিয় বিচক্ষণতা হিসাবে কাজ করবে: কিছু ভুল হলে স্ক্রিপ্টটি বাতিল করে দিন।
মিক্কো রেন্টালাইনেন

6
আপনি যদি একসাথে কমান্ডগুলি পাইপ করছেন তবে set -o pipefailবিকল্পটি সেট করে যদি সেগুলির মধ্যে কোনওটি ব্যর্থ হয় তবে আপনি ব্যর্থও হতে পারেন ।
জ্যাক বিসিঞ্জার

18
আসলে আইডিয়োম্যাটিক কোডটি set -eকেবল ন্যায়সঙ্গত হবে make || exit $?
ট্রিপলি

4
এছাড়াও আপনি set -u। দেখে নিন ব্যবহার করার বেসরকারী ব্যাশ কঠোর মোডে : set -euo pipefail
পাবলো এ

235

একজন সিসঅপস লোক একবার আমাকে তিন-আঙুলযুক্ত নখ কৌশলটি শিখিয়েছিল:

yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }

এই ফাংশনগুলি হ'ল * এনআইএক্স ওএস এবং শেল ফ্লেভার-রোস্ট। এগুলি আপনার স্ক্রিপ্টের শুরুতে (বাশ বা অন্যথায়) try()আপনার বিবৃতি এবং কোডটি রাখুন।

ব্যাখ্যা

( উড়ন্ত ভেড়ার মন্তব্যের ভিত্তিতে )।

  • yell: স্ক্রিপ্টের নাম এবং সমস্ত আর্গুমেন্ট এতে মুদ্রণ করুন stderr:
    • $0 স্ক্রিপ্টের পথ;
    • $* সমস্ত যুক্তি হয়।
    • >&2মানে >স্ট্যান্ডআউটকে & পাইপে পুনর্নির্দেশ করুন2নল1 হবে stdoutনিজেই।
  • dieযেমনটি করে yellতবে অ -0 প্রস্থান স্থিতি দিয়ে বের হয় যার অর্থ "ব্যর্থ"।
  • try||(বুলিয়ান OR) ব্যবহার করে , যা কেবলমাত্র বাম দিকটি ব্যর্থ হলে ডান দিকটি মূল্যায়ন করে।
    • $@সমস্ত যুক্তি আবার, কিন্তু ভিন্ন

3
আমি ইউনিক্স স্ক্রিপ্টিংয়ে মোটামুটি নতুন। উপরের ফাংশনগুলি কীভাবে কার্যকর করা যায় তা দয়া করে ব্যাখ্যা করতে পারেন? আমি এমন কিছু নতুন সিনট্যাক্স দেখছি যার সাথে আমি পরিচিত নই। ধন্যবাদ।
kaizenCoder

15
চিৎকার : $0স্ক্রিপ্টের পথ। $*সমস্ত যুক্তি হয়। >&2অর্থ " >স্টাইডাউটটি &পাইপে পুনর্নির্দেশ করুন 2"। পাইপ 1 নিজেই stdout হবে। সুতরাং চিৎকারের স্ক্রিপ্টের নাম সহ স্টোরারকে প্রিন্ট করে সমস্ত আর্গুমেন্ট। ডাই চিত্কার হিসাবে একই , কিন্তু একটি অ -0 প্রস্থান স্থিতি সঙ্গে প্রস্থান করে, যার অর্থ "ব্যর্থ"। বুলিয়ান ব্যবহার করার চেষ্টা করুন বা ||, যা বাম দিকটি ব্যর্থ না হলে কেবল ডান দিকটি মূল্যায়ন করে। $@সমস্ত যুক্তি আবার, কিন্তু ভিন্ন । আশা করি যা সমস্ত কিছু ব্যাখ্যা করে
উড়ন্ত ভেড়া

1
আমি এটিকে die() { yell "$1"; exit $2; }এমনভাবে সংশোধন করেছি যাতে আপনি কোনও বার্তা এবং পাসওয়ার্ড দিয়ে পাস করতে পারেন die "divide by zero" 115
লাকাটা

3
আমি কীভাবে ব্যবহার করব yellএবং তা দেখতে পাচ্ছি die। তবে tryতেমন কিছু নয়। আপনি এটি ব্যবহারের উদাহরণ প্রদান করতে পারেন?
kshenoy

2
হুম, তবে আপনি কীভাবে এগুলি কোনও স্ক্রিপ্টে ব্যবহার করবেন? আপনার বক্তব্য এবং কোড চালু করে "চেষ্টা করুন" বলতে কী বোঝাতে চাইছি তা আমি বুঝতে পারি না।
দ্যা জাভাগুই-ইভান মিলোসভ্লজেভিć

33

আপনি যদি স্ক্রিপ্টটির সাথে অনুরোধ করেন তবে sourceআপনি return <x>যেখানে <x>স্ক্রিপ্টের প্রস্থান স্থিতি হবে তা ব্যবহার করতে পারেন (ত্রুটি বা মিথ্যাটির জন্য একটি শূন্য-মান ব্যবহার করুন)। তবে আপনি যদি একটি এক্সিকিউটেবল স্ক্রিপ্ট (অর্থাৎ সরাসরি এর ফাইল নাম সহ) প্রার্থনা করেন তবে রিটার্নের বিবৃতিটি অভিযোগের ফলে ঘটবে (ত্রুটির বার্তা "রিটার্ন: কোনও ফাংশন বা উত্সাহিত স্ক্রিপ্ট থেকে কেবল 'ফেরত' দিতে পারে)।

exit <x>পরিবর্তে যদি ব্যবহার করা হয়, যখন স্ক্রিপ্টটি চালু করা হয় source, এর ফলে স্ক্রিপ্টটি শুরু হওয়া শেলটি থেকে বেরিয়ে আসে, তবে এক্সিকিউটেবল স্ক্রিপ্টটি প্রত্যাশার মতো শেষ হবে।

একই স্ক্রিপ্টে উভয় ক্ষেত্রে পরিচালনা করতে, আপনি ব্যবহার করতে পারেন

return <x> 2> /dev/null || exit <x>

এটি যে কোনও প্রার্থনার উপযুক্ত হতে পারে তা পরিচালনা করবে। এটি ধরে নেওয়া হচ্ছে আপনি এই বিবৃতিটি স্ক্রিপ্টের শীর্ষ স্তরে ব্যবহার করবেন। আমি কোনও ফাংশন থেকে সরাসরি স্ক্রিপ্টটি প্রস্থান করার বিরুদ্ধে পরামর্শ দেব।

দ্রষ্টব্য: <x>কেবল একটি সংখ্যা বলে মনে করা হচ্ছে।


কোনও ফাংশনের অভ্যন্তরে রিটার্ন / প্রস্থান সহ একটি স্ক্রিপ্টে আমার পক্ষে কাজ করে না, অর্থাত শেলটি উপস্থিত না করে ফাংশনের অভ্যন্তরে প্রস্থান করা সম্ভব, তবে ফাংশনের রিটার্ন কোডের সঠিক চেক জন্য ফাংশন কলারের যত্ন না করেই ?
জানু

@jan কলকারী রিটার্ন মান সহ যা করে (বা না করে) তা কীভাবে আপনি ফাংশন থেকে ফিরে আসবেন তা সম্পূর্ণ অর্থেগোনাল (অর্থাৎ স্বতন্ত্র) এটি (... ডাব্লু / ও শেল থেকে বেরিয়ে আসুক না কেন, প্রার্থনা যাই হোক না কেন)। এটি মূলত কলার কোডের উপর নির্ভর করে, যা এই প্রশ্নোত্তরের অংশ নয়। এমনকি আপনি
কলকারীর প্রয়োজন অনুসারে ফাংশনের রিটার্ন মানটিও উপস্থাপন

11

আমি প্রায়শই ত্রুটিগুলি পরিচালনা করতে রান () নামে একটি ফাংশন অন্তর্ভুক্ত করি। আমি যে প্রতিটি কল করতে চাই তা এই ফাংশনটিতে পাঠানো হয় যাতে কোনও ব্যর্থতা আঘাতের পরে পুরো স্ক্রিপ্টটি প্রস্থান করে। সেট-সমাধান সমাধানের মাধ্যমে এর সুবিধাটি হ'ল কোনও লাইন ব্যর্থ হলে স্ক্রিপ্টটি নিঃশব্দে প্রস্থান করে না এবং সমস্যাটি কী তা বলতে পারে। নিম্নলিখিত উদাহরণে, 3 য় লাইনটি কার্যকর করা হয়নি কারণ স্ক্রিপ্টটি কল এ প্রকারে মিথ্যা হয়ে যায়।

function run() {
  cmd_output=$(eval $1)
  return_value=$?
  if [ $return_value != 0 ]; then
    echo "Command $1 failed"
    exit -1
  else
    echo "output: $cmd_output"
    echo "Command succeeded."
  fi
  return $return_value
}
run "date"
run "false"
run "date"

1
মানুষ, কোনও কারণে, আমি এই উত্তরটি সত্যিই পছন্দ করি। আমি বুঝতে পারি যে এটি কিছুটা জটিল, তবে এটি বেশ কার্যকর বলে মনে হচ্ছে। এবং প্রদত্ত যে আমি কোনও বাশ বিশেষজ্ঞ নই, এটি আমাকে বিশ্বাস করতে পরিচালিত করে যে আমার যুক্তিটি ত্রুটিযুক্ত, এবং এই পদ্ধতিটিতে কিছু ভুল আছে, অন্যথায়, আমি অন্যরা মনে করি যে এটি আরও প্রশংসা করেছে given তো, এই ফাংশনটিতে সমস্যা কী? এখানে কি আমার সন্ধান করা উচিত?

আমি eval ব্যবহার করার জন্য আমার কারণ মনে করতে পারি না, ফাংশনটি cmd_output = $ ($ 1) দিয়ে দুর্দান্ত কাজ করে
জোসেফ শেডি

আমি এটিকে একটি জটিল মোতায়েন প্রক্রিয়ার অংশ হিসাবে কেবল প্রয়োগ করেছি এবং এটি দুর্দান্ত কাজ করেছে worked আপনাকে ধন্যবাদ এবং এখানে একটি মন্তব্য এবং একটি উত্সাহ।
ফিজিগ্রুপ

সত্যিই আশ্চর্যজনক কাজ! এটি সবচেয়ে সহজ এবং পরিষ্কার সমাধান যা ভালভাবে কাজ করে। আমার জন্য আমি এটি একটি ফর লুপে একটি কমান্ডের আগে যুক্ত করেছি যেহেতু ফর লুপগুলি গ্রহণ করবে না set -e option। তারপর কমান্ড, যেহেতু এটি আর্গুমেন্ট সহ, আমি একক উদ্ধৃতি ব্যবহার করা ব্যাশ সমস্যা তাই মত এড়াতে: runTry 'mysqldump $DB_PASS --user="$DB_USER" --host="$BV_DB_HOST" --triggers --routines --events --single-transaction --verbose $DB_SCHEMA $tables -r $BACKUP_DIR/$tables$BACKUP_FILE_NAME'। দ্রষ্টব্য আমি ফাংশনের নামটি রানট্রিতে পরিবর্তন করেছি।
টনি-ক্যাফে

1
evalআপনি যদি স্বেচ্ছাসেবক ইনপুট গ্রহণ করেন তবে এটি সম্ভবত বিপজ্জনক, তবে অন্যথায় এটি দেখতে দুর্দান্ত দেখাচ্ছে।
ড্রাগন 788

5

ifনির্মাণের পরিবর্তে , আপনি শর্ট সার্কিট মূল্যায়নটি উপকার করতে পারেন :

#!/usr/bin/env bash

echo $[1+1]
echo $[2/0]              # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]

বিকল্প জোড় অপারেটরের অগ্রাধিকারের কারণে প্রয়োজনীয় বন্ধনীগুলির জুড়িটি নোট করুন। $?সর্বাধিক পরিচিত কমান্ডের কোডটি প্রস্থান করার জন্য একটি বিশেষ পরিবর্তনশীল সেট।


1
যদি আমি command -that --fails || exit $?এটি বন্ধনী ছাড়াই কাজ করি , তবে এটি echo $[4/0]আমাদের কী প্রয়োজন তা কারণ?
এ্যানেন্ট্রপিক

2
অ্যান্ট্রোপিক বিভক্ত-বাই-শূন্য প্রথম বন্ধনী (অর্থাত, একটি সহজ ছাড়া কোড 1. সঙ্গে শেল থেকে একটি তাৎক্ষণিক প্রস্থান কারণ হবে echo $[4/0] || exit $?) ব্যাশ চালানো না হবে echo, একা শুনা যাক ||
বোবোগো

1

আমার একই প্রশ্ন আছে তবে এটি জিজ্ঞাসা করতে পারছি না কারণ এটি নকল হবে।

গৃহীত উত্তর, প্রস্থান ব্যবহার করে, স্ক্রিপ্টটি আরও জটিল হলে কাজ করে না। আপনি যদি শর্তটি পরীক্ষা করতে কোনও ব্যাকগ্রাউন্ড প্রক্রিয়া ব্যবহার করেন তবে প্রস্থানটি কেবলমাত্র সেই প্রক্রিয়া থেকে প্রস্থান করে, কারণ এটি একটি সাব-শেলের মধ্যে চলে। স্ক্রিপ্টটি মারতে, আপনাকে এটিকে স্পষ্টভাবে মেরে ফেলতে হবে (কমপক্ষে এটিই আমি জানি way

এটি কীভাবে করা যায় সে সম্পর্কে এখানে একটি ছোট স্ক্রিপ্ট রয়েছে:

#!/bin/bash

boom() {
    while true; do sleep 1.2; echo boom; done
}

f() {
    echo Hello
    N=0
    while
        ((N++ <10))
    do
        sleep 1
        echo $N
        #        ((N > 5)) && exit 4 # does not work
        ((N > 5)) && { kill -9 $$; exit 5; } # works 
    done
}

boom &
f &

while true; do sleep 0.5; echo beep; done

এটি একটি উত্তম উত্তর তবে এখনও অসম্পূর্ণ একটি আমি সত্যিই জানি না কীভাবে বুম অংশটি থেকে মুক্তি পাবেন ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.