sed: como substituir a linha se encontrada ou anexada ao final do arquivo, se não for encontrada?

29

Com um único arquivo de entrada que contém apenas comentários (começando com #) e VARIÁVEL = linhas de valor, é possível substituir um valor para uma única variável se encontrado e, caso contrário, acrescentar o par ao final do arquivo se não for encontrado?

Meu método atual funciona excluindo-o em uma primeira passagem e, em seguida, anexando-o ao final do arquivo em uma segunda passagem, mas esse método atrapalha a ordenação de linha (e também são dois comandos diferentes):

sed -r "/^FOOBAR=.*$/d"      -i samefile &&
sed -r "$ a\FOOBAR=newvalue" -i samefile

Existe alguma maneira de fazer isso, ou seja. mantendo a ordem da linha, em uma única linha sed? Se algum outro utilitário (awk, ...) fizer isso, eu o levaria para o sed.

    
por BlakBat 02.05.2013 / 16:49

8 respostas

26

Na verdade, é bem simples com sed : se uma linha corresponder, basta copiá-la para o espaço h old e, em seguida, 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, então nada a fazer. Se estiver vazio, significa que nenhuma correspondência foi encontrada, então substitua o espaço padrão pela variável = valor e acrescente à linha atual no buffer de armazenamento. Finalmente, e x muda novamente:

sed '/^FOOBAR=/{h;s/=.*/=newvalue/};${x;/^$/{s//FOOBAR=newvalue/;H};x}' infile

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

sed '/^FOOBAR=/{
h
s/=.*/=newvalue/
}
${
x
/^$/{
s//FOOBAR=newvalue/
H
}
x
}' infile
    
por 22.09.2015 / 20:06
18

Isso provavelmente pode ser encurtado. Não é um único comando sed e também usa grep, mas isso parece ser basicamente o que você está querendo. É uma única linha e edita o arquivo no local (sem arquivos temporários).

grep -q "^FOOBAR=" file && sed "s/^FOOBAR=.*/FOOBAR=newvalue/" -i file || 
    sed "$ a\FOOBAR=newvalue" -i file
    
por 02.05.2013 / 17:48
9

Aqui está uma abordagem mais simples de sed , pois não acho fácil trabalhar com sed hold space . Se você estiver confortável com hold space , usar a abordagem don_crissti oferece mais uma oportunidade para preservar qualquer coisa da linha existente, mas isso geralmente é muito raro.

Nesta abordagem, basta imprimir todos, exceto a linha que deseja descartar e, no final, anexar a substituição.

sed -n -e '/^FOOBAR=/!p' -e '$aFOOBAR=newvalue' infile
    
por 16.11.2016 / 12:59
3

Com base nas outras respostas, se o que você deseja fazer é substituir o valor de uma variável se essa variável estiver presente no arquivo e anexá-la ao final do arquivo, se não estiver (o que não é o seu postado sed de comandos), você poderia tentar isto:

perl -ne '$c=1 if s/^FOOBAR=.*$/FOOBAR=newvalue/;  
             print; 
             END{print "FOBAR=newvalue" unless $c==1}' file > tmpfile && 
mv tmpfile file
    
por 02.05.2013 / 18:02
1

É um pouco mais fácil no awk, embora a "edição no local" não seja automática:

awk -v varname="FOOBAR" -v newval="newvalue" '
    BEGIN {FS = OFS = "="}
    $1 == varname {$2 = newval; found = 1}
    {print}
    END {if (! found) {print varname, newval}}
' file > tempfile &&
mv tempfile file
    
por 02.05.2013 / 17:47
0

Basta usar grep e echo para criar um registro vazio:

grep -q '^FOOBAR=' somefile || echo 'FOOBAR=VALUE' >> somefile
sed -i 's/FOOBAR=.*$/FOOBAR=VALUE/' somefile 

Cada linha escapa com o código de erro zero.

    
por 08.03.2016 / 15:38
0

Na verdade, trabalha com o seguinte: %código% Na resposta escolhida -i está faltando.

    
por 22.04.2016 / 14:42
-1

para fazer isso com perl e in-place, isso funciona bem para mim:

grep ^FOOBAR= my.file && perl -i -ple "s/^FOOBAR=.+/FOOBAR=newvalue/g" my.file || echo FOOBAR=newvalue >> my.file
    
por 29.10.2015 / 15:03