एक चर में संग्रहीत एक कमांड निष्पादित करें


11

मेरे पास एक चर में संग्रहित एक कमांड है। आइए दिखाते हैं कि चर $iका मान है:

cat -nT index.php |grep 'someregex'

जब मैं उपरोक्त चर को टाइप करके $iनिष्पादित करने का प्रयास करता है तो यह विफल हो जाता है क्योंकि शेल पूरे चर को एक कमांड के रूप में निष्पादित करने का प्रयास करता है। मैंने बैकटिक्स में भी उपयोग करने eval($i)और डालने की कोशिश की $i

मैं शेल को कैसे निष्पादित कर सकता हूं $iजैसे कि यह एक कमांड था? और यह काम क्यों नहीं कर रहा है।

$i='echo hi'; $i

क्या इसलिए कि मुझे सिंगल कोट्स में हैक करना था? (क्योंकि आप उन्हें घोंसला नहीं दे सकते।) वर्तमान में मेरा समाधान है

echo $i > /foo;  . /foo

लेकिन मैं इसके लिए सिर्फ एक फाइल नहीं बनाना चाहता, केवल बाद में इसे हटा देना चाहता हूं।

मेरे द्वारा "मैंने एकल उद्धरणों में हैक किया गया" का क्या अर्थ है:

$i='cat index.php | grep -P '"'"'MYREGEXHERE'"'"

4
सवाल यह है कि कमांड को पहली जगह में एक चर में क्यों संग्रहीत किया जाता है? जब आप इसे चलाते हैं तो आप कमांड को असेंबल करना बेहतर समझते हैं, विकल्प तर्क को चर या सरणी में संग्रहीत करते हैं। क्या आप पूरी स्क्रिप्ट दिखा सकते हैं?
slhck

जवाबों:


18

संक्षिप्त उत्तर: BashAQ # 50 देखें : मैं एक चर में एक कमांड डालने की कोशिश कर रहा हूं, लेकिन जटिल मामले हमेशा विफल होते हैं!

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

इसे हल करने के लिए, आपको @ slhck के प्रश्न का उत्तर देने की आवश्यकता है: पहली जगह में एक चर में कमांड क्यों संग्रहीत है? वास्तविक समस्या क्या है जिसे आप हल करने का प्रयास कर रहे हैं? वास्तविक लक्ष्य के आधार पर, कई संभावित समाधान हैं:

  • इसे एक चर में संग्रहीत न करें, बस इसे सीधे निष्पादित करें। बाद में उपयोग के लिए आदेशों को संग्रहीत करना मुश्किल है, और यदि आपको वास्तव में ज़रूरत नहीं है, तो बस नहीं।

  • एक चर के बजाय एक फ़ंक्शन का उपयोग करें। यही कारण है कि वे सब के बाद:

    i() { cat -nT index.php |grep 'someregex'; }
    i

    इसका मुख्य नुकसान यह है कि आप फ़ंक्शन को गतिशील रूप से नहीं बना सकते - आप सशर्त रूप से फ़ंक्शन से कोड को शामिल या बाहर नहीं कर सकते हैं (हालांकि फ़ंक्शन में सशर्त तत्व हो सकते हैं जो निष्पादित होने पर चुने जाते हैं)।

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

    i="cat -nT index.php |grep 'someregex'"
    eval "$i"

EDIT: एक और मानक स्टोर-ए-कमांड-इन-इन-चर दृष्टिकोण एक साधारण चर के बजाय एक सरणी का उपयोग करना है। यह आपको परेशानी के बिना जटिल तर्कों (जैसे रिक्त स्थान वाले) के साथ एक कमांड स्टोर करने की अनुमति देता है, लेकिन पाइप और रीडायरेक्ट जैसी चीजों को स्टोर नहीं करेगा। तो, सरणी दृष्टिकोण इस विशेष मामले में उपयोगी नहीं होगा।


evalविधि के लिए +1 । इसने मुझे वही सवाल पूछने से रोका :)। मेरे पास ऐसा कुछ है sudo rsync -aAHXi -n --delete-excluded --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/lost+found","/mnt/DATA/*","/var/log/*","/var/swap","/var/cache/apt/archives/*.deb"} -e ssh root@piac_wireless:/ /home/mrx/Docs/RPi/backup/piac/piac_usb-rootजो बहिष्करण को सही ढंग से निष्पादित नहीं कर रहा था।
डेंटेक्स

@ डेंटेक्स मैं इसके evalलिए उपयोग करने के खिलाफ दृढ़ता से सिफारिश करूंगा - गलत होने के कई तरीके हैं। एक सरणी ऐसा करने का एक बेहतर तरीका होगा। उदाहरण के लिए यहां , यहां और यहां देखें ।
गॉर्डन डेविसन

सलाह के लिये धन्यवाद। मैं बहिष्करण सूची को rsync पर भेजने के लिए, सरणी के साथ समाधान को लागू करने का प्रयास करूंगा।
डेन्थेक्स

4

यह सिर्फ काम करना चाहिए:

a="cat -nT index.php |grep 'someregex'"
eval "$a"

सावधान रहें जो evalसंभावित कमजोरियों और अप्रत्याशित व्यवहार स्थितियों का परिचय देता है, इसलिए यदि आवश्यक हो, अतिरिक्त देखभाल के साथ इसका उपयोग किया जाना चाहिए।


यदि आप उपयोग करते हैं eval, तो आपको वास्तव में eval "$i"अतिरिक्त-अतिरिक्त-अजीब प्रभावों से बचने के लिए दोहरे-उद्धरण ( ) का उपयोग करने की आवश्यकता है । उदाहरण के लिए, इस के साथ प्रयास करें a="cat -nT index.php |grep ' .* '"(यानी regex को उन दोनों के बीच किसी भी वर्ण के अनुक्रम के साथ मेल खाना चाहिए) और देखें कि वास्तव में क्या होता है। अतिरिक्त ऋण के लिए, यह बताएं कि ऐसा क्यों होता है।
गॉर्डन डेविसन

@GordonDavisson दोहरे उद्धरण जोड़े गए।
jlliagre

2

चर घोषित करते समय, आपको उपसर्ग के रूप में डॉलर चिह्न का उपयोग नहीं करना चाहिए।

इसे इस्तेमाल करे:

i='echo hi'; $i

1
यह सही है, लेकिन यह ओपी के सवाल का जवाब नहीं है।
slhck

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