如何检查程序是不是在 Windows 上的 Ubuntu 上的 Bash 中运行,而不仅仅是普通的 Ubuntu?

Posted

技术标签:

【中文标题】如何检查程序是不是在 Windows 上的 Ubuntu 上的 Bash 中运行,而不仅仅是普通的 Ubuntu?【英文标题】:How to check if a program is run in Bash on Ubuntu on Windows and not just plain Ubuntu?如何检查程序是否在 Windows 上的 Ubuntu 上的 Bash 中运行,而不仅仅是普通的 Ubuntu? 【发布时间】:2016-10-31 08:52:31 【问题描述】:

非常简单,找出您所在操作系统的常用位置似乎与 Ubuntu for Windows 上的普通 Ubuntu 相同。例如,uname -a 与原生 GNU/Linux 安装相同,/etc/os-version 与 Ubuntu Trusty Tahr 安装相同。

我唯一能想到的就是检查/mnt/c/Windows 是否存在,但我不确定这是否是万无一失的想法。

【问题讨论】:

【参考方案1】:

防故障测试:

grep -qi -- '-WSL' /proc/sys/kernel/osrelease || test -f /proc/sys/fs/binfmt_misc/WSLInterop

理由:

    解析 /proc/version 很危险。它可能包含误导性信息(想象一下由 microsoft 编译的 gcc)。最好只解析内核版本。 WSL2:没有任何 WSL... 环境变量。 (WINDOWS 10 20H2 build 19042.1165,UBUNTU 18.04.5 LTS,内核 5.10.16.3-microsoft-standard-WSL2) 如果内核版本测试失败,则会进行第二次测试。

注意:有两个测试,从第一个测试中我删除了 microsoft 和 grep 仅在 -WSL 上。在这种最简单的形式中,它几乎是万无一失的。

binfmt_misc 模板文件(用于在 linux 下运行 Windows 可执行文件)同时存在于 WSL 和 WSL2 上。

【讨论】:

嗯,主要是防故障的。有人可能是病态的并将/proc/sys/fs/binfmt_misc/WSLInterop 放在不同的发行版上:-)。是的,该文件仍然存在于 WSL1 下。 真的,您没有得到任何WSL_* 变量吗?我认为发行版名称由/init 填充。我也在运行 19042.1165,但我还没有更新我的内核。【参考方案2】:

由于 WSL1 和 WSL2 的区别在于第一个在容器中运行,而第二个在虚拟机中运行,我们可以使用“systemd-detect-virt --container”来区分这两种环境。

if [ -n "$WSL_DISTRO_NAME" ]; then
  # In WSL but which one?
  virt_container="$(systemd-detect-virt --container)"
  case $virt_container in
    wsl)
      echo "This is WSL 1"
      ;;
    none)
      echo "This is WSL 2"
      ;;
    *)
      echo "Don't known $virt_container"
      ;;
  esac
fi

【讨论】:

【参考方案3】:
if [[ `uname -a | grep -i linux | grep -i microsoft`  != "" ]]; then echo "microsoft wsl"; fi;

或多行语法:

if [[ `uname -a | grep -i linux | grep -i microsoft`  != "" ]]; then 
    echo "microsoft wsl" 
fi

注意:条件必须用反引号括起来,否则会产生错误,例如:

zsh: parse error: condition expected: uname

【讨论】:

【参考方案4】:

@per-lundberg 更新答案:

if [[ -n "$IS_WSL" || -n "$WSL_DISTRO_NAME" ]]; then
    echo "This is WSL"
else
    echo "This is not WSL"
fi

注意:IS_WSL 存在于旧版本中(使用 lxrun),而WSL_DISTRO_NAME 存在于当前版本中(来自 Microsoft Store)。

【讨论】:

