Combinando declarações sed

2

Digamos que meu arquivo de entrada se pareça com:

ID1
1    5
6    8
ID2
1    4
5    7

Estou tentando formular um loop que pode combinar essas ações:

  • Se a linha começar com uma letra: mantenha o '\ n' depois do campo

  • Se a linha começar com um número: substitua cada '\ t' e '\ n' por uma vírgula ( sed 's / \ t /, / g; s / \ n /, / g ' ) EXCETO se a próxima linha começar com uma letra ( sed 's / \ t /, / g' )

Resultado esperado:

ID1     
1, 5, 6, 8
ID2     
1, 4, 5, 7
    
por dovah 28.07.2014 / 13:24

4 respostas

3
sed '/^[0-9]/{:a;s/[\t\n ]\+/,/g;N;/\n[A-Z]/!ba;}'

fará as coisas.

Explicação:

/^[0-9]/ corresponderá apenas às linhas iniciadas com o número e aplicará o grupo de comando a ele

{} grupo de comando para aplicar

{:a;s/[\t\n ]\+/,/g;N;/\n[A-Z]/!ba;} lerá o ciclo linha por linha e substituirá todos os espaços, tabulações e novas linhas por vírgula até que a linha comece com a letra.

    
por 28.07.2014 / 13:39
1

Você deve conseguir isso da seguinte maneira: se a linha atual começar com um dígito, anexe a próxima linha no espaço padrão e substitua sequências de espaços, tabulações e novas linhas por vírgula:

$ sed '/^[0-9]/{N;s/[ \t\n]\+/, /g}' file
ID1
1, 5, 6, 8
ID2
1, 4, 5, 7
    
por 28.07.2014 / 13:34
1

Gostaria de ir para awk , que fornece mais controle e generaliza o problema:

awk 'BEGIN{FS="\t"; OFS=","}
      /^[^A-Z]/ {for (i=1; i<=NF; i++) {if (!a) a=$i; else a=a OFS $i} next}
      {if (a) print a; a=""; print}
     END{print a}'

Explicação

  • BEGIN{FS="\t"; OFS=","} definir o separador de campo de entrada como separador e separador de campo de saída como vírgula.
  • /^[^A-Z]/ {for (i=1; i<=NF; i++) {if (!a) a=$i; else a=a OFS $i} next} nas linhas que não começam com letra maiúscula, armazenam os valores em uma variável a .
  • {if (a) print a; a=""; print} no resto dos casos (isto é, linhas iniciando com letra maiúscula), imprima o valor armazenado junto com a linha atual.
  • END{print a} depois de processar o arquivo inteiro, imprima a última variável armazenada com os valores do último bloco.

Veja a saída:

$ awk 'BEGIN{FS="\t"; OFS=","}/^[^A-Z]/ {for (i=1; i<=NF; i++) {if (!a) a=$i; else a=a OFS $i} next} {if (a) print a; a=""; print} END{print a}' file
ID1
1,5,6,8
ID2
1,4,5,7

No sed, lembre-se de que você sempre pode usar a opção -e para combinar comandos.

    
por 28.07.2014 / 13:35
1
tr -s '\t\nI' '  \n' <<\DATA |\
sed 's/^/I/;s/  */\n/;s/  *[0-9]/,&/g'
ID1
1    5
6    8
ID2
1    4
5    7
DATA

OUTPUT

ID1
1, 5, 6, 8
ID2
1, 4, 5, 7    
  • Primeiro tr traduz todas as abas e novas linhas para espaços e todo o capital está em novas linhas. Também aperta repetições. Isso torna isso muito fácil, porque nesse ponto ele passa para sed input que parece:

    ^D [num] [num] [num] [num] [num] ... [num] $

  • Próximo sed coloca o I de volta, substitui uma nova linha pelo primeiro espaço na linha, limpa todos os espaços à direita e, em seguida ...

  • Coloca uma vírgula na frente de cada espaço restante na linha e pronto.

por 28.07.2014 / 13:43

Tags