Linux下Makefile中用tree输出替换围栏文本块的sed实现问题
在Makefile中用tree输出替换多行围栏文本块的解决方案
我之前也碰到过类似的需求,在Makefile里处理跨行文本替换确实有点麻烦——毕竟sed默认是单行模式,直接用它匹配带换行的围栏块很容易踩坑。下面给你两种实用的解决方案,分别对应替换整个围栏块和只替换中间占位符的场景:
场景1:替换整个围栏块(从[fencedtitle]到第二个----的全部内容)
如果你的目标是把整个围栏结构(包括标题、分隔线和占位符)直接换成tree的输出,用awk会比sed更直观,因为awk天然支持多行处理逻辑。
在Makefile里添加如下规则:
update-tree-output: # 先获取tree的输出,转义特殊字符避免冲突 TREE_CONTENT=$$(tree | sed 's/\$$/\\$$/g'); \ # 用awk处理文本替换 awk -v tree="$$TREE_CONTENT" ' \ /^\[fencedtitle\]$/ { \ print tree; # 输出tree的结果 skip_mode=1; # 开启跳过模式 next; \ } \ skip_mode && /----$$/ { \ skip_mode++; \ # 遇到第二个----时关闭跳过模式 if (skip_mode == 3) skip_mode=0; \ next; \ } \ !skip_mode # 非跳过模式下正常输出原内容 ' README.md > tmp_tree.md && mv tmp_tree.md README.md
逻辑说明:
- 用
$$(tree | sed 's/\$$/\\$$/g')获取tree的输出并转义$符号,避免和Makefile的变量语法冲突; awk通过skip_mode变量控制跳过围栏块的内容:匹配到[fencedtitle]时输出tree结果,然后跳过后续行直到遇到第二个----;- 最后把处理后的内容写入临时文件,再替换原文件(避免直接修改原文件导致意外)。
场景2:保留围栏结构,只替换中间的REPLACEMENT占位符
如果想保留[fencedtitle]和上下的----分隔线,只替换中间的REPLACEMENT文本,只需调整awk的逻辑:
update-tree-placeholder: TREE_CONTENT=$$(tree | sed 's/\$$/\\$$/g'); \ awk -v tree="$$TREE_CONTENT" ' \ /^\[fencedtitle\]$/ { \ print; # 保留原标题行 skip_mode=1; \ next; \ } \ skip_mode == 1 && /----$$/ { \ print; # 保留第一个分隔线 skip_mode=2; \ next; \ } \ skip_mode == 2 && /REPLACEMENT$$/ { \ print tree; # 替换占位符为tree输出 skip_mode=3; \ next; \ } \ skip_mode == 3 && /----$$/ { \ print; # 保留第二个分隔线 skip_mode=0; \ next; \ } \ !skip_mode || skip_mode !=2 # 非跳过模式或非占位符行正常输出 ' README.md > tmp_tree.md && mv tmp_tree.md README.md
可选:用sed实现的方案(需要处理多行匹配)
如果你坚持要用sed,可以利用它的循环读取多行功能,但需要注意转义换行和特殊字符:
update-tree-with-sed: # 把tree输出的换行转义成\n,方便sed识别 TREE_CONTENT=$$(tree | sed 's/[\/&]/\\&/g; s/$$/\\n/g' | tr -d '\n'); \ sed -i.bak '/^\[fencedtitle\]$/{:loop;N;/----$$/!bloop;s/.*----\n.*\n----/'"$$TREE_CONTENT"'/}' README.md
说明:
:loop;N;/----$$/!bloop是sed的多行循环:读取下一行,直到匹配到第二个----;s/.*----\n.*\n----/.../把整个围栏块替换成转义后的tree输出;-i.bak会生成原文件的备份(比如README.md.bak),如果不需要备份可以去掉.bak。
注意事项
- 如果你需要排除某些目录/文件,可以给
tree加参数,比如tree -I 'node_modules|.git'; - 处理包含特殊字符(如
/、&、$)的输出时,一定要先转义,避免替换命令出错; - 测试时可以先输出到临时文件,确认结果正确后再替换原文件,防止误改内容。
内容的提问来源于stack exchange,提问作者John Ericksen
相关产品推荐
相关产品推荐

