इनमें से अधिकांश उत्तर उस विशिष्ट मामले पर हिट करते हैं जिसके बारे में आप पूछ रहे हैं। वहाँ एक सामान्य दृष्टिकोण एक दोस्त है कि और मैं विकसित किया है कि मनमाने ढंग से मामले में के हवाले से आप की जरूरत के लिए अनुमति देता है के लिए बोली बैश आदेशों खोल विस्तार, जैसे की कई परतों, ssh के माध्यम से के माध्यम से, su -c
, bash -c
, आदि एक कोर आदिम आप की जरूरत है, यहाँ भी नहीं है देशी बाश में:
quote_args() {
local sq="'"
local dq='"'
local space=""
local arg
for arg; do
echo -n "$space'${arg//$sq/$sq$dq$sq$dq$sq}'"
space=" "
done
}
यह वास्तव में यही कहता है: यह प्रत्येक तर्क को व्यक्तिगत रूप से उद्धृत करता है (विस्तार के बाद, निश्चित रूप से):
$ quote_args foo bar
'foo' 'bar'
$ quote_args arg1 'arg2 arg2a' arg3
'arg1' 'arg2 arg2a' 'arg3'
$ quote_args dq'"'
'dq"'
$ quote_args dq'"' sq"'"
'dq"' 'sq'"'"''
$ quote_args "*"
'*'
$ quote_args /b*
'/bin' '/boot'
यह विस्तार की एक परत के लिए स्पष्ट काम करता है:
$ bash -c "$(quote_args echo a'"'b"'"c arg2)"
a"b'c arg2
(ध्यान दें कि $(quote_args ...)
परिणाम को एक एकल तर्क में बनाने के लिए आसपास के दोहरे उद्धरण आवश्यक हैं bash -c
।) और इसे विस्तार की कई परतों के माध्यम से ठीक से उद्धृत करने के लिए अधिक सामान्यतः उपयोग किया जा सकता है:
$ bash -c "$(quote_args bash -c "$(quote_args echo a'"'b"'"c arg2)")"
a"b'c arg2
उपरोक्त उदाहरण:
- शेल प्रत्येक उद्धरण को आंतरिक रूप से
quote_args
व्यक्तिगत रूप से बताता है और फिर परिणामी आउटपुट को एक एकल तर्क में आंतरिक दोहरे उद्धरणों के साथ जोड़ता है।
- खोल-उद्धरण
bash
, -c
और चरण 1 से पहले ही एक बार उद्धृत परिणाम है, और फिर बाहरी दोहरे उद्धरण चिह्नों के साथ एक एकल बहस में परिणाम को जोड़ती है।
- उस मेस को बाहरी के तर्क के रूप में भेजता है
bash -c
।
संक्षेप में यह विचार है। आप इसके साथ कुछ बहुत जटिल चीजें कर सकते हैं, लेकिन आपको मूल्यांकन के क्रम के बारे में सावधान रहना होगा और इसके बारे में जो सब्स्टीट्यूशन उद्धृत किए गए हैं। उदाहरण के लिए, निम्नलिखित गलत काम करते हैं ("गलत" की कुछ परिभाषा के लिए):
$ (cd /tmp; bash -c "$(quote_args cd /; pwd 1>&2)")
/tmp
$ (cd /tmp; bash -c "$(quote_args cd /; [ -e *sbin ] && echo success 1>&2 || echo failure 1>&2)")
failure
पहले उदाहरण में, बैश तुरंत quote_args cd /; pwd 1>&2
दो अलग-अलग कमांडों में फैलता है , quote_args cd /
और pwd 1>&2
, इसलिए /tmp
जब pwd
कमांड निष्पादित होता है, तो CWD अभी भी है। दूसरा उदाहरण ग्लोबिंग के लिए एक समान समस्या दिखाता है। दरअसल, सभी बैश विस्तार के साथ एक ही मूल समस्या होती है। यहां समस्या यह है कि एक कमांड प्रतिस्थापन एक फ़ंक्शन कॉल नहीं है: यह शाब्दिक रूप से एक बैश स्क्रिप्ट का मूल्यांकन कर रहा है और दूसरे आउटपुट स्क्रिप्ट के भाग के रूप में इसके आउटपुट का उपयोग कर रहा है।
यदि आप शेल संचालकों से बचने का प्रयास करते हैं, तो आप विफल हो जाएंगे क्योंकि परिणामी स्ट्रिंग को पारित कर दिया गया bash -c
है, जो कि व्यक्तिगत रूप से उद्धृत स्ट्रिंग्स का एक अनुक्रम है, जिसे तब ऑपरेटरों के रूप में व्याख्या नहीं किया जाता है, जो यह देखना आसान है कि क्या आप स्ट्रिंग को प्रतिध्वनित करते हैं? बैश करने के लिए पारित किया गया है:
$ (cd /tmp; echo "$(quote_args cd /\; pwd 1\>\&2)")
'cd' '/;' 'pwd' '1>&2'
$ (cd /tmp; echo "$(quote_args cd /\; \[ -e \*sbin \] \&\& echo success 1\>\&2 \|\| echo failure 1\>\&2)")
'cd' '/;' '[' '-e' '*sbin' ']' '&&' 'echo' 'success' '1>&2' '||' 'echo' 'failure' '1>&2'
यहाँ समस्या यह है कि आप अति-उद्धृत कर रहे हैं। परिचालकों के इनपुट के रूप में आपको जो कुछ भी आवश्यक है, वह ऑपरेटरों के लिए है bash -c
, जिसका अर्थ है कि उन्हें $(quote_args ...)
कमांड प्रतिस्थापन के बाहर होना चाहिए ।
नतीजतन, आपको सबसे सामान्य अर्थों में क्या करना है, कमांड के प्रत्येक शब्द को अलग से कमांड प्रतिस्थापन के समय विस्तारित करने का इरादा नहीं है, और शेल ऑपरेटरों को कोई अतिरिक्त उद्धरण लागू नहीं करना है:
$ (cd /tmp; echo "$(quote_args cd /); $(quote_args pwd) 1>&2")
'cd' '/'; 'pwd' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")
/
$ (cd /tmp; echo "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
'cd' '/'; [ -e *'sbin' ] && 'echo' 'success' 1>&2 || 'echo' 'failure' 1>&2
$ (cd /tmp; bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")
success
एक बार जब आप ऐसा कर लेते हैं, तो संपूर्ण स्ट्रिंग मूल्यांकन के मनमाने स्तरों को उद्धृत करने के लिए उचित खेल है:
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")"
/
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")"
/
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); $(quote_args pwd) 1>&2")")")"
/
$ bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")"
success
$ bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *sbin ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")"
success
$ bash -c "$(quote_args bash -c "$(quote_args bash -c "$(quote_args cd /tmp); $(quote_args bash -c "$(quote_args cd /); [ -e *$(quote_args sbin) ] && $(quote_args echo success) 1>&2 || $(quote_args echo failure) 1>&2")")")"
success
आदि।
इन उदाहरणों अतिव्य्घ्र दिया लग सकता है कि शब्द की तरह है success
, sbin
और pwd
खोल उद्धृत करने की आवश्यकता नहीं है, लेकिन प्रमुख मुद्दा जब एक स्क्रिप्ट मनमाने ढंग से इनपुट लेने लेखन याद करने के लिए है कि आप सब कुछ आप पूरी तरह से सुनिश्चित नहीं कर रहे हैं उद्धृत करने के लिए चाहता हूँ नहीं करता ' t को उद्धृत करने की आवश्यकता है, क्योंकि आप कभी नहीं जानते कि उपयोगकर्ता कब में फेंक देगा Robert'; rm -rf /
।
यह समझने के लिए कि कवर के तहत क्या हो रहा है, आप दो छोटे सहायक कार्यों के साथ खेल सकते हैं:
debug_args() {
for (( I=1; $I <= $#; I++ )); do
echo -n "$I:<${!I}> " 1>&2
done
echo 1>&2
}
debug_args_and_run() {
debug_args "$@"
"$@"
}
इसे निष्पादित करने से पहले प्रत्येक तर्क को एक कमांड में रखा जाएगा:
$ debug_args_and_run echo a'"'b"'"c arg2
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)"
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2
$ bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run bash -c "$(quote_args debug_args_and_run echo a'"'b"'"c arg2)")")")"
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'bash'"'"' '"'"'-c'"'"' '"'"''"'"'"'"'"'"'"'"'debug_args_and_run'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'echo'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'a"b'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'c'"'"'"'"'"'"'"'"' '"'"'"'"'"'"'"'"'arg2'"'"'"'"'"'"'"'"''"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'bash' '-c' ''"'"'debug_args_and_run'"'"' '"'"'echo'"'"' '"'"'a"b'"'"'"'"'"'"'"'"'c'"'"' '"'"'arg2'"'"''>
1:<bash> 2:<-c> 3:<'debug_args_and_run' 'echo' 'a"b'"'"'c' 'arg2'>
1:<echo> 2:<a"b'c> 3:<arg2>
a"b'c arg2