बाश में एक आदेश में एकल उद्धरण के अंदर चर का विस्तार


393

मैं एक bash स्क्रिप्ट से एक कमांड चलाना चाहता हूं जिसमें सिंगल कोट्स और एक वेरिएबल के अंदर सिंगल कोट्स और कुछ अन्य कमांड्स हैं।

जैसे repo forall -c '....$variable'

इस प्रारूप में, $बच जाता है और चर का विस्तार नहीं किया जाता है।

मैंने निम्नलिखित बदलावों की कोशिश की, लेकिन उन्हें अस्वीकार कर दिया गया:

repo forall -c '...."$variable" '

repo forall -c " '....$variable' "

" repo forall -c '....$variable' "

repo forall -c "'" ....$variable "'"

यदि मैं चर के स्थान पर मान को प्रतिस्थापित करता हूं तो कमांड को ठीक-ठीक निष्पादित किया जाता है।

कृपया बताएं कि मैं कहां गलत हूं।


33
repo forall -c ' ...before... '"$variable"' ...after...'
एन। 'सर्वनाम' मी।

2
@ सिंगल कोट्स रेपो कमांड का एक हिस्सा हैं। मुझे नहीं लगता कि यह काम करेगा
Rachit

1
bashएकल उद्धरण खाती है। या तो आप अंदर नहीं हैं bash, या एकल उद्धरण repoकमांड का हिस्सा नहीं हैं ।
एन। 'सर्वनाम' मी।

मुझे यकीन नहीं है कि मैं आपको मिल सकता हूं, लेकिन अगर सिंगल कोट्स में होने की जरूरत है, तो फॉरेस्ट -c को "..." से पहले ... "$ चर" ... के बाद ... '' काम नहीं करना चाहिए?
इको

इसके बैश शेल और रेपो फोर्ल कमांड में चलने वाली बैश स्क्रिप्ट सिंगल कोट्स के अंदर पैरामीटर लेती है। यदि मैं वास्तविक मूल्य को प्रतिस्थापित करता हूं, तो कमांड ठीक चलता है।
राचिट

जवाबों:


621

एकल उद्धरण के अंदर सब कुछ अपवाद के बिना, शाब्दिक रूप से संरक्षित है।

इसका मतलब है कि आपको उद्धरणों को बंद करना है, कुछ डालना है, और फिर फिर से दर्ज करना है।

'before'"$variable"'after'
'before'"'"'after'
'before'\''after'

शब्द संघटन केवल रसोपचार द्वारा किया जाता है। जैसा कि आप सत्यापित कर सकते हैं, उपरोक्त प्रत्येक पंक्ति शेल के लिए एक एकल शब्द है। उद्धरण (एकल या दोहरे उद्धरण, स्थिति पर निर्भर करता है) शब्दों को अलग नहीं करते हैं। उनका उपयोग केवल विभिन्न विशेष वर्णों की व्याख्या को अक्षम करने के लिए किया जाता है, जैसे कि व्हाट्सएप $, ;... मार्क रीड के उत्तर को देखने के लिए एक अच्छे ट्यूटोरियल के लिए। इसके अलावा प्रासंगिक: कौन से पात्रों को बैश में भागने की आवश्यकता है?

खोल द्वारा व्याख्या किए गए तारों को समतल न करें

आपको चर को समाप्‍त करके शेल कमांड बनाने से पूरी तरह बचना चाहिए। यह एसक्यूएल के टुकड़े (एसक्यूएल इंजेक्शन!) के समान है।

आमतौर पर कमांड में प्लेसहोल्डर्स रखना संभव होता है, और कमांड को चर के साथ एक साथ आपूर्ति करना ताकि कैली उन्हें मंगलाचरण तर्क सूची से प्राप्त कर सकें।

उदाहरण के लिए, निम्नलिखित बहुत असुरक्षित है। यह मत करो

script="echo \"Argument 1 is: $myvar\""
/bin/sh -c "$script"

यदि सामग्री $myvarअविश्वासित है, तो यहां एक शोषण है:

myvar='foo"; echo "you were hacked'

उपरोक्त आह्वान के बजाय, स्थिति संबंधी तर्कों का उपयोग करें। निम्नलिखित आह्वान बेहतर है - यह शोषक नहीं है:

script='echo "arg 1 is: $1"'
/bin/sh -c "$script" -- "$myvar"

असाइनमेंट में एकल टिक्स के उपयोग पर ध्यान दें script, जिसका अर्थ है कि यह शाब्दिक रूप से लिया गया है, चर विस्तार या किसी अन्य व्याख्या के बिना।


