如何从Bash脚本中检测操作系统?

cse*_*ton 463 bash os-detection

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

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

Tim*_*mmm 416

我认为以下内容应该有效.我不确定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
Run Code Online (Sandbox Code Playgroud)

  • 在Windows上,你将获得Git Bash/msysGit的`msys`和Cygwin的`cygwin` (7认同)
  • 当你用命令替换注释时,有些东西会让我失望 - 确保以`;`结尾. (4认同)
  • 有趣的是。Mac OSX仍会给出“ darwin”。 (2认同)
  • 当我添加像 `source somefile 之类的命令时;`,我在意外标记 elif 附近收到了`语法错误。 (2认同)

小智 285

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

platform='unknown'
unamestr=`uname`
if [[ "$unamestr" == 'Linux' ]]; then
   platform='linux'
elif [[ "$unamestr" == 'FreeBSD' ]]; then
   platform='freebsd'
fi
Run Code Online (Sandbox Code Playgroud)

然后我做的事情如下:

if [[ $platform == 'linux' ]]; then
   alias ls='ls --color=auto'
elif [[ $platform == 'freebsd' ]]; then
   alias ls='ls -G'
fi
Run Code Online (Sandbox Code Playgroud)

这很难看,但它确实有效.如果您愿意,可以使用case而不是if.

  • 不要使用反引号,使用更新的更清晰的语法:"unamestr = $(uname)". (79认同)
  • @ david-winiecki因为如果你需要嵌套命令,例如$(command-1 $(command-2)) (29认同)
  • 从快速浏览一下,反推可以像一根绳子. (14认同)
  • 为什么你从unamestr设置平台,而不是只使用unamestr? (6认同)
  • 这样做不是更好:`platform ="$(uname | tr'[:upper:]''[:lower:]')"`然后肯定处理一个案例?在非常具体的输出上硬编码依赖项似乎很奇怪. (3认同)
  • 如果您在终端中执行此操作来检测 mac,您将获得 darwin。echo `uname` 达尔文 (2认同)

Joh*_*itb 272

bash手册页说变量OSTYPE存储操作系统的名称:

OSTYPE自动设置为描述正在执行bash的操作系统的字符串.默认值取决于系统.

它设置在linux-gnu这里.

  • `case $ OSTYPE in darwin*)echo我是Mac ;; esac` (81认同)
  • @tripleee或者对"if"语法更熟悉的人:`if [[$ OSTYPE == darwin*]]; 然后回声我是Mac; fi` (36认同)
  • 删除它并不是什么大不了的事:`os = $ {OSTYPE // [0-9.] /}` (16认同)
  • 另外,$ OSTYPE在我的mac(Leopard)上是'darwin9.0',在Cygwin下是'cygwin'. (5认同)
  • 在SnowLeopard上$ OSTYPE是darwin10.0.附加版本的WTF?意味着简单的案例陈述不起作用. (5认同)

ken*_*orb 142

您可以简单地使用预定义的$ OSTYPE变量即:

case "$OSTYPE" in
  solaris*) echo "SOLARIS" ;;
  darwin*)  echo "OSX" ;; 
  linux*)   echo "LINUX" ;;
  bsd*)     echo "BSD" ;;
  msys*)    echo "WINDOWS" ;;
  *)        echo "unknown: $OSTYPE" ;;
esac
Run Code Online (Sandbox Code Playgroud)

另一种方法是基于$OSTYPE命令检测平台.

请参阅以下脚本(准备包含在.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
Run Code Online (Sandbox Code Playgroud)

你可以在我的一些实际例子$OSTYPE.

  • $OSTYPE 检查缺少 cygwin 的一个分支,这表示 Windows 机器。uname 检查也无法正常工作,在 cygwin 上 uname 返回“CYGWIN_NT-10.0”,而在 MinGW 上 uname 返回“MINGW64_NT-10.0”。 (2认同)

Nor*_*sey 35

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

关键要素是

  • uname -p处理器类型,但通常unknown在现代Unix平台上.

  • uname -m 将在某些Unix系统上提供"机器硬件名称".

  • /bin/arch,如果它存在,通常会给出处理器的类型.

  • uname 没有参数将命名操作系统.

最终,您将不得不考虑平台之间的区别以及您想要制作它们的精确程度. 例如,只是为了让事情变得简单,我把i386通过i686,任何" Pentium*"任何" AMD*Athlon*"所有的x86.

~/.profile在启动时运行一个脚本,它将一个变量设置为一个字符串,表示CPU和操作系统的组合.我有特定于平台的bin,man,lib,和include基于该是那些获得建立目录.然后我设置了一大堆环境变量.因此,例如,重新格式化邮件的shell脚本可以调用,例如,$LIB/mailfmt这是特定于平台的可执行二进制文件.

如果你想偷工减料,那么uname -m普通话uname会告诉你在许多平台上你想知道什么.在需要时添加其他东西.(并使用case,而不是嵌套if!)

  • @AndrewDeAndrade我很惭愧将此代码暴露给公众.http://pastebin.com/J66Lj6wf (4认同)
  • 根据*[uname Command](http://publib.boulder.ibm.com/infocenter/aix/v6r1/topic/com.ibm.aix.cmds/doc/aixcmds5/uname.htm)*,uname没有参数相当于使用"-s"参数:" - s显示系统名称.此标志默认为打开.".要明确,可以使用"uname -s"而不是"uname".(详见*[回答'Shell输出帮助'](http://unix.stackexchange.com/questions/5522/shell-output-help/32052#32052)*) (2认同)

cot*_*oto 33

我建议使用这个完整的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
Run Code Online (Sandbox Code Playgroud)

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

  • 您会考虑在脚本的最后添加“echo ${OS}”吗? (2认同)

Bra*_*rad 14

如果有人也有兴趣检测 WSL 与 WSL 版本 2,我会使用此方法。这在 ZSH 和 BASH 中都有效。

#!/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};
Run Code Online (Sandbox Code Playgroud)

更新:我还将其添加到我的脚本中,用于检测 M1 与普通 Mac。

if [[ ${OS} == "Mac" ]] && sysctl -n machdep.cpu.brand_string | grep -q 'Apple M1'; then
    OS="MacM1"
fi
Run Code Online (Sandbox Code Playgroud)


Ted*_*ddy 10

在bash中,使用$OSTYPE$HOSTTYPE记录; 这就是我做的.如果这还不够,如果偶数unameuname -a(或其他适当的选项)没有提供足够的信息,那么GNU项目中的config.guess脚本总是完全用于此目的.


Joa*_*lva 9

尝试使用"uname".例如,在Linux中:"uname -a".

根据手册页,uname符合SVr4和POSIX,因此它也应该在Mac OS X和Cygwin上可用,但我无法确认.

BTW:$ OSTYPE也设置在linux-gnu这里:)


Aki*_*iva 9

我建议避免一些这些答案.不要忘记您可以选择其他形式的字符串比较,这将清除大多数变体或提供的丑陋代码.

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

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

除了版本后缀之外,它还具有匹配任何版本的Darwin的额外好处.这也适用于Linux人们可能期望的任何变化.

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

  • 链接失效了.. (3认同)

kfi*_*fix 8

我在这里写了这些糖.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" ]];
}
Run Code Online (Sandbox Code Playgroud)

所以我可以这样做:

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"
Run Code Online (Sandbox Code Playgroud)


Ale*_*sov 8

尝试这个:

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


gun*_*uns 7

我编写了一个个人Bash库和脚本框架,它使用GNU shtool进行相当准确的平台检测.

GNU shtool是一组非常便携的脚本,除了其他有用的东西之外,还包含'shtool platform'命令.这是输出:

shtool platform -v -F "%sc (%ac) %st (%at) %sp (%ap)"
Run Code Online (Sandbox Code Playgroud)

在几台不同的机器上:

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)
Run Code Online (Sandbox Code Playgroud)

如您所见,这会产生非常令人满意的结果.GNU shtool有点慢,所以我实际上将平台标识存储并更新到我的脚本调用的系统上的文件中.这是我的框架,所以对我有用,但你的里程可能会有所不同.

现在,您必须找到一种方法来使用脚本打包shtool,但这不是一项艰苦的练习.你也总是可以依靠uname输出.

编辑:

我错过了泰迪的帖子config.guess(某种程度上).这些是非常相似的脚本,但不一样.我个人也将shtool用于其他用途,它对我来说一直很好用.


Exe*_*ero 7

下面是一种检测基于 Debian 和 RedHat 的Linux 操作系统的方法,该方法使用/etc/lsb-release/etc/os-release(取决于您使用的 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
Run Code Online (Sandbox Code Playgroud)

输出例如用于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] 
...            
Run Code Online (Sandbox Code Playgroud)


Che*_*oor 7

您可以使用以下内容:

OS=$(uname -s)
Run Code Online (Sandbox Code Playgroud)

然后您可以在脚本中使用OS变量.


R J*_*R J 5

这应该可以安全地用于所有发行版.

$ cat /etc/*release
Run Code Online (Sandbox Code Playgroud)

这产生了这样的东西.

     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/"
Run Code Online (Sandbox Code Playgroud)

根据需要提取/分配变量

注意:在某些设置上.这也可能会给您一些您可以忽略的错误.

     cat: /etc/upstream-release: Is a directory
Run Code Online (Sandbox Code Playgroud)

  • 不适用于Mac:`cat:/ etc/*release:没有这样的文件或目录` (4认同)

Tah*_*koz 5

您可以使用以下 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
Run Code Online (Sandbox Code Playgroud)