在Bash中给$@添加前缀和后缀

18

如何给$@添加前缀和后缀?

如果我执行$PREFIX/$@/$SUFFIX,则只会在第一个参数中获得前缀和后缀。


1
你需要迭代数组,并为每个条目添加前缀和后缀。 - Sameer Naik
你是否想要在每个参数前后添加前缀和后缀,或者在现有参数集的两侧添加新的前缀和后缀参数?例如,如果你的前缀是P,后缀是S,而$@1 2 3,你是想要得到P1S P2S P3S还是P 1 2 3 S呢? - dimo414
1
我正在寻找 P1S P2S P3S - Richard
3个回答

38

我会使用 [参数扩展] 来完成这个任务。

$ set -- one two three
$ echo "$@"
one two three
$ set -- "${@/#/pre}" && set -- "${@/%/post}"
$ echo "$@"
preonepost pretwopost prethreepost

注意

  • # 匹配开头
  • % 匹配结尾
  • ${@} 周围使用双引号会将每个元素视为单独的单词,因此替换会发生在每个位置参数上。

2
这很好而且紧凑。楼主应该考虑将其设为被采纳的解决方案。 - John1024

10

让我们创建一个用于测试的参数:

$ set -- one two three
$ echo "$@"
one two three

现在,让我们使用bash添加前缀和后缀:

$ IFS=$'\n' a=($(printf "pre/%s/post\n" "$@"))
$ set -- "${a[@]}"
$ echo -- "$@"
pre/one/post pre/two/post pre/three/post

限制:(a)由于这使用换行符分隔字符串,如果您的$@本身包含换行符,则无法正常工作。在这种情况下,可能有另一种选择 IFS 可以胜任。(b) 这是受到通配符影响的。 如果这两者中的任何一个是问题,请参见下面的更一般解决方案。

另一方面,如果定位参数不包含空格,则不需要更改 IFS

此外,如果更改了 IFS,则可能希望先保存 IFS 然后再恢复它。

更一般的解决方案

如果我们不想对空格进行任何假设,我们可以使用循环修改 "$@":

$ a=(); for p in "$@"; do a+=("pre/$p/post"); done
$ set -- "${a[@]}"
$ echo "$@"
pre/one/post pre/two/post pre/three/post

为什么我们需要在这里更改IFS?我尝试过不更改,似乎也可以工作。 - Richard
4
只有在参数中包含空格或制表符时,更改IFS才是重要的。 否则,它不是必需的。 set 是一个shell内置命令,用于设置位置参数,除此之外还有其他功能。 - John1024
@mklement0 您具体在哪里看到 "globbing" 问题? - John1024
1
@John1024:a =($(echo'*')); declare-p a。命令替换的输出受到全局匹配的影响。 - mklement0
1
@mklement0 好的。谢谢。我更新了答案,指出该问题适用于第一种方法。 - John1024
显示剩余3条评论

8

注意:这基本上是sjam的答案的略微详细版本。

John1024的答案很有帮助,但是:

  • 需要一个子shell(涉及子进程
  • 可能会导致不想要的通配符扩展应用于数组元素。

幸运的是,Bash参数展开也可以应用于数组,避免了这些问题:

set -- 'one' 'two' # sample input array, which will be reflected in $@

# Copy $@ to new array ${a[@]}, adding a prefix to each element.
# `/#` replaces the string that follows, up to the next `/`,
# at the *start* of each element.
# In the absence of a string, the replacement string following
# the second `/` is unconditionally placed *before* each element.
a=( "${@/#/PREFIX}" )

# Add a suffix to each element of the resulting array ${a[@]}.
# `/%` replaces the string that follows, up to the next `/`,
# at the *end* of each element.
# In the absence of a string, the replacement string following
# the second `/` is unconditionally placed *after* each element.
a=( "${a[@]/%/SUFFIX}" )

# Print the resulting array.
declare -p a

这将产生:
declare -a a='([0]="PREFIXoneSUFFIX" [1]="PREFIXtwoSUFFIX")'

请注意,双引号引用数组下标对于保护它们的元素免受潜在的单词分割文件名扩展(globbing)(这两者都是shell扩展的实例)至关重要。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接