从Bash脚本中检测操作系统

我想将我的.bashrc.bash_login文件保存在版本控制中,以便我可以在所有使用的计算机之间使用它们。 问题是我有一些操作系统特定的别名,所以我正在寻找一种方法来确定脚本是否在Mac OS X,Linux或Cygwin上运行 。

在Bash脚本中检测操作系统的正确方法是什么?

对于我的.bashrc,我使用下面的代码:

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

然后我做一些事情,如:

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

这是丑陋的,但它的作品。 如果您愿意,您可以使用case

bash manpage说variablesOSTYPE存储操作系统的名字:

OSTYPE自动设置为描述执行bash的操作系统的string。 缺省是系统相关的。

它在这里设置为linux-gnu

我认为以下应该工作。 虽然我不知道win32

 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 

你可以简单地使用预先定义的$ OSTYPEvariables,即:

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

另一种方法是基于uname命令检测平台。

看到下面的脚本(准备包含在.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 

你可以在我的.bashrcfind一些实际的例子 。

检测操作系统和CPUtypes并不容易。 我有一个约100行的sh脚本,适用于各种Unix平台:自1988年以来我使用过的任何系统。

关键要素是

  • uname -p处理器types,但在现代Unix平台上通常是unknown

  • uname -m将在某些Unix系统上给出“机器硬件名称”。

  • /bin/arch ,如果存在的话,通常会给出处理器的types。

  • uname没有参数会命名操作系统。

最终,你将不得不考虑平台之间的区别,以及你想要做什么。 例如,为了简单i686 ,我把i386通过i686 ,任何“ Pentium* ”和任何“ AMD*Athlon* ”作为x86

我的~/.profile在启动时运行一个脚本,它将一个variables设置为一个string,表示CPU和操作系统的组合。 我有特定于平台的binmanlib ,以及include基于此目录设置的目录。 然后我设置了一堆环境variables。 因此,例如,重新格式化邮件的shell脚本可以调用,例如$LIB/mailfmt ,这是一个特定于平台的可执行二进制文件。

如果你想偷工减料uname -muname会告诉你在很多平台上你想知道什么。 当你需要的时候添加其他东西。 (和用caseif没有nesteed!)

我build议使用这个完整的bash代码

 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 

更多示例示例在这里: https : //github.com/coto/server-easy-install/blob/master/lib/core.sh

在bash中,使用$OSTYPE$HOSTTYPE ,如文档所述; 这是我所做的。 如果这还不够,而且即使unameuname -a (或者其他适当的选项)没有提供足够的信息,总是会有GNU项目中的config.guess脚本,完全是为了这个目的而做的。

尝试使用“uname”。 例如,在Linux中:“uname -a”。

根据手册页,uname符合SVr4和POSIX,所以也应该可以在Mac OS X和Cygwin上使用 ,但我无法确认。

顺便说一句:$ OSTYPE也设置为linux-gnu这里:)

 uname 

要么

 uname -a 

如果你想要更多的信息

我写了一个个人Bash库和脚本框架 ,使用GNU shtool来做一个相当准确的平台检测。

GNU shtool是一个非常便携的脚本集,其中包含了“shtool平台”命令。 这里是输出:

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

在几个不同的机器上:

 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) 

如您所见,这会产生相当令人满意的结果。 GNU shtool有点慢,所以我实际上是在我的脚本所调用的系统文件中存储和更新平台标识。 这是我的框架,所以适用于我,但你的里程可能会有所不同。

现在,你必须find一个方法来打包你的脚本shtool,但这不是一个艰苦的工作。 你也可以总是回到uname输出。

编辑:

我错过了关于config.guess (不知何故)的Teddy的post。 这些脚本非常相似,但不一样。 我个人也使用shtool作为其他用途,它一直工作得很好。

我build议避免一些这些答案。 不要忘记,你可以select其他forms的string比较,这将清除大部分变化,或提供丑陋的代码。

一个这样的解决scheme将是一个简单的检查,例如:

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

尽pipe它是版本后缀,但它还具有与任何版本的Darwin匹配的额外好处。 这也适用于Linux可能期望的任何变化。

你可以在这里看到我的点文件中的一些额外的例子

这应该是安全的在所有发行版上使用。

 $ cat /etc/*release 

这产生了这样的事情。

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

根据需要提取/分配给variables

注意:在一些设置。 这也可能会给你一些你可以忽略的错误。

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

我把这些糖写在我的.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" ]]; } 

所以我可以做这样的事情:

 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" 

下面是使用/ etc / lsb-release/ etc / os-release (取决于您所使用的Linux风格)检测基于Debian和RedHat的Linux操作系统的方法,并根据它进行简单的操作。

 #!/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 

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

执行以下操作帮助正确执行了ubuntu的检查:

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

我倾向于将.bashrc和.bash_alias保留在所有平台可以访问的文件共享上。 这是我如何克服我的.bash_alias问题:

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

我有一个.bash_alias_Linux例如:

 alias ls='ls --color=auto' 

通过这种方式,我可以将特定于平台的可移植代码分开,您可以对.bashrc执行相同的操作

您可以使用以下if子句并根据需要展开它:

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

我在几个Linux发行版上尝试了上面的消息,发现以下对我最合适。 这是一个简短的,精确的单词答案,也适用于Windows上的Bash。

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