在 shell 中为 $* 的每个元素添加一个字符串

在 shell 中为 $* 的每个元素添加一个字符串

我正在寻找最简单的解决方案,它$*作为输入,并扩展到以给定字符串为前缀和后缀的每个元素:

$*=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 ,并对数组的每个元素执行此操作。$varxy${array[@]/*/x\0y}

因此,对于位置参数数组:

print -r -- "${@/*/x\0y}"

(但是请注意,就像您的一样${*/#/x},当位置参数列表为空时,它会出现错误)。

桀骜

zshksh93与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 "$@"

就地修改$@(又名$argvin )(这里假设不是zsh"$@"空列表)。

巴什

bashshell 中,您可能需要使用中间数组分两步执行此操作,如下所示由 @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 功能。

相关内容