मैं बैश में एक सरणी के तत्वों को कैसे जोड़ सकता हूं?


416

अगर मेरे पास बाश में इस तरह की एक सरणी है:

FOO=( a b c )

मैं तत्वों को कॉमा के साथ कैसे जोड़ूं? उदाहरण के लिए, उत्पादन a,b,c

जवाबों:


571

100% शुद्ध बैश (कोई बाहरी आदेश) में एक समारोह के रूप में पास्कल पिल्ज़ द्वारा पुनर्लेखन समाधान:

function join_by { local IFS="$1"; shift; echo "$*"; }

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

join_by , a "b c" d #a,b c,d
join_by / var local tmp #var/local/tmp
join_by , "${FOO[@]}" #a,b,c

वैकल्पिक रूप से, हम मल्टी-कैरेक्टर सीमांकक का समर्थन करने के लिए प्रिंट का उपयोग कर सकते हैं, @gniourf_gniourf द्वारा विचार का उपयोग कर

function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }

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

join_by , a b c #a,b,c
join_by ' , ' a b c #a , b , c
join_by ')|(' a b c #a)|(b)|(c
join_by ' %s ' a b c #a %s b %s c
join_by $'\n' a b c #a<newline>b<newline>c
join_by - a b c #a-b-c
join_by '\' a b c #a\b\c

9
मल्टीचैकर विभाजकों के लिए इसका उपयोग करें: समारोह में शामिल हों {perl -e '$ s = shift @ARGV; प्रिंट जॉइन ($ s, @ARGV);) "$ @"; } join ',' abc # a, b, c
डैनियल पटरू

4
@dpatru वैसे भी उस शुद्ध बैश बनाने के लिए?
CMCDragonkai

4
@puchu क्या काम नहीं करता है बहु चरित्र विभाजक है। "अंतरिक्ष काम नहीं करता है" कहने के लिए यह ध्वनि की तरह है कि अंतरिक्ष के साथ जुड़ने से काम नहीं चलता है। ऐसा होता है।
एरिक

6
यह स्पॉन सबस्क्रिप्शन को बढ़ावा देता है अगर आउटपुट को वेरिएबल में स्टोर किया जाए। konsoleboxशैली का उपयोग करें :) function join { local IFS=$1; __="${*:2}"; }या function join { IFS=$1 eval '__="${*:2}"'; }। इसके __बाद उपयोग करें । हां, मैं __एक परिणाम चर के रूप में उपयोग को बढ़ावा देने वाला हूं ;) (और एक सामान्य पुनरावृत्ति चर या अस्थायी चर)। यदि अवधारणा एक लोकप्रिय बैश विकी साइट पर मिलती है, तो उन्होंने मुझे :) :)
konsolebox

6
विस्तार $dको प्रारूप प्रारूप में न रखें printf। आपको लगता है कि आप "बच गए" से सुरक्षित हैं, %लेकिन अन्य चेतावनी भी हैं: जब सीमांकक में एक बैकस्लैश (जैसे \n) या तब होता है जब सीमांकक एक हाइफ़न के साथ शुरू होता है (और शायद अन्य मैं अब सोच भी नहीं सकता)। आप निश्चित रूप से इन्हें ठीक कर सकते हैं (बैकस्लैश को डबल बैकस्लैश और उपयोग द्वारा प्रतिस्थापित करें printf -- "$d%s"), लेकिन कुछ बिंदु पर आपको लगेगा कि आप इसके साथ काम करने के बजाय शेल के खिलाफ लड़ रहे हैं। इसीलिए, नीचे दिए गए मेरे उत्तर में, मैंने परिसीमन में शामिल होने की शर्तों को पूर्व निर्धारित किया।
गनीउर्फ़_ग्निउरफ़

206

अभी तक एक और समाधान:

#!/bin/bash
foo=('foo bar' 'foo baz' 'bar baz')
bar=$(printf ",%s" "${foo[@]}")
bar=${bar:1}

echo $bar

संपादित करें: लेकिन बहु-वर्ण चर लंबाई विभाजक के लिए समान:

#!/bin/bash
separator=")|(" # e.g. constructing regex, pray it does not contain %s
foo=('foo bar' 'foo baz' 'bar baz')
regex="$( printf "${separator}%s" "${foo[@]}" )"
regex="${regex:${#separator}}" # remove leading separator
echo "${regex}"
# Prints: foo bar)|(foo baz)|(bar baz

7
+1। किस बारे में printf -v bar ",%s" "${foo[@]}"? यह एक forkकम (वास्तव में clone) है। यह भी एक फ़ाइल को पढ़ने forking है: printf -v bar ",%s" $(<infile)
ट्रू यॉन

