【问题标题】:How to check if running in Cygwin, Mac or Linux?如何检查是否在 Cygwin、Mac 或 Linux 中运行?
【发布时间】:2011-03-28 19:50:54
【问题描述】:

我有一个在 Windows/Cygwin 和 Mac 和 Linux 上都使用的 shell 脚本。每个版本需要稍微不同的变量。

shell/bash 脚本如何检测它是在 Cygwin、Mac 还是 Linux 中运行?

【问题讨论】:

    标签: bash shell cross-platform cygwin


    【解决方案1】:

    通常,uname 及其各种选项会告诉您正在运行的环境:

    pax> uname -a
    CYGWIN_NT-5.1 IBM-L3F3936 1.5.25(0.156/4/2) 2008-06-12 19:34 i686 Cygwin
    
    pax> uname -s
    CYGWIN_NT-5.1
    

    并且,根据非常有用的schot(在 cmets 中),uname -s 为 OSX 提供 Darwin,为 Linux 提供 Linux,而我的 Cygwin 提供 CYGWIN_NT-5.1。但是您可能必须尝试各种不同的版本。

    因此,执行此类检查的 bash 代码如下:

    unameOut="$(uname -s)"
    case "${unameOut}" in
        Linux*)     machine=Linux;;
        Darwin*)    machine=Mac;;
        CYGWIN*)    machine=Cygwin;;
        MINGW*)     machine=MinGw;;
        *)          machine="UNKNOWN:${unameOut}"
    esac
    echo ${machine}
    

    请注意,我在这里假设您实际上是在 CygWin(它的bash shell)中运行,因此应该已经正确设置了路径。正如一位评论者所说,您可以运行 bash 程序,并从 cmd 本身传递脚本,这可能会导致未按需要设置路径。

    如果您正在这样做,则您有责任确保调用正确的可执行文件(即 CygWin 的),可能通过事先修改路径或完全指定可执行文件位置(例如, /c/cygwin/bin/uname)。

    【讨论】:

    • 有时少即是多 ;) 顺便说一句,维基百科在en.wikipedia.org/wiki/Uname 有一个示例 uname 输出表
    • Windows 7 上的 Git Bash uname -s 输出为 MINGW32_NT-6.1。此外,没有/cygdrive 前缀,只有/c 代表C:
    • Git Bash 不是 Cygwin。它是 MinGW,是 MS Windows 的最小 GNU,这就是行为不同的原因。
    • 我推广了另一个答案,因为这个答案不涉及 OP 部分 How can a shell/bash script detect ... 而另一个则可以。
    • 您可以在没有 cygwin 的情况下在 Windows 10 中运行 Bash。 uname 将返回类似:MSYS_NT-10.0-19041 所以匹配 MSYS_NT*) 就可以了。
    【解决方案2】:

    这是我用来检测三种不同操作系统类型(GNU/Linux、Mac OS X、Windows NT)的 bash 脚本

    注意

    • 在你的bash脚本中,使用#!/usr/bin/env bash而不是#!/bin/sh来防止/bin/sh链接到不同平台的不同默认shell引起的问题,否则会出现unexpected operator之类的错误,这就是我电脑上发生的事情(Ubuntu 64 bits 12.04)。
    • Mac OS X 10.6.8 (Snow Leopard) 没有expr 程序,除非你安装它,所以我只使用uname

    设计

    1. 使用uname获取系统信息(-s参数)。
    2. 使用exprsubstr处理字符串。
    3. 使用ifeliffi进行匹配工作。
    4. 您可以根据需要添加更多系统支持,只需遵循uname -s 规范即可。

    实施

    #!/usr/bin/env bash
    
    if [ "$(uname)" == "Darwin" ]; then
        # Do something under Mac OS X platform        
    elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
        # Do something under GNU/Linux platform
    elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
        # Do something under 32 bits Windows NT platform
    elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
        # Do something under 64 bits Windows NT platform
    fi
    

    测试

    • Linux(Ubuntu 12.04 LTS,内核 3.2.0)测试正常。
    • OS X (10.6.8 Snow Leopard) 测试正常。
    • Windows(Windows 7 64 位)测试正常。

    我学到了什么

    1. 检查开盘价和收盘价。
    2. 检查是否缺少括号和大括号{}

    参考文献

    【讨论】:

    • 对于 MinGW,检查:[ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ] 可能更有意义。
    • @Albert: 表达式"$(expr substr $(uname -s) 1 5)" 有点奇怪。有更多漂亮的方法可以做到这一点,例如:if [ `uname -s` == CYGWIN* ]; then。阅读:如果uname -sCYGWIN 开头,那么...
    • @DawidFerenczy 我相信它需要像if [[ $(uname -s) == CYGWIN* ]]; then 这样的双括号
    • 这没有检测到 Cygwin,正如问题中所问的那样。
    • 为什么只检查 Linux 的前 5 个字符?是否有现代 Linux 发行版的示例,其中 uname -s 会产生“Linux”以外的其他内容?
    【解决方案3】:

    使用 uname -s (--kernel-name),因为 Mac OS 和 Solaris。您也可以只使用 uname 而不使用任何参数,因为默认参数是 -s (--kernel-name)。

    下面的 sn-p 不需要(即不需要#!/bin/bash

    #!/bin/sh
    
    case "$(uname -s)" in
    
       Darwin)
         echo 'Mac OS X'
         ;;
    
       Linux)
         echo 'Linux'
         ;;
    
       CYGWIN*|MINGW32*|MSYS*|MINGW*)
         echo 'MS Windows'
         ;;
    
       # Add here more strings to compare
       # See correspondence table at the bottom of this answer
    
       *)
         echo 'Other OS' 
         ;;
    esac
    

    以下Makefile 的灵感来自Git project (config.mak.uname)

    ifdef MSVC     # Avoid the MingW/Cygwin sections
        uname_S := Windows
    else                          # If uname not available => 'not' 
        uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
    endif
    
    # Avoid nesting "if .. else if .. else .. endif endif"
    # because maintenance of matching if/else/endif is a pain
    
    ifeq ($(uname_S),Windows)
        CC := cl 
    endif
    ifeq ($(uname_S),OSF1)
        CFLAGS += -D_OSF_SOURCE
    endif
    ifeq ($(uname_S),Linux)
        CFLAGS += -DNDEBUG
    endif
    ifeq ($(uname_S),GNU/kFreeBSD)
        CFLAGS += -D_BSD_ALLOC
    endif
    ifeq ($(uname_S),UnixWare)
        CFLAGS += -Wextra
    endif
    ...
    

    另见this complete answer about uname -s and Makefile

    这个答案底部的对应表来自Wikipedia article about uname。请做出贡献以使其保持最新(编辑答案或发表评论)。您也可以更新 Wikipedia 文章并发表评论以通知我您的贡献;-)

    Operating System uname -s
    Mac OS X Darwin
    Cygwin 32-bit (Win-XP) CYGWIN_NT-5.1
    Cygwin 32-bit (Win-7 32-bit)@ 987654348@
    Cygwin 32-bit (Win-7 64-bit)CYGWIN_NT-6.1-WOW64
    Cygwin 64-bit (Win-7 64-bit)CYGWIN_NT-6.1 kbd>
    MinGW (Windows 7 32-bit) MINGW32_NT-6.1
    MinGW (Windows 10 64-bit) MINGW64_NT-10.0
    Interix (Services for UNIX) Interix
    MSYS MSYS_NT-6.1
    MSYS2 MSYS_NT-10.0-17763
    @987654325@ Linux
    Android Linux
    coreutils Linux
    CentOS Linux

    Fedora Linux
    Gentoo @987654374 @
    Red Hat Linux Linux
    Linux Mint Linux
    openSUSE Linux
    Ubuntu Linux
    Unity Linux Linux
    @987654385 @Linux
    OpenWRT r40420 Linux
    Debian (Linux) Linux
    Debian (GNU Hurd) GNU
    Debian (kFreeBSD) GNU/kFreeBSD
    FreeBSD FreeBSD
    NetBSD NetBSD
    OpenBSD OpenBSD
    DragonFlyBSD DragonFly Haiku Haiku
    NonStop NONSTOP_KERNEL
    QNX QNX
    ReliantUNIX ReliantUNIX-Y
    SINIX SINIX-Y
    Tru64 OSF1
    Ultrix ULTRIX
    IRIX 32 bits IRIX
    IRIX 64 bits @ 987654420@
    MINIX Minix
    Solaris SunOS
    UWIN (64-bit Windows 7) UWIN-W7
    SYS$UNIX:SH on OpenVMS IS/WB
    z/OS USS OS/390
    @ 987654431@sn5176
    (SCO) OpenServer SCO_SV
    (SCO) System V kbd>SCO_SV
    (SCO) UnixWare UnixWare
    IBM AIX AIX
    IBM i with QSH OS400
    HP-UX HP-UX

    【讨论】:

    • 为 Solaris 和上面的研究点赞。
    • 嗨@okutane。我不懂你说什么。请提供更多详细信息。你有什么建议吗?干杯
    • 我要投赞成票,就是这样。
    • 这正是我想要编写一个可移植/跨平台的~/.profile(设置环境变量,如$PATH——评论为后代提供搜索关键字)。
    • 我来到这里是因为我想专门检测 WSL,并将其与其他 Linux 区分开来。那么似乎对我有用的是检查uname -sr并在Linux*)之前与Linux*Microsoft)进行比较。
    【解决方案4】:

    Bash 设置 shell 变量 OSTYPE。来自man bash

    自动设置为描述操作系统的字符串 哪个 bash 正在执行。

    这与uname 相比有一个微小的优势,因为它不需要启动新进程,因此执行起来会更快。

    但是,我找不到权威的期望值列表。对我来说,在 Ubuntu 14.04 上它设置为“linux-gnu”。我已经在网上搜索了一些其他值。因此:

    case "$OSTYPE" in
      linux*)   echo "Linux / WSL" ;;
      darwin*)  echo "Mac OS" ;; 
      win*)     echo "Windows" ;;
      msys*)    echo "MSYS / MinGW / Git Bash" ;;
      cygwin*)  echo "Cygwin" ;;
      bsd*)     echo "BSD" ;;
      solaris*) echo "Solaris" ;;
      *)        echo "unknown: $OSTYPE" ;;
    esac
    

    星号在某些情况下很重要 - 例如 OSX 在“darwin”之后附加一个操作系统版本号。有人告诉我,'win' 值实际上是 'win32' - 也许有一个 'win64'?

    也许我们可以一起工作,在这里填写一个验证值表:

    • Linux Ubuntu(包括WSL):linux-gnu
    • Cygwin 64 位:cygwin
    • Msys/MINGW(Windows 版 Git Bash):msys

    (如果与现有条目不同,请附加您的值)

    【讨论】:

    • 我已经比我更喜欢你的回答,非常适合我需要这个的罕见时间
    • 从技术上讲,它不是环境变量,而是 shell 变量。这就是为什么你不会在env | grep OSTYPE 下看到它,但你会在set | grep OSTYPE 下看到它
    • 对于那些感兴趣的人,Bash 的 OSTYPE 变量 (conftypes.h) 在构建时使用 automake 的 OS 变量 (Makefile.in) 的精确副本进行配置。可以查阅 automake 的 lib/config.sub 文件以了解所有可用类型。
    • 还有 zsh 设置 OSTYPE
    【解决方案5】:
    # This script fragment emits Cygwin rulez under bash/cygwin
    if [[ $(uname -s) == CYGWIN* ]];then
        echo Cygwin rulez
    else 
        echo Unix is king
    fi
    

    如果uname -s命令的前6个字符为“CYGWIN”,则假定为cygwin系统

    【讨论】:

    • if [ `uname -s` == CYGWIN* ]; then 看起来更好,效果也一样。
    • 可以,但使用双括号:[[ $(uname -s) == CYGWIN* ]]。另请注意,在我们的例子中,扩展正则表达式更精确:[[ $(uname -s) =~ ^CYGWIN* ]]
    • 上述方法效果更好,因为expr substr $(uname -s) 1 6 在 macOS 上会出现错误 (expr: syntax error)。
    • 请注意,扩展正则表达式不是 glob,因此要匹配 CYGWIN 之后的“任何字符”需要 .*。添加* 只会匹配额外的Ns。因此,[[ $(uname -s) =~ ^CYGWIN.*$ ]] 需要精确度,但对于我们的情况,[[ $(uname -s) =~ ^CYGWIN ]] 就足够了
    【解决方案6】:

    基于 Albert 的回答,我喜欢使用 $COMSPEC 来检测 Windows:

    #!/bin/bash
    
    if [ "$(uname)" == "Darwin" ]
    then
     echo Do something under Mac OS X platform
    elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]
    then
      echo Do something under Linux platform
    elif [ -n "$COMSPEC" -a -x "$COMSPEC" ]
    then 
      echo $0: this script does not support Windows \:\(
    fi
    

    这避免了为$OS 解析Windows 名称的变体,以及解析uname 的变体,如MINGW、Cygwin 等。

    背景:%COMSPEC% 是一个 Windows 环境变量,用于指定命令处理器(也称为 Windows shell)的完整路径。该变量的值通常为%SystemRoot%\system32\cmd.exe,其计算结果通常为C:\Windows\system32\cmd.exe

    【讨论】:

    • 不正确,因为在 Windows UWS Bash 环境下运行时没有设置 $COMSPEC。
    【解决方案7】:

    http://en.wikipedia.org/wiki/Uname

    您将需要的所有信息。 Google 是您的朋友。

    使用uname -s查询系统名称。

    • 苹果机:Darwin
    • 赛格温:CYGWIN_...
    • Linux:各种,LINUX 最多

    【讨论】:

      【解决方案8】:

      当被问到这个问题时,Linux 的 Windows 子系统并不存在。它在我的测试中给出了这些结果:

      uname -s -> Linux
      uname -o -> GNU/Linux
      uname -r -> 4.4.0-17763-Microsoft
      

      这意味着你需要 uname -r 来区分它和原生 Linux。

      【讨论】:

      • 不幸的是,Mingw-w64 给出的结果完全相同。
      【解决方案9】:

      好的,这是我的方式。

      osis()
      {
          local n=0
          if [[ "$1" = "-n" ]]; then n=1;shift; fi
      
          # echo $OS|grep $1 -i >/dev/null
          uname -s |grep -i "$1" >/dev/null
      
          return $(( $n ^ $? ))
      }
      

      例如

      osis Darwin &&
      {
          log_debug Detect mac osx
      }
      osis Linux &&
      {
          log_debug Detect linux
      }
      osis -n Cygwin &&
      {
          log_debug Not Cygwin
      }
      

      我在我的dotfiles 中使用它

      【讨论】:

        【解决方案10】:

        我猜 uname 的答案是无与伦比的,主要是在清洁度方面。

        虽然执行起来需要很长的时间,但我发现测试特定文件的存在也能给我带来更好更快的结果,因为我没有调用可执行文件:

        所以,

        [ -f /usr/bin/cygwin1.dll ] && echo Yep, Cygwin running

        只使用快速的 Bash 文件存在检查。由于我现在在 Windows 上,我无法告诉你任何适用于 Linux 和 Mac OS X 的特定文件,但我很确定它们确实存在。 :-)

        【讨论】:

          猜你喜欢
          • 2015-10-12
          • 2010-11-16
          • 2017-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多