Editar arquivo baseado na existência de uma string

5

Eu tenho um arquivo de entrada, digamos, file1 , que aparece da seguinte maneira:

WRITE=2
START=1
SMEAR=0
MIN=6
MAX=100

Meu problema é procurar pela string SMEAR e, se a string existir, substituir a linha inteira por SMEAR=-5 . No entanto, se o SMEAR não existir, será necessário inserir uma nova linha SMEAR=-5 . Por fim, a linha SMEAR=-5 deve aparecer apenas uma vez. Eu posso substituir a string usando sed:

 sed -i '/SMEAR/c\SMEAR=-5' file1

Ou eu posso inserir a string como uma nova linha

 sed -i '10i SMEAR=-5' file1

Mas como posso combiná-los com base na existência da string no arquivo?

EDITAR: Também seria útil se eu pudesse passar o valor de SMEAR como uma variável.

    
por WanderingMind 11.05.2016 / 21:58

3 respostas

6

Parece que a sequência das linhas não importa para o seu caso de uso. Dado isso, eu usaria ex e simplesmente:

  1. Remover todas as instâncias de SMEAR ;
  2. Insira a linha que você deseja.

Você pode fazer isso da seguinte forma:

printf '%s\n' 'g/SMEAR/d' '$a' 'SMEAR=-5' . x | ex file.txt

O primeiro comando é g lobally d elete todas as linhas que correspondem à regex /SMEAR/ .

O próximo comando é a ppend após a última linha ( $ ) da linha SMEAR=-5 . O . termina o texto a ser anexado.

O comando x salva as alterações e sai.

Cada comando é finalizado por uma nova linha usando printf '%s\n' para enviá-los para ex .

Veja também esta solução muito parecida que escrevi um tempo atrás na troca de pilha vi / Vim.

Para testar as alterações imprimindo o arquivo alterado na linha de comando sem salvar as alterações, substitua o x pelos dois comandos %p 'q!' da seguinte forma:

printf '%s\n' 'g/SMEAR/d' '$a' 'SMEAR=-5' . %p 'q!' | ex file.txt

% significa "buffer inteiro", que é o que obtém p rinted.

q! significa "sair, descartando as alterações".

Para salvar as alterações em um novo arquivo, substitua o %p por w newfile.txt da seguinte forma:

printf '%s\n' 'g/SMEAR/d' '$a' 'SMEAR=-5' . 'w newfile.txt' 'q!' | ex file.txt

Este w cria o buffer modificado em newfile.txt .

Como alternativa, você pode fazer isso no início, fazer um backup e salvar o conteúdo do arquivo alterado no local original, file.txt , assim:

printf '%s\n' 'w file.txt.bak' 'g/SMEAR/d' '$a' 'SMEAR=-5' . x | ex file.txt

Editar: Na verdade, você não precisa usar q! ; simplesmente omitir o x é suficiente para evitar salvar as alterações. Quando ex recebe um EOF ao tentar ler mais entradas, ele sai e não salva as alterações.

    
por 11.05.2016 / 22:03
5

Você poderia tentar assim: se uma linha coincide com apenas copiá-la para o espaço h old, então s ubstitute o valor.
Na linha $ t e x change armazena espaço e espaço padrão, então verifique se o último está vazio. Se não estiver vazio, significa que a substituição já foi feita e nada para fazer. Se estiver vazio, significa que nenhuma correspondência foi encontrada, portanto, substitua o espaço de padrão por SMEAR=-5 e, em seguida, acrescente à linha atual no buffer de armazenamento. Finalmente, e x muda novamente:

sed '/SMEAR/{h;s/.*/SMEAR=-5/};${x;/^$/{s//SMEAR=-5/;H};x}' infile

A descrição acima é de gnu sed syntax. Portátil:

sed '/SMEAR/{
h
s/.*/SMEAR=-5/
}
${
x
/^$/{
s//SMEAR=-5/
H
}
x
}' infile

Alternar com ed :

ed -s infile<<\IN || printf %s\n SMEAR=-5 >> infile
/SMEAR.*/s//SMEAR=-5/ 
w
q
IN

Se nenhuma linha corresponder ao padrão, ed terá o erro eliminado para que o segundo comando ( printf... ) seja executado para anexar a linha ao arquivo. Caso contrário, ed editará o arquivo no local.

Se você tiver o valor de SMEAR salvo na variável, por exemplo,

var=-7

você executaria:

sed '/SMEAR/{h;s/.*/SMEAR='"$var"'/};${x;/^$/{s//SMEAR='"$var"'/;H};x}' infile

ou

ed -s infile<<IN || printf %s\n "SMEAR=${var}" >> infile
/SMEAR.*/s//SMEAR=${var}/ 
w
q
IN
    
por 11.05.2016 / 22:03
1

Ou, implementando a ideia da Wildcard (remova qualquer / todas as linhas existentes que contenham SMEAR , e depois insira a linha que você quer) com ferramentas da idade da pedra:

(grep -v '^SMEAR=' file1; echo 'SMEAR=-5') > file1.tmp  &&  cp file1.tmp file1  &&  rm file1.tmp

ou, se você não estiver preocupado sobre a preservação dos atributos (por exemplo, permissões) de e hard links para file1 , você poderia fazer

(grep -v '^SMEAR=' file1; echo 'SMEAR=-5') > file1.tmp  &&  mv file1.tmp file1

ou, se você tiver sponge , você poderia fazer

(grep -v '^SMEAR=' file1; echo 'SMEAR=-5') | sponge file1
    
por 01.11.2018 / 20:20