14
प्रार्थना करने के बजाय $separatorइसमें %sया ऐसा नहीं है , आप अपनी printfताकत बना सकते हैं printf "%s%s" "$separator" "${foo[@]}":।
मुशीफिल

5
@ मुसिफिल गलत। बैश मैन से: "प्रारूप को सभी तर्कों का उपभोग करने के लिए आवश्यक के रूप में पुन: उपयोग किया जाता है। जैसे दो प्रारूप प्लेसहोल्डर्स का printf "%s%s"उपयोग करना, पहली बार आउटपुट के पहले सेट में विभाजक का उपयोग करेगा, और उसके बाद केवल शेष तर्क को
सम्‍मिलित करें

3
@AndrDevEK: गलती पकड़ने के लिए धन्यवाद। इसके बजाय मैं कुछ सुझाव दूंगा printf "%s" "${foo[@]/#/$separator}"
मुसीफिल

2
@ मुसिफिल, धन्यवाद। हाँ! फिर प्रिंटफ निरर्थक हो जाता है और उस लाइन को कम किया जा सकता है IFS=; regex="${foo[*]/#/$separator}"। इस बिंदु पर यह अनिवार्य रूप से gniourf_gniourf का उत्तर बन जाता है जो IMO शुरू से ही क्लीनर है, अर्थात IFS परिवर्तनों और अस्थायी vars के दायरे को सीमित करने के लिए फ़ंक्शन का उपयोग करता है।
AnyDev

145
$ foo=(a "b c" d)
$ bar=$(IFS=, ; echo "${foo[*]}")
$ echo "$bar"
a,b c,d

3
बाहरी दोहरे उद्धरण और बृहदान्त्र के चारों ओर दोहरे उद्धरण आवश्यक नहीं हैं। केवल आंतरिक दोहरे उद्धरण आवश्यक हैं:bar=$( IFS=, ; echo "${foo[*]}" )
9

8
सबसे कॉम्पैक्ट समाधान के लिए +1 जिसमें छोरों की आवश्यकता नहीं होती है, जिसे बाहरी आदेशों की आवश्यकता नहीं होती है और जो तर्कों के चरित्र सेट पर अतिरिक्त प्रतिबंध नहीं लगाता है।
10

22
मुझे समाधान पसंद है, लेकिन यह केवल तभी काम करता है जब IFS एक चरित्र है
Jayen

8
किसी भी विचार क्यों यह काम नहीं करता है अगर के @बजाय का उपयोग कर *, के रूप में $(IFS=, ; echo "${foo[@]}")? मैं देख सकता हूं कि *पहले से ही तत्वों में व्हाट्सएप को संरक्षित करता है, फिर से सुनिश्चित नहीं है कि, चूंकि @आमतौर पर इस खातिर आवश्यक है।
haridsv

10
मुझे अपने ही सवाल का जवाब ऊपर मिला। इसका उत्तर यह है कि IFS के लिए ही मान्यता प्राप्त है *। बैश मैन पेज में, "स्पेशल पैरामीटर्स" की खोज करें और आगे के स्पष्टीकरण की तलाश करें *:
haridsv

66

शायद, जैसे,

SAVE_IFS="$IFS"
IFS=","
FOOJOIN="${FOO[*]}"
IFS="$SAVE_IFS"

echo "$FOOJOIN"

3
यदि आप ऐसा करते हैं, तो यह सोचता है कि IFS- चर है। आपको करना होगा echo "-${IFS}-"(घुंघराले ब्रेसिज़ को वैरिएबल नाम से अलग करते हैं)।
अगली सूचना तक रोक दिया गया।

1
अभी भी एक ही परिणाम मिला (मैं बिंदु को स्पष्ट करने के लिए डैश लगाता हूं ... echo $IFSएक ही काम करता है।
डेविड वोलेवर

41
उस ने कहा, यह अभी भी काम करने लगता है ... इसलिए, बैश के साथ अधिकांश चीजों की तरह, मैं इसे दिखावा करूंगा जैसे मैं इसे समझता हूं और अपने जीवन के साथ मिलता हूं।
डेविड वोलेवर 20

2
एक "-" एक चर नाम के लिए एक वैध चरित्र नहीं है, इसलिए शेल $ IFS- का उपयोग करते समय सही काम करता है, आपको $ {IFS} की आवश्यकता नहीं है - (linash और Solaris में bash, ksh, sh और zsh) भी सहमत)।
इडेलिक

2
@ आपकी प्रतिध्वनि और डेनिस के बीच अंतर यह है कि उन्होंने दोहरे उद्धरण का उपयोग किया है। IFS की सामग्री को 'इनपुट पर' शब्द-विभाजक वर्णों की घोषणा के रूप में प्रयोग किया जाता है - इसलिए आपको हमेशा उद्धरण के बिना एक खाली रेखा मिलेगी।
21-28

