cómo agregar una línea solo si la línea no está configurada después de una palabra específica

cómo agregar una línea solo si la línea no está configurada después de una palabra específica

Construyo el siguiente sed cli para agregar la siguiente línea

force_https_protocol=PROTOCOL_TLSv1_2

después de la línea:

[security]

el sed cli:

sed  -i '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2'  /etc/ambari-agent/conf/ambari-agent.ini

pero el problema es cuando la línea - force_https_protocol=PROTOCOL_TLSv1_2 ya está después[security]

¿Cómo cambiar la sintaxis sed para ignorar agregar la línea si la línea ya existe?

Rendimiento esperado

[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

Archivo incorrecto:

[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

Respuesta1

Suponiendo que todos los "force_https_protocol=PROTOCOL_TLSv1_2" del archivo están dentro de la etiqueta [seguridad] y no aparecen en ningún otro lugar

sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
    -e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file

La idea es eliminar todas las líneas del archivo que contienen (solo) la cadena "force_https_protocol=PROTOCOL_TLSv1_2".

Explicación

/^force_https_protocol=PROTOCOL_TLSv1_2$/d'

Elimine todas las líneas que contengan la cadena "force_https_protocol=PROTOCOL_TLSv1_2".

Pruebas

$ 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

Respuesta2

1. Usando AWK

Aquí hay una posible solución al problema más general de agregar uncadenaa un bloque de texto etiquetado (es decir, las líneas de texto que siguen a una etiqueta específica en un archivo y preceden a la siguiente etiqueta o al final del archivo) solo sicadenaaún no está presente.

Un enfoque simple es recorrer el archivo hacia atrás y realizar un seguimiento de la última vez que nos encontramos.cadena, imprimirlo cada vez que encontremos una etiqueta específica (justo antes de imprimir la etiqueta en sí), pero solo si no la hemos visto (cadena) todavía, y olvídate de haberlo encontrado (cadena) cada vez que nos encontramos con una etiqueta. Y, por supuesto, revertir el resultado como último paso.

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, incluido enGNU Coreutils, concatena e invierte archivos línea por línea. Cómo revertir un archivo con otras herramientas estándar se trata en varias preguntas y respuestas sobre U&L (por ejemplo,¿Cómo invierte el comando sed '1!G;h;$!d' el contenido de un archivo?yGrepping inverso).

Esto no se insertará force_https_protocol=PROTOCOL_TLSv1_2después del primero [security]en el siguiente fragmento de texto:

[security]
keysdir=/var/lib/ambari-agent/keys
force_https_protocol=PROTOCOL_TLSv1_2
passphrase_env_var_name=AMBARI_PASSPHRASE

[security]
...

Para simplemente insertarcadenadespués de cada aparición de una etiqueta a menos quecadenaya existe, el mismo enfoque puede conducir 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

(Estevoluntadinsertar force_https_protocol=PROTOCOL_TLSv1_2después [security]en el ejemplo de texto anterior).

2. Usando sed

Con sedpuede utilizar una variación del N;P;D;ciclo (que se trata abundantemente en otras preguntas y respuestas sobre U&L; por ejemplo:¿Cómo puedo usar sed para reemplazar una cadena de varias líneas?o¿Cómo editar la siguiente línea después del patrón usando sed?).

Esto insertará la línea force_https_protocol=PROTOCOL_TLSv1_2después de una línea compuesta únicamente por [security]solo si la primera aún no está allí.

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 guión:

  • para cada línea, excepto la última ( $!), agrega una nueva línea seguida de la siguiente línea al espacio del patrón ( N) (que ya contiene la línea actual);
  • imprime la primera línea en el espacio del patrón ( P); si esa linea es [security]...
    • ...y la siguiente línea es force_https_protocol=PROTOCOL_TLSv1_2, simplemente elimina la primera línea del espacio del patrón y comienza un nuevo ciclo ( b b, :b D);
    • de lo contrario, imprime force_https_protocol=PROTOCOL_TLSv1_2en la salida estándar ( i\) antes de eliminar la primera línea del espacio del patrón e iniciar un nuevo ciclo ( D);
  • si la última línea es [security], la reemplaza por sí misma seguida de una nueva línea e force_https_protocol=PROTOCOL_TLSv1_2imprime el resultado (mediante el implícito p).

información relacionada