mesclar grupos de linhas com sed

3

Eu gostaria de mesclar cada grupo de linhas do arquivo:

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

para uma linha (número de espaços ou tabulações entre tds não é importante para mim):

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

Cada grupo (com ': set line' no vi) é assim:

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

Eu tenho um problema real para fazer isso sozinho com o comando sed. Qualquer ajuda será apreciada.

    
por kato sheen 10.08.2013 / 23:22

6 respostas

1

Aqui está uma solução usando perl ao invés de sed. Acho essa solução mais simples de ler e entender.

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

saída:

<tr>    <td >441</td>   <td >S</td>     <td >0,74</td></tr>
<tr>    <td >442</td>   <td >S</td>     <td >0,14</td></tr>
    
por 11.08.2013 / 13:53
2

Com sed, você pode fazer isso:

$ 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>

que faz isso:

  • :a faz uma etiqueta
  • N anexará a linha atual ao buffer, permitindo assim o próximo comando
  • s/\n// irá substituir a nova linha do comando anterior por nada, assim efetivamente juntando as linhas
  • ta é "goto: a"

Uma maneira mais fácil é usar 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>

onde -d '\n' significa "excluir nova linha".

EDIT: Não entendi o que você quer. Se você quiser processar vários dos grupos acima em um fluxo de entrada, veja o que você pode fazer com 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

Como outros já mencionaram, você pode fazer isso de uma forma um pouco mais legível com awk ou perl ou python, mas observe uma coisa - o regexp não é poderoso o suficiente para analisar HTML ou XML. Veja este para uma boa discussão:

Espero que isso ajude.

    
por 10.08.2013 / 23:38
1
# cat foo.html | xargs echo -n
<tr> <td >441</td> <td >S</td> <td >0,74</td> </tr>

Ou para despir todos os espaços ...

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

Você pode conseguir isso de dentro do vi apenas fazendo:

!!xargs echo -n
    
por 11.08.2013 / 01:41
1

Solução com awk :

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>
    
por 11.08.2013 / 15:43
0
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>
    
por 11.08.2013 / 13:36
0

Se você tiver certeza do tamanho dos grupos e ainda quiser usar sed , considere uma variação sobre o seguinte:

sed -e 'N;N;N;N;s/\(.*\)\n\(.*\)\n\(.*\)\n\(.*\)\n\(.*\)//'

observe como essa solução permite descartar ou reorganizar linhas, mas, como foi dito, depende do tamanho consistente dos grupos no arquivo de entrada.

    
por 27.07.2018 / 21:35