![在 shell 中为 $* 的每个元素添加一个字符串](https://linux22.com/image/177454/%E5%9C%A8%20shell%20%E4%B8%AD%E4%B8%BA%20%24*%20%E7%9A%84%E6%AF%8F%E4%B8%AA%E5%85%83%E7%B4%A0%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2.png)
我正在寻找最简单的解决方案,它$*
作为输入,并扩展到以给定字符串为前缀和后缀的每个元素:
$*=foo bar baz
<solution(x,y)>=xfooy xbary xbazy
我可以做前置或附加,但不能同时做:
echo ${*/#/x}
# prints xfoo xbar xbaz
echo ${*/%/y}
# prints fooy bary bazy
我无法结合这两种解决方案。这文档声称parameter=* 情况下的扩展返回的值是一个列表,但我无法这样使用它。我想将生成的值数组作为单独的参数传递给进一步的命令,因此简单地构建单个字符串是行不通的。
答案1
${var/pattern/replacement}
zsh
是一个 ksh93 参数扩展运算符,也受、mksh
和的支持bash
,但有一些变体(mksh
's 目前无法对数组进行操作)。
克什93
在 中ksh93
,您需要为with${var/*/x\0y}
的扩展添加前缀with ,并为后缀with ,并对数组的每个元素执行此操作。$var
x
y
${array[@]/*/x\0y}
因此,对于位置参数数组:
print -r -- "${@/*/x\0y}"
(但是请注意,就像您的一样${*/#/x}
,当位置参数列表为空时,它会出现错误)。
桀骜
zsh
ksh93
与s等效的\0
调用替换中匹配字符串的是$MATCH
,但前提是您(#m)
在模式中使用(为此您需要该extendedglob
选项):
set -o extendedglob
print -r -- "${@/(#m)*/x${MATCH}y}"
但是在 中zsh
,您可以嵌套参数扩展,因此您也可以这样做:
print -r -- ${${@/#/x}/%/y}
尽管您可能更愿意使用$^array
打开rcexpandparam
该数组扩展的运算符,使其表现得像大括号扩展:
print -r -- x$^@y
或者你可以使用:
printf -v argv x%sy "$@"
就地修改$@
(又名$argv
in )(这里假设不是zsh
"$@"
空列表)。
巴什
在bash
shell 中,您可能需要使用中间数组分两步执行此操作,如下所示由 @L.ScottJohnson 显示,或$@
就地修改:
set -- "${@/#/x}"
echo -E "${@/%/y}"
(这里假设前缀(x
在本例中)不以 开头-
)。
POSIXly
您可以使用循环就地修改位置参数:
for i do
set -- "$@" "x${i}y"
shift
done
echo "$@"
(但请注意,echo
不能可移植地用于显示可能包含反斜杠字符或以 开头的任意数据-
)
笔记
请注意,$*
参数扩展的形式(仅在引用时有用)是一种旨在连接位置参数($IFS
默认第一个字符为 SPC)。您需要$@
(再次引用)将所有位置参数扩展为分隔参数。不加引号,$*
并且$@
没有什么意义(除非zsh
它们扩展到非空位置参数),因为它们会受到 split+glob 的影响,并且 shell 之间的行为有所不同。
答案2
#!/bin/bash
echo $*
FIELDS=("${@/#/x}")
FIELDS=("${FIELDS[@]/%/y}")
echo "${FIELDS[*]}"
运行时:
$ t.sh foo bar baz
foo bar baz
xfooy xbary xbazy
答案3
给定一个列表$@
...打印它
set -- foo bar baz
printf '%s\n' "$@"
foo
bar
baz
...执行列表操作
set -- $(printf 'x%sy ' "$@")
printf '%s\n' "$@"
xfooy
xbary
xbazy
... 字符串化列表
printf '%s\n' "$*"
xfooy xbary xbazy
不涉及特殊的 bash 功能。