Use sed para copiar para a linha anterior

2

Eu quero converter:

A,p
B,q
C,r
D,s

Em:

A,p,q
B,q,r
C,r,s

Usando sed .

    
por Inspired_Blue 09.01.2018 / 15:37

2 respostas

3

Eu suspeito que sed não é o melhor para isso (e outros podem saber como fazer melhor com sed ), mas aqui vai:

$ sed '2,$ s/.$/&,&/' file | sed -r ':a;N;s/\n(.)(,?.?)(,.)$/\n/;ta' | sed '$d'
A,p,q
B,q,r
C,r,s

Notas

sed '2,$ s/.$/&,&/' significa duplicar o último caractere em todos exceto na primeira linha, adicionando uma vírgula:

  • 2,$ da segunda linha em diante
  • s/old/new/ replace old com new
  • .$ o último caractere
  • & o padrão correspondente

sed -r ':a;N;s/\n(.)(,?.?)(,.)$/\n/;ta;' significa pegar o último caractere de cada linha após o primeiro e colocá-lo no final da linha anterior:

  • -r use ERE
  • :a label: execute daqui
  • ; separa os comandos
  • N leu a próxima linha no espaço de padrão para que possamos usar \n para representar novas linhas no padrão
  • (.) salve um caractere para mais tarde
  • ? zero ou um dos caracteres anteriores
  • $ fim da linha
  • referência ao padrão salvo
  • ta se o último comando s foi bem sucedido, ramifique para :a e execute o loop novamente
  • $d elimina a última linha

Se o seu arquivo não tiver apenas caracteres únicos entre as vírgulas, você não poderá usar a regex muito simples acima. Aqui está uma versão que funciona se o arquivo for separado por vírgulas. Por exemplo, dado

January,apple
February,pear
March,kiwi
April,mango

Você pode fazer isso, o que também funciona se é apenas um caractere, é claro

$ sed '2,$ s/[^,]*$/&,&/' file | sed -r ':a;N;s/\n([^,]*)(,?[^,]*)(,[^,]*)$/\n/;ta;' | sed '$d'
January,apple,pear
February,pear,kiwi
March,kiwi,mango

sed scripts podem ser escritos em várias linhas. Não posso afirmar que isso melhora significativamente a legibilidade;) mas pode ser mais portável, pois há restrições quanto ao uso de ; em versões não-GNU de sed :

sed '2,$ s/[^,]*$/&,&/' file |
sed -r '{:a
          N
          s/\n([^,]*)(,?[^,]*)(,[^,]*)$/\n/
          ta}' |
sed '$d'

[^,]* significa zero ou mais caracteres que não são vírgulas.

    
por Zanna 09.01.2018 / 19:18
1

Aqui está uma maneira de fazer isso em uma única chamada de sed que eu acho:

sed -nE '$!{:a;N;s/(.*)\n(.*)(,[^,]*$)/\n/;P;D;ba;}' file
A,p,q
B,q,r
C,r,s

Explicação

A estrutura :a;N;...P;D;ba mantém essencialmente um buffer de 2 linhas, dentro do qual podemos dividir os campos e copiar / mover grupos de caracteres:

$!{                                   # For any line except the last
  :a                                  # Enter a loop:
  N                                   # Append the following line, after a newline  
  s/(.*)\n(.*)(,[^,]*)$/\n/   # Capture (1) up to the newline, 
                                      # (2) from the newline to the last comma, 
                                      # and (3) everything else into groups and 
                                      # copy group 3 before the newline
  P                                   # Print everything up to the newline
  D                                   # Delete everything up to the newline, 
                                      # ready for the next iteration
  ba
}

Observe que o uso da regex estendida -E (ou -r ) não é um requisito, apenas reduz a quantidade de escape necessária.

    
por steeldriver 10.01.2018 / 13:49