24

I'd like to change the following patterns:

getFoo_Bar

to:

getFoo_bar

(note the lower b)

Knowing neither foo nor bar, what is the replacement pattern?

I started writing

sed 's/\(get[A-Z][A-Za-z0-9]*_\)\([A-Z]\)/\1

but I'm stuck: I want to write "\2 lower case", how do I do that?

Maybe sed is not adapted?

Chad Birch
  • 73,098
  • 23
  • 151
  • 149
cadrian
  • 7,332
  • 2
  • 33
  • 42

7 Answers7

40

To change getFoo_Bar to getFoo_bar using sed :

echo "getFoo_Bar" | sed 's/^\(.\{7\}\)\(.\)\(.*\)$/\1\l\2\3/'

The upper and lowercase letters are handled by :

  • \U Makes all text to the right uppercase.
  • \u makes only the first character to the right uppercase.
  • \L Makes all text to the right lowercase.
  • \l Makes only the first character to the right lower case. (Note its a lowercase letter L)

The example is just one method for pattern matching, just based on modifying a single chunk of text. Using the example, getFoo_BAr transforms to getFoo_bAr, note the A was not altered.

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
Matt Thomas
  • 1,437
  • 1
  • 11
  • 3
  • 1
    Is there some way to make things go back to normal after an \L command? – Benjamin Aug 27 '10 at 09:41
  • 7
    From http://www.gnu.org/software/sed/manual/sed.html : `\E` _Stop case conversion started by_ `\L` _or_ `\U`. – Xr. Nov 18 '11 at 08:25
  • 2
    This is a great answer that goes far and beyond just answering the original question. It provides reference information about dealing with all kinds of case transformation tasks in sed. Saved me lots of research time. Thank you! – rustyx Jun 03 '12 at 10:54
  • 4
    this gives me getFoo_lBar with mac 10.8 default sed. I guess mac doesn't handle \L or \l – Michael Chinen Nov 14 '13 at 00:29
26
s/\(get[A-Z][A-Za-z0-9]*_\)\([A-Z]\)/\1\L\2/g

Test:

$ echo 'getFoo_Bar' | sed -e 's/\(get[A-Z][A-Za-z0-9]*_\)\([A-Z]\)/\1\L\2/g'
getFoo_bar
strager
  • 88,763
  • 26
  • 134
  • 176
  • 1
    To extend the answer, here's the general expression to turn to lower case all characters: `echo getFoo_Bar | sed -e 's/\([A-Z][A-Za-z0-9]*\)/\L\1/g'`, that produces `getfoo_bar` – espinchi Jun 22 '12 at 18:21
  • 10
    Note that this solution works only with GNU sed. There is no `\l`/`\L`/`\u`/`\U`/`\E` in POSIX sed. In this case you could use perl (see [@user83591's answer to this question](http://stackoverflow.com/a/689620/2451238)) or awk (see [my answer to another question](http://stackoverflow.com/a/18298882/2451238)). – mschilli Aug 28 '13 at 09:25
  • @mschilli - are you saying that POSIX sed doesn't understand tagged regexes? I don't have it to test with - I have GNU sed. Quite a significant shortcoming if it doesn't, no? – Graham Nicholls Aug 05 '18 at 15:33
  • @GrahamNicholls: From [the `sed` manual](https://www.gnu.org/software/sed/manual/html_node/The-_0022s_0022-Command.html): '*Finally, **as a GNU sed extension**, you can include a special sequence made of a backslash and one of the letters L, l, U, u, or E.*' – mschilli Aug 06 '18 at 10:24
8

Somewhat shorter:

echo getFoo_Bar | sed 's/_\(.\)/_\L\1/'
kalyanji
  • 4,608
  • 2
  • 17
  • 6
5

Shortest I can come up with:

echo getFoo_Bar | sed 's/_./\L&/'
Peter.O
  • 6,696
  • 4
  • 30
  • 37
Dušan
  • 59
  • 1
  • 1
2

You can use perl for this one:

perl -pe 's/(get[A-Z][A-Za-z0-9]*)_([A-Z])/\1_\l\2/'

The \l is the trick here.

sed doesn't do upper/lowercase on matched groups.

brian-brazil
  • 31,678
  • 6
  • 93
  • 86
0

If you want to write everything in lowercase just after underscore, than this would work for you:

echo getFoo_Bar | gawk -F_ '{print tolower($2)}'
Diosney
  • 10,520
  • 15
  • 66
  • 111
-2
echo getFoo_Bar | sed 's/[Bb]/\L&/g'
Widor
  • 13,003
  • 7
  • 42
  • 64
  • You missed the point. You're doing a global search/replace here, not the one after the underscore. – Jon M Apr 17 '15 at 07:17