最的一些工作需要涉及到很多 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 文件即可實現即插即用