在 Windows 版 Ubuntu 中,shell 脚本中的 If/Else 会引发错误

在 Windows 版 Ubuntu 中,shell 脚本中的 If/Else 会引发错误

以下是一个简单的 shell 脚本示例:

#!/usr/bin/env bash
if [ 1 == 1 ]; then
echo "Something"
fi

当我运行这个

sh ./test.sh

我得到:

./test.sh: 4: ./test.sh: Syntax error: "fi" unexpected (expecting "then")

它似乎无法识别我在其中的“then”。有什么线索可以解释原因吗?如果这部分很重要,这是适用于 Windows 的 Ubuntu。

运行 shell 脚本通常不是问题,只是 if/else 有点问题。

答案1

这里有两个问题。首先,虽然你有一个舍邦线调用 bash,您将以 的身份执行脚本sh script.sh。shebang 行已经为该脚本指定了解释器。因此,只需使脚本可执行即可:

chmod a+x ./test.sh

然后运行它:

./test.sh

或者,使用 bash 明确运行它:

bash ./test.sh

这将使它使用bash而不是 来运行sh,这是一个功能更有限的 shell,并且不理解==。这给我们带来了第二个问题以及为什么会失败。奇怪的是,你想要eq=,而不是==。在 POSIX shell 脚本中测试数字相等性的运算符(sh是符合 POSIX 的 shell)是,-eq而测试的运算符是细绳平等既是事物=,又==不是事物。

因此,如果您希望脚本由 运行sh,请将其更改为:

if [ 1 = 1 ]; then
    echo "Something"
fi

这检查细绳 1细绳 1,或者进行数值比较,使用:

if [ 1 -eq 1 ]; then
    echo "Something"
fi

此外,您还有另一个问题。如果我在 后面dash添加 ,我只能重现您遇到的特定错误。这是在 Windows 和 Linux 之间移动时的一个经典问题。虽然 Linux 使用作为行结束符,但 Windows 使用 来结束行。此字符对用户不可见,但它存在并混淆脚本。因此,您可以使用以下命令将其删除:\rthen\n\r\n\r

sed -i 's/\r//' ./test.sh

以后,请使用合适的文本编辑器来编写脚本。要么是可以在 WSL 系统中运行的编辑器,要么是至少可以配置为不添加\r到行尾的编辑器。

答案2

让我们简单一点:

  • sh不在bashUbuntu 上(请参阅以供参考)。

  • [是命令,与test命令相同。它不支持==算术比较。改用-eq。这是由指定的实用程序之一POSIX 标准bash,因此在和中都有效dash

    if [ 1 -eq 1 ];
    then
        echo "it works!"
    fi
    
  • bash((,称为算术扩展。这支持==。此功能显然是从kshshell 借用的。

    $ var=25 bash -c 'if((var==5)); then echo Y;else echo "N";fi'      
    N
    $ var=25 bash -c 'if((var==25)); then echo Y;else echo "N";fi' 
    Y
    
  • 尽管dash不支持if (()),但在任何一个 shell 中$((都可以工作,因为它是由POSIX 标准仅考虑两种 shell 共有的特征,我们可以做这样的事情,同时仍然用于==比较:

    
    $ var=25 dash -c 'if [ $((var==25)) -eq 1 ];then echo Y; else echo N;fi'
    Y
    $ var=25 dash -c 'if [ $((var==5)) -eq 1 ];then echo Y; else echo N;fi' 
    N
    

  • 我们可以完全抛弃if语句并使用case(注意,返回状态符合 C,而不是 shell 行为,即 true 为 1,false 为 0,而不是像 shell 中那样反过来):

    $ dash -c 'case $((1==1)) in 1) echo "equal";; 0) echo "not equal";;esac'                                                                                                
    equal
    $ dash -c 'case $((1==2)) in 1) echo "equal";; 0) echo "not equal";;esac'                                                                                                
    not equal
    
  • 或者我们可以巧妙地使用算术扩展:

    $ var=25 dash -c '_0(){ false;}; _1(){ true;}; if "_$((var==25))" ; then echo Y; else echo N; fi'
    

相关内容