@ Jo.SO काम नहीं करेगा। क्योंकि पहले उद्धरण बंद होने तक रेपो कमांड केवल पैरामीटर लेगी। उसके बाद कुछ भी रेपो के लिए अनदेखा किया जाएगा और एक और त्रुटि उत्पन्न करेगा।
राचिट

8
@ राचिट - शेल उस तरह से काम नहीं करता है। "some"thing' like'thisखोल के लिए एक शब्द है। उद्धरण चिह्न किसी भी चीज़ को समाप्त नहीं करते हैं जहां तक ​​पार्सिंग का संबंध है, और शेल द्वारा बताई गई कमांड के लिए कोई रास्ता नहीं है कि यह कैसे उद्धृत किया गया था।
मार्क रीड रीड

3
वह दूसरा वाक्य ("आप सिंगल कोट्स से बच भी नहीं सकते") सिंगल कोट्स को शेल के ब्लैक होल बनाता है।

@Evert: यह बेहतर कैसे कहना नहीं जानता। मैंने वाक्य हटा दिया है।
जो

@ जोसो यह शर्म की बात है: कोई भी मजाक सपाट नहीं होता है।

96

repoआदेश की परवाह नहीं कर सकते हैं उद्धरण किस तरह यह हो जाता है। यदि आपको पैरामीटर विस्तार की आवश्यकता है, तो दोहरे उद्धरण चिह्नों का उपयोग करें। यदि इसका मतलब है कि आप बहुत सारे सामान को बैकस्लैश कर रहे हैं, तो इसमें से अधिकांश के लिए सिंगल कोट्स का उपयोग करें, और फिर उनमें से तोड़कर उस हिस्से के लिए डबल्स में जाएं जहां आपको विस्तार की आवश्यकता है।

repo forall -c 'literal stuff goes here; '"stuff with $parameters here"' more literal stuff'

यदि आप रुचि रखते हैं, तो स्पष्टीकरण इस प्रकार है।

जब आप शेल से एक कमांड चलाते हैं, तो उस कमांड को तर्कों के रूप में प्राप्त होता है, जो शून्य-समाप्त स्ट्रिंग्स की एक सरणी है। उन तार पूरी तरह से हो सकती है किसी भी गैर-शून्य चरित्र।

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

आप किसी अक्षर के सामने एक बैकस्लैश का उपयोग कर सकते हैं (अंतरिक्ष, या किसी अन्य बैकस्लैश सहित), इस अक्षर को अक्षरशः व्यवहार करने के लिए शेल को बताने के लिए। लेकिन जब आप ऐसा कुछ कर सकते हैं:

echo \"Thank\ you.\ \ That\'ll\ be\ \$4.96,\ please,\"\ said\ the\ cashier

... यह थकाऊ हो सकता है। तो शेल एक विकल्प प्रदान करता है: उद्धरण चिह्न। ये दो मुख्य किस्मों में आते हैं।

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

echo "\"Thank you. That'll be \$4.96, please,\" said the cashier"

एकल-उद्धरण चिह्न अधिक ड्रैकियन हैं। उनके बीच सब कुछ पूरी तरह से शाब्दिक रूप से लिया जाता है, जिसमें बैकस्लैश भी शामिल है। एकल उद्धरणों के अंदर शाब्दिक एकल उद्धरण प्राप्त करने का कोई तरीका नहीं है।

सौभाग्य से, खोल में उद्धरण चिह्न शब्द सीमांकक नहीं हैं ; अपने आप से, वे एक शब्द को समाप्त नहीं करते हैं। आप वांछित परिणाम प्राप्त करने के लिए एक ही शब्द के भीतर उद्धरणों के विभिन्न प्रकारों सहित, अंदर और बाहर जा सकते हैं:

echo '"Thank you. That'\''ll be $4.96, please," said the cashier'

तो यह आसान है - बहुत कम बैकस्लैश, हालांकि क्लोज-सिंगल-कोट, बैकस्लेशेड-शाब्दिक-सिंगल-कोट, ओपन-सिंगल-क्वैस सीक्वेंस में कुछ आदतें लग जाती हैं।

