如何用sed替换指定注释间内容并每日自动更新(FreeBSD环境)
问题:替换指定注释块间的动态内容
场景说明
我需要按需更新模板文件里CODE1或CODE2注释块之间的内容,同时保留这两个注释行,方便后续Cron每日执行脚本时重复更新。模板文件结构如下:
... some code ... // BEGIN CODE1 // END CODE1 ... some code ... // BEGIN CODE2 // END CODE2 ... some code ...
其中CODE1区域用于动态生成include文件路径,每次Cron运行时都会生成新的路径内容。
尝试过的脚本及报错
我写了如下脚本:
#!/bin/sh directory="/path/to/list/files" for file in "$directory"/*.txt do if [ -f "$file" ]; then content=$(sed -n '/\/\/ BEGIN CODE1/{:a;N;/\/\/ END CODE1/!ba;p}' "$file") sed -i '' '/\/\/ BEGIN/,/\/\/ END/{//!c\ INCLUDE /tmp/test.txt }' "/root/replace.txt" fi done
运行后出现报错:
sed: 1: "/\/\/ BEGIN/{:a;N;/\/\/ ...": unexpected EOF (pending }'s)
期望输出
CODE1区域更新后需变成:
... some code ... // BEGIN CODE1 $INCLUDE "/usr/local/etc/namedb/keys/domain.com/ksk.key" $INCLUDE "/usr/local/etc/namedb/keys/domain.com/zsk.key" // END CODE1 ... some code ... // BEGIN CODE2 // END CODE2 ... some code ...
实际业务场景
通过Cron每日检查$FolderKeys目录,更新/usr/local/etc/namedb/working/domain.com.db文件中// BEGIN DNSSEC CODE与// END DNSSEC CODE之间的内容,要求只替换块内内容、保留注释行,不修改文件其他部分。
动态生成内容的逻辑如下:
FolderKeys="/usr/local/namedb/keys" FolderSites="/usr/local/etc/namedb/working" declare -a Sites=( $(ls /$FolderSites | grep '.db$' | sed 's/.db$//') ) for Site in "${Sites[@]}" do ls -la $FolderJail$FolderKeys/$Site/*.key done
解决方案
1. 修复sed语法错误
你遇到的报错是FreeBSD sed的语法限制导致的:c命令后的换行格式有严格要求,而且模糊的匹配范围(/\/\/ BEGIN/,/\/\/ END/)容易误命中其他注释块。
2. 完整适配脚本
下面是适配FreeBSD环境的脚本,能精准替换指定块内容,同时自动生成动态INCLUDE行:
#!/bin/sh # 配置参数 FolderKeys="/usr/local/namedb/keys" FolderSites="/usr/local/etc/namedb/working" TargetFile="/usr/local/etc/namedb/working/domain.com.db" # 精准定位目标块的标记 StartMarker="// BEGIN DNSSEC CODE" EndMarker="// END DNSSEC CODE" # 若用到FolderJail请补充定义 # FolderJail="/path/to/jail" # 动态生成要插入的INCLUDE内容 generate_content() { for site_db in "$FolderSites"/*.db; do site=$(basename "$site_db" .db) # 遍历该站点下的所有key文件 for key_file in "$FolderJail$FolderKeys/$site"/*.key; do [ -f "$key_file" ] && echo "\$INCLUDE \"$key_file\"" done done } # 生成临时内容文件 TempContent=$(mktemp) generate_content > "$TempContent" # 执行sed替换:保留起始/结束标记,替换中间内容 sed -i.bak '' -e "/$StartMarker/{ p r $TempContent :a N /$EndMarker/!ba s/.*\n// }" "$TargetFile" # 清理临时文件 rm "$TempContent" # 可选:删除备份文件,不需要则注释此行 # rm "${TargetFile}.bak"
脚本关键逻辑
- 精准匹配:用
StartMarker和EndMarker定位目标块,避免误替换其他注释区域 - 动态生成:自动遍历站点和key文件,生成符合格式的
$INCLUDE行 - sed替换逻辑:
- 匹配到起始标记后先打印该行
- 插入临时文件里的动态内容
- 循环读取后续行直到匹配到结束标记,清空中间原有内容后打印结束标记
- 安全备份:
-i.bak会自动生成原文件的备份,防止误操作丢失数据
注意事项
- 确保Cron执行用户对目标文件、key目录有读写权限
- 测试时可去掉
-i.bak参数,直接将输出打印到终端,确认逻辑正确后再执行修改 - 若
FolderJail是必填参数,记得在脚本开头补充定义
内容的提问来源于stack exchange,提问作者Wisdom
相关产品推荐
相关产品推荐

