在bash的case语句中使用正则表达式会抛出“unexpected token”错误。

14 浏览
0 Comments

在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部分不起作用。它直接进入错误,这很奇怪,因为这是一种解释性语言。

0
0 Comments

在这个问题中,出现了"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

这是目前最优雅的解决方案,目前工作正常,没有增加任何显著的复杂性。

0