如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
当前回答
这些解决方案中的许多(如果不是大多数的话)依赖于晦涩难懂的语法、耗费脑力的正则表达式技巧或对外部可执行文件的调用。我想提出一个简单的、只使用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
$
其他回答
$ set a 'b c' d
$ history -p "$@" | paste -sd,
a,b c,d
也许迟到了,但这对我来说是可行的:
function joinArray() {
local delimiter="${1}"
local output="${2}"
for param in ${@:3}; do
output="${output}${delimiter}${param}"
done
echo "${output}"
}
下面是大多数POSIX兼容shell支持的一个:
join_by() {
# Usage: join_by "||" a b c d
local arg arr=() sep="$1"
shift
for arg in "$@"; do
if [ 0 -lt "${#arr[@]}" ]; then
arr+=("${sep}")
fi
arr+=("${arg}") || break
done
printf "%s" "${arr[@]}"
}
我相信这是最短的解决方案,正如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
使用变量间接直接引用数组也可以。也可以使用命名引用,但它们在4.3中才可用。
使用这种形式的函数的好处是,分隔符可以是可选的(默认为默认IFS的第一个字符,它是一个空格;如果你愿意,也可以将其设置为空字符串),并且它避免了两次展开值(第一次作为参数传递,第二次作为函数中的“$@”)。
这个解决方案也不需要用户在命令替换中调用函数(调用子shell)来获得赋值给另一个变量的字符串的连接版本。
function join_by_ref {
__=
local __r=$1[@] __s=${2-' '}
printf -v __ "${__s//\%/%%}%s" "${!__r}"
__=${__:${#__s}}
}
array=(1 2 3 4)
join_by_ref array
echo "$__" # Prints '1 2 3 4'.
join_by_ref array '%s'
echo "$__" # Prints '1%s2%s3%s4'.
join_by_ref 'invalid*' '%s' # Bash 4.4 shows "invalid*[@]: bad substitution".
echo "$__" # Prints nothing but newline.
请随意为该函数使用一个更舒服的名称。
这适用于3.1到5.0-alpha。正如所观察到的,变量间接性不仅适用于变量,也适用于其他参数。
参数是存储值的实体。它可以是一个名字 数字,或以下特殊字符中列出的一个 参数。变量是用名称表示的参数。
数组和数组元素也是参数(存储值的实体),对数组的引用在技术上也是对参数的引用。和特殊的参数@很像,数组[@]也有一个有效的引用。
偏离参数本身引用的修改或选择形式的展开(如子字符串展开)不再工作。
更新
在Bash 5.0的发布版本中,变量间接已经被称为间接扩展,其行为已经在手册中明确记录:
如果参数的第一个字符是感叹号(!),并且 Parameter不是一个nameref,它引入了一个间接级别。 Bash使用通过展开参数的其余部分所形成的值作为 新的参数;然后展开该值,并在 其余的扩充,而不是原来的扩充 参数。这就是所谓的间接扩张。
请注意,在${parameter}的文档中,parameter被称为“PARAMETERS中描述的shell参数或数组引用”。在数组的文档中,提到了“数组的任何元素都可以使用${name[下标]}引用”。这使得__r[@]成为数组引用。
通过参数加入
在Riccardo Galli的回答中可以看到我的评论。