目录
服役已久的 2015 年款 13 寸 MacBook Pro 当前运行起来实在有点吃力了,因此换电脑的计划逐渐提上日程。考虑到毒瘤的 Apple T2 这一因素,以及现在的 Mac 价格越来越高,我开始考虑其它品牌的笔记本。 首先,Mac 上诸多人性化的设计,是我们在 Windows 上首先需要找回的。 我们知道 macOS 有一个非常好的设计就是快速预览,俗称“一指禅”。幸好,在 Windows 上我们有类似的替代品。 对于 Mac 的终端,在 Windows 上现在我们有 Windows Terminal,这也是题图中出现的 Terminal。 该终端定制性很好,可以参阅官方文档做进一步的自定义。 我在 Mac 上的主力浏览器是 Safari,主要看中了它的高效能,因此我可以打开一大堆标签页。 Mac 以其强大的时间机器备份深受用户喜爱,遗憾的是至今在 Windows 上还尚未有能完全与时间机器匹敌的解决方案。不过,我们仍然可以使用“备份与还原 (Windows 7)” 来进行备份,只需前往控制面板寻找即可。 这里我们只需要备份系统映像即可。 你可以在组策略的计算机配置->管理模板->Windows 组件->Microsoft Edge 下找到“使收藏夹在 Internet Explorer 和 Microsoft Edge 之间保持同步”,并启用它。 偶尔我们可能会需要在 Windows 和其它操作系统之间切换。由于 Windows 默认不使用 UTC 时间作为 BIOS 时间,而其它系统通常使用,因此多系统切换会导致时间混乱。我们可以使 Windows 使用 UTC 时间。通过注册表: 微软基于 Chromium 推出了全新的 Edge。尽管它的表现也不错,但是旧版 Edge 中有许多令人喜爱的功能是新版 Edge 所没有的。因此我们可能不希望新版 Edge 取代它,而是选择安装 Beta 版 Edge Chromium 配合使用。 WSL,全称适用于 Linux 的 Windows 子系统(Windows Subsystem for Linux),可以说是 Windows 近年来吸引 macOS 开发者用户最大的杀手锏了。其中 WSL 分 WSL1 和 WSL2。 WSL1 是微软对 Linux 进行了 clean-room,然后实现出了一个兼容的 Linux 内核。但它并非真正的 Linux 内核,也有许多功能没有实现,例如它没有完整的网络栈,自然就没有了强大的 netfilter 子系统,以及 PID namespace 等。WSL2 则是将真正的 Linux 内核放入 Hyper-V 运行,并进行了一些修改使其与 Windows 配合。 我不否认 WSL2 具有一定的优越性,但 WSL1 有着更加统一的体验与更少的割裂感,因此目前我坚持使用 WSL1,仅使用 WSL2 作为 Docker 后端。本文该部分也以 WSL1 为主。 首先,在控制面板->程序与功能->打开或关闭 Windows 功能中,将“适用于 Linux 的 Windows 子系统”打开。 你当然可以在商店中安装 WSL,但是这样 WSL 的数据文件在 UWP 的数据文件夹中,这并不方便维护。因此我建议通过 tarball 安装。 下载后,我们可以通过 这一步操作是将 注意这里 当我们导入一个 WSL 发行版时,我们会发现默认用户为 root。而 对于 Linux 来说,服务的自启动是一个重要的功能。很不幸的是 WSL 的 init 并非 SysVinit 或者 systemd,而是微软开发的私有 init。这个 init 没有启动服务的功能。 对于 WSL2,或许可以使用 PID namespace 的一些骚操作实现启动 systemd,但 WSL1 不能。显然我们自行实现 systemd 的服务启动职能是比较困难的,且 cgroups 等等功能的缺失也让我们难以实现部分功能。因此我退而求其次,由于 WSL 不存在引导,我们只要部分实现 inittab 和服务启动即可。 以下以 Ubuntu 20.04 为例。 首先,我们通过 这样该脚本首先在 这样 init 等级就设为 3。 这时候我们需要配置 Windows 服务,你当然可以使用 Windows 自带的 sc 或者注册表。但是我个人更喜欢 nssm。但无论你使用什么,配置方法都是一样的。 其中 Ubuntu 为 WSL 发行版名称。 注意,WSL 发行版的所有权是属于单个用户的,因此这个服务需要以你的帐户的身份启动,你需要设置启动帐户为你的帐户。但是这里有一个坑点,如果你使用 Windows Hello 或者 PIN 码等方式登录操作系统,你需要注销然后使用密码登入的环境下进行服务启动帐户的设置,否则会鉴权失败。 至此,WSL 的服务配置已经完成。 在 WSL 中有许多奇技淫巧可以使得 WSL 与 Windows 更好地结合。 比如,我们可以安装一些 X Window 服务器例如 VcXsrv 或 X410 等来使用 Linux 程序的图形界面。只需安装这些程序,并在 WSL 中设置环境变量 我们还可以安装 Node.js 程序 macOS 的 有时候我们可能希望使用 WSL 中的程序播放音频,这时候我们可以安装 PulseAudio for Windows 并设置环境变量 使用 WSL 中的 git 时,我们会发现每次都需要输入凭据,这是因为 WSL 中没有钥匙串等凭据管理器,我们可以安装 Git for Windows,然后: 另外,我们可能希望 WSL 中访问的 Windows 卷能够正确设置权限,只需在 根据官方文档,Linux 权限在 DrvFS 下是以 NTFS metadata 的形式存储。因此对于 FAT 系列文件系统可能不能正常存储权限。 我们在 WSL 中运行 Windows 程序的时候通常需要添加 我们还可以使用 binfmt 来实现 vbs 等脚本的直接执行,不过限于篇幅在此按下不表,今后可能会开一个 blog 专门谈谈。 我们通过一个 Hyper-V 的 Linux 虚拟机来辅助 Windows。主要目的是绕开 UWP 环回限制使用代理,以及更好地使用 n2n 等服务。 首先,我们在控制面板->程序与功能->打开或关闭 Windows 功能中启用 Hyper-V。然后在 Hyper-V 管理器中新建一个交换机,我们称之为 假设我们在 Windows 上启动的代理监听于 这样我们把 我们可以在虚拟机中安装你喜欢的 HTTP 代理转换软件,这里以 polipo 为例,配置好 polipo 之后(假设监听端口 8123),就可以在 Windows 中设置代理为 这里我们用 n2n 举例,因为它在 Windows 上运行会比较令人烦躁。 然后,我们在虚拟机中配置 NAT 与 DNAT,即可几乎将虚拟机隐形,所有请求都好像是直接发向 Windows 的:
大概从去年开始,我就通过 Windows To Go 体验了一下现在的 Windows 10。不得不说和 2015 年的 Windows 10 相比有了巨大的提升,更加适合开发使用了。经过数个月的考察,时机已经成熟。
恰逢 Surface Book 3 发布,于是通过一些渠道,我成功以大约官网一半的价格得到了一台 15 寸顶配 16GB 内存与 1TB 硬盘的 Surface Book 2 作为主力机使用。
终于,我找回了 2015 年看 Surface Book 发布会时的尖叫。
找回熟悉的体验
空格键预览
它就是 QuickLook。
终端
对于这个终端,我们从中启动 WSL 的 shell 后,其工作目录通常是 Windows 的系统目录或者用户目录,如果想要让它使用 Linux 中用户的主目录,可以在相应的 profile 中设置如下:"startingDirectory" : "//wsl$/【WSL 发行版名】/home/【用户名】"
浏览器
而在 Windows 上,Edge(旧版)可以很好的贴合我的需求。
关于 Edge 的书签问题,详见备份
Windows 系统调优
Edge 书签与 IE 同步
但你也可以使用注册表:Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\MicrosoftEdge\Main]
"SyncFavoritesBetweenIEAndMicrosoftEdge"=dword:00000001
使用 UTC 时间
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation]
"RealTimeIsUniversal"=dword:00000001
屏蔽 Edge Chromium 更新
好在微软提供了工具包来屏蔽:MSEdge Blocker Toolkit
如果你不幸已经更新到 Edge Chromium,可以使用以下方法(摘编自Carton的回答 – 知乎)
cd "C:\Program Files (x86)\Microsoft\Edge\Application\83.0.478.61\Installer"
然后按回车,其中“83.0.478.61”是版本号,要与自己的Edge版本对应,路径视自己的情况更改,一般相同。setup.exe --uninstall --system-level --verbose-logging --force-uninstall
WSL 相关
安装与维护 WSL 发行版
Ubuntu 是提供了专供 wsl 的 rootfs 的,例如 Ubuntu 20.04 Focal Fossa 的 rootfs for WSL。wsl.exe
来导入发行版,例如:wsl.exe --import Ubuntu C:\WSL\Ubuntu C:\Users\Victor\Downloads\focal-server-cloudimg-amd64-wsl.rootfs.tar.gz
focal-server-cloudimg-amd64-wsl.rootfs.tar.gz
这个 tarball 作为发行版 Ubuntu 安装至 C:\WSL\Ubuntu
。wsl.exe
支持方便地导入和导出 WSL 发行版,因此,如果你想要备份你的发行版,一个很好的例子就是:wsl.exe --export Ubuntu Ubuntu.tar
wsl.exe
是可以将 tar 内容输出到 stdout 的,因此你可以方便地利用管道调用 gzip 等等。wsl.exe
本身是没有提供修改默认登录用户的功能的。好在我翻阅 WSL 在 GitHub 上的 Issue 列表时发现了一条 comment 提供了解决方法如下:Get-ItemProperty Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss\*\ DistributionName | Where-Object -Property DistributionName -eq 【发行版名】 | Set-ItemProperty -Name DefaultUid -Value 【待指定用户 UID】
服务开机自启
update-rc.d
,生成 rc.d 脚本,以供使用。
由于 WSL 不存在引导,因此我们需要借用 Windows 的服务来实现 WSL 的启动。
创建 /etc/rc.windows
,填入以下内容:#!/bin/sh
INIT_LEVEL=$(grep -ve '^#' /etc/inittab 2> /dev/null | grep 'initdefault' | head -n 1 | cut -d ':' -f 2)
if [ -n $INIT_LEVEL ]; then
printf
if [ $? -eq 0 ]; then
for service in /etc/rcS.d/S*; do
$service start
done
for service in /etc/rc${INIT_LEVEL}.d/S*; do
$service start
done
fi
fi
/etc/rc.local
/bin/login
/etc/inittab
找寻 initdefault 配置来确定用户需要的目标 init 等级,我们可以在 /etc/inittab
中填入:id:3:initdefault:
服务启动的二进制程序应当设置为 -d Ubuntu --user root /bin/sh /etc/rc.windows
Awesome WSL!
DISPLAY=0:0
。wsl-open
来模拟实现 macOS 中 open
或 Linux 桌面中的 xdg-open
的效果。pbcopy
和 pbpaste
这两个可以直接对剪贴板进行读写的命令也是深受用户喜爱的。在 WSL 中,我们可以通过直接调用 C:\bin
下我们可以这样写 pbpaste
:#!/bin/sh
"/mnt/c/bin/paste.exe" $@ | sed 's/\r$//g'
PULSE_SERVER=tcp:localhost
。git config --global credential.helper "/mnt/c/Program\ Files/Git/mingw64/libexec/git-core/git-credential-manager.exe"
/etc/wsl.conf
中配置:[automount]
enabled = true
options = "metadata,umask=22,fmask=11"
mountFsTab = false
.exe
后缀,这不够好。我们可以通过对 shell 的未找到命令的处理函数进行修改来实现不加 .exe
后缀执行。下面以 zsh 为例,bash 用户可自行修改:function command_not_found_handler {
WINCMD="cmd.exe"
PWSH="powershell.exe"
prog="$1"
shift
function _validate_cmdsuffix {
type ${prog}.$1 > /dev/null 2>&1
}
function _validate_cmdintc {
! ${WINCMD} /c help "$1" > /dev/null 2>&1
}
function _throw_command_not_found {
echo "zsh: command not found: $1" > /dev/stderr
return 127
}
if [ $(grep -e "\.(exe|com|bat|cmd)$" <<< "$prog") ]; then
_throw_command_not_found $prog
else
if
_validate_cmdsuffix exe || _validate_cmdsuffix com || _validate_cmdsuffix bat || _validate_cmdsuffix cmd || \
_validate_cmdintc ${prog}
then
${PWSH} ${prog} $@
else
_throw_command_not_found $prog
fi
fi
}
网络
基础配置
Router Network
。
然后新建一个 Linux 虚拟机,将其加入主网桥和 Router Network
。
这里,我们设置 Windows 在 Router Network
中的 IP 地址为 100.98.22.33
,虚拟机的 IP 地址为 100.98.22.1
。代理
127.0.0.1:1080
。
首先,我们需要配置 Windows 的 netsh 端口转发,将代理端口转给虚拟机可以连接的端口:netsh interface portproxy add v4tov4 listenport=1079 connectaddress=127.0.0.1 connectport=1080 listenaddress=100.98.22.33
100.98.22.33:1079
转发到 127.0.0.1:1080
。
然后我们配置 Windows 防火墙,在高级防火墙配置中建立一条自定义入站规则,协议类型选择 TCP,本地端口使用 1079,作用域中选择远程 IP 地址为下列 IP 地址,并把虚拟机的 IP 地址添加,操作为允许连接。http://100.98.22.1:8123
来实现代理。n2n
首先我们安装 n2n,该过程按下不表,之后可能会写一篇 blog 谈谈,这里假设 n2n 的 IP 地址为 10.11.20.2/24
。
我们首先需要在 Windows 上配置永久路由表:route.exe -p add 10.11.20.0 mask 255.255.255.0 100.98.22.1
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -A FORWARD -j ACCEPT
iptables -t nat -A POSTROUTING -s 100.98.22.33 -j MASQUERADE
iptables -t nat -A PREROUTING -d 10.11.20.2 -j DNAT --to-destination 100.98.22.33
好耶!
代理的话,似乎可以直接使用 Clash for Windows 的 TAP 模式。
TAP 模式确实不错,不过当时我不清楚为什么在我的电脑上 SSTap 和 Clash 的 TUN/TAP 模式性能都不太理想,因此就用了 Hyper-V 虚拟机。
其实这里 Hyper-V 虚拟机主要是方便跑 n2n,n2n 在 Windows 上原生跑实在太人间疾苦。