एक कमांड के तर्कों में एक सरणी बदलना?


39

मेरे पास एक कमांड के "विकल्प" की एक सरणी है।

my_array=(option1 option2 option3)

मैं विकल्प के रूप में सरणी से मानों का उपयोग करके इस कमांड को बैश स्क्रिप्ट में कॉल करना चाहता हूं। तो, command $(some magic here with my_array) "$1"बन जाता है:

command -option1 -option2 -option3 "$1"

मैं यह कैसे कर सकता हूं? क्या यह संभव है?


1
तो आप -प्रत्येक शब्द की शुरुआत में जोड़ना चाहते हैं my_array?
केविन

@ केविन: हाँ, और इसे निष्पादित करें। सभी लाइनें एक ही बैश स्क्रिप्ट के अंदर हैं। मैं यह पूछ रहा हूं क्योंकि ये समान विकल्प स्क्रिप्ट के अंदर बहुत सारे स्थानों पर उपयोग किए जाने वाले हैं, इसलिए इन सभी को चारों ओर से कॉपी करने के बजाय, मैंने एक सरणी के बारे में सोचा।
कोई व्यक्ति अभी भी आपको

1
यह व्यर्थ लग सकता है, लेकिन अगर आप बड़ी शेल स्क्रिप्ट बना रहे हैं, तो शायद आपको भी इस पर गौर करना चाहिए, इस तरह की बात करना बहुत आसान है।
एल्फा ६४

जवाबों:


43

मैं एक सादा bashतरीका पसंद करूंगा :

command "${my_array[@]/#/-}" "$1"

इसका एक कारण रिक्त स्थान हैं। उदाहरण के लिए यदि आपके पास:

my_array=(option1 'option2 with space' option3)

sedआधारित समाधान में यह बदल सकते हैं -option1 -option2 -with -space -option3(लंबाई 5), लेकिन इसके बाद के संस्करण bashविस्तार में बदलने जाएगा -option1 -option2 with space -option3(लंबाई अभी भी 3)। शायद ही कभी, लेकिन कभी-कभी यह महत्वपूर्ण होता है, उदाहरण के लिए:

bash-4.2$ my_array=('Ffoo bar' 'vOFS=fiz baz')
bash-4.2$ echo 'one foo bar two foo bar three foo bar four' | awk "${my_array[@]/#/-}" '{print$2,$3}'
 two fiz baz three

अगर मैं सही ढंग से समझूं, तो इस चर प्रतिस्थापन को एक फ़ंक्शन में नहीं लपेटा जा सकता है, और न ही एक चर को सौंपा जा सकता है, है ना? इसे सीधे कमांड इनवोकेशन में जाने की जरूरत है।
कोनराड रूडोल्फ

1
@KonradRudolph, आप इसे दूसरे वेरिएबल को तब तक असाइन कर सकते हैं जब तक आप इसे एरे असाइनमेंट के रूप में करते हैं: somevar=("${my_array[@]/#/-}")(मान के चारों ओर कोष्ठक पर ध्यान दें।) तब निश्चित रूप से आपको इसे उपयोग करते समय ऐरे के रूप में संभाल कर रखना होगा echo "${somevar[@]}":। कार्यों के संबंध में, आप भाषा की संभावनाओं से बहुत सीमित हैं। : आप एक सरणी पारित कर सकते हैं somefunc "${my_array[@]/#/-}"अंदर आप इसे में होगा तो, $@: function somefunc() { echo "$@"; }। लेकिन $@इसमें अन्य पैरामीटर भी होंगे, यदि मौजूद है, और स्टडआउट की तुलना में संशोधित सरणी को वापस करने का कोई अन्य तरीका नहीं है।
manatwork

अजीब पर्याप्त है, zsh के साथ काम नहीं करता है। पहली बार मैंने किसी ऐसी चीज पर ठोकर खाई जो बाश में काम करती है लेकिन zsh में नहीं।
हाय-एंजेल

