Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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?

share|improve this question

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
share|improve this answer

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.

Tests:

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.

Tests:

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'
share|improve this answer
    
Can't use perl. But thanks for the thorough answer anyway –  SSumner Jun 11 '12 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

Explanation:

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.

share|improve this answer
    
I had already found my answer before seeing yours and mine is easier for me to understand. Thanks anyway –  SSumner Jun 11 '12 at 14:20
up vote 1 down vote accepted

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!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.