বাশ ফাংশন থেকে স্ট্রিংয়ের মানটি কীভাবে ফিরে আসে


461

আমি বাশ ফাংশন থেকে একটি স্ট্রিং ফিরিয়ে দিতে চাই।

আমি যা করতে চাই তা দেখানোর জন্য আমি জাভাতে উদাহরণ লিখব:

public String getSomeString() {
  return "tadaa";
}

String variable = getSomeString();

নীচের উদাহরণটি ব্যাশে কাজ করে তবে এটি করার কী আরও ভাল উপায় আছে?

function getSomeString {
   echo "tadaa"
}

VARIABLE=$(getSomeString)

4
একদিকে function funcName {যেমন , প্রার-পসিক্স লিগ্যাসি সিনট্যাক্সটি প্রারম্ভিক ksh থেকে উত্তরাধিকার সূত্রে প্রাপ্ত (যেখানে এর অর্থগত পার্থক্য রয়েছে যা বাশ সম্মান করে না)। পরিবর্তে, funcName() {না সহ function, ব্যবহার করা উচিত; দেখতে wiki.bash-hackers.org/scripting/obsolete
চার্লস ডাফি

এই লিঙ্কটি NAME () COMPOUND-CMD বা ফাংশন NAME {সিএমডিএস ব্যবহার করতে বলে; } তাই function myFunction { blah; }ঠিক আছে; এটি দুর্দান্ত function myFunction() { blah }নয়, অর্থাত্ কীওয়ার্ড ফাংশন সহ প্রথম বন্ধনী ব্যবহার।
উইল

উত্তর:


290

আমি জানি এর চেয়ে ভাল আর কোনও উপায় নেই। বাশ কেবল স্ট্যাটাসে লিখিত স্ট্যাটাস কোড (পূর্ণসংখ্যা) এবং স্ট্রিংগুলি জানে।


15
+1 @ টমাস-এফ: এই ফাংশন "getSomeString ()" তে আপনার যা আছে তা সম্পর্কে আপনাকে অবশ্যই সতর্কতা অবলম্বন করতে হবে কারণ যে কোনও কোড থাকার ফলে অবশেষে প্রতিধ্বনিত হবে তার অর্থ আপনি ভুল ফেরতের স্ট্রিং পাবেন।
মণি

11
এটি কেবল সাধারণ ভুল। আপনি একটি রিটার্ন ভেরিয়েবলের মধ্যে স্বেচ্ছাসেবক ডেটা দিতে পারেন। যা পরিষ্কারভাবে একটি ভাল উপায়।
Evi1M4chine

36
@ Evi1M4chine, উম ... না, আপনি পারবেন না। আপনি একটি গ্লোবাল ভেরিয়েবল সেট করতে পারেন এবং এটিকে "রিটার্ন" হিসাবে কল করতে পারেন, আমি দেখতে পাচ্ছি যে আপনি আপনার স্ক্রিপ্টগুলিতে করছেন। কিন্তু তারপরে এটি কনভেনশন করে, আসলে আপনার কোডটি কার্যকর করার সাথে প্রোগ্রামগতভাবে আবদ্ধ হয় না। "পরিষ্কারভাবে একটি ভাল উপায়"? উম, না। কমান্ড প্রতিস্থাপন অনেক বেশি সুস্পষ্ট এবং মডুলার।
ওয়াইল্ডকার্ড

6
"কমান্ডের প্রতিস্থাপনটি আরও স্পষ্ট এবং মডুলার" প্রাসঙ্গিক হবে যদি প্রশ্নটি আদেশের বিষয়ে ছিল; এই প্রশ্নটি কীভাবে কোনও স্ট্রিং ফিরিয়ে আনবে, বাশ ফাংশন থেকে! ওপি যা বলেছে তা করার একটি অন্তর্নির্মিত পরিমাণ 4.3 বাশ (2014?) থেকে পাওয়া যায় - নীচে আমার উত্তর দেখুন।
জেনান

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

193

আপনি প্রথম আর্গ হিসাবে ফাংশনটি একটি ভেরিয়েবল নিতে এবং আপনি যে স্ট্রিংটিতে ফিরে আসতে চান তার মাধ্যমে পরিবর্তনশীলটি সংশোধন করতে পারেন।

#!/bin/bash
set -x
function pass_back_a_string() {
    eval "$1='foo bar rab oof'"
}

return_var=''
pass_back_a_string return_var
echo $return_var

"ফু বার রব ওফ" মুদ্রণ করুন।

সম্পাদনা : @ লুকা বোররিওনের মন্তব্যে সম্বোধন করার জন্য স্ট্রিংয়ে সাদা জায়গার অনুমতি দেওয়ার জন্য উপযুক্ত জায়গায় উদ্ধৃতি যুক্ত করা হয়েছে।

সম্পাদনা : একটি বিক্ষোভ হিসাবে, নিম্নলিখিত প্রোগ্রামটি দেখুন। এটি একটি সাধারণ-উদ্দেশ্য সমাধান: এটি আপনাকে স্থানীয় ভেরিয়েবলের স্ট্রিংও পেতে দেয়।

#!/bin/bash
set -x
function pass_back_a_string() {
    eval "$1='foo bar rab oof'"
}

return_var=''
pass_back_a_string return_var
echo $return_var

function call_a_string_func() {
     local lvar=''
     pass_back_a_string lvar
     echo "lvar='$lvar' locally"
}

call_a_string_func
echo "lvar='$lvar' globally"

এই মুদ্রণ:

+ return_var=
+ pass_back_a_string return_var
+ eval 'return_var='\''foo bar rab oof'\'''
++ return_var='foo bar rab oof'
+ echo foo bar rab oof
foo bar rab oof
+ call_a_string_func
+ local lvar=
+ pass_back_a_string lvar
+ eval 'lvar='\''foo bar rab oof'\'''
++ lvar='foo bar rab oof'
+ echo 'lvar='\''foo bar rab oof'\'' locally'
lvar='foo bar rab oof' locally
+ echo 'lvar='\'''\'' globally'
lvar='' globally

সম্পাদনা : এটি প্রমাণ করে যে ফাংশনে আসল ভেরিয়েবলের মান পাওয়া যায়, যেমনটি একটি মন্তব্যে @ জিচেন লি ভুলভাবে সমালোচনা করেছিলেন।

#!/bin/bash
set -x
function pass_back_a_string() {
    eval "echo in pass_back_a_string, original $1 is \$$1"
    eval "$1='foo bar rab oof'"
}

return_var='original return_var'
pass_back_a_string return_var
echo $return_var

function call_a_string_func() {
     local lvar='original lvar'
     pass_back_a_string lvar
     echo "lvar='$lvar' locally"
}

call_a_string_func
echo "lvar='$lvar' globally"

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

+ return_var='original return_var'
+ pass_back_a_string return_var
+ eval 'echo in pass_back_a_string, original return_var is $return_var'
++ echo in pass_back_a_string, original return_var is original return_var
in pass_back_a_string, original return_var is original return_var
+ eval 'return_var='\''foo bar rab oof'\'''
++ return_var='foo bar rab oof'
+ echo foo bar rab oof
foo bar rab oof
+ call_a_string_func
+ local 'lvar=original lvar'
+ pass_back_a_string lvar
+ eval 'echo in pass_back_a_string, original lvar is $lvar'
++ echo in pass_back_a_string, original lvar is original lvar
in pass_back_a_string, original lvar is original lvar
+ eval 'lvar='\''foo bar rab oof'\'''
++ lvar='foo bar rab oof'
+ echo 'lvar='\''foo bar rab oof'\'' locally'
lvar='foo bar rab oof' locally
+ echo 'lvar='\'''\'' globally'
lvar='' globally

1
এই উত্তর দুর্দান্ত! প্যারামিটারগুলি রেফারেন্সগুলি দ্বারা পাস করা যেতে পারে, সি ++ তে ধারণার মতো।
ইউন হুয়াং

4
এই উত্তর সম্পর্কে কোনও বিশেষজ্ঞের কাছ থেকে প্রতিক্রিয়া পেয়ে ভাল লাগবে। আমি কখনও স্ক্রিপ্টগুলিতে ব্যবহার করতে দেখিনি, সম্ভবত কোনও ভাল কারণে। যাইহোক: এটি +1 এটি সঠিক উত্তরের জন্য ভোট দেওয়া উচিত ছিল
জন

fgmসরলীকরণের মাধ্যমে উত্তরটি কি একই রকম লেখা হয় না? যদি স্ট্রিংটিতে fooসাদা স্পেস থাকে তবে এটি কাজ করবে না , যখন যেটি fgmদেখিয়ে দিচ্ছে সেভাবেই এটি করবে ...
লুকা বোররিওন

4
@ শিচেনলি: আপনার ডাউনটাতে একটি মন্তব্য দেওয়ার জন্য ধন্যবাদ; আমার সম্পাদনা দেখুন। আপনি ভেরিয়েবলের প্রাথমিক মানটি সাথে পেতে পারেন \$$1। আপনি যদি কিছু আলাদা খুঁজছেন তবে দয়া করে আমাকে জানান।
bstpierre

1
@ টিমস্কোডিং এটি দিয়ে স্থির করা যেতে পারে printf '%q' "$var"। % q শেল পালানোর জন্য একটি বিন্যাসের স্ট্রিং। তারপর শুধু এটি কাঁচা পাস।
বিবি010 জি

99

উপরের সমস্ত উত্তর বাশের ম্যান পৃষ্ঠাতে যা বলেছিল তা উপেক্ষা করে।

  • কোনও ফাংশনের অভ্যন্তরে ঘোষিত সমস্ত ভেরিয়েবলগুলি কলিং পরিবেশের সাথে ভাগ করা হবে।
  • স্থানীয় ঘোষিত সমস্ত ভেরিয়েবল ভাগ করা হবে না।

উদাহরণ কোড

#!/bin/bash

f()
{
    echo function starts
    local WillNotExists="It still does!"
    DoesNotExists="It still does!"
    echo function ends
}

echo $DoesNotExists #Should print empty line
echo $WillNotExists #Should print empty line
f                   #Call the function
echo $DoesNotExists #Should print It still does!
echo $WillNotExists #Should print empty line

এবং আউটপুট

$ sh -x ./x.sh
+ echo

+ echo

+ f
+ echo function starts 
function starts
+ local 'WillNotExists=It still does!'
+ DoesNotExists='It still does!'
+ echo function ends 
function ends
+ echo It still 'does!' 
It still does!
+ echo

এছাড়াও pdksh এবং ksh এর অধীনে এই স্ক্রিপ্টটি একই কাজ করে!


10
এই উত্তরের গুণাবলি রয়েছে। আমি এখানে এসে ভাবছিলাম যে আমি কোনও ফাংশন থেকে একটি স্ট্রিং ফিরিয়ে দিতে চাই। এই উত্তরটি আমাকে বুঝতে পেরেছিল যে এটি আমার সি # হবিটদের সাথে কথা বলছিল। আমি সন্দেহ করি অন্যেরও একই অভিজ্ঞতা থাকতে পারে।
লস

4
@ এলমারজান্ডার আপনি ভুল, এটি সম্পূর্ণ প্রাসঙ্গিক। এটি একটি ফাংশন-স্কোপ মান হিসাবে বৈশ্বিক সুযোগসুবিধাতে আসার একটি সহজ উপায় এবং কেউ কেউ বিএসপিয়ারের দ্বারা বর্ণিত একটি বৈশ্বিক পরিবর্তনশীলকে পুনরায় সংজ্ঞায়িত করার জন্য এই পদ্ধতির চেয়ে আরও ভাল / সহজ বিবেচনা করবে।
কমডোডেভ

স্থানীয়-নন-ব্যাশ স্ক্রিপ্টগুলির কাছে বহনযোগ্য নয় যা কিছু কারণের কারণে এড়ানো যায়।
উজ্জ্বল ডোন

প্রশ্ন: লুপগুলিতে ভেরিয়েবল সম্পর্কে কী?
আনু

1
একটি ম্যাক ($ বাশ - রূপান্তর জিএনইউ ব্যাশ, সংস্করণ 3.2.57 (1) -রিলিজ (x86_64-আপেল-ডারউইন 14) কপিরাইট (সি) 2007 ফ্রি সফটওয়্যার ফাউন্ডেশন, ইনক।), এটি সঠিক যে কোনও মিলিয়ে গ্লোবাল ভেরিয়েবল আরম্ভ করা হয়েছে, তবে যখন আমি অন্য ফাংশন এফ 2 তে একই পরিবর্তনশীলটিকে পার্শ্ব-প্রতিক্রিয়া করার চেষ্টা করি তখন সেই পার্শ্ব-প্রতিক্রিয়াটি স্থির থাকে না। সুতরাং, এটি খুব বেমানান বলে মনে হচ্ছে এবং এটি আমার ব্যবহারের পক্ষে ভাল নয়।
অ্যানি দ্য অ্যাজিল

45

বাশ, সংস্করণ ৪.৩ থেকে, ফেব্রুয়ারী ২০১৪ (?), একই উপকারী কর্মক্ষমতা এবং দিকনির্দেশনা প্রভাব সহ "ইওল" এর বাইরে রেফারেন্স ভেরিয়েবল বা নাম রেফারেন্সের (নেমরেফ) স্পষ্ট সমর্থন রয়েছে এবং যা আপনার স্ক্রিপ্টগুলিতে আরও স্পষ্ট এবং আরও শক্ত হতে পারে "'ওয়াল' করতে ভুলে যেতে এবং এই ত্রুটিটি ঠিক করতে হবে":

declare [-aAfFgilnrtux] [-p] [name[=value] ...]
typeset [-aAfFgilnrtux] [-p] [name[=value] ...]
  Declare variables and/or give them attributes
  ...
  -n Give each name the nameref attribute, making it a name reference
     to another variable.  That other variable is defined by the value
     of name.  All references and assignments to name, except for
     changing the -n attribute itself, are performed on the variable
     referenced by name's value.  The -n attribute cannot be applied to
     array variables.
...
When used in a function, declare and typeset make each name local,
as with the local command, unless the -g option is supplied...

এবং আরো:

প্যারামিটার

একটি ভেরিয়েবলকে নেমরেফ তৈরির জন্য -n বিকল্পটি ব্যবহার করে নাম বা স্থানীয় বিল্টিন কমান্ডের (নীচে ঘোষিত এবং স্থানীয় বর্ণনার বিবরণ দেখুন) অথবা অন্য ভেরিয়েবলের একটি রেফারেন্স নির্ধারণ করা যেতে পারে। এটি ভেরিয়েবলকে অপ্রত্যক্ষভাবে হেরফের করতে দেয় allows যখনই নেমরেফ ভেরিয়েবলকে ⋅ রেফারেন্সযুক্ত বা নির্ধারিত করা হয়, অপারেশনটি আসলে নামরেফ ভেরিয়েবলের মান দ্বারা নির্দিষ্ট ভেরিয়েবলের উপর সঞ্চালিত হয়। একটি নেমরেফ শেল ফাংশনগুলির মধ্যে সাধারণত একটি ভেরিয়েবলের উল্লেখ করতে ব্যবহৃত হয় যার নামটি আর্গুমেন্ট হিসাবে আর্গুমেন্ট হিসাবে পাস হয়। উদাহরণস্বরূপ, যদি কোনও চলক নামটি শেল ফাংশনে তার প্রথম যুক্তি হিসাবে চালিত হয় তবে এটি চলছে

      declare -n ref=$1

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

উদাহরণস্বরূপ ( সম্পাদনা 2 : (আপনাকে ধন্যবাদ রন) ফাংশন-অভ্যন্তরীণ ভেরিয়েবল নামটি স্পেস-এর (পূর্বনির্ধারিত) নাম, বাইরের ভেরিয়েবল সংঘর্ষকে হ্রাস করতে, যা শেষ পর্যন্ত সঠিকভাবে উত্তর দেওয়া উচিত, কার্স্টেনের মন্তব্যে উত্থাপিত বিষয়টি):

# $1 : string; your variable to contain the return value
function return_a_string () {
    declare -n ret=$1
    local MYLIB_return_a_string_message="The date is "
    MYLIB_return_a_string_message+=$(date)
    ret=$MYLIB_return_a_string_message
}

এবং এই উদাহরণটি পরীক্ষা:

$ return_a_string result; echo $result
The date is 20160817

নোট করুন যে ব্যাশ "ডিক্লেয়ার" বিল্টিন, যখন কোনও ফাংশনে ব্যবহৃত হয়, ঘোষিত ভেরিয়েবলটিকে ডিফল্টরূপে "স্থানীয়" করে তোলে এবং "-n" "স্থানীয়" দিয়েও ব্যবহার করা যেতে পারে।

আমি "বিরক্তিকর স্থানীয়" ভেরিয়েবলগুলির মধ্যে "গুরুত্বপূর্ণ ঘোষণা" ভেরিয়েবলকে পৃথক করতে পছন্দ করি, সুতরাং "ডিক্লেয়ার" এবং "স্থানীয়" এভাবে ব্যবহার করে ডকুমেন্টেশন হিসাবে কাজ করে।

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

$ return_a_string ret; echo $ret
The date is 20170104

(উপরের ফাংশনটিকে বাশ টার্মে আটকানোর পরে আমি এখনই এটি চালিয়েছি - যেমন আপনি দেখতে পাচ্ছেন, ফলাফলটি ঠিক কাজ করে))


4
এটি আমার আশা যে এটি শীর্ষে পৌঁছেছে। eval একটি শেষ অবলম্বন করা উচিত। উল্লেখ যোগ্য যে nameref ভেরিয়েবল ব্যাশ 4.3 (অনুসারে যেহেতু কেবল প্রাপ্তিসাধ্য হয় পরিবর্তণের ) (ফেব্রুয়ারী 2014 [?] সালে মুক্তি)। বহনযোগ্যতা যদি উদ্বেগ হয় তবে এটি গুরুত্বপূর্ণ is অনুগ্রহ করে বাশ ম্যানুয়ালটি উল্লেখ করুন যা declareফাংশনের অভ্যন্তরে স্থানীয় ভেরিয়েবল তৈরি করে (যে তথ্যটি দেওয়া হয় না help declare): "... কোনও ফাংশনে ব্যবহৃত হলে, ডিক্লেয়ার এবং টাইপসেটকে স্থানীয় কমান্ডের মতো প্রতিটি নাম স্থানীয় করে তোলে, যদি না - g বিকল্প সরবরাহ করা হয়েছে ... "
init_js

2
এটি যেমন বিভাজন সমাধান হিসাবে একই aliasing সমস্যা আছে। আপনি যখন কোনও ফাংশন কল করেন এবং আউটপুট ভেরিয়েবলের নামে পাস করেন, আপনাকে কল করা ফাংশনটির মধ্যে স্থানীয়ভাবে ব্যবহৃত একটি ভেরিয়েবলের নামটি এড়াতে হবে। এটি এনক্যাপসুলেশনের ক্ষেত্রে একটি বড় সমস্যা, কারণ আউটপুট প্যারামিটারের জন্য কোনও ফাংশন কলকারীরা নামটি ব্যবহার করতে চাইলে আপনি কেবল কোনও ফাংশনে নতুন স্থানীয় ভেরিয়েবল যুক্ত বা নাম পরিবর্তন করতে পারবেন না।
কার্স্টেন

1
@ কার্স্টেন সম্মত হয়েছেন। উভয় ক্ষেত্রে (ইওল এবং নেমরেফ), আপনাকে অন্য কোনও নাম বাছতে হতে পারে। ইওল এর উপরে নেমরেফ পদ্ধতির সাথে একটি সুবিধা হ'ল পলাতক স্ট্রিংগুলির সাথে কারও মুখোমুখি হতে হয় না। অবশ্যই, আপনি সর্বদা এমন কিছু করতে পারেন K=$1; V=$2; eval "$A='$V'";তবে একটি ভুল (যেমন একটি খালি বা বাদ দেওয়া প্যারামিটার), এবং এটি আরও বিপজ্জনক হবে। @ কার্স্টেনের উত্থাপিত ইস্যুটি @ জেনান প্রযোজ্য যদি আপনি "রেট" এর পরিবর্তে "বার্তা "টিকে ফেরত পরিবর্তনশীল নাম হিসাবে বেছে নেন।
init_js

3
একটি নেমরেফ যুক্তি গ্রহণ করার জন্য সম্ভবত একটি ফাংশন সম্ভবত শুরু থেকেই ডিজাইন করা উচিত, সুতরাং ফাংশন লেখককে নামের সংঘর্ষের সম্ভাবনা সম্পর্কে সচেতন হওয়া উচিত এবং এটি এড়াতে কিছু সাধারণ সম্মেলন ব্যবহার করতে পারেন। উদাহরণস্বরূপ, এক্স ফাংশনের ভিতরে, কনভেনশন "এক্স_লোকাল_নাম" সহ স্থানীয় ভেরিয়েবলের নাম দিন।
রন বার্ক

34

উপরের বাইস্টপিয়ারের মতো আমিও আউটপুট ভেরিয়েবলের নাম স্পষ্টভাবে ব্যবহার করার এবং ব্যবহারের পরামর্শ দিচ্ছি:

function some_func() # OUTVAR ARG1
{
   local _outvar=$1
   local _result # Use some naming convention to avoid OUTVARs to clash
   ... some processing ....
   eval $_outvar=\$_result # Instead of just =$_result
}

Quot উদ্ধৃতি ব্যবহার নোট করুন। এটি $resultশেল বিশেষ অক্ষর হিসাবে সামগ্রী ব্যাখ্যা করা এড়াবে। আমি খুঁজে পেয়েছি যে এটি এর চেয়ে দ্রুততর মানের একটি ক্রমresult=$(some_func "arg1") প্রতিধ্বনি ক্যাপচার মূর্খতার । গতি পার্থক্য এমএসওয়াইএসে ব্যাশ ব্যবহার করে আরও উল্লেখযোগ্য বলে মনে হয় যেখানে ফাংশন কলগুলি থেকে স্ট্যান্ডআউট ক্যাপচারিং প্রায় বিপর্যয়কর।

স্থানীয় ভেরিয়েবলগুলি প্রেরণ করা ঠিক আছে যেহেতু স্থানীয়রা গতিশীলভাবে ব্যাশে স্ক্যাপেড রয়েছে:

function another_func() # ARG
{
   local result
   some_func result "$1"
   echo result is $result
}

4
এটি আমাকে সহায়তা করে কারণ আমি ডিবাগিং / লগিংয়ের উদ্দেশ্যে একাধিক প্রতিধ্বনি বিবৃতি ব্যবহার করতে চাই। প্রতিধ্বনির প্রতিচ্ছবি ব্যর্থ হয় কারণ এটি সমস্তকে ক্যাপচার করে। ধন্যবাদ!
অ্যানি দ্য অ্যাজিল 20

এটিই (দ্বিতীয়-সেরা) সঠিক সমাধান! পরিষ্কার, দ্রুত, মার্জিত, বুদ্ধিমান।
Evi1M4chine

এটি আসল রাখার জন্য +2। আমি বলতে চলেছিলাম। echoকমান্ড সাবস্টিটিউশনের সাথে মিলিতভাবে কোনও ক্রমের অভ্যন্তরের সংমিশ্রণকে এত লোক উপেক্ষা করতে পারে !
অ্যান্টনি রটলেজ

22

আপনি ফাংশন আউটপুট ক্যাপচার করতে পারে:

#!/bin/bash
function getSomeString() {
     echo "tadaa!"
}

return_var=$(getSomeString)
echo $return_var
# Alternative syntax:
return_var=`getSomeString`
echo $return_var

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


11
বিকল্প সিনট্যাক্স নোট বাদে, এই বিকল্পটি নিজের প্রশ্নে ইতিমধ্যে লিখেছিল ঠিক একই জিনিস নয়?
লুকা বোরিওনি

12

সর্বাধিক সরল ও দৃ solution় সমাধান হ'ল কমান্ড সাবস্টিটিউশন ব্যবহার করা, যেমন অন্য লোকেরা লিখেছিল:

assign()
{
    local x
    x="Test"
    echo "$x"
}

x=$(assign) # This assigns string "Test" to x

ক্ষতি একটি পারফরম্যান্স কারণ এটি একটি পৃথক প্রক্রিয়া প্রয়োজন।

এই বিষয়টিতে প্রস্তাবিত অন্যান্য কৌশল, যথা যুক্তি হিসাবে নির্ধারিত কোনও ভেরিয়েবলের নাম পাস করার সাথে তার পার্শ্ব প্রতিক্রিয়া রয়েছে এবং আমি এটির মূল আকারে এটি প্রস্তাব দেব না। সমস্যাটি হ'ল রিটার্নের মান গণনা করার জন্য আপনার সম্ভবত ফাংশনে কিছু ভেরিয়েবলের প্রয়োজন হবে এবং এটি ঘটতে পারে যে রিটার্নের মান সংরক্ষণের উদ্দেশ্যে ভেরিয়েবলের নাম তাদের মধ্যে একটির সাথে হস্তক্ষেপ করবে:

assign()
{
    local x
    x="Test"
    eval "$1=\$x"
}

assign y # This assigns string "Test" to y, as expected

assign x # This will NOT assign anything to x in this scope
         # because the name "x" is declared as local inside the function

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

একটি সম্ভাব্য কাজ হ'ল গ্লোবাল হিসাবে পাস ভেরিয়েবলের একটি সুস্পষ্ট ঘোষণা:

assign()
{
    local x
    eval declare -g $1
    x="Test"
    eval "$1=\$x"
}

"X" নামটি যদি আর্গুমেন্ট হিসাবে পাস করা হয় তবে ফাংশন বডিটির দ্বিতীয় সারিটি পূর্ববর্তী স্থানীয় ঘোষণাকে ওভাররাইট করে। নামগুলি নিজেরাই এখনও হস্তক্ষেপ করতে পারে, সুতরাং যদি আপনি সেখানে ফেরতের মান লেখার আগে উত্তীর্ণ ভেরিয়েবলের মধ্যে পূর্বে সঞ্চিত মানটি ব্যবহার করতে চান তবে সচেতন হন যে আপনাকে অবশ্যই একেবারে অন্য স্থানীয় ভেরিয়েবলে অনুলিপি করতে হবে; অন্যথায় ফলাফল অনির্দেশ্য হবে! তদতিরিক্ত, এটি কেবল BASH এর সাম্প্রতিকতম সংস্করণে কাজ করবে, যার অর্থ 4.2। আরও পোর্টেবল কোড একই প্রভাব সহ সুস্পষ্ট শর্তাধীন কাঠামো ব্যবহার করতে পারে:

assign()
{
    if [[ $1 != x ]]; then
      local x
    fi
    x="Test"
    eval "$1=\$x"
}

সম্ভবত সবচেয়ে মার্জিত সমাধান হ'ল ফাংশন রিটার্ন মানগুলির জন্য একটি গ্লোবাল নাম সংরক্ষণ করা এবং এটি আপনি লেখার প্রতিটি ফাংশনে ধারাবাহিকভাবে ব্যবহার করুন।


3
এই। অজান্তে অ্যালিয়্যাসিং যা এনক্যাপসুলেশন ভেঙে দেয় তা হ'ল উভয় evalএবং declare -nসমাধানের ক্ষেত্রেই বড় সমস্যা । resultসমস্ত আউটপুট প্যারামিটারের মতো একক উত্সর্গীকৃত ভেরিয়েবলের নাম রাখার একমাত্র সমাধানটি মনে হয় যে দ্বন্দ্ব এড়ানোর জন্য তার কলারগুলির সমস্ত জানতে কোনও ফাংশনের প্রয়োজন হয় না।
কার্স্টেন

12

পূর্বে উল্লিখিত হিসাবে, একটি ফাংশন থেকে একটি স্ট্রিং ফিরে আসার "সঠিক" উপায় হ'ল কমান্ড প্রতিস্থাপন। যদি ফাংশনটি কনসোল করার জন্য আউটপুটও প্রয়োজন (ইভেন্ট যেমন @ মণি উপরে উল্লেখ করেছেন), ফাংশনটির শুরুতে একটি অস্থায়ী fd তৈরি করুন এবং কনসোলে পুনঃনির্দেশ করুন। আপনার স্ট্রিং ফিরে আসার আগে অস্থায়ী fd বন্ধ করুন।

#!/bin/bash
# file:  func_return_test.sh
returnString() {
    exec 3>&1 >/dev/tty
    local s=$1
    s=${s:="some default string"}
    echo "writing directly to console"
    exec 3>&-     
    echo "$s"
}

my_string=$(returnString "$*")
echo "my_string:  [$my_string]"

কোনও প্যারাম ছাড়াই স্ক্রিপ্ট কার্যকর করছে ...

# ./func_return_test.sh
writing directly to console
my_string:  [some default string]

আশা করি এটি মানুষকে সাহায্য করবে

-Andy


6
এটির ব্যবহারগুলি রয়েছে তবে সামগ্রিকভাবে আপনার কনসোলটিতে স্পষ্টত পুনঃনির্দেশ করা এড়ানো উচিত; আউটপুট ইতিমধ্যে পুনঃনির্দেশিত হতে পারে, বা স্ক্রিপ্টটি এমন প্রসঙ্গে চলতে পারে যেখানে কোনও টিটিই নেই। আপনি 3>&1স্ক্রিপ্টের শিরোনামে নকল করে, তারপরে হেরফের করে &1 &3এবং &4ফাংশনের মধ্যে অন্য কোনও স্থানধারক দ্বারা এটি পেতে পারেন। যদিও চতুর্দিকে কুরুচিপূর্ণ।
জেএমবি

8

আপনি একটি বৈশ্বিক চলক ব্যবহার করতে পারেন:

declare globalvar='some string'

string ()
{
  eval  "$1='some other string'"
} # ----------  end of function string  ----------

string globalvar

echo "'${globalvar}'"

এই দেয়

'some other string'

6

অতিরিক্ত ফাইল বর্ণনাকারী ম্যানিপুলেশন সহ অ্যান্ডির উত্তর সম্পর্কে আমার মন্তব্য চিত্রিত করতে /dev/tty:

#!/bin/bash

exec 3>&1

returnString() {
    exec 4>&1 >&3
    local s=$1
    s=${s:="some default string"}
    echo "writing to stdout"
    echo "writing to stderr" >&2
    exec >&4-
    echo "$s"
}

my_string=$(returnString "$*")
echo "my_string:  [$my_string]"

তবুও বাজে।


3

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


3

নিম্নলিখিত কোডটি বিবেচনা করে ভিকি রনেনের মাথা উঁচু করে সম্বোধন করা:

function use_global
{
    eval "$1='changed using a global var'"
}

function capture_output
{
    echo "always changed"
}

function test_inside_a_func
{
    local _myvar='local starting value'
    echo "3. $_myvar"

    use_global '_myvar'
    echo "4. $_myvar"

    _myvar=$( capture_output )
    echo "5. $_myvar"
}

function only_difference
{
    local _myvar='local starting value'
    echo "7. $_myvar"

    local use_global '_myvar'
    echo "8. $_myvar"

    local _myvar=$( capture_output )
    echo "9. $_myvar"
}

declare myvar='global starting value'
echo "0. $myvar"

use_global 'myvar'
echo "1. $myvar"

myvar=$( capture_output )
echo "2. $myvar"

test_inside_a_func
echo "6. $_myvar" # this was local inside the above function

only_difference



দিতে হবে

0. global starting value
1. changed using a global var
2. always changed
3. local starting value
4. changed using a global var
5. always changed
6. 
7. local starting value
8. local starting value
9. always changed

সম্ভবত স্বাভাবিক পরিস্থিতিটি test_inside_a_funcফাংশনে ব্যবহৃত সিনট্যাক্স ব্যবহার করা হয় , সুতরাং আপনি বেশিরভাগ ক্ষেত্রে উভয় পদ্ধতিই ব্যবহার করতে পারেন, যদিও আউটপুট ক্যাপচার করা সর্বদা যে কোনও পরিস্থিতিতে কাজ করা নিরাপদ পদ্ধতি, কোনও ফাংশন থেকে ফেরত মানকে নকল করে Vicky Ronnenসঠিকভাবে নির্দেশিত হিসাবে অন্যান্য ভাষায় সন্ধান করুন ।


2

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

UnGetChar=
function GetChar() {
    # assume failure
    GetChar=
    # if someone previously "ungot" a char
    if ! [ -z "$UnGetChar" ]; then
        GetChar="$UnGetChar"
        UnGetChar=
        return 0               # success
    # else, if not at EOF
    elif IFS= read -N1 GetChar ; then
        return 0           # success
    else
        return 1           # EOF
    fi
}

function UnGetChar(){
    UnGetChar="$1"
}

এবং, এই জাতীয় ফাংশন ব্যবহার করার একটি উদাহরণ:

function GetToken() {
    # assume failure
    GetToken=
    # if at end of file
    if ! GetChar; then
        return 1              # EOF
    # if start of comment
    elif [[ "$GetChar" == "#" ]]; then
        while [[ "$GetChar" != $'\n' ]]; do
            GetToken+="$GetChar"
            GetChar
        done
        UnGetChar "$GetChar"
    # if start of quoted string
    elif [ "$GetChar" == '"' ]; then
# ... et cetera

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

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

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


2

আপনি echoএকটি স্ট্রিং করতে পারেন , তবে পাইপ দিয়ে এটি ধরুন (| তবে ফাংশনটি অন্য কোনও কিছুর সাথে ।

আপনি এটি দিয়ে এটি করতে পারেন expr, যদিও শেলচেক এই ব্যবহারটিকে অবহিত হিসাবে প্রতিবেদন করেছে।


সমস্যা হ'ল পাইপের ডানদিকে জিনিসটি একটি সাবশেল। সুতরাং myfunc | read OUTPUT ; echo $OUTPUTকিছুই ফলন। myfunc | ( read OUTPUT; echo $OUTPUT )প্রত্যাশিত মান পায় এবং ডানদিকের দিকে কী ঘটছে তা স্পষ্ট করে। তবে অবশ্যই আপনার প্রয়োজন যেখানে OUTPUT উপলভ্য নয় ...
এড র্যান্ডাল

2

তারা যে কোনও 'নামক আউটপুট ভেরিয়েবল' স্কিমের মূল সমস্যা যেখানে কলারটি ভেরিয়েবল নামে (ব্যবহার করা evalবা না হওয়া declare -n) অজ্ঞাতপরিচয় অ্যালিয়াসিং অর্থাৎ নাম সংঘর্ষে পাস করতে পারে : একটি এনক্যাপসুলেশন দৃষ্টিকোণ থেকে এটি যোগ বা নাম পরিবর্তন করতে সক্ষম না হওয়া ভয়াবহ ful সমস্ত পরীক্ষা না করে কোনও ফাংশনে লোকাল ভেরিয়েবল প্রথম ফাংশনের কলারের তারা আউটপুট প্যারামিটার হিসাবে যে একই নামের পাস অনুপস্থিত করছি না করা। (বা অন্য দিকে, আমি যে ফাংশনটি ব্যবহার করতে চাইছি তা পড়তে চাই না যে আমি যে আউটপুট প্যারামিটারটি ব্যবহার করতে চাইছি তা সেই ফাংশনের স্থানীয় নয় make)

এর একমাত্র উপায় হ'ল একক উত্সর্গীকৃত আউটপুট ভেরিয়েবলের মতো ব্যবহার use REPLY (যেমন Evi1M4chine দ্বারা প্রস্তাবিত ) বা রন বার্কের প্রস্তাবিত কনভেনশন ব্যবহার করা ।

তবে, অভ্যন্তরীণভাবে ফাংশনগুলি একটি নির্দিষ্ট আউটপুট ভেরিয়েবল ব্যবহার করা সম্ভব এবং তারপরে উপরের অংশে কিছুটা চিনি যুক্ত করা সম্ভব এই সত্যটি কলারের কাছ থেকে আড়াল , যেমন আমি callনিম্নলিখিত উদাহরণটিতে ফাংশনটি দিয়ে করেছি । এটি ধারণার প্রমাণ হিসাবে বিবেচনা করুন, তবে মূল বিষয়গুলি হ'ল

  • ফাংশনটি সর্বদা ফেরতের মান নির্ধারণ করে REPLYএবং যথারীতি একটি প্রস্থান কোডও ফেরত দিতে পারে
  • কলারের দৃষ্টিকোণ থেকে, রিটার্ন মান সহ যেকোন ভেরিয়েবল (স্থানীয় বা গ্লোবাল) এর জন্য বরাদ্দ করা যেতে পারে REPLY (দেখুন দেখুনwrapper উদাহরণ । ফাংশনের প্রস্থান কোড মাধ্যমে গৃহীত হয়, তাই তাদের একটি যেমন ব্যবহার ifবা whileবা অনুরূপ নির্মান কাজ আশানুরূপ।
  • সিনট্যাক্টিক্যালি ফাংশন কলটি এখনও একটি সাধারণ বিবৃতি statement

এই কাজটির কারণ হ'ল callফাংশনে নিজেই কোনও স্থানীয় নেই এবং REPLYনাম সংঘর্ষের কোনও সম্ভাবনা এড়ানো ছাড়া অন্য কোনও ভেরিয়েবল ব্যবহার করে না । কলার-সংজ্ঞায়িত আউটপুট ভেরিয়েবলের নাম নির্ধারণ করা হয়েছে এমন স্থানে, আমরা কলিংয়ের ক্ষেত্রের পরিবর্তে কলিংয়ের ক্ষেত্রের (প্রযুক্তিগতভাবে callফাংশনের অভিন্ন ক্ষেত্রে ) কার্যকরভাবে থাকি

#!/bin/bash
function call() { # var=func [args ...]
  REPLY=; "${1#*=}" "${@:2}"; eval "${1%%=*}=\$REPLY; return $?"
}

function greet() {
  case "$1" in
    us) REPLY="hello";;
    nz) REPLY="kia ora";;
    *) return 123;;
  esac
}

function wrapper() {
  call REPLY=greet "$@"
}

function main() {
  local a b c d
  call a=greet us
  echo "a='$a' ($?)"
  call b=greet nz
  echo "b='$b' ($?)"
  call c=greet de
  echo "c='$c' ($?)"
  call d=wrapper us
  echo "d='$d' ($?)"
}
main

আউটপুট:

a='hello' (0)
b='kia ora' (0)
c='' (123)
d='hello' (0)

1

উভয় স্কেলার এবং অ্যারের মান অবজেক্টগুলিকে ফিরিয়ে আনতে বাশ প্যাটার্ন :

সংজ্ঞা

url_parse() { # parse 'url' into: 'url_host', 'url_port', ...
   local "$@" # inject caller 'url' argument in local scope
   local url_host="..." url_path="..." # calculate 'url_*' components
   declare -p ${!url_*} # return only 'url_*' object fields to the caller
}

আবাহন

main() { # invoke url parser and inject 'url_*' results in local scope
   eval "$(url_parse url=http://host/path)" # parse 'url'
   echo "host=$url_host path=$url_path" # use 'url_*' components
}

0

আমার প্রোগ্রামগুলিতে, কনভেনশন অনুসারে, এটি পূর্ব-বিদ্যমান $REPLYভেরিয়েবলের জন্য যা readএটি সঠিক উদ্দেশ্যে ব্যবহৃত হয়।

function getSomeString {
  REPLY="tadaa"
}

getSomeString
echo $REPLY

এই echoএস

tadaa

তবে দ্বন্দ্ব এড়ানোর জন্য, অন্য কোনও বৈশ্বিক পরিবর্তনশীল তা করবে।

declare result

function getSomeString {
  result="tadaa"
}

getSomeString
echo $result

যদি এটি পর্যাপ্ত না হয় তবে আমি মার্কারিয়ান 451 এর সমাধানের প্রস্তাব দিই ।


-2
agt@agtsoft:~/temp$ cat ./fc 
#!/bin/sh

fcall='function fcall { local res p=$1; shift; fname $*; eval "$p=$res"; }; fcall'

function f1 {
    res=$[($1+$2)*2];
}

function f2 {
    local a;
    eval ${fcall//fname/f1} a 2 3;
    echo f2:$a;
}

a=3;
f2;
echo after:a=$a, res=$res

agt@agtsoft:~/temp$ ./fc
f2:10
after:a=3, res=
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.