如何检查是否在Cygwin,Mac或Linux上运行?


334

我有一个在Windows / Cygwin以及Mac和Linux上都使用的Shell脚本。每个版本需要略有不同的变量。

shell / bash脚本如何检测它是否在Cygwin,Mac或Linux中运行?

Answers:


322

通常,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(在注释中),uname -s给出Darwin了OSX和LinuxLinux的代码,而我的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它的外壳)中运行,因此路径应该已经正确设置。正如一位评论者所述,您可以bashcmd自己传递脚本的方式运行该程序,这可能会导致未根据需要设置路径。

如果你正在这样做,这是你的责任,以确保正确的可执行文件(即,在Cygwin的)都被调用,可能通过修改路径提前或完全指定可执行文件的位置(例如,/c/cygwin/bin/uname)。


11
有时候,少就是多;)顺便说一句,维基百科在en.wikipedia.org/wiki/Uname上
schot 2010年

Windows 7上的Git Bash uname -s输出为MINGW32_NT-6.1。此外,没有/cygdrive前缀,仅/c用于C:
ColinM 2011年

7
Git Bash不是Cygwin。这是MinGW,用于MS Windows的最小GNU,这就是行为不同的原因。
2014年

我提出了另一个答案,因为这个答案不涉及OP部分How can a shell/bash script detect ...,另一个涉及。
Jesse Chisholm

如果我通过执行“ \ cygwin64 \ bin \ bash -c脚本名”在cygwin下运行脚本,则此方法不一定有效。在这种情况下,不会设置cygwin路径,并uname -s最终调用uname当前路径中的第一个路径,而在我的系统上,该路径原来是安装的版本,可用geda来返回text WindowsNT。不过,它也可以是如上所述的MinGW版本。对cygwin的可靠检测不得依赖于正确设置的路径IMO。因此,$(uname -s)应更改$(/bin/uname -s)为检测cygwin。
Jules

329

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

请注意

  • 在您的bash脚本中,使用#!/usr/bin/env bash而不是#!/bin/sh来防止由于/bin/sh链接到不同平台上的不同默认Shell所引起的问题,否则将出现类似意料之外的错误的错误,这就是我的计算机上发生的情况(Ubuntu 64位12.04)。
  • expr除非您安装了Mac OS X 10.6.8(Snow Leopard),否则没有程序,因此我只使用uname

设计

  1. 使用uname来获取系统信息(-s参数)。
  2. 使用exprsubstr处理字符串。
  3. if elif fi做匹配工作。
  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,Kernel 3.2.0)测试正常。
  • OS X(10.6.8雪豹)测试正常。
  • Windows(Windows 7 64位)测试正常。

我学到的是

  1. 检查开头和结尾的报价。
  2. 检查缺少的括号和花括号{}

参考文献


对于MinGW,检查:可能更有意义[ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]
Achal Dave

2
@Albert:表情有点奇怪"$(expr substr $(uname -s) 1 5)"。有更多漂亮的方法可以做到这一点,例如:if [ `uname -s` == CYGWIN* ]; then。阅读它:如果uname -sCYGWIN开始,那么...
David FerenczyRogožan2014年

10
@DawidFerenczy我相信这将需要双括号一样if [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack

1
正如问题所问的那样,这不能检测到Cygwin。
rmcclellan

2
为什么对于Linux仅检查前5个字符?是否有现代Linux发行版的示例,这些发行版uname -s将产生除“ Linux”以外的其他内容?
ktbiz

127

使用uname -s--kernel-name)是因为在某些操作系统(例如Mac OSSolaris)上不支持uname -o--operating-system)。您也可以不带任何参数使用,因为默认参数为()。uname-s--kernel-name

