বাশ: পরামিতি হিসাবে একটি ফাংশন পাস


91

বাশের একটি প্যারামিটার হিসাবে আমার একটি ফাংশন পাস করতে হবে। উদাহরণস্বরূপ, নিম্নলিখিত কোড:

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  eval $1
  echo "after"
}

around x

আউটপুট করা উচিত:

before
Hello world
after

আমি জানি evalযে প্রসঙ্গে সঠিক নয় তবে এটি কেবল একটি উদাহরণ :)

কোন ধারণা?

উত্তর:


126

যদি আপনার কোনও ক্রিয়াকলাপের নাম বা যুক্তিগুলির মূল্যায়ন বিলম্ব করার মতো অভিনব কোনও প্রয়োজন না হয়, আপনার প্রয়োজন হবে না eval:

function x()      { echo "Hello world";          }
function around() { echo before; $1; echo after; }

around x

আপনি যা চান তা করে আপনি এমনকি ফাংশন এবং এর যুক্তিগুলি এভাবে পাস করতে পারেন:

function x()      { echo "x(): Passed $1 and $2";  }
function around() { echo before; "$@"; echo after; }

around x 1st 2nd

প্রিন্ট

before
x(): Passed 1st and 2nd
after

4
আমার যদি অন্য একটি y () ফাংশন থাকে তবে আমি কি X 1 য় 2 য় y 1 ম 2 য়ের কাছাকাছি করতে পারি? এটি কীভাবে জানতে পারে যে x এবং y হল চারপাশের জন্য আর্গুমেন্ট এবং প্রথম এবং দ্বিতীয়টি X এবং y এর পক্ষে যুক্তিযুক্ত?
techguy2000

এবং আপনি ফাংশন শব্দ বাদ দিতে পারেন।
জেসনলোনহার্ড

তবে, তারপর তারা নাম-ব্যবধানে থাকবে না। অর্থাত্ যদি আপনার পদ্ধতিগুলির অভ্যন্তরে কোনও পদ্ধতি থাকে এবং আপনি functionশব্দটি রাখেন তবে আপনি শীর্ষ স্তরের পদ্ধতিটি চালা না করা অবধি এই অভ্যন্তরীণ পদ্ধতিগুলিতে অ্যাক্সেস করতে পারবেন না।
জেসনলোনহার্ড

29

আমি মনে করি না কেউ এই প্রশ্নের যথেষ্ট উত্তর দিয়েছে। তিনি জিজ্ঞাসা করেননি যে সেগুলি ক্রমে স্ট্রিং প্রতিধ্বনি করতে পারে কিনা। বরং প্রশ্নের লেখক জানতে চান যে তিনি ফাংশন পয়েন্টার আচরণ অনুকরণ করতে পারেন কিনা।

এখানে বেশ কয়েকটি উত্তর রয়েছে যা আমি যা করছিলাম তার মতো এবং আমি এটি অন্য একটি উদাহরণ দিয়ে প্রসারিত করতে চাই।

লেখকের কাছ থেকে:

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  ($1)                   <------ Only change
  echo "after"
}

around x

এটি প্রসারিত করতে, ফাংশন বাস্তবায়ন কখন ঘটে থাকে তা দেখানোর জন্য আমাদের ফাংশন এক্স ইকো "হ্যালো ওয়ার্ল্ড: $ 1" থাকবে। আমরা একটি স্ট্রিং পাস করব যা "x" ফাংশনের নাম:

function x() {
  echo "Hello world:$1"
}

function around() {
  echo "before"
  ($1 HERE)                   <------ Only change
  echo "after"
}

around x

এটি বর্ণনার জন্য, "x" স্ট্রিংটি () এর চারপাশে ফাংশনটিতে প্রেরণ করা হয় যা "এর আগে" থাকে, ফাংশনটিকে x (ভ্যারিয়েবল $ 1 এর মাধ্যমে বলে, প্রথম প্যারামিটারটি চারপাশে চলে গেছে) "HERE" আর্গুমেন্টটি পাস করে শেষ পর্যন্ত ইকোস করে ।

