我试图要求 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
更新答案:
此问题背后的核心问题已在最新的 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_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
也能正确处理此问题。
在我个人看来,grep 输出可能是一个非常不稳定的解决方案,因为输出的格式可能会随时改变。
我发现自己能够通过运行以下命令来检测是否安装了特定的发行版:
wsl --distribution "{distribution}" --exec true
或简称:
wsl -d "{distribution}" -e true
这将尝试在名为
true
的发行版中运行 {distribution}
命令。
如果未找到分发版,wsl
会退出并显示错误代码 -1
。
如果分布存在,则执行命令 true
,该命令始终以代码 0
退出。