join数组的元素?

如果我在Bash中有这样一个数组:

FOO=( abc ) 

我如何用逗号join元素? 例如,生产a,b,c

Pascal Pilz重写解决scheme作为100%纯Bash(无外部命令)的function:

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

例如,

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

或者,我们可以使用printf来支持多字符分隔符,使用@gniourf_gniourf

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

例如,

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

又一个解决scheme:

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

编辑:相同,但多字符可变长度分隔符:

 #!/bin/bash separator=")|(" # eg 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 
 $ foo=(a "bc" d) $ bar=$(IFS=, ; echo "${foo[*]}") $ echo "$bar" a,bc,d 

也许,例如,

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

这是一个100%纯Bash函数来完成这项工作:

 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 $ 

这甚至保留了换行符,并且不需要一个子shell来获得函数的结果。 如果你不喜欢printf -v (为什么你不喜欢它?)并传递一个variables名,你当然可以使用一个全局variables作为返回的string:

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

令人惊讶的是,我的解决scheme还没有给:)这是我最简单的方法。 它不需要一个function:

 IFS=, eval 'JOINED="${FOO[*]}"' 

重复使用@并不重要“的解决scheme,而是通过避免$ {1}的replace和一个中间variables的需要来进行一个声明。

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

printf的'格式string被重复使用,以满足参数的需要。 在其手册页中,以便将string的连接logging下来。 然后诀窍是使用LIST长度来切割最后一个分析器,因为当字段计数时,cut仅保留LIST的长度。

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

接受任何长度的分隔符的printf解决scheme(基于@无关紧要)

 #/!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 

我会将数组作为string回显,然后将空格转换为换行符,然后使用paste将所有内容join到一行中,如下所示:

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

结果:

a,b,c

这对我来说似乎是最快最干净的!

 $ set a 'bc' d $ history -p "$@" | paste -sd, a,bc,d 

最佳答案的较短版本:

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

用法:

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

现在我正在使用:

 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 ' ' ','`" 

哪些工作,但(在一般情况下),如果arrays元素有一个空间,将打破可怕的。

(对于那些感兴趣的,这是一个围绕pep8.py的包装脚本)

 $ FOO=( abc ) $ BAR=${FOO[@]} $ BAZ=${BAR// /,} $ echo $BAZ a,b,c 

警告,它假定元素没有空格。

perl用于多字符分隔符:

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

或者在一行中:

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

这种方法处理值中的空格,但需要一个循环:

 #!/bin/bash FOO=( abc ) BAR="" for index in ${!FOO[*]} do BAR="$BAR,${FOO[$index]}" done echo ${BAR:1} 

如果你想要join的元素不是一个只是空格分隔string的数组,你可以这样做:

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

例如,我的用例是一些string在我的shell脚本中传递,我需要使用它在SQL查询上运行:

./my_script“aa bb cc dd”

在my_script中,我需要执行“SELECT * FROM table WHERE name IN('aa','bb','cc','dd'),那么上面的命令将会很有用。

我的企图

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

如果你在一个循环中构build数组,这里有一个简单的方法:

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

也许我错过了一些明显的东西,因为我是整个bash / zsh的新手,但是在我看来,你根本不需要使用printf 。 如果没有,也不会变得非常难看。

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

至less,它迄今为止一直在为我工作,没有问题。

例如, join \| *.sh join \| *.sh ,让我们说我在我的~目录,输出utilities.sh|play.sh|foobar.sh 。 对我来说足够了。

编辑:这基本上是无Geisweiller的答案 ,但泛化为一个函数。

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

最后还要照顾额外的逗号。 我不是bash的专家。 只是我的2C,因为这是更基本和可以理解的

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

要么

 $ a=(1 "ab" 3) $ b=$(IFS=, ; echo "${a[*]}") $ echo $b 1,ab,3