比较传统的应用迁移(我司大量部署在tomcat上的程序),因为需要大面积修改或替换配置文件,手工一个个改不仅费时费力还难免出错,所以用go写了个小工具,打包成linux环境的可执行文件,用ansible分发执行即可。
测试执行效果
代码及配置
配置文件:text_replace.yaml
# 修改前的文件备份目录
backup_info:
backup_path: ./bak/
# 需要替换的文件,生产环境下写绝对路径比较好
file_infos:
- file: ./initTopics.sh
- file: ./test1.txt
- file: ./test2.txt
- file: ./test3.txt
# 需要替换的内容
replace_text_infos:
- {old_text: 123, new_text: 一二三}
- {old_text: 10.244.224.70, new_text: 10.22.161.209}
golang代码:text_replace.go
package main
import (
"crypto/sha256"
"fmt"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
"io"
"io/fs"
"os"
"strings"
"unsafe"
)
// ReplaceInfo 配置文件结构体
type ReplaceInfo struct {
BackupInfo BackupInfo `yaml:"backup_info"`
FileInfos FileInfos `yaml:"file_infos"`
ReplaceTextInfos ReplaceTextInfos `yaml:"replace_text_infos"`
}
type BackupInfo struct {
BackupPath string `yaml:"backup_path"`
}
type FileInfos []struct {
File string `yaml:"file"`
}
type ReplaceTextInfos []struct {
OldText string `yaml:"old_text"`
NewText string `yaml:"new_text"`
}
func main() {
// 读取配置文件
replaceInfo := ReadYaml("./text_replace.yaml")
backupInfo, fileInfos, replaceTextInfos := replaceInfo.BackupInfo, replaceInfo.FileInfos, replaceInfo.ReplaceTextInfos
// 创建备份目录
err := os.MkdirAll(backupInfo.BackupPath, fs.ModePerm)
if err != nil {
log.Infof(err.Error())
}
// 遍历配置中每一个需要替换的文件
for _, fileInfo := range fileInfos {
// 读取要修改的文本文件
content, isExist := ReadText(fileInfo.File)
originalText, modifiedText := contesnt, content
if isExist == false {
log.Infof("文件不存在或为非文本文件,跳过 %v ", fileInfo.File)
continue
}
// 替换文本
for _, replaceTextInfo := range replaceTextInfos {
modifiedText = strings.ReplaceAll(modifiedText, replaceTextInfo.OldText, replaceTextInfo.NewText)
}
// 对比文本修改前后是否一致,一致则跳过本次循环
if originalText==modifiedText {
log.Infof("文件中没有需要修改的文本 %v ", fileInfo.File)
continue
}
// 备份
fileBakup := fmt.Sprintf("%s%s", backupInfo.BackupPath, fileInfo.File)
err := WriteText(fileBakup, originalText)
if err != nil {
log.Errorf(err.Error())
}
// 替换好的覆盖原文件
WriteText(fileInfo.File, modifiedText)
log.Infof("文件已替换完成 %v ,原文件备份至 %s ", fileInfo.File, fileBakup)
}
}
// ReadYaml 读取配置文件
func ReadYaml(yamlInfo string) ReplaceInfo {
dataBytes, err := os.ReadFile(yamlInfo)
if err != nil {
log.Fatalln("读取文件失败:", err)
}
config := ReplaceInfo{}
err = yaml.Unmarshal(dataBytes, &config)
if err != nil {
log.Fatalln("解析 yaml 文件失败:", err)
}
return config
}
// ReadText 读取要修改的文本文件
func ReadText(path string) (text string, isExist bool) {
file, err := os.Open(path)
if err != nil {
log.Infoln(err)
isExist = false
return
}
defer file.Close()
data, err := io.ReadAll(file)
if err != nil {
log.Infoln(err)
isExist = false
return
}
return *(*string)(unsafe.Pointer(&data)), true
}
// WriteText 写入文本文件
func WriteText(src, content string) error {
data := []byte(content)
return os.WriteFile(src, data, os.ModePerm)
}