Grep per trovare la riga corretta, sed per cambiare il contenuto, quindi rimetterlo nel file originale?


9

Sto provando a cambiare una singola parola su una riga specifica in un file, ma ho qualche problema a collegarmi tutti insieme.

Fondamentalmente, su una riga del mio file c'è una parola chiave "firmware_revision", e su questa linea (e solo questa riga) voglio sostituire la parola "test" con la parola "produzione".

Quindi posso farlo:

grep 'firmware_revision' myfile.py | sed 's/test/production'

Questo sceglierà la riga che desidero ed eseguirà la sostituzione, ma non riesco a capire come ottenere questa nuova riga nel file originale per sostituire la vecchia riga. Ovviamente non posso semplicemente reindirizzarlo al file, quindi cosa dovrei fare?

Anche se uso i provvisori, usando grepper ottenere solo la linea di cui ho bisogno, perdo tutti gli altri dati nel file, quindi non posso più reindirizzare tutto su un file temporaneo, quindi sostituire l'originale con il temp.

Modifica: qualcuno ha chiesto ulteriori informazioni

Diciamo che ho un file pieno di righe come questo

[
  ('key_name1', str, 'value1', 'Description'),
  ('key_name2', str, 'value2', 'Description'),
  ('key_name3', str, 'value3', 'Description'),
  ('firmware_revision', str, 'my-firmware-name-test', 'Firmware revision name')
]

ora voglio scrivere uno script (idealmente un one-liner) che troverà la riga che contiene 'firmware_revision', e cambierà tutte le istanze della parola 'test' su quella linea in 'produzione'. La parola "test" potrebbe trovarsi in altri punti del file e non voglio che vengano modificati. Quindi, per essere chiari, voglio cambiare la riga sopra in

('firmware_revision', str, 'my-firmware-name-production', 'Firmware revision name')

Come faccio a fare questo?


5
sedè molto potente, può svolgere entrambe le funzioni ( grepe la sostituzione) ma avremo bisogno di maggiori informazioni su come appare la linea per aiutarti.
grochmal

Aggiungerò ulteriori informazioni al post originale
John Allard,

7
Prova:sed -i.bak '/firmware_revision/ s/test/production/' myfile.py
Giovanni 1024,

1
Ah ha funzionato perfettamente! Puoi spiegare la sintassi?
John Allard,

@JohnAllard Molto bene. Ho aggiunto una risposta con spiegazione.
Giovanni 1024,

Risposte:


22

Provare:

sed -i.bak '/firmware_revision/ s/test/production/' myfile.py

Qui, /firmware_revision/funge da condizione. È vero per le linee che corrispondono al regex firmware_revisione false per le altre linee. Se la condizione è vera, viene eseguito il comando che segue. In questo caso, quel comando è un comando sostitutivo che sostituisce la prima occorrenza di testcon production.

In altre parole, il comando s/test/production/viene eseguito solo su righe che corrispondono alla regex firmware_revision. Tutte le altre linee passano invariate.

Di default, sed invia il suo output allo standard out. Tuttavia, volevi modificare il file in atto. Quindi, abbiamo aggiunto l' -iopzione. In particolare, -i.bakprovoca la modifica del file in atto con una copia di backup salvata con .bakun'estensione.

Se hai deciso che il comando funziona per te e vuoi vivere pericolosamente e non creare un backup, quindi, con GNU sed (Linux), usa:

sed -i '/firmware_revision/ s/test/production/' myfile.py

Al contrario, su BSD (OSX), l' -iopzione deve avere un argomento. Se non si desidera conservare un backup, fornire un argomento vuoto. Pertanto, utilizzare:

sed -i '' '/firmware_revision/ s/test/production/' myfile.py

modificare

Nella modifica alla domanda, l'OP chiede che ogni occorrenza di testsulla riga sia sostituita production. In tal caso, aggiungiamo l' gopzione al comando di sostituzione per una sostituzione globale (per quella linea):

sed -i.bak '/firmware_revision/ s/test/production/g' myfile.py

5
Per completezza, potresti voler spiegare anche la -i.bakparte.
Stephen Harris,

5
@StephenHarris Ottimo punto. Spiegazione di -iaggiunto.
Giovanni 1024,

Sento che probabilmente potresti raggiungere le stelle, semplicemente in piedi sul libro che spiega tutte le cose che sedpossono fare ...
KlaymenDK

@ John1024 Per le persone non BSD, potresti aggiungere le ragioni del primo ''dopo -i?
Hastur,

3
OP voleva cambiare tutte le istanze della parola "test" su quella linea in "produzione" . In questo caso è importante aggiungere / g al comando sed: in caso sed -i '/firmware_revision/ s/test/production/g' myfile.pycontrario viene modificata solo la prima istanza.
Knub

4

Su macchine più vecchie con vecchia scuola sedche non supportano l'opzione -i:

TF=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) && \
trap 'rm -f "$TF"' EXIT HUP INT QUIT TERM && \
sed '/firmware_revision/ s/test/production/' myfile.py >"$TF" && \
mv -f "$TF" myfile.py

1
Su quelle macchine più vecchie puoi semplicemente usare ede farlo in una riga:printf %s\\n g/firmware_revision/s/test/production/g w q | ed -s myfile.py
don_crissti

1
@don_crissti È vero, ma ed(1)non offre alcun pretesto per mostrare l'uso di mktemp(1).
Satō Katsura,

Se stai usando un tempfile, puoi anche mantenere l'inode e i permanenti del file originale, come edfa. Invece di mv -f "$TF" myfile.pl, utilizzare cat "$TF" > myfile.pl && rm -f "$TF". A proposito, è buona norma usare nomi di variabili minuscole ( $tfinvece di $TF), sono garantiti per non essere in conflitto con alcun VAR incorporato bash (probabilmente anche con altre shell bourne).
Cas

@cas Re:: cat "$TF" > myfile.plprova questo: touch a b; chmod 0444 a; cat b >a(A proposito, sed -inon funzionerà neanche in quel caso). Meglio lasciare che l'utente lo gestisca. Ri:: rm -f "$TF"non necessario, vedi trap ... EXIT. Ri: $tfinvece di $TF: forse; è una questione di stile.
Satō Katsura,

Questo è il comportamento normale e previsto delle autorizzazioni per i file unix. Il mio punto era che la creazione di un nuovo file e il suo spostamento sull'originale 1. risulterebbe in un nuovo inode per quel nome di file (interrompendo qualsiasi collegamento reale). 2. eventualmente cambiare permanenti, se la corrente umask differisce dai permanenti originali. Per quanto riguarda i caratteri maiuscoli, non è solo una questione di stile: molte persone che hanno commesso l'errore di usare PATH o RANDOM o SHELL maiuscoli o qualsiasi altra cosa per le proprie variabili hanno scoperto la strada difficile. (e sì, uso spesso anche io lettere maiuscole. So che è sbagliato, sto cercando di rompere l'abitudine).
Cas
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.