मैं पहले से ही कई तरीकों पर काम करने के तरीके के बारे में पहले से ही चर्चा कर चुका हूँ, इसलिए मैं इसे दोबारा नहीं करूँगा। व्यक्तिगत रूप से, विषय पर मेरे अपने पसंदीदा यहां और यहां हैं ।
यदि आप पढ़ने में रुचि नहीं रखते हैं, लेकिन फिर भी उत्सुक हैं तो बस यह समझें कि फ़ंक्शन के इनपुट से जुड़े यहाँ-डॉक्स का मूल्यांकन फ़ंक्शन के चलने से पहले शेल विस्तार के लिए किया जाता है , और वे राज्य में नए सिरे से उत्पन्न होते हैं जब वे फ़ंक्शन को परिभाषित किया गया था हर बार फ़ंक्शन को कहा जाता है।
घोषित
आपको बस एक फ़ंक्शन की आवश्यकता है जो अन्य कार्यों की घोषणा करता है।
_fn_init() { . /dev/fd/4 ; } 4<<INIT
${1}() { $(shift ; printf %s\\n "$@")
} 4<<-REQ 5<<-\\RESET
: \${_if_unset?shell will ERR and print this to stderr}
: \${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init $(printf "'%s' " "$@")
RESET
INIT
चलाओ
यहाँ मैं आह्वान करता _fn_init
हूँ कि मुझे एक समारोह घोषित किया जाए fn
।
set -vx
_fn_init fn \
'echo "this would be command 1"' \
'echo "$common_param"'
#OUTPUT#
+ _fn_init fn 'echo "this would be command 1"' 'echo "$common_param"'
shift ; printf %s\\n "$@"
++ shift
++ printf '%s\n' 'echo "this would be command 1"' 'echo "$common_param"'
printf "'%s' " "$@"
++ printf ''\''%s'\'' ' fn 'echo "this would be command 1"' 'echo "$common_param"'
#ALL OF THE ABOVE OCCURS BEFORE _fn_init RUNS#
#FIRST AND ONLY COMMAND ACTUALLY IN FUNCTION BODY BELOW#
+ . /dev/fd/4
#fn AFTER _fn_init .dot SOURCES IT#
fn() { echo "this would be command 1"
echo "$common_param"
} 4<<-REQ 5<<-\RESET
: ${_if_unset?shell will ERR and print this to stderr}
: ${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init 'fn' \
'echo "this would be command 1"' \
'echo "$common_param"'
RESET
आवश्यक
अगर मैं इस फ़ंक्शन को कॉल करना चाहता हूं तो यह तब तक मर जाएगा जब तक कि पर्यावरण चर _if_unset
सेट नहीं हो जाता।
fn
#OUTPUT#
+ fn
/dev/fd/4: line 1: _if_unset: shell will ERR and print this to stderr
कृपया खोल के निशान के क्रम पर ध्यान दें - न केवल fn
असफल होने पर बुलाया जाता है जब _if_unset
वह परेशान होता है, लेकिन यह पहली जगह में कभी नहीं चलता है । यह समझने के लिए सबसे महत्वपूर्ण कारक है कि यहां दस्तावेज़-विस्तार के साथ काम करते समय - उन्हें हमेशा पहले होना चाहिए क्योंकि वे <<input
सब के बाद हैं।
त्रुटि /dev/fd/4
इसलिए आती है क्योंकि पैरेंट शेल उस इनपुट को फंक्शन में भेजने से पहले उसका मूल्यांकन कर रहा होता है। यह आवश्यक वातावरण के लिए परीक्षण करने का सबसे सरल, सबसे कुशल तरीका है।
वैसे भी, विफलता आसानी से हल हो जाती है।
_if_unset=set fn
#OUTPUT#
+ _if_unset=set
+ fn
+ echo 'this would be command 1'
this would be command 1
+ echo 'REQ/RESET added to all funcs'
REQ/RESET added to all funcs
लचीला
चर common_param
का मूल्यांकन प्रत्येक फ़ंक्शन के लिए इनपुट पर एक डिफ़ॉल्ट मान के लिए किया जाता है _fn_init
। लेकिन वह मूल्य किसी भी अन्य के लिए भी परिवर्तनशील है जिसे समान रूप से घोषित हर फ़ंक्शन द्वारा सम्मानित किया जाएगा। अब मैं खोल के निशान छोड़ दूँगा - हम यहाँ या किसी भी क्षेत्र में नहीं जा रहे हैं।
set +vx
_fn_init 'fn' \
'echo "Hi! I am the first function."' \
'echo "$common_param"'
_fn_init 'fn2' \
'echo "This is another function."' \
'echo "$common_param"'
_if_unset=set ;
ऊपर मैंने दो कार्यों की घोषणा की और सेट किया _if_unset
। अब, किसी भी फ़ंक्शन को कॉल करने से पहले, मैं परेशान हो जाऊंगा common_param
ताकि आप देख सकें कि जब मैं उन्हें कॉल करूंगा तो वे इसे स्वयं सेट कर देंगे।
unset common_param ; echo
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
REQ/RESET added to all funcs
This is another function.
REQ/RESET added to all funcs
और अब कॉलर के दायरे से:
echo $common_param
#OUTPUT#
REQ/RESET added to all funcs
लेकिन अब मैं चाहता हूं कि यह पूरी तरह से कुछ और हो:
common_param="Our common parameter is now something else entirely."
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
Our common parameter is now something else entirely.
This is another function.
Our common parameter is now something else entirely.
और अगर मैं परेशान हूं _if_unset
?
unset _if_unset ; echo
echo "fn:"
fn ; echo
echo "fn2:"
fn2 ; echo
#OUTPUT#
fn:
dash: 1: _if_unset: shell will ERR and print this to stderr
fn2:
dash: 1: _if_unset: shell will ERR and print this to stderr
रीसेट
यदि आपको किसी भी समय फ़ंक्शन की स्थिति को रीसेट करने की आवश्यकता है, तो यह आसानी से किया जाता है। आपको केवल (फ़ंक्शन के भीतर से) की आवश्यकता है:
. /dev/fd/5
मैंने शुरू में 5<<\RESET
इनपुट फ़ाइल-डिस्क्रिप्टर में फ़ंक्शन को घोषित करने के लिए उपयोग किए गए तर्कों को सहेजा । इसलिए .dot
यह सुनिश्चित करना कि किसी भी समय शेल में यह प्रक्रिया दोहराई जाएगी जो इसे पहले स्थान पर स्थापित करती है। यदि आप इस तथ्य को नजरअंदाज करने के इच्छुक हैं कि यह वास्तव में बहुत आसान है, वास्तव में, और बहुत अधिक पूरी तरह से पोर्टेबल है, तो POSIX वास्तव में फ़ाइल-डिस्क्रिप्टर डिवाइस नोड पथ (जो शेल के लिए एक आवश्यकता है .dot
) निर्दिष्ट नहीं करता है ।
आप आसानी से इस व्यवहार का विस्तार कर सकते हैं और अपने कार्य के लिए विभिन्न राज्यों को कॉन्फ़िगर कर सकते हैं।
अधिक?
यह मुश्किल से सतह को खरोंचता है, वैसे। मैं अक्सर इन तकनीकों का उपयोग मुख्य कार्य के इनपुट में किसी भी समय घोषित छोटे सहायक कार्यों को करने के लिए करता हूं - उदाहरण के लिए, अतिरिक्त स्थितिगत $@
सरणियों के लिए आवश्यकतानुसार। वास्तव में - जैसा कि मेरा मानना है, यह इस के बहुत करीब होना चाहिए कि उच्चतर आदेश शेल वैसे भी करते हैं। आप देख सकते हैं कि वे बहुत आसानी से प्रोग्राम नाम से हैं।
मैं एक जनरेटर फ़ंक्शन की घोषणा करना भी पसंद करता हूं जो एक सीमित प्रकार के पैरामीटर को स्वीकार करता है और फिर एकल-उपयोग या अन्यथा स्कोप-सीमित बर्नर-फ़ंक्शन को एक लैम्ब्डा की तर्ज पर परिभाषित करता है - या एक इन-लाइन फ़ंक्शन - जो कि बस unset -f
तब ही होता है के माध्यम से। आप एक शेल फंक्शन पास कर सकते हैं।