bash - print - uso comando sed




Come fare una ricerca/sostituzione ricorsiva di una stringa con awk o sed? (20)

Come trovo e sostituisco ogni occorrenza di:

subdomainA.example.com

con

subdomainB.example.com

in ogni file di testo sotto l'albero /home/www/ directory in modo ricorsivo?


Avevo solo bisogno di questo e non ero soddisfatto della velocità degli esempi disponibili. Quindi sono venuto con il mio:

cd /var/www && ack-grep -l --print0 subdomainA.example.com | xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

Ack-grep è molto efficiente nel trovare file pertinenti. Questo comando ha sostituito ~ 145.000 file con una leggera brezza mentre altri hanno impiegato così tanto tempo che non potevo aspettare fino alla fine.


Ecco una versione che dovrebbe essere più generale della maggior parte; non richiede la find (usando invece du ), per esempio. Richiede xargs , che si trovano solo in alcune versioni di Plan 9 (come 9front).

 du -a | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'

Se vuoi aggiungere filtri come le estensioni di file usa grep :

 du -a | grep "\.scala$" | awk -F' '  '{ print $2 }' | xargs sed -i -e 's/subdomainA\.example\.com/subdomainB.example.com/g'

Io uso solo punte:

find . -name '*.[c|cc|cp|cpp|m|mm|h]' -print0 |  xargs -0 tops -verbose  replace "verify_noerr(<b args>)" with "__Verify_noErr(<args>)" \
replace "check(<b args>)" with "__Check(<args>)" 

Per Qshell (qsh) su IBMi, non bash come taggato da OP.

Limitazioni dei comandi qsh:

  • find non ha l'opzione -print0
  • xargs non ha l'opzione -0
  • sed non ha l'opzione -i

Quindi la soluzione in qsh:

    PATH='your/path/here'
    SEARCH=\'subdomainA.example.com\'
    REPLACE=\'subdomainB.example.com\'

    for file in $( find ${PATH} -P -type f ); do

            TEMP_FILE=${file}.${RANDOM}.temp_file

            if [ ! -e ${TEMP_FILE} ]; then
                    touch -C 819 ${TEMP_FILE}

                    sed -e 's/'$SEARCH'/'$REPLACE'/g' \
                    < ${file} > ${TEMP_FILE}

                    mv ${TEMP_FILE} ${file}
            fi
    done

Avvertenze:

  • La soluzione esclude la gestione degli errori
  • Non Bash come taggato da OP

Per me la soluzione più semplice da ricordare è https://.com/a/2113224/565525 , ovvero:

sed -i '' -e 's/subdomainA/subdomainB/g' $(find /home/www/ -type f)

NOTA : -i '' risolve problema OSX sed: 1: "...": invalid command code .

NOTA : se ci sono troppi file da elaborare, si otterrà un Argument list too long . La soluzione alternativa: utilizzare la soluzione find -exec o xargs descritta in precedenza.


Per ridurre i file su sed modo ricorsivo, potresti grep per la tua istanza di stringa:

grep -rl <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

Se esegui man grep noterai che puoi anche definire un --exlude-dir="*.git" se vuoi omettere la ricerca attraverso le directory .git, evitando i problemi dell'indice git come altri hanno gentilmente fatto notare.

Ti porta a:

grep -rl --exclude-dir="*.git" <oldstring> /path/to/folder | xargs sed -i s^<oldstring>^<newstring>^g

Prova questo:

sed -i 's/subdomainA/subdomainB/g' `grep -ril 'subdomainA' *`

Puoi usare awk per risolvere questo come di seguito,

for file in `find /home/www -type f`
do
   awk '{gsub(/subdomainA.example.com/,"subdomainB.example.com"); print $0;}' $file > ./tempFile && mv ./tempFile $file;
done

spero che questo ti possa aiutare !!!



Se non ti dispiace usare vim insieme a grep o strumenti di find , potresti seguire la risposta fornita dall'utente Gert in questo link -> Come fare una sostituzione del testo in una gerarchia di cartelle grandi? .

