简体   繁体   English

使用简单的Bash if / elif / else语句遇到麻烦

[英]Having trouble with simple Bash if/elif/else statement

I'm writing bash scripts that need to work both on Linux and on Mac. 我正在编写需要在Linux和Mac上都可以使用的bash脚本。

I'm writing a function that will return a directory path depending on which environment I'm in. 我正在编写一个函数,该函数将根据所处的环境返回目录路径。

Here is the pseudo code: 这是伪代码:

If I'm on a Mac OS X machine, I need my function to return the path: 如果我在Mac OS X机器上,则需要我的函数来返回路径:

/usr/local/share/

Else if I'm on a Linux machine, I need my function to return the path: 否则,如果我在Linux机器上,则需要我的函数来返回路径:

/home/share/

Else, you are neither on a Linux or a Mac...sorry. 否则,您既没有使用Linux也没有使用Mac ...对不起。

I'm very new to Bash, so I apologize in advance for the really simple question. 我是Bash的新手,所以我为这个非常简单的问题向您道歉。

Below is the function I have written. 下面是我编写的函数。 Whether I'm on a Mac or Linux, it always returns 无论是在Mac还是Linux上,它总是会返回

/usr/local/share/

Please take a look and enlighten me with the subtleties of Bash. 请看一下,并以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

} }

You need spaces around the operator in a test command: [ $os_type == "Darwin" ] instead of [ $os_type=="Darwin" ] . 在测试命令中,操作符周围需要空格: [ $os_type == "Darwin" ]而不是[ $os_type=="Darwin" ] Actually, you should also use = instead of == (the double-equal is a bashism, and will not work in all shells). 实际上,您还应该使用=而不是== (双等号是bashism,并且不适用于所有shell)。 Also, the function keyword is also nonstandard, you should leave it off. 另外, function关键字也是非标准的,您应该将其保留。 Also, you should double-quote variable references (like "$os_type" ) just in case they contain spaces or any other funny characters. 同样,您应该对变量引用(例如"$os_type" )加双引号,以防它们包含空格或任何其他有趣的字符。 Finally, echoing an error message ("...not supported") to standard output may confuse whatever's calling the function, because it'll appear where it expected to find a path; 最后,在标准输出中回显错误消息(“ ...不支持”)可能会使正在调用该函数的用户感到困惑,因为它会出现在期望找到路径的位置。 redirect it to standard error ( >&2 ) instead. 将其重定向到标准错误( >&2 )。 Here's what I get with these cleaned up: 这是我清理后得到的结果:

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"
}

EDIT: My explanation of the difference between assignments and comparisons got too long for a comment, so I'm adding it here. 编辑:我对赋值和比较之间的区别的解释太长了,无法发表评论,因此我在此处添加了它。 In many languages, there's a standard expression syntax that'll be the same when it's used independently vs. in test. 在许多语言中,有一种标准的表达式语法,当单独使用它与在测试中使用时,它将是相同的。 For example, in C a = b does the same thing whether it's alone on a line, or in a context like if ( a = b ) . 例如,在C中,无论a = b是单独出现在一行上还是在if ( a = b )这样的上下文中, a = b都可以执行相同的操作。 The shell isn't like that -- its syntax and semantics vary wildly depending on the exact context, and it's the context (not the number of equal signs) that determines the meaning. 外壳不是那样的-它的语法和语义根据确切的上下文而千差万别,而上下文(而不是等号的数量)决定了含义。 Here are some examples: 这里有些例子:

  • a=b by itself is an assignment a=b本身就是一个赋值
  • a = b by itself will run a as a command, and pass it the arguments "=" and "b". a = b本身将作为命令运行a ,并向其传递参数“ =”和“ b”。
  • [ a = b ] runs the [ command (which is a synonym for the test command) with the arguments "a", "=", "b", and "]" -- it ignores the "]", and parses the others as a comparison expression. [ a = b ]使用参数“ a”,“ =“,“ b”和“]”运行[命令(这是test命令的同义词)–它忽略“]”,并解析其他作为比较表达式。
  • [ a=b ] also runs the [ ( test ) command, but this time after removing the "]" it only sees a single argument, "a=b" -- and when test is given a single argument it returns true if the argument isn't blank, which this one isn't. [ a=b ]也运行[test )命令,但是这一次在删除“]”之后,它只会看到一个参数“ a = b”-当给test一个参数时,如果参数不是空白,而这个不是。

bash's builtin version of [ ( test ) accepts == as a synonym for = , but not all other versions do. bash的内置版本[test )接受==作为=的同义词,但并非所有其他版本都支持。

BTW, just to make things more complicated bash also has [[ ]] expressions (like test , but cleaner and more powerful) and (( )) expressions (which are totally different from everything else), and even ( ) (which runs its contents as a command, but in a subshell). 顺便说一句,只是为了使事情变得更复杂,bash还具有[[ ]]表达式(如test ,但更简洁,功能更强大)和(( ))表达式(与其他事物完全不同),甚至还有( ) (运行它的内容作为命令,但在子外壳中)。

You need to understand what [ means. 您需要了解[意思。 Originally, this was a synonym for the /bin/test command. 最初,这是/bin/test命令的同义词。 These are identical: 这些是相同的:

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

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

Now, you can see why spaces are needed for all of the parameters . 现在,您可以了解为什么所有参数都需要空格。 These are parameters and not merely boolean expressions. 这些是参数 ,而不仅仅是布尔表达式。 In fact, the test manpage is a great place to learn about the various tests. 实际上, 测试手册页是了解各种测试的好地方。 (Note: The test and [ are built in commands to the BASH shell.) (注意: test[是BASH shell的内置命令。)

if  [ $os_type=="Darwin" ]
then

This should be three parameters: 这应该是三个参数:

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

    if [ "$os_type" = "Darwin" ] # Three parameters to the [ command then 如果[“$操作系统类型” =“达尔文”]#三个参数到[命令然后

If you use single square brackets, you should be in the habit to surround your parameters with quotation marks. 如果使用单个方括号,则应该习惯于用引号将参数引起来。 Otherwise, you will run into trouble: 否则,您将遇到麻烦:

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

In the above, the shell will interpolate $foo and $bar with their values before evaluating the expressions. 在上面的代码中,shell在评估表达式之前将其值插入$foo$bar You'll get: 你会得到:

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

The [ will look at this and realize that neither The or value are correct parameters, and will complain. [将查看此内容,并意识到Thevalue都不是正确的参数,并且会抱怨。 Using quotes will prevent this: 使用引号可以防止这种情况:

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

This becomes: 变成:

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

This is why it's highly recommended that you use double square brackets for your tests: [[ ... ]] . 这就是为什么强烈建议您在测试中使用双方括号: [[ ... ]] The test looks at the parameters before the shell interpolates them: 该测试在外壳程序对参数进行插值之前先检查它们:

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

Also, the [[ ... ]] allows for pattern matching: 另外, [[ ... ]]允许模式匹配:

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 

This way, if the string is Darwin32 or Darwin64 , the if statement still functions. 这样,如果字符串是Darwin32Darwin64 ,则if语句仍然起作用。 Again, notice that there has to be white spaces around everything because these are parameters to a command (actually, not anymore, but that's the way the shell parses them). 再次注意,所有内容周围都必须有空格,因为这些是命令的参数(实际上已经不复存在了,但这是Shell解析它们的方式)。

Adding spaces between the arguments for the conditionals fixed the problem. 在条件的参数之间添加空格可解决此问题。

This works 这有效

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

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM