How to detect the OS from a Bash script?

BashOs Detection

Bash Problem Overview


I would like to keep my .bashrc and .bash_login files in version control so that I can use them between all the computers I use. The problem is I have some OS specific aliases so I was looking for a way to determine if the script is running on Mac OS X, Linux or Cygwin.

What is the proper way to detect the operating system in a Bash script?

Bash Solutions


Solution 1 - Bash

I think the following should work. I'm not sure about win32 though.

if [[ "$OSTYPE" == "linux-gnu"* ]]; then
        # ...
elif [[ "$OSTYPE" == "darwin"* ]]; then
        # Mac OSX
elif [[ "$OSTYPE" == "cygwin" ]]; then
        # POSIX compatibility layer and Linux environment emulation for Windows
elif [[ "$OSTYPE" == "msys" ]]; then
        # Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
elif [[ "$OSTYPE" == "win32" ]]; then
        # I'm not sure this can happen.
elif [[ "$OSTYPE" == "freebsd"* ]]; then
        # ...
else
        # Unknown.
fi

Solution 2 - Bash

For my .bashrc, I use the following code:

platform='unknown'
unamestr=$(uname)
if [[ "$unamestr" == 'Linux' ]]; then
   platform='linux'
elif [[ "$unamestr" == 'FreeBSD' ]]; then
   platform='freebsd'
fi

Then I do somethings like:

if [[ $platform == 'linux' ]]; then
   alias ls='ls --color=auto'
elif [[ $platform == 'freebsd' ]]; then
   alias ls='ls -G'
fi

It's ugly, but it works. You may use case instead of if if you prefer.

Solution 3 - Bash

The bash manpage says that the variable OSTYPE stores the name of the operation system:

> OSTYPE Automatically set to a string that describes the operating system on which bash is executing. The default is system- dependent.

It is set to linux-gnu here.

Solution 4 - Bash

$OSTYPE

You can simply use pre-defined $OSTYPE variable e.g.:

case "$OSTYPE" in
  solaris*) echo "SOLARIS" ;;
  darwin*)  echo "OSX" ;; 
  linux*)   echo "LINUX" ;;
  bsd*)     echo "BSD" ;;
  msys*)    echo "WINDOWS" ;;
  cygwin*)  echo "ALSO WINDOWS" ;;
  *)        echo "unknown: $OSTYPE" ;;
esac

However it's not recognized by the older shells (such as Bourne shell).


uname

Another method is to detect platform based on uname command.

See the following script (ready to include in .bashrc):

# Detect the platform (similar to $OSTYPE)
OS="`uname`"
case $OS in
  'Linux')
    OS='Linux'
    alias ls='ls --color=auto'
    ;;
  'FreeBSD')
    OS='FreeBSD'
    alias ls='ls -G'
    ;;
  'WindowsNT')
    OS='Windows'
    ;;
  'Darwin') 
    OS='Mac'
    ;;
  'SunOS')
    OS='Solaris'
    ;;
  'AIX') ;;
  *) ;;
esac

You can find some practical example in my .bashrc.


Here is similar version used on Travis CI:

case $(uname | tr '[:upper:]' '[:lower:]') in
  linux*)
    export TRAVIS_OS_NAME=linux
    ;;
  darwin*)
    export TRAVIS_OS_NAME=osx
    ;;
  msys*)
    export TRAVIS_OS_NAME=windows
    ;;
  *)
    export TRAVIS_OS_NAME=notset
    ;;
esac

Solution 5 - Bash

Detecting operating system and CPU type is not so easy to do portably. I have a sh script of about 100 lines that works across a very wide variety of Unix platforms: any system I have used since 1988.

The key elements are

  • uname -p is processor type but is usually unknown on modern Unix platforms.

  • uname -m will give the "machine hardware name" on some Unix systems.

  • /bin/arch, if it exists, will usually give the type of processor.

  • uname with no arguments will name the operating system.

Eventually you will have to think about the distinctions between platforms and how fine you want to make them. For example, just to keep things simple, I treat i386 through i686 , any "Pentium*" and any "AMD*Athlon*" all as x86.

My ~/.profile runs an a script at startup which sets one variable to a string indicating the combination of CPU and operating system. I have platform-specific bin, man, lib, and include directories that get set up based on that. Then I set a boatload of environment variables. So for example, a shell script to reformat mail can call, e.g., $LIB/mailfmt which is a platform-specific executable binary.

If you want to cut corners, uname -m and plain uname will tell you what you want to know on many platforms. Add other stuff when you need it. (And use case, not nested if!)

Solution 6 - Bash

I recommend to use this complete bash code

lowercase(){
	echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/"
}

