我有一个数组:
CATEGORIES=(one two three four)
我可以使用参数扩展在每个数组成员前面添加:
echo ${CATEGORIES[@]/#/foo }
我可以以相同的方式附加到每个数组成员:
echo ${CATEGORIES[@]/%/ bar}
我怎样才能两者兼得?这些都不起作用:
echo ${CATEGORIES[@]/(.*)/foo \1 bar}
echo ${CATEGORIES[@]/(.*)/foo $1 bar}
echo ${CATEGORIES[@]/(.*)/foo ${BASH_REMATCH[1]} bar}
答案1
根据您的最终目标,您可以使用printf
:
$ a=(1 2 3)
$ printf "foo %s bar\n" "${a[@]}"
foo 1 bar
foo 2 bar
foo 3 bar
printf
重新使用格式字符串,直到所有参数都用完,因此它提供了一种将某些格式应用于一组字符串的简单方法。
答案2
根据记录, with zsh
,有一个${^array}
运算符可以在数组元素上打开类似大括号的扩展。所以:
$ a=(one two three)
$ b=('foo '${^a}' bar')
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>
搜索和替换也适用于zsh
.
$ printf '<%s>\n' ${a//(#m)*/foo $MATCH bar}
<foo one bar>
<foo two bar>
<foo three bar>
以及printf -v
在数组上:
$ b=(); printf -v b 'foo %s bar' "$a[@]"
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>
如果echo ${CATEGORIES[@]/(.*)/foo \1 bar}
写成ksh93
:
$ printf '<%s>\n' "${CATEGORIES[@]/@(.*)/foo \1 bar}"
<foo one bar>
<foo two bar>
<foo three bar>
答案3
p='* "foo '
s=' bar $USER'
CATEGORIES=(one two three four)
CATEGORIES=("${CATEGORIES[@]/#/$p}")
CATEGORIES=("${CATEGORIES[@]/%/$s}")
paste <(printf '[%s]\n' "${!CATEGORIES[@]}") \
<(printf '%s\n' "${CATEGORIES[@]}")
输出:
[0] * "foo one bar $USER
[1] * "foo two bar $USER
[2] * "foo three bar $USER
[3] * "foo four bar $USER
答案4
这是一个特例当附加(或前置)字符串是一个时适合的解决方案单个字符,并且不需要新数组中的值:
array=( aa bb cc )
IFS="]" # or, IFS="["
echo "${array[*]/#/ [}$IFS" # or, echo "$IFS${array[*]/%/] }
产生输出[aa] [bb] [cc]
.
- 带引号的形式在每对之间
"${array[*]}"
添加分隔符( 的第一个字符,这是出现约束的地方)]
IFS
${array[*]/#/ [}
添加[
到每个元素的前面(或/%/
附加的形式)- 最后添加一个尾随
]
(fromIFS
)到扩展值
如果一一应用这些步骤,您将得到:
aa]bb]cc
[aa] [bb] [cc
[aa] [bb] [cc]
(您也可以轻松地将数据恢复为新数组如果这些值不包含空格。)
您可以在一行中执行不同的前缀/后缀操作:
for ii in "${array[@]/#/foo }"; do echo "${ii/%/ bar}"; done
这是一个更强大的printf
解决方案,可以复制到新数组:
mapfile -d '' newarray < <(printf "foo %s bar\0" "${array[@]}")
尽管以牺牲子 shell 为代价(需要 bash-4.4 mapfile -d
)
最后是一个循环变体,它复制到新数组,并且如果需要的话还可以处理稀疏数组和关联数组。
declare -a array newarray # -a for indexed array, -A for associative
array=( one two three )
for ii in "${!array[@]}"; do
printf -v "newarray[$ii]" "foo %s bar" "${array[$ii]}"
done
(printf
不是必需的,您可以直接分配,但恕我直言,它更清楚。bash
(还!)支持打印到数组中,但是zsh
支持打印到数组中,为您提供无循环复制和转换单行,请参阅上面 Stéphane 的答案。)
这里有用的是,如果bash
支持通用&
(如$MATCH
)zsh
作为扩展中匹配字符串的占位符。代码就在那里(并且已经很长一段时间了),但遗憾的是它尚未启用(请shouldexp_replacement()
参阅subst.c
)。如果启用它(两次#if 0
更改,然后重新编译),这将按预期工作:
array=( aa bb cc )
newarray=( "${array[@]/*/foo & bar}" )
没关系,也许在下一个版本中可用......
compgen
有前缀/后缀操作(并且支持&
,但不是我们可以在此处使用的方式)。我们能做的最好的事情还不如穆鲁的printf
解决方案:
compgen -P "foo " -S " bar" -W "${array[*]}"
(注意-W
只需要一个选项,因此数组被展平,这会导致带有空格或任何内容的值出现问题IFS
)