एक बैश फ़ंक्शन में वापसी मान


303

मैं बैश स्क्रिप्ट के साथ काम कर रहा हूं और मैं रिटर्न वैल्यू प्रिंट करने के लिए एक फंक्शन निष्पादित करना चाहता हूं:

function fun1(){
  return 34
}
function fun2(){
  local res=$(fun1)
  echo $res
}

जब मैं निष्पादित fun2करता हूं , तो यह "34" प्रिंट नहीं करता है। यह एक केस क्यों है?


8
returnआपके मामले में अनिवार्य रूप से वही है exit codeजो कि सीमा से है 0 - 255echo@ सेप्टि द्वारा सुझाए अनुसार उपयोग करें । बाहर निकलें कोड के साथ कब्जा किया जा सकता है $?
देवनुल

1
इस मामले में यह पहले से ही मज़ेदार 1 में इको का उपयोग करने के लिए अधिक लचीला है। यह यूनिक्स-प्रोग्रामिंग का विचार है: इको मानक परिणामों को परिणाम भेजता है जो फिर res = $ (fun1) के साथ अन्य कार्यों द्वारा पुन: उपयोग किया जा सकता है - या सीधे अन्य कार्यों के लिए पाइप किया जा सकता है:function a() { echo 34; } function b() { while read data; do echo $data ; done ;} a | b
Arne Babenhauserheide

ऐसा करने का उचित तरीका यह है कि किसी समारोह में शीर्ष स्तर के सामान को रखा जाए और बैश के गतिशील स्कूपिंग नियम के साथ स्थानीय का उपयोग किया जाए। मैं प्रदर्शित करने के लिए एक उत्तर दूंगा, यह एक प्रसिद्ध विशेषता नहीं है, लेकिन एक पूरी तरह से समर्थित है।
ओलिवर


जवाबों:


372

हालांकि बैश का एक returnबयान है, केवल एक चीज जिसे आप निर्दिष्ट कर सकते हैं वह फ़ंक्शन की अपनी exitस्थिति (बीच का मान 0और 255, जिसका अर्थ है "सफलता")। तो returnवह नहीं है जो आप चाहते हैं।

आप अपने returnकथन को एक echoकथन में बदलना चाहते हैं - इस तरह आपके फ़ंक्शन आउटपुट को $()ब्रेसिज़ का उपयोग करके कैप्चर किया जा सकता है , जो कि वास्तव में आप चाहते हैं।

यहाँ एक उदाहरण है:

function fun1(){
  echo 34
}

function fun2(){
  local res=$(fun1)
  echo $res
}

वापसी मान प्राप्त करने का दूसरा तरीका (यदि आप पूर्णांक 0-255 वापस करना चाहते हैं) है $?

function fun1(){
  return 34
}

function fun2(){
  fun1
  local res=$?
  echo $res
}

इसके अलावा, ध्यान दें कि आप बूलियन लॉजिक का उपयोग करने के लिए रिटर्न वैल्यू का उपयोग कर सकते हैं, जैसे कि वैल्यू रिटर्न होने पर fun1 || fun2ही चलेगा । डिफ़ॉल्ट रिटर्न मान फ़ंक्शन के भीतर निष्पादित अंतिम विवरण का निकास मूल्य है।fun2fun10


2
आपको निष्पादित करने की आवश्यकता है fun1और फिर रिटर्न वैल्यू को स्टोर किया जाता है $?। हालांकि मैं ऐसा करने की सिफारिश नहीं
करूंगा

9
उपयोग क्यों नहीं $??
पिथिकोस

147
नहीं, मुझे लानत मूल्य की आवश्यकता है । गूंज के साथ नरक करने के लिए।
टॉम ज़ातो -

7
इस वातावरण में @Blauhirn, इस ||निर्माण के साथ , 0 से बाहर निकलने का कोड सफलता माना जाता है और इसलिए "सही" है। गैर-शून्य त्रुटि है और इसलिए गलत है। fun1 || fun2"अगर fun1 रिटर्न सफलता या fun2 रिटर्न सफलता" के लिए आशुलिपि के बारे में सोचें, तो वास्तविक रिटर्न मूल्यों पर एक ऑपरेटर के बजाय।
दविद

