-1
#!/bin/bash

if [ ["$OSTYPE" == "linux-gnu"*] ]; then
    SCRIPT_PATH=$(dirname $(realpath -s $0))
elif [ ["$OSTYPE" == "darwin"*] ]; then
    SCRIPT_PATH=$(dirname $(pwd))
    echo "mac!!"
else
     echo "Unknown OS!"
    exit
fi

I want to write a bash script to specify the OS type. But on my MacOS, the result shows "Unknown OS!", which is wrong. I tried echo $OSTYPE in terminal, it shows darwin20.0. So I wonder what's the problem in my code?

Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • because `== "…"*` isn't a thing. You have to use grep. – Thomas Aug 29 '21 at 08:19
  • 2
    Please paste your script at [shellcheck.net](http://www.shellcheck.net/) and try to implement the recommendations made there. – Cyrus Aug 29 '21 at 08:22
  • sorry, I don't understand what do you mean by using grep? I saw the code in this question: https://stackoverflow.com/questions/394230/how-to-detect-the-os-from-a-bash-script – ZIH-YOU Yang Aug 29 '21 at 08:25
  • @ZIH-YOUYang see my answer below. – Thomas Aug 29 '21 at 08:26
  • 2
    @ZIH-YOUYang: Your syntax is wrong and Thomas is wrong. No need for `grep`. See: `OSTYPE="darwin20.0"; [[ "$OSTYPE" == "darwin"* ]] && echo "bingo"` – Cyrus Aug 29 '21 at 08:28
  • @Cyrus yeah, okay, he could just correct to `[[ "$OSTYPE" == "darwin*" ]]` _etc._ (_i.e._ get rid of spaces, and put wildcard inside the compared string). – Thomas Aug 29 '21 at 08:32
  • @Thomas: Yes, quotes prevent bash from expanding glob `*`. – Cyrus Aug 29 '21 at 08:34
  • @ZIH-YOUYang As a general rule in shell scripts, spaces *matter*. They're important delimiters, so when you're copying an example, be sure to put spaces in the same places. Adding or removing them can change the meaning of a command completely (as it did here). – Gordon Davisson Aug 29 '21 at 08:52

3 Answers3

1

The case statement is specifically intended for comparing a single string against various patterns, and doing different things depending on which it matches:

#!/bin/bash

case "$OSTYPE" in
    "linux-gnu"* )
        script_path="$(dirname "$(realpath -s "$0")")" ;;

    "darwin"* )
        script_path="$(dirname "$(pwd)")" ;;

    * )
        echo "Unknown OS!" >&2
        exit 1 ;;
esac

Notes: each pattern is delimited with a ) at the end. You can also put a ( at the beginning, but most people don't bother. Each case ends with a double semicolon. The * case at the end will match anything that didn't match an earlier pattern, so it functions like an else clause in an if ... elif ... statement.

Some other changes I made:

  • It's a good idea to double-quote variable references and command substitutions (e.g. "$(realpath -s "$0")" instead of just $(realpath -s $0)) to avoid weird parsing problems with some characters (mostly spaces) in values. (There are some places where it's safe to leave the double-quotes off, but it's not worth trying to remember where they are.)
  • Since there are a whole bunch of all-caps names with special functions, it's safest to use lower- or mixed-case names (e.g. script_path instead of SCRIPT_PATH) to avoid conflicts.
  • Error and status messages (like "Unknown OS!") should generally be sent to standard error instead of standard output. I used >&2 to redirect the message to standard error.
  • When a script (or function, or program, or whatever) exits after an error, it should return a nonzero exit status to indicate that it failed. Different codes can be used to indicate different problems, but 1 is commonly used as a generic "something went wrong" code, so I used exit 1 here.

And I recommend using shellcheck.net to scan your scripts for common mistakes. It'll save you a lot of trouble.

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

Make sure you have no spaces between your opening and closing brackets, i.e., [[ and ]] vs [ [ and ] ] and you may get rid of the quotes in your patterns:

#!/usr/bin/env bash

OSTYPE=linux-gnu-123

if [[ "$OSTYPE" == linux-gnu* ]]; then
  echo "linux"
elif [[ "$OSTYPE" == darwin* ]]; then
  echo "mac"
else
  echo "Unknown OS!"
fi

Also, use https://www.shellcheck.net/ to verify your scripts.

Ionuț G. Stan
  • 176,118
  • 18
  • 189
  • 202
  • Thank you! I am confused about the syntax and the difference between [ and [[ operator. I will read more documents. – ZIH-YOU Yang Aug 29 '21 at 08:56
  • @ZIH-YOUYang it's a tricky aspect of Bash, I agree. See this question though: https://stackoverflow.com/questions/669452/is-double-square-brackets-preferable-over-single-square-brackets-in-ba – Ionuț G. Stan Aug 29 '21 at 09:02
-1

The problem is your attempt checking wildcard expressions via =="..."*. This needs to be done via grep. Try something like this:

#!/usr/bin/env bash

# define method
function checkOS() {
    local os="$OSTYPE";
    if [[ "$os" == "msys" ]]; then
        echo "windows";
    elif ( echo "$os" | grep -Eq "^darwin.*$" ); then
        echo "mac";
    elif ( echo "$os" | grep -Eq "^linux-gnu.*$" ); then
        echo "linux";
    else
        echo "Unknown OS!" >> /dev/stderr;
        exit 1;
    fi
}

# try method
os="$( checkOS )";
echo -e "Current OS is \033[1m${os}\033[0m.";
Thomas
  • 175
  • 11