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/replaceoldcomnew -
.$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:
-
-ruse ERE -
:alabel: execute daqui -
;separa os comandos -
Nleu a próxima linha no espaço de padrão para que possamos usar\npara 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 -
tase o último comandosfoi bem sucedido, ramifique para:ae execute o loop novamente -
$delimina 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.