Como substituir uma cadeia de texto em vários arquivos no Linux

3

Existem várias maneiras de substituir uma sequência de texto por outra em vários arquivos. Aqui estão algumas maneiras:

usando sed e encontre:

sed 's/oldstring/newstring/' "$1" > "$1".new && find -iname "*.new" | sed 's/.new//' | sh

usando grep e sed:

grep -rl oldstring . | xargs sed -i -e 's/oldstring/newstring/'

usando grep e perl:

grep -rl oldstring . | xargs perl -pi~ -e 's/oldstring/newstring/'

Por favor, ofereça suas próprias sugestões.

    
por mezgani 03.10.2009 / 01:25

6 respostas

0

Eu usaria o Python para isso. Coloque todo este código em um arquivo chamado mass_replace e " chmod +x mass_replace ":

#!/usr/bin/python

import os
import re
import sys

def file_replace(fname, s_before, s_after):
    out_fname = fname + ".tmp"
    out = open(out_fname, "w")
    for line in open(fname):
        out.write(re.sub(s_before, s_after, line))
    out.close()
    os.rename(out_fname, fname)


def mass_replace(dir_name, s_before, s_after):
    for dirpath, dirnames, filenames in os.walk(dir_name):
        for fname in filenames:
            f = fname.lower()
            # example: limit replace to .txt, .c, and .h files
            if f.endswith(".txt") or f.endswith(".c") or f.endswith(".h"):
                f = os.path.join(dirpath, fname)
                file_replace(f, s_before, s_after)

if len(sys.argv) != 4:
    u = "Usage: mass_replace <dir_name> <string_before> <string_after>\n"
    sys.stderr.write(u)
    sys.exit(1)

mass_replace(sys.argv[1], sys.argv[2], sys.argv[3])

Para uma única pesquisa e substituição de uma string em um tipo de arquivo, a solução com find e sed não é ruim. Mas se você quiser fazer muito processamento em um passo, você pode editar este programa para ampliá-lo, e será fácil (e provavelmente estará correto na primeira vez).

    
por 02.12.2009 / 02:14
3

Usando o GNU find, xargs e sed assim:

 find -name '*.txt' -o -name '*.html' -print0 | xargs -0 -P 1 -n 10 sed --in-place 's/oldstring/newstring/g'

Ajuste os parâmetros -P e -n conforme desejar. O /g é necessário para que cada ocorrência em uma linha seja substituída, não apenas a primeira ( g significa global se bem me lembro). Você também pode passar um valor para --in-place para fazer um backup.

    
por 04.10.2009 / 05:11
3

Eu gosto da receita de filtragem no local do perl.

   perl -pi.bak -e 's/from/to/' file1 file2 ...

No contexto ...

% echo -e 'foo\ngoo\nboo' >test
% perl -pi.bak -e 's/goo/ber/' test
% diff -u test.bak test
--- test.bak    2010-01-06 05:43:53.072335686 -0800
+++ test    2010-01-06 05:44:03.751585440 -0800
@@ -1,3 +1,3 @@
 foo
-goo
+ber
 boo

aqui está a referência rápida aparada no encantamento perl usado ...

% perl --help
Usage: perl [switches] [--] [programfile] [arguments]
  -e program        one line of program (several -e's allowed, omit programfile)
  -i[extension]     edit <> files in place (makes backup if extension supplied)
  -n                assume "while (<>) { ... }" loop around program
  -p                assume loop like -n but print line also, like sed
    
por 06.01.2010 / 14:49
0

Supondo que a lista de arquivos não tenha uma milha de comprimento, você não precisa usar xargs, já que o sed pode manipular vários arquivos na linha de comando:

sed -i -e 's/oldstring/newstring/' 'grep -rl oldstring .'
    
por 04.10.2009 / 06:12
0

Tenha cuidado se substituir URLs por caracteres "/".

Um exemplo de como fazer isso:

sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"

Extraído de: link

    
por 27.07.2015 / 20:29
-1

Obrigado por algumas ótimas respostas a todos! Isso foi super útil.

Como não tinha centenas de arquivos para substituir linhas, usei um loop do tipo:

   for R in 1 2 3 4 5; do sed -i -e 's/oldstring/newstring/' file$R; done

Espero que ajude!

    
por 07.05.2015 / 13:00