user4513271
user4513271

Reputation:

Bash: convert to lowercase, BUT preserve the case of the first letter of every word

I searched for this repeatedly but I couldn't find an answer for this specific scenario. I'd like to be able to convert a string to lowercase while also preserving any existing titled words.

For example:

Hello, this is a Titled woRd aND ThIs one is UPPERCASED.

should become:

Hello, this is a Titled word and This one is Uppercased.

Every letter would be lowercased, except the first letter of each word would keep its case. I'm familiar with the common forms of changing case but not something this specific. Not to be confused with Title case, as that is not what I'm asking here. Any help is much appreciated.

Upvotes: 1

Views: 725

Answers (2)

Raman Sailopal
Raman Sailopal

Reputation: 12867

Using GNU awk:

awk '{ for (i=1;i<=NF;i++) { printf "%s",substr($i,1,1);for(j=2;j<=length($i);j++) { printf "%s",tolower(substr($i,j,1))} printf "%s"," " } }' <<< "Hello, this is a Titled woRd aND ThIs one is UPPERCASED."

Explanation:

awk '{ 
       for (i=1;i<=NF;i++) {                           # Loop on each word
          printf "%s",substr($i,1,1);                  # Print the first letter in the word
          for(j=2;j<=length($i);j++) {  
            printf "%s",tolower(substr($i,j,1))        # Loop on the rest of the letters in the word and print in lower case
          }  
       printf "%s"," "                                 # Print a space
       } 
     }' <<< "Hello, this is a Titled woRd aND ThIs one is UPPERCASED."

Using bash:

for var in $(echo "Hello, this is a Titled woRd aND ThIs one is UPPERCASED.");
do 
   printf "%s" ${var:0:1};             # Print the first letter of the word
   var1=${var:1};                      # Read the rest of the word into var1
   printf "%s " "${var1,,[$var1]}";    # Convert vars into lowercase and print
done

Upvotes: 2

Thomas
Thomas

Reputation: 181715

Not sure if you need a pure bash solution, but using some commonly available utilities makes life easier.

Using awk:

$ echo 'Hello, this is a Titled woRd aND ThIs one is UPPERCASED.' | \
    awk '{for(i=1;i<=NF;i++){$i=substr($i,1,1)tolower(substr($i,2))}}1'
Hello, this is a Titled word and This one is Uppercased.

It simply iterates over all fields (space-separated) and assigns to each field ($i) the first letter of that field, followed by a downcased copy of the remainder of the field.

Using GNU sed (less portable, but perhaps more readable):

$ echo 'Hello, this is a Titled woRd aND ThIs one is UPPERCASED.' | \
    sed -r 's/\b(\w)(\w*)/\1\L\2/g'
Hello, this is a Titled word and This one is Uppercased.

This matches a word boundary (\b) followed by a letter (word character, \w) and then zero or more letters (\w*). It replaces this by the first letter (\1), followed by the lowercased version (\L) of the remaining letters (\2).

Upvotes: 3

Related Questions