संक्षिप्त उत्तर: देखें BashFAQ # 50: मैं एक चर में एक कमांड डालने की कोशिश कर रहा हूं, लेकिन जटिल मामले हमेशा विफल होते हैं! ।
लंबा उत्तर: जब शेल एक कमांड लाइन को पार्स करता है, तो यह ऐसा करता है जैसे कि यह पता लगाना कि लाइन के कौन से भाग उद्धरण में हैं (या बच गए या जो भी हो) से पहले यह चर का विकल्प देता है; इस प्रकार, यदि आपके पास चर के मूल्यों के अंदर कोई उद्धरण या भाग है, तो जब तक वे कमांड में प्रतिस्थापित नहीं हो जाते, तब तक उन्हें कुछ भी करने के लिए बहुत देर हो चुकी होती है। यह प्रतिस्थापित चरों के मूल्यों पर थोड़ी-बहुत पार्सिंग करता है: यह उन्हें रिक्त स्थान, टैब, आदि के आधार पर "शब्द" में विभाजित करता है (चाहे वे उद्धरण में हों), और यह वाइल्डकार्ड (फिर, यहां तक कि वे) का विस्तार 'फिर से उद्धरण में)। BTW, यह शेल सिंटैक्स के अन्य बिट्स जैसे पाइप, रीडायरेक्ट, आदि को प्रभावी होने में बहुत देर कर देता है। इसका वर्णन करने के लिए, मेरे पास एक आदेश है printargs
वह अपने तर्कों को छापता है। जब मैं एक चर में एक जटिल कमांड को स्टोर करने की कोशिश करता हूं तो यहां क्या होता है:
$ cmd='printargs " * " | cat >outfile &'
$ $cmd
Got 8 arguments:
'"'
'file1.txt'
'file2.txt'
'"'
'|'
'cat'
'>outfile'
'&'
ध्यान दें कि उद्धरण, पाइप, आदि सभी को सामान्य वर्णों के रूप में माना जाता है, न कि सिंटैक्स।
कई समाधान हैं, इस बात पर निर्भर करता है कि आपने कमांड को पहले वेरिएबल में क्यों रखा है:
यदि आपको वास्तव में कमांड को एक चर में रखने की आवश्यकता नहीं है, नहीं । कमांड को निष्पादित किया जाना है, इसलिए जब तक कोई अच्छा कारण नहीं है, बस इसे सीधे निष्पादित करें।
यदि आप अनिवार्य रूप से एक ही कमांड का कई बार उपयोग करना चाहते हैं & amp; हर बार पूरी बात लिखना नहीं चाहते हैं (प्रोग्रामिंग के "खुद को दोहराएं नहीं"), फ़ंक्शन का उपयोग करें
execute_command() {
foo "$1" --option1 --option2 "$2"
}
... और फिर उसे बार-बार फोन करते हैं। ध्यान दें कि मैंने चर संदर्भों को दोहरे-उद्धरणों में रखा है; आपको (लगभग) हमेशा ऐसा करना चाहिए जिससे उन्हें शब्द विभाजन और उन पर लागू वाइल्डकार्ड विस्तार को रोका जा सके।
यदि आपको कमांड को गतिशील रूप से बनाने की आवश्यकता है, तो एक ऐरे का उपयोग करें:
post_data=("var1=value1" "var2=value2" ...)
post_args=()
for post_arg in "${post_data{@]}"; do # Note that this is the correct idiom for expanding an array in bash
post_data+=(-d "$post_arg")
done
curl "${post_args[@]}" "$url"
ध्यान दें कि यह एकल कमांड के लिए जटिल तर्कों के लिए काम करता है, लेकिन पाइप, रीडायरेक्ट और बैकग्राउंडिंग जैसी चीजों के लिए काम नहीं करेगा ( &
), क्योंकि फिर से चर को प्रतिस्थापित करने से पहले उन्हें पार्स किया जाता है।
अंत में, कुछ चेतावनियाँ:
उपयोग न करें eval
या bash -c
जब तक आप नहीं जानते ठीक ठीक शेल पार्सिंग कैसे काम करता है (और यदि आप यह सवाल पूछ रहे हैं, तो आपको ठीक से पता नहीं है कि शेल पार्सिंग कैसे काम करता है)। इन दोनों के कारण पार्सिंग की एक अतिरिक्त परत होती है, जो परीक्षण में महान काम करती है, लेकिन कभी-कभी असफल होती है (असंगत कारणों के लिए)। eval
वास्तव में अजीब और सूक्ष्म कीड़े के स्रोत के रूप में अच्छी तरह से लायक प्रतिष्ठा है; तथा bash -c
अनिवार्य रूप से एक ही काम करता है, सिर्फ एक उपधारा के साथ इसे भी अजीब बनाने के लिए।
अनपेक्षित शब्द विभाजन और वाइल्डकार्ड विस्तार को रोकने के लिए डबल-उद्धरण चर संदर्भ।
आप शायद उपयोग नहीं करना चाहते हैं exec
- यह वर्तमान शेल (& amp; शेल स्क्रिप्ट) से बाहर निकलता है, और इसे कमांड के साथ बदल देता है; यह शायद वह नहीं है जिसका आपने इरादा किया था।