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.
echo ' 1 2     3  '|sed 's/[[:space:]]*/_/g'

I want to see _1_2_____3__ as the output. Instead, I am seeing _1_2_3_ as the output. What am I doing wrong??

EDIT
The other thing confusing me, which I forgot to put in the above example, is why this:

echo ' test1 test2  ' | sed 's/[[:space:]]*/_/g'

shows this:

_t_e_s_t_1_t_e_s_t_2_

How can [[:space:]] match between t and e and s...?

share|improve this question
1  
The posted answer already answer that too. * matches 0 or more spaces. –  Leiaz Aug 16 at 19:03
    
@Leiaz Hmmm....didn't think of that. So how do I match one or more? –  BenjiWiebe Aug 16 at 19:03
    
With + echo ' test1 test2 ' | sed 's/[[:space:]]\+/_/g' –  Leiaz Aug 16 at 19:05
1  
@Leiaz: Use 's/[[:space:]]\{1,\}/_/g' for portability. –  Gnouc Aug 16 at 19:08
    
@Leiaz Oh yes...been too long since I've studied regex. I do remember now about '+'. –  BenjiWiebe Aug 16 at 19:14

3 Answers 3

up vote 6 down vote accepted

Because you use *, meaning it matches 0 or more spaces. So zero or multiple spaces is substitued by one underscore _.

Try:

$ echo ' 1 2     3  ' | sed 's/[[:space:]]/_/g'
_1_2_____3__

Remember that [[:space:]] also matches tab, newline, carriage return.

Note

share|improve this answer

You've already got an answer but I want to point out that in such simple scenario there is no need to be fancy:

$ echo ' 1 2     3  ' | sed 's/ /_/g'
_1_2_____3__

If you want to replace only spaces and tabs you can use [ \t] construct as well:

$ echo -e " 1\t2     3  " | sed 's/[ \t]/_/g'
_1_2_____3__
share|improve this answer

The question asks explicitly about sed, and it's a very valid question about sed regexp syntax.

But in case the underlying question is about replacing spaces by _ really, here is an alternative answer using the "right tool for the job" for translating characters, which is tr. (man tr).

The command tr abc 123 replaces the chars of the first list with the corresponding chars in the second. Thus, tr ' ' _ replaces space by underscore.

$ echo ' 1 2     3  ' | tr ' ' _
_1_2_____3__


To show the more general case, including various kinds of whitespace like your example,
here is the output for only translating the normal space character ' ' for comparison:

echo ' 1 2     3  x\ny\tz' | tr ' ' _        
_1_2_____3__x
y       z

And here is the output when translating all characters of the class :space: to _:

echo ' 1 2     3  x\ny\tz' | tr '[:space:]' _
_1_2_____3__x_y_z_

(Note there is no newline at the end of the output - and there is a _ after the z.)
This can be written explicitly as tr ' \t\n' _, which is the short form of tr ' \t\n' ___.

$ echo ' 1 2     3  x\ny\tz' | tr ' \t\n' _    
_1_2_____3__x_y_z_
share|improve this answer
    
I know about tr. I will forever regret the example I initially posted. I was specifically wondering how to replace a sequence of whitespace with one character, even though I did a poor job of explaining that. –  BenjiWiebe Aug 19 at 1:35
    
I really did not post my real problem at first, just a portion of it. I thought I could figure out the main problem if I could get over the puzzling behavior of my first example. –  BenjiWiebe Aug 19 at 1:36
    
Oh, you were clear enough that you ask about sed; But even if the answer is not helpful for you, it may help someone else reading the questions and answers. Someone who uses sed like in the answers should at least know that there is a much tool simpler tool for this. –  Volker Siegel Aug 19 at 13:50

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.