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

FOO=( a b c )

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


当前回答

这与现有的解决方案并没有太大的不同,但它避免了使用单独的函数,不修改父shell中的IFS,并且都在一行中:

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

导致

a,b,c

限制:分隔符不能超过一个字符。


可以化简为

(IFS=,; printf '%s' "${arr[*]}")

在这一点上,它基本上与Pascal的答案相同,但使用printf而不是echo,并将结果打印到stdout,而不是将其赋值给变量。

其他回答

顶部答案的简短版本:

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

用法:

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

下面是一个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}"
}

结合所有最好的世界到目前为止与以下的想法。

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

这个小杰作是

100%纯bash(参数扩展,暂时不设置IFS,没有外部调用,没有printf…) 紧凑、完整和完美(适用于单字符和多字符限制符,适用于包含空格、换行符和其他shell特殊字符的限制符,适用于空分隔符) 高效(无子shell,无数组复制) 简单而愚蠢,但在某种程度上,也很漂亮,很有教育意义

例子:

$ 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

我的尝试。

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

也许我遗漏了一些明显的东西,因为我是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的答案,但推广到一个函数。