Usando sed como substituir um padrão se ocorrer em uma linha seguindo outro padrão?

4

Diga, o seguinte é o conteúdo de um arquivo

$ cat file
Name=Tom
Value=10
Name=Tom
Name=Harry
Value=20

Em algumas ocasiões, o valor não ocorre após um nome. Então, o que eu preciso fazer é encontrar o padrão Name = Tom e substituir o valor, mas somente se ocorrer na linha imediatamente após o nome. Como fazer isso?

    
por Debabrata Roy 24.07.2017 / 14:22

3 respostas

4

Mais compacto e um pouco mais fácil:

sed 'G;/^Value=/s/=.*\nName=Tom/=42/;s/\n.*//;h' file

Isso acrescenta a linha anterior do espaço de espera a cada linha. Para Value= linhas, o valor será substituído se Name=Tom estiver no espaço de armazenamento. Caso contrário, a linha anexada é removida e a linha é armazenada no espaço de espera do próximo ciclo.

    
por 24.07.2017 / 16:30
5

com awk :

awk 'prev ~ /^Name=(Tom|Anything)$/ && /^Value=/ {$0 = "Value=123"}
     {print; prev = $0}'

Ou com o nome e o novo valor armazenado em uma variável:

export NAME=Tom VALUE=123
awk 'prev == "Name=" ENVIRON["NAME"] && /^Value=/ {
       $0 = "Value=" ENVIRON["VALUE"]
     }
     {print; prev = $0}'

Com sed , o equivalente seria algo como:

sed -e 'x;/^Name=Tom$/{g;/^Value/s/=.*/=123/;h;b' -e '}' -e g

Embora, como sempre, seja mais curto, mas significativamente menos legível do que com awk . Além disso, para trabalhar com valores arbitrários armazenados em variáveis, sed não tem o equivalente de awk ' ENVIRON ', ou a capacidade de fazer uma comparação simples de strings (em oposição à correspondência de regex), precisa pré-processar os valores das variáveis primeiro, a menos que você possa garantir que as variáveis não contenham caracteres especiais para sed .

sed -e "x;/^Name=$NAME\$/{g;/^Value/s/=.*/=$VALUE/;h;b" -e '}' -e g

Seria uma vulnerabilidade de injeção de comando (pelo menos com GNU sed ) se $NAME e $VALUE não fossem rigidamente controlados.

    
por 24.07.2017 / 14:33
4
sed -e '
   /^Name=Tom$/!b
   $!N
   /\(\nValue\)=.*/s//=NEW_VALUE/
   P;D
' data.inp

Explicação

  • Ele procurará linhas que tenham o nome Tom nelas. A não correspondência irá para stdout.
  • Em seguida, ele tentará anexar a próxima linha ao espaço do padrão, desde que não seja a última linha.
  • Irá procurar o valor regex = na linha que acabou de ser anexada e, se sim, o valor é alterado para NEW_VALUE (você deve alterá-lo para o que precisar).
  • P; D = > imprimirá a parte do espaço de padrão à esquerda de \ n, ou seja, a linha anterior que tinha Nome = Tom e, em seguida, remove essa parte. Agora ficamos com Value = NEW_VALUE e com isso ele salta para o início da linha do script sed: / ^ Name = Tom $ /! B Obviamente, isso irá falhar e, portanto, será levado para o stdout. Isso é feito para cuidar de linhas consecutivas de Name = Tom.

Resultados

Name=Tom
Value=NEW_VALUE
Name=Tom
Name=Harry
Value=20
    
por 24.07.2017 / 15:09

Tags