逻辑反了,第一种情况是wsl: if [[ ! -z "$IS_WSL" && ! -z "$WSL_DISTRO_NAME" ]];然后回显“你在wsl中!” else echo "你不在wsl中!"菲 这是检查 WSL 的最快和最有效的方法。不需要真正通过 grep 或读取 /proc 或调用像 uname 这样的外部可执行文件。 此方法比公认的答案好 100%,因为它在 WSL2 下运行自定义编译内核时也有效。其他存在的环境变量是WSL_INTEROPWSLENV 嗯,我找不到任何以 WSL 开头的环境变量。 WINDOWS 10 20H2 build 19042.1165,UBUNTU 18.04.5 LTS,内核 5.10.16.3-microsoft-standard-WSL2 @Massimo - 我正在使用相同的 Windows 版本,以上版本工作正常。我将环境变量设置为WSL_DISTRO_NAME=Ubuntu-20.04。使用命令printenv检查。【参考方案5】:

以下内容适用于 Windows 10、macOS 和 Linux 上的 bash:

#!/bin/bash
set -e
if grep -qEi "(Microsoft|WSL)" /proc/version &> /dev/null ; then
    echo "Windows 10 Bash"
else
    echo "Anything else"
fi

您需要根据 WSL 开发人员 Ben Hillis 的 this comment 检查“Microsoft”和“WSL”:

目前这可能是最好的方法。我不能 保证我们永远不会更改这些 ProcFs 文件的内容,但是 我认为我们不太可能将其更改为不 包含“Microsoft”或“WSL”。

/proc/sys/kernel/osrelease
/proc/version

grep 的大小写将被忽略。在 WSL2 中,/proc/version 给出小写的 microsoft。

【讨论】:

不需要 grep,if [[ "$(< /proc/version)" == *@(Microsoft|WSL)* ]]; then ... 更快。 评论补充说,在 WSL 2 中它说“microsoft”,全部小写。 当心!在解析 /proc/version 时,它可能包含误导性信息(想象一下由 microsoft 编译的 gcc)。最好只解析内核版本:/proc/sys/kernel/osrelease 另外请注意,可以为 WSL2 编译您自己的内核(最初提出问题时并非如此)。假设 控制环境并且可以确定不是这种情况,这个答案很好。如果您需要能够处理您不知道 WSL 正在运行股票-Microsoft 内核的罕见极端情况,那么可能需要像@Massimo 建议的那样使用其他方法。【参考方案6】:

除了Windows Subsystem for Linux 2,我还需要测试macOS

这对我们来说是最简单的事情。

if [[ $OSTYPE == darwin* ]]; then
  # macOS
elif [[ "$(</proc/sys/kernel/osrelease)" == *microsoft* ]]; then
  # WSL2
else
  # Other *nix distro.
fi

注意:if 订单很重要。在 macOS 上查看 proc/version 时会出现此错误。 /proc/version: No such file or directory

在最佳答案的 cmets 中向@Niklas Holm 和 @Marc Cornellà 致敬,让我朝着正确的 WSL 检查方向前进。

【讨论】:

【参考方案7】:

对于 WSL2,我们无法再通过内核版本进行检测,因为它在 Hyper-V 中运行实际的 Linux 内核。但是,它仍然可以调用每个 Windows 安装中存在的explorer.exe。所以我们可以...

if [ -x "$(command -v explorer.exe)" ]; then
echo "We are running on WSL"
fi

这应该是一种更通用的方法来检测脚本是否在 WSL 上运行。

编辑:见上面的答案。我忘记算上 Msys2 等类 Unix 环境了。

【讨论】:

wsl2 在/proc/versionosrelease 上仍然使用Microsoft 标题【参考方案8】:

不用我做任何特别的事情,这些环境变量似乎已经设置好了:

$ set | grep WSL
IS_WSL='Linux version 4.4.0-18362-Microsoft (Microsoft@Microsoft.com) (gcc version 5.4.0 (GCC) ) #1-Microsoft Mon Mar 18 12:02:00 PST 2019'
WSLENV=
WSL_DISTRO_NAME=Debian

