बाश कार्यों में उपनाम


9

मैं एक स्क्रिप्ट का उपयोग करता हूं (जो कि मेरे पास पहुंच नहीं है) जो पर्यावरण को स्थापित करने के लिए एलियंस का एक गुच्छा बनाता है। मैं अपने वातावरण को सेट करने के लिए एक बैश फ़ंक्शन बनाना चाहूंगा, लेकिन ऐसा लगता है कि उपनाम फ़ंक्शन बॉडी से जीवित नहीं हैं।

यहाँ एक न्यूनतम उदाहरण है:

# aliases.sh
alias fooAlias='echo "this will never work!"'  

# .bashrc
function setupLotsOfThings() {
    source aliases.sh
    fooAlias
}

अब, अगर मैं केवल aliases.shअंतःक्रियात्मक रूप से स्रोत हूं, तो चीजें अपेक्षित रूप से काम करती हैं:

[mycomputer]~/ $ source aliases.sh
[mycomputer]~/ $ fooAlias
this will never work!

हालाँकि, अगर मैं इसके बजाय मेरे .bashrc में परिभाषित फ़ंक्शन को कॉल करता हूं, तो यह अपनी परिभाषा के स्रोत के बाद उपनाम को नहीं पहचानता है:

[mycomputer]~/ $ setupLotsOfThings
-bash: fooAlias: command not found

यहाँ क्या हो रहा है? क्या ऐसा कुछ aliasहै जो किसी फ़ंक्शन में उपयोग किए जाने पर कमांड के दायरे के बारे में याद आ रहा है?

संपादित करें: जो कुछ मैं पूरा करने की कोशिश कर रहा हूं, उस पर कुछ प्रकाश डालने के लिए मैं न्यूनतम उदाहरण से परे कुछ विवरण जोड़ूंगा।

अपने काम के लिए मैं एक क्लस्टर और / या ग्रिड पर बहुत सारे सॉफ्टवेयर विकसित और चलाता हूं। मेरे पास कई परियोजनाएं हैं जिनके लिए पूरी तरह से अलग वातावरण की आवश्यकता होती है, जैसे कि अलग-अलग जीसीसी संस्करण, विशिष्ट सॉफ़्टवेयर रिलीज़, कॉन्फ़िगरेशन और डेटा पेट्स, और विभिन्न पर्यावरण चर। व्यवस्थापक विभिन्न कार्यों को सेट करने के लिए स्क्रिप्ट प्रदान करते हैं, आमतौर पर शेल फ़ंक्शन या उपनामों को परिभाषित करके, जो अन्य कार्यों या उपनामों को लागू करते हैं या अन्य स्क्रिप्ट चलाते हैं। मेरे लिए, यह एक ब्लैक बॉक्स है।

मैं अपने विभिन्न वातावरणों को एक ही कमांड के साथ सेटअप करना चाहता हूं। वर्तमान में, मैं कुछ ऐसा करता हूं:

[mycomputer]~/ $ source /some/environment/setup/script.sh
[mycomputer]~/ $ aliasToSetupSomeSoftwareVersion    #this was defined in the above
[mycomputer]~/ $ anotherAliasForOtherSoftware
[mycomputer]~/ $ source /maybe/theres/another/script.sh
[mycomputer]~/ $ runSomeOtherSetup      # this was defined in the new script

इन आदेशों को आम तौर पर क्रम में चलाना पड़ता है। मेरा विचार मूल रूप से उपरोक्त पंक्तियों को एक फ़ंक्शन ब्लॉक में कॉपी करना था, लेकिन मूल उदाहरण से पता चलता है, कि बस काम नहीं करता है। वैकल्पिक workarounds स्वागत से अधिक कर रहे हैं!

जवाबों:


10

एक वैकल्पिक समाधान एक फ़ंक्शन ब्लॉक के बजाय उन आदेशों को एक पाठ फ़ाइल में पेस्ट करना है। कुछ इस तरह:

## This is needed to make the sourced aliases available
## within the script.
shopt -s expand_aliases

source /some/environment/setup/script.sh
aliasToSetupSomeSoftwareVersion
anotherAliasForOtherSoftware
source /maybe/theres/another/script.sh
runSomeOtherSetup

setup1.shआप जहां चाहें उसे सहेज लें । चाल तब इस फ़ाइल को स्रोत है , इसे निष्पादित नहीं:

$ source setup1.sh

यह स्क्रिप्ट में मौजूद उपनामों को चलाएगा और उन्हें आपके वर्तमान शेल के लिए भी उपलब्ध कराएगा।

आप इसे अपने साथ जोड़कर प्रक्रिया को और सरल बना सकते हैं .bashrc:

