6

On my main machine, a MacBook Pro, I have a .bash_profile file that I'd like to use unaltered on my Dreamhost linux machine. However, there's a few lines that are only applicable to macOS, such as alias mvim="/Applications/MacVim.app/Contents/MacOS/MacVim".

Is there a way in bash to test for whether it's running under macOS or Debian (or just not macOS) and only execute that above line, and a few others, when running under macOS? Whereas other questions here address how to find out which Linux distro is being used, here I only need to know if I'm running on macOS or Linux, and the solutions for knowing the Linux distro aren't available on macOS.

Chuck
  • 487
  • What does uname -s show on a Mac? Under Linux, it returns Linux. – John1024 Jul 05 '16 at 00:03
  • Darwin, so, that helps quite a bit, along with Julie's suggestion. ty – Chuck Jul 05 '16 at 00:16
  • @cat not in this case. The question there and the answers seem to revolve around which Linux distro is being used, whereas I needed to know only whether I'm working on Linux or macOS (Darwin). uname seems to be perfect for that. – Chuck Jul 05 '16 at 05:04
  • @Chuck Oops, that question isn't the one I was looking for as a dupe. I swore we had a canonical "what's uname" etc question but I guess not – cat Jul 05 '16 at 05:10

3 Answers3

11

On OSX, uname -s returns Darwin (most Linux uname programs return Linux).

As a general rule (aside from personal use), uname has quirks for different systems. In autoconf, scripts use config.guess, which provides consistent information.

For example in my Debian 7,

x86_64-pc-linux-gnu

and in OSX El Capitan

x86_64-apple-darwin15.5.0

You could use if-then-else statements in the shell, or a case-statement. The latter are more easily maintained, e.g.,

case $(config.guess) in
*linux*)
    DoSomeLinuxStuff
    ;;
*apple-darwin*)
    DoSomeMacStuff
    ;;
esac

Many Linux distributions add information to the output of uname, but this is useful only on a case-by-case basis. There is no standard for the information added.

For my Debian 7:

$ uname -v
#1 SMP Debian 3.2.81-1

while OSX is radically different:

$ uname -v
Darwin Kernel Version 15.5.0: Tue Apr 19 18:36:36 PDT 2016; root:xnu-3248.50.21~8/RELEASE_X86_64

Further reading:

Thomas Dickey
  • 76,765
  • Thanks for the details, but while it sounds like config.guess is more robust than uname, for macOS, uname returns Darwin, and Linux won't return that no matter what, so that's sufficient for my needs. I suppose it's possible that a raw Darwin (no macOS GUI) will also return Darwin, I've never used such a system, only macOS, Linux, and (if I can't avoid it) Windows. – Chuck Jul 05 '16 at 05:33
10
if [[ $(uname -s) == Linux ]]
then
    doThis
else
    doThat
fi
  • Just in case someone doesn't see my comment above, using if [[ $(uname -s) == Darwin ]] in the first line will execute the then clause. – Chuck Jul 05 '16 at 00:23
  • @Chuck: Not sure what you mean. I tried to remove the then and it didn't work. – Julie Pelletier Jul 05 '16 at 00:30
  • I wasn't clear. I didn't mean to imply that then wasn't required, only that using Darwin works if you want then then clause to execute on macOS. – Chuck Jul 05 '16 at 01:00
  • Note that -s seems to be superfluous. If no flags are provided, the -s is implied, so the if line can be if [[ $(uname) == Darwin ]], which I've confirmed both with the man page and testing. – Chuck Jul 05 '16 at 01:07
  • did you mean if [[ "$(uname -s)" == "Linux" ]]; then... ? (And if not, then why?) – cat Jul 05 '16 at 05:01
  • @cat: the quotes are not required. – Julie Pelletier Jul 05 '16 at 05:05
  • 1
    Huh, and what happens if someone has the bright idea to make uname -s output blah"blah" or ]]; then :; fi; rm -rf / # ? – cat Jul 05 '16 at 05:13
  • 3
    @cat: uname is a built-in Unix command. If someone is stupid enough to do that, they should expect lots of problems. – Julie Pelletier Jul 05 '16 at 05:16
  • Evolution In Action, unix-style – cas Jul 05 '16 at 06:09
  • +1 for me.... note some others: for AIX: "AIX", For MacOS: "Darwin", and for Solaris: "SunOS". I don't know for other systems (yet) but those would be nice to be included in the answer – Olivier Dulac Jul 05 '16 at 09:50
2

As an alternate solution, you might try splitting your .bash_profile into a portable part and a system-specific part.

In your main .bash_profile add the following:

if [ -f ~/.bash_profile_local ] ; then
    . ~/.bash_profile_local
fi

Then put any customizations that apply only to a given system into .bash_profile_local on that system. If you have no customizations, you don't have to create the file.

Or, if you wanted to go even further and have pieces shared among some systems but not others, you could do a full-on SYSV-style rc.d directory. In .bash_profile:

if [ -d ~/.bash_profile.d ] ; then
    for f in ~/.bash_profile.d/* ; do
        if [ -f "$f" ] ; then
            . "$f"
        fi
    done
fi

Then create a .bash_profile.d directory, and any files you put in there will be run as if they were part of your .bash_profile.

Jander
  • 16,682
  • Thanks, @Jander, but I do like the simplicity of the accepted solution. The platform-specific lines are very few (4 or so), and are mostly just alias declarations like the example I gave (MacVim, Sage, etc.), although I'll probably change the MacVim alias into a function so I can stop having to type mvim file & and just type mvim file. – Chuck Jul 05 '16 at 04:58