আমি কীভাবে বাশে কোনও অ্যারের উপাদানগুলিতে যোগদান করতে পারি?


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
মাল্টিচ্যারেক্টর বিভাজকগুলির জন্য এটি ব্যবহার করুন: ফাংশন জয়েন {পার্ল-ই '= s = শিফট @ARGV; মুদ্রণ যোগদান ($ গুলি, @ আরজিভি); ' "$ @"; } যোগদান ',' abc # a, b, c
ড্যানিয়েল প্যাট্রু

4
@ ডিপাত্রু যেভাবেই হোক খাঁটি বাশ করতে?
সিএমসিডিগ্রাগনকাই

4
@ পুচু যা কাজ করে না তা হ'ল বহু-চরিত্র বিভাজক। "স্পেস কাজ করে না" বলার মতো শব্দটি এমন একটি জায়গার সাথে যোগদানের কাজ করে না বলে মনে হয়। এটা করে.
এরিক 18

6
যদি আউটপুটটি ভেরিয়েবলের মধ্যে সঞ্চয় থাকে তবে এটি স্প্যানিং সাবসেলগুলি প্রচার করে। konsoleboxশৈলী ব্যবহার করুন :) function join { local IFS=$1; __="${*:2}"; }বা function join { IFS=$1 eval '__="${*:2}"'; }। তারপরে ব্যবহার করুন __। হ্যাঁ, আমি __ফলস্বরূপ পরিবর্তনশীল;) (এবং একটি সাধারণ পুনরাবৃত্তির পরিবর্তনশীল বা অস্থায়ী ভেরিয়েবল) হিসাবে এর ব্যবহার প্রচার করি । যদি ধারণাটি কোনও জনপ্রিয় বাশ উইকি সাইটের কাছে পায় তবে তারা আমার অনুলিপি করেছে :)
কনসোলবক্স

6
$dএর ফর্ম্যাট স্পেসিফায়ারে প্রসারণটি রাখবেন না printf। আপনি মনে করেন আপনি নিরাপদ যেহেতু আপনি "পালিয়ে গেছেন" %তবে অন্যান্য সতর্কতা রয়েছে: যখন ডিলিমেটারটিতে একটি ব্যাকস্ল্যাশ থাকে (যেমন, \n) বা যখন ডিলিমিটারটি হাইফেন দিয়ে শুরু হয় (এবং অন্যরাও আমি এখন ভাবতে পারি না)। আপনি অবশ্যই এগুলি ঠিক করতে পারেন (ডাবল ব্যাকস্ল্যাশ এবং ব্যাকস্ল্যাশগুলি ব্যবহার করে ব্যাকস্ল্যাশগুলি প্রতিস্থাপন করুন printf -- "$d%s") তবে কিছু সময় আপনি অনুভব করবেন যে আপনি এটির সাথে কাজ করার পরিবর্তে শেলের বিরুদ্ধে লড়াই করছেন। সে কারণেই, নীচে আমার উত্তরে আমি শর্তাদির সাথে ডিলিমিটারকে যুক্ত হওয়ার শোধ করলাম।
gniourf_gniourf

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)
Y

14
প্রার্থনা করার পরিবর্তে $separatorধারণ করে না %sবা এই ধরনের, আপনি আপনার করতে পারেন printfশক্তসমর্থ: printf "%s%s" "$separator" "${foo[@]}"
ম্যাসিফিল

5
@ মুশিফিল ভুল ব্যাশ মানুষ থেকে: "বিন্যাস এর সব আর্গুমেন্ট গ্রাস প্রয়োজনীয় হিসাবে পুনঃব্যবহৃত করা হয় দুই বিন্যাস প্লেসহোল্ডার ব্যবহার করে না। printf "%s%s"প্রথমত শুধুমাত্র আউটপুট সেট বিভাজক ব্যবহার করেন এবং তারপর কেবল আর্গুমেন্ট বাকি কনক্যাটেনেট।
AnyDev

3
@ আন্ডারডেভেক: ভুলটি ধরার জন্য ধন্যবাদ পরিবর্তে আমি এর মতো কিছু প্রস্তাব করব printf "%s" "${foo[@]/#/$separator}"
ম্যাসিফিল

2
@ মুশিফিল, ধন্যবাদ হ্যাঁ! তারপরে প্রিন্টফ রিডানড্যান্ট হয়ে যায় এবং সেই লাইনটি কমে যেতে পারে IFS=; regex="${foo[*]/#/$separator}"। এই মুহুর্তে এটি মূলত gniourf_gniourf এর উত্তরে পরিণত হয় যা আইএমও শুরু থেকেই পরিষ্কার, অর্থাৎ আইএফএস পরিবর্তন এবং টেম্প ওয়ার্সের পরিধি সীমাবদ্ধ করতে ফাংশন ব্যবহার করে।
যেকোনোদেব

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

3
বাইরের ডাবল কোট এবং কোলনের চারপাশে ডাবল উদ্ধৃতি প্রয়োজন হয় না। কেবলমাত্র অভ্যন্তরীণ ডাবল উদ্ধৃতিগুলি প্রয়োজনীয়:bar=$( IFS=, ; echo "${foo[*]}" )
সিলিং

8
সর্বাধিক কমপ্যাক্ট সমাধানের জন্য +1 যা লুপগুলির প্রয়োজন হয় না, যার জন্য বাহ্যিক কমান্ডের প্রয়োজন হয় না এবং যা আর্গুমেন্টের চরিত্র সেটটিতে অতিরিক্ত বিধিনিষেধ আরোপ করে না।
সিলিং

22
আমি সমাধানটি পছন্দ করি তবে এটি কেবল তখনই কার্যকর হয় যদি আইএফএসের একটি চরিত্র হয়
জয়েন

8
কোন ধারণা কেন এই যদি ব্যবহার কাজ করে না @পরিবর্তে *, হিসাবে $(IFS=, ; echo "${foo[@]}")? আমি দেখতে পাচ্ছি যে *ইতিমধ্যে উপাদানগুলির মধ্যে শ্বেত স্থান সংরক্ষণ করেছে, আবার নিশ্চিত নয় কীভাবে, যেহেতু @সাধারণত এই কারণে প্রয়োজন হয়।
haridsv

10
আমি আমার নিজের প্রশ্নের উত্তর উপরে পেয়েছি। উত্তরটি হ'ল আইএফএস কেবলমাত্র স্বীকৃত *। বাশ ম্যান পৃষ্ঠায়, "বিশেষ পরামিতি" অনুসন্ধান করুন এবং এর পরবর্তী ব্যাখ্যাটি দেখুন *:
হরিদসভ

66

হতে পারে, যেমন,

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

echo "$FOOJOIN"

3
যদি আপনি এটি করেন, এটি আইএফএস- পরিবর্তনশীল বলে মনে করে thinks আপনাকে করতে হবে echo "-${IFS}-"(কোঁকড়ানো ধনুর্বন্ধনী বক্রবন্ধগুলি পরিবর্তনশীল নাম থেকে ড্যাশগুলি পৃথক করে)।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

1
এখনও একই ফলাফল পেয়েছি (আমি শুধু বিন্দু চিত্রিত করার জন্য ড্যাশ করা ... echo $IFSএকই জিনিস আছে।
ডেভিড Wolever

41
এটি বলেছিল, এটি এখনও কাজ করে বলে মনে হচ্ছে ... সুতরাং, বাশের সাথে বেশিরভাগ জিনিসগুলির মতো, আমি এটি বোঝার মতো ভান করব এবং আমার জীবনযাত্রা চালিয়ে যাব।
ডেভিড ওলবার

2
একটি "-" ভেরিয়েবল নামের জন্য বৈধ অক্ষর নয়, সুতরাং আপনি যখন $ আইএফএস- ব্যবহার করেন তখন শেলটি সঠিকভাবে কাজ করে, আপনাকে লিনাক্স এবং সোলারিসে $ {আইএফএস} প্রয়োজন হবে না - বাশ, কেশ, শ এবং জেডএস এছাড়াও একমত)।
আইডেলিক

