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

FOO=( a b c )

如何用逗号连接元素?例如,生成a b c。


当前回答

也许我遗漏了一些明显的东西,因为我是bash/zsh的新手,但在我看来,您根本不需要使用printf。没有它也不会变得很难看。

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

至少,到目前为止,它对我来说是有效的。

例如,加入\| *.sh,假设我在~目录下,输出utilities.sh|play.sh|foobar.sh。对我来说足够好了。

编辑:这基本上是Nil Geisweiller的答案,但推广到一个函数。

其他回答

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

or

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

也许,例如,

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

echo "$FOOJOIN"

使用perl实现多字符分隔符:

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

下面是一个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(为什么你不喜欢它?)并传递一个变量名,你当然可以为返回的字符串使用一个全局变量:

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

这里有一个单行,有点奇怪,但适用于多字符分隔符,并支持任何值(包括包含空格或任何东西):

ar=(abc "foo bar" 456)
delim=" | "
printf "%s\n$delim\n" "${ar[@]}" | head -n-1 | paste -sd ''

这将在控制台显示为

abc | foo bar | 456

注意:注意一些解决方案是如何使用${ar[*]}和${ar[@]}的printf ?

带@的使用printf特性,通过重复格式模板来支持多个参数。

带*的不应该使用。它们实际上不需要打印,而是依赖于操作字段分隔符和bash的单词展开。这些方法同样适用于echo、cat等——这些解决方案可能使用printf,因为作者并不真正理解他们在做什么……