I am writing a bash script to automatically generate some other files, and I have to format some strings a certain way. Specifically, the last problem I'm having is formatting a string that has individual capital letters and a word that starts with a capital letter. For example:

O S D Settings needs to become OSD Settings

I have a sed command that strips the first space, but it also deletes the "D" (i.e. O S D Settings -> OS Settings). This command is:

O S D Settings | sed 's/ \([A-Z]\)* \(A-Za-z]*\)/\1/g'

Does anyone know how to delete the spaces in between individual capital letters without losing any letters?

4 Answers 4


This takes care of names like A B Chadwick and A B C D'Souza

Text such as A B cde and A B CDE are not modified.

It uses two temporary null characters \x00 to mark changes (per name) as it progress through a line, removing spaces.

:N and :S are branch-to labels (any name will do)
t and b are branching instructions.
t branches upon a successful replacemnt in the previous s/../../ command.
b branches unconditionally.

sed -r ":N                                                # loop per name
         /(\<[A-Z]\> )+[A-Z][a-z']/{                      # line needs action
             s/((\<[A-Z]\> )+)([A-Z][a-z'])/\x00\1\x00\3/ # add \x00 markers
            :S                                            # loop per space
             s/(\x00[A-Z]+) (\<[A-Z]\>)/\1\2/             # delete a space
             t S                                          # any more spaces? 
             b N                                          # any more names?
         }; s/\x00//g"                                    # remove \x00

It's tricky with sed, but if perl is okay you can do it this way

echo O S D Settings | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'

This is hard in sed because it does not support look-ahead assertions.


echo O S D | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D Settings | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D. | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo One O DDE T. S Asdf Q R Tee | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D\  | perl -p -e 's/([A-Z]) (?=.([^\w]|$))/$1/g'

If you want a sloppy solution with sed, try

echo O S D Settings | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'

Which works for your sample, but will fail for other cases.


echo O S D | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D Settings | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D. | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo One O DDE T. S Asdf Q R Tee | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D\  | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
  • Can't use perl. But thanks for the thorough answer anyway
    – SSumner
    Jun 11, 2012 at 14:17

This might work for you:

echo "O S D Settings and B T W and A B C D'Souza too F Y I" |
sed ':a;s/\(\<[[:upper:]]\>\) \(\<[[:upper:]]\>\([^'\'']\|$\)\)/\1\n\2/g;ta;s/\n//g'
OSD Settings and BTW and ABC D'Souza too FYI


Use a character that does not exist in the original string to replace the spaces you want deleting, then delete that chosen character throughout the string. \n is a good candidate as it cannot exist normally because it is used by sed as line delimiter.

  • I had already found my answer before seeing yours and mine is easier for me to understand. Thanks anyway
    – SSumner
    Jun 11, 2012 at 14:20

I ended up just using sed with pipes to get a statement that is easy for me to understand:

echo O S D Settings | sed 's/\([A-Z][^ ]\)/_\1/g' | sed 's/ //g' | sed 's/_/ /g'

All this does is replaces the spaces I don't want with the underscore and then deletes them. Thanks for all the answers!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .