0

I'm writing bash scripts that need to work both on Linux and on Mac.

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:

/usr/local/share/

Else if I'm on a Linux machine, I need my function to return the path:

/home/share/

Else, you are neither on a Linux or a Mac...sorry.

I'm very new to Bash, so I apologize in advance for the really simple question.

Below is the function I have written. Whether I'm on a Mac or Linux, it always returns

/usr/local/share/

Please take a look and enlighten me with the subtleties of 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

}

user2852381
  • 69
  • 1
  • 6
  • The term you are looking for when saying "sudo code" is pseudo code. As for your question, take a look at http://stackoverflow.com/questions/394230/detect-the-os-from-a-bash-script. – MeetTitan Mar 10 '15 at 05:07

3 Answers3

2

You need spaces around the operator in a test command: [ $os_type == "Darwin" ] instead of [ $os_type=="Darwin" ]. Actually, you should also use = instead of == (the double-equal is a bashism, and will not work in all shells). Also, the function keyword is also nonstandard, you should leave it off. Also, you should double-quote variable references (like "$os_type") just in case they contain spaces or any other funny characters. 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. 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 ). 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 by itself will run a as a command, and pass it the arguments "=" and "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 ] 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.

bash's builtin version of [ (test) accepts == as a synonym for =, but not all other versions do.

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).

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151
1

You need to understand what [ means. Originally, this was a synonym for the /bin/test command. 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.)

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. 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. 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. 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).

David W.
  • 105,218
  • 39
  • 216
  • 337
0

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

}

user2852381
  • 69
  • 1
  • 6