How to detect the OS from a Bash script?
我想将
在Bash脚本中检测操作系统的正确方法是什么?
我认为以下内容应该有效。我不确定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
对于我的.bashrc,我使用以下代码:
1 2 3 4 5 6 7 | platform='unknown' unamestr=`uname` if [["$unamestr" == 'Linux' ]]; then platform='linux' elif [["$unamestr" == 'FreeBSD' ]]; then platform='freebsd' fi |
然后我做的事情如下:
1 2 3 4 5 | if [[ $platform == 'linux' ]]; then alias ls='ls --color=auto' elif [[ $platform == 'freebsd' ]]; then alias ls='ls -G' fi |
这很难看,但它确实有效。如果您愿意,可以使用
bash手册页说变量OSTYPE存储操作系统的名称:
OSTYPE Automatically set to a string that describes the operating system on which bash is executing. The default is system-
dependent.
它在这里设置为
您可以简单地使用预定义的
1 2 3 4 5 6 7 8 | case"$OSTYPE" in solaris*) echo"SOLARIS" ;; darwin*) echo"OSX" ;; linux*) echo"LINUX" ;; bsd*) echo"BSD" ;; msys*) echo"WINDOWS" ;; *) echo"unknown: $OSTYPE" ;; esac |
但是旧版的shell(例如Bourne shell)无法识别它。
另一种方法是基于
请参阅以下脚本(准备包含在.bashrc中):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # 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 |
你可以在我的
以下是Travis CI上使用的类似版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
检测操作系统和CPU类型并不容易移植。我有一个大约100行的
关键要素是
-
uname -p 是处理器类型,但在现代Unix平台上通常是unknown 。 -
uname -m 将在某些Unix系统上提供"机器硬件名称"。 -
/bin/arch ,如果存在,通常会给出处理器的类型。 -
没有参数的
uname 将命名操作系统。
最终,您将不得不考虑平台之间的区别以及您想要制作它们的精确程度。例如,为了简单起见,我将
我的
如果你想偷工减料,
我建议使用这个完整的bash代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | 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" " ' '| sed s/VERSION.*//` REV=`cat /etc/SuSE-release | tr" " ' ' | 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" " ' ' | 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中,使用
尝试使用"uname"。例如,在Linux中:"uname -a"。
根据手册页,uname符合SVr4和POSIX,因此它应该可以在Mac  OS  X和Cygwin上使用,但我无法确认。
BTW:$ OSTYPE也设置为
我建议避免一些这些答案。不要忘记您可以选择其他形式的字符串比较,这将清除大多数变体或提供的丑陋代码。
一个这样的解决方案是简单的检查,例如:
if [["$OSTYPE" =~ ^darwin ]]; then
除了版本后缀之外,它还具有匹配任何版本的Darwin的额外好处。这也适用于人们可能期望的
您可以在我的dotfiles中看到一些其他示例
我在
1 2 3 4 5 6 7 8 9 | 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" ]]; } |
所以我可以这样做:
1 2 3 4 5 | 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" |
我编写了一个个人Bash库和脚本框架,它使用GNU shtool进行相当准确的平台检测。
GNU shtool是一组非常便携的脚本,除了其他有用的东西之外,还包含'shtool platform'命令。这是输出:
1 | shtool platform -v -F"%sc (%ac) %st (%at) %sp (%ap)" |
在几台不同的机器上:
1 2 3 4 5 6 7 8 | 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有点慢,所以我实际上将平台标识存储并更新到我的脚本调用的系统上的文件中。这是我的框架,所以这对我有用,但你的里程可能会有所不同。
现在,您必须找到一种方法来使用脚本打包shtool,但这并不是一项艰苦的练习。你也总是可以依靠uname输出。
编辑:
我错过了Teddy关于
您可以使用以下内容:
1 | OS=$(uname -s) |
然后您可以在脚本中使用OS变量。
1 | uname |
要么
1 | uname -a |
如果你想了解更多信息
这应该可以安全地用于所有发行版。
1 | $ cat /etc/*release |
这产生了这样的东西。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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/" |
根据需要提取/分配变量
注意:在某些设置上。这也可能会给您一些您可以忽略的错误。
1 | cat: /etc/upstream-release: Is a directory |
您可以使用以下if子句并根据需要展开它:
1 2 3 4 5 6 7 | if ["${OSTYPE//[0-9.]/}" =="darwin" ] then aminute_ago="-v-1M" elif ["${OSTYPE//[0-9.]/}" =="linux-gnu" ] then aminute_ago="-d "1 minute ago"" fi |
下面是一种检测基于Debian和RedHat的Linux操作系统的方法,它使用/ etc / lsb-release和/ etc / os-release(取决于你正在使用的Linux风格)并采取基于它的简单操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #!/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的输出示例:
1 2 3 4 5 6 7 8 9 10 | 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] ... |
我倾向于将.bashrc和.bash_alias保存在所有平台都可以访问的文件共享上。这就是我在.bash_alias中克服问题的方法:
1 2 3 | if [[ -f (name of share)/.bash_alias_$(uname) ]]; then . (name of share)/.bash_alias_$(uname) fi |
我有一个.bash_alias_Linux,例如:
1 | alias ls='ls --color=auto' |
这样我将平台特定和可移植代码分开,你可以为.bashrc做同样的事情
试试这个:
1 2 | DISTRO=$(cat /etc/*-release | grep -w NAME | cut -d= -f2 | tr -d '"') echo"Determined platform: $DISTRO" |
我在几个Linux发行版上尝试了上述消息,发现以下内容最适合我。这是一个简短,简洁的单词答案,适用于Windows上的Bash。
1 | OS=$(cat /etc/*release | grep ^NAME | tr -d 'NAME="') #$ echo $OS # Ubuntu |
如果linux发行版是Debian或Ubunu,它会检查一堆
1 2 3 4 5 | os='Uknown' unamestr="${OSTYPE//[0-9.]/}" os=$( compgen -G"/etc/*release"> /dev/null && cat /etc/*release | grep ^NAME | tr -d 'NAME="' || echo"$unamestr") echo"$os" |
执行以下操作有助于为ubuntu正确执行检查:
1 2 3 | if [["$OSTYPE" =~ ^linux ]]; then sudo apt-get install <some-package> fi |