Ecco l'accordo:

  • ricorsivamente grep per la stringa che si desidera sostituire in un determinato percorso e prendere solo il percorso completo del file corrispondente. (che sarebbe il $(grep 'string' 'pathname' -Rl) .

  • (facoltativo) se vuoi fare un pre-backup di quei file in una directory centralizzata potresti usare anche questo: cp -iv $(grep 'string' 'pathname' -Rl) 'centralized-directory-pathname'

  • successivamente è possibile modificare / sostituire a piacere in vim seguendo uno schema simile a quello fornito sul link dato:

    • :bufdo %s#string#replacement#gc | update

Secondo this post del blog:

find . -type f | xargs perl -pi -e 's/oldtext/newtext/g;'

Tutti i trucchi sono quasi gli stessi, ma mi piace questo:

find <mydir> -type f -exec sed -i 's/<string1>/<string2>/g' {} +
  • find <mydir> : cerca nella directory.

  • -type f :

    Il file è di tipo: file normale

  • -exec command {} + :

    Questa variante dell'azione -exec esegue il comando specificato sui file selezionati, ma la riga di comando viene creata aggiungendo alla fine ciascun nome di file selezionato; il numero totale di invocazioni del comando sarà molto inferiore al numero di file corrispondenti. La riga di comando è costruita nello stesso modo in cui xargs costruisce le sue linee di comando. Solo un'istanza di "{}" è consentita all'interno del comando. Il comando viene eseguito nella directory di partenza.


Un modo più semplice è utilizzare il sotto sulla riga di comando

find /home/www/ -type f|xargs perl -pi -e 's/subdomainA\.example\.com/subdomainB.example.com/g' 

Usando la combinazione di grep e sed

for pp in $(grep -Rl looking_for_string)
do
    sed -i 's/looking_for_string/something_other/g' "${pp}"
done

solo per evitare di cambiare anche

  • NearlysubdomainA.example.com
  • subdomainA.example.comp.other

ma ancora

  • subdomainA.example.com.IsIt.good

(forse non va bene nell'idea dietro la radice del dominio)

find /home/www/ -type f -exec sed -i 's/\bsubdomainA\.example\.com\b/\1subdomainB.example.com\2/g' {} \;

grep -lr 'subdomainA.example.com' | while read file; do sed -i "s/subdomainA.example.com/subdomainB.example.com/g" "$file"; done

Immagino che la maggior parte della gente non sappia che possono incanalare qualcosa in un "file di lettura mentre" ed evita quegli argomenti di brutto-impronta, mentre presiedono gli spazi nei nomi dei file.

Inoltre, aggiungendo echo prima di sed, è possibile vedere quali file cambieranno prima di farlo effettivamente.


Nota : non eseguire questo comando su una cartella che include un repository git - le modifiche a .git potrebbero danneggiare il tuo indice git.

find /home/www/ -type f -exec \
    sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

Rispetto ad altre risposte qui, questo è più semplice della maggior parte e usa sed invece di perl, che è quello che la domanda originale chiedeva.


Un po 'vecchia scuola, ma questo ha funzionato su OS X.

Ci sono alcuni trucchi:

.sls solo i file con estensione .sls nella directory corrente

. deve essere scappato per garantire che sed non li valuti come "qualsiasi carattere"

, viene utilizzato come delimitatore sed invece del solito /

Si noti inoltre che è necessario modificare un modello Jinja per passare una variable nel percorso import (ma questo è fuori tema).

Innanzitutto, verifica che il tuo comando sed faccia ciò che vuoi (questo stamperà solo le modifiche allo stdout, non cambierà i file):

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

Modifica il comando sed secondo necessità, una volta che sei pronto per apportare modifiche:

for file in $(find . -name *.sls -type f); do echo -e "\n$file: "; sed -i '' 's,foo\.bar,foo/bar/\"+baz+\"/,g' $file; done

Notare -i '' nel comando sed , non volevo creare un backup dei file originali (come spiegato nelle modifiche sul posto con sed su OS X o nel commento di Robert Lujo in questa pagina).

Persone seducenti felici!


cd /home/www && find . -type f -print0 |
  xargs -0 perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g'

find /home/www/ -type f -exec perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

find /home/www/ -type f elencherà tutti i file in / home / www / (e le sue sottodirectory). Il flag "-exec" dice find per eseguire il seguente comando su ogni file trovato.

perl -i.bak -pe 's/subdomainA\.example\.com/subdomainB.example.com/g' {} +

è il comando eseguito sui file (molti alla volta). {} Viene sostituito dai nomi dei file. Il + alla fine del comando dice find per creare un comando per molti nomi di file.

Per la pagina man di find : "La riga di comando è costruita più o meno allo stesso modo in cui xargs costruisce le sue linee di comando."

Quindi è possibile raggiungere il tuo obiettivo (e gestire nomi di file contenenti spazi) senza usare xargs -0 o -print0 .





replace