如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
当前回答
这里有一个单行,有点奇怪,但适用于多字符分隔符,并支持任何值(包括包含空格或任何东西):
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,因为作者并不真正理解他们在做什么……
其他回答
x = $ {arr [*] / /,)
这是做这件事最短的方法。
的例子,
# ZSH:
arr=(1 "2 3" 4 5)
x=${"${arr[*]}"// /,}
echo $x # output: 1,2,3,4,5
# ZSH/BASH:
arr=(1 "2 3" 4 5)
a=${arr[*]}
x=${a// /,}
echo $x # output: 1,2,3,4,5
支持多字符分隔符的100%纯Bash函数是:
function join_by {
local d=${1-} f=${2-}
if shift 2; then
printf %s "$f" "${@/#/$d}"
fi
}
例如,
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
join_by '-n' '-e' '-E' '-n' #-e-n-E-n-n
join_by , #
join_by , a #a
上面的代码基于@gniourf_gniourf、@AdamKatz、@MattCowell和@x-yuri的想法。它使用选项errexit (set -e)和nounset (set -u)。
或者,一个更简单的只支持单个字符分隔符的函数是:
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
这个解决方案是基于Pascal Pilz最初的建议。
前面提出的解决方案的详细说明可以在“如何在bash脚本中连接()数组元素”中找到,这是meleu在dev.to上发表的一篇文章。
这里有一个单行,有点奇怪,但适用于多字符分隔符,并支持任何值(包括包含空格或任何东西):
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,因为作者并不真正理解他们在做什么……
下面是一个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}"
}
也许,例如,
SAVE_IFS="$IFS"
IFS=","
FOOJOIN="${FOO[*]}"
IFS="$SAVE_IFS"
echo "$FOOJOIN"