以下代码段不需要 (即不需要#!/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项目(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
...

另请参阅有关uname -s和的完整答案Makefile

该答案底部的对应表来自Wikipedia文章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)CYGWIN_NT-6.1
Cygwin 32-bit (Win-7 64-bit)CYGWIN_NT-6.1-WOW64
Cygwin 64-bit (Win-7 64-bit)CYGWIN_NT-6.1
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
Windows Subsystem for Linux Linux
Android Linux
coreutils Linux
CentOS Linux
Fedora Linux
Gentoo Linux
Red Hat Linux Linux
Linux Mint Linux
openSUSE Linux
Ubuntu Linux
Unity Linux Linux
Manjaro Linux Linux
OpenWRT r40420 Linux
Debian (Linux) Linux
Debian (GNU Hurd) GNU
Debian (kFreeBSD) GNU/kFreeBSD
FreeBSD FreeBSD
NetBSD NetBSD
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 IRIX64
MINIX Minix
Solaris SunOS
UWIN (64-bit Windows 7) UWIN-W7
SYS$UNIX:SH on OpenVMS IS/WB
z/OS USS OS/390
Cray sn5176
(SCO) OpenServer SCO_SV
(SCO) System V SCO_SV
(SCO) UnixWare UnixWare
IBM AIX AIX
IBM i with QSH OS400
HP-UX HP-UX


3
赞成以上的Solaris和研究。
okutane'2

嗨@okutane 我不懂你说什么。请提供更多详细信息。你有什么建议吗?干杯
olibre

3
我投票赞成,就是这样。
okutane

1
这正是我寻找可移植/跨平台~/.profile(设置环境变量,例如$PATH-注释以提供后代搜索关键字)所需的内容。
布拉汉姆·斯奈德

1
我来这里是因为我想专门检测WSL,并将其与其他Linux区分。似乎什么工作对我来说是再检查uname -sr和比较反对Linux*Microsoft)Linux*)
einarmagnus

65

Bash设置外壳程序变量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'之后附加OS版本号。有人告诉我'win'值实际上是'win32'-也许有一个'win64'吗?

也许我们可以一起在此处填充经过验证的值的表格:

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

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


1
我已经比我更喜欢您的回答了,非常适合我需要的罕见情况
Charles Roberto Canato

6
从技术上讲,它不是环境变量,而是shell变量。这就是为什么您不会在下面看到它的原因env | grep OSTYPE,但是您会在下面看到它set | grep OSTYPE
wisbucky

4
对于那些感兴趣的人,Bash OSTYPE变量(conftypes.h)在构建时使用automake OS变量的精确副本(Makefile.in)进行配置。可以参考automake的lib / config.sub文件获取所有可用类型。
jdknight

9

为了建立在阿尔伯特的答案上,我喜欢用它$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

这样可以避免解析Windows名称用于的$OS变体,以及解析uname诸如MINGW,Cygwin等的变体。

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


在Windows UWS Bash环境下运行时未设置$ COMSPEC,因此不再正确。
朱利安·奈特

9
# 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看起来更好,工作原理相同。
David FerenczyRogožan2014年

6
是的,但请使用双括号:[[ $(uname -s) == CYGWIN* ]]。还需要注意的是扩展的正则表达式是在我们的情况更精确:[[ $(uname -s) =~ ^CYGWIN* ]]
Andreas Spindler 2014年

上面的方法效果更好,因为在macOS上expr substr $(uname -s) 1 6显示错误(expr: syntax error)。
doekman

2

好的,这是我的方式。

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
}

我在我的点文件中使用它



2

询问此问题时,Linux的Windows子系统不存在。它在我的测试中给出了以下结果:

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

这意味着您需要uname -r才能将其与本机Linux区别开。


1
不幸的是,Mingw-w64给出的结果完全相同。

1

我想这个一致的答案是无与伦比的,主要是在清洁方面。

尽管执行起来花了很多时间,但我发现测试特定文件的存在也会使我获得更好更快的结果,因为我没有调用可执行文件:

所以,

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

只是使用快速的Bash文件存在性检查。就像我现在在Windows上一样,我无法从脑海中告诉您Linux和Mac OS X的任何特定文件,但是我很确定它们确实存在。:-)


-3

多亏了贾斯汀,在命令行中仅使用此命令就可以很好地工作:

#!/bin/bash

################################################## #########
# Bash script to find which OS
################################################## #########

OS=`uname`
echo "$OS"

资源


您的脚本中有什么新内容?
mallaudin '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.