sed正则处理特殊字符输入的健壮性问题及Perl替代方案咨询
不用切换到Perl!让你的
comment函数更健壮的方法 当然不用转去Perl啦,我们可以通过调整sed的用法,让你的comment函数完美处理包含任意特殊字符的匹配字符串,比如/、*、.这些之前坑到你的符号。下面是具体的优化方案:
1. 更换sed的匹配分隔符,避免与/冲突
默认sed用/作为匹配模式的分隔符,所以当你的$1里包含/时(比如/dev/sysmsg),就会导致sed语法错误。解决这个问题很简单——换一个不常用的字符作为分隔符,比如@、#或者|。
修改后的函数可以这样写:
comment () { # 用@代替/作为sed匹配分隔符,注意前面加转义符\ sed -i "\@$1@s/^/$2 /g" "$3" }
这样即使$1里有/,也不会和分隔符冲突了。不过要注意,如果$1里刚好包含你选的分隔符(比如@),还是会出问题,所以更稳妥的方式是自动选择一个不在$1里的字符,不过对于大多数场景,选一个不常用的符号已经足够。
2. 转义正则特殊字符,让$1作为字面量匹配
你的第二个问题是*会被sed当作正则表达式处理,如果你希望$1是字面量字符串匹配(而不是正则规则),就需要把$1里的正则元字符(比如*、.、^、$、[、&等)转义掉。
我们可以先写一个辅助函数来处理转义:
# 转义sed正则中的特殊字符 escape_sed_pattern() { printf '%s\n' "$1" | sed 's/[\/&*.^$[]/\\&/g' }
然后修改comment函数,先转义匹配字符串再传给sed:
comment () { local escaped_pattern=$(escape_sed_pattern "$1") # 依然用@作为分隔符,同时使用转义后的字面量模式 sed -i "\@$escaped_pattern@s/^/$2 /g" "$3" }
现在执行comment '*.err' '#' /tmp/1时,*.err会被转义成\*\.\err,sed就会准确匹配文件中的*.err字面字符串,而不是把*当作正则的“任意字符”解析。
3. 额外的健壮性优化
- 给所有变量加上双引号(比如
"$3"),防止文件名或参数中包含空格时出错; - 用
local声明函数内的变量,避免污染全局变量;
测试一下
现在用你的测试内容*.err;kern.notice;auth.notice /dev/sysmsg fff ff来测试:
- 执行
comment /dev/sysmsg '#' /tmp/1:会找到包含/dev/sysmsg的行,在行首加上#; - 执行
comment '*.err' '#' /tmp/1:会找到包含*.err的行,在行首加上#;
两个命令都能正常工作啦!
内容的提问来源于stack exchange,提问作者Sandra Schlichting
相关产品推荐
相关产品推荐

