如何使用 Bash 和 `wsl.exe` 让 WSL 检查发行版是否存在?

问题描述 投票:0回答:2

我试图要求 WSL 检查发行版是否存在,例如,

wsl.exe -l -v
输出:

  NAME                   STATE           VERSION
  Arch-Linux             Running         2
* Ubuntu                 Running         2
  docker-desktop         Running         2
  docker-desktop-data    Running         2

我需要让 WSL 检查

desktop-desktop-data
Arch
是否存在。

这是我的小 Bash 代码。我用了几种不同的方法进行了测试,没有任何效果。

# Distribution name: Ubuntu
wsl_distro_name="docker-desktop"

# WSL command to find the distribution name
wsl_command=`wsl.exe -l -v | grep -iq '^$wsl_distro_name' | awk '{print $2}'`

if [[ "$wsl_command" ]]; then
    echo "Distro found"
    exit 0
else
    echo "Not found"
    exit 1
fi
bash windows-subsystem-for-linux
2个回答
2
投票

更新答案

此问题背后的核心问题已在最新的 WSL 预览版 (0.64.0) 中得到修复或至少得到改进,但请注意,目前仅适用于 Windows 11 用户。

为了避免破坏依赖(或解决)该问题的旧代码,修复是选择加入的。 设置

WSL_UTF8
环境变量的值为
1
(并且仅在我的测试中,该值)将导致
wsl.exe
的正确/预期输出。

请注意,如果在inside WSL 中使用此环境变量,您还需要将其添加到

WSLENV
,以便它通过 Interop“传回”Windows。

例如,为了供您使用,以下内容现在可以使用:

export WSL_UTF8=1
WSLENV="$WSLENV":WSL_UTF8

wsl_distro_name="docker-desktop-data"
wsl.exe -l -v | grep -q "\s${wsl_distro_name}\s" && echo "Found" || echo "Not found"f

对于较旧的 WSL 安装

简短回答:

wsl_distro_name="docker-desktop-data"
wsl.exe -l -v | iconv -f UTF-16 | grep -q "\s${wsl_distro_name}\s" && echo "Found" || echo "Not found"

解释

您的示例发生了一些事情:

  • 首先,最让您困扰的可能是 WSL 错误(在这个问题中更详细地介绍),它导致输出采用损坏的 UTF-16 编码。 您可以通过

    wsl.exe | hexdump -C
    在某种程度上看到这一点,它将在每个常规字符后面显示空字节字符。

    该部分的解决方案是将其运行一遍

    iconv -f utf16
    。 例如:

    wsl.exe -l -v | iconv -f UTF-16
    

我猜您在尝试解决上述错误时可能在代码中引入了以下一些错误:

  • 您的

    $wsl_distro_name
    中的单引号包含
    grep
    ,这会禁用 Bash 中的字符串插值。 你需要在那里加双引号。

  • ^
    在正则表达式的开头不起作用,因为
    wsl.exe -l -v
    输出的前几个字符中有空格(和/或星号)。 最好使用
    "\s$wsl_distro_name\s
    来查找被空格包围的发行版名称。

    这也将阻止表达式找到“部分”发行版名称。 如果没有它,“docker-desktop”将匹配“docker-desktop”和/或“docker-desktop-data”。

  • grep -q
    禁用输出,仅在找到时返回
    0
    状态代码,如果未找到则返回
    1
    。 由于您尝试将 grep 输出捕获到
    $wsl_command
    中,因此结果将始终为空。 您可以删除
    -q
    以捕获输出,或者继续使用
    -q
    并测试状态代码。

  • 鉴于您的

    if
    声明,您似乎可能期望输出无论如何都是状态结果,但测试
    "$wsl_command"
    不起作用,也不会通过反引号捕获输出。 那看起来更像是:

    wsl_distro_name="docker-desktop-data"
    wsl.exe -l -v | iconv -f UTF-16 | grep -q "\s${wsl_distro_name}\s"
    if [[ $? -eq 0 ]]; then
        echo Found
    fi
    

    $?
    变量保存最后一个命令的退出代码。

    或者:

    wsl_distro_name="docker-desktop-data"
    wsl_distro_result=$(wsl.exe -l -v | iconv -f UTF-16 | grep -o "\s${wsl_distro_name}\s.*" | awk '{print $2}')
    if [[ -n "$wsl_distro_result" ]]; then
        echo "Found ${wsl_distro_name} and it is ${wsl_distro_result}."
    else
        echo "${wsl_distro_name} not found."
    fi
    

    请注意,我在该片段中将

    -o
    选项添加到了
    grep
    中。 默认分布在第一个字段中会有一个星号,这意味着我们需要对其进行“标准化”,以便
    awk
    的第二个字段始终是状态。

  • 最后,建议使用

    $()
    而不是反引号。 请参阅这个问题,但请注意 POSIX 规范说:“不建议使用反引号的命令替换。”

  • 旁注:如果由于某种原因您需要在 Alpine 中运行此程序,请确保安装

    gnu-libiconv
    软件包,以便
    iconv
    也能正确处理此问题。


0
投票

在我个人看来,grep 输出可能是一个非常不稳定的解决方案,因为输出的格式可能会随时改变。

我发现自己能够通过运行以下命令来检测是否安装了特定的发行版:

wsl --distribution "{distribution}" --exec true

或简称:

wsl -d "{distribution}" -e true

这将尝试在名为

true
的发行版中运行
{distribution}
命令。 如果未找到分发版,
wsl
会退出并显示错误代码
-1
。 如果分布存在,则执行命令
true
,该命令始终以代码
0
退出。

© www.soinside.com 2019 - 2024. All rights reserved.