Substituir nova linha + 4x espaço para nova linha no stdout

4

Eu preciso juntar 2 linhas em uma em stdout - substituir nova linha E 4x espaço com um espaço, mas nova linha sem espaço não toque em

tcpdump -vvv ... -l | xyz

esta é a saída:

2014-06-06 AAA
    BBB
2014-06-06 CCC
    DDD

mas preciso:

2014-06-06 AAA BBB
2014-06-06 CCC DDD
    
por user70763 06.06.2014 / 22:56

5 respostas

4

Pensei em outra maneira de fazer isso que não depende de linhas pareadas, mas apenas um caractere <space> após um caractere \n ewline:

sed ':n;N;s/\n  */ /;tn;P;D' 

Isso usa uma janela deslizante de dados de nova linha e a função t est para operar. O fluxo é assim:

  1. defina o rótulo :n ext
  2. acrescentar N ext na entrada ao espaço padrão
  3. s/ elege um caractere de ewline \n seguido por 1 ou mais caracteres <space> e os substitui por um único /<space>/
  4. t est se a última s/// foi bem-sucedida e, em caso afirmativo, ramifique para :n ext label, else ...
  5. P rint até o primeiro caractere \n ewline no espaço padrão e ...
  6. D elete até e incluindo primeiro caractere% ewline \n no espaço padrão e reinicia o ciclo com o espaço padrão restante ou com a próxima linha

Então, basicamente, todas as ocorrências de \n [ ]* na entrada são espremidas em [ ] :

sed ':n;N;s/\n  */ /;tn;P;D' <<\DATA
2014-06-06 AAA
    BBB
2014-06-06 CCC
    DDD
2014-06-06 EEE
2014-06-06 FFF
    GGG
DATA

OUTPUT:

2014-06-06 AAA BBB
2014-06-06 CCC DDD
2014-06-06 EEE
2014-06-06 FFF GGG

OLD:

sed -n 'h;n;H;x;s/\n */ /p' <<\DATA
2014-06-06 AAA
    BBB
2014-06-06 CCC
    DDD
DATA

OUTPUT:

2014-06-06 AAA BBB
2014-06-06 CCC DDD

Eu uso os comandos 5 sed .

  1. sobrescreve h espaço antigo com espaço padrão ...
  2. sobrescreve o espaço padrão com a linha n ext na entrada
  3. acrescente espaço padrão a H old space após um caractere \n ewline inserido automaticamente
  4. e x alteram o conteúdo dos espaços de retenção e padrão
  5. s/ elege o primeiro caractere% ewline \n e qualquer um ou * de todos os espaços seguintes, em seguida, / substitui a seleção por um único espaço e /p rint o resultado.

No entanto, agora que penso nisso, uma versão simplificada das respostas mine e @Falsenames - que realmente é melhor que essa - seria apenas:

sed 'N;s/\n */ /' <<\DATA
2014-06-06 AAA
    BBB
2014-06-06 CCC
    DDD
DATA    

OUTPUT:

2014-06-06 AAA BBB
2014-06-06 CCC DDD
    
por 06.06.2014 / 23:28
5

Editando isso para dar mais correção de erros.

O comando 'N' no sed anexa a próxima linha. Usando isso em conjunto com uma substituição para trocar a nova linha e um monte de espaços com nada.

$ cat foo | sed 's/^/    /'
2014-06-06 AAA
    BBB
2014-06-06 CCC
    DDD
2014-06-06 EEE
2014-06-06 FFF
    GGG

Minha nova resposta:

$ sed ':a;$!{N;s/\n   //;ba;}' foo
2014-06-06 AAA BBB
2014-06-06 CCC DDD
2014-06-06 EEE
2014-06-06 FFF GGG

Isso parece ser muito superior à minha resposta antiga:

$ sed '/^[^ ]/N;s/\n   //' foo
2014-06-06 AAA BBB
2014-06-06 CCC DDD
2014-06-06 EEE
2014-06-06 FFF
    GGG

Ou o bonito e bonitinho @mikeserv listado.

$ sed -n 'h;n;H;x;s/\n */ /p' foo
2014-06-06 AAA BBB
2014-06-06 CCC DDD
2014-06-06 EEE 2014-06-06 FFF
    GGG 
    
por 06.06.2014 / 23:33
5
awk -v ORS= '/^ {4}/{print substr($0,4); next}
     {print s $0; s="\n"}
     END{print s}'

Esse deve funcionar para insumos como:

2014-06-06 AAA
    BBB
2014-06-06 CCC
    DDD
    EEE
2014-06-06 EEE
2014-06-06 FFF

E produza:

2014-06-06 AAA BBB
2014-06-06 CCC DDD EEE
2014-06-06 EEE
2014-06-06 FFF

com perl :

perl -0777 -pe 's/\n {4}/ /g'

Mas isso significa introduzir a entrada while na memória primeiro.

    
por 06.06.2014 / 23:28
5
echo "2014-06-06 AAA
      BBB
2014-06-06 CCC
    DDD
" | paste - - | tr -s '[:blank:]' '[ *]'
2014-06-06 AAA BBB
2014-06-06 CCC DDD
    
por 06.06.2014 / 23:40
1

Outro comando awk ,

$ awk '{var=$0; getline; print var,$1}' file
2014-06-06 AAA BBB
2014-06-06 CCC DDD
    
por 07.06.2014 / 05:31