Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I would like to merge each group of lines from file :

    <tr>
            <td >441</td>
            <td >S</td>
            <td >0,74</td>
    </tr>
    <tr>
            <td >442</td>
            <td >S</td>
            <td >0,14</td>
    </tr>

to one line (number of spaces or tabs between td's is not important for me):

    <tr> <td >441</td> <td >S</td> <td >0,74</td> </tr>
    <tr> <td >442</td> <td >S</td> <td >0,14</td> </tr>

Each group ( with ':set line' in vi ) looks like this :

     ^I<tr>$
     ^I^I<td >441</td>$
     ^I^I<td >S</td>$
     ^I^I<td >0,74</td>$
     ^I</tr>$

I have real problem to do it myself with sed command. Any help will be appreciated.

share|improve this question

5 Answers 5

up vote 1 down vote accepted

Here's a solution using perl instead of sed. I find this solution simpler to read and understand.

perl -pe 's|\n|| ; s|</tr>|</tr>\n|' file

output:

<tr>    <td >441</td>   <td >S</td>     <td >0,74</td></tr>
<tr>    <td >442</td>   <td >S</td>     <td >0,14</td></tr>
share|improve this answer
    
Works in my system. –  kato sheen Aug 12 '13 at 16:44
# cat foo.html | xargs echo -n
<tr> <td >441</td> <td >S</td> <td >0,74</td> </tr>

Or to strip all spaces...

# cat foo.html | xargs -n1 echo -n
<tr><td>441</td><td>S</td><td>0,74</td></tr>

You can achieve this affect right from inside vi just by doing:

!!xargs echo -n
share|improve this answer
    
I like this for this feel simpler, but does it work in aix ? Also, didn't it simply remove all newline ? how to handles the 2 line arguments ? –  Antony Lee Aug 11 '13 at 12:46
    
If your file is extremely regular, you can just play with the number of arguments that xargs will handle at once. With your example text, "cat foo.html | xargs -n8 echo" works perfectly. –  aharrison Aug 12 '13 at 3:56
    
As for aix, if the gnu utils exist on aix, then you should be good to go. I'd be surprised if they didn't, but my total lifetime minutes spent at an aix prompt is about 10, so I'm not qualified to answer for it. –  aharrison Aug 12 '13 at 4:06

With sed, you can do this:

$ cat inf
    <tr>
            <td >441</td>
            <td >S</td>
            <td >0,74</td>
    </tr>
$ sed ':a;N;s/\n//;ta' inf
    <tr>            <td >441</td>           <td >S</td>         <td >0,74</td>  </tr>

which does this:

  • :a makes a label
  • N will append the current line to the buffer, thus allowing for the next command
  • s/\n// will replace the new line from the previous command with nothing, thus effectively joining the lines
  • ta is "goto :a"

An easier way is to use tr:

$ cat inf
    <tr>
            <td >441</td>
            <td >S</td>
            <td >0,74</td>
    </tr>
$ cat inf|tr -d '\n'
    <tr>            <td >441</td>           <td >S</td>         <td >0,74</td>  </tr>

where -d '\n' means "delete new line".

EDIT: Misunderstood what you want. If you want to process multiple of the above groups in one input stream, here's what you can do with sed:

$ cat inf
  foo
  baz
    <tr>
            <td >441</td>
            <td >S</td>
            <td >0,74</td>
    </tr>
  fizz
  buzz
    <tr>
            <td >441</td>
            <td >S</td>
            <td >0,74</td>
    </tr>
  tomato
  potato
$ sed -r '/<tr/{:a;N;s/[\t\n]//g;/<\/tr/!ba}' inf
  foo
  baz
<tr><td >441</td><td >S</td><td >0,74</td></tr>
  fizz
  buzz
<tr><td >441</td><td >S</td><td >0,74</td></tr>
  tomato
  potato

As others have mentioned, you can do this in a bit more readable form with awk or perl or python, but please note one thing - regexp is not powerful enough to parse HTML or XML. See this one for a good discussion:

Hope this helps.

share|improve this answer
    
maybe its because I use 'FreeBSD 9.0-RELEASE'. The s/\n// replace doesn't work as it should ( it seems not to find any \n ). 'tr' command makes only one very long line - I would like that each group be in separate line. –  kato sheen Aug 10 '13 at 22:22
    
@katosheen Misunderstood what you meant - see my edit and obviously take a look at other answers, too. I think perl or awk solutions are more readable here, in case you don't need to use sed exclusively. –  icyrock.com Aug 11 '13 at 16:53

Solution with :

awk '/<tr>/,/<\/tr>/{printf("%s", $0)};/<\/tr/{printf("\n")}' file

$ cat file
    <tr>
        <td >441</td>
        <td >S</td>
        <td >0,74</td>
    </tr>
    <tr>
        <td >442</td>
        <td >S</td>
        <td >0,14</td>
    </tr>

$  awk '/<tr>/,/<\/tr>/{printf("%s", $0)};/<\/tr/{printf("\n")}' file
    <tr>    <td >441</td>   <td >S</td>     <td >0,74</td> </tr>
    <tr>    <td >442</td>   <td >S</td>     <td >0,14</td> </tr>
share|improve this answer
    
Works in my system. –  kato sheen Aug 12 '13 at 16:45
sed -r ':k /<tr>/,/<\/tr>/{/<\/tr>/! {N;s/\n/ /;tk}}' file

$ cat file
    <tr>
        <td >441</td>
        <td >S</td>
        <td >0,74</td>
    </tr>
    <tr>
        <td >442</td>
        <td >S</td>
        <td >0,14</td>
    </tr>

$ sed -r ':k /<tr>/,/<\/tr>/{/<\/tr>/! {N;s/\n/ /;tk}}' file
    <tr>    <td >441</td>   <td >S</td>     <td >0,74</td> </tr>
    <tr>    <td >442</td>   <td >S</td>     <td >0,14</td> </tr>
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.