去年帮朋友处理一个被挂马的软件站群,两百多个静态页面的批量源码里,几乎每个文件都嵌了同一个博彩域名。替换手动改?程序光打开文件就能把手点废。当时写了个Python脚本,目录名遍历目录、内域匹配字符串、软件批量替换,批量前后不到三分钟搞定。替换这件事让我意识到,程序批量替换程序目录内的目录名域名,本质上是内域个体力活的自动化——但细节没处理好,照样翻车。软件
最直接的批量坑是编码。Windows下用记事本存过的替换文件,默认可能是GBK,而Linux服务器上跑的多半是UTF-8。你脚本里写个
open(file, 'r'),遇到混合编码的目录直接报UnicodeDecodeError。我的习惯是先用chardet探一遍,或者干脆用二进制模式读写,把域名当字节串替换。比如把b'old-domain.com'换成b'new-domain.com',绕开解码问题。代价是没法处理跨编码的变体,但实际场景里域名基本都是ASCII,够用了。另一个容易忽略的是文件类型过滤。程序目录里往往混着图片、压缩包、甚至数据库文件。你拿文本方式去读一个JPEG,轻则乱码,重则把二进制内容改坏。我一般只处理白名单后缀:
.php、.html、.js、.css、.json、.xml、.txt。有人图省事用os.walk全量遍历,结果把.git目录里的对象文件也改了,仓库直接报废。加个if '.git' in dirs: dirs.remove('.git'),能省掉事后恢复的麻烦。替换逻辑本身也有讲究。简单
str.replace会误伤——比如你要把api.old.com换成api.new.com,但目录里有个变量叫myapi.old.com_backup,一替换就变成myapi.new.com_backup,语义全变了。更稳妥的做法是用正则加单词边界:re.sub(r'\b' + re.escape(old) + r'\b', new, content)。但域名里的点号在正则里是通配符,必须转义。我见过有人直接写re.sub('old.com', 'new.com', text),结果把oldXcom也改了,哭笑不得。备份这事怎么强调都不为过。我现在的习惯是替换前先
shutil.copytree整个目录到_backup后缀的文件夹,或者至少把原文件重命名为.bak。有次帮人改WordPress主题,替换完发现某个序列化数据里的字符串长度变了,导致页面白屏。幸好备份还在,回滚后改用sed只替换特定行,才没耽误上线。序列化、base64编码、URL编码这些场景,纯文本替换基本都会出问题,得单独处理。性能方面,小目录无所谓,上万文件时
os.walk加逐行读写会慢得离谱。可以先用grep -rl或Python的mmap快速定位包含目标域名的文件,只处理命中的那部分。我试过在一个含三万文件的Node.js项目里全量扫描,机械硬盘上跑了将近两分钟;换成先grep再替换,降到八秒。如果经常干这事,写个带进度条和日志的脚本,比每次现敲命令靠谱。最后说个真实翻车案例。某次替换后网站能访问,但CSS里的字体图标全挂了。查了半天发现,原域名是
顶: 2踩: 43cdn.example.com,替换成了static.example.com,但CSS里有个@font-face的src写的是协议相对URL//cdn.example.com/font.woff。替换脚本把//后面的部分改了,却漏掉了前面的双斜杠,导致浏览器把static.example.com当成了相对路径。教训是:替换前先grep一遍所有变体,带协议的、不带协议的、带端口的、URL编码过的,列个清单再动手。域名这玩意,看着简单,藏得深的地方多着呢。






评论专区