sed: Múltiplo -e ou while loop?

0

Eu tenho um arquivo CSV com tuplas de valores em que preciso alterar as ocorrências de uma para outra em um arquivo (grande) diferente.

Até agora, fiz uma linha de leitura [...] < foo.csv, essencialmente executando sed uma vez para cada linha no arquivo CSV.

Isso leva um pouco de tempo, então me perguntei se eu deveria mudar o loop while para construir uma string muito longa de várias instruções -e e então executá-la com eval.

Eu poderia tentar, obviamente, mas se alguém puder me dizer se o sed irá apenas, essencialmente, fazer o mesmo que eu fiz até agora, ou seja, executar o arquivo para cada instrução -e, significando que nenhum ganho de desempenho é ter, então eu não acho que vou me incomodar.

Editar após comentários:

Basicamente, eu faço o seguinte:

while read line
do
  old_user=echo $line | cut -d \; -f 2|tr -d \"
  new_user=echo $line | cut -d \; -f 4|tr -d \"

  if [ "$old_user" != "$new_user" ]
  then
    sed -i -e "s/^(.*ri:username=\")$old_user(\".*)$/$new_user/g" confluence/entities_converted.xml
  fi
done < usernames.csv

Se você perceber que é um arquivo XML, o motivo é que há várias instâncias em que a análise e a regravação de XML são incômodas, portanto, sed . Pergunto-me se, em vez de executar sed várias vezes, devo construir vários argumentos -e para sed .

usernames.csv parece com

    "Full name";"Username";"Email";"New username"
    "Sune Mølgaard";"sune.molgaard";"[email protected]";"smo"

Pode haver qualquer número de linhas ao longo do caminho da segunda linha, daí o looping. Estou ciente de que a primeira linha provavelmente não será compatível, mas isso é insignificante.

    
por Sune Mølgaard 08.09.2015 / 10:24

2 respostas

3

Não há necessidade de avaliar ou construir vários -e's. Sed pode ler seu "programa" a partir de um arquivo ou pipe que você pode de fato gerar também:

cut -f2,4 -d\; usernames.csv \
    | sed -e 's/^/s%ri:username=/' -e 's/;/%ri:username=/' -e 's/$/%/' \
    | sed -i~ -f- confluence/entities_converted.xml

Para verificar o programa gerado, remova a última linha.

Se você quiser pular as linhas onde nenhuma alteração é necessária (pode acelerar), remova-as inserindo grep entre os seds:

   | grep -v '"\(.*\)".*""' \
    
por 08.09.2015 / 11:11
0

você deve usar o awk para analisar usernames.csv (onde os campos 2 e 4 são diferentes) e gerar o arquivo sed.

 tr -d \" username.csv |
 awk -F\; '$2 != $4 { printf "s/^(.*ri:username=%c)%s(%c.*)$/\1%s\2/g\n",34,$2,34,$4 ; }' |
 sed -i -f - confluence/entities_converted.xml

algum truque

  • use printf "..% c ..", 34 para gerar aspas.
  • você pode pular a linha sed na parte de depuração para garantir que todas as instruções de sed sejam geradas adequadamente.
  • você precisa de /g em substituição?

no meu arquivo de teste

;foo;;foo;;
;fubar;;mr X;;
;bar;;bistro;;
    "Full name";"Username";"Email";"New username"
    "Sune Mølgaard";"sune.molgaard";"[email protected]";"smo"

isso gera

s/^(.*ri:username=")fubar(".*)$/mr X/g
s/^(.*ri:username=")bar(".*)$/bistro/g
s/^(.*ri:username=")Username(".*)$/New username/g
s/^(.*ri:username=")sune.molgaard(".*)$/smo/g

não se preocupe em remover a linha do Username, se não for encontrado, não há substituto.

    
por 08.09.2015 / 11:05

Tags