2013-11-28 10 views
25

Sto usando il sed seguente comando per sostituire alcuni parametri in un file di configurazione:Come aggiungere una linea nella sed se non viene trovata

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

ora ho un problema. Se la linea non esiste, voglio aggiungerla alla fine del file.

Sto chiamando questo con un popen di un programma C. Ho provato a utilizzare awk.

risposta

41

Prova questo:

grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file 
+0

Molto facile e utile! – JohnyTex

1

Ecco un awk implementazione

/^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" 
} 

Run utilizzando

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 

EDIT: come 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 
+0

Ho bisogno di una causa uno di linea trasmetto questo come una chiamata di sistema da un c programma. – Evilmachine

2

qui è un awk one-liner:

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

questo non cambiano sul posto sul file, è possibile comunque:

awk '...' file > tmpfile && mv tmpfile file 
3

utilizzando sed, si potrebbe dire:

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

Questo sostituirà il parametro se esiste, altrimenti lo aggiungerebbe alla fine del file.


Utilizzare l'opzione -i se si desidera modificare il file sul posto:

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

Questo non sembra funzionare affatto. Aggiunge "opzione = valore" dopo ogni riga. Non so come abbia ottenuto due upvotes. Potresti fare '$ aoption = value' ma non riesco a renderlo condizionale alla partita precedente in modo che appaia alla fine a prescindere. – sosiouxme

1
sed -i '1 h 
1 !H 
$ { 
    x 
    s/^option.*/option=value/g 
    t 
    s/$/\ 
option=value/ 
    }' /etc/fdm_monitor.conf 

caricare tutti i file in tampone, alla fine, modificare tutte le verificarsi e se nessun cambiamento verificano, aggiungere alla fine

2
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 
3

Come awk-unico-liner:

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] è l'input file. Viene aperto e scritto nel ciclo for del blocco END. L'apertura di file per l'output nel blocco END sostituisce la necessità di utilità come sponge o la scrittura in un file temporaneo e quindi mv il file temporaneo in file.

Le due assegnazioni all'array a[] accumulano tutte le linee di uscita in a.if(!f)a[++n]=s aggiunge il nuovo option=value se il ciclo di awk principale non ha trovato option in file.

Ho aggiunto alcuni spazi (non molti) per la leggibilità, ma è necessario solo uno spazio nell'intero programma awk, lo spazio dopo print. Se file include # comments, questi verranno conservati.

0

Ho elaborato la soluzione grep/sed di kev impostando le variabili per ridurre la duplicazione.

Impostare le variabili nella prima riga (suggerimento: $_option deve corrispondere a tutto nella riga fino al valore [compreso qualsiasi seperatore come = o:]).

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

mente che il sh -c '...' appena ha l'effetto di estendere il campo delle variabili, senza la necessità di un export. (Vedi Setting an environment variable before a command in bash not working for second command in a pipe)

1

Ecco un one-liner sed che fa il lavoro in linea. Si noti che conserva la posizione della variabile e la sua indentazione nel file quando esiste. Questo è spesso importante per il contesto, come quando ci sono commenti in giro o quando la variabile si trova in un blocco rientrato. Qualsiasi soluzione basata sul paradigma "delete-then-append" fallisce in questo modo.

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

Con un paio generico di variabile/valore che si può scrivere in questo modo:

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 

Infine, se anche voi volete mantenere commenti in linea, è possibile farlo con un fermo gruppo. Per esempio. se test.conf contiene:

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

Poi eseguire questo

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

Produce che:

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