如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
当前回答
我将数组作为字符串回显,然后将空格转换为换行,然后使用粘贴将所有内容连接到一行,如下所示:
tr " " "\n" <<< "$FOO" |粘贴-sd, -
结果:
a, b, c
对我来说,这似乎是最快最干净的!
其他回答
支持多字符分隔符的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上发表的一篇文章。
s=$(IFS=, eval 'echo "${FOO[*]}"')
这些解决方案中的许多(如果不是大多数的话)依赖于晦涩难懂的语法、耗费脑力的正则表达式技巧或对外部可执行文件的调用。我想提出一个简单的、只使用bash的解决方案,它非常容易理解,在性能方面只是稍微次优。
join_by () {
# Argument #1 is the separator. It can be multi-character.
# Argument #2, 3, and so on, are the elements to be joined.
# Usage: join_by ", " "${array[@]}"
local SEPARATOR="$1"
shift
local F=0
for x in "$@"
do
if [[ F -eq 1 ]]
then
echo -n "$SEPARATOR"
else
F=1
fi
echo -n "$x"
done
echo
}
例子:
$ a=( 1 "2 2" 3 )
$ join_by ", " "${a[@]}"
1, 2 2, 3
$
我想指出,任何使用/usr/bin/[或/usr/bin/printf的解决方案本质上都比我的解决方案慢,因为我使用100%纯bash。作为性能的一个例子,这里有一个演示,我创建了一个包含1,000,000个随机整数的数组,然后用逗号将它们全部连接起来,并计时。
$ eval $(echo -n "a=("; x=0 ; while [[ x -lt 1000000 ]]; do echo -n " $RANDOM" ; x=$((x+1)); done; echo " )")
$ time join_by , ${a[@]} >/dev/null
real 0m8.590s
user 0m8.591s
sys 0m0.000s
$
这里有一个单行,有点奇怪,但适用于多字符分隔符,并支持任何值(包括包含空格或任何东西):
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,因为作者并不真正理解他们在做什么……
我相信这是最短的解决方案,正如Benamin W.已经提到的:
(IFS=,; printf %s "${a[*]}")
想要添加,如果你使用zsh,你可以删除子shell:
IFS=, printf %s "${a[*]}"
测试:
a=(1 'a b' 3)
IFS=, printf %s "${a[*]}"
1,a b,3