6
कष्टप्रद यह है कि एक फ़ंक्शन जिसे डेटा प्रदान करना चाहिए वह स्टडआउट के लिए अन्य सामान को भी प्रतिध्वनित नहीं कर सकता है, क्योंकि $ () का उपयोग करने वाले कॉलर को वह भी प्राप्त होगा और भ्रमित हो जाएगा या आउटपुट को पार्स करना होगा। वैश्विक चर महान नहीं हैं क्योंकि यह केवल समय की बात है इससे पहले कि आप दो स्थानों पर एक ही वैश्विक संस्करण का उपयोग करें जो कि नेस्टेड हो और डेटा खो जाए। डेटा बनाम प्रिंटिंग डेटा वापस भेजने के लिए अलग-अलग चैनल होने चाहिए।
ओलिवर

68

$(...)भीतर निहित आदेश द्वारा stdout को भेजे गए पाठ को कैप्चर करता है। returnstdout में आउटपुट नहीं करता है। $?अंतिम आदेश का परिणाम कोड समाहित करता है।

fun1 (){
  return 34
}

fun2 (){
  fun1
  local res=$?
  echo $res
}

5
हाँ जो returnसेटिंग के लिए उपयोग किया $?जाता है exit status। उपरोक्त उदाहरण में, fun1के exit statusहोगा 34। यह $(...)भी ध्यान दें कि निर्दिष्ट कमांड से stdout के अलावा stderr पर भी कब्जा है।
swoop81

58

बैश में कार्य अन्य भाषा की तरह कार्य नहीं हैं; वे वास्तव में आज्ञा हैं। इसलिए फ़ंक्शंस का उपयोग किया जाता है जैसे कि वे आपके रास्ते से प्राप्त बायनेरी या स्क्रिप्ट थे। आपके कार्यक्रम तर्क के दृष्टिकोण से वास्तव में कोई अंतर नहीं होना चाहिए।

शेल कमांड पाइप (उर्फ स्ट्रीम) से जुड़े हैं, और मौलिक या उपयोगकर्ता-परिभाषित डेटा प्रकार नहीं हैं, जैसा कि "वास्तविक" प्रोग्रामिंग भाषाओं में है। कमांड के लिए रिटर्न वैल्यू जैसी कोई चीज नहीं है, हो सकता है कि ज्यादातर इसलिए कि इसे घोषित करने का कोई वास्तविक तरीका नहीं है। यह मैन-पेज, या पर हो सकता है--help कमांड आउटपुट , लेकिन दोनों केवल मानव-पठनीय हैं और इसलिए हवा में लिखे गए हैं।

जब कोई कमांड इनपुट प्राप्त करना चाहता है तो वह इसे अपने इनपुट स्ट्रीम, या तर्क सूची से पढ़ता है। दोनों ही मामलों में टेक्स्ट स्ट्रिंग्स को पार्स किया जाना है।

जब कोई कमांड कुछ वापस करना चाहता है echoतो उसे अपनी आउटपुट स्ट्रीम पर ले जाना पड़ता है। एक और अक्सर प्रचलित तरीका समर्पित, वैश्विक चर में वापसी मूल्य को संग्रहीत करना है। आउटपुट स्ट्रीम में लिखना स्पष्ट और अधिक लचीला है, क्योंकि यह बाइनरी डेटा भी ले सकता है। उदाहरण के लिए, आप एक BLOB आसानी से लौटा सकते हैं:

encrypt() {
    gpg -c -o- $1 # encrypt data in filename to stdout (asks for a passphrase)
}

encrypt public.dat > private.dat # write function result to file

जैसा कि दूसरों ने इस धागे में लिखा है, $()आउटपुट को पकड़ने के लिए कॉलर कमांड प्रतिस्थापन का उपयोग भी कर सकता है ।

समानांतर रूप से, फ़ंक्शन gpg(GnuPG) का निकास कोड "वापस" कर देगा । निकास कोड को एक बोनस के रूप में समझें जो अन्य भाषाओं में नहीं है, या, आपके स्वभाव पर निर्भर करता है, शेल फ़ंक्शन के "श्मुतज़ेफ़ेक्ट" के रूप में। यह स्थिति, कन्वेंशन द्वारा, सफलता पर 0 या किसी अन्य चीज़ के लिए 1-255 सीमा में पूर्णांक है। यह स्पष्ट करने के लिए: return(जैसेexit ) केवल 0-255 से मान ले सकते हैं, और 0 के अलावा अन्य मान आवश्यक रूप से त्रुटियां नहीं हैं, जैसा कि अक्सर माना जाता है।

जब आप returnस्टेटस के साथ एक स्पष्ट मूल्य प्रदान नहीं करते हैं तो आखिरी कमांड से बैश स्टेटमेंट / फंक्शन / कमांड और इसके बाद के संस्करण में लिया जाता है। इसलिए हमेशा एक स्थिति है, और returnइसे प्रदान करने का एक आसान तरीका है।


