同版本Bash脚本在Fedora正常Manjaro报语法错误原因排查
Bash case 分支语法跨发行版报错问题
问题场景
通过source加载自定义构建脚本时,相同版本号的Bash在Fedora 36上可正常运行,在Manjaro上抛出语法错误,zsh在两台设备上均运行正常。
使用的脚本代码如下:
function buildprog () { local builddir="/home/$USER/prog/build" echo "$builddir" # max threads - 2 local np=6 local old_wd=$(pwd) local rel="Release" local deb="Debug" case $1 in "all"); buildprog $rel & buildprog $deb;; "$rel") cd "${builddir}/$rel"; make -j $np;; "$deb") cd "${builddir}/$rel"; make -j $np;; *) echo "Build option '$1' unknown.";;; esac cd $old_wd } complete -W "all Debug Release" buildprog
Manjaro 端报错信息:
bash: ./testscript.sh: line 12: syntax error near unexpected token `;' bash: ./testscript.sh: line 12: ` "all");'
两台设备Bash版本均显示为5.1.16(1)-release,仅平台标识分别为(x86_64-redhat-linux-gnu)(Fedora)和(x86_64-pc-linux-gnu)(Manjaro)。
根本原因
两台设备的Bash行为差异和架构标识无关,核心原因是 Fedora 发行版给Bash打了非上游的自定义兼容补丁:
- 上游原生Bash的case语法明确要求:模式匹配段的闭括号
)后,不能直接跟冗余分号再接命令,分支终止符;;前也不允许多余的分号,否则会判定为语法错误。Manjaro源里的Bash是直接基于上游源码编译的,没有携带这类兼容补丁,所以会抛出语法错误。 - Fedora 为了兼容更多不规范的Shell写法,给Bash打了额外的容错补丁,会自动忽略case分支里这类冗余的分号,所以脚本能正常运行。
- zsh 原生语法容错性更高,默认就允许这类冗余分号写法,因此两个发行版的zsh都不会报错。
另外脚本里还存在两个隐藏问题:
Debug分支的cd路径写错了,仍然指向Release目录,会导致Debug版本实际用了Release目录的构建配置- 所有分支的cd操作没有做错误判断,如果目录不存在会直接在错误路径执行make,引发构建问题
修复方案
删除case块里所有冗余分号,修正笔误,增加路径跳转容错,改成符合POSIX和上游Bash标准的写法即可,修改后的case段参考:
case $1 in "all") buildprog "$rel" & buildprog "$deb" ;; "$rel") cd "${builddir}/$rel" || { echo "Enter $rel build dir failed"; return 1; } make -j "$np" ;; "$deb") cd "${builddir}/$deb" || { echo "Enter $deb build dir failed"; return 1; } make -j "$np" ;; *) echo "Build option '$1' unknown." ;; esac
修改后的脚本可以在所有发行版的原生Bash、zsh环境下正常运行,不会出现语法错误。
内容的提问来源于stack exchange,提问作者RL-S
相关产品推荐
相关产品推荐