অন্য একদিকে যেমন ফাংশনের নাম হিসাবে ভেরিয়েবল ব্যবহার করার পদ্ধতি এটি। ভেরিয়েবলগুলি প্রকৃতপক্ষে স্ট্রিংটি ধারণ করে যা ফাংশনের নাম এবং ($ ভেরিয়েবল আরগ 1 আরজি 2 ...) আর্গুমেন্টগুলি অতিক্রম করে ফাংশনটিকে কল করে। নিচে দেখ:

function x(){
    echo $3 $1 $2      <== just rearrange the order of passed params
}

Z="x"        # or just Z=x

($Z  10 20 30)

দেয়: 30 10 20, যেখানে আমরা ভেরিয়েবল জেডে "x" নামক ফাংশনটি কার্যকর করি এবং 10 20 এবং 30 প্যারামিটারগুলি পাস করেছি।

উপরে যেখানে আমরা ফাংশনগুলিতে ভেরিয়েবল নাম নির্ধারণ করে ফাংশনগুলি উল্লেখ করি যাতে আমরা ফাংশনটির নামটি জানার পরিবর্তে চলকটি ব্যবহার করতে পারি (যা প্রোগ্রামের প্রবাহকে সাধারণীকরণের জন্য সিতে খুব ক্লাসিক ফাংশন পয়েন্টার অবস্থায় আপনি যা করতে পারেন তার অনুরূপ তবে পূর্বের - কমান্ড লাইন আর্গুমেন্টের উপর ভিত্তি করে ফাংশন কলগুলি নির্বাচন করা)।

ব্যাশে এগুলি ফাংশন পয়েন্টার নয়, তবে ভেরিয়েবলগুলি যা আপনার পরে ব্যবহার করা ফাংশনগুলির নাম উল্লেখ করে।


এই উত্তর দুর্দান্ত। আমি সমস্ত উদাহরণের বাশ স্ক্রিপ্ট তৈরি করে এনেছি। আপনি কীভাবে "কেবলমাত্র পরিবর্তন" এর নির্মাতাদের তৈরি করেছিলেন যা আপনাকে অনেক সহায়তা করেছিল তা আমিও সত্যিই পছন্দ করি। আপনার দ্বিতীয় থেকে শেষ অনুচ্ছেদে একটি ভুল বানান রয়েছে: "অ্যাবোভ"
জেএমআই

টাইপো স্থির ধন্যবাদ @J MADISON
uDude

7
আপনি কেন এটি মুড়ে ()রাখবেন না যে উপ-শেলটি শুরু করবে না?
ঘোড়াওয়ালা

17

ব্যবহার করার দরকার নেই eval

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  var=$($1)
  echo "after $var"
}

around x

5

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

এখানে একটি দ্রুত বোকা

foldl() {
    echo $(($(</dev/stdin)$2))
} < <(tr '\n' "$1" <$3)

# Sum 20 random ints from 0-999
foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)

ফাংশনগুলি রফতানি করা যায়, তবে এটি প্রথম প্রদর্শিত হওয়ার মতো আকর্ষণীয় নয়। আমি এটি ডিবাগিং ফাংশনগুলি স্ক্রিপ্টগুলি বা স্ক্রিপ্টগুলি চালিত অন্যান্য প্রোগ্রামগুলিতে অ্যাক্সেসযোগ্য করার জন্য দরকারী বলে মনে করি।

(
    id() {
        "$@"
    }

    export -f id
    exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi'
)

id এখনও কেবল একটি স্ট্রিং পাওয়া যায় যা কোনও ফাংশনের (পরিবেশে সিরিয়ালাইজেশন থেকে স্বয়ংক্রিয়ভাবে আমদানি করা হয়) এবং এর আরোগুলির নাম হতে পারে।