3
फ़ंक्शंस बनाम कमांड को समझाने के लिए +1 और यह कॉल करने वाले को डेटा भेजने की धारणा को कैसे प्रभावित करता है
ओलिवर

3
+1 समझाने के लिए कि शेल प्रोग्रामिंग पाइप के माध्यम से कमांड कनेक्ट करने के बारे में है। अन्य प्रोग्रामिंग लैंग्वेज रिटर्न टाइप्स के जरिए फंक्शन्स कंपोज करती हैं। बैश पाठ की धाराओं के माध्यम से कमांड बनाता है।
जहाराली

29

returnबयान समारोह के निकास कोड, ज्यादा एक ही रूप में सेट exitपूरी स्क्रिप्ट के लिए क्या करेंगे।

अंतिम कमांड के लिए निकास कोड हमेशा $?चर में उपलब्ध होता है ।

function fun1(){
  return 34
}

function fun2(){
  local res=$(fun1)
  echo $? # <-- Always echos 0 since the 'local' command passes.

  res=$(fun1)
  echo $?  #<-- Outputs 34
}

19

अन्य उत्तरों के साथ समस्या यह है कि वे या तो एक वैश्विक का उपयोग करते हैं, जिसे एक कॉल श्रृंखला में कई फ़ंक्शन होने पर अधिलेखित किया जा सकता है, या echoजिसका अर्थ है कि आपका फ़ंक्शन नैदानिक ​​जानकारी को आउटपुट नहीं कर सकता है (आप अपने फ़ंक्शन को यह भूल जाएंगे और "परिणाम", अर्थात वापस आ जाएंगे। मूल्य, आपके कॉलर अपेक्षा से अधिक जानकारी समाहित करेगा, अजीब बग के लिए अग्रणी), याeval जो बहुत भारी और हैक्‍सी है।

ऐसा करने का उचित तरीका एक फ़ंक्शन में शीर्ष स्तर का सामान डालना और localबैश के गतिशील स्कूपिंग नियम के साथ उपयोग करना है । उदाहरण:

func1() 
{
    ret_val=hi
}

func2()
{
    ret_val=bye
}

func3()
{
    local ret_val=nothing
    echo $ret_val
    func1
    echo $ret_val
    func2
    echo $ret_val
}

func3

यह आउटपुट

nothing
hi
bye

डायनेमिक स्कूपिंग का मतलब है कि ret_valकॉलर के आधार पर एक अलग वस्तु की ओर इशारा करना! यह लेक्सिकल स्कूपिंग से अलग है, जो कि अधिकांश प्रोग्रामिंग भाषाएं उपयोग करती हैं। यह वास्तव में एक प्रलेखित विशेषता है , बस याद करना आसान है, और बहुत अच्छी तरह से समझाया नहीं गया है, यहां इसके लिए दस्तावेज है (जोर मेरा है):

फ़ंक्शन के लिए चर स्थानीय बिल्डिन के साथ स्थानीय घोषित किए जा सकते हैं। ये चर केवल फ़ंक्शन और आदेशों के लिए दृश्यमान होते हैं ।

C / C ++ / Python / Java / C # / javascript बैकग्राउंड वाले किसी व्यक्ति के लिए, यह संभवतः सबसे बड़ी बाधा है: bash में फ़ंक्शन फ़ंक्शंस नहीं होते हैं, वे कमांड होते हैं, और इस तरह व्यवहार करते हैं: वे stdout/ के लिए आउटपुट कर सकते हैंstderr कर सकते हैं, वे इसमें पाइप कर सकते हैं / बाहर, वे एक निकास कोड वापस कर सकते हैं। मूल रूप से एक स्क्रिप्ट में एक कमांड को परिभाषित करने और एक निष्पादन योग्य बनाने के बीच कोई अंतर नहीं है जिसे कमांड लाइन से बुलाया जा सकता है।

इसलिए इस तरह से अपनी स्क्रिप्ट लिखने के बजाय:

top-level code 
bunch of functions
more top-level code

इसे इस तरह लिखें:

# define your main, containing all top-level code
main() 
bunch of functions
# call main
main  

जहां के रूप में main()घोषित ret_valकिया गया है localऔर अन्य सभी कार्यों के माध्यम से मान लौटाते हैं ret_val

निम्नलिखित यूनिक्स और लिनक्स प्रश्न भी देखें: शेल फ़ंक्शंस में स्थानीय चर के दायरे

एक और, शायद स्थिति के आधार पर बेहतर समाधान भी, हां.टेक द्वारा पोस्ट किया गया है जो उपयोग करता है local -n


16

