696

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

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

4

22 回答 22

762

我认为以下应该有效。我不确定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
于 2011-12-21T22:46:47.777 回答
307

对于我的 .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而不是。if

于 2008-12-26T20:36:15.140 回答
291

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

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

它设置在linux-gnu这里。

于 2008-12-26T20:31:39.317 回答
226

$OSTYPE

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

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

但是,较旧的 shell (例如Bourne shell )无法识别它。


uname

另一种方法是基于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

你可以在我的.bashrc.


这是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
于 2013-08-25T23:43:01.260 回答
41

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

关键要素是

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

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

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

  • uname不带参数将命名操作系统。

最终,您将不得不考虑平台之间的区别以及您希望将它们做得多好。 例如,为了简单起见,我将i386through i686、 any " Pentium*" 和 any " AMD*Athlon*" all 视为x86

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

如果你想偷工减料uname -mplainuname会在很多平台上告诉你你想知道的。需要时添加其他内容。(并且使用case,而不是嵌套if!)

于 2008-12-26T21:07:13.707 回答
40

我建议使用这个完整的 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
echo $OS
echo $KERNEL
echo $MACH

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

于 2010-09-25T07:00:11.757 回答
18

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

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

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

尽管它是版本后缀,但它具有匹配任何版本的达尔文的额外好处。这也适用于Linux人们可能期望的任何变化。

您可以在我的 dotfiles 中看到一些其他示例

于 2012-05-03T21:59:43.050 回答
11

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

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

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

于 2008-12-26T20:33:03.493 回答
11

在 bash 中,使用$OSTYPEand $HOSTTYPE,如文档所述;这就是我所做的。如果这还不够,并且 even unameor uname -a(或其他适当的选项)没有提供足够的信息,那么GNU 项目中总会有专门为此目的而制作的config.guess脚本。

于 2009-01-14T11:24:37.300 回答
10

我把这些糖写在我的.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"
于 2015-03-24T17:52:36.047 回答
9
uname

或者

uname -a

如果您想了解更多信息

于 2008-12-26T20:33:45.363 回答
8

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

GNU shtool 是一组非常便携的脚本,其中包含“shtool platform”命令等有用的东西。这是输出:

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 有点慢,所以我实际上在我的脚本调用的系统上的一个文件中存储和更新平台标识。这是我的框架,所以对我有用,但你的里程可能会有所不同。

现在,您必须找到一种方法将 shtool 与您的脚本打包在一起,但这并不是一项艰巨的练习。您也可以随时使用 uname 输出。

编辑:

我错过了泰迪关于config.guess(不知何故)的帖子。这些是非常相似的脚本,但并不相同。我个人也将 shtool 用于其他用途,它对我来说效果很好。

于 2009-03-12T19:15:28.040 回答
8

下面是一种使用/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] 
...            
于 2017-01-20T12:36:45.650 回答
8

您可以使用以下内容:

OS=$(uname -s)

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

于 2017-11-23T11:42:13.080 回答
7

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

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

根据需要提取/分配给变量

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

     cat: /etc/upstream-release: Is a directory
于 2014-08-21T01:10:35.450 回答
5

试试这个:

DISTRO=$(cat /etc/*-release | grep -w NAME | cut -d= -f2 | tr -d '"')
echo "Determined platform: $DISTRO"
于 2018-11-08T10:04:54.513 回答
4

您可以使用以下 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
于 2016-02-27T21:12:16.620 回答
3

我倾向于将我的 .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 做同样的事情

于 2015-01-15T17:36:42.927 回答
3

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

OS=$(cat /etc/*release | grep ^NAME | tr -d 'NAME="') #$ echo $OS # Ubuntu
于 2017-03-08T16:25:00.430 回答
3

这会检查一堆known文件以识别 linux 发行版是 Debian 还是 Ubunu,然后它默认为$OSTYPE变量。

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"
于 2018-10-02T19:12:04.877 回答
1

如果有人也对检测 WSL 与 WSL 版本 2 感兴趣,这就是我使用的。

#!/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};
于 2021-08-09T02:47:43.660 回答
-1

执行以下操作有助于正确执行 ubuntu 的检查:

if [[ "$OSTYPE" =~ ^linux ]]; then
    sudo apt-get install <some-package>
fi
于 2013-08-21T01:53:56.960 回答