Prepend and append a string to each element of $* in shell

${var/pattern/replacement} is a ksh93 parameter expansion operator, also supported by zsh, mksh, and bash, though with variations (mksh's currently can't operate on arrays).

ksh93

In ksh93, you'd do ${var/*/x\0y} to prefix the expansion of $var with x and suffix with y, and ${array[@]/*/x\0y} to do that for each element of the array.

So, for the array of positional parameters:

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

(beware however that like for your ${*/#/x}, it's buggy when the list of positional parameters is empty).

zsh

zsh's equivalent of ksh93's \0 to recall the matched string in the replacement is $MATCH, but only if you use (#m) in the pattern (for which you need the extendedglob option):

set -o extendedglob
print -r -- "${@/(#m)*/x${MATCH}y}"

But in zsh, you can nest parameter expansions, so you can also do:

print -r -- ${${@/#/x}/%/y}

Though you would probably rather use the $^array operator which turns on rcexpandparam for the expansion of that array, making it behave like brace expansion:

print -r -- x$^@y

Or you could use:

printf -v argv x%sy "$@"

To modify $@ (aka $argv in zsh) in-place (here assuming "$@" is not the empty list).

bash

In the bash shell, you'd probably need to do it in two steps with an intermediary array as shown by @L.ScottJohnson, or modifying $@ in place with:

set -- "${@/#/x}"
echo -E "${@/%/y}"

(here assuming the prefix (x in this case), doesn't start with -).

POSIXly

You could modify the positional parameters in-place with a loop:

for i do
  set -- "$@" "x${i}y"
  shift
done
echo "$@"

(though beware that echo can't be used portably to display arbitrary data that may contain backslash characters or start with -)

Note

Note that the $* form of parameter expansion (which is only useful quoted), is the one that is meant to concatenate the positional parameters (with the first character of $IFS, SPC by default). You need $@ (again, quoted) to expand to all positional parameters as separated arguments. Unquoted, $* and $@ make little sense (except in zsh where they expand to the non-empty positional parameters) as they would be subject to split+glob, and the behaviour varies between shells.


#!/bin/bash
echo $*
FIELDS=("${@/#/x}")
FIELDS=("${FIELDS[@]/%/y}")
echo "${FIELDS[*]}"

When run:

$ t.sh foo bar baz
foo bar baz
xfooy xbary xbazy

Given a list in $@
... print it

set -- foo bar baz
printf '%s\n' "$@"
foo
bar
baz

... perform a list op

set -- $(printf 'x%sy ' "$@")
printf '%s\n' "$@"
xfooy
xbary
xbazy

... stringify list

printf '%s\n' "$*"
xfooy xbary xbazy

No special bash features involved.