इसे प्राप्त करने का दूसरा तरीका नाम संदर्भ है (बश 4.3+ की आवश्यकता है)।

function example {
  local -n VAR=$1
  VAR=foo
}

example RESULT
echo $RESULT

2
कोई भी सोचता है कि क्या -n <name>=<reference>करता है: नए बनाए गए चर को किसी दूसरे द्वारा इंगित किया गया संदर्भ बनाता है <reference>। आगे के कार्य <name>संदर्भित चर पर किए जाते हैं।
वलेरियो

7

मैं निम्नलिखित करना पसंद करता हूं यदि स्क्रिप्ट में जहां फ़ंक्शन परिभाषित है, वहां चल रहा है:

POINTER= # used for function return values

my_function() {
    # do stuff
    POINTER="my_function_return"
}

my_other_function() {
    # do stuff
    POINTER="my_other_function_return"
}

my_function
RESULT="$POINTER"

my_other_function
RESULT="$POINTER"

मुझे यह पसंद है, क्योंकि मैं चाहूं तो मैं अपने कार्यों में प्रतिध्वनित बयान शामिल कर सकता हूं

my_function() {
    echo "-> my_function()"
    # do stuff
    POINTER="my_function_return"
    echo "<- my_function. $POINTER"
}

4

दूसरों के उत्कृष्ट पदों पर एक ऐड-ऑन के रूप में, इन तकनीकों को संक्षेप में प्रस्तुत करने वाला एक लेख है:

  • एक वैश्विक चर सेट करें
  • एक वैश्विक वैरिएबल सेट करें, जिसका नाम आप फंक्शन में गए हैं
  • रिटर्न कोड सेट करें (और इसे $ के साथ चुनें?)
  • कुछ डेटा 'गूंज' (और इसे MYVAR = $ (myfunction) के साथ चुनें)

बैश फंक्शंस से रिटर्निंग वैल्यू


यह सबसे अच्छा जवाब है, क्योंकि लेख सभी विकल्पों पर सफाई से चर्चा करता है।
mzimmermann

-2

एकाधिक रिटर्न मानों के लिए सरणियों का उपयोग करके विंडोज पर बैश बैश करें

फैशन कोड:

#!/bin/bash

##A 6-element array used for returning
##values from functions:
declare -a RET_ARR
RET_ARR[0]="A"
RET_ARR[1]="B"
RET_ARR[2]="C"
RET_ARR[3]="D"
RET_ARR[4]="E"
RET_ARR[5]="F"


function FN_MULTIPLE_RETURN_VALUES(){

   ##give the positional arguments/inputs
   ##$1 and $2 some sensible names:
   local out_dex_1="$1" ##output index
   local out_dex_2="$2" ##output index

   ##Echo for debugging:
   echo "running: FN_MULTIPLE_RETURN_VALUES"

   ##Here: Calculate output values:
   local op_var_1="Hello"
   local op_var_2="World"

   ##set the return values:
   RET_ARR[ $out_dex_1 ]=$op_var_1
   RET_ARR[ $out_dex_2 ]=$op_var_2
}


echo "FN_MULTIPLE_RETURN_VALUES EXAMPLES:"
echo "-------------------------------------------"
fn="FN_MULTIPLE_RETURN_VALUES"
out_dex_a=0
out_dex_b=1
eval $fn $out_dex_a $out_dex_b  ##<--Call function
a=${RET_ARR[0]} && echo "RET_ARR[0]: $a "
b=${RET_ARR[1]} && echo "RET_ARR[1]: $b "
echo
##----------------------------------------------##
c="2"
d="3"
FN_MULTIPLE_RETURN_VALUES $c $d ##<--Call function
c_res=${RET_ARR[2]} && echo "RET_ARR[2]: $c_res "
d_res=${RET_ARR[3]} && echo "RET_ARR[3]: $d_res "
echo
##----------------------------------------------##
FN_MULTIPLE_RETURN_VALUES 4 5  ##<---Call function
e=${RET_ARR[4]} && echo "RET_ARR[4]: $e "
f=${RET_ARR[5]} && echo "RET_ARR[5]: $f "
echo
##----------------------------------------------##


read -p "Press Enter To Exit:"

अपेक्षित उत्पादन:

FN_MULTIPLE_RETURN_VALUES EXAMPLES:
-------------------------------------------
running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[0]: Hello
RET_ARR[1]: World

running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[2]: Hello
RET_ARR[3]: World

running: FN_MULTIPLE_RETURN_VALUES
RET_ARR[4]: Hello
RET_ARR[5]: World

Press Enter To Exit:
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.