最的一些工作需要涉及到很多 windows 独占的引擎和工具,所以暂时还离不开 windows 环境(没法摸鱼),但又有炼丹需求,所以打算试试 WSL,安装一个可移动的,windows 友好的 ubuntu 实例。
安装 WSL Ubuntu#
直接去 Microsoft Store 获取 WSL Ubuntu 实例。
这里可能涉及到一些 Clash 用户无法打开 Store,只需要在 Clash 设置里设置 UWP Loopback,勾选 Store - Save 即可。
安装包可以在C:\Program Files\WindowsApps\CanonicalGroupLimited.Ubuntu22.04LTS_2204.5.10018.0_x64__79rhkp1fndgsc
找到,其大小恒定。
而真正的系统内容则存储在: %LocalAppData%\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc
因此有必要把他迁移到其他盘符。
提取安装包#
以管理员方式打开 power shell, 安装 windows linux 子系统支持
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
安装完毕后, 按 Y 重启。
之后可以设置 wsl 的模式,
wsl --set-default-version 1
wsl1 和 wsl2 的区别在于,wsl2 做到了系统的彻底隔离,类似虚拟机,而 wsl1 是把 linux 的文件直接呈现在 NTFS 系统中。如果设置了 wsl 2,安装的时候可能会出现错误
WslRegisterDistribution failed with error: 0x800701bc
这是因为没有对应 wsl2 的内核,需要 wsl 官网下载更新包
来到安装包位置,打包复制进移动硬盘(这里是 F:)
双击可执行程序安装。
在这里我遇到了一些问题,安装界面卡在 intalling ... 很久, github issue 提出了一个解决方案:I got the same issue, but found a workaround: you just have to use ctrl+c and then it will continue and ask you for a username and password
然后成功安装。 因为我们选择的是 wsl 1 模式,所以能够看到在 rootfs 文件夹下 linux 系统文件 F:\Ubuntu\rootfs
至此,可以再次打开刚才执行安装的可执行程序(Ubuntu2204)测试
清理内容#
在开始菜单中卸载 Ubuntu, 用来释放 C 盘的安装包。
从移动硬盘分离主机
来到注册表位置 :
计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss{*****}
最后一个位置是随机的GUID
,打开可以看到两个关键内容:
BasePath : F:\Ubunut DistributionName: Ubuntu-22.04
path
用来指示 wsl,linux 实例的目录(rootfs
),name 用来告知这个实例的名字(wsl –list
)
其余的几项分别是用来激活登录用户和设置 wsl 模式的值,总之,有了这个信息,可以使用命令行直接启动 wsl:
wsl -d Ubuntu-22.04
我们把这个注册表导出到 Ubuntu 目录:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss{8f49723d-d252-404e-b36a-e376ee44c835}]
"State"=dword:00000001
"DistributionName"="Ubuntu-22.04"
"Version"=dword:00000002
"BasePath"="F:\Ubuntu"
"Flags"=dword:00000007
"DefaultUid"=dword:000003e8
当我们需要在另一个主机上打开这个实例时,只需要修改 basepath 到当前移动硬盘在另一个主机上的盘符,(F: -> E:),然后双击这个注册表,把注册表安装进另一个主机即可。
如果是多个 wsl 实例,则需要注意不要重名
通过一个批处理文件实现。
@echo off
setlocal EnableDelayedExpansion
set batfilenam=%~nx0
set batdir=%~dp0
set batdir=%batdir:~0,-1%
set batdir2=%batdir:=\%
set ThisWslDistributionName=%~1
set UnixUser=%~2
REM =========== BAT PARAMETER CHECKING ==============
if not defined ThisWslDistributionName (
echo. Need a DistributionName as parameter.
echo. The DistributionName is a new name to be registered into Lxss service.
echo. This .bat is compatible with Win10.21H2 or above.
echo. Examples:
echo. %batfilenam% Ubuntu-22.04
echo. %batfilenam% Ubuntu-22.04 bob
exit /b 4
)
if not "" == "%~3" (
call :Echos Error: Only one or two parameter should be given.
exit /b 4
)
call :HasSpaceChar %ThisWslDistributionName%
if %ERRORLEVEL%==1 (
call :Echos Error: DistributionName must NOT have space char in it.
exit /b 4
)
if defined UnixUser (
call :HasSpaceChar %UnixUser%
if %ERRORLEVEL%==1 (
call :Echos Error: UnixUser must NOT have space char in it.
exit /b 4
)
set _u_param=-u %UnixUser%
) else (
set _u_param=
)
REM =========== ENV CHECKING ==============
set wsl1_checkdir=%batdir%\rootfs\root
set wsl1_seen=
if exist "%wsl1_checkdir%" set wsl1_seen=1
set wsl2_checkfile=%batdir%\ext4.vhdx
set wsl2_seen=
if exist "%wsl2_checkfile%" set wsl2_seen=1
if "%wsl1_seen%%wsl2_seen%" == "" (
call :Echos Error: No WSL file-system found in "%batdir%" .
call :Echos You should either have
call :Echos "%wsl1_checkdir%" ^(for WSL1^)
call :Echos or
call :Echos "%wsl2_checkfile%" ^(for WSL2^)
exit /b 4
)
REM =========== PREPARE .REG FILE ==============
REM We need to generate a GUID for current DistributionName,
REM We can ensure it being unique by calcuating %ThisWslDistributionName%.
echo %ThisWslDistributionName%> "%batdir%\wslname.tmp"
call :GetFileMD5 "%batdir%\wslname.tmp" md5
if not defined md5 (
call :Echos Error: Cannot generate a GUID for ThisWslDistributionName.
exit /b 4
)
set md5guid=%md5:~0,8%-%md5:~8,4%-%md5:~12,4%-%md5:~16,4%-%md5:~20,12%
rem For "Ubuntu-22.04", md5guid is
rem 2b0c8e79-b4a5-1bfc-49cd-4f344cbfe444
set md5finalchar=%md5:~31,1%
if not defined md5finalchar (
call :Echos Error: When generating MD5 for ThisWslDistributionName, certttil.exe returns expected result.
call :Echos md5=%md5%
exit /b 4
)
set badoutput=%md5:~32,1%
if defined badoutput (
call :Echos Error: When generating MD5 for ThisWslDistributionName, certttil.exe returns expected result.
call :Echos md5=%md5%
exit /b 4
)
set regfile=%batdir%\WSL-green.reg
echo Windows Registry Editor Version 5.00 >> "%regfile%"
echo.>> "%regfile%"
echo [HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Lxss{%md5guid%}]>> "%regfile%"
if defined wsl1_seen (
echo "Flags"=dword:00000007 >> "%regfile%"
set wslverhint=WSL1
) else if defined wsl2_seen (
echo "Flags"=dword:0000000f >> "%regfile%"
set wslverhint=WSL2
) else (
echo "wsl version not found" >> "%regfile%"
)
echo "BasePath"="%batdir2%" >> "%regfile%"
echo "DistributionName"="%ThisWslDistributionName%" >> "%regfile%"
type "%batdir%\WSL-green.reg.0" >> "%regfile%"
REM =========== IMPORTING REGISTRY ==============
call :Echos Registering WSL instance using:
call :Echos . WSL version = %wslverhint%
call :Echos . GUID = {%md5guid%}
call :Echos . DistributionName = %ThisWslDistributionName%
call :EchoAndExec reg import "%regfile%"
if not %ERRORLEVEL%==0 (
call :Echos Import registry file fail: %regfile%
pause
exit /b 4
)
title WSL - %ThisWslDistributionName%
call :EchoAndExec wsl -d %ThisWslDistributionName% %_u_param% --cd ~
if not %ERRORLEVEL%==0 (
echo.
echo "wsl -d" execution fail. Please check your bat file or Windows environment.
echo.
pause
exit /b 4
)
exit /b 0
REM =============================
REM ====== Functions Below ======
REM =============================
:Echos
REM This function preserves %ERRORLEVEL% for the caller,
REM and, LastError does NOT pollute the caller.
setlocal & set LastError=%ERRORLEVEL%
echo [%batfilenam%] %*
exit /b %LastError%
:EchoAndExec
echo [%batfilenam%] EXEC: %*
call %*
exit /b %ERRORLEVEL%
:HasSpaceChar
REM Check if the input params has space-char in it.
REM
REM call :HasSpaceChar param1 param2
REM call :HasSpaceChar "param1 param2"
REM -- ERRORLEVEL above will be 1, means yes.
REM
REM call :HasSpaceChar ans param1-param2
REM -- ERRORLEVEL above will be 0, means no.
REM
REM If no input param, consider it "have" spacechar.
setlocal & set input=%*
if not defined input exit /b 1
set input=%input:"=#%
set count=0
for %%i in (%input%) do (
set /A count=count+1
)
if %count% == 1 (
exit /b 0
) else (
exit /b 1
)
:GetFileMD5
REM Thanks to: https://github.com/npocmaka/batch.scripts/blob/master/fileUtils/md5.bat
REM Usage:
REM call :GetFileMD5
set "md5="
for /f "skip=1 tokens=* delims=" %%# in ('certutil -hashfile "%~f1" MD5') do (
if not defined md5 (
for %%Z in (%%#) do set "md5=!md5!%%Z"
)
)
endlocal && (set "%~2=%md5%")
后续只需要双击 bat 文件即可实现即插即用