OS=`lowercase \`uname\``
KERNEL=`uname -r`
MACH=`uname -m`

if [ "{$OS}" == "windowsnt" ]; then
	OS=windows
elif [ "{$OS}" == "darwin" ]; then
	OS=mac
else
	OS=`uname`
	if [ "${OS}" = "SunOS" ] ; then
		OS=Solaris
		ARCH=`uname -p`
		OSSTR="${OS} ${REV}(${ARCH} `uname -v`)"
	elif [ "${OS}" = "AIX" ] ; then
		OSSTR="${OS} `oslevel` (`oslevel -r`)"
	elif [ "${OS}" = "Linux" ] ; then
		if [ -f /etc/redhat-release ] ; then
			DistroBasedOn='RedHat'
			DIST=`cat /etc/redhat-release |sed s/\ release.*//`
			PSUEDONAME=`cat /etc/redhat-release | sed s/.*\(// | sed s/\)//`
			REV=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//`
		elif [ -f /etc/SuSE-release ] ; then
			DistroBasedOn='SuSe'
			PSUEDONAME=`cat /etc/SuSE-release | tr "\n" ' '| sed s/VERSION.*//`
			REV=`cat /etc/SuSE-release | tr "\n" ' ' | sed s/.*=\ //`
		elif [ -f /etc/mandrake-release ] ; then
			DistroBasedOn='Mandrake'
			PSUEDONAME=`cat /etc/mandrake-release | sed s/.*\(// | sed s/\)//`
			REV=`cat /etc/mandrake-release | sed s/.*release\ // | sed s/\ .*//`
		elif [ -f /etc/debian_version ] ; then
			DistroBasedOn='Debian'
			DIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F=  '{ print $2 }'`
			PSUEDONAME=`cat /etc/lsb-release | grep '^DISTRIB_CODENAME' | awk -F=  '{ print $2 }'`
			REV=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F=  '{ print $2 }'`
		fi
		if [ -f /etc/UnitedLinux-release ] ; then
			DIST="${DIST}[`cat /etc/UnitedLinux-release | tr "\n" ' ' | sed s/VERSION.*//`]"
		fi
		OS=`lowercase $OS`
		DistroBasedOn=`lowercase $DistroBasedOn`
	 	readonly OS
	 	readonly DIST
		readonly DistroBasedOn
	 	readonly PSUEDONAME
	 	readonly REV
	 	readonly KERNEL
	 	readonly MACH
	fi

fi
echo $OS
echo $KERNEL
echo $MACH

more examples examples here: https://github.com/coto/server-easy-install/blob/master/lib/core.sh

Solution 7 - Bash

I would suggest avoiding some of these answers. Don't forget that you can choose other forms of string comparison, which would clear up most of the variations, or ugly code offered.

One such solution would be a simple check, such as:

if [[ "$OSTYPE" =~ ^darwin ]]; then

Which has the added benefit of matching any version of Darwin, despite it's version suffix. This also works for any variations of Linux one may expect.

You can see some additional examples within my dotfiles here

Solution 8 - Bash

Try using "uname". For example, in Linux: "uname -a".

According to the manual page, uname conforms to SVr4 and POSIX, so it should be available on Mac OS X and Cygwin too, but I can't confirm that.

BTW: $OSTYPE is also set to linux-gnu here :)

Solution 9 - Bash

In bash, use $OSTYPE and $HOSTTYPE, as documented; this is what I do. If that is not enough, and if even uname or uname -a (or other appropriate options) does not give enough information, there’s always the config.guess script from the GNU project, made exactly for this purpose.

Solution 10 - Bash

I wrote these sugars in my .bashrc:

if_os () { [[ $OSTYPE == *$1* ]]; }
if_nix () { 
	case "$OSTYPE" in
    	*linux*|*hurd*|*msys*|*cygwin*|*sua*|*interix*) sys="gnu";;
		*bsd*|*darwin*) sys="bsd";;
    	*sunos*|*solaris*|*indiana*|*illumos*|*smartos*) sys="sun";;
	esac
    [[ "${sys}" == "$1" ]];
}

So I can do stuff like:

if_nix gnu && alias ls='ls --color=auto' && export LS_COLORS="..."
if_nix bsd && export CLICOLORS=on && export LSCOLORS="..."
if_os linux && alias psg="ps -FA | grep" #alternative to pgrep
if_nix bsd && alias psg="ps -alwx | grep -i" #alternative to pgrep
if_os darwin && alias finder="open -R"

Solution 11 - Bash

uname
or
uname -a
if you want more information

Solution 12 - Bash

Below it's an approach to detect Debian and RedHat based Linux OS making use of the /etc/lsb-release and /etc/os-release (depending on the Linux flavor you're using) and take a simple action based on it.

#!/bin/bash
set -e

YUM_PACKAGE_NAME="python python-devl python-pip openssl-devel"
DEB_PACKAGE_NAME="python2.7 python-dev python-pip libssl-dev"

 if cat /etc/*release | grep ^NAME | grep CentOS; then
    echo "==============================================="
    echo "Installing packages $YUM_PACKAGE_NAME on CentOS"
    echo "==============================================="
    yum install -y $YUM_PACKAGE_NAME
 elif cat /etc/*release | grep ^NAME | grep Red; then
    echo "==============================================="
    echo "Installing packages $YUM_PACKAGE_NAME on RedHat"
    echo "==============================================="
    yum install -y $YUM_PACKAGE_NAME
 elif cat /etc/*release | grep ^NAME | grep Fedora; then
    echo "================================================"
    echo "Installing packages $YUM_PACKAGE_NAME on Fedorea"
    echo "================================================"
    yum install -y $YUM_PACKAGE_NAME
 elif cat /etc/*release | grep ^NAME | grep Ubuntu; then
    echo "==============================================="
    echo "Installing packages $DEB_PACKAGE_NAME on Ubuntu"
    echo "==============================================="
    apt-get update
    apt-get install -y $DEB_PACKAGE_NAME
 elif cat /etc/*release | grep ^NAME | grep Debian ; then
    echo "==============================================="
    echo "Installing packages $DEB_PACKAGE_NAME on Debian"
    echo "==============================================="
    apt-get update
    apt-get install -y $DEB_PACKAGE_NAME
 elif cat /etc/*release | grep ^NAME | grep Mint ; then
    echo "============================================="
    echo "Installing packages $DEB_PACKAGE_NAME on Mint"
    echo "============================================="
    apt-get update
    apt-get install -y $DEB_PACKAGE_NAME
 elif cat /etc/*release | grep ^NAME | grep Knoppix ; then
    echo "================================================="
    echo "Installing packages $DEB_PACKAGE_NAME on Kanoppix"
    echo "================================================="
    apt-get update
    apt-get install -y $DEB_PACKAGE_NAME
 else
    echo "OS NOT DETECTED, couldn't install package $PACKAGE"
    exit 1;
 fi

exit 0

Output example for Ubuntu Linux:

delivery@delivery-E5450$ sudo sh detect_os.sh
[sudo] password for delivery: 
NAME="Ubuntu"
===============================================
Installing packages python2.7 python-dev python-pip libssl-dev on Ubuntu
===============================================
Ign http://dl.google.com stable InRelease
Get:1 http://dl.google.com stable Release.gpg [916 B]                          
Get:2 http://dl.google.com stable Release [1.189 B] 
...            

Solution 13 - Bash

I wrote a personal Bash library and scripting framework that uses GNU shtool to do a rather accurate platform detection.

GNU shtool is a very portable set of scripts that contains, among other useful things, the 'shtool platform' command. Here is the output of:

shtool platform -v -F "%sc (%ac) %st (%at) %sp (%ap)"

on a few different machines:

Mac OS X Leopard: 
    4.4BSD/Mach3.0 (iX86) Apple Darwin 9.6.0 (i386) Apple Mac OS X 10.5.6 (iX86)

Ubuntu Jaunty server:
    LSB (iX86) GNU/Linux 2.9/2.6 (i686) Ubuntu 9.04 (iX86)

Debian Lenny:
    LSB (iX86) GNU/Linux 2.7/2.6 (i686) Debian GNU/Linux 5.0 (iX86)

This produces pretty satisfactory results, as you can see. GNU shtool is a little slow, so I actually store and update the platform identification in a file on the system that my scripts call. It's my framework, so that works for me, but your mileage may vary.

Now, you'll have to find a way to package shtool with your scripts, but it's not a hard exercise. You can always fall back on uname output, also.

EDIT:

I missed the post by Teddy about config.guess (somehow). These are very similar scripts, but not the same. I personally use shtool for other uses as well, and it has been working quite well for me.

Solution 14 - Bash

You can use the following:

OS=$(uname -s)

then you can use OS variable in your script.

Solution 15 - Bash

This should be safe to use on all distros.

$ cat /etc/*release

This produces something like this.

     DISTRIB_ID=LinuxMint
     DISTRIB_RELEASE=17
     DISTRIB_CODENAME=qiana
     DISTRIB_DESCRIPTION="Linux Mint 17 Qiana"
     NAME="Ubuntu"
     VERSION="14.04.1 LTS, Trusty Tahr"
     ID=ubuntu
     ID_LIKE=debian
     PRETTY_NAME="Ubuntu 14.04.1 LTS"
     VERSION_ID="14.04"
     HOME_URL="http://www.ubuntu.com/"
     SUPPORT_URL="http://help.ubuntu.com/"
     BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"

Extract/assign to variables as you wish

Note: On some setups. This may also give you some errors that you can ignore.

     cat: /etc/upstream-release: Is a directory

Solution 16 - Bash

try this:

DISTRO=$(cat /etc/*-release | grep -w NAME | cut -d= -f2 | tr -d '"')
echo "Determined platform: $DISTRO"

Solution 17 - Bash

You can use following if clause and expand it as needed:

if [ "${OSTYPE//[0-9.]/}" == "darwin" ]
then
	aminute_ago="-v-1M"
elif  [ "${OSTYPE//[0-9.]/}" == "linux-gnu" ]
then
	aminute_ago="-d \"1 minute ago\""
fi

Solution 18 - Bash

I tend to keep my .bashrc and .bash_alias on a file share that all platforms can access. This is how I conquer the problem in my .bash_alias:

if [[ -f (name of share)/.bash_alias_$(uname) ]]; then
    . (name of share)/.bash_alias_$(uname)
fi

And I have for example a .bash_alias_Linux with:

alias ls='ls --color=auto'

This way I keep platform specific and portable code separate, you can do the same for .bashrc

Solution 19 - Bash

I tried the above messages across a few Linux distros and found the following to work best for me. It’s a short, concise exact word answer that works for Bash on Windows as well.

OS=$(cat /etc/*release | grep ^NAME | tr -d 'NAME="') #$ echo $OS # Ubuntu

Solution 20 - Bash

This checks a bunch of known files to identfy if the linux distro is Debian or Ubunu, then it defaults to the $OSTYPE variable.

os='Unknown'
unamestr="${OSTYPE//[0-9.]/}"
os=$( compgen -G "/etc/*release" > /dev/null  && cat /etc/*release | grep ^NAME | tr -d 'NAME="'  ||  echo "$unamestr")

echo "$os"

Solution 21 - Bash

This is what I use if anyone is interested in detecting WSL vs WSL verion 2 as well.

#!/usr/bin/env bash

unameOut=$(uname -a)
case "${unameOut}" in
    *Microsoft*)     OS="WSL";; #must be first since Windows subsystem for linux will have Linux in the name too
    *microsoft*)     OS="WSL2";; #WARNING: My v2 uses ubuntu 20.4 at the moment slightly different name may not always work
    Linux*)     OS="Linux";;
    Darwin*)    OS="Mac";;
    CYGWIN*)    OS="Cygwin";;
    MINGW*)     OS="Windows";;
    *Msys)     OS="Windows";;
    *)          OS="UNKNOWN:${unameOut}"
esac

echo ${OS};

Solution 22 - Bash

Doing the following helped perform the check correctly for ubuntu:

if [[ "$OSTYPE" =~ ^linux ]]; then
    sudo apt-get install <some-package>
fi

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncsextonView Question on Stackoverflow
Solution 1 - BashTimmmmView Answer on Stackoverflow
Solution 2 - Bashuser49221View Answer on Stackoverflow
Solution 3 - BashJohannes Schaub - litbView Answer on Stackoverflow
Solution 4 - BashkenorbView Answer on Stackoverflow
Solution 5 - BashNorman RamseyView Answer on Stackoverflow
Solution 6 - BashcotoView Answer on Stackoverflow
Solution 7 - BashAkivaView Answer on Stackoverflow
Solution 8 - BashJoao da SilvaView Answer on Stackoverflow
Solution 9 - BashTeddyView Answer on Stackoverflow
Solution 10 - BashkfixView Answer on Stackoverflow
Solution 11 - BashFederico A. RamponiView Answer on Stackoverflow
Solution 12 - BashExequiel BarrireroView Answer on Stackoverflow
Solution 13 - BashgunsView Answer on Stackoverflow
Solution 14 - BashChetan kapoorView Answer on Stackoverflow
Solution 15 - BashR JView Answer on Stackoverflow
Solution 16 - BashAlexander NekrasovView Answer on Stackoverflow
Solution 17 - BashTahsin TurkozView Answer on Stackoverflow
Solution 18 - BashericcurtinView Answer on Stackoverflow
Solution 19 - BashintellilogicView Answer on Stackoverflow
Solution 20 - BashKuzekoView Answer on Stackoverflow
Solution 21 - BashBradView Answer on Stackoverflow
Solution 22 - BashsandmanView Answer on Stackoverflow