অন্য উত্তরে পুমবা ৮০ এর মন্তব্যটিও ভাল ( eval $(declare -F "$1")), তবে এটি মূলত অ্যারেগুলির জন্য কার্যকর, ফাংশন নয়, কারণ তারা সর্বদা বিশ্বব্যাপী। আপনি যদি এটি কোনও ফাংশনটির মধ্যে চালাতে চান তবে এটিই এটির নতুন সংজ্ঞা দেওয়া হবে, সুতরাং এর কোনও প্রভাব নেই। এটি ক্লোজার বা আংশিক ফাংশন বা "ফাংশন দৃষ্টান্তগুলি" তৈরি করতে ব্যবহৃত হতে পারে যা বর্তমান স্কোপটিতে আবদ্ধ হতে পারে তার উপর নির্ভর করে। সর্বোপরি এটি স্ট্রিংয়ে ফাংশন সংজ্ঞা সংরক্ষণ করতে ব্যবহার করা যেতে পারে যা অন্য কোথাও পুনরায় সংজ্ঞায়িত হয় - তবে সেই ফাংশনগুলি কেবল হার্ডকোড করা যেতে পারে যদি না অবশ্যই evalব্যবহৃত হয়

মূলত বাশকে এভাবে ব্যবহার করা যায় না।


2

আপনার ফাংশনগুলিতে স্থানীয় ভেরিয়েবলগুলি ব্যবহার করা আরও ভাল পদ্ধতির। সমস্যাটি তখন হয়ে যায় আপনি কলারের কাছে কীভাবে ফলাফল পাবেন। একটি প্রক্রিয়া হ'ল কমান্ড প্রতিস্থাপন ব্যবহার:

function myfunc()
{
    local  myresult='some value'
    echo "$myresult"
}

result=$(myfunc)   # or result=`myfunc`
echo $result

এখানে ফলাফলটি stdout এ আউটপুট এবং কলকারী একটি ভেরিয়েবলের মান ক্যাপচারের জন্য কমান্ড প্রতিস্থাপন ব্যবহার করে। ভেরিয়েবলটি তখন প্রয়োজনীয় হিসাবে ব্যবহার করা যেতে পারে।


1

আপনার লাইনের সাথে কিছু থাকতে হবে:

function around()
{
  echo 'before';
  echo `$1`;
  echo 'after';
}

তারপরে আপনি কল করতে পারেন around x


-1

সম্ভবত এটি সম্পাদনের একমাত্র উপায় ev একমাত্র আসল ক্ষতি এটির সুরক্ষা দিক, কারণ আপনাকে অবশ্যই নিশ্চিত করতে হবে যে দূষিত কোনও কিছুই প্রবেশ করতে পারে না এবং কেবল যে ফাংশনগুলিতে আপনাকে কল করতে চান সেগুলি ডাকা হবে (পাশাপাশি এটি পরীক্ষা করতে হবে যে এটির মতো 'বাজে অক্ষর নেই;'; ' এটিতেও)।

সুতরাং আপনি যদি কোডটি কল করে থাকেন তবে সম্ভবত এটি করা একমাত্র উপায় al মনে রাখবেন যে এওল এর অন্যান্য ফর্মগুলি সম্ভবত সাবকম্যান্ডস ($ ()) এবং ``) এর সাথে জড়িত কাজ করে তবে তারা নিরাপদ নয় এবং আরও ব্যয়বহুল।


eval এটি করার একমাত্র উপায়।
ওয়েজ

4
আপনি সহজেই পরীক্ষা করতে পারবেন যদি eval $1একটি ফাংশন ব্যবহার করে কল করবেif declare -F "$1" >/dev/null; then eval $1; fi
user123444555621

4
... বা আরও ভাল:eval $(declare -F "$1")
ব্যবহারকারী 123444555621
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.