让我们从一个简单的脚本重写开始,让它在处理更广泛的替换值时更加健壮,而且速度更快:
#!/bin/bash
# escape regexp and replacement strings for sed
escapeRegex() { sed 's/[^^]/[&]/g; s/\^/\\^/g' <<<"$1"; }
escapeSubst() { sed 's/[&/\]/\\&/g' <<<"$1"; }
while read -r old new; do
find test -type f -exec sed "/$(escapeRegex "$old")/$(escapeSubst "$new")/g" -i '{}' \;
done <test.txt
因此,我们在test.txt 的行中循环遍历由空格分隔的字段对(old、new),并对使用find 找到的所有文件运行标准的sed 就地替换。
与您的脚本非常相似,但我们 properly read lines 来自 test.txt(没有分词、路径名/变量扩展等),我们尽可能使用 Bash 内置函数(无需调用像 cat 这样的外部工具, cut, xargs);我们将escape sed metacharacters 中的old/new 值正确用作sed 的正则表达式和替换表达式。
现在让我们添加logging from sed:
#!/bin/bash
# escape regexp and replacement strings for sed
escapeRegex() { sed 's/[^^]/[&]/g; s/\^/\\^/g' <<<"$1"; }
escapeSubst() { sed 's/[&/\]/\\&/g' <<<"$1"; }
while read -r old new; do
find test -type f -printf '\n[%p]\n' -exec sed "/$(escapeRegex "$old")/{
h
s//$(escapeSubst "$new")/g
H
x
s/\n/ --> /
w /dev/stdout
x
}" -i '{}' > >(tee -a change.log) \;
done <test.txt
上面的sed 脚本将每个old 更改为new,但它还将old --> new 行写入/dev/stdout(特定于Bash),我们依次将其附加到change.log 文件。 find 中的 -printf 操作为每个处理的文件输出一个带有文件名的“标题”行。
这样,您的“更改日志”将如下所示:
[file1]
hostname=abc.com --> hostname=xyz.com
[file2]
[file1]
db-host=abc.com --> db-host=xyz.com
[file2]
db-host=abc.com --> db-host=xyz.com
为了完整起见,快速浏览sed 脚本。我们只对包含old 值的行执行操作。对于每个这样的行,我们将其存储到保持空间(h),将其更改为new,将该新值附加到现在拥有old\nnew 的保持空间(与换行符连接,H)。我们将保持与模式空间 (x) 交换,因此我们可以运行 s 命令将其转换为 old --> new。在使用w 将其写入stdout 之后,我们将new 从保留移回模式空间,因此它被(就地)写入处理的文件。