Qual é a maneira mais concisa de inserir ou atualizar uma linha? [duplicado]

2

Eu escrevo um monte de scripts ad hoc para adicionar linhas a sudoers, sysctl.conf etc. Geralmente eu uso o módulo ansible lineinfile. Às vezes, no entanto, não consigo fazer isso, então uso:

WHAT_I_WANT='my line of text = something'
WHAT_TO_REPLACE='my line of text = .*'
FILE_TO_EDIT=conf_file.conf
if ( ! grep -q "^$WHAT_I_WANT\$" FILE_TO_EDIT ); then
    echo  "$WHAT_I_WANT" >> FILE_TO_EDIT
else
    sed -i "s/$WHAT_TO_REPLACE/$WHAT_I_WANT/g' FILE_TO_EDIT
fi

Meu palpite é que existe uma maneira mais eficiente de fazer isso. O ideal é com uma linha e uma linguagem (e também de uma maneira que permita a correspondência de expressões regulares, removendo linhas comentadas e arquivos de backup). Mas eu não sei o que é isso.

    
por Peter Turner 11.08.2017 / 17:18

2 respostas

1

  • O uso de nomes de variáveis extra longos para substituir cadeias longas é IMO contraproducente.
  • Para que as variáveis sejam expandidas em comandos do grep / sed, use aspas duplas.
  • O uso de curingas .* em atribuições variáveis realiza a expansão do nome de arquivo (globbing)
  • O script a seguir usa a execução condicional no sucesso && ou falha || em vez de um if.
REPL='something'
PATT='my line of text = '
FILE=conf_file.conf

cat $FILE
echo '========='

grep -q "^$PATT" $FILE && (sed -i "s/^$PATT.*$/$PATT$REPL/" $FILE) || (echo "$PATT$REPL" >> $FILE)

cat $FILE
    
por 11.08.2017 / 20:04
1

Na verdade, não é uma linha única, mas você poderia fazer isso com uma invocação de sed :

sed -e '
   /pat/{s//repl/g;h;}
   $!b
   G
   s/\n..*//;t
   s/$/repl/
' yourfile

N.B .: Eu deliberadamente usei pat e repl para padrão e substituição, respectivamente, e não as variáveis de shell como você fez. Basicamente por 2 razões principais, eles iriam atrapalhar o fluxo do código sed + para correção, precisamos citar ambos, e diferentemente, para fazê-los funcionar. Esse trabalho eu deixo para você.

Fluxo: Digamos, o arquivo nunca teve um / pat / então todas as linhas são tomadas para stdout pelo comando $! b e a última linha quando anexada por G apenas vê uma espera vazia então o t não é tirado e temos uma operação de acréscimo.

Quando vemos uma linha / pat /, então é s /// - ed e a área de espera está marcada. se não for a última linha, simplesmente saímos para a stdout. Para eof, fazemos uma verificação de espera e, como não está vazia (assumindo que repl é NONEMPTY , o caminho de teste seria obtido após remover a retenção do espaço de padrão.

Perl oferece a clareza para corresponder à intenção palavra por palavra no código:

perl -lne '$a += s/pat/repl/g,print}{print q[repl] unless $a'

Para ser lido como: A variável $a serve como contador para o número de substituições. No final, adicionaríamos ao arquivo quando não houvesse subscrições feitas anteriormente.

E quanto ao fornecimento de informações de padrão / substituição por meio de variáveis, podemos fazer isso:

WHAT_I_WANT='my line of text = something'
WHAT_TO_REPLACE='my line of text = .*'
FILE_TO_EDIT=conf_file.conf

perl -li -sn -e '
        $a += s/$pat/$repl/g,print}{print $repl unless $a
' -- -pat="$WHAT_I_WANT" -repl="$WHAT_TO_REPLACE" -- "$FILE_TO_EDIT"
    
por 11.08.2017 / 18:07