Perl正则表达式在cron任务中执行异常的问题排查
解决cron中Perl正则删除整行失效的问题
问题场景
原始配置文件内容如下:
[grundbild] geo40=AdnQywADAAAAAAAAAAAAAAAAAt8AAAIVAAAAAAAAAAAAAALfAAACFQAAAAAAAAAAB4AAAAAAAAAAAAAAAt8AAAIV [MainWindow] geo40=AdnQywADAAAAAAAXAAAAEQAABrwAAAPwAAAAGAAAADAAAAa7AAAD7wAAAAAAAAAAB4AAAAAYAAAAMAAABrsAAAPv dockPos40=AAAA/wAAAAD9AAAAAQAAAAAAAACyAAADcfwCAAAAA/sAAAAOAGsAZQB5AGwAYQBiAHMBAAAAOQAAAW4AAAAtAP////sAAAASAHMAdABhAHIAdABtAGUAbgB1AQAAAa0AAAFtAAAAWQD////7AAAAEgBoAGUAbABwAF8AZABvAGMAawEAAAMgAAAAigAAAIoA////AAAF7AAAA3EAAAAEAAAABAAAAAgAAAAI/AAAAAEAAAACAAAABAAAABIAcwBoAG8AcgB0AGMAdQB0AHMBAAAAAP////8AAAAAAAAAAAAAABYAbQBpAG4AaQBkAGUAcwBrAHQAbwBwAQAAADH/////AAAAAAAAAAAAAAASAGgAZQBsAHAAZgB1AG4AYwBzAQAAAKT/////AAAAAAAAAAAAAAAGAG8AYgBpAQAAAR7/////AAAAAAAAAAA=
需要删除所有以geo40=开头的行,在命令行执行以下命令时完全正常:
find /conf/ -type f -name "geometry.*.pas" -exec perl -pi -e 's/^geo40=.*$\n//' {} ';'
处理后文件内容符合预期:
[grundbild] [MainWindow] dockPos40=AAAA/wAAAAD9AAAAAQAAAAAAAACyAAADcfwCAAAAA/sAAAAOAGsAZQB5AGwAYQBiAHMBAAAAOQAAAW4AAAAtAP////sAAAASAHMAdABhAHIAdABtAGUAbgB1AQAAAa0AAAFtAAAAWQD////7AAAAEgBoAGUAbABwAF8AZABvAGMAawEAAAMgAAAAigAAAIoA////AAAF7AAAA3EAAAAEAAAABAAAAAgAAAAI/AAAAAEAAAACAAAABAAAABIAcwBoAG8AcgB0AGMAdQB0AHMBAAAAAP////8AAAAAAAAAAAAAABYAbQBpAG4AaQBkAGUAcwBrAHQAbwBwAQAAADH/////AAAAAAAAAAAAAAASAGgAZQBsAHAAZgB1AG4AYwBzAQAAAKT/////AAAAAAAAAAAAAAAGAG8AYgBpAQAAAR7/////AAAAAAAAAAA=
但将命令加入cron定时任务后:
0 5 * * * find /conf/ -type f -name "geometry.*.pas" -exec perl -pi.cronbak -e 's/^geo40=.*$\n//' {} ';'
处理结果异常:仅删除了geo40=前缀,该行剩余内容被保留,如下:
[grundbild] QywADAAAAAAAAAAAAAAAAAt8AAAIVAAAAAAAAAAAAAALfAAACFQAAAAAAAAAAB4AAAAAAAAAAAAAAAt8AAAIV [MainWindow] QywADAAAAAAAXAAAAEQAABrwAAAPwAAAAGAAAADAAAAa7AAAD7wAAAAAAAAAAB4AAAAAYAAAAMAAABrsAAAPv dockPos40=AAAA/wAAAAD9AAAAAQAAAAAAAACyAAADcfwCAAAAA/sAAAAOAGsAZQB5AGwAYQBiAHMBAAAAOQAAAW4AAAAtAP////sAAAASAHMAdABhAHIAdABtAGUAbgB1AQAAAa0AAAFtAAAAWQD////7AAAAEgBoAGUAbABwAF8AZABvAGMAawEAAAMgAAAAigAAAIoA////AAAF7AAAA3EAAAAEAAAABAAAAAgAAAAI/AAAAAEAAAACAAAABAAAABIAcwBoAG8AcgB0AGMAdQB0AHMBAAAAAP////8AAAAAAAAAAAAAABYAbQBpAG4AaQBkAGUAcwBrAHQAbwBwAQAAADH/////AAAAAAAAAAAAAAASAGgAZQBsAHAAZgB1AG4AYwBzAQAAAKT/////AAAAAAAAAAAAAAAGAG8AYgBpAQAAAR7/////AAAAAAAAAAA=
问题原因
- Perl的
-p模式会自动读取每行并去掉末尾的换行符,因此正则中的$\n无法匹配到换行符,原本的替换逻辑存在缺陷,命令行中可能因shell的换行处理巧合生效,但cron的非交互式shell环境下暴露了问题。 - 部分系统的cron对正则中的特殊字符解析行为与交互式shell不同,导致
.*$未能正确匹配行尾内容。
解决方案
改用更可靠的整行删除逻辑,直接跳过或不打印匹配的行,替换后的cron命令如下:
0 5 * * * find /conf/ -type f -name "geometry.*.pas" -exec perl -pi.cronbak -e 'next if /^geo40=/' {} ';'
或者使用-n模式配合打印逻辑:
0 5 * * * find /conf/ -type f -name "geometry.*.pas" -exec perl -ni.cronbak -e 'print unless /^geo40=/' {} ';'
这两种写法直接针对匹配行进行处理,无需依赖换行符的正则匹配,在命令行和cron环境下均能稳定生效。
内容的提问来源于stack exchange,提问作者Andy A.
相关产品推荐
相关产品推荐

