Eu construo o seguinte sed cli para adicionar a seguinte linha
force_https_protocol=PROTOCOL_TLSv1_2
depois da linha:
[security]
o sed cli:
sed -i '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' /etc/ambari-agent/conf/ambari-agent.ini
mas o problema é quando a fila force_https_protocol=PROTOCOL_TLSv1_2
já está depois[security]
como alterar a sintaxe sed para ignorar a adição da linha se a linha já existir?
resultado esperado
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
arquivo errado:
[security]
force_https_protocol=PROTOCOL_TLSv1_2
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
Responder1
Supondo que todos os "force_https_protocol=PROTOCOL_TLSv1_2" no arquivo estejam dentro da tag [security] e não apareçam em nenhum outro lugar
sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
-e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file
A ideia é deletar todas as linhas do arquivo que contém (apenas) a string "force_https_protocol=PROTOCOL_TLSv1_2".
Explicação
/^force_https_protocol=PROTOCOL_TLSv1_2$/d'
Exclua todas as linhas que contêm a string "force_https_protocol=PROTOCOL_TLSv1_2".
Testes
$ cat file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
$ sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
-e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
Responder2
1. Usando AWK
Aqui está uma possível solução para o problema mais geral de adicionar umcordapara um bloco de texto rotulado (ou seja, as linhas de texto que seguem um rótulo específico em um arquivo e precedem o próximo rótulo ou o local do arquivo) somente secordaainda não está presente.
Uma abordagem simples é percorrer o arquivo de trás para frente e acompanhar a última vez que encontramoscorda, imprima-o sempre que encontrarmos uma etiqueta específica (pouco antes de imprimir a etiqueta em si), mas apenas se não a tivermos visto (corda) ainda, e esqueça de tê-lo encontrado (corda) sempre que nos deparamos com um rótulo. E, claro, inverta o resultado como última etapa.
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = 1
}
/^\[security\]$/ {
if ( ! seen ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
/^\[[^]]*\]$/ {
seen = 0
}
1' | tac
tac
, incluído emGNU Coreutils, concatena e reverte arquivos linha por linha. Como reverter um arquivo com outras ferramentas/padrão é abordado em várias perguntas e respostas sobre U&L (por exemplo,Como o comando sed '1!G;h;$!d' reverte o conteúdo de um arquivo?eGrepping reverso).
Isso não será inserido force_https_protocol=PROTOCOL_TLSv1_2
após o primeiro [security]
trecho de texto a seguir:
[security]
keysdir=/var/lib/ambari-agent/keys
force_https_protocol=PROTOCOL_TLSv1_2
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
...
Para simplesmente inserircordaapós cada ocorrência de um rótulo, a menos quecordajá existe, a mesma abordagem pode levar a:
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = NR
}
/^\[security\]$/ {
if ( ( NR == 1 ) || ! ( NR == seen + 1 ) ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
1' | tac
(Essevaiinsira force_https_protocol=PROTOCOL_TLSv1_2
depois [security]
no exemplo de texto acima).
2. Usando sed
Com sed
você pode usar uma variação do N;P;D;
ciclo (que é abundantemente abordada em outras perguntas e respostas sobre U&L; por exemplo:Como posso usar o sed para substituir uma string multilinha?ouComo editar a próxima linha após o padrão usando sed?).
Isto irá inserir a linha force_https_protocol=PROTOCOL_TLSv1_2
após uma linha composta apenas [security]
se a primeira ainda não estiver lá.
sed '
$! {
N
P
/^\[security\]\n/ {
/\nforce_https_protocol=PROTOCOL_TLSv1_2$/ b b
i\
force_https_protocol=PROTOCOL_TLSv1_2
}
:b
D
}
s/^\[security\]$/&\
force_https_protocol=PROTOCOL_TLSv1_2/'
Este roteiro:
- para cada linha, exceto a última (
$!
), anexa uma nova linha seguida pela próxima linha ao espaço padrão (N
) (que já contém a linha atual); - imprime a primeira linha no espaço padrão (
P
); se essa linha for[security]
...- ...e a próxima linha é
force_https_protocol=PROTOCOL_TLSv1_2
, apenas exclui a primeira linha do espaço padrão e inicia um novo ciclo (b b
,:b D
); - caso contrário, imprime
force_https_protocol=PROTOCOL_TLSv1_2
na saída padrão (i\
) antes de excluir a primeira linha do espaço padrão e iniciar um novo ciclo (D
);
- ...e a próxima linha é
- se a última linha for
[security]
, substitui-a por ela mesma seguida por uma nova linha eforce_https_protocol=PROTOCOL_TLSv1_2
imprime o resultado (por meio do implícitop
).