GNU/Linux >> Linux Esercitazione >  >> Linux

Come sostituire una stringa in un file?

La sostituzione delle stringhe nei file in base a determinati criteri di ricerca è un'operazione molto comune. Come posso

  • sostituisci la stringa foo con bar in tutti i file nella directory corrente?
  • Fare lo stesso ricorsivamente per le sottodirectory?
  • sostituire solo se il nome del file corrisponde a un'altra stringa?
  • sostituire solo se la stringa si trova in un determinato contesto?
  • sostituire se la stringa si trova su un certo numero di riga?
  • sostituisci più stringhe con la stessa sostituzione
  • sostituisci più stringhe con sostituzioni diverse

Risposta accettata:

1. Sostituzione di tutte le occorrenze di una stringa con un'altra in tutti i file nella directory corrente:

Questi sono per i casi in cui sai che la directory contenga solo file regolari e che desideri elaborare tutti i file non nascosti. In caso contrario, utilizzare gli approcci in 2.

Tutti i sed le soluzioni in questa risposta presuppongono GNU sed . Se utilizzi FreeBSD o macOS, sostituisci -i con -i '' . Si noti inoltre che l'uso di -i passare con qualsiasi versione di sed ha alcune implicazioni sulla sicurezza del filesystem ed è sconsigliabile in qualsiasi script che intendi distribuire in alcun modo.

  • Non ricorsivo, solo file in questa directory:

     sed -i -- 's/foo/bar/g' *
     perl -i -pe 's/foo/bar/g' ./* 
    

(il perl uno fallirà per i nomi di file che terminano con | o spazio)).

  • File ricorsivi e regolari (compresi quelli nascosti ) in questa e in tutte le sottodirectory

     find . -type f -exec sed -i 's/foo/bar/g' {} +
    

    Se stai usando zsh:

     sed -i -- 's/foo/bar/g' **/*(D.)
    

    (potrebbe fallire se l'elenco è troppo grande, vedi zargs per aggirare).

    Bash non può verificare direttamente la presenza di file regolari, è necessario un ciclo (le parentesi graffe evitano di impostare le opzioni a livello globale):

     ( shopt -s globstar dotglob;
         for file in **; do
             if [[ -f $file ]] && [[ -w $file ]]; then
                 sed -i -- 's/foo/bar/g' "$file"
             fi
         done
     )
    

    I file vengono selezionati quando sono file effettivi (-f) e sono scrivibili (-w).

2. Sostituisci solo se il nome del file corrisponde a un'altra stringa / ha un'estensione specifica / è di un certo tipo ecc:

  • Non ricorsivo, solo file in questa directory:

    sed -i -- 's/foo/bar/g' *baz*    ## all files whose name contains baz
    sed -i -- 's/foo/bar/g' *.baz    ## files ending in .baz
    
  • File ricorsivi e regolari in questa e in tutte le sottodirectory

    find . -type f -name "*baz*" -exec sed -i 's/foo/bar/g' {} +
    

    Se stai usando bash (le parentesi graffe evitano di impostare le opzioni a livello globale):

    ( shopt -s globstar dotglob
        sed -i -- 's/foo/bar/g' **baz*
        sed -i -- 's/foo/bar/g' **.baz
    )
    

    Se stai usando zsh:

    sed -i -- 's/foo/bar/g' **/*baz*(D.)
    sed -i -- 's/foo/bar/g' **/*.baz(D.)
    

Il -- serve a dire a sed che non verranno più forniti flag nella riga di comando. Questo è utile per proteggere dai nomi di file che iniziano con - .

  • Se un file è di un certo tipo, ad esempio, eseguibile (vedi man find per ulteriori opzioni):

    find . -type f -executable -exec sed -i 's/foo/bar/g' {} +
    

zsh :

    sed -i -- 's/foo/bar/g' **/*(D*)

3. Sostituisci solo se la stringa si trova in un determinato contesto

  • Sostituisci foo con bar solo se esiste un baz più avanti sulla stessa riga:

     sed -i 's/foo(.*baz)/bar1/' file
    

In sed , utilizzando ( ) salva tutto ciò che è tra parentesi e puoi quindi accedervi con 1 . Esistono molte varianti di questo tema, per saperne di più su tali espressioni regolari, vedere qui.

  • Sostituisci foo con bar solo se foo si trova nella colonna 3d (campo) del file di input (assumendo campi separati da spazi):

     gawk -i inplace '{gsub(/foo/,"baz",$3); print}' file
    

(richiede gawk 4.1.0 o successivo).

  • Per un campo diverso usa semplicemente $N dove N è il numero del campo di interesse. Per un separatore di campo diverso (: in questo esempio) usa:

     gawk -i inplace -F':' '{gsub(/foo/,"baz",$3);print}' file
    

Un'altra soluzione che utilizza perl :

    perl -i -ane '$F[2]=~s/foo/baz/g; $" = " "; print "@Fn"' foo 

NOTA:sia il awk e perl le soluzioni influiranno sulla spaziatura nel file (rimuovere gli spazi vuoti iniziali e finali e convertire le sequenze di spazi vuoti in uno spazio in quelle righe che corrispondono). Per un campo diverso, usa $F[N-1] dove N è il numero di campo desiderato e per un separatore di campo diverso utilizzare (il $"=":" imposta il separatore del campo di output su : ):

    perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo 
  • Sostituisci foo con bar solo sulla 4a riga:

     sed -i '4s/foo/bar/g' file
     gawk -i inplace 'NR==4{gsub(/foo/,"baz")};1' file
     perl -i -pe 's/foo/bar/g if $.==4' file
    

4. Operazioni multiple di sostituzione:sostituisci con stringhe diverse

  • Puoi combinare sed comandi:

     sed -i 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    

Tieni presente che l'ordine è importante (sed 's/foo/bar/g; s/bar/baz/g' sostituirà foo con baz ).

  • o comandi Perl

     perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    
  • Se hai un numero elevato di pattern, è più facile salvare i tuoi pattern e le loro sostituzioni in un sed file di script:

     #! /usr/bin/sed -f
     s/foo/bar/g
     s/baz/zab/g
    
  • Oppure, se hai troppe coppie di pattern perché quanto sopra sia fattibile, puoi leggere le coppie di pattern da un file (due pattern separati da spazi, $pattern e $replacement, per riga):

     while read -r pattern replacement; do   
         sed -i "s/$pattern/$replacement/" file
     done < patterns.txt
    
  • Sarà piuttosto lento per lunghi elenchi di pattern e file di dati di grandi dimensioni, quindi potresti voler leggere i pattern e creare un sed script da loro invece. Quanto segue presuppone uno <spazio> delimitatore separa un elenco di MATCH<spazio>REPLACE coppie che si verificano una per riga nel file patterns.txt :

     sed 's| *([^ ]*) *([^ ]*).*|s/1/2/g|' <patterns.txt |
     sed -f- ./editfile >outfile
    

Il formato sopra è in gran parte arbitrario e, ad esempio, non consente uno <spazio> in una delle PARTITA o SOSTITUIRE . Il metodo è però molto generale:in pratica, se riesci a creare un flusso di output che assomigli a un sed script, quindi puoi ottenere quel flusso come sed script specificando sed 's file di script come - stdin.

  • Puoi combinare e concatenare più script in modo simile:

     SOME_PIPELINE |
     sed -e'#some expression script'  
         -f./script_file -f-          
         -e'#more inline expressions' 
     ./actual_edit_file >./outfile
    

Un POSIX sed concatenerà tutti gli script in uno nell'ordine in cui appaiono sulla riga di comando. Nessuno di questi deve terminare con un n ewline.

  • grep può funzionare allo stesso modo:

     sed -e'#generate a pattern list' <in |
     grep -f- ./grepped_file
    
  • Quando si lavora con stringhe fisse come pattern, è buona norma evitare i metacaratteri dell'espressione regolare . Puoi farlo abbastanza facilmente:

     sed 's/[]$&^*./[]/\&/g
          s| *([^ ]*) *([^ ]*).*|s/1/2/g|
     ' <patterns.txt |
     sed -f- ./editfile >outfile
    

5. Operazioni multiple di sostituzione:sostituisci più pattern con la stessa stringa

  • Sostituisci uno qualsiasi di foo , bar o baz con foobar

     sed -Ei 's/foo|bar|baz/foobar/g' file
    
  • o

     perl -i -pe 's/foo|bar|baz/foobar/g' file
    

Linux
  1. Come sostituire il testo come sed con python?

  2. Rimuovi le occorrenze della stringa nel file di testo

  3. Come inserire un testo all'inizio di un file?

  4. Come sostituire una stringa in più file nella riga di comando di Linux

  5. Comando tr - come sostituire la stringa \n con una nuova riga effettiva (\n)

Come utilizzare sed per trovare e sostituire la stringa nei file

Come trovare una stringa in un file su Linux

Sostituzione di String in Bash

Come utilizzare il comando SED per trovare e sostituire la stringa nei file

Come trovare e sostituire testo, parola o stringa in un file

Come utilizzare Sed per trovare e sostituire una stringa in un file