如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
当前回答
不使用外部命令:
$ 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
警告,它假设元素没有空格。
其他回答
也许,例如,
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(为什么你不喜欢它?)并传递一个变量名,你当然可以为返回的字符串使用一个全局变量:
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,因为作者并不真正理解他们在做什么……
顶部答案的简短版本:
joinStrings() { local a=("${@:3}"); printf "%s" "$2${a[@]/#/$1}"; }
用法:
joinStrings "$myDelimiter" "${myArray[@]}"
$ set a 'b c' d
$ history -p "$@" | paste -sd,
a,b c,d