@ हाय-एंजेल, क्या आप सुनिश्चित हैं कि आपने @सरणी सबस्क्रिप्ट के रूप में उपयोग किया है ? मैंने इसे zsh 5.5.1 के साथ एक परीक्षण दिया और एकमात्र अंतर जो मैंने देखा कि zsh ने केवल प्रत्येक आइटम को जब लिखा गया था तब उपसर्ग किया ${my_array[@]/#/-}, जबकि बैश ने इसे *सबस्क्रिप्ट के लिए भी किया।
manatwork

ओह, क्षमा करें, मैंने कुछ खराब कर दिया है, वास्तव में मेरे लिए काम करता है!
हाय-एंजेल

2

मैंने यह प्रक्रिया नहीं की कि यह एक सरणी में था और एक स्ट्रिंग में व्हाट्सएप-अलग होने के बारे में सोच रहा था। यह समाधान उस के साथ काम करेगा, लेकिन यह देखते हुए कि यह एक सरणी है, मैनटवर्क के समाधान ( @{my_array[@]/#/-}) के साथ जाएं ।


यह बहुत खराब नहीं है sedऔर एक उपधारा है। रेगेक्स कितना आसान है यह इस बात पर निर्भर करता है कि आप विकल्पों के बारे में क्या गारंटी दे सकते हैं। यदि विकल्प सभी एक "शब्द" ( a-zA-Z0-9केवल) हैं, तो एक सरल शुरुआत शब्द सीमा ( \<) पर्याप्त होगी:

command $(echo $my_array | sed 's/\</-/g') "$1"

यदि आपके विकल्पों में अन्य वर्ण हैं (सबसे अधिक संभावना है -), तो आपको कुछ अधिक जटिल की आवश्यकता होगी:

command $(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g') "$1"

^लाइन की शुरुआत से [ \t]मेल खाता है , एक स्थान या टैब से \|मेल खाता है , या तो पक्ष ( ^या [ \t]), \( \)समूहों (के लिए \|) से \<मेल खाता है और परिणाम को संग्रहीत करता है, एक शब्द की शुरुआत से मेल खाता है। \1पहले मैच को पैरेंस ( \(\)) से रख कर रिप्लेसमेंट शुरू करता है , और -निश्चित रूप से उस डैश को जोड़ता है जिसकी हमें जरूरत है।

ग्नू सेड के साथ ये काम, अगर वे आपके साथ काम नहीं करते हैं, तो मुझे बताएं।

और यदि आप एक ही चीज़ का कई बार उपयोग कर रहे हैं, तो आप बस एक बार उसकी गणना करके उसे स्टोर कर सकते हैं:

opts="$(echo $my_array | sed 's/\(^\|[ \t]\)\</\1-/g')"
...
command $opts "$1"
command $opts "$2"

यह मैक ओएस एक्स सेड के साथ काम नहीं करता था, इसलिए मुझे उपयोग करने की आवश्यकता थी gsed(मैंने उपयोग करके स्थापित किया homebrew)। एक और बात: इसके बजाय echo $my_array, मुझे echo ${my_array[@]}सभी वस्तुओं को प्राप्त करने के लिए करने की आवश्यकता थी my_array: echo $my_arrayमुझे केवल पहला तत्व दे रहा था। लेकिन विशेष रूप से "शब्द सीमा" के बारे में रेगेक्स के उत्तर और स्पष्टीकरण के लिए धन्यवाद, यह बेहद उपयोगी है। :)
कोई अभी भी आपको

मैं स्क्रिप्ट से बाहर निकलना चाहूंगा अगर सिस्टम का सेड इस शब्द सीमा विशेषता के साथ संगत नहीं है। मैं यह कैसे करूंगा? मुद्रण sed संस्करण और इसकी तुलना? सीड के किस संस्करण से यह सुविधा जोड़ी गई थी?
कोई अभी भी आप

1
@ SomebodystillusesyouMS-DOS मेरा पहला विचार सीधे जाँच करना है कि क्या यह काम करता है - [ $(echo x | sed 's/\</y/') == "yx" ] || exit
केविन

2
यह तब टूटेगा जब किसी भी सरणी तत्व में विशेष वर्ण होंगे, सबसे स्पष्ट और अक्षम रूप से व्हाट्सएप।
गिलेस एसओ-

1
@ SomebodystillusesyouMS-DOS Gilles सही है, आपको अपनी स्वीकृति को मैनटवर्क में बदलना चाहिए।
केविन

0
[srikanth@myhost ~]$ sh sample.sh 

-option1 -option2 -option3

[srikanth@myhost ~]$ cat sample.sh

#!/bin/bash

my_array=(option1 option2 option3)

echo ${my_array[@]} | sed 's/\</-/g'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.