目录

AaronJny

诗酒繁华,书剑天涯。

使用Python脚本批量替换项目中的数据库地址

这几天接手到了一个很老很老的项目,PHP 的,里面的数据库地址不是同一配置的。有很多子站点,每个字站点又有自己的配置文件,这个时候,问题来了,要换数据库地址了!!!

初闻这个问题,我整个人都是懵逼的,这不是搞我嘛?这么多改起来得多麻烦?

但活儿还是得做啊,于是作为一名机智的大彩笔,我决定写个 Python 脚本解决这个问题。

当然,这个问题可以被简单理解为,给定路径 a,字符串列表 b,字符串 c,请将路径 a 下的全部文本文件(包括若干级子目录下的文本文件)中的字符串列表 b 中的全部字符串统一替换为字符串 c。

脚本编写如下:

# -*- coding: utf-8 -*-
# @File  : replace_content.py
# @Author: AaronJny
# @Date  : 2019/11/21
# @Desc  : 给定路径a,字符串列表b,字符串c,请将路径a下的全部文本文件(包括若干级子目录下的文本文件)中的字符串列表b中的全部字符串统一替换为字符串c。
import logging
import os
from pprint import pprint
import time

# 设置日志输出格式
logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                    level=logging.INFO)

# 需要进行替换的文件的根路径
ROOT_PATH = '/home/aaron/code/'
# 待替换的原始字符串
ORIGIN_STRING_LIST = ['张三', '李四']
# 用于替换的目标字符串
TARGET_STRING = '王五'
# 需要替换的文件的扩展名列表
FILENAME_EXTENSIONS = ['.php']
# 文件编码类型
ENCODE_TYPE = 'utf-8'

check_results = []


def check_filename_extension(filename, extensions):
    """
    给定一个文件名filename,判断文件名是否以扩展名列表extensions中的任意一个

    Args:
        filename: 文件名
        extensions: 扩展名列表

    Returns:
        bool:给定文件是否以扩展名列表中的一个扩展名结尾
    """
    for extension in extensions:
        if filename.endswith(extension):
            return True
    return False


def check_content(text, origin_strings):
    """
    检查给定的文本text中,是否包含待替换字符串列表origin_strings中的若干项

    Args:
        text: 被检查的文本
        origin_strings: 待替换字符串列表

    Returns:
        list: 文本中包含的待替换字符串列表
    """
    ret = []
    # 逐个查找origin_string
    for origin_string in origin_strings:
        # 如果找到了,就加入到返回列表中
        if origin_string in text:
            ret.append(origin_string)
    return ret


def read_file(path):
    """
    给定路径path,读取对应的文本文件内容

    Args:
        path: 文件路径

    Returns:
        str: 文件内容
    """
    with open(path, 'r', encoding=ENCODE_TYPE) as f:
        text = f.read()
    return text


def dfs_find(path, origin_strings, filename_extensions):
    """
    递归查找包含有origin_strings中的任意一个字符串的全部文本路径

    Args:
        path: 当前目录路径
        origin_strings: 待替换的原始字符串列表
        filename_extensions: 文件扩展名列表,只对扩展名在列表中的文件进行查找
    """
    # 如果给定路径不是目录,就直接跳过
    if not os.path.isdir(path):
        return
    # 获取路径下的全部文件和子目录
    for obj in os.listdir(path):
        abs_obj_path = os.path.abspath(os.path.join(path, obj))
        # 如果是目录,就递归查找
        if os.path.isdir(abs_obj_path):
            dfs_find(abs_obj_path, origin_strings, filename_extensions)
        # 是文件,并且扩展名正确
        elif check_filename_extension(abs_obj_path, filename_extensions):
            # 先读取文件
            text = read_file(abs_obj_path)
            # 然后判断文本中是否包含指定字符串
            ret_strings = check_content(text, origin_strings)
            if ret_strings:
                logging.info('找到一个需要进行替换的文件 {},待替换词为 {}'.format(abs_obj_path, ret_strings))
                check_results.append((abs_obj_path, ret_strings))


# 先查找包含待替换字符串的文件路径
logging.info('开始查找需要替换的文件...')
dfs_find(ROOT_PATH, origin_strings=ORIGIN_STRING_LIST,
         filename_extensions=FILENAME_EXTENSIONS)
# 等待确认
logging.info('查找完成,共有如下文件需要进行替换,请确认!(10s后将自动开始执行)')
time.sleep(1)
pprint(check_results)
time.sleep(10)
logging.info('开始替换...')
# 开始替换
for path, origin_strings in check_results:
    logging.info('正在替换 {}'.format(path))
    # 先读取
    text = read_file(path)
    # 再替换
    for origin_string in origin_strings:
        text = text.replace(origin_string, TARGET_STRING)
    # 再写入
    with open(path, 'w', encoding=ENCODE_TYPE) as f:
        f.write(text)
logging.info('完毕!')

请注意,在执行脚本前,请确认你清楚脚本的执行结果,最好先对数据备份。请谨慎执行。


标题:使用Python脚本批量替换项目中的数据库地址
作者:AaronJny
地址:https://aaronjny.com/articles/2019/11/21/1574321234088.html