आधुनिक गोले ने एक और उद्धरण शैली जोड़ दी है जो पोसिक्स मानक द्वारा निर्दिष्ट नहीं है, जिसमें अग्रणी एकल उद्धरण चिह्न एक डॉलर चिह्न के साथ उपसर्ग है। स्ट्रिंग को एएनएसआई सी प्रोग्रामिंग भाषा में स्ट्रिंग शाब्दिक के समान सम्मेलनों के रूप में उद्धृत किया जाता है, और इसलिए कभी-कभी "एएनएसआई स्ट्रिंग्स" और $'... 'जोड़ी "एएनएसआई उद्धरण" कहा जाता है। इस तरह के तार के भीतर, बैकस्लैश के बारे में उपरोक्त सलाह का शाब्दिक अर्थ अब लागू नहीं होता है। इसके बजाय, वे फिर से विशेष हो जाते हैं - न केवल आप एक शाब्दिक उद्धरण उद्धरण या बैकस्लैश को इसमें शामिल कर सकते हैं, बल्कि शेल एएनएसआई सी अक्षर से बाहर निकलता है (जैसे \nएक नई पंक्ति के लिए, \tटैब के लिए, और \xHHचरित्र के लिए) हेक्साडेसिमल कोडHH)। अन्यथा, हालांकि, वे एकल-उद्धृत स्ट्रिंग्स के रूप में व्यवहार करते हैं: कोई पैरामीटर या कमांड प्रतिस्थापन नहीं होता है:

echo $'"Thank you.  That\'ll be $4.96, please," said the cashier'

ध्यान देने वाली महत्वपूर्ण बात यह है कि echoकमांड के तर्क के रूप में प्राप्त एकल स्ट्रिंग इन सभी उदाहरणों में बिल्कुल समान है। शेल को एक कमांड लाइन पार्स करने के बाद, कमांड को चलाने के लिए कोई रास्ता नहीं है यह बताने के लिए कि कैसे उद्धृत किया गया था। चाहने पर भी।


2
हाँ। मैं अब समझता हूँ। यह पूरी तरह से काम करता है। आपकी सहायता के लिए धन्यवाद!
राचिट

6
यह जवाब कमाल का था।
विनियस फेरो

1
क्या $'string'प्रारूप POSIX अनुपालन है? इसके अलावा, क्या इसका कोई नाम है?
वाइल्डकार्ड

2
@Wildcard $'string'एक गैर-POSIX एक्सटेंशन है, जिसे मैंने "ANSI स्ट्रिंग्स" के रूप में संदर्भित किया है; मैंने उत्तर में उन तथ्यों को शामिल किया है। इस तरह के तार अधिकांश आधुनिक बॉर्न-संगत गोले में काम करते हैं: बैश, डैश, ksh (एटी एंड टी और पीडी दोनों), और zsh सभी उनका समर्थन करते हैं।
मार्क रीड

1
लिंक वापस - कमांड लाइन के तर्कों में किन वर्णों के भाग जाने की आवश्यकता है? यूनिक्स और लिनक्स स्टैक एक्सचेंज पर।
वाइल्डकार्ड

3

नीचे मेरे लिए क्या काम किया गया है -

QUOTE="'"
hive -e "alter table TBL_NAME set location $QUOTE$TBL_HDFS_DIR_PATH$QUOTE"

2
मुझे उम्मीद है कि TBL_HDFS_DIR_PATH उपयोगकर्ता को इनपुट btw प्रदान नहीं करता है, यह एक अच्छा sql इंजेक्शन की अनुमति देगा ...
domenukk

1
QUOTEएक अलग चर में डाल पूरी तरह से सतही है; डबल कोट्स के अंदर सिंगल कोट्स एक रेगुलर कैरेक्टर हैं। (इसके अलावा, अपने निजी चर के लिए ऊपरी मामले का उपयोग न करें।)
13

2

संपादित करें: (प्रश्न में टिप्पणियों के अनुसार :)

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


आपकी मदद के लिए धन्यवाद केविन।
राचिट

2

बस प्रिंटफ का उपयोग करें

के बजाय

repo forall -c '....$variable'

विस्तारित चर के साथ चर टोकन को बदलने के लिए प्रिंटफ का उपयोग करें।

उदाहरण के लिए:

template='.... %s'

repo forall -c $(printf "${template}" "${variable}")

यह टूट गया; printfवास्तव में आप यहाँ कुछ भी नहीं खरीदते हैं, और कमांड सबसिट्रेशन को उद्धृत करने में विफल होने से नए उद्धरण समस्याओं का कारण बनता है।
त्रिकाल

0

चर में एकल उद्धरण हो सकते हैं।

myvar=\'....$variable\'

repo forall -c $myvar

वे कर सकते हैं, लेकिन यह ऐसा करने का सही तरीका नहीं है - आपको अभी भी "$myvar"दोहरे उद्धरण चिह्नों में रखना चाहिए ।
ट्रिपल

-2

क्या यह आपके लिए कार्य करता है?

eval repo forall -c '....$variable'

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