ফা

ফাংশন মধ্যে Bash

{one: "১টি অনুশীলনী", other: "%{count}টি অনুশীলনী"}

ফাংশন সম্পর্কে

অনেক Bash স্ক্রিপ্ট কঠোরভাবে ইমপারেটিভ স্টাইলে লেখা হয়: একটি কমান্ড চালান, তারপর আরেকটি কমান্ড চালান, এভাবে চলতে থাকে। কখনও কখনও আপনার এমন একগুচ্ছ কমান্ড একসাথে দলবদ্ধ করার দরকার পড়ে যারা ধারণাগতভাবে একটি মাত্র উদ্দেশ্য পালন করে। এখানেই ফাংশন-এর প্রয়োজন পড়ে।

একটি ফাংশন ডিফাইন করা

আপনি এভাবে একটি ফাংশন ডিফাইন করেন:

my_function () {
    COMMANDS
}

খালি বন্ধনী জোড়াটি শুধু বোঝায় যে আপনি একটি ফাংশন ডিফাইন করছেন। এর ভিতরে কিছুই বসে না।

ফাংশনের প্যারামিটার

ফাংশন, একবার ডিফাইন করা হলে, অন্য যেকোনো কমান্ডের মতোই কাজ করে (বিল্টইন হোক বা না হোক)। যেকোনো কমান্ডের মতোই, আপনি আপনার ফাংশনে আর্গুমেন্ট দিতে পারেন। ফাংশনের ভিতরে, আপনি পজিশনাল প্যারামিটার ব্যবহার করে আর্গুমেন্টগুলো অ্যাক্সেস করেন: $1, $2 ইত্যাদি। (মনে করুন, আমরা ভ্যারিয়েবল কনসেপ্টে পজিশনাল প্যারামিটার সম্পর্কে শিখেছিলাম।)

Advanced

$0 বিশেষ প্যারামিটারটি একটি ফাংশনের ভিতরে পরিবর্তিত হয় না; এটি তখনও চলমান স্ক্রিপ্টের নামই থাকে। বর্তমানে চলমান ফাংশনটি $FUNCNAME ভ্যারিয়েবলের মাধ্যমে তার নিজের নাম অ্যাক্সেস করতে পারে।

ম্যানুয়ালে 3.4.2 বিশেষ প্যারামিটার দেখুন।

ভ্যারিয়েবল

আপনি একটি ফাংশনের ভিতরে ভ্যারিয়েবল ডিফাইন করতে পারেন। আপনি যদি local কমান্ড দিয়ে ভ্যারিয়েবলগুলো ডিক্লেয়ার করেন, তাহলে ভ্যারিয়েবলের স্কোপ বর্তমান ফাংশনে (এবং এটি দ্বারা কল করা যেকোনো ফাংশনে) সীমাবদ্ধ থাকে। অন্যথায়, ভ্যারিয়েবলটি গ্লোবাল স্কোপে রাখা হয়।

লোকাল ভ্যারিয়েবলের নাম একটি গ্লোবাল ভ্যারিয়েবলের মতো একই হতে পারে। সেক্ষেত্রে লোকাল ভ্যারিয়েবলটি গ্লোবাল ভ্যারিয়েবলকে "ছায়া" দেয়। উদাহরণস্বরূপ, একটি ফাংশনে ডিক্লেয়ার করা একটি লোকাল ভ্যারিয়েবল একই নামের একটি গ্লোবাল ভ্যারিয়েবলকে লুকিয়ে রাখে: রেফারেন্স ও অ্যাসাইনমেন্ট লোকাল ভ্যারিয়েবলকেই বোঝায়, ফলে গ্লোবাল ভ্যারিয়েবলটি অপরিবর্তিত থাকে। ফাংশনটি রিটার্ন করলে, গ্লোবাল ভ্যারিয়েবলটি আবার দৃশ্যমান হয়।

x=5

myfunc () {
    local x=100
    echo "in my function, $x == 100"
}

echo "in the global scope, $x == 5"

myfunc

echo "back in the global scope, $x == 5"

এটি আউটপুট দেয়

in the global scope, 5 == 5
in my function, 100 == 100
back in the global scope, 5 == 5

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

Advanced

প্রযুক্তিগতভাবে, "গ্লোবাল" শব্দটি ব্যবহার করা ঠিক নয়। একটি ফাংশনে একটি ভ্যারিয়েবল এক্সপ্যান্ড করতে, Bash কল স্ট্যাকের উপর দিয়ে, গ্লোবাল স্কোপ পর্যন্ত উপরে উঠে যায়, সেই ফাংশনটি খুঁজে বের করার জন্য যেখানে ওই ভ্যারিয়েবলের নামটি ডিক্লেয়ার করা হয়েছে।

এই উদাহরণটি ম্যানুয়ালের শেল ফাংশন অংশ থেকে নেওয়া:

func1() {
    local var='func1 local'
    func2
}

func2() {
    echo "In func2, var = $var"
}

var=global
func1
func2

আউটপুটটি হলো:

In func2, var = func1 local
In func2, var = global

একইভাবে, একটি ভ্যারিয়েবলে একটি মান অ্যাসাইন করলে সেটি যেখানে ডিক্লেয়ার করা হয়েছিল সেই স্কোপে অ্যাসাইন হবে। এই "দূর থেকে ক্রিয়া" অনুসরণ করা কঠিন কোড তৈরি করতে পারে, কারণ একটি ভ্যারিয়েবলে কোথায় মান অ্যাসাইন করা হয়েছে তা সবসময় স্পষ্ট নয়।

Advanced

FUNCNAME অ্যারে ভ্যারিয়েবলটি ব্যবহার করে কল স্ট্যাক পরীক্ষা করা যায়।

রিটার্ন ভ্যালু

একটি ফাংশনের, যেকোনো কমান্ডের মতোই, একটি এক্সিট স্ট্যাটাস থাকে। ডিফল্টভাবে, একটি ফাংশনের স্ট্যাটাস হলো সর্বশেষ চালানো কমান্ডের এক্সিট স্ট্যাটাস।

আপনি একটি নির্দিষ্ট এক্সিট স্ট্যাটাস নিয়ে ফাংশন থেকে ফিরে আসতে return কমান্ডটি ব্যবহার করতে পারেন।

check_password () {
    if [[ $1 == "secret" ]]; then
        return 0
    else
        return 1
    fi
}

read -sp "Enter your password: " pass

if check_password "$pass"; then
    echo "Correct!"
else
    echo "Wrong password."
fi

কোনো আর্গুমেন্ট ছাড়া return ব্যবহার করলে সর্বশেষ চালানো কমান্ডের স্ট্যাটাস রিটার্ন হয়।

Note

লক্ষ্য করুন, check_password ফাংশনটি এভাবে সরল করা যায়:

check_password () { [[ $1 == "secret" ]]; }
  1. [[...]] কন্ডিশনাল কনস্ট্রাক্টের একটি এক্সিট স্ট্যাটাস থাকে: "true"-এর জন্য 0, "false"-এর জন্য 1।
  2. {...} গ্রুপিং কনস্ট্রাক্টে শেষ ব্রেসের আগে অবশ্যই একটি নতুন লাইন বা একটি সেমিকোলন থাকতে হবে।

ফাংশনের আউটপুট

একটি ফাংশনের রিটার্ন স্ট্যাটাস শুধু একটি সংখ্যা। তাহলে একটি ফাংশন কীভাবে আউটপুট তৈরি করবে?

আপনার ফাংশন স্ট্যান্ডার্ড আউটপুটে প্রিন্ট করতে পারে। এটি ক্যাপচার করতে পরিচিত কমান্ড সাবস্টিটিউশন ব্যবহার করুন:

d6 () { echo "$(( 1 + RANDOM % 6 ))"; }

die=$( d6 )
echo "You rolled a $die."

আউটপুট ও স্ট্যাটাস দুটোই ব্যবহার করা

আপনি আউটপুট ক্যাপচার করছেন তখনও একটি ফাংশনের এক্সিট স্ট্যাটাস ব্যবহারের জন্য উপলব্ধ থাকে।

roll () {
    local n=$1
    if (( 4 <= n && n <= 20 )); then
        echo "$(( 1 + RANDOM % n ))"  # exit status is 0
    else
        return 1
    fi
}

read -p "How many faces does your die have? " faces
if die=$( roll "$faces" ); then
    echo "You rolled a $die."
else
    echo "I can't roll a die with $faces faces."
fi

রিকার্শন

ফাংশন নিজেদের রিকার্সিভলি কল করতে পারে। ডিফল্টভাবে, রিকার্শনের গভীরতার কোনো সীমা নেই।

একটি উদাহরণ:

fibonacci() {
    local n=$1
    if (( n <= 1 )); then
        echo "1"
    else
        local a=$(fibonacci "$(( n - 1 ))")
        local b=$(fibonacci "$(( n - 2 ))")
        echo "$(( a + b ))"
    fi
}

for i in {1..10}; do fibonacci "$i"; done
# => 1
# => 2
# => 3
# => 5
# => 8
# => 13
# => 21
# => 34
# => 55
# => 89
Advanced

FUNCNEST ভ্যারিয়েবলটি দিয়ে রিকার্শনের গভীরতা নিয়ন্ত্রণ করা যায়।

bash -c '
    recur() {
        echo $1
        recur $(($1 + 1))
    }
    FUNCNEST=5
    recur 1
'
1
2
3
4
5
environment: line 1: recur: maximum function nesting level exceeded (5)
GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি নতুন একটি উইন্ডো বা ট্যাবে খুলবে