2011-07-18 12 views
31

Sto provando ad aggiungere una riga di testo al centro di un file di testo in uno script bash. Specificamente sto provando ad aggiungere un nameserver al mio file /etc/resolv.conf. Così com'è, resolv.conf assomiglia a questo:Come si aggiunge una riga di testo al centro di un file usando bash?

# Generated by NetworkManager 
domain dhcp.example.com 
search dhcp.example.com 
nameserver 10.0.0.1 
nameserver 10.0.0.2 
nameserver 10.0.0.3 

Il mio obiettivo è quello di aggiungere nameserver 127.0.0.1 sopra tutte le altre linee di server dei nomi, ma al di sotto qualsiasi testo di sopra. Alla fine voglio il mio file resolve.conf a guardare come questo:

# Generated by NetworkManager 
domain dhcp.example.com 
search dhcp.example.com 
nameserver 127.0.0.1 
nameserver 10.0.0.1 
nameserver 10.0.0.2 
nameserver 10.0.0.3 

Come è possibile tramite uno script bash? È qualcosa che sed o awk può fare? O farebbe volentieri la creatività di ricreare il file?

risposta

34

Ecco una soluzione che utilizza sed:

$ sed -n 'H;${x;s/^\n//;s/nameserver .*$/nameserver 127.0.0.1\n&/;p;}' resolv.conf 

# Generated by NetworkManager 
domain dhcp.example.com 
search dhcp.example.com 
nameserver 127.0.0.1 
nameserver 10.0.0.1 
nameserver 10.0.0.2 
nameserver 10.0.0.3 

Come funziona: prima, sopprimere l'uscita del sed con la bandiera -n. Quindi, per ogni linea, aggiungiamo la linea allo spazio stiva, separandoli con newlines:

H 

Quando si arriva alla fine del file (affrontato da $) si sposta il contenuto dello spazio stiva di lo spazio modello:

x 

Se la prima riga nello spazio modello è vuota, la sostituiamo con nulla.

s/^\n// 

Poi abbiamo sostituire la prima riga che inizia con nameserver da una linea contenente nameserver 127.0.0.1, una nuova linea (La versione di sed potrebbe non supportare \n, nel qual caso sostituire il n con un ritorno a capo letterale) e la linea originale (rappresentato da &):

s/nameserver .*$/nameserver 127.0.0.1\n&/ 

Ora abbiamo solo bisogno di stampare i risultati:

p 
+1

questo è grande. L'unica cosa strana è aggiungere una riga vuota nella parte superiore del nuovo file. Non è un grosso problema, ma sta causando un momento OCD. – PHLAK

+4

Oh, sì, hai ragione! Il comando 'sed -n 'H; $ {x; s/^ \ n //; s/nameserver. * \ N/nameserver 127.0.0.1 \ n & /; p;}' resolv.conf', tuttavia, risolve questo problema. Ho aggiunto 's/^ \ n //' al comando in modo da rimuovere il newline all'inizio del contenuto dello spazio pattern. – brandizzi

+0

Fantastico, grazie! – PHLAK

8

awk '/^nameserver/ && !modif { printf("INSERT\n"); modif=1 } {print}'

+0

Ottima soluzione 'awk', forse l'unica che non copia l'intero file in memoria ... – MestreLion

15

Supponendo che si desidera inserire immediatamente dopo la riga search, questo è molto più semplice:

sed -ie '/^search/a nameserver 127.0.0.1' filename 
  • -i: Modifica file in luogo
  • -e: permette l'esecuzione di uno script/espressione comandi all'interno sed
  • a mynewtext: comando che indica a sed di inserire il mynewtext testo dopo gli abbinamenti
+0

Questo è il cosa ... quella linea di ricerca potrebbe essere o non esserci. Le righe dei nameserver dovrebbero sempre essere lì, e voglio che la nuova riga venga inserita immediatamente prima di esse, indipendentemente dal resto del contenuto del file. – PHLAK

+0

@PHLAK, la soluzione offerta da Jim è buona. Lo modificherei, comunque. Aggiungi semplicemente un _ commento speciale_ per segnare la linea in cui si suppone che le nuove cose vengano inserite. Per esempio. una riga come '# <>' o qualcosa del genere. Quindi, invece di '/^cerca /' puoi cercare '/^# <> $ /', rendendo molto più improbabile che corrisponda alla linea sbagliata. – bitmask

+0

Come modificheresti questo (se possibile) per usare una singola linea da un altro file (supponi che questo file abbia solo una riga), invece di 'nameserver 127.0.0.1'? – Juan

0

Questo potrebbe funzionare per si:

sed -e '/nameserver/{x;/./b;x;h;i\nameserver 127.0.0.1' -e '}' resolv.conf 

o GNU sed:

sed -e '0,/nameserver/{//i\nameserver 127.0.0.1' -e '}' resolv.conf 
0

Ecco una soluzione Perl:

perl -lne 'if (not $f and /^nameserver/){ print "nameserver 127.0.0.1"; $f=1 }; print' resolv.conf

  • -n cappio intorno ad ogni riga del file di input, non stampare automaticamente ogni linea

  • -l rimuove a capo prima della lavorazione, e li aggiunge di nuovo in seguito

  • -e eseguire il codice perl

$f viene utilizzato come un flag per indicare che la stringa nameserver è già stato trovato

Problemi correlati