如果我在Bash中有一个这样的数组:

FOO=( a b c )

如何用逗号连接元素?例如,生成a b c。


当前回答

s=$(IFS=, eval 'echo "${FOO[*]}"')

其他回答

使用变量间接直接引用数组也可以。也可以使用命名引用,但它们在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的回答中可以看到我的评论。

awk -v sep=. 'BEGIN{ORS=OFS="";for(i=1;i<ARGC;i++){print ARGV[i],ARGC-i-1?sep:""}}' "${arr[@]}"

or

$ a=(1 "a b" 3)
$ b=$(IFS=, ; echo "${a[*]}")
$ echo $b
1,a b,3

现在我用的是:

TO_IGNORE=(
    E201 # Whitespace after '('
    E301 # Expected N blank lines, found M
    E303 # Too many blank lines (pep8 gets confused by comments)
)
ARGS="--ignore `echo ${TO_IGNORE[@]} | tr ' ' ','`"

这是可行的,但是(在一般情况下)如果数组元素中有空格,将会严重破坏。

(对于那些感兴趣的人,这是一个围绕pep8.py的包装器脚本)

也许,例如,

SAVE_IFS="$IFS"
IFS=","
FOOJOIN="${FOO[*]}"
IFS="$SAVE_IFS"

echo "$FOOJOIN"

下面是大多数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[@]}"
}