飞机Telegram算计机器人 用 | 代替 / 做分隔符——路径里全是 /,再用 / 当分隔符就得疯狂转义。
不用检索,sed 批处理是稳定知识。这道题正好是今天博客园同一天发的文章标题 [citation:26.9],我直接讲最常用的几种模式。
---
核心命令
sed -i 's|旧路径|新路径|g' *.sql
关键技巧:用 | 代替 / 做分隔符——路径里全是 /,再用 / 当分隔符就得疯狂转义。
---
四种最常见的场景
场景一:替换绝对路径前缀
把所有 C:\oldproject\data\ 开头的路径换成 D:\newproject\data\:
Mac/Linux 版
sed -i 's|/var/www/oldsite/|/var/www/newsite/|g' *.sql
Windows (Git Bash / WSL)
sed -i 's|C:\oldproject\|D:\newproject\|g' *.sql
场景二:只改 LOAD DATA / INFILE 行
如果只想动 LOAD DATA INFILE 和 SELECT ... INTO OUTFILE 这类文件导入导出语句里的路径,其他行不碰:
sed -i '/INFILE/s|/old/path/|/new/path/|g' *.sql
sed -i '/OUTFILE/s|/old/path/|/new/path/|g' *.sql
/INFILE/ 是行匹配——只处理包含 INFILE 的行。
场景三:替换 mysqldump 导出文件中的路径
mysqldump 导出的 SQL 里如果有 LOAD DATA LOCAL INFILE '路径',要批量换导数据文件的目录:
sed -i "s|LOAD DATA LOCAL INFILE '/backup/old/'|LOAD DATA LOCAL INFILE '/backup/new/'|g" dump.sql
场景四:批量处理子目录所有 SQL 文件
不只是当前目录,还要递归进子目录:
Linux / Mac
find . -name "*.sql" -exec sed -i 's|/old/path|/new/path|g' {} +
或者用 grep + xargs(更传统)
grep -rl '/old/path' --include="*.sql" . | xargs sed -i 's|/old/path|/new/path|g'
---
几个容易忘的参数
| 参数 | 作用 |
|------|------|
| -i | 原地修改(直接改原文件) |
| -i.bak | 原地修改并备份原文件为 .bak——第一次用强烈建议加这个 |
| -n | 不自动打印,配合 p 只输出匹配行 |
| g | 全局替换,不只是一行里第一次出现 |
安全模式:先备份再改
sed -i.bak 's|/old/path|/new/path|g' *.sql
改完后对比确认
diff -u .sql.bak .sql | head -50
---
Windows 环境怎么办
| 你有 | 方案 |
|-----|------|
| WSL / Git Bash | 直接用上面的 sed 命令 |
| PowerShell | 用 -replace 操作符(不走 sed) |
| 只有 cmd | 装一个 sed for Windows,或改用 PowerShell |
PowerShell 版:
Get-ChildItem -Filter *.sql | ForEach-Object {
(Get-Content $.FullName) -replace 'C:\oldproject\', 'D:\new_project\' |
Set-Content $_.FullName
}
---
先试跑再真改
任何时候拿不准正则对不对,先不加 -i 看输出:
sed 's|/old/path|/new/path|g' sample.sql | head -30
确认输出对了,再换成 -i 真改。和你 Qt 里重构代码先编译确认再 merge 是一个道理——预览确认永远比回滚省时间。