क्या मैं बैश में "निर्यात" कर सकता हूं?


80
source some_file

some_file:

doit ()
{
  echo doit $1
}
export TEST=true

यदि मैं some_file फ़ंक्शन " doit " को स्रोत करता हूं और कमांड लाइन पर वेरिएबल टेस्ट उपलब्ध है। लेकिन इस स्क्रिप्ट को चलाना:

script.sh:

#/bin/sh
echo $TEST
doit test2

TEST का मान लौटाएगा, लेकिन अज्ञात फ़ंक्शन "doit" के बारे में एक त्रुटि उत्पन्न करेगा।

क्या मैं फ़ंक्शन को "निर्यात" भी कर सकता हूं, या क्या मुझे script.sh में कुछ फ़ंक्शन का उपयोग करने के लिए some_file स्रोत करना है?


2
नीचे दिए गए जवाबों को संक्षेप में प्रस्तुत करना (enzotib सही है, मान लें कि आप बैश का उपयोग कर सकते हैं, जैसा कि प्रश्न इंगित करता है): #!/bin/shकरने के लिए बदल #!/bin/bashऔर बस के बाद doit() {...}export -f doit
michael

बस रिकॉर्ड के लिए: यह समाधान आमतौर पर तब काम करेगा जब आप #!/bin/shभी उपयोग करते हैं, लेकिन इसका उपयोग करने के लिए अच्छा अभ्यास है #!/bin/bashताकि आप समस्याओं से बचें जब डिफ़ॉल्ट शेल बैश न हो।
नागल

जवाबों:


119

बाश में आप फ़ंक्शन परिभाषाओं को उप-शेल के साथ निर्यात कर सकते हैं

export -f function_name

उदाहरण के लिए आप इस सरल उदाहरण की कोशिश कर सकते हैं:

./script1:

    #!/bin/bash

    myfun() {
        echo "Hello!"
    }

    export -f myfun
    ./script2

./script2:

    #!/bin/bash

    myfun

यदि आप कॉल ./script1करते हैं तो आप आउटपुट देखेंगे हैलो!


16

"निर्यात" एक फ़ंक्शन का उपयोग करके export -fफ़ंक्शन बॉडी के साथ एक पर्यावरण चर बनाता है। इस उदाहरण पर विचार करें:

$ fn(){ echo \'\"\ \ \$; }
$ export -f fn
$ sh -c printenv\ fn
() {  echo \'\"\ \ \$
}

इसका मतलब है कि केवल शेल (बस बैश?) फ़ंक्शन को स्वीकार करने में सक्षम होगा। आप फ़ंक्शन को स्वयं भी सेट कर सकते हैं क्योंकि बैश केवल एन्वार () {को फ़ंक्शन के रूप में शुरू करने पर विचार करता है:

$ fn2='() { echo Hi;}' sh -c fn2
Hi
$ fn3='() {' sh -c :
sh: fn3: line 1: syntax error: unexpected end of file
sh: error importing function definition for `fn3'

यदि आपको एसएसएच पर इस चर को "निर्यात" करने की आवश्यकता है, तो आपको वास्तव में एक स्ट्रिंग के रूप में फ़ंक्शन की आवश्यकता है। यह प्रिंट विकल्प (साथ किया जा सकता -pकार्य (के लिए) -fके) declareमें निर्मित:

$ declare -pf fn
fn () 
{ 
    echo \'\"\ \ \$
}

यह बहुत उपयोगी है यदि आपके पास अधिक जटिल कोड है जिसे एसएसएच पर निष्पादित करने की आवश्यकता है। निम्नलिखित काल्पनिक लिपि पर विचार करें:

#!/bin/bash
remote_main() {
   local dest="$HOME/destination"

   tar xzv -C "$dest"
   chgrp -R www-data "$dest"
   # Ensure that newly written files have the 'www-data' group too
   find "$dest" -type d -exec chmod g+s {} \;
}
tar cz files/ | ssh user@host "$(declare -pf remote_main); remote_main"

fn2='() { echo Hi;}' sh -c fn2मेरे लिए काम नहीं किया। shबैश v5.0.7 होने के साथ मेहराब पर sh: fn2: command not found। Ubuntu पर shडैश v0.2.3 होने के साथ मुझे मिला sh: 1: fn2: not foundshआपने किस शेल का उपयोग किया?
सोकोवि जूल

मुझे लगता है कि आपका जवाब गलत है। f(){ echo a;}; export -f f; echo "$f"; sh -c 'printenv f; echo "$f"'मेरे लिए कुछ भी प्रिंट नहीं करता है, इसलिए स्पष्ट रूप fसे सादे स्ट्रिंग के रूप में निर्यात नहीं किया जाता है। मैंने ऊपर वर्णित दोनों संयोजनों के साथ परीक्षण किया।
सोकोवि जूल

और भले ही फ़ंक्शन को स्ट्रिंग के रूप में निर्यात किया गया था, फिर भी shउस स्ट्रिंग को फ़ंक्शन के रूप में क्यों निष्पादित किया जाना चाहिए ? आपके उदाहरण fn2='() { echo Hi;}' sh -c fn2में fn2दी गई कमांड sh का शाब्दिक अर्थ स्ट्रिंग है "fn2"shअपने PATH में इस तरह के कमांड को खोजना चाहिए, लेकिन यह नहीं देखना चाहिए कि क्या कोई वैरिएबल है $fn2, उस वैरिएबल का विस्तार करें, और फ़ंक्शन के रूप में इसके मान को निष्पादित करें - मेरे लिए एक प्रमुख सुरक्षा समस्या जैसा लगता है। संपादित करें: मुझे लगता है कि यह है! क्या आपके दिखाए गए व्यवहार को सुरक्षा बग शेलशॉक / बाशडोर के रूप में जाना जाता है ?
सोकोवई

बैश 5.0.7 (आर्क लिनक्स) के साथ, ऐसा प्रतीत होता है कि एक उपसर्ग उपसर्ग है। शेलशॉक के जवाब में ऐसा किया गया था। उदाहरण: fn(){ echo foo; }; export -f fn; env | grep fooआउटपुटBASH_FUNC_fn%%=() { echo foo
लेकेनस्टीन

7

@ Lekensteyn के जवाब पर बिल्डिंग ...

यदि आप इसका उपयोग करते हैं तो declare -pfयह वर्तमान शेल में पहले से परिभाषित सभी कार्यों को STDOUT में आउटपुट करेगा।

उस बिंदु पर आप जहाँ चाहें, जहाँ चाहें और जहाँ चाहें वहाँ पहले से परिभाषित कार्यों को लागू कर सकते हैं।

निम्नलिखित उत्तर उन्हें एक चर में बदल देगा। फिर हम उस चर और उस फ़ंक्शन के आह्वान को प्रतिध्वनित करते हैं, जिसे हम नए शेल में चलाना चाहते हैं जो एक नए उपयोगकर्ता के रूप में शुरू किया गया है। हम उपयोग करके ऐसा कर sudoके साथ -u(उर्फ। user) स्विच और बस बैश होने (जिसमें इनपुट के रूप में चलाने के लिए पाइप STDOUT प्राप्त होगा)।

जैसा कि हम जानते हैं कि हम एक बैश शेल से एक बैश शेल में जा रहे हैं, हम जानते हैं कि बैश पिछले गोले परिभाषित कार्यों की सही व्याख्या करेगा। वाक्यविन्यास तब तक ठीक होना चाहिए जब तक हम एक ही संस्करण के एक बैश शेल के बीच एक ही संस्करण के नए बैश शेल के बीच आगे बढ़ रहे हैं।

YMMV यदि आप अलग-अलग गोले के बीच या सिस्टम के बीच चल रहे हैं जिसमें बैश के अलग-अलग संस्करण हो सकते हैं।

#!/bin/bash
foo() {
  echo "hello from `whoami`"
}

FUNCTIONS=`declare -pf`; echo "$FUNCTIONS ; foo" | sudo -u otheruser bash
# $./test.sh
# hello from otheruser

5

आप फ़ंक्शन का निर्यात नहीं कर सकते हैं, जिस तरह से आप वर्णन नहीं कर रहे हैं। शेल केवल ~/.bashrcएक इंटरेक्टिव शेल के शुरू होने पर फ़ाइल को लोड करेगा ( बैश मैनपेज में "इन्वोकेशन" के लिए खोज )।

आप "लाइब्रेरी" बना सकते हैं जो प्रोग्राम शुरू करते समय लोड किया जाता है:

source "$HOME/lib/somefile"

और अपने गैर-इंटरैक्टिव कार्यों और सेटिंग्स को वहां रखें।


इसलिए मुझे या तो "लॉगिन" पैरामीटर (फ़ाइल को पार्स करने के लिए ~ / .profile) या उस फ़ाइल के स्रोत से सबस्क्रिप्शन शुरू करना होगा।
निल्स

गैर-संवादात्मक गोले पर थोड़ा अधिक बारीकी से देखते हुए, आप पहले से ही आपके पास BASH_ENVपर्यावरण चर सेट कर सकते some_fileहैं, और इसे कहा जाएगा। यह पता लगाना काफी आसान होगा कि:echo echo foobar > /tmp/foobar; BASH_ENV=/tmp/foobar $SHELL -c :
Arcege

2

eval "$(declare -F | sed -e 's/-f /-fx /')"सभी कार्यों का निर्यात करेगा ।

मैं स्क्रिप्ट में एक इंटरैक्टिव शेल शुरू करने से पहले बहुत कुछ करता हूं ताकि मुझे अपने कार्यों और चर का उपयोग करते हुए स्क्रिप्ट संदर्भ में डीबग करने और काम करने में सक्षम हो सके।

उदाहरण:

eval "$(declare -F | sed -e 's/-f /-fx /')"
export SOME IMPORTANT VARIABLES AND PASSWORDS
bash -i

1

उपप्रकारों को कार्य निर्यात नहीं किया जाता है। यही कारण है कि .kshrc या .bashrc नाम की फाइलें हैं: उन कार्यों को परिभाषित करने के लिए जो श्योलड उप-नंबरों में भी उपलब्ध हैं।

यदि कोई स्क्रिप्ट चल रही है, तो *। आपको कोड को स्पष्ट रूप से कोड करना होगा, जैसे कि . ~/.kshrc


इसलिए ~ रूट / .bashrc मेरे मामले में एक विकल्प हो सकता है, क्योंकि स्क्रिप्ट रूट के रूप में चलाई जाती हैं। उस संकेत के लिए धन्यवाद।
Nils

अगर। * श्रक फ़ाइलों का उपयोग करते हैं, तो सुनिश्चित करें कि वे इंटरैक्टिव व्यवहार को मजबूर नहीं करते हैं (जैसे बेवकूफ उपनाम rm=rm -i)
ktf

0

ठीक है, मैं लिनक्स के लिए नया हूं, लेकिन आप यह कोशिश कर सकते हैं। कुछ फ़ाइल में, आप इसे 'tmp / general' कहते हैं, जिसे आप अपना फ़ंक्शन बनाते हैं:

func1(){
   echo "func from general"
}

अपने शेल स्क्रिप्ट ऐड में:

. /tmp/general

और भाग खड़ा हुआ:

func1

आप स्क्रीन पर मिल जाएगा: func from general


0
declare -x -f NAME

और जानकारी

फ़ंक्शन और प्रदर्शन नाम और परिभाषाओं को प्रतिबंधित करें
-x NAME निर्यात करने के लिए
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.