4

I'm trying to capitalize the first letter of every word in a string using the following sed command, but it's not working:

 echo "my string" | sed 's/\b\(.\)/\u\1/g'

Output:

 my string

What am I doing wrong?

Thank you

Veerendra Gadekar
  • 4,452
  • 19
  • 24
Ares
  • 1,411
  • 1
  • 19
  • 35
  • possible duplicate of [How can I use regex with sed (or equivalent unix command line tool) to fix title case in LaTeX headings?](http://stackoverflow.com/questions/31909531/how-can-i-use-regex-with-sed-or-equivalent-unix-command-line-tool-to-fix-title) – ghoti Aug 12 '15 at 15:32

4 Answers4

8

Given your sample input, this will work in any awk:

$ echo 'my string' | awk '{for (i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)} 1'
My String

If that doesn't do what you really want then edit your question to show some more truly representative sample input and expected output.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

Here is a sed solution that works on OSX:

echo 'my string
ANOTHER STRING
tHiRd StRiNg' | sed -En '
y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
:loop
h
s/^(.*[^a-zA-Z0-9])?([a-z]).*$/\2/
t next
b end
:next
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/
G
s/^(.+)\n(.*[^a-zA-Z0-9])?[a-z](.*)$/\2\1\3/
t loop
:end
p
'

Output:
My String
Another String
Third String

The sed command works as follows:

  1. sed inputs a line, and the first y command transforms all uppercase letters to lowercase.
  2. The commands from :loop to t loop form a loop that executes once for each word in the current line, capitalizing the first letter of each word.
  3. When there are no more words to capitalize for the current line, the p command prints the line, and sed inputs the next line.

Here is how the loop works:

  1. The h command saves the line as it currently stands to the hold space.
  2. The first s command looks for the first letter of the first non-capitalized word. If such a word is found, the s command saves its first letter to the pattern space, and the t command branches to the :next label. If such a word is not found, which indicates that there are no more words to capitalize, the b command is executed instead, branching to the :end label to print out and complete the processing of the current line.
  3. If a word needing capitalizing was found, execution resumes at the :next label, and the y command transforms the first letter, which is now in the pattern space, from lowercase to uppercase.
  4. The G command appends the non-transformed version of the current line from the hold space to the end of the pattern space.
  5. The second s command reconstructs the current line, replacing the first letter of the word currently being processed with its capitalized version.
  6. The t command branches to the :loop label to look for the next word needing capitalization.

Execution speed testing revealed that the current sed approach executes at approximately the same speed as the awk solution submitted by Ed Morton.

scolfax
  • 710
  • 2
  • 6
  • 17
0

This has already been addressed: Uppercasing First Letter of Words Using SED

I get the correct behavior with GNU sed, but not with the standard BSD sed that ships with OS X. I think the \u "regular expression" is a GNU thing. How about "port install gsed"?

Edit: if you really want to use BSD sed, which I would not recommend (because the command becomes very ugly), then you can do the following: sed -E "s:([^[:alnum:]_]|^)a:\1A:g; s:([^[:alnum:]_]|^)b:\1B:g; s:([^[:alnum:]_]|^)c:\1C:g; s:([^[:alnum:]_]|^)d:\1D:g; s:([^[:alnum:]_]|^)e:\1E:g; s:([^[:alnum:]_]|^)f:\1F:g; s:([^[:alnum:]_]|^)g:\1G:g; s:([^[:alnum:]_]|^)h:\1H:g; s:([^[:alnum:]_]|^)i:\1I:g; s:([^[:alnum:]_]|^)j:\1J:g; s:([^[:alnum:]_]|^)k:\1K:g; s:([^[:alnum:]_]|^)l:\1L:g; s:([^[:alnum:]_]|^)m:\1M:g; s:([^[:alnum:]_]|^)n:\1N:g; s:([^[:alnum:]_]|^)o:\1O:g; s:([^[:alnum:]_]|^)p:\1P:g; s:([^[:alnum:]_]|^)q:\1Q:g; s:([^[:alnum:]_]|^)r:\1R:g; s:([^[:alnum:]_]|^)s:\1S:g; s:([^[:alnum:]_]|^)t:\1T:g; s:([^[:alnum:]_]|^)u:\1U:g; s:([^[:alnum:]_]|^)v:\1V:g; s:([^[:alnum:]_]|^)w:\1W:g; s:([^[:alnum:]_]|^)x:\1X:g; s:([^[:alnum:]_]|^)y:\1Y:g; s:([^[:alnum:]_]|^)z:\1Z:g;"

Community
  • 1
  • 1
Goens
  • 407
  • 3
  • 11
  • Unfortunately, installing a gsed is not a viable option. I'm writing a script that will be used mainly by other OSX users. – Ares Aug 12 '15 at 15:17
  • Then I think sed is not the right tool for the job here, since you won't get capitalization without GNU extensions, you might want to try perl for example (don't know about awk). If you really *need* to do it with BSD sed, then you have to do it letter by letter... – Goens Aug 12 '15 at 15:33
  • 1
    I've reached the same conclusion. I ended up using a bash for loop and tr. – Ares Aug 12 '15 at 15:53
  • @Ares Every time you write a loop in shell just to manipulate text you have the wrong approach (google it). Just use awk since text manipulation is what it was invented to do. – Ed Morton Aug 12 '15 at 18:27
-1

Try:

echo "my string" | sed -r 's/\b(.)/\u\1/g'
Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134