2
@ ডেভিড আপনার প্রতিধ্বনি এবং ডেনিসের মধ্যে পার্থক্য হ'ল তিনি ডাবল উদ্ধৃতি ব্যবহার করেছেন। আইএফএসের বিষয়বস্তু শব্দ-বিভাজক অক্ষরের ঘোষণা হিসাবে 'ইনপুট অন' ব্যবহার করা হয় - সুতরাং আপনি সর্বদা উদ্ধৃতি ছাড়াই একটি খালি লাইন পাবেন।
মার্টিন ক্লেটন 21

30

আশ্চর্যজনকভাবে আমার সমাধানটি এখনও দেওয়া হয়নি :) এটি আমার পক্ষে সহজতম উপায়। এটির জন্য কোনও ক্রিয়াকলাপের প্রয়োজন নেই:

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

দ্রষ্টব্য: এই সমাধানটি নন-পসিক্স মোডে ভালভাবে কাজ করতে দেখা গেছে। ইন POSIX মোড উপাদান এখনও সঠিকভাবে যোগ দেন কিন্তু হয় IFS=,স্থায়ী হয়ে যায়।


দুর্ভাগ্যক্রমে শুধুমাত্র একক-চরিত্রের সীমানা
মাওজম

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


$

এটি এমনকি চলমান নতুন লাইনের সংরক্ষণ করে এবং ফাংশনটির ফলাফল পেতে একটি সাবশেলের প্রয়োজন হয় না। আপনি যদি পছন্দ করেন না 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
@ জেমসনিয়ারঞ্জার আমি সাবজেলগুলি এড়ানোর জন্য উদ্দেশ্যমূলকভাবে এই নকশাটি ব্যবহার করেছি। শেল স্ক্রিপ্টিংয়ে, অন্যান্য অনেক ভাষার মতো নয়, বৈশ্বিক ভেরিয়েবলগুলি সেভাবে ব্যবহার করা কোনও খারাপ জিনিস নয়; বিশেষত যদি তারা এখানে সাবস্কেলগুলি এড়াতে সহায়তা করে থাকে। অধিকন্তু, $(...)নতুন লাইন trailing ট্রিম; সুতরাং অ্যারের শেষ ক্ষেত্রটিতে যদি নতুন লাইনের চিহ্ন থাকে তবে এগুলি ছাঁটাই করা হবে (ডেমো দেখুন যেখানে তারা আমার নকশাটি ছাঁটাচ্ছেন না)।
gniourf_gniourf

এটি বহু-চরিত্র বিভাজকের সাথে কাজ করে, যা আমাকে খুশি করে ^ _ ^
spiffytech

"কেন আপনি প্রিন্টফ-ভি পছন্দ করেন না?" সম্বোধনের জন্য: বাশ-এ স্থানীয় ভেরিয়েবলগুলি সত্যই ফাংশন-লোকাল হয় না, তাই আপনি এই জাতীয় জিনিসগুলি করতে পারেন। (স্থানীয় ভেরিয়েবল এক্স সহ ফাংশন এফ 1 কল করুন, যার ফলে ফাংশন এফ 2 কল করে যা এক্সকে পরিবর্তন করে - যা এফ 1 এর আওতায় স্থানীয় হিসাবে ঘোষণা করা হয়) তবে স্থানীয় ভেরিয়েবলগুলি কীভাবে কাজ করা উচিত তা সত্য নয়। স্থানীয় ভেরিয়েবলগুলি যদি সত্যিই স্থানীয় হয় (বা ধরে নেওয়া হয়, উদাহরণস্বরূপ কোনও স্ক্রিপ্টে যা অবশ্যই ব্যাশ এবং 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 এর দৈর্ঘ্য ধরে রাখতে পারে।


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

8
আপনার উত্তরটি বের করে দেওয়া উচিত।
joce

খুব ভাল এক। ধন্যবাদ !!
পিটার প্যান জিজেড

4
আমি আশা করি আমি এই উত্তরটিকে নীচে নামাতে পারব কারণ এটি একটি সুরক্ষা গর্ত খোলে এবং কারণ এটি উপাদানগুলির স্পেস নষ্ট করে দেয়।
ইয়েল 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 '
ee ghEEz

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

এটি একটি নেতৃস্থানীয় কমা দিয়ে আউটপুট উত্পাদন করে।
মার্ক রেনুফ

শেষ বার = $ {বার: $ {# সেপ}। বিভাজককে সরিয়ে দেয়। আমি কেবল অনুলিপি করে একটি ব্যাশ শেলের মধ্যে পেস্ট করেছি এবং এটি কাজ করে। আপনি কোন শেল ব্যবহার করছেন?
রিকার্ডো গালি

2
যে কোনও printf ফর্ম্যাট স্পেসিফায়ার (উদাহরণস্বরূপ %sঅনিচ্ছাকৃতভাবে $sepসমস্যার কারণ হবে
পিটার.ও

sepসঙ্গে স্যানিটাইজ করা যেতে পারে ${sep//\%/%%}। আমি তার চেয়ে উত্তম আপনার সমাধান মত ${bar#${sep}}বা ${bar%${sep}}(বিকল্প)। এটি এমন কোনও ফাংশনে রূপান্তরিত হয় যা জেনেরিক ভেরিয়েবলের মতো ফলাফল সঞ্চয় করে __এবং echoএটি না করে।
কনসোলবক্স

function join_by { printf -v __ "${1//\%/%%}%s" "${@:2}"; __=${__:${#1}}; }
কনসোলবক্স

4
$ set a 'b c' d

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

এটি শীর্ষে থাকা উচিত।
এরিক ওয়াকার

6
এটি শীর্ষে থাকা উচিত নয়: তবে কী HISTSIZE=0?
har-wradim

@ হার-ওয়াদিম, কৌশলটি paste -sd,ইতিহাসের ব্যবহার সম্পর্কে নয়।
বেদ

@ বেদা না, এটি সংমিশ্রণের ব্যবহার সম্পর্কে, এবং যদি HISTSIZE=0এটি চেষ্টা করে - তবে এটি কার্যকর হবে না ।
har-wradim

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% খাঁটি বাশ (আইএফএসের সাথে প্যারামিটার সম্প্রসারণ অস্থায়ীভাবে আনসেট করা হবে না, কোনও বাহ্যিক কল নেই, কোনও প্রিন্টফ নেই ...)
  • কমপ্যাক্ট, সম্পূর্ণ এবং নির্দোষ
  • দক্ষ (কোনও সাবশেল নেই, অ্যারে অনুলিপি নেই)
  • সাধারণ এবং বোকা এবং একটি নির্দিষ্ট ডিগ্রী পর্যন্ত সুন্দর এবং শিক্ষণীয়

উদাহরণ:

$ 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 ,(কোনও যুক্তি ছাড়াই) ভুল আউটপুট ,,। ২. join_ws , -eভুলভাবে কিছুই আউটপুট করে না (কারণ আপনি এর echoপরিবর্তে ভুলভাবে ব্যবহার করছেন printf)। এর echoপরিবর্তে আপনি কেন বিজ্ঞাপনটির বিজ্ঞাপন দিয়েছেন তা আমি জানি না printf: echoকুখ্যাতভাবে ভেঙে গেছে, এবং printfএটি শক্তিশালী অন্তর্নির্মিত।
gniourf_gniourf 21

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" নয়?
ghostdog74

এই ক্ষেত্রে আমি মানগুলি কঠোরভাবে কোডিং করছি , তবে আমি সেগুলি একটি অ্যারেতে রাখতে চাই যাতে প্রতিটি স্বতন্ত্রভাবে মন্তব্য করতে পারি। আমি কী বলতে চাইছি তা উত্তর দেওয়ার জন্য আমি উত্তর আপডেট করেছি।
ডেভিড ওলবার

ধরে নেওয়া যাক আপনি আসলে ব্যাশ ব্যবহার করছেন, এই আরো ভালোভাবে কাজ করতে পারেন: ARGS="--ignore $(echo "${TO_IGNORE[@]}" | tr ' ' ',')"। অপারেটর $()backtics (এর পাখির অনুমতি দেয় অপেক্ষা অধিক শক্তিধর কে $()এবং "")। ${TO_IGNORE[@]}ডাবল উদ্ধৃতি দিয়ে মোড়ানোও সহায়তা করা উচিত।
কেভিনার্পে


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}"; }

ধারণা দ্বারা এই সৌন্দর্য হয়

  • (তবুও) ১০০% খাঁটি বাশ (প্রিন্টফ একটি বিল্টিনও স্পষ্টভাবে নির্দেশ করার জন্য ধন্যবাদ। আমি এর আগে এ বিষয়ে অবগত ছিলাম না ...)
  • মাল্টি-ক্যারেক্টার ডিলিমিটারগুলির সাথে কাজ করে
  • আরও কমপ্যাক্ট এবং আরও সম্পূর্ণ এবং এবার অন্যদের মধ্যে শেল স্ক্রিপ্ট থেকে এলোমেলো সাবস্ট্রিংগুলির সাথে সাবধানতার সাথে দীর্ঘমেয়াদী স্ট্রেস-টেস্টের সাথে বিবেচনা করা হয়েছে, শেল বিশেষ অক্ষরের ব্যবহার বা নিয়ন্ত্রণ অক্ষর বা বিভাজক এবং / অথবা প্যারামিটার উভয় অক্ষরের অক্ষর এবং প্রান্তের কেসগুলি , এবং কোণার কেস এবং অন্যান্য কোয়েবলের মতো কোনও যুক্তি নেই। এটি গ্যারান্টি দেয় না যে আর কোনও ত্রুটি নেই, তবে এটি খুঁজে পাওয়া একটু কঠিন চ্যালেঞ্জ হবে। বিটিডাব্লিউ, এমনকি বর্তমানে শীর্ষে ভোট দেওয়া উত্তর এবং সম্পর্কিত যেমন -e বাগ ...

অতিরিক্ত উদাহরণ:

$ 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'

উদাহরণস্বরূপ, আমার ব্যবহারের ক্ষেত্রেটি হ'ল যে আমার শেল স্ক্রিপ্টে কিছু স্ট্রিং উত্তীর্ণ হয়েছে এবং এসকিউএল কোয়েরিতে চালানোর জন্য আমার এটি ব্যবহার করতে হবে:

./my_script "aa bb cc dd"

মাই_সক্রিপ্টে, আমাকে "সারণি * সারণী থেকে কোথাও নাম ('এএ', 'বিবি', 'সিসি', 'ডিডি') করতে হবে Then তারপরে উপরের আদেশটি কার্যকর হবে be


আপনি printf -v bar ...একটি সাবশেলে প্রিন্টফ লুপ চালানোর পরিবর্তে এবং আউটপুট ক্যাপচার করতে পারেন।
কোডফোরস্টার

উপরের সমস্ত অভিনব উত্সাহিত সমাধানগুলি কাজ করে না তবে আপনার
ক্রুডটি

1

এখানে বেশিরভাগ পসিএক্স সামঞ্জস্যপূর্ণ শেলগুলি সমর্থন করে:

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[@]}"
}

এটি দুর্দান্ত বাশ কোড, তবে পসিক্সের কাছে অ্যারে (বা local) মোটেই নেই
অ্যান্ডারস ক্যাসরগ

@ আন্ডারস: হ্যাঁ আমি খুব শক্তভাবে খুব সম্প্রতি শিখেছি :( আমি এখনই এটি ছেড়ে দিচ্ছি যদিও বেশিরভাগ
পসিক্সের

1

ভেরিয়েবল ইন্ডিয়ারেশন ব্যবহার করে সরাসরি অ্যারে রেফারেন্স করতেও কাজ করে। নামযুক্ত রেফারেন্সগুলিও ব্যবহার করা যেতে পারে তবে সেগুলি কেবল ৪.৩-এ উপলব্ধ হয়েছিল।

কোনও ফাংশনের এই ফর্মটি ব্যবহার করার সুবিধাটি হ'ল আপনি বিভাজক optionচ্ছিক (ডিফল্টের প্রথম অক্ষরের ডিফল্ট 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 এর রিলিজ সংস্করণে, পরিবর্তনশীল ইন্ডিরেশনকে ইতিমধ্যে পরোক্ষ সম্প্রসারণ বলা হয় এবং এর আচরণটি স্বতন্ত্রভাবে ম্যানুয়ালটিতে নথিভুক্ত করা হয়েছে:

যদি প্যারামিটারের প্রথম অক্ষরটি একটি বিস্ময়কর বিন্দু (!) হয় এবং পরামিতি নামরেফ না হয় তবে এটি ইন্ডিয়ারেশনের একটি স্তর প্রবর্তন করে। বাশ বাকী প্যারামিটারটিকে নতুন প্যারামিটার হিসাবে প্রসারিত করে গঠিত মান ব্যবহার করে; এটির পরে প্রসারিত হয় এবং সেই মানটি মূল প্যারামিটারের প্রসারণের পরিবর্তে বাকী প্রসারণে ব্যবহৃত হয়। এটি পরোক্ষ সম্প্রসারণ হিসাবে পরিচিত।

দয়া করে মনে রাখবেন ডকুমেন্টেশন মধ্যে গ্রহণ ${parameter}, parameterহিসাবে উল্লেখ করা হয় "বর্ণনা (IN) হিসাবে একটি শেল প্যারামিটার প্যারামিটার অথবা একটি অ্যারের রেফারেন্স "। এবং অ্যারের ডকুমেন্টেশনে এটি উল্লেখ করা হয়েছে যে "অ্যারের কোনও উপাদান ব্যবহার করে রেফারেন্স করা যেতে পারে ${name[subscript]}"। এটা তৈরি করে__r[@] একটি অ্যারে রেফারেন্স তৈরি করে।

যুক্তি সংস্করণ দ্বারা যোগদান করুন

আমার দেখুন মন্তব্য মধ্যে Riccardo Galli এর উত্তর


2
__একটি পরিবর্তনশীল নাম হিসাবে ব্যবহার করার কোনও নির্দিষ্ট কারণ আছে ? কোডটি সত্যিই অপঠনযোগ্য করে তোলে।
পেসা দ্য

@ পেসা এটি কেবল একটি পছন্দ। আমি রিটার্ন ভেরিয়েবলের জন্য জেনেরিক নাম ব্যবহার করা পছন্দ করি। অন্যান্য অ-জেনেরিক নামগুলি নির্দিষ্ট ফাংশনগুলিতে নিজেকে বিশেষীকরণ করে এবং এর মুখস্তকরণ প্রয়োজন। একাধিক ফাংশন কল করা যা বিভিন্ন ভেরিয়েবলগুলিতে মান ফেরত দেয় কোড অনুসরণ করা কম সহজ করতে পারে। জেনেরিক নাম ব্যবহার করা স্ক্রিপ্টরকে দ্বন্দ্ব এড়ানোর জন্য রিটার্ন ভেরিয়েবল থেকে মানটি যথাযত পরিবর্তনশীলকে স্থানান্তর করতে বাধ্য করে এবং প্রত্যাবর্তিত মানগুলি যেখানে যায় সে স্পষ্ট হয়ে যাওয়ার কারণে কোডটি শেষ পর্যন্ত আরও পঠনযোগ্য হয়ে পড়ে। যদিও আমি সেই নিয়মে কিছু ব্যতিক্রম করি।
কনসোলবক্স

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 = (a" b c "d); প্রতিধ্বনি $ {t [2]} ("বি সি" প্রিন্ট করুন); প্রতিধ্বনি $ {"$ {t [*]}" // /,} (একটি, বি, সি, ডি প্রিন্ট করে)
কাউনপিস

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

সম্ভবত আমি স্পষ্ট কিছু মিস করছি, যেহেতু আমি পুরো বাশ / zsh জিনিসটির জন্য একটি নতুন, তবে এটি আমার কাছে এমন মনে হচ্ছে যে আপনাকে কোনও ব্যবহার 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। আমার জন্য যথেষ্ট ভাল।

সম্পাদনা: এটি মূলত নীল গিসওইলারের উত্তর , তবে একটি ফাংশনে সাধারণীকরণ।


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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.