I have a shell variable for example. a="big little man". How do I use regex in bash print out the variable with only the middle word capitalized? (big LITTLE man)

I can do it by separating the variable into 3 variables and then expanding them in echo. For eg first=${a%* }, etc. But how do I do it in one single go with one regex?

Is it possible to do it in a single line? Using the capitalize operators (^)

  • I can do it by separating the string into 3 different variables and then echoing it together with the mid variable capitalized. I wanted to know if I can do it in one go
    – Vaish MK
    Feb 9, 2019 at 7:13

3 Answers 3



Assuming you're using GNU sed:

$ sed -E 's/(\w+) (\w+) (\w+)/\1 \U\2\E \3/' <<< 'big little man'
big LITTLE man

This command makes use of the GNU specific sequences \U and \E which turn the subsequent characters into upper case and cancel case conversion respectively.


While not operating on regular expressions, awk provides another convenient way to capitalize a single word:

$ awk '{print($1, toupper($2), $3)}' <<< 'big little man'
big LITTLE man


Although Bash on its own does not have regular expression based conversions, you can still achieve partial capitalization by treating your string as an array, e.g.

$ (read -a words; echo "${words[0]} ${words[1]^^} ${words[2]}") <<< 'big little man'
big LITTLE man

Here ^^ converts the second element of our array (i.e. the second word) to upper case. The feature was introduced in Bash 4.


As requested, doing it in bash on a single line using ${variable^^}:

$ a="big little man"
$ [[ "$a" =~ ^([^ ]+)\ ([^ ]+)\ (.*) ]] && a="${BASH_REMATCH[1]} ${BASH_REMATCH[2]^^} ${BASH_REMATCH[3]}"
$ echo "$a"
big LITTLE man

This matches the regular expression ([^ ]+)\ ([^ ]+)\ (.*) against the string in $a. If it matches, then it contains three substrings separated by spaces. The first and second substring will be any string not containing a space, and the third substring will be the remaining bit of the string.

If the expression matches, the $a value is rewritten with the second substring in upper case.

This assumes that the original string starts with a non-space character.


I don't think you can do it with bash expansion operators in one go. You could with zsh's:

set -o extendedglob # for (#m)

b=${a/(#m) * /${(U)MATCH}}


b=${(S)a/(#b)(*) (*) (*)/$match[1] ${(U)match[2]} $match[3]}


  • (#m) causes the matched string to be available in $MATCH
  • (#b) enables back-references
  • ${(U)var} (also $var:u) turns to upper case (predates bash's ${var^^pattern} by decades).
  • (S) turns on non-greedy matching.
  • Which bash version do you use?
    – Cyrus
    Feb 9, 2019 at 14:55
  • 2
    @Cyrus Stéphane is using zsh, not bash.
    – Kusalananda
    Jun 17, 2020 at 9:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .