如何检查是否在 Cygwin、Mac 还是 Linux 中运行?

发布于 2024-09-13 15:54:05 字数 127 浏览 5 评论 0原文

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

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

I have a shell script that is used both on Windows/Cygwin and Mac and Linux. It needs slightly different variables for each versions.

How can a shell/bash script detect whether it is running in Cygwin, on a Mac or in Linux?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

眼泪都笑了 2024-09-20 15:54:05

通常,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}

请注意,我假设您实际上在 CygWin 内运行(bash shell),因此路径应该已经正确设置。正如一位评论者指出的那样,您可以从 cmd 本身运行 bash 程序并传递脚本,这可能会导致路径未根据需要设置。

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

Usually, uname with its various options will tell you what environment you're running in:

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

And, according to the very helpful schot (in the comments), uname -s gives Darwin for OSX and Linux for Linux, while my Cygwin gives CYGWIN_NT-5.1. But you may have to experiment with all sorts of different versions.

So the bash code to do such a check would be along the lines of:

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}

Note that I'm assuming here that you're actually running within CygWin (the bash shell of it) so paths should already be correctly set up. As one commenter notes, you can run the bash program, passing the script, from cmd itself and this may result in the paths not being set up as needed.

If you are doing that, it's your responsibility to ensure the correct executables (i.e., the CygWin ones) are being called, possibly by modifying the path beforehand or fully specifying the executable locations (e.g., /c/cygwin/bin/uname).

捂风挽笑 2024-09-20 15:54:05

检测三种不同的操作系统类型(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 (Snow Leopard) 没有 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,内核 3.2.0)测试正常。
  • OS X(10.6.8 Snow Leopard)测试正常。
  • Windows(Windows 7 64 位)测试正常。

我学到了什么

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

参考文献

Detect three different OS types (GNU/Linux, Mac OS X, Windows NT)

Notes

  • In your bash script, use #!/usr/bin/env bash instead of #!/bin/sh to prevent the problem caused by /bin/sh linked to different default shell in different platforms, or there will be error like unexpected operator, that's what happened on my computer (Ubuntu 64 bits 12.04).
  • Mac OS X 10.6.8 (Snow Leopard) do not have expr program unless you install it, so I just use uname.

Design

  1. Use uname to get the system information (-s parameter).
  2. Use expr and substr to deal with the string.
  3. Use if elif fi to do the matching job.
  4. You can add more system support if you want, just follow the uname -s specification.

Implementation

#!/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

Testing

  • Linux (Ubuntu 12.04 LTS, Kernel 3.2.0) tested OK.
  • OS X (10.6.8 Snow Leopard) tested OK.
  • Windows (Windows 7 64 bit) tested OK.

What I learned

  1. Check for both opening and closing quotes.
  2. Check for missing parentheses and braces {}

References

本宫微胖 2024-09-20 15:54:05

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

为了区分 WSL 和 Linux,einarmagnus 建议 uname -sr (--kernel-name --kernel-release),如建议的那样以下脚本。

Use uname -s (--kernel-name) because uname -o (--operating-system) is not supported on some Operating Systems such as Mac OS and Solaris. You may also use just uname without any argument since the default argument is -s (--kernel-name).

To distinguish WSL from Linux, einarmagnus recommends uname -sr (--kernel-name --kernel-release) as proposed in the following script. ????

#!/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

The following Makefile is inspired from 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
...

See also this complete answer about uname -s and Makefile.

The correspondence table in the bottom of this answer is from Wikipedia article about uname. Please contribute to keep it up-to-date (edit the answer or post a comment). You may also update the Wikipedia article and post a comment to notify me about your contribution ;-)

Operating Systemuname -s
Mac OS XDarwin
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
MSYSMSYS_NT-6.1
MSYS2MSYS_NT-10.0-17763
Windows Subsystem for LinuxLinux
AndroidLinux
coreutilsLinux
CentOSLinux
FedoraLinux
GentooLinux
Red Hat LinuxLinux
Linux MintLinux
openSUSELinux
UbuntuLinux
Unity LinuxLinux
Manjaro LinuxLinux
OpenWRT r40420Linux
Debian (Linux)Linux
Debian (GNU Hurd)GNU
Debian (kFreeBSD)GNU/kFreeBSD
FreeBSDFreeBSD
NetBSDNetBSD
OpenBSDOpenBSD
DragonFlyBSDDragonFly
HaikuHaiku
NonStopNONSTOP_KERNEL
QNXQNX
ReliantUNIXReliantUNIX-Y
SINIXSINIX-Y
Tru64OSF1
UltrixULTRIX
IRIX 32 bitsIRIX
IRIX 64 bitsIRIX64
MINIXMinix
SolarisSunOS
UWIN (64-bit Windows 7)UWIN-W7
SYS$UNIX:SH on OpenVMSIS/WB
z/OS USSOS/390
Craysn5176
(SCO) OpenServerSCO_SV
(SCO) System VSCO_SV
(SCO) UnixWareUnixWare
IBM AIXAIX
IBM i with QSHOS400
HP-UXHP-UX
二智少女 2024-09-20 15:54:05

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
  • MacOS Venura:darwin22。 0

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

Bash sets the shell variable OSTYPE. From man bash:

Automatically set to a string that describes the operating system on
which bash is executing.

This has a tiny advantage over uname in that it doesn't require launching a new process, so will be quicker to execute.

However, I'm unable to find an authoritative list of expected values. For me on Ubuntu 14.04 it is set to 'linux-gnu'. I've scraped the web for some other values. Hence:

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

The asterisks are important in some instances - for example OSX appends an OS version number after the 'darwin'. The 'win' value is actually 'win32', I'm told - maybe there is a 'win64'?

Perhaps we could work together to populate a table of verified values here:

  • Linux Ubuntu (incl. WSL): linux-gnu
  • Cygwin 64-bit: cygwin
  • Msys/MINGW (Git Bash for Windows): msys
  • MacOS Venura: darwin22.0

(Please append your value if it differs from existing entries)

你怎么敢 2024-09-20 15:54:05
# 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 系统

# This script fragment emits Cygwin rulez under bash/cygwin
if [[ $(uname -s) == CYGWIN* ]];then
    echo Cygwin rulez
else 
    echo Unix is king
fi

If the 6 first chars of uname -s command is "CYGWIN", a cygwin system is assumed

满身野味 2024-09-20 15:54:05

为了以 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< 的变体。 /code> 如 MINGW、Cygwin 等。

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

To build upon Albert's answer, I like to use $COMSPEC for detecting 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

This avoids parsing variants of Windows names for $OS, and parsing variants of uname like MINGW, Cygwin, etc.

Background: %COMSPEC% is a Windows environmental variable specifying the full path to the command processor (aka the Windows shell). The value of this variable is typically %SystemRoot%\system32\cmd.exe, which typically evaluates to C:\Windows\system32\cmd.exe .

小姐丶请自重 2024-09-20 15:54:05

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

您将得到的所有信息需要。谷歌是你的朋友。

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

  • Mac:Darwin
  • Cygwin:CYGWIN_...
  • Linux:各种,LINUX 适用于大多数

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

All the info you'll ever need. Google is your friend.

Use uname -s to query the system name.

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: various, LINUX for most
撕心裂肺的伤痛 2024-09-20 15:54:05

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

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

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

Windows Subsystem for Linux did not exist when this question was asked. It gave these results in my test:

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

This means that you need uname -r to distinguish it from native Linux.

伏妖词 2024-09-20 15:54:05

好的,这是我的方法。

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 中使用它

Ok, here is my way.

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
}

I use this in my dotfiles

栩栩如生 2024-09-20 15:54:05

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

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

所以,

[ -f /usr/bin/cygwin1.dll ]&& echo 是的,Cygwin 运行

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

I guess the uname answer is unbeatable, mainly in terms of cleanliness.

Although it takes a ridiculous time to execute, I found that testing for specific files presence also gives me good and quicker results, since I'm not invoking an executable:

So,

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

just uses a quick Bash file presence check. As I'm on Windows right now, I can't tell you any specific files for Linuxes and Mac OS X from my head, but I'm pretty sure they do exist. :-)

秋风の叶未落 2024-09-20 15:54:05

非常令人惊讶的是没有人提到 GNU config.guess 为了完整性

鉴于 bash 已经预期可以工作,应该不会有什么麻烦,因为 config.guess 主要是用 shell 语言实现的,并且预期可以正常工作。它确实依赖于一些有效的 uname 命令,但该命令几乎总是由可用 bash 的安装提供。并且几乎没有任何替代方案可以拥有更全面的支持平台集(除了基于它的平台,例如GNU Autoconf)。事实上,与通常的需要相比,它往往太长了。您可能拥有其中的一些有限子集。当许可证有问题时,您也可以避免直接使用它。

但针对 Windows 的一些注意事项:

  • Cygwin 和 MinGW(32) 是不同的平台,而 MSYS(2) 是 Cygwin 的变体 用于不同目的
    • MinGW 本机 Win32,因为它们不需要像 cygwin1.dllmsys-2.0.dll 这样的子系统 DLL(除了 Win32) 。 MinGW 程序通常使用与 MSVC 构建的程序完全相同的 DLL 集(即使使用相同的 libc),只是它们可能具有不同的 C++ 运行时依赖项(例如 libstdc++-6.dll+libgcc_s_ [sjlj/dw/seh]-X.dllmsvcpXXX.dll/vcruntimeXXX_1.dll),因为使用了不同的工具链。
  • 目前,GNU bash 无法构建为本机 Win32 程序,并且这一点将来也不太可能改变。但是,$PATH 中可能还有其他本机 Win32 程序,包括 uname.exe。 (实际上,这是 MSYS2 安装 运行 MinGW 环境之一 的预期情况,其中是使用 bash 和其他 MSYS2 工具以及 MinGW32 本机工具链的核心机制。)您应该在报告 CYGWIN 的路径中有一个 uname.exe > 或 MSYS 作为系统,而不是 MINGW 如果您的目标程序是 bash 而不是本机 Win32 程序。
  • 在极少数情况下,这些平台共享一些代码,例如,在 GCC 树中,它们统称为“cygming”,用于在 Windows 上运行的常见 PE 目标。通常,最好单独检测它们,然后在需要时将其委托给一些通用逻辑。

Quite surprising that no one mentions GNU config.guess for completeness.

Given that bash is already expected working, there should be few troubles because config.guess is mostly implemented in the shell language and it is expected just work. It does relies on some working uname command, but that should almost always provided by the installation where bash is available. And there are almost no alternatives can have a more comprehensive sets of supported platforms (except something based on it, e.g. GNU Autoconf). In fact it is often too lengthy compared to the usual needs. You may have some limited subset of it. You may also avoid to use it directly when the license is a problem.

But some caveats for Windows:

  • Cygwin and MinGW(32) are different platforms, and MSYS(2) is the variant like Cygwin for different purposes.
    • MinGW is the native Win32, as they need no subsystem DLLs (besides Win32) like cygwin1.dll or msys-2.0.dll. MinGW programs typically use exactly the same set of DLLs as programs built by MSVC (even with same libc), except that they may have different C++ runtime dependencies (e.g. libstdc++-6.dll+libgcc_s_[sjlj/dw/seh]-X.dll vs. msvcpXXX.dll/vcruntimeXXX_1.dll) due to different toolchains are used.
  • At current GNU bash can't be built as native a Win32 program, and this would not likely change in future. However, there can be other native Win32 programs in $PATH, including uname.exe. (Actually this is the expected case for MSYS2 a installation running one of the MinGW environments, which is the core mechanism to use bash and other MSYS2 tools together with MinGW32 native toolchains.) You should have a uname.exe in the path reporting CYGWIN or MSYS as the system, not MINGW one if you are targetting programs as bash rather than native Win32 ones.
  • In rare cases these platforms share some code, e.g. in GCC tree they are collectively named cygming stuff for common PE targets running on Windows. Normally they are better to be detected separately and then delegated to some common logic when needed.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文