62
array=(a b c d)

I would like to add a character before each element of the array in order to have this

array=(^a ^b ^c ^d)

An easy way to do that is to loop on array elements and change values one by one

for i in "${#array[@]}"
do
    array[i]="^"array[i]
done

But I would like to know if there is any way to do the same thing without looping on the array as I have to do the same instruction on all elements.

Thanks in advance.

saloua
  • 2,433
  • 4
  • 27
  • 37

2 Answers2

98

Use Parameter Expansion:

array=("${array[@]/#/^}")

From the documentation:

${parameter/pattern/string}

Pattern substitution. The pattern is expanded to produce a pattern just as in pathname expansion. Parameter is expanded and the longest match of pattern against its value is replaced with string. If pattern begins with /, all matches of pattern are replaced with string. Normally only the first match is replaced. If pattern begins with #, it must match at the beginning of the expanded value of parameter. If pattern begins with %, it must match at the end of the expanded value of parameter. If string is null, matches of pattern are deleted and the / following pattern may be omitted. If parameter is @ or *, the substitution operation is applied to each positional parameter in turn, and the expansion is the resultant list. If parameter is an array variable subscripted with @ or *, the substitution operation is applied to each member of the array in turn, and the expansion is the resultant list.

choroba
  • 231,213
  • 25
  • 204
  • 289
  • I have just another question. I would like to know if I can use this to change just a subset of an array because I obtain a syntax error when I run this array[@]:i:10=(${array[@]:i:10}/#/^}) – saloua Oct 05 '12 at 10:59
  • @tuxworker I think you need to assign your sub-range array to another array variable first, then add the prefixes. – Werner Lehmann May 04 '13 at 22:25
  • 1
    NB: If you have IFS=$'\n' (to handle names with whitespace) then the command will not keep the original array structure. It will just make array contain only 1 item (a string list), with all the changed strings. As seen if you run: `declare -p array` afterwards. – Magne Apr 28 '21 at 13:00
10

This way also honor whitespaces in array values:

array=( "${array[@]/#/^}" )

Note, this will FAIL if array was empty and you set previously

set -u

I don't know how to eliminate this issue using short code...

socketpair
  • 1,893
  • 17
  • 15
  • Maybe `array=("${array[@]:+${array[@]/#/^}}")`, but I can't reproduce it (empty array + `set -u`) with neither `bash-4.4.0`, nor `bash-4.1.5`. In the latter you need this construct for iterating over an array with `for`, though. – x-yuri Dec 01 '16 at 19:54
  • How would you mark start and end of the string? From this: `declare -a arr=(12 123); echo "${arr[@]/12/00}"` I want `00 123` but I'm getting `00 003`. – mattalxndr Dec 13 '21 at 22:38