alias setupLotsOfThings="source setup1.sh"

अब आप बस रन कर सकते हैं setupLotsOfThingsऔर फ़ंक्शन से वांछित व्यवहार प्राप्त कर सकते हैं ।


व्याख्या

यहां दो समस्याएं हैं। सबसे पहले, उपनाम उन फ़ंक्शन के लिए उपलब्ध नहीं हैं जिन्हें वे घोषित किए जाते हैं, लेकिन केवल एक बार उस फ़ंक्शन से बाहर निकल गए हैं और दूसरा यह कि उपनाम स्क्रिप्ट के भीतर उपलब्ध नहीं हैं। दोनों को एक ही खंड में समझाया गया है man bash:

जब शेल इंटरएक्टिव नहीं होता है, तब तक एलियासेस का विस्तार नहीं किया जाता है, जब तक कि एक्सप्लोसिअलीस शेल विकल्प शॉप्ट का उपयोग करके सेट नहीं किया जाता है (नीचे शेल बिल्डिन के तहत शॉप का वर्णन देखें)।

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

फिर, फ़ाइल को निष्पादित और सोर्स करने में अंतर है। असल में, एक स्क्रिप्ट चलाने से यह एक अलग शेल में चलता है, जबकि सोर्सिंग से यह चालू शेल में चलता है। इसलिए, सोर्सिंग setup.shएलियास को स्क्रिप्ट के रूप में निष्पादित करते समय मूल शेल में उपलब्ध कराती है।


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

और PS स्क्रिप्ट जो उपनाम सेट करती है दुर्भाग्य से बहुत ही क्रियात्मक है और थोड़ी धीमी है (क्योंकि यह NFS पर कई फाइलों को छूती है), इसलिए मैं लॉगिन टाइम पर इन सभी चीजों को स्रोत नहीं बनाना पसंद करता हूं।
पीछा

@ मिलें, लेकिन वे केवल आपके द्वारा चलाए जाने पर खट्टे होते हैं setupLotsOfThings, वे केवल फ़ंक्शन के लिए उपलब्ध नहीं होते हैं। वे उस शेल को काम करते हैं जिसे आपने फ़ंक्शन कहा है। वैसे भी, यदि आपका कार्य केवल उपनाम का स्रोत है तो केवल एक उपनाम का उपयोग क्यों नहीं करें? उदाहरण के लिए alias setupstuff="source aliases.sh":।
टेर्डन

सही है, लेकिन मैं प्रति सेक्शन के बारे में चिंतित नहीं हूं । आदर्श रूप से मैं सिर्फ "स्रोत सामान" और "रन अलायस" चरण को एक में जोड़ना चाहता हूं। शायद यह 3 कार्यों के साथ किया जा सकता है? function sourceStuff () {स्रोत ...}; function runStuff () {someAlias; ...}; समारोह setupLotsOfThings () {sourceStuff; runStuff; };
पीछा

@ हाँ, मैं इसके बारे में सोचा था, लेकिन यह काम नहीं किया :)। क्या आप अपने प्रश्न का विस्तार कर सकते हैं कि आपको और क्या करने की आवश्यकता है? फ़ंक्शंस केवल इतनी जटिलता से निपट सकते हैं, आपको इसके बजाय थोड़ा स्क्रिप्ट लिखना पड़ सकता है।
टेराडॉन

7

दरअसल, फंक्शन लोड होने के बाद आपके एलियासेस उपलब्ध हैं! आप .bashrcफ़ंक्शन को निष्पादित करने के बाद अपने इंटरैक्टिव शेल में, या अपने उपयोग कर सकते हैं ।

प्रतिबंध यह है कि फ़ंक्शन परिभाषा में उपनामों का विस्तार तब किया जाता है जब फ़ंक्शन परिभाषा को पढ़ा जाता है, न कि जब फ़ंक्शन का मूल्यांकन किया जाता है। यह बैश की एक सीमा है। तो यह काम करेगा:

function setupLotsOfThings() {
    source aliases.sh
}
setupLotsOfThings
fooAlias

लेकिन यह नहीं:

function setupLotsOfThings() {
    source aliases.sh
}
function useTheAliases() {
    fooAlias
}
setupLotsOfThings
useTheAliases

यदि आपको ऐसे उपनामों की आवश्यकता है जो फ़ंक्शन के अंदर उपयोग करने योग्य हैं और फ़ंक्शन के पार्स होने के बाद उन्हें परिभाषित किया जा सकता है, तो उनके बजाय कार्य करें। याद रखें कि आप commandउसी नाम के एक फ़ंक्शन से बाहरी कमांड को लागू करने के लिए बिलिन का उपयोग कर सकते हैं ।

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