Estoy utilizando el siguiente sed comando para reemplazar a algunos de los parámetros en un archivo de configuración:

sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf

Ahora tengo un problema. Si la línea no existe, quiero añadir a la parte inferior del archivo.

Estoy llamando a este con un popen de un programa en C. He intentado utilizar awk.

InformationsquelleAutor Evilmachine | 2013-11-28

11 Comentarios

  1. 66

    Intente esto:

    grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file
    • Muy fácil y muy útil!
    • Para una explicación véase: explainshell
  2. 9

    El uso de sed, la sintaxis simple:

    sed \
        -e '/^\(option=\).*/{s//value/;:a;n;ba;q}' \
        -e '$aoption=value' filename

    Esto reemplaza el parámetro, si es que existe, otra cosa sería añadir a la parte inferior del archivo.

    Utilizar el -i opción si desea editar el archivo en el lugar.


    Si quieres aceptar y mantener los espacios en blanco, y además de eliminar el comentario, si la línea ya existe, pero se comenta, escribe:

    sed -i \
        -e '/^#\?\(\s*option\s*=\s*\).*/{s//value/;:a;n;ba;q}' \
        -e '$aoption=value' filename

    Por favor, tenga en cuenta que ni opción ni valor debe contener una barra /, o usted tendrá que escapar a \/.


    A usar bash-variables $option y $value, usted podría escribir:

    sed -i \
        -e '/^#\?\(\s*'${option//\//\/}'\s*=\s*\).*/{s//'${value//\//\/}'/;:a;n;ba;q}' \
        -e '$a'${option//\//\/}'='${value//\//\/} filename

    El bash expresión ${option//\//\\/} cotizaciones de barras, reemplaza todas las / con \/.

    Nota: me Acaba atrapado en un problema. En bash se puede citar "${option//\//\\/}", pero en el sh de busybox, esto no funciona, así que usted debe evitar las citas, al menos en la no-bourne-conchas.


    Todo combinado en una función bash:

    # call option with parameters: $1=name $2=value $3=file
    function option() {
        name=${1//\//\/}
        value=${2//\//\/}
        sed -i \
            -e '/^#\?\(\s*'"${name}"'\s*=\s*\).*/{s//'"${value}"'/;:a;n;ba;q}' \
            -e '$a'"${name}"'='"${value}" $3
    }

    Explicación:

    • /^\(option=\).*/: Coinciden con las líneas que comienzan con option= y (.*) ignorar todo después de la =. El \(\) encierra la parte vamos a reutilizar como \1más tarde.
    • /^#\?(\s*'»${opción//////}»‘\s*=\s*).*/: Ignorar código comentado con # al comienzo de la línea. \? significa «opcional». El comentario será eliminado, porque está fuera de la copia de la parte en \(\). \s* significa «cualquier número de espacios en blanco» (espacio, tabulador). Los espacios en blanco se copian, ya que están dentro de \(\), así que usted no pierde el formato.
    • /^\(option=\).*/{…}: Si coincide con una línea de /…/, a continuación, ejecute el siguiente comando. Comando a ejecutar no es un solo comando, pero un bloque {…}.
    • s//…/: Buscar y reemplazar. Desde el término de búsqueda está vacío //, se aplica el último partido, que fue /^\(option=\).*/.
    • s//\1value/: Replace the last match with everything in(…), referenced by\1and the textvalor`
    • :a;n;ba;q: Conjunto de etiquetas a, luego lea la siguiente línea n, a continuación, rama b (o ir) de vuelta a la etiqueta a, que significa: leer todas las líneas hasta la y de archivo, así que después del primer partido, acaba de recuperar todas las líneas siguientes, sin más transformación. Luego q guit y, por tanto, ignorar todo lo demás.
    • $aoption=value: Al final del archivo $, anexar a el texto option=value

    Más información sobre sed y un comando reseña en mi blog:

    • cómo es esto para los archivos como «valor de opción»? Cuando puedo reemplazar = por un espacio de la función de corrección de la opción, pero el resto del archivo se ha perdido 🙁
    • Lo siento mucho, no fue un error en mi código. El comando es «ba», no «:ba». He editado el texto y se corrigió. Por favor, inténtelo de nuevo.
    • He añadido una explicación detallada de la sed código.
    • Usted podría escapar de la / carácter mediante el uso de otro personaje en la sustitución de comandos (como !): sed -i -e '/^\(option=\).*/{s!!\1value!;:a;n;ba;q}' -e '$aoption=value' filename
    • Sí,usted puede utilizar cualquier carácter para el comando sed. De hecho, yo a menudo el uso de la coma: sed 's,from,to,g', sino para permitir que la arbitraria pares de nombre y valor, por ejemplo, los argumentos de una llamada a una función, usted todavía necesita para escapar de ellos.
  3. 4

    Aquí es un one-liner sed que hace el trabajo en línea. Tenga en cuenta que conserva la ubicación de la variable y su sangría en el archivo cuando existe. Esto es a menudo importante para el contexto, como cuando hay comentarios alrededor o cuando la variable está en una sangría de bloque. Cualquier solución basada en «eliminar-entonces-append» paradigma no mal en esto.

       sed -i '/^[ \t]*option=/{h;s/=.*/=value/};${x;/^$/{s//option=value/;H};x}' test.conf

    Con un genérico par de variable/valor puede escribir de esta manera:

       var=c
       val='12 34' # it handles spaces nicely btw
       sed -i '/^[ \t]*'"$var"'=/{h;s/=.*/='"$val"'/};${x;/^$/{s//c='"$val"'/;H};x}' test.conf

    Por último, si quieres también para mantener a los comentarios en línea, usted puede hacerlo con una captura de grupo. E. g. si test.conf contiene lo siguiente:

    a=123
    # Here is "c":
      c=999 # with its own comment and indent
    b=234
    d=567

    A continuación, ejecutar este

    var='c'
    val='"yay"'
    sed -i '/^[ \t]*'"$var"'=/{h;s/=[^#]*\(.*\)/='"$val"'/;s/'"$val"'#/'"$val"' #/};${x;/^$/{s//'"$var"'='"$val"'/;H};x}' test.conf

    Produce que:

    a=123
    # Here is "c":
      c="yay" # with its own comment and indent
    b=234
    d=567
  4. 3

    Como awk-sólo uno-forro:

    awk -v s=option=value '/^option=/{$0=s;f=1} {a[++n]=$0} END{if(!f)a[++n]=s;for(i=1;i<=n;i++)print a[i]>ARGV[1]}' file

    ARGV[1] es la entrada file. Se abre y se escriben en el for bucle de laEND bloque. La apertura de file de salida en el END bloque reemplaza la necesidad de los servicios públicos como sponge o escribir en un archivo temporal y, a continuación, mving el archivo temporal para file.

    Las dos tareas a la matriz a[] se acumulan todas las líneas de salida en a. if(!f)a[++n]=s anexa el nuevo option=value si el principal awk bucle no se pudo encontrar option en file.

    He añadido algunos espacios (no muchos) para mejorar la legibilidad, pero usted realmente necesita sólo un espacio en el conjunto de la awk programa, el espacio después de print.
    Si file incluye # comments se conservarán.

  5. 3
     sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf
     grep -q "option=value" /etc/fdm_monitor.conf || echo "option=value" >> /etc/fdm_monitor.conf
  6. 2

    aquí es un awk one-liner:

     awk -v s="option=value" '/^option/{f=1;$0=s}7;END{if(!f)print s}' file

    esto no hace, en lugar de cambiar en el archivo, sin embargo, puede :

    awk '...' file > tmpfile && mv tmpfile file
  7. 2

    Utilizando sed, usted podría decir:

    sed -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename

    Esto reemplaza el parámetro, si es que existe, otra cosa sería añadir a la parte inferior del archivo.


    Utilizar el -i opción si desea editar el archivo en el lugar:

    sed -i -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename
    • Esto no parece funcionar del todo. Añade «opción=valor» después de cada línea. No está seguro de cómo llegó dos upvotes. Usted podría hacer ‘$aoption=valor’, pero me parece que no puede hacer que dependa de que el partido anterior por lo que sólo se anexa a la final independientemente.
  8. 2

    He aquí un awk aplicación

    /^option *=/ { 
      print "option=value"; # print this instead of the original line
      done=1;               # set a flag, that the line was found
      next                  # all done for this line
    }
    {print}                 # all other lines -> print them
    END {                   # end of file
      if(done != 1)         # haven't found /option=/-> add it at the end of output
        print "option=value"
    }

    Ejecutar utilizando

    awk -f update.awk < /etc/fdm_monitor.conf > /etc/fdm_monitor.conf.tmp && \
       mv /etc/fdm_monitor.conf.tmp /etc/fdm_monitor.conf

    o

    awk -f update.awk < /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf

    EDITAR:
    Como un one-liner:

    awk '/^option *=/{print "option=value";d=1;next}{print}END{if(d!=1)print "option=value"}' /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf
    • Necesito un forro de causa puedo enviar esto como un sistema de llamada de un c programm.
  9. 1
    sed -i '1 h
    1 !H
    $ {
       x
       s/^option.*/option=value/g
       t
       s/$/\
    option=value/
       }' /etc/fdm_monitor.conf

    Cargar todos los archivos en el buffer, al final, cambiar todas las ocurrencias y si no se producen los cambios, añadir al final

  10. 0

    He elaborado sobre kev del grep/sed solución mediante la configuración de las variables con el fin de reducir la duplicación de esfuerzos.

    Conjunto de las variables en la primera línea (sugerencia: $_option deberá coincidir con todo en la línea hasta que el valor de [incluyendo cualquier separador como = o :]).

    _file="/etc/ssmtp/ssmtp.conf" _option="mailhub=" _value="mi.dominio.tld" \ 
    sh-c '\ 
    grep -q "^$_option" "$_file" \ 
    && sed-i "s/^$_option.*/$_option$_value/" "$_file" \ 
    || echo "$_option$_value" >> "$_file"\ 
    ' 
    

    Cuenta que el sh -c '...' sólo tiene el efecto de ampliar el alcance de las variables sin la necesidad de un export. (Ver Establecer una variable de entorno antes de que un comando en bash no trabajan para el segundo comando en una tubería)

  11. 0

    Puede utilizar esta función para buscar config cambios:

    #!/bin/bash
    
    #Find and Replace config values
    find_and_replace_config () {
       file=$1
       var=$2
       new_value=$3
       awk -v var="$var" -v new_val="$new_value" 'BEGIN{FS=OFS="="}match($1, "^\s*" var "\s*") {$2=" " new_val}1' "$file" > output.tmp && sudo mv output.tmp $file
    }
    
    find_and_replace_config /etc/php5/apache2/php.ini max_execution_time 60

Dejar respuesta

Please enter your comment!
Please enter your name here