30

आश्चर्यजनक रूप से मेरा समाधान अभी तक नहीं दिया गया है :) यह मेरे लिए सबसे सरल तरीका है। यह एक समारोह की जरूरत नहीं है:

IFS=, eval 'joined="${foo[*]}"'

नोट: यह समाधान गैर-पॉसिक्स मोड में अच्छी तरह से काम करने के लिए देखा गया था। में POSIX मोड , तत्व अभी भी ठीक से शामिल हुए, लेकिन कर रहे हैं IFS=,स्थायी हो जाता है।


दुर्भाग्य से केवल एकल चरित्र के लिए काम करता है delimiters
maoizm

24

यहां 100% शुद्ध बैश फ़ंक्शन है जो काम करता है:

join() {
    # $1 is return variable name
    # $2 is sep
    # $3... are the elements to join
    local retname=$1 sep=$2 ret=$3
    shift 3 || shift $(($#))
    printf -v "$retname" "%s" "$ret${@/#/$sep}"
}

देखो:

$ a=( one two "three three" four five )
$ join joineda " and " "${a[@]}"
$ echo "$joineda"
one and two and three three and four and five
$ join joinedb randomsep "only one element"
$ echo "$joinedb"
only one element
$ join joinedc randomsep
$ echo "$joinedc"

$ a=( $' stuff with\nnewlines\n' $'and trailing newlines\n\n' )
$ join joineda $'a sep with\nnewlines\n' "${a[@]}"
$ echo "$joineda"
 stuff with
newlines
a sep with
newlines
and trailing newlines


$

यह भी अनुगामी newlines को संरक्षित करता है, और फ़ंक्शन के परिणाम प्राप्त करने के लिए एक उप-संस्करण की आवश्यकता नहीं है। यदि आपको कोई पसंद नहीं है printf -v(आप इसे क्यों पसंद नहीं करेंगे?) और एक चर नाम से गुजर रहा है, तो आप निश्चित रूप से लौटे हुए के लिए एक वैश्विक चर का उपयोग कर सकते हैं:

join() {
    # $1 is sep
    # $2... are the elements to join
    # return is in global variable join_ret
    local sep=$1 IFS=
    join_ret=$2
    shift 2 || shift $(($#))
    join_ret+="${*/#/$sep}"
}

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

1
@JamesSneeringer मैंने जानबूझकर इस डिज़ाइन का उपयोग किया ताकि सब-सब्सक्रिप्शन से बचा जा सके। शेल स्क्रिप्टिंग में, कई अन्य भाषाओं के विपरीत, वैश्विक चर का उपयोग उस तरह से जरूरी नहीं है कि एक बुरी चीज है; विशेष रूप से अगर वे यहां उप-वर्गों से बचने में मदद करने के लिए हैं। इसके अलावा, $(...)ट्रिमिंग नईलाइन्स; इसलिए यदि सरणी के अंतिम क्षेत्र में नई अनुगामी शामिल हैं, तो इन्हें ट्रिम किया जाएगा (डेमो देखें जहां वे मेरे डिज़ाइन के साथ ट्रिम नहीं किए गए हैं)।
गनीउर्फ़_निगियॉर्फ

यह मल्टी-कैरेक्टर
सेपरेटर्स के

"क्यों आप प्रिंटफ-वी पसंद नहीं करेंगे?" को संबोधित करने के लिए: बाश में, स्थानीय चर वास्तव में फ़ंक्शन-स्थानीय नहीं हैं, इसलिए आप इस तरह की चीजें कर सकते हैं। (स्थानीय चर x के साथ कॉल फ़ंक्शन f1, जो बदले में फ़ंक्शन f2 को कॉल करता है जो x को संशोधित करता है - जिसे f1 के दायरे में स्थानीय घोषित किया जाता है) लेकिन यह वास्तव में नहीं है कि स्थानीय चर कैसे काम करें। यदि स्थानीय चर वास्तव में स्थानीय हैं (या माना जाता है, उदाहरण के लिए एक स्क्रिप्ट में जो बश और ksh दोनों पर काम करना चाहिए) तो यह इस "इस नाम के साथ चर में संग्रहित करके एक मान लौटाता है"।
tetsujin

15

यह सभी मौजूदा समाधानों से बहुत अलग नहीं है, लेकिन यह एक अलग फ़ंक्शन का उपयोग करने से बचता है, IFSमूल शेल में संशोधित नहीं होता है और सभी एक एकल में हैं:

arr=(a b c)
printf '%s\n' "$(IFS=,; printf '%s' "${arr[*]}")"

जिसके परिणामस्वरूप

a,b,c

सीमा: विभाजक एक वर्ण से अधिक लंबा नहीं हो सकता है।


13

कोई बाहरी आदेश का उपयोग करना:

$ FOO=( a b c )     # initialize the array
$ BAR=${FOO[@]}     # create a space delimited string from array
$ BAZ=${BAR// /,}   # use parameter expansion to substitute spaces with comma
$ echo $BAZ
a,b,c

चेतावनी, यह मानता है कि तत्वों में व्हाट्सएप नहीं है।


4
यदि आप एक मध्यवर्ती चर का उपयोग नहीं करना चाहते हैं, तो इसे और भी कम किया जा सकता है:echo ${FOO[@]} | tr ' ' ','
jesjimher

2
मैं नकारात्मक मतों को नहीं समझता। यह यहां पोस्ट किए गए अन्य की तुलना में बहुत कॉम्पैक्ट और पठनीय समाधान है, और यह स्पष्ट रूप से चेतावनी दी है कि जब रिक्त स्थान होते हैं तो यह काम नहीं करता है।
jesjimher

12

मैं एक स्ट्रिंग के रूप में सरणी को प्रतिध्वनित करूंगा, फिर रिक्त स्थान को लाइन फीड में रूपांतरित करूंगा, और फिर pasteसब कुछ एक पंक्ति में शामिल करने के लिए उपयोग करूंगा जैसे:

tr " " "\n" <<< "$FOO" | paste -sd , -

परिणाम:

a,b,c

यह मुझे सबसे तेज और सबसे साफ लगता है!


$FOOहालांकि, सरणी का पहला तत्व है। इसके अलावा, यह रिक्त स्थान वाले सरणी तत्वों के लिए टूटता है।
बेंजामिन डब्ल्यू।

9

@ के पुन: उपयोग से 'कोई फर्क नहीं पड़ता' समाधान, लेकिन एक बयान के साथ $ {: 1} सबस्टेशन और इंटरमीडिएट चर की जरूरत से बचना चाहिए।

echo $(printf "%s," "${LIST[@]}" | cut -d "," -f 1-${#LIST[@]} )

प्रिंटफ में 'प्रारूप स्ट्रिंग का उपयोग तर्कों को संतुष्ट करने के लिए अक्सर आवश्यक रूप से किया जाता है।' इसके मैन पेजों में, ताकि स्ट्रिंग्स के कॉन्टैक्शंस को प्रलेखित किया जाए। फिर ट्रिक अंतिम स्पिंटर को काटने के लिए LIST की लंबाई का उपयोग करने के लिए है, क्योंकि कट केवल फ़ील्ड की गिनती के दौरान LIST के लेन को बनाए रखेगा।


7
s=$(IFS=, eval 'echo "${FOO[*]}"')

8
आपको अपना जवाब देना चाहिए।
जॉसे

बहुत ही बेहतरीन। धन्यवाद!!
पीटर पैन gz

4
काश मैं इस उत्तर को अस्वीकार कर सकता क्योंकि यह एक सुरक्षा छेद खोलता है और क्योंकि यह तत्वों में रिक्त स्थान को नष्ट कर देगा।
eel ghEEz

1
@ बीएक्सएम वास्तव में, यह रिक्त स्थान को संरक्षित करने के लिए लगता है और यह गूंज तर्कों के संदर्भ से बचने की अनुमति नहीं देता है। मुझे लगा कि जोड़ने @Qसे गलत तरीके से जुड़ने से बच सकते हैं, जब वे उनके साथ foo=("a ," "b ' ' c" "' 'd e" "f " ";" "ls -latr"); s=$(IFS=, eval 'echo "${foo[*]@Q}"'); echo "${s}"'a ,','b '\'' '\'' c',''\'' '\''d e','f ',';','ls -latr '
जुड़ेंगे

1
जब तक आवश्यक न हो, समाधानों का उपयोग करने से बचें।
कोनोस्कोप

5

प्रिंटफ़ समाधान जो किसी भी लम्बाई के विभाजकों को स्वीकार करता है (@ के आधार पर जवाब नहीं देता है)

#/!bin/bash
foo=('foo bar' 'foo baz' 'bar baz')

sep=',' # can be of any length
bar=$(printf "${sep}%s" "${foo[@]}")
bar=${bar:${#sep}}

echo $bar

यह एक प्रमुख अल्पविराम के साथ उत्पादन करता है।
मार्क रेनॉफ

अंतिम बार = $ {बार: $ {# sep}} विभाजक को हटाता है। मैं बस एक बैश शेल में कॉपी और पेस्ट करता हूं और यह काम करता है। आप किस खोल का उपयोग कर रहे हैं?
रिकार्डो गली

2
कोई भी printf प्रारूप निर्दिष्ट करने वाला (जैसे। %sअनायास $sepही समस्याओं का कारण होगा।
पीटर

sepके साथ सैनिटाइज किया जा सकता है ${sep//\%/%%}। मुझे आपका समाधान ( ${bar#${sep}}या ${bar%${sep}}वैकल्पिक) से बेहतर लगता है । यह अच्छा है अगर एक फ़ंक्शन में परिवर्तित किया जाता है जो स्टोर का परिणाम जेनेरिक चर की तरह होता है __, और echoयह नहीं ।
कोनोकोलबॉक्स

function join_by { printf -v __ "${1//\%/%%}%s" "${@:2}"; __=${__:${#1}}; }
konsolebox

4
$ set a 'b c' d

$ history -p "$@" | paste -sd,
a,b c,d

यह सबसे ऊपर होना चाहिए।
एरिक वॉकर

6
यह शीर्ष पर नहीं होना चाहिए: क्या होगा अगर HISTSIZE=0?
हर-वादीम

@ har-wradim, ट्रिक paste -sd,इतिहास के उपयोग के बारे में नहीं है।
वेद

@ वेदा नहीं, यह संयोजन के उपयोग के बारे में है, और यह काम नहीं करेगा अगर HISTSIZE=0- इसे आज़माएं।
हर-वीरिम

4

शीर्ष उत्तर का छोटा संस्करण:

joinStrings() { local a=("${@:3}"); printf "%s" "$2${a[@]/#/$1}"; }

उपयोग:

joinStrings "$myDelimiter" "${myArray[@]}"

1
एक लंबा संस्करण है, लेकिन किसी सरणी चर के लिए तर्कों के एक स्लाइस की प्रतिलिपि बनाने की आवश्यकता नहीं है:join_strings () { local d="$1"; echo -n "$2"; shift 2 && printf '%s' "${@/#/$d}"; }
रॉकलाईट

अभी तक एक और संस्करण: join_strings () { local d="$1"; echo -n "$2"; shift 2 && printf '$d%s' "${@}"; } यह उपयोग के साथ काम करता है: join_strings 'delim' "${array[@]}"या join_strings 'delim' ${array[@]}
निर्विवाद

4

निम्नलिखित विचार के साथ अब तक की सभी दुनियाओं में सर्वश्रेष्ठ का मिश्रण करें।

# join with separator
join_ws()  { local IFS=; local s="${*/#/$1}"; echo "${s#"$1$1$1"}"; }

यह छोटी कृति है

  • 100% शुद्ध बैश (IFS के साथ पैरामीटर विस्तार अस्थायी रूप से परेशान, कोई बाहरी कॉल, कोई प्रिंटफ नहीं ...)
  • कॉम्पैक्ट, पूर्ण और निर्दोष (एकल और बहु-चरित्र सीमाओं के साथ काम करता है, सफेद स्थान, लाइन ब्रेक और अन्य शेल विशेष वर्णों के साथ काम करता है, खाली सीमांकक के साथ काम करता है)
  • कुशल (कोई उपधारा नहीं, कोई सरणी प्रतिलिपि नहीं)
  • सरल और बेवकूफ और, कुछ हद तक, सुंदर और शिक्षाप्रद

उदाहरण:

$ join_ws , a b c
a,b,c
$ join_ws '' a b c
abc
$ join_ws $'\n' a b c
a
b
c
$ join_ws ' \/ ' A B C
A \/ B \/ C

1
यह अच्छा नहीं है: कम से कम 2 समस्याएं: 1. join_ws ,(बिना किसी तर्क के) गलत तरीके से आउटपुट ,,। 2. join_ws , -eगलत तरीके से आउटपुट कुछ भी नहीं (कि है, क्योंकि आप गलत तरीके से उपयोग कर रहे हैं echoके बजाय printf)। मुझे वास्तव में नहीं पता है कि आपने echoइसके बजाय विज्ञापन का उपयोग क्यों किया printf: echoकुख्यात रूप से टूटा हुआ है, और printfएक मजबूत बिलिन है।
गनीउर्फ़_निगियॉर्फ

1

अभी मैं उपयोग कर रहा हूं:

TO_IGNORE=(
    E201 # Whitespace after '('
    E301 # Expected N blank lines, found M
    E303 # Too many blank lines (pep8 gets confused by comments)
)
ARGS="--ignore `echo ${TO_IGNORE[@]} | tr ' ' ','`"

जो काम करता है, लेकिन (सामान्य स्थिति में) बहुत बुरी तरह से टूट जाएगा अगर सरणी तत्वों में उनके लिए जगह है।

(रुचि रखने वालों के लिए, यह pep8.py के आसपास एक आवरण स्क्रिप्ट है )


आप उन सरणी मानों को कहां से प्राप्त करते हैं? यदि आप इसे इस तरह से हार्डकोड कर रहे हैं, तो सिर्फ foo = "a, b, c" क्यों नहीं?
भूतडॉग ghost।

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

यह मानते हुए कि आप वास्तव में बैश का उपयोग कर रहे हैं, यह बेहतर काम कर सकता है ARGS="--ignore $(echo "${TO_IGNORE[@]}" | tr ' ' ',')":। ऑपरेटर $()बैकटिक्स की तुलना में अधिक शक्तिशाली है (घोंसले के शिकार $()और अनुमति देता है "")। ${TO_IGNORE[@]}दोहरे उद्धरण चिह्नों के साथ लपेटकर भी मदद करनी चाहिए।
केविनरपे 16

1

मेरा प्रयास।

$ array=(one two "three four" five)
$ echo "${array[0]}$(printf " SEP %s" "${array[@]:1}")"
one SEP two SEP three four SEP five

1

मल्टीचैकर विभाजकों के लिए पर्ल का उपयोग करें:

function join {
   perl -e '$s = shift @ARGV; print join($s, @ARGV);' "$@"; 
}

join ', ' a b c # a, b, c

या एक पंक्ति में:

perl -le 'print join(shift, @ARGV);' ', ' 1 2 3
1, 2, 3

मेरे लिए काम करता है, हालांकि joinनाम कुछ बकवास के साथ संघर्ष करता है OS X.. मैं इसे कॉल करूँगा conjoined, या शायद jackie_joyner_kersee?
एलेक्स ग्रे

1

मेरी अब तक की सर्वश्रेष्ठ दुनिया के संयोजन पर विस्तृत टिप्पणियों के लिए @gniourf_gniourf धन्यवाद। कोड को पूरी तरह से डिजाइन और परीक्षण नहीं करने के लिए क्षमा करें। यहाँ एक बेहतर कोशिश है।

# join with separator
join_ws() { local d=$1 s=$2; shift 2 && printf %s "$s${@/#/$d}"; }

गर्भाधान द्वारा यह सौंदर्य है

  • (अभी भी) 100% शुद्ध बैश (स्पष्ट रूप से इंगित करने के लिए धन्यवाद कि प्रिंटफ एक बिलिन के रूप में अच्छी तरह से है। मुझे इसके बारे में पहले कोई जानकारी नहीं थी ...)
  • मल्टी-कैरेक्टर डेलिमिटर के साथ काम करता है
  • अधिक कॉम्पैक्ट और अधिक पूर्ण और इस बार ध्यान से सोचा और लंबे समय तक तनाव-परीक्षण दूसरों के बीच शेल लिपियों से यादृच्छिक substrates के साथ, खोल विशेष वर्ण या नियंत्रण वर्ण या विभाजक और / या मापदंडों, और किनारे मामलों में कोई वर्ण का उपयोग को कवर , और कोने के मामले और अन्य विचित्रताएं जैसे कोई तर्क नहीं। यह गारंटी नहीं है कि अधिक बग नहीं है, लेकिन इसे खोजने के लिए थोड़ी कठिन चुनौती होगी। BTW, यहां तक ​​कि वर्तमान में शीर्ष मतदान के जवाब और उस तरह की चीजों से संबंधित पीड़ित हैं -इ बग ...

अतिरिक्त उदाहरण:

$ join_ws '' a b c
abc
$ join_ws ':' {1,7}{A..C}
1A:1B:1C:7A:7B:7C
$ join_ws -e -e
-e
$ join_ws $'\033[F' $'\n\n\n'  1.  2.  3.  $'\n\n\n\n'
3.
2.
1.
$ join_ws $ 
$

1

यदि आप जिन तत्वों से जुड़ना चाहते हैं, वह एक ऐसा स्थान नहीं है जो केवल एक अलग की गई स्ट्रिंग है, तो आप कुछ ऐसा कर सकते हैं:

foo="aa bb cc dd"
bar=`for i in $foo; do printf ",'%s'" $i; done`
bar=${bar:1}
echo $bar
    'aa','bb','cc','dd'

उदाहरण के लिए, मेरा उपयोग मामला यह है कि कुछ तार मेरी शेल स्क्रिप्ट में पास किए गए हैं और मुझे SQL क्वेरी पर चलने के लिए इसका उपयोग करने की आवश्यकता है:

./my_script "aa bb cc dd"

My_script में, मुझे "SELECT * FROM टेबल से करना है, जहां IN ('आ', 'bb', 'cc', 'dd') करने की जरूरत है। फिर उपरोक्त कमांड उपयोगी होगी।


आप printf -v bar ...प्रिंटफ़ लूप को एक सबशेल में चलाने और आउटपुट कैप्चर करने के बजाय उपयोग कर सकते हैं ।
कोडवर्ड

ऊपर दिए गए सभी फैंसी समाधानों ने काम नहीं किया लेकिन आपके क्रूड ने मेरे लिए (वाई)
ishandutta2007

1

यहाँ एक है कि अधिकांश POSIX संगत गोले समर्थन करते हैं:

join_by() {
    # Usage:  join_by "||" a b c d
    local arg arr=() sep="$1"
    shift
    for arg in "$@"; do
        if [ 0 -lt "${#arr[@]}" ]; then
            arr+=("${sep}")
        fi
        arr+=("${arg}") || break
    done
    printf "%s" "${arr[@]}"
}

यह ठीक बैश कोड है, लेकिन POSIX में एरेज़ (या local) बिल्कुल नहीं है
एंडर्स कासोर्ग

@ एंडर्स: हाँ, मैंने इसे बहुत मुश्किल तरीके से हाल ही में सीखा है :( मैं इसे अभी के लिए छोड़ दूंगा, क्योंकि अधिकांश पॉसिक्स संगत गोले सरणियों का समर्थन करते हैं।
user541686

1

किसी सरणी में सीधे संदर्भित करने के लिए चर अप्रत्यक्षता का उपयोग करना भी काम करता है। नामांकित संदर्भों का भी उपयोग किया जा सकता है, लेकिन वे केवल 4.3 में उपलब्ध हो गए।

एक फ़ंक्शन के इस रूप का उपयोग करने का लाभ यह है कि आपके पास विभाजक वैकल्पिक हो सकता है (डिफ़ॉल्ट के पहले चरित्र के लिए डिफ़ॉल्ट IFS, जो कि एक स्थान है; शायद इसे एक खाली स्ट्रिंग बनाएं यदि आप चाहें), और यह दो बार विस्तार मान से बचा जाता है (पहले जब मापदंडों के रूप में पारित किया जाता है, और "$@"फ़ंक्शन के अंदर दूसरा )।

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

function join_by_ref {
    __=
    local __r=$1[@] __s=${2-' '}
    printf -v __ "${__s//\%/%%}%s" "${!__r}"
    __=${__:${#__s}}
}

array=(1 2 3 4)

join_by_ref array
echo "$__" # Prints '1 2 3 4'.

join_by_ref array '%s'
echo "$__" # Prints '1%s2%s3%s4'.

join_by_ref 'invalid*' '%s' # Bash 4.4 shows "invalid*[@]: bad substitution".
echo "$__" # Prints nothing but newline.

फंक्शन के लिए अधिक आरामदायक नाम का उपयोग करने के लिए स्वतंत्र महसूस करें।

यह 3.1 से 5.0-अल्फा से काम करता है। जैसा कि देखा गया है, चर अप्रत्यक्ष केवल चर के साथ ही नहीं बल्कि अन्य मापदंडों के साथ भी काम करता है।

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

सरणी और सरणी तत्व भी पैरामीटर (ऐसी संस्थाएं हैं जो मूल्य को संग्रहीत करती हैं), और सरणियों के संदर्भ तकनीकी रूप से भी मापदंडों के संदर्भ हैं। और विशेष पैरामीटर की तरह @, array[@]एक वैध संदर्भ भी बनाता है।

विस्‍तारित या चयनात्मक रूप विस्‍तार (जैसे विस्‍तारित विस्‍तार) जो पैरामीटर से विचलन को संदर्भित करता है वह अब काम नहीं करता है।

अपडेट करें

बैश 5.0 के रिलीज़ संस्करण में, चर अप्रत्यक्ष को पहले से ही अप्रत्यक्ष विस्तार कहा जाता है और इसका व्यवहार पहले से ही मैनुअल में स्पष्ट रूप से प्रलेखित है:

यदि पैरामीटर का पहला वर्ण विस्मयादिबोधक बिंदु (!) है, और पैरामीटर एक nameref नहीं है, तो यह अप्रत्यक्ष स्तर का परिचय देता है। बैश नए पैरामीटर के रूप में बाकी पैरामीटर का विस्तार करके गठित मूल्य का उपयोग करता है; इसके बाद इसका विस्तार किया जाता है और मूल पैरामीटर के विस्तार के बजाय शेष विस्तार में इसका उपयोग किया जाता है। इसे अप्रत्यक्ष विस्तार के रूप में जाना जाता है।

ध्यान दें कि के दस्तावेज में ले रहा है ${parameter}, parameterके रूप में जाना जाता है "वर्णित (में) के रूप में एक खोल पैरामीटर पैरामीटर या एक सरणी संदर्भ "। और सरणियों के दस्तावेज़ीकरण में, यह उल्लेख किया गया है कि "सरणी के किसी भी तत्व का उपयोग करके संदर्भित किया जा सकता है ${name[subscript]}"। यह __r[@]एक सरणी संदर्भ बनाता है ।

तर्क संस्करण से जुड़ें

रिकार्डो गली के जवाब में मेरी टिप्पणी देखें ।


2
क्या __चर नाम के रूप में उपयोग करने का कोई विशेष कारण है ? कोड को वास्तव में अपठनीय बनाता है।
पेसा द जूल 15'18

@Pesa यह सिर्फ एक प्राथमिकता है। मैं एक रिटर्न वैरिएबल के लिए जेनेरिक नामों का उपयोग करना पसंद करता हूं। अन्य गैर-जेनेरिक नाम विशिष्ट कार्यों के लिए स्वयं को विशेषता देते हैं, और इसके लिए संस्मरण की आवश्यकता होती है। विभिन्न चर पर मान लौटाने वाले कई कार्यों को कॉल करने से कोड का पालन करना आसान हो जाता है। जेनेरिक नाम का उपयोग करने से स्ट्राइकर को संघर्ष से बचने के लिए रिटर्न वैरिएबल से वैल्यू ट्रांसफर करने के लिए मजबूर होना पड़ेगा, और यह कोड को अधिक पठनीय बनाता है क्योंकि यह स्पष्ट हो जाता है कि लौटे मान कहां जाते हैं। मैं हालांकि उस नियम के कुछ अपवाद बनाता हूं।
konsolebox

0

यह दृष्टिकोण मानों के भीतर रिक्त स्थान की देखभाल करता है, लेकिन इसके लिए एक लूप की आवश्यकता होती है:

#!/bin/bash

FOO=( a b c )
BAR=""

for index in ${!FOO[*]}
do
    BAR="$BAR,${FOO[$index]}"
done
echo ${BAR:1}

0

यदि आप एक लूप में सरणी बनाते हैं, तो यहां एक सरल तरीका है:

arr=()
for x in $(some_cmd); do
   arr+=($x,)
done
arr[-1]=${arr[-1]%,}
echo ${arr[*]}

0

x=${"${arr[*]}"// /,}

यह इसे करने का सबसे छोटा तरीका है।

उदाहरण,

arr=(1 2 3 4 5)
x=${"${arr[*]}"// /,}
echo $x  # output: 1,2,3,4,5

1
यह रिक्त स्थान के साथ स्ट्रिंग के लिए सही ढंग से काम नहीं करता है: `t = (एक" बी सी "डी); गूंज $ {t [2]} (प्रिंट "बी सी"); गूंज $ {"$ {t [*]}" / /,} (प्रिंट्स ए, बी, सी, डी)
kounoupis

7
bash: ${"${arr[*]}"// /,}: bad substitution
कैमरन हडसन

0

शायद पार्टी के लिए देर हो रही है, लेकिन यह मेरे लिए काम करता है:

function joinArray() {
  local delimiter="${1}"
  local output="${2}"
  for param in ${@:3}; do
    output="${output}${delimiter}${param}"
  done

  echo "${output}"
}

-1

शायद मुझे कुछ स्पष्ट याद आ रहा है, क्योंकि मैं पूरी मार / ज़श चीज़ के लिए एक नया हूँ, लेकिन यह मुझे ऐसा लगता है जैसे आपको बिल्कुल भी उपयोग करने की आवश्यकता नहीं है printf। और न ही यह वास्तव में बिना करने के लिए बदसूरत मिलता है।

join() {
  separator=$1
  arr=$*
  arr=${arr:2} # throw away separator and following space
  arr=${arr// /$separator}
}

कम से कम, इसने मेरे लिए इस तरह से बिना मुद्दे के काम किया है।

उदाहरण के लिए, join \| *.shजो, मान लें कि मैं अपनी ~निर्देशिका में हूँ , आउटपुट utilities.sh|play.sh|foobar.sh। मेरे लिए काफी अच्छा।

EDIT: यह मूल रूप से Nil Geisweiller का उत्तर है , लेकिन एक फ़ंक्शन में सामान्यीकृत है।


1
मैं नीच नहीं हूँ, लेकिन एक समारोह में एक वैश्विक हेरफेर बहुत निराला लगता है।
ट्रिपल एफ

-2
liststr=""
for item in list
do
    liststr=$item,$liststr
done
LEN=`expr length $liststr`
LEN=`expr $LEN - 1`
liststr=${liststr:0:$LEN}

यह अंत में अतिरिक्त अल्पविराम का भी ख्याल रखता है। मैं कोई बैश विशेषज्ञ नहीं हूं। बस मेरा 2 सी, क्योंकि यह अधिक प्राथमिक और समझने योग्य है


-2
awk -v sep=. 'BEGIN{ORS=OFS="";for(i=1;i<ARGC;i++){print ARGV[i],ARGC-i-1?sep:""}}' "${arr[@]}"

या

$ a=(1 "a b" 3)
$ b=$(IFS=, ; echo "${a[*]}")
$ echo $b
1,a b,3
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.