我有一个在Windows/Cygwin、Mac和Linux上都使用的shell脚本。每个版本都需要稍微不同的变量。
如何让shell/bash脚本检测它是在Cygwin、Mac还是Linux上运行?
我有一个在Windows/Cygwin、Mac和Linux上都使用的shell脚本。每个版本都需要稍微不同的变量。
如何让shell/bash脚本检测它是在Cygwin、Mac还是Linux上运行?
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;;
MSYS_NT*) machine=Git;;
*) machine="UNKNOWN:${unameOut}"
esac
echo ${machine}
#!/usr/bin/env bash
而不是#!/bin/sh
,以防止/bin/sh
在不同平台上链接到不同的默认shell引起问题。否则可能会出现错误,例如“意外运算符”,这就是我电脑(Ubuntu 64位12.04)上发生的情况。expr
程序,除非您安装了它,因此我只使用uname
。uname
获取系统信息(-s
参数)。expr
和substr
处理字符串。if
elif
fi
进行匹配。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
[ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]
。 - Achal Dave"$(expr substr $(uname -s) 1 5)"
有点奇怪。有更好的方法来实现,例如:if [ \
uname -s` == CYGWIN* ]; then。意思是:如果
uname -s`以CYGWIN开头,则... - David Ferenczy Rogožanif [[ $(uname -s) == CYGWIN* ]]; then
。 - rogerdpackuname -s
返回值不是 "Linux" 的例子? - ktbiz使用uname -s
(--kernel-name
)是因为一些操作系统不支持uname -o
(--operating-system
),例如Mac OS和Solaris。您还可以只使用uname
而不带任何参数,因为默认参数是-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
...
本答案底部的对应表格来自uname
的维基百科文章。请贡献力量,使其保持最新(编辑答案或发表评论)。您也可以更新维基百科文章并发表评论以通知我您的贡献;-)
操作系统 | uname -s |
---|---|
Mac OS X | Darwin |
Cygwin 32位(Win-XP) | CYGWIN_NT-5.1 |
Cygwin 32位(Win-7 32位) | CYGWIN_NT-6.1 |
Cygwin 32位(Win-7 64位) | CYGWIN_NT-6.1-WOW64 |
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子系统 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 |
OpenBSD | OpenBSD |
DragonFlyBSD | DragonFly |
Haiku | Haiku |
NonStop | 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 |
SYS$UNIX: |
~/.profile
(设置环境变量,如$PATH
- 为后人提供搜索关键字的注释)。 - Braham Snyderuname -sr
并将其与 Linux*Microsoft)
比较,先于 Linux*)
。 - einarmagnusman bash
:uname
相比,这具有微小的优势,因为它不需要启动新进程,所以执行速度更快。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
env | grep OSTYPE
下看不到它,但在 set | grep OSTYPE
下可以看到它的原因。 - wisbuckyOSTYPE
变量(conftypes.h)是在构建时使用automake的OS
变量(Makefile.in)的确切副本进行配置的。可以参考automake的lib/config.sub文件以获取所有可用类型的信息。 - jdknight# 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系统。[[ $(uname -s) == CYGWIN* ]]
。同时请注意,在我们的情况下,扩展正则表达式更加精确:[[ $(uname -s) =~ ^CYGWIN* ]]
。 - Andreas Spindlerexpr substr $(uname -s) 1 6
在 macOS 上会报错(expr: syntax error
)。 - doekmanCYGWIN
后面的 "任何字符",需要使用 .*
。添加 *
只会匹配额外的 N
。因此,为了精确匹配,需要使用 [[ $(uname -s) =~ ^CYGWIN.*$ ]]
,但对于我们的情况,[[ $(uname -s) =~ ^CYGWIN ]]
就足够了。 - jalanb在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变体名称以及解析像MINGW、Cygwin等的uname变体。
背景: %COMSPEC%
是一个Windows环境变量,用于指定命令处理器的完整路径(也称为Windows shell)。该变量的值通常为%SystemRoot%\system32\cmd.exe
,通常会转换为C:\Windows\system32\cmd.exe
。
https://en.wikipedia.org/wiki/Uname
所有你需要的信息都可以在Google上找到。
使用uname -s
来查询系统名称。
Darwin
CYGWIN_...
LINUX
uname -s -> Linux
uname -o -> GNU/Linux
uname -r -> 4.4.0-17763-Microsoft
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 ^ $? ))
}
e.g.
osis Darwin &&
{
log_debug Detect mac osx
}
osis Linux &&
{
log_debug Detect linux
}
osis -n Cygwin &&
{
log_debug Not Cygwin
}