trova / sostituisci batch usando sed o awk


1

In ogni file con nome file corrispondente a pattern1 voglio cercare le righe che iniziano con pattern2 e aggiungere qualche stringa in una nuova riga sopra quelle corrispondenti.

Come semplice esempio supponiamo che stia cercando ricorsivamente file .txt alla ricerca di patate e che voglia aggiungere "spam" sopra, quindi il file /tmp/blah.txt

hello
potato
world
not potato
bye

sarebbe trasformato in

hello
spam
potato
world
not potato
bye

Sembra un semplice lavoro per un mago della shell, qual è il modo più semplice per raggiungere questo obiettivo? Ho taggato alcuni degli strumenti che penso siano i soliti sospetti qui, ma sono aperto ad altri suggerimenti. Punti bonus se può mostrarmi un'anteprima prima di confermare di modificare i file in atto.


Vuoi abbinare anche "nessuna patata"? La tua domanda indica che sì, ma l'output desiderato ti mostra di no.
Terdon,

Scusate, non volevo perché non era all'inizio della linea
w

OK, risposta modificata.
Terdon,

Risposte:


2

Lo farei anche in Perl:

$ for f in *txt; do perl -pne 'print "spam\n" if /^potato/' "$f"; done
hello
spam
potato
world
spam
not potato
bye

Il -pflag fa sì che perl stampi ogni riga del file di input. Il -nmezzo "legge il file di input riga per riga" e applica lo script fornito da -eciascuna riga. Quindi, lo script stesso verrà stampato spamse la riga corrente contiene potatoe stamperà ogni riga. Il risultato sarà la stringa spamstampata sopra le righe che contengono potato.

Questo semplicemente stamperà il nuovo file senza modificarlo. Se si desidera quindi apportare le modifiche al file originale, utilizzare -i:

$ for f in *txt; do perl -i.bak -pne 'print "spam\n" if /^potato/' "$f"; done

Ciò creerà un file di backup chiamato foo.txt.bakper ciascun file elaborato e applicherà le modifiche a foo.txt.


Credo che /potato/dovrebbe essere /^potato$/altrimenti corrisponderebbe anche alla riga "non di patate"?
Olivier Dulac,

@OlivierDulac l'OP ha detto "righe contenenti patate" Volevo abbinare la riga "no potato".
Terdon,

1
@OlivierDulac risulta che avevi ragione, grazie, risposta modificata.
Terdon,

2

Personalmente probabilmente userei perl per qualcosa del genere, ma puoi ottenere ciò che vuoi solo in bash:

while read -r line ; do if [[ $line =~ "potato" ]]; then echo spam;  fi;  echo $line; done < file.txt

Se vuoi inserire il risultato in un nuovo file:

while read -r line ; do if [[ $line =~ "potato" ]]; then echo spam;  fi;  echo $line; done < file.txt > /tmp/outfile.txt

Credo che $line =~ "potato"dovrebbe essere $line =~ "^potato$"altrimenti corrisponderebbe anche alla riga "non di patate"?
Olivier Dulac,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.