कैसे परिभाषित करें और अपने स्वयं के शेल फ़ंक्शन को zsh में लोड करें


54

मैं एक कठिन समय निर्धारित कर रहा हूं और अपने स्वयं के शेल फ़ंक्शन को zsh में चला रहा हूं। मैंने आधिकारिक दस्तावेज़ीकरण पर निर्देशों का पालन ​​किया और पहले आसान उदाहरण के साथ प्रयास किया, लेकिन मैं इसे काम करने में विफल रहा।

मेरे पास एक फ़ोल्डर है:

~/.my_zsh_functions

इस फ़ोल्डर में मेरे पास उपयोगकर्ता अनुमतियों के functions_1साथ एक फ़ाइल है rwx। इस फ़ाइल में मेरे पास निम्नलिखित शेल फ़ंक्शन परिभाषित हैं:

my_function () {
echo "Hello world";
}

मैंने FPATHफ़ोल्डर में पथ शामिल करने के लिए परिभाषित किया ~/.my_zsh_functions:

export FPATH=~/.my_zsh_functions:$FPATH

मैं पुष्टि कर सकता हूं कि फ़ोल्डर .my_zsh_functionsफ़ंक्शंस पथ में echo $FPATHया के साथ हैecho $fpath

हालाँकि, अगर मैं फिर शेल से निम्नलिखित कोशिश करता हूँ:

> autoload my_function
> my_function

मुझे मिला:

zsh: my_test_function: फ़ंक्शन परिभाषा फ़ाइल नहीं मिली

क्या मुझे कॉल करने में सक्षम होने के लिए कुछ और करने की आवश्यकता है my_function?

अपडेट करें:

अब तक के जवाबों का सुझाव है कि फ़ाइल को zsh फ़ंक्शन के साथ सोर्स करना। यह समझ में आता है, लेकिन मैं थोड़ा उलझन में हूं। Zsh नहीं पता होना चाहिए कि वे फाइलें कहां हैं FPATH? autoloadतब का उद्देश्य क्या है ?


सुनिश्चित करें कि आपके पास $ ZDOTDIR ठीक से परिभाषित है। zsh.sourceforge.net/Intro/intro_3.html
ramonovski

2
$ ZDOTDIR का मूल्य इस समस्या से संबंधित नहीं है। चर परिभाषित करता है जहां zsh उपयोगकर्ता की कॉन्फ़िगरेशन फ़ाइलों की तलाश कर रहा है। यदि यह परेशान है तो इसके बजाय $ HOME का उपयोग किया जाता है, जो लगभग सभी के लिए सही मूल्य है।
फ्रैंक टेर्बेक

जवाबों:


94

Zsh में, फ़ंक्शन खोज पथ ($ fpath) निर्देशिकाओं के एक सेट को परिभाषित करता है, जिसमें ऐसी फाइलें होती हैं जिन्हें स्वचालित रूप से लोड करने के लिए चिह्नित किया जा सकता है जब उनके पास पहली बार होने वाले फ़ंक्शन की आवश्यकता होती है।

Zsh के पास ऑटोलोदिंग फ़ाइलों के दो तरीके हैं: Zsh का मूल तरीका और एक अन्य मोड जो ksh की ऑटोलडिंग के जैसा होता है। यदि KSH_AUTOLOAD विकल्प सेट है तो बाद वाला सक्रिय है। Zsh का मूल मोड डिफ़ॉल्ट है और मैं यहां दूसरे तरीके पर चर्चा नहीं करूंगा (ksh-style autoloading के बारे में विवरण के लिए "man zshmisc" और "man zshoptions")।

ठीक है। मान लें कि आपको एक निर्देशिका मिली ~ ~ / .zfunc 'और आप इसे फ़ंक्शन खोज पथ का हिस्सा बनाना चाहते हैं, आप ऐसा करते हैं:

fpath=( ~/.zfunc "${fpath[@]}" )

यह आपकी निजी निर्देशिका को खोज पथ के सामने जोड़ता है। यदि आप अपने स्वयं के साथ zsh के इंस्टॉलेशन से कार्यों को ओवरराइड करना चाहते हैं, तो यह महत्वपूर्ण है (जैसे, जब आप किसी अपडेटेड फंक्शन का उपयोग करना चाहते हैं, जैसे zsh के CVS रिपॉजिटरी से शेल के पुराने संस्करण के साथ)।

