MrPizzaFace
MrPizzaFace

Reputation: 8086

Easiest way to capitalize a string within bash 3.2?

For example: var=dog and echo $var output is dog. Capitalize $var expected output Dog.

Tried multiple ways but just not getting the expected output. Some attempts:

echo $var | sed "s/[a-z]\&[:upper:]//"  #dog
echo $var | sed "s/([a-z])/[:upper:]/"  #dog

Upvotes: 5

Views: 3198

Answers (4)

mklement0
mklement0

Reputation: 438073

tl;dr:

  • macOS, with Unicode support, OR cross-platform, but ASCII-only, and for background information:

    • See the tr solution below.
  • GNU utilities, with Unicode support (Linux: preinstalled; macOS: installable via Homebrew):

    • sed 's/^./\u&/' <<<'dog' # -> 'Dog'
      • macOS: after installing with brew install gnu-sed, use gsed instead of sed
    • awk alternative: see dev-null's answer
      • macOS: after installing with brew install gawk, use gawk instead of awk.
  • Cross-platform, with Unicode support:

  • Bash 4+, with Unicode support, which on macOS you can also install with Homebrew:

    • echo "${var^}"

Try

var='dog'
echo "$(tr '[:lower:]' '[:upper:]' <<<"${var:0:1}")${var:1}" # -> 'Dog'
  • tr '[:lower:]' '[:upper:]' <<<"${var:0:1}" extracts the 1st char from $var (${var:0:1}) and uses tr to translate it to uppercase.

  • ${var:1} returns everything from the 2nd char in $var's value.

Note that this solution is Unicode-aware[1], unlike the macOS awk and Python 2.x solutions Update: @idjaw fixed the Python 2.x solution with .decode('utf-8'), and presumably also slightly faster than them (tr is lighter-weight than awk and python).

[1] This applies to the BSD tr version that comes with macOS. GNU tr, by contrast, does not handle non-ASCII characters correctly - as John1024 notes, according to Wikipedia, "Most versions of tr, including GNU tr and classic Unix tr, operate on single-byte characters and are not Unicode compliant.".


As for your attempt at a sed solution:

Using macOS's (BSD) sed, I'm not aware of any substring-manipulation features.

If you had GNU sed - which you could install via Homebrew - you could use the following:

sed 's/^./\u&/' <<<'dog' # -> 'Dog'

\u tells GNU Sed to capitalize the following letter. Sadly, you can't do that with macOS's Sed.

[:upper:] only ever works as a matching character class, it never performs transformation, which is why your command didn't work.
The only exception is tr, where you can pair an [:upper:] with a [:lower:] to effect transformation, as in my solution above.


Sneak preview of a Bash 4+ solution:

var='dog'; echo "${var^}"

Upvotes: 11

idjaw
idjaw

Reputation: 26586

You can use Python if that's an option:

After input from different people (thanks all), this seems to be a good working solution that is in line with OP requests for only the first letter as proposed by @PM2Ring:

Best proposed solution for first character only

bash-3.2$ var="it's an öyster's life"
bash-3.2$ python -c "import sys;print sys.argv[1].decode('utf8').capitalize()" "$var"
It's an öyster's life

Following solutions attempt to capitalize all first characters of words in a string:

The following solution has some drawbacks:

bash-3.2$ python -c "print raw_input().decode('utf-8').title()" <<<"it's an öyster's life" 
It'S An Öyster'S Life

Simple solution using a variable:

bash-3.2$ var='dog is dog'
bash-3.2$ python -c "print raw_input().decode('utf-8').title()" <<<"$var"
Dog Is Dog

As can be seen from the comments in this answer (thanks for the input all), it is important to note the limitations of using this, especially using OSX native Python language 2.7.

Example 1: (Thanks @john1024 & @dev-null)

Quote issues.

small modification with quotes required to handle the below string sample

var="it's a dog's life"
bash-3.2$ python -c "print '$var'.title()"
It'S A Dog'S Life

Additional example that does not work with my solution: var="hello ''' world"

Example 2: (Thanks @mklement0)

Unicode issues

bash-3.2$ var='öyster'
bash-3.2$ python -c "print '$var'.title()"
öYster

Notice that it capitalized the second letter, which is the first ascii character that the title method will capitalize per how it is expected in Python2.

The following modification to the solution can be made to help with unicode characters:

bash-3.2$ var='öyster'
python -c "print '$var'.decode('utf-8').title()" 
Öyster

Finally, when putting the solutions together from the discussion below, this is how it was put together to finally have:

python -c "print raw_input().decode('utf-8').title()" <<<"it's an öyster's life" 

Upvotes: 3

dawg
dawg

Reputation: 103874

If you want to be unicode aware, consider using perl:

$ perl -lne 'use open qw(:std :utf8); print ucfirst' <<< 'dog'
Dog
$ perl -lne 'use open qw(:std :utf8); print ucfirst' <<< 'élan'
Élan

As pointed out in comments:

$ perl -C -lne 'print ucfirst' <<< 'élan'
Élan

Upvotes: 3

Andreas Louv
Andreas Louv

Reputation: 47099

var="hello world"
echo "$var" | awk '{print toupper(substr($0, 1, 1)) substr($0, 2)}' # Hello world

and if you want to Capitalize Each Word:

var="hello world"
echo "$var" | awk 'BEGIN{RS = " "};{printf("%s ", toupper(substr($0, 1, 1)) substr($0, 2))}' # Hello World

Upvotes: 4

Related Questions