Как заменить текстовую строку в нескольких файлах в Linux
Существует множество способов заменить одну строку текста другой во многих файлах. Вот несколько способов:
используя sed и найдите:
sed 's/oldstring/newstring/' "$1" > "$1".new && find -iname "*.new" | sed 's/.new//' | sh
используя grep и sed:
grep -rl oldstring . | xargs sed -i -e 's/oldstring/newstring/'
используя grep и perl:
grep -rl oldstring . | xargs perl -pi~ -e 's/oldstring/newstring/'
Пожалуйста, предложите свои собственные предложения.
6 ответов
Я бы использовал Python для этого. Поместите весь этот код в файл с именем mass_replace и "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])
Для одного поиска и замены одной строки в одном типе файла решение с find и sed не плохое. Но если вы хотите выполнить большую обработку за один проход, вы можете отредактировать эту программу, чтобы расширить ее, и это будет легко (и, вероятно, будет правильным в первый раз).
Используя GNU find, xargs и sed, вот так:
find -name '*.txt' -o -name '*.html' -print0 | xargs -0 -P 1 -n 10 sed --in-place 's/oldstring/newstring/g'
Настроить -P
а также -n
параметры, как вам нравится. /g
необходимо, чтобы заменялось каждое вхождение в строке, а не только первое (g
означает глобальный, если я правильно помню). Вы также можете передать значение --in-place
сделать резервную копию.
Мне нравится рецепт фильтрации на месте Perl.
perl -pi.bak -e 's / from / to /' file1 file2...
В контексте...
% 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
Вот краткий справочник об использованном заклинании Perl...
% 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
Будьте осторожны, если вы заменяете URL символом "/".
Пример того, как это сделать:
sed -i "s%http://domain.com%http://www.domain.com/folder/%g" "test.txt"
Извлечено из: http://www.sysadmit.com/2015/07/linux-reemplazar-texto-en-archivos-con-sed.html
Предполагая, что список файлов не имеет длины в милю, вам не нужно использовать xargs, так как sed может обрабатывать несколько файлов в командной строке:
sed -i -e 's/oldstring/newstring/' `grep -rl oldstring .`
Спасибо за отличные ответы всем! Это было супер-полезно.
Поскольку у меня не было сотен файлов для замены строк, я использовал цикл do, например:
for R in 1 2 3 4 5; do sed -i -e 's/oldstring/newstring/' file$R; done
Надеюсь, это поможет!