因此,在这种情况下,类似以下 sn-p 的内容也应该有效(我自己使用的示例):

if [ ! -z "$IS_WSL" ]; then
    alias code='/mnt/c/Users/per/AppData/Local/Programs/Microsoft\ VS\ Code/Code.exe'
fi

(请注意,从技术上讲,-z does not check if the variable is unset,只是它是空的;实际上,这在这种情况下已经足够好用了。开头的 ! 用于否定检查。)

【讨论】:

IS_WSL 不再可用,但有一个名为 WSL_DISTRO_NAME 的新变量。【参考方案9】:

Windows 10 Pro Insider Preview Build 18917 中适用于 Linux 2 (WSL 2) 的 Windows 子系统

/proc/version 包含:

Linux 版本 4.19.43-microsoft-standard (oe-user@oe-host)(gcc 版本 7.3.0 (GCC))#1 SMP...

【讨论】:

【参考方案10】:

如果您在 Bash 中并想避免使用 fork

is_wsl=0
read os </proc/sys/kernel/osrelease || :
if [[ "$os" == *Microsoft ]]; then
  is_wsl=1
fi

【讨论】:

【参考方案11】:

这是我在 .bashrc 中添加的内容

if [[ $(uname -v | sed -rE 's/^#[0-9]3,-(\S+).+/\1/') == "Microsoft" ]]; then
  # WSL-specific code
fi
uname -v 获取#379-Microsoft Wed Mar 06 19:16:00 PST 2019 格式的内核版本,sed 表达式拉出Microsoft 字符串。

【讨论】:

【参考方案12】:

我刚刚为我的 .bashrc 想出了这个,用于将一些 WSL 项添加到 $PATH。

适用于 1703 年。不确定是否更早的版本。

if [[ $(uname -r) =~ Microsoft$ ]]; then
    foo
fi

【讨论】:

【参考方案13】:

我也一直在寻找检测方法。到目前为止,我已经找到了 2 个。

/proc/sys/kernel/osrelease 是“3.4.0-Microsoft”

/proc/version 是“Linux 版本 3.4.0-Microsoft (Microsoft@Microsoft.com) (gcc 版本 4.7 (GCC)) #1 SMP PREEMPT 2014 年 12 月 31 日星期三 14:42:53 PST"

如果你只是使用默认安装的 Ubuntu 发行版,使用它们应该没有问题,如they said that it would be unlikely for them to set either to something that doesn't contain "Microsoft" or "WSL"。

但是,如果您要安装不同的 Linux 发行版,我很确定 /proc/sys/kernel/osrelease/proc/version 的内容会改变,因为该发行版不会由 Microsoft 编译。

【讨论】:

因为 procfs 是由 Windows 模拟的,所以它应该(原则上,如 Github 评论中所述)始终包含那些 Microsoft 字符串,无论使用何种发行版,所以最后一段对我来说似乎很困惑。 @GuillemJover,我猜这取决于假设的其他发行版是否使用 WSL。我不知道 Cygwin 是否模拟了该功能,但如果是,我不认为它会说 Microsoft。 (虽然我猜“Microsoft Windows”这个短语可能会出现在字符串中。我打赌“Microsoft@Microsoft.com”不会!) @HarryJohnston 在 Cygwin 下,/proc/version 包含一个以“CYGWIN_NT”开头的字符串,而/proc/sys/kernel/osrelease 根本不存在。

以上是关于如何检查程序是不是在 Windows 上的 Ubuntu 上的 Bash 中运行,而不仅仅是普通的 Ubuntu?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查是不是在 C# 中安装了 Windows 服务

如何检查窗口在 Windows 窗体中是不是真的可见?

如何在运行应用程序的系统上检查所需的 Windows API 功能是不是可用?

如何检查某个表是不是正在被 AWS Redshift 上的某个程序或视图使用

如何检查我的应用程序是不是由 WatchOS 上的 Siri 快捷方式启动?

如何检查文件是不是存在于 Windows 应用商店应用程序中?