Ares
Ares

Reputation: 1461

How to capitalize first letter of every word using sed in OSX

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

Upvotes: 4

Views: 6619

Answers (4)

scolfax
scolfax

Reputation: 720

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.

Upvotes: 1

Ed Morton
Ed Morton

Reputation: 203684

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.

Upvotes: 10

Goens
Goens

Reputation: 415

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;"

Upvotes: -1

Diego Torres Milano
Diego Torres Milano

Reputation: 69228

Try:

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

Upvotes: -1

Related Questions