如何检查如果运行在Cygwin, Mac或Linux?

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

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

205779 次浏览

通常,带有各种选项的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给出了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外壳),因此路径应该已经正确设置。正如一位评论者指出的那样,你可以从cmd本身运行bash程序,传递脚本,这可能会导致路径没有按需要设置。

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

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

所有你需要的信息。谷歌是你的朋友。

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

  • 麦克:Darwin
  • Cygwin: CYGWIN_...
  • Linux:各种,大多数为LINUX
# 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

检测三种不同的操作系统类型(GNU/Linux, Mac OS X, Windows NT)

笔记

  • 在你的bash脚本中,使用#!/usr/bin/env bash而不是#!/bin/sh来防止由/bin/sh链接到不同平台上的不同默认shell所引起的问题,否则会出现像意想不到的运营商这样的错误,这就是在我的计算机上发生的事情(Ubuntu 64位12.04)。
  • Mac OS X 10.6.8(雪豹)没有expr程序,除非你安装它,所以我只是使用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)测试OK。
  • OS X (10.6.8 Snow Leopard)测试正常。
  • Windows (Windows 7 64位)测试正常。

我学到了什么

  1. 检查开头和结尾的引号。
  2. 检查是否缺少括号和大括号{}

参考文献

根据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

使用uname -s (--kernel-name),因为某些操作系统(如Mac OS--kernel-name0)不支持uname -o (--operating-system)。你也可以只使用--kernel-name1,因为默认参数是-s (--kernel-name)。

为了区分WSL和Linux, einarmagnus推荐下面脚本中提出的uname -sr (--kernel-name --kernel-release)。😉

#!/bin/sh


case "$(uname -sr)" in


Darwin*)
echo 'Mac OS X'
;;


Linux*Microsoft*)
echo 'WSL'  # Windows Subsystem for Linux
;;


Linux*)
echo 'Linux'
;;


CYGWIN*|MINGW*|MINGW32*|MSYS*)
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
...

另见关于__ABC0和Makefile的完整答案

这个答案底部的对应表来自维基百科关于uname的文章。请投稿以保持更新(编辑答案或发表评论)。您也可以更新维基百科的文章,并发表评论,以通知我您的贡献;-)

操作系统 uname - s
Mac OS X 达尔文
Cygwin 32位(Win-XP) cygwin_nt - 5.1
Cygwin 32位(Win-7 32位) cygwin_nt - 6.1
Cygwin 32位(Win-7 64位) cygwin_nt wow64——6.1
Cygwin 64位(Win-7 64位) cygwin_nt - 6.1
MinGW (Windows 7 32位) mingw32_nt - 6.1
MinGW (Windows 10 64位) mingw64_nt - 10.0
Interix (UNIX服务) Interix
MSYS msys_nt - 6.1
MSYS2 msys_nt - 10.0 - 17763
Windows Subsystem for Linux Linux
安卓 Linux
coreutils Linux
CentOS Linux
Fedora Linux
Gentoo Linux
红帽Linux Linux
Linux Mint Linux
openSUSE Linux
Ubuntu Linux
Linux统一 Linux
Manjaro Linux Linux
OpenWRT r40420 Linux
Debian (Linux) Linux
Debian (GNU Hurd) GNU
Debian (kFreeBSD) GNU / kFreeBSD
FreeBSD FreeBSD
NetBSD NetBSD
OpenBSD OpenBSD
DragonFlyBSD 蜻蜓
三行俳句诗 三行俳句诗
不间断的 NONSTOP_KERNEL
QNX QNX
ReliantUNIX ReliantUNIX-Y
SINIX SINIX-Y
Tru64 OSF1
Ultrix ULTRIX
IRIX 32位 IRIX
IRIX 64位 IRIX64
MINIX Minix
Solaris SunOS
UWIN(64位Windows 7) UWIN-W7
系统$UNIX:SH在OpenVMS 是/白平衡
z / OS号航空母舰 OS / 390
克雷 sn5176
(上海合作组织)OpenServer SCO_SV
(SCO)系统V SCO_SV
(上海合作组织)UnixWare UnixWare
IBM AIX AIX
IBM i与QSH OS400
hp - ux hp - ux

好的,这是我的方法。

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
}

我在.中使用这个

我想无名的答案是无敌的,主要是在清洁方面。

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

所以,

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

只是使用一个快速的Bash文件存在检查。因为我现在使用的是Windows,所以我无法告诉你任何linux和Mac OS X的具体文件,但我非常确定它们确实存在。: -)

Bash设置shell变量OSTYPE。从man 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 (Git Bash for Windows): msys

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

当提出这个问题时,Linux的Windows子系统还不存在。它在我的测试中给出了以下结果:

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

这意味着您需要使用uname -r来将其与本地Linux区分开来。