使用简单的Bash if / elif / else语句时遇到问题

时间:2015-03-10 05:04:42

标签: linux macos bash conditional-statements

我正在编写需要在Linux和Mac上运行的bash脚本。

我正在编写一个函数,根据我所处的环境返回目录路径。

这是伪代码:

如果我在Mac OS X机器上,我需要我的功能来返回路径:

/usr/local/share/

否则如果我在Linux机器上,我需要我的函数来返回路径:

/home/share/

否则,你既不在Linux上也不在Mac上......抱歉。

我对Bash很新,所以我提前为这个非常简单的问题道歉。

以下是我写的功能。无论我是在Mac还是Linux上,它总会返回

/usr/local/share/

请看看Bash的微妙之处,启发我。

function get_path(){
    os_type=`uname`
    if  [ $os_type=="Darwin" ]; then
            path="/usr/local/share/"
    elif [ $os_type=="Linux" ]; then
            path="/home/share/"
    else
            echo "${os_type} is not supported"
            exit 1
    fi 
    echo $path

}

3 个答案:

答案 0 :(得分:2)

在测试命令中需要操作符周围的空格:[ $os_type == "Darwin" ]而不是[ $os_type=="Darwin" ]。实际上,您还应该使用=而不是==(双重等于是一种基础,并且不会在所有shell中起作用)。此外,function关键字也是非标准关键字,您应该将其关闭。此外,您应该引用变量引用(如"$os_type"),以防它们包含空格或任何其他有趣的字符。最后,向标准输出回显错误消息(" ...不支持")可能会混淆调用该函数的任何内容,因为它会出现在预期找到路径的位置;将其重定向到标准错误(>&2)。以下是我清理过的内容:

get_path(){
    os_type=`uname`
    if  [ "$os_type" = "Darwin" ]; then
        path="/usr/local/share/"
    elif [ "$os_type" = "Linux" ]; then
        path="/home/share/"
    else
        echo "${os_type} is not supported" >&2
        exit 1
    fi 
    echo "$path"
}

编辑:我对作业和比较之间差异的解释对于评论来说太长了,所以我在这里添加它。在许多语言中,标准表达式语法在独立使用时与测试中相同。例如,在C a = b中,无论是单独行还是像if ( a = b )这样的上下文,都会做同样的事情。 shell不是那样的 - 它的语法和语义根据确切的上下文而变化很大,它是确定含义的上下文(不是等号的数量)。以下是一些例子:

  • a=b本身就是一项作业
  • a = b本身将a作为命令运行,并将参数传递给#34; ="和" b"。
  • [ a = b ]使用参数" a"," =&#34运行[命令(这是test命令的同义词) ;," b"和"]" - 它忽略"]",并将其他人解析为比较表达式。
  • [ a=b ]也会运行[test)命令,但这次删除"]"它只能看到一个参数," a = b" - 当test给出一个参数时,如果参数不是空白,则返回true,这个参数不是。

bash的内置版[test)接受==作为=的同义词,但并非所有其他版本都这样做。

顺便说一句,只是为了让事情变得更复杂bash还有[[ ]]个表达式(如test,但更清晰,更强大)和(( ))表达式(与其他所有内容完全不同) ,甚至( )(将其内容作为命令运行,但在子shell中)。

答案 1 :(得分:1)

您需要了解[的含义。最初,这是/bin/test命令的同义词。这些是相同的:

if test -z "$foo"
then
    echo "String '$foo' is null."
fi

if [ -z "$foo" ]
then
    echo "String '$foo' is null."
fi

现在,您可以看到为什么所有参数都需要空格。这些是参数而不仅仅是布尔表达式。实际上,test联机帮助页是了解各种测试的好地方。 (注意:test[是在BASH shell的命令中构建的。)

if  [ $os_type=="Darwin" ]
then

这应该是三个参数:

  • "$os_type"
  • =而非==
  • "Darwin"

    if [“$ os_type”=“Darwin”]#[命令的三个参数 然后

如果使用单方括号,则应习惯用引号括住参数。否则,你会遇到麻烦:

foo="The value of FOO"
bar="The value of BAR"
if [ $foo != $bar ]    #This won't work
then
    ...

在上面,shell会在评估表达式之前插入$foo$bar及其值。你会得到:

if [ The value of FOO != The value of BAR ]

[会看到这一点并意识到Thevalue都不是正确的参数,并会抱怨。使用引号可以防止这种情况:

if [ "$foo" != "$bar" ]    #This will work
then

这变为:

if [ "The value of FOO" != "The value of BAR" ]

这就是为什么强烈建议您为测试使用双方括号:[[ ... ]]。测试在shell插入之前查看参数:

if [[ $foo = $bar ]]   #This will work even without quotation marks

此外,[[ ... ]]允许模式匹配:

if   [[ $os_type = D* ]]       # Single equals is supported
then
    path="/usr/local/share/"
elif [[ $os_type == L* ]]      # Double equals is also supported
then
    path="/home/share/"
else
    echo "${os_type} is not supported"
    exit 1
fi 

这样,如果字符串为Darwin32Darwin64,则if语句仍然有效。再次注意,所有东西都必须有空格,因为这些是命令的参数(实际上,不再是,但这就是shell解析它们的方式)。

答案 2 :(得分:0)

在条件的参数之间添加空格来解决问题。

这有效

function get_path(){
os_type=`uname`
if  [ $os_type == "Darwin" ]; then
        path="/usr/local/share/"
elif [ $os_type == "Linux" ]; then
        path="/home/share/"
else
        echo "${os_type} is not supported"
        exit 1
fi 
echo $path

}