linux
  • bash
  • recursion
  • sed
  • grep
  • 2013-04-10 11 views 28 likes 
    28

    sto diventando uncercare una stringa in tutti i file ricorsive tramite grep e sed

    sed: -e expression #1, char 22: unterminated `s' command 
    

    c'è un problema sul mio script? Anche il "oldstring" ha i caratteri speciali

    #!bin/bash 
    oldstring='<script>"[oldscript]"</script>' 
    newstring='<script>"[newscript]"</script>' 
    grep -rl $oldstring /path/to/folder | xargs sed -i s/$oldstring/$newstring/g 
    
    +1

    Le parentesi quadre possono avere bisogno di essere sfuggito. Anche la doppia citazione del modello sed. – phs

    +3

    Avrai anche un problema con '/' nei tuoi pattern. Dovrebbero essere scappati. Oppure potresti usare un altro delimitatore per il comando 's' (ad es.' @ '). –

    risposta

    36

    Come ha detto @Didier, è possibile modificare il delimitatore a qualcosa di diverso /:

    grep -rl $oldstring /path/to/folder | xargs sed -i [email protected][email protected][email protected] 
    
    +5

    Quanto sopra potrebbe fallire in così tanti modi interessanti dati così tanti possibili contenuti di oldstring o newstring. –

    +1

    @EdMorton, potresti inserire un esempio di come fallisce? So che hai postato la tradizionale forma di fare sotto, ma solo dicendo che può fallire lascia la domanda su come. Allora potrei capire perché dovrei la tua soluzione. Queste soluzioni sembrano molto più semplici. Grazie –

    +3

    Prova quanto sopra con qualsiasi carattere di globbing della shell o un @ in una variabile stringa. I caratteri globbing possono/corrisponderanno ai nomi dei file nella tua directory, se non oggi un giorno in futuro, quando lo aspetterai l'ultima volta, e @ terminerà il tuo comando sed. Fallirà anche se oldstring contiene spazi in varie posizioni, per non parlare se una stringa contiene caratteri di nuova riga. L'OP ha detto in particolare che "la" vecchia stringa "ha caratteri speciali", quindi è un grande vantaggio che qualsiasi cosa ho appena descritto e più probabilmente accadrà. –

    3

    sed espressione deve essere citato

    sed -i "s/$oldstring/$newstring/g" 
    
    4

    I ragazzi della GNU REALMENTE hanno incasinato quando hanno introdotto il file ricorsivo alla ricerca di grep. grep è per trovare i RE nei file e stampare la riga corrispondente (g/re/p ricorda?) NON per trovare i file. C'è un ottimo strumento con un nome molto ovvio per trovare i file. Qualunque cosa sia accaduta al mantra UNIX di fare una cosa e farla bene?

    In ogni caso, ecco come si farebbe ciò che si vuole utilizzare l'approccio tradizionale UNIX (non testata):

    find /path/to/folder -type f -print | 
    while IFS= read -r file 
    do 
        awk -v old="$oldstring" -v new="$newstring" ' 
         BEGIN{ rlength = length(old) } 
         rstart = index($0,old) { $0 = substr($0,rstart-1) new substr($0,rstart+rlength) } 
         { print } 
        ' "$file" > tmp && 
        mv tmp "$file" 
    done 
    

    Non che utilizzando awk/index() al posto di sed e grep di evitare la necessità di sfuggire a tutti i metacaratteri di RE che potrebbero apparire nella tua vecchia o nella tua nuova stringa, oltre a capire un carattere da usare come delimitatore di sed che non può apparire nelle tue vecchie o nuove stringhe e che non devi eseguire grep poiché la sostituzione si verifica solo per i file che contengono la stringa desiderata. Detto questo, se non si desidera modificare il timestamp del file se non si modifica il file, basta fare un diff su tmp e il file originale prima di fare il mv o lanciare un fgrep -q prima del awk.

    Avvertenza: quanto sopra non funzionerà per i nomi di file che contengono newline. Se ne hai, quindi faccelo sapere e possiamo mostrarti come gestirli.

    +2

    +1 Quando qualcuno parla dell'uso di 'sed' con' grep', ci sono ottime possibilità che dovrebbero usare solo 'sed' o passare a' awk'. A proposito, se hai usato '-print0' nel tuo find, e (in BASH) usando' -d \ 0' dovresti occuparti dei nomi dei file con nuove linee al loro interno. –

    +0

    @DavidW. Destra.E quando inizi a parlare di escape dei metacaratteri di RE in modo che sed o grep non li trattino come tali, devi passare a awk/index() o fgrep in modo da poter cercare stringhe invece di RE. –

    +0

    @josten l'argomento '-r' per' grep' è un'alternativa all'utilizzo di 'find' per non usare' awk'. Puoi usare 'awk' con' find + xargs' invece di 'grep + sed' e il risultato sarà solitamente più conciso ed efficiente. L'uso di 'awk' non ti farà certamente creare enormi one-liner contorti. –

    9
    grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g" 
    
    +0

    Quindi la complicazione con questo, i file con spazi nei loro nomi non verranno raccolti. Se avessi "/ files/File Two.txt", sed proverebbe "/ files/File" e "Two.txt". – Captainlonate

    -1
    grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g' 
    
    Problemi correlati