如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
如果我在Bash中有一个这样的数组:
FOO=( a b c )
如何用逗号连接元素?例如,生成a b c。
当前回答
也许我遗漏了一些明显的东西,因为我是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的答案,但推广到一个函数。
其他回答
这个特别适用于busybox的sh和$@:
$ FOO=(a b c)
$ printf '%s\n' "${FOO[@]}" | paste -sd,
a,b,c
Or:
join_by() {
local d=$1
shift
printf '%s\n' "$@" | paste -sd "$d"
}
join_by , "${FOO[@]}" # a,b,c
$ set a 'b c' d
$ history -p "$@" | paste -sd,
a,b c,d
使用变量间接直接引用数组也可以。也可以使用命名引用,但它们在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的回答中可以看到我的评论。
还有另一个解决方案:
#!/bin/bash
foo=('foo bar' 'foo baz' 'bar baz')
bar=$(printf ",%s" "${foo[@]}")
bar=${bar:1}
echo $bar
编辑:相同,但用于多字符可变长度分隔符:
#!/bin/bash
separator=")|(" # e.g. constructing regex, pray it does not contain %s
foo=('foo bar' 'foo baz' 'bar baz')
regex="$( printf "${separator}%s" "${foo[@]}" )"
regex="${regex:${#separator}}" # remove leading separator
echo "${regex}"
# Prints: foo bar)|(foo baz)|(bar baz
我将数组作为字符串回显,然后将空格转换为换行,然后使用粘贴将所有内容连接到一行,如下所示:
tr " " "\n" <<< "$FOO" |粘贴-sd, -
结果:
a, b, c
对我来说,这似乎是最快最干净的!