Sostituisci rapidamente il testo in file molto grandi


25

Ho un file di testo da 25 GB che necessita di una stringa sostituita su poche righe. Posso usarlo sedcon successo ma ci vuole molto tempo per eseguirlo.

sed -i 's|old text|new text|g' gigantic_file.sql

C'è un modo più rapido per farlo?


Conosci i numeri di riga in cui si trova il testo da sostituire? In caso contrario, l'unica opzione per accelerarla è quella di ottenere un computer più veloce. Il fatto che tu abbia una grande quantità di dati significa che ci vorrà molto tempo per cercarli.
David King,

Posso chiamare i numeri di riga abbastanza rapidamente, quindi sì.
Eisaacson,

Puoi anche usare più core della CPU per velocizzarlo - rankfocus.com/use-cpu-cores-linux-commands
ahaswer

Non usare sed per file di grandi dimensioni. Dai un'occhiata a vi o vim invece.
MikeJRamsey56,

Risposte:


26

Puoi provare:

sed -i '/old text/ s//new text/g' gigantic_file.sql

Da questo ref :

OTTIMIZZAZIONE PER LA VELOCITÀ: se è necessario aumentare la velocità di esecuzione (a causa di file di input di grandi dimensioni o processori lenti o dischi rigidi), la sostituzione verrà eseguita più rapidamente se viene specificata l'espressione "trova" prima di dare "s /.../. ../ "istruzione.

Ecco un confronto su un file 10G. Prima:

$ time sed -i 's/original/ketan/g' wiki10gb
real    5m14.823s
user    1m42.732s
sys     1m51.123s

Dopo:

$ time sed -i '/ketan/ s//original/g' wiki10gb
real    4m33.141s
user    1m20.940s
sys     1m44.451s

L'ultimo sedè errato. Ho modificato questo post ieri per correggere l'ultimo sedcomando che dovrebbe essere time sed -i '/original/ s//ketan/g' wiki10gbe non time sed -i '/ketan/ s//original/g' wiki10gb. Oggi sto ripristinando la mia modifica perché 1. i tempi non corrispondono più al comando e 2. Ho fatto lo stesso test con GNU sed su un file da 3+ GB e non osservo alcuna differenza tra le due sedalternative. Sospetto che la differenza nei tempi sia dovuta all'errore di ortografia.
Xhienne,

@xhienne Non sono sicuro di cosa intendi per errore di ortografia. Nel primo tentativo, sto sostituendo la parola "originale" con "ketan" e nel secondo sto sostituendo il termine "ketan" con il termine "originale", con conseguente uguale numero di sostituzioni in entrambi i casi.
MK

1
Stavo applicando una "correzione" segnalata da un nuovo utente con reputazione insufficiente. Ora capisco cosa hai fatto. Tuttavia, se vuoi dimostrare che una sintassi è migliore dell'altra, devi fare esattamente la stessa operazione che non è il caso qui (dal punto di vista della CPU, cercare una stringa di 5 caratteri non è la stessa cosa che cercare un Stringa di 7 caratteri). Inoltre, questo tipo di test su un file da 10 GB dipende fortemente dal carico della macchina (CPU, disco). Ho visto molte fluttuazioni nei timerisultati personalmente, ma tutto sommato, non c'è stata alcuna differenza nel tempo.
Xhienne,

Credo che questo sia correlato - vedi la risposta accettata qui, stackoverflow.com/questions/11145270/… >> sed trasmette l'intero file, ma come indicato in questa risposta, specificare il numero di riga (se noto) aiuta: nel mio caso , un aumento di ~ 2 volte della velocità di esecuzione (GNU sed 4.5). È possibile grep -n o ripgrep (rg) per trovare i numeri di riga, in base alle ricerche del modello. In effetti, specificare il numero di riga è come avere un risultato di ricerca su quel file, per la risposta sopra.
Victoria Stuart,

1

La risposta breve è "No" - il fattore che limita questo tipo di operazione è l'IO del disco. Non è possibile eseguire lo streaming di 25 GB di un disco più velocemente. Potresti ottenere un miglioramento minore se non esegui la modifica in loco e scrivi il risultato di sedsu un'unità separata (se ne hai una disponibile), perché in questo modo puoi leggere da una, mentre scrivi su un'altra e c'è leggermente di conseguenza meno contesa.

Si potrebbe essere in grado di accelerarlo un po 'non usando il motore di espressioni regolari per ogni linea - così per esempio usando perl (io sono abbastanza sicuro che si può fare questo con sed, ma non so la sintassi) - questo partirà da linea 10.000 in poi.

perl -pe '$. > 10_000 && s/old_text/new_text/g' 

E se c'è qualche tipo di complicanza nel RE (metacaratteri), minimizzare quelli migliorerà leggermente l'efficienza del motore regex.


1
In sed che sarebbesed -i '10000,$ s/old_text/new_text/g'
Dani_l

Bello. Non so come si sedconfronta - presumo leggermente più veloce, ma non molto a causa delle dimensioni del file.
Sobrique,

Suppongo che il perl sia più veloce di sed, ma sed è un po 'meno enigmatico, o piuttosto richiede meno di una curva di apprendimento iniziale.
Dani_l

1
Vedi, ora avrei detto il contrario - si può (quasi) di scrittura sedin perl, ma quest'ultimo permette anche di scrivere più prolisso script troppo.
Sobrique,

0

Se i nuovi e vecchi testi hanno la stessa lunghezza, puoi cercare nel file e scrivere solo i byte modificati, invece di copiare l'intero file. Altrimenti rimani intrappolato nello spostamento di molti dati.

Nota: questo è complicato e comporta la scrittura di codice personalizzato.

Vedi la pagina man di fseek se stai lavorando in C o C ++, o i tuoi wrapper di lingua preferiti per le chiamate di sistema di ricerca e scrittura.

Se insisti nell'usare solo la riga di comando e puoi ottenere gli offset di byte del testo, puoi scrivere il testo sostitutivo con comandi "dd" accuratamente scritti.

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.