bash脚本内grep返回换行符、命令行直接执行却返回空的问题排查
基于正则的SQL Lint脚本执行异常说明
实际异常现象
- 目标:通过正则表达式完成SQL代码的lint校验,目前已写出可初步运行的实现逻辑,但执行表现和预期不一致
- 异常表现:将grep相关逻辑写入bash脚本执行时,grep输出会附带换行符;但在命令行直接执行完全相同的grep命令时,却返回空结果,怀疑脚本本身存在逻辑问题
当前使用的脚本实现
LINT='pcregrep -Mi' PATTERN="(^\s*SELECT(.*)(\n|\r\n|\r))((^(\s*--(.*))|^(\s*(.*),))(\n|\r\n|\r))*(^(\s*--(.*))(\n|\r\n|\r))*(^\s*FROM(.*))" files=$(git diff --name-only --diff-filter=ACM | grep "\.sql$") if [ "$files" = "" ]; then exit 0 fi pass=true echo -e "\nLinting SQL:\n" for file in ${files}; do result=$($LINT $PATTERN ${file} | grep "No syntax errors detected in ${file}") if [ "$result" != "" ]; then echo -e "\t\033[32mPassed: ${file}\033[0m" else echo -e "\t\033[31mFailed: ${file}\033[0m" echo $result | tr ' \n' '#$' echo "$($LINT $PATTERN ${file})" pass=false fi done
测试用的SQL样例
SELECT val1, val2, val3 FROM
脚本存在的核心问题
- 校验判断逻辑完全错位:当前代码用pcregrep的输出匹配固定字符串
No syntax errors detected in ${file}作为校验通过的判断依据,但pcregrep本身的输出逻辑是「匹配到符合规则的内容时直接打印匹配行」,不会主动生成“无语法错误”类的提示文本,等于这段grep逻辑永远匹配不到目标内容,校验分支完全走偏。 - 命令行与脚本执行结果不一致的根因:脚本中通过变量传递执行参数时,字符串会经过一次bash变量展开,最终传给pcregrep的正则字符串、文件路径参数,和在命令行直接手动敲写的命令参数存在细微差异(比如特殊字符转义、多空格拆分),才会出现命令行返回空、脚本输出带换行的表现差异。
- 空值判断逻辑不严谨:当前用
if [ "$files" = "" ]判断是否存在需要校验的SQL文件,实际files变量在多文件场景下是带换行的多行字符串,直接做全字符串等值比较的逻辑鲁棒性差,容易出现判断错误。 - 违规匹配的逻辑未对齐:当前写的PCRE正则的设计目标是匹配「SELECT后所有列项均以逗号结尾、直接衔接FROM子句」的违规场景,即匹配到内容就说明存在SQL语法问题,但脚本中并未直接利用pcregrep的退出码做判断,反而绕了不必要的grep步骤。
- 冗余残留代码:脚本中
echo $result | tr ' \n' '#$'这段逻辑,因为$result永远为空,实际执行没有任何有效输出,属于从其他校验脚本复制过来的无意义残留。
参考修正方向
- 直接利用pcregrep的退出码做结果判断:匹配到违规内容时pcregrep返回退出码0,未匹配到任何内容时返回退出码1,无需额外通过grep匹配固定文本判断结果
- 定义执行命令时优先使用数组格式,避免变量展开带来的参数错位问题
- 空值判断统一使用
[ -z "$变量名" ]的语法,适配多值场景下的判断需求
内容的提问来源于stack exchange,提问作者Reed Richards
相关产品推荐
相关产品推荐

