在bash的case语句中使用正则表达式会抛出“unexpected token”错误。
在bash的case语句中使用正则表达式会抛出“unexpected token”错误。
编辑:我已经将我的代码推送到一个新的分支,专门为了这个问题。
链接到分支
链接到shell脚本
我试图创建一个bash文件,循环遍历预定义结构的所有目录(和子目录)(即,我确定目录的命名方式是特定的)。
一个明显的解决方案是使用正则表达式模式的case...esac
语句。所以我去StackOverflow上找到了这个帖子,解释了如何做到我需要的事情,所以我准备创建一个测试代码,下面是我想到的:
test | |__ python | |__ python- | |__ python-a | |__ python-0 | |__ python0- | |__ python2 | |__ pythona | |__ test.sh
并运行以下代码:
# test.sh #!/bin/bash shopt -s extglob; for dir in $(ls); do case $dir in python*(-)*([a-zA-Z0-9])) echo "yes -> $dir" ;; *) echo "no -> $dir" ;; esac done shopt -u extglob;
这给了我以下输出:
yes -> python yes -> python- yes -> python-a no -> python0- yes -> python2 yes -> pythona no -> test.sh
看起来工作得很好。
我将这种方法应用到了我的实际代码中:
# actual_code.sh cd $PROGRAMS_DIR for language in $(ls -l --group-directories-first | tail -n $(ls -l | awk '{print $1}' | grep d | wc -l) | awk '{print $9}'); do cd $language echo "language -> $language" for algorithm in $(ls -l --group-directories-first | tail -n $(ls -l | awk '{print $1}' | grep d | wc -l) | awk '{print $9}'); do cd $algorithm echo "algo -> $algorithm" shopt -s extglob; case $language in rust*(-)*([0-9])) rustc "${algorithm}_run.rs" -o "${algorithm}_run" COMMAND="./${algorithm}_run" if [ $TEST -eq 1 ]; then echo "> Running Rust tests for $algorithm" rustc --test "${algorithm}_test.rs" -o "${algorithm}_test" ./${algorithm}_test if [ $(echo $?) -ne 0 ]; then exit 1 fi fi ;; go*(-)*([0-9])) go build -o "${algorithm}_run" . COMMAND="./${algorithm}_run" if [ $TEST -eq 1 ]; then echo "> Running Go tests for $algorithm" go test if [ $(echo $?) -ne 0 ]; then exit 1 fi fi ;; java*(-)*([0-9])) javac -cp .:$JUNIT:$HAMCREST *.java COMMAND="java -cp .:${JUNIT}:${HAMCREST} ${algorithm}_run" if [ $TEST -eq 1 ]; then echo "> Running Java tests for $algorithm" java -cp .:${JUNIT}:${HAMCREST} ${algorithm}_test if [ $(echo $?) -ne 0 ]; then exit 1 fi fi ;; c*(-)*([0-9])) # TODO: 尝试实现普通可执行文件和-O2优化 gcc -Wall -c "${algorithm}.c" "${algorithm}_run.c" gcc -o "${algorithm}_run" "${algorithm}.o" "${algorithm}_run.o" COMMAND="./${algorithm}_run" if [ $TEST -eq 1 ]; then echo "> Running C tests for $algorithm" gcc -Wall -c "${algorithm}.c" "${algorithm}_test.c" $UNITY gcc -o "${algorithm}_test" "${algorithm}.o" "${algorithm}_test.o" "unity.o" ./${algorithm}_test if [ $(echo $?) -ne 0 ]; then exit 1 fi fi ;; python*(-)*([0-9])) COMMAND="python ${algorithm}_run.py" if [ $TEST -eq 1 ]; then echo "> Running Python tests for $algorithm" pytest . if [ $(echo $?) -ne 0 ]; then exit 1 fi fi ;; haxe*(-)*([0-9])) COMMAND="haxe --main ${algorithm^}_Run.hx --interp" if [ $TEST -eq 1 ]; then echo "> Running Haxe tests for $algorithm" haxe --main "${algorithm^}_Test.hx" --library utest --interp -D UTEST_PRINT_TESTS if [ $(echo $?) -ne 0 ]; then exit 1 fi fi ;; *) echo "($language)没有编译步骤。您是否忘记更新基准测试脚本?" ;; esac shopt -u extglob; . . . 其他一些随机代码 . . . done done
现在执行这段代码给了我以下结果:
./actual_code.sh: line 408: syntax error near unexpected token `(' ./actual_code.sh: line 408: ` rust*(-)*([0-9]))'
显然我漏掉了某些东西,但在我看来它们看起来是一样的。另外,echo
部分不起作用。它直接进入错误,这很奇怪,因为这是一种解释性语言。
在这个问题中,出现了"unexpected token"错误。错误的原因是在bash的case语句中使用了正则表达式。解决方法是使用条件正则表达式匹配来替代case语句。
首先,感谢所有对解决方案提出建议、指导我方向并为这个项目做出贡献的人。
尽管shellcheck是一个很好的资源,并指出了我的脚本中的许多(可能的)缺陷,但它要求的一些修复措施并不是真正的修复,而是对不必要的传统做法的警告,这些做法对实际功能并不必要。我选择遵循其中一些,但并不是全部,因为其中一些给出了意外的结果。正如在原始的问题线程中提到的那样,这表明存在一些未知的潜在问题,因此在我的存储库中推送了一个新的分支,其中基准测试脚本将以一种通过shellcheck的方式重新编写。
感谢提出使用Makefile的建议,这是我的最初决定,但由于经验不足,我无法在剩余的时间内完成这个任务(这仍然是我最后一年的论文)。
目前采用的解决方法是应用条件正则表达式匹配,如下所示:
# 去掉开头的'./' language=${language:2:${#language}} # 匹配'-haxe'后缀或任何其他模式的语言 if [[ $language =~ [a-zA-Z]*-[a-zA-Z0-9]* ]]; then readarray -d "-" -t LANGUAGE <<< $language lang="${LANGUAGE[0]}" else lang=$language fi
这是目前最优雅的解决方案,目前工作正常,没有增加任何显著的复杂性。