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.