2010-06-24 4 views
5

Я хотел бы научиться использовать python в качестве замены сценариев командной строки. Я провел некоторое время с питоном в прошлом, но прошло какое-то время. Это, по-видимому, входит в сферу его применения.Сделайте поиск и замените все файлы в папке через python?

У меня есть несколько файлов в папке, в которой я хочу выполнить поиск и замену во всех них. Я хотел бы сделать это с помощью скрипта python.

Например, найдите и замените все экземпляры "foo" на "foobar".

ответ

2

Обычно я выскочить старый perl -pi -e 's/foo/foobar/' для этого, но если вы хотите Python:

import os 
import re 
_replace_re = re.compile("foo") 
for dirpath, dirnames, filenames in os.walk("directory/"): 
    for file in filenames: 
     file = os.path.join(dirpath, file) 
     tempfile = file + ".temp" 
     with open(tempfile, "w") as target: 
      with open(file) as source: 
       for line in source: 
        line = _replace_re.sub("foobar", line) 
        target.write(line) 
     os.rename(tempfile, file) 

И если вы на Windows, вам нужно добавить os.remove(file) перед os.rename(tempfile, file).

+0

Кроме того, было бы хорошо поставить в маленькой проверке, чтобы проверить, что 'tempfile' еще не существует ... –

+0

Это, кажется, имеет смысл. Является ли акт создания временного файла просто так, если разрешений недостаточно, мы все равно можем выполнить действие? В этом случае удаление и переименование не будут работать, исправить? – fruit

+0

Tempfile гарантирует, что мы не перезаписываем реальный файл слишком рано и чтобы мы не использовали много памяти в большом файле (наивный способ сделать это был бы примерно так: 'data = open (файл) .read(); data = _replace_re.sub («foobar», data); open (файл, «w»). write (data) ', но это будет использовать много памяти и, если компьютер разбился на полпути 'write', вы потеряете неписанные данные) –

1

Я работал над этим, и это, похоже, работает, но любые ошибки, которые можно указать, были бы удивительными.

import fileinput, sys, os 

def replaceAll(file, findexp, replaceexp): 
    for line in fileinput.input(file, inplace=1): 
     if findexp in line: 
      line = line.replace(findexp, replaceexp) 
     sys.stdout.write(line) 

if __name__ == '__main__': 
    files = os.listdir("c:/testing/") 
    for file in files: 
     newfile = os.path.join("C:/testing/", file) 
     replaceAll(newfile, "black", "white") 

Расширение на этом было бы перемещение в папки в папках.

+0

Что вы можете сделать, это изменить это на' replaceAll (файл, «черный», «белый») '- как есть, если у вас когда-нибудь будет' somedir/blackdir/blackfile.txt', то вы получите 'somedir/whitedir/whitefile.txt'.Если, конечно, вы этого не хотите, и в этом случае оставите это, как у вас есть. –

+0

Зачем нужна функция переименования файлов? Он ищет его по строкам .. – fruit

5

Добро пожаловать в StackOverflow. Поскольку вы хотите учиться (+1), я просто дам вам несколько указателей.

Отъезд os.walk(), чтобы получить доступ ко всем файлам.

Затем перебирайте каждую строку в файлах (for line in currentfile: пригодится здесь).

Теперь вы должны знать, если вы хотите «глупо» заменить (найти/заменить каждую foo, даже если он находится в середине слова (скажем foobar - вы хотите foofoobar в результате) или смарт заменить?.

для первого, посмотрите на str.replace(), для последнего, посмотрите на re.sub() и выяснить, какие r'\bfoo\b' средства.

+0

Очень круто, спасибо! Изучение новых функций (os.walk()) всегда хорошо. Проходит ли он также подкаталоги? Я предполагаю, что ваша ссылка мне скажет. – fruit

+0

Да, да, да, да! –

0

это альтернатива, так как у вас есть различные Python решения, представленные Вам. самая полезная утилита (по мне), в Unix/Windows, это команда GNU find и инструменты для замены, такие как sed/awk. для поиска f iles (рекурсивно) и делать замену, простая команда вроде этого делает трюк (синтаксис приходит из памяти и не тестируется). это говорит найти все текстовые файлы и изменить слово «старый» на «новый» в их содержании, в то же время, использовать sed для резервного копирования исходных файлов ...

$ find /path -type f -iname "*.txt" -exec sed -i.bak 's/old/new/g' "{}" +; 
Смежные вопросы