यह भी ध्यान देने योग्य है, कि '$ fpath' से निर्देशिकाओं को पुनरावर्ती रूप से नहीं खोजा गया है। यदि आप चाहते हैं कि आपकी निजी निर्देशिका को फिर से खोजा जाए, तो आपको खुद का ध्यान रखना होगा, इस तरह (निम्नलिखित स्निपेट को सेट करने के लिए `EXTENDED_GLOB 'विकल्प की आवश्यकता होती है):

fpath=(
    ~/.zfuncs
    ~/.zfuncs/**/*~*/(CVS)#(/N)
    "${fpath[@]}"
)

यह अप्रशिक्षित आंख को गुप्त लग सकता है, लेकिन यह वास्तव में "सीवीएस" नामक निर्देशिकाओं को अनदेखा करते हुए '~ / .zfunc' के नीचे सभी निर्देशिकाओं को जोड़ता है, (जो कि उपयोगी है, यदि आप पूरी जांच करने की योजना बना रहे हैं। अपने निजी खोज पथ में zsh के सीवीएस से फ़ंक्शन ट्री)।

मान लें कि आपको एक फ़ाइल मिली है ~ ~ / .zfunc / hello 'जिसमें निम्न पंक्ति है:

printf 'Hello world.\n'

अब आपको केवल अपने पहले संदर्भ पर स्वचालित रूप से लोड होने वाले फ़ंक्शन को चिह्नित करना है :

autoload -Uz hello

"क्या है -यूज़ के बारे में?", आप पूछते हैं ठीक है, यह सिर्फ विकल्पों का एक सेट है जो `ऑटोलॉड 'का कारण होगा सही काम करने के लिए, इससे कोई फर्क नहीं पड़ता कि क्या विकल्प सेट किए जा रहे हैं। फ़ंक्शन लोड होने के दौरान `यू 'उर्फ विस्तार को अक्षम करता है और` z' शैली zsh- शैली को ऑटोलिडिंग करता है, भले ही `KSH_AUTOLOAD 'जो भी कारण से सेट हो।

उसके बाद ध्यान रखा गया है, आप अपने नए 'हैलो' फ़ंक्शन का उपयोग कर सकते हैं:

zsh% हैलो
नमस्ते दुनिया।

इन फाइलों को सोर्स करने के बारे में एक शब्द: यह सिर्फ गलत है । यदि आप स्रोत कि `~ / .zfunc / हैलो 'फाइल करते हैं, तो यह सिर्फ" हैलो वर्ल्ड "प्रिंट करेगा। एक बार। और कुछ नहीं। कोई फ़ंक्शन परिभाषित नहीं किया जाएगा। और इसके अलावा, विचार केवल फ़ंक्शन के कोड को लोड करना है जब यह आवश्यक हो । `ऑटोलोड’ कॉल के बाद फ़ंक्शन की परिभाषा नहीं पढ़ी जाती है। फ़ंक्शन को केवल आवश्यकतानुसार बाद में ऑटोलोडेड होने के लिए चिह्नित किया गया है।

और अंत में, $ FPATH और $ fpath के बारे में एक नोट: Zsh उन लोगों को जुड़े मापदंडों के रूप में रखता है। निचला केस पैरामीटर एक सरणी है। ऊपरी मामला संस्करण एक स्ट्रिंग स्केलर है, जिसमें प्रविष्टियों के बीच कॉलन द्वारा शामिल लिंक किए गए सरणी से प्रविष्टियां हैं। यह किया जाता है, क्योंकि स्केलर की सूची को संभालना एरे का उपयोग करके अधिक प्राकृतिक है, जबकि स्केल के पैरामीटर का उपयोग करने वाले कोड के लिए पीछे की संगतता भी बनाए रखना है। यदि आप $ FPATH (स्केलर वन) का उपयोग करना चुनते हैं, तो आपको सावधान रहने की आवश्यकता है:

FPATH=~/.zfunc:$FPATH

काम करेगा, जबकि निम्नलिखित नहीं होगा:

FPATH="~/.zfunc:$FPATH"

कारण यह है कि दोहरे उद्धरण चिह्नों के भीतर टिल्ड विस्तार का प्रदर्शन नहीं किया जाता है। यह आपकी समस्याओं का स्रोत है। यदि echo $FPATHएक टिल्ड प्रिंट करता है और एक विस्तारित मार्ग नहीं है, तो यह काम नहीं करेगा। सुरक्षित होने के लिए, मैं इस तरह से एक टिल्ड के बजाय $ HOME का उपयोग करूँगा:

FPATH="$HOME/.zfunc:$FPATH"

यह कहा जा रहा है, मैं बहुत से सरणी पैरामीटर का उपयोग करूँगा जैसे मैंने इस स्पष्टीकरण के शीर्ष पर किया था।

आपको $ FPATH पैरामीटर का निर्यात भी नहीं करना चाहिए। यह केवल वर्तमान शेल प्रक्रिया द्वारा आवश्यक है और इसके किसी भी बच्चे द्वारा नहीं।

अपडेट करें

'$ Fpath' में फ़ाइलों की सामग्री के बारे में:

जेड-स्टाइल ऑटोलॉडिंग के साथ, एक फ़ाइल की सामग्री उस फ़ंक्शन का शरीर है जिसे वह परिभाषित करता है। इस प्रकार "हेल्लो" नामक एक फाइल जिसमें एक लाइन होती है, echo "Hello world.""हेलो" नामक एक फ़ंक्शन को पूरी तरह से परिभाषित करती है। आप hello () { ... }कोड के चारों ओर रखने के लिए स्वतंत्र हैं , लेकिन यह बहुत ही अच्छा होगा।

दावा है कि एक फ़ाइल में केवल एक फ़ंक्शन हो सकता है, हालांकि पूरी तरह से सही नहीं है।

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

यदि - उप-फ़ंक्शंस के साथ - आपने फ़ाइल के भीतर फ़ाइल की तरह एक फ़ंक्शन को परिभाषित नहीं किया है, तो आप उस फ़ंक्शन के साथ इसमें परिभाषाएँ (अर्थात् फ़ाइल में उप-फ़ंक्शन) को समाप्त करेंगे। हर बार जब आप फ़ंक्शन को फ़ाइल की तरह नामित किया जाता है, तो आप अपने सभी उप-कार्यों को प्रभावी ढंग से परिभाषित कर रहे होंगे। आम तौर पर, यह वह नहीं है जो आप चाहते हैं, इसलिए आप एक फ़ंक्शन को फिर से परिभाषित करेंगे, जिसे फ़ाइल के भीतर फ़ाइल की तरह नाम दिया गया है।

मैं एक छोटा कंकाल शामिल करूंगा, जिससे आपको अंदाजा होगा कि यह कैसे काम करता है:

# Let's again assume that these are the contents of a file called "hello".

# You may run arbitrary code in here, that will run the first time the
# function is referenced. Commonly, that is initialisation code. For example
# the `_tmux' completion function does exactly that.
echo initialising...

# You may also define additional functions in here. Note, that these
# functions are visible in global scope, so it is paramount to take
# care when you're naming these so you do not shadow existing commands or
# redefine existing functions.
hello_helper_one () {
    printf 'Hello'
}

hello_helper_two () {
    printf 'world.'
}

# Now you should redefine the "hello" function (which currently contains
# all the code from the file) to something that covers its actual
# functionality. After that, the two helper functions along with the core
# function will be defined and visible in global scope.
hello () {
    printf '%s %s\n' "$(hello_helper_one)" "$(hello_helper_two)"
}

# Finally run the redefined function with the same arguments as the current
# run. If this is left out, the functionality implemented by the newly
# defined "hello" function is not executed upon its first call. So:
hello "$@"

यदि आप यह मूर्खतापूर्ण उदाहरण चलाते हैं, तो पहला रन इस तरह दिखाई देगा:

zsh% हैलो
आरंभ करीत आहे ...
नमस्ते दुनिया।

और लगातार कॉल इस तरह दिखाई देंगे:

zsh% हैलो
नमस्ते दुनिया।

मै उम्मीद करता हू कि यह बातें अब साफ है।

(उन सभी चालों का उपयोग करने वाले अधिक जटिल वास्तविक दुनिया उदाहरणों में से एक है, जो पहले से ही ज़ेड के फ़ंक्शन आधारित पूर्णता प्रणाली से ` _tmux 'फ़ंक्शन का उल्लेख करता है।)


धन्यवाद फ्रैंक! मैंने अन्य उत्तरों में पढ़ा कि मैं प्रति फ़ाइल केवल एक फ़ंक्शन को परिभाषित कर सकता हूं, क्या यह सही है? मैंने देखा कि आपने my_function () { }अपने Hello worldउदाहरण में वाक्य रचना का उपयोग नहीं किया । यदि सिंटैक्स की आवश्यकता नहीं है, तो इसका उपयोग कब करना उपयोगी होगा?
एमिलियो वाज़केज़-रीना

1
मैंने उन सवालों के जवाब के लिए मूल उत्तर भी दिया।
फ्रैंक टेर्बेक

"आप हमेशा उस फ़ंक्शन में परिभाषित करेंगे जिसका नाम फ़ाइल में फ़ाइल की तरह है और फ़ाइल के अंत में उस फ़ंक्शन को कॉल करें": ऐसा क्यों?
हिबू

Hibou57: (असाइड: यह एक टाइपो है, जिसे "एक फ़ंक्शन को परिभाषित करना चाहिए", जो अब ठीक हो गया है।) मुझे लगा कि यह स्पष्ट था, जब आप कोड स्निपेट लेते हैं जो विचार में आता है। वैसे भी, मैंने एक पैराग्राफ जोड़ा है जो कारण को थोड़ा और अधिक शाब्दिक रूप से बताता है।
फ्रैंक Terbeck

यहाँ आपकी साइट से अधिक जानकारी है, धन्यवाद।
टिमो

5

किसी fpathतत्व द्वारा नामित डायरेक्टरी में फ़ाइल का नाम ऑटोलैडेबल फ़ंक्शन के नाम से मेल खाना चाहिए जो इसे परिभाषित करता है।

आपका फ़ंक्शन नाम दिया गया है my_functionऔर ~/.my_zsh_functionsआपके लिए इच्छित निर्देशिका है fpath, इसलिए my_functionफ़ाइल में परिभाषा होनी चाहिए ~/.my_zsh_functions/my_function

आपके प्रस्तावित फ़ाइलनाम ( functions_1) में बहुवचन इंगित करता है कि आप फ़ाइल में कई फ़ंक्शन डालने की योजना बना रहे थे। यह कैसे fpathऔर ऑटोलडिंग का काम नहीं है। आपके पास प्रति फ़ाइल एक फ़ंक्शन परिभाषा होनी चाहिए।


2

देना source ~/.my_zsh_functions/functions1टर्मिनल में और The का मूल्यांकन my_function, अब आप फ़ंक्शन को कॉल करने में सक्षम हो जाएगा


2
धन्यवाद, लेकिन क्या की भूमिका है FPATHऔर autoloadउसके बाद? मुझे फ़ाइल को स्रोत करने की आवश्यकता क्यों है? मेरा अद्यतन प्रश्न देखें।
Amelio Vazquez-Reina

1

आप इस तरह से अपने $ ZDOTDIR / .zshrc में अपने सभी कार्यों के साथ एक फ़ाइल को "लोड" कर सकते हैं।

source $ZDOTDIR/functions_file

या डॉट का उपयोग कर सकते हैं "।" "स्रोत" के बजाय।


1
धन्यवाद, लेकिन क्या की भूमिका है FPATHऔर autoloadउसके बाद? मुझे फ़ाइल को स्रोत करने की आवश्यकता क्यों है? मेरा अद्यतन प्रश्न देखें।
Amelio Vazquez-Reina

0

सोर्सिंग निश्चित रूप से सही दृष्टिकोण नहीं है, क्योंकि आप जो चाहते हैं वह आलसी आरंभीकृत कार्यों के लिए है। इसके autoloadलिए जो है। यहां बताया गया है कि आप किस तरह से काम करते हैं।

अपने में ~/.my_zsh_functions, आप कहते हैं कि आप एक कार्य करना चाहते हैं, जिसे my_functionइकोस "हैलो वर्ल्ड" कहा जाता है। लेकिन, आप इसे एक फ़ंक्शन कॉल में लपेटते हैं, जो कि यह कैसे काम करता है। इसके बजाय, आपको एक फ़ाइल बनाने की आवश्यकता है जिसे कहा जाता है ~/.my_zsh_functions/my_function। इसमें, सिर्फ echo "Hello world"एक फ़ंक्शन आवरण में नहीं, डाल दिया । आप भी ऐसा कुछ कर सकते हैं अगर आप वास्तव में रैपर को पसंद करते हैं।

# ~/.my_zsh_functions/my_function
__my_function () {
    echo "Hello world";
}
# you have to call __my_function
# if this is how you choose to do it
__my_function

अपनी .zshrcफ़ाइल में अगला, निम्नलिखित जोड़ें:

fpath=(~/.my_zsh_functions $fpath);
autoload -U ~/.my_zsh_functions/my_function

जब आप एक नया ZSH शेल लोड करते हैं, तो टाइप करें which my_function। आपको यह देखना चाहिए:

my_function () {
    # undefined
    builtin autoload -XU
}

ZSH सिर्फ तुम्हारे लिए my_function बाहर निकाल दिया autoload -X। अब, चलाएं my_functionलेकिन सिर्फ टाइपिंग my_function। आपको Hello worldप्रिंट आउट देखना चाहिए , और अब जब आप दौड़ेंगे which my_functionतो आपको इस तरह से भरे हुए फंक्शन को देखना चाहिए:

my_function () {
    echo "Hello world"
}

अब, असली जादू तब आता है जब आप अपने पूरे ~/.my_zsh_functionsफ़ोल्डर को काम करने के लिए सेट करते हैं autoload। अगर आप चाहते हैं कि आप इस फोल्डर में मौजूद हर फाइल को इस तरह से काम करें, तो जो .zshrcकुछ आप इस में डालते हैं उसे इस तरह बदलें :

# add ~/.my_zsh_functions to fpath, and then lazy autoload
# every file in there as a function
fpath=(~/.my_zsh_functions $fpath);
autoload -U fpath[1]/*(.:t)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.