玩转 Windows 10 中的 Linux 子系统

2016-07-25
13分钟阅读时长

在今年的 Build 2016 上,微软向全世界介绍了他们还处于 Beta 阶段的 Windows 下的 Linux 子系统 Windows Subsystem for Linux (WSL),它可以让开发者们在 Windows 10 下通过 Bash shell 运行原生的 Ubuntu 用户态二进制程序。如果你参与了 Windows Insider 计划,你就可以在最新的 Windows 10 年度升级版的 Insider 构建版中体验这个功能了。

Web 开发人员们不用再苦恼所用的 Windows 开发平台上没有合适的 Linux 工具和库了。WSL 是由 Windows 内核团队与 Canonical 合作设计和开发的,可以让 Windows 10 下的开发者们在拥有 Windows 中那些强力支持之外,还能使用 Linux 下丰富的开发环境与工具,而不用启动到另外的操作系统或者使用虚拟机。这绝对是一个“来自开发者,服务开发者”的 Windows 10 特色,它的目的是让开发者们每天的开发工作都变得顺畅而便捷。

在本文中,我会展示给你一些我认为非常有趣的功能,以及告诉你一些可以让你找到更多信息的资源。首先,我会展示 WSL 所集成的那些主要命令(比如 ssh)是如何操作服务器和设备的。其次,我会演示使用 Bash 脚本是如何以简明的方式来自动化执行任务的。其三,我会利用极棒的命令行编译器、一些其它工具以及对 *nix 兼容的能力来玩一个轻量级的古典黑客级游戏: NetHack。最后,我会展示如何使用已有的 Python 脚本和其它来自网上的脚本。

从我的第一台 286 上运行的 Windows 3.0 开始,Windows 就一直是我的主要操作系统和开发环境。不过,我身边也有很多 Linux 服务器和设备。从树莓派和路由器/网关设备这样的物联网设备,到 Minecraft 服务器,它们堆满了我的办公室的每个角落。而我经常要从我的主工作站中去管理和配置这些 Linux 计算机。

管理服务器和设备

我在我的家中运行着一台无显示器的 Ubuntu Minecraft 服务器,这是我去年给我十岁大的儿子的圣诞礼物,但是它已经变成了我的玩具而不是他的(好吧,主要是我的玩具)。我以前在我的 Windows 10 电脑上使用几个客户端来管理它,不过我现在想使用 Windows 中的 Bash 里面的 ssh 命令行来管理它。使用类似 PuTTY 或来自 Cygwin 的 Tera Term 这样的应用当然也可以,但是我想试试真正原生而自然的体验也是一种不错的选择。Cygwin 就像是在披萨店订购的披萨一样,好吃,但是没有那种氛围。

我已经使用 WSL 中的 ssh-keygenssh-copy-id 设置好了公私密钥对,所以使用 ssh 只需要如下简单输入即可:

$ ssh <username>@<server>

我还为此创建了一个别名,以便更快一些。这是一个标准的 Linux/Bash 功能:

$ alias mc='ssh <user>@<server>'

现在,我要访问我的 Minecraft 服务器只需要在 Windows 10 下的 Bash 中输入“mc”即可。

当然,同样的方法你也可以用于任何 Linux 上的 Web 或数据库服务器上,甚至树莓派或其它的物联网设备也可以。

在终端里面进行 ssh 只是为了方便而已,不过当你在 shell 中工作时,如果还有类似 apt、node、Ruby、Python 等等工具时,你就有了自动化各种工作的可能。

远程脚本

假如说你有一大堆 Linux 服务器和设备,而你要在它们上面执行一个远程命令的话,如果已经配置好公私密钥对,你就可以在 Bash 中直接远程执行命令。

举个例子说,想知道远程服务器自从上次重启后已经运行了多长时间了,你只需要输入:

$ ssh <user>@<server> 'last -x|grep reboot'

ssh 会连接到该服务器并执行 last -x 命令,然后搜索包含“reboot”的一行。我在我的 Ubuntu Minecraft 服务器上运行的结果如下:

reboot   system boot  4.4.0-28-generic Thu Jul  7 08:14   still running

这只是一台服务器,如果你有许多服务器的话,你可以自动化这个过程。我在 WSL 里我的主目录下创建了一个名为 servers.txt 的文件,它包含了一系列 Linux 服务器/设备的名称,每个一行。然后我就可以创建一个脚本来读取这个文件。

在使用了很多年像树莓派这样的设备之后,我已经变成了一个 nano 人(在 VMS 上我是一个 LSEdit 人),下面是我用我喜爱的 nano 编辑器打开的脚本。

当然,你也可以使用 vim 、 emacs 或者其它可以用在 Ubuntu 终端上的编辑器。

该脚本是 Bash 脚本,要执行该脚本,输入:

$ ./foreachserver.sh 'last -x|grep reboot'

它将迭代输出文件中的每个服务器/设备,然后通过 ssh 远程执行该命令。当然,这个例子非常简单,但是你可以像这样把你的本地脚本或其它命令变成远程的。Bash 脚本语言足够丰富,所以你可以使用它来完成你的大多数远程管理任务。你可以用你下载到 WSL 或远程系统中的其它应用来扩展它的使用。

你是否需要在工作中把本地的 Windows 文件或资源用于其它的 Linux 计算机吗?或者,你根本不使用 Linux ?Bash 可以操作本地的 Windows 文件或资源,还是说它就是一个完全独立的环境?

使用 Windows 文件

WSL 系统可以通过 /mnt/<盘号>/ 目录(挂载点)来访问你计算机上的文件系统。举个例子,你的 Windows 上的 C:\ 和 D:\ 根目录可以在 WSL 中相应地通过 /mnt/c 和 /mnt/d 访问。当你要把你的 Windows 下的项目文件、下载的内容和其它文件用到 Linux/Bash 之中时这很有用。

上图显示的两个目录分别对应于我的计算机上的 SSD 和硬盘:

这是逻辑挂载,所以当你在 shell 中使用类似 mount 这样的命令时它们不会显示。但是它们可以如你预期的那样工作。举个例子,在 Windows 中,我在我的 C 盘根目录下放了一个名为 test.txt 的文件,我可以在 WSL 中如下访问它:

在 Build Tour 大会期间,我们要确保所有的演示都可以在没有互联网时也能正常工作(你绝不会知道会场的网络是什么样子的) ,所以为了让 Bash/WSL 可以演示 Git 操作,该演示访问的是本地计算机上的 Windows 文件,我在 Windows 上的 C:\git\NetHack 下设置一个本地仓库。 要在 WSL 中进行 clone 操作,我执行了如下命令:

$ git –clone file:///mnt/c/git/NetHack

该命令告诉 git 使用 file:// 协议,并 clone 了位于 /mnt/c/git/NetHack 下的仓库。你可以以类似的方式来访问你的 Windows 下的所有文件。

警示:就像在其它终端中一样,如果你不小心的话,你可以在 Bash 中修改/删除 Windows 文件系统中的文件。举个例子,你可以像下面这样来干掉你的 Windows ,假如你有合适的权限的话。

$ rm -rf /mnt/c/  [千万别试!][千万别试!][千万别试!]

我之所以郑重提醒是因为我们很多人都是刚刚接触 Linux 命令,它们不是 Windows 命令。

这种可以让文件系统集成到一起的魔法来自 DrvFs。如果你希望了解该文件系统的更多细节,以及它是如何工作在 WSL 中的,WSL 团队为此写了一篇详细的文章

当然, 文件系统访问只是 WSL 其中的一部分功能而已,许多开发任务还需要通过 HTTP 或其它网络协议访问远程资源。

发起 HTTP 请求

从脚本或命令行而不是从一个编译好的程序或 Web 页面上发起 REST 或其它 HTTP(或 FTP)请求是很有用的。就像在大多数 Linux 发行版一样,WSL 也包括了类似 curl 或 wget 获取资源这样的标准功能,它们可以用来发起 HTTP 或者其它网络请求。举个例子,下面是使用 curl 对 Github 发起 REST 请求来获取我个人的属性信息:

$ curl -i https://api.github.com/users/Psychlist1972
HTTP/1.1 200 OK
Server: GitHub.com
Date: Wed, 13 Jul 2016 02:38:08 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 1319
Status: 200 OK
...
{
  "login": "Psychlist1972",
  "avatar_url": "https://avatars.githubusercontent.com/u/1421146?v=3",
  "url": "https://api.github.com/users/Psychlist1972",
  "name": "Pete Brown",
  "company": "Microsoft",
   ...
}
$

你可以用它和 Bash 脚本来创建一个 REST API 的快速测试客户端,也可以用来探测一个 Web 页面或服务器并报告其返回的状态。它用来从网上下载文件也很棒,你可以简单地重定向输出到一个文件而不是在屏幕上显示它:

$ curl -i https://api.github.com/users/Psychlist1972 > pete.json

我也是一个 PowerShell 用户,甚至还使用 Windows 10 MIDI in PowerShell 创建了一些有趣的扩展,也修复过出现在特定的录音硬件设备上的一些文件问题。作为长时间的 .NET 开发者和爱好者,我经常使用和扩展 PowerShell 以满足我的项目需求。但是 PowerShell 并不是一个可以运行所有的那些 Bash 脚本和针对 Linux 的开源工具的地方。我希望以一种最简单、最舒服的方式来完成这些任务,在某种意义上,这意味着我们需要在 Bash 中完成它们。

我已经一掠而过的介绍了 Bash、Bash 脚本以及你可以在 shell 中完成的任务。到目前为止,我谈论的都是有助于开发工作的那些功能。但是在 WSL 中实际的开发和编译工作是怎样的?我在 Build Tour 大会上演示了下面这个部分。

Build Tour 大会上的演示:NetHack

这个夏初,来自微软的讲演者们向大家演示了一些来自 Windows 和微软云上的很酷的开发者新功能。作为其中的一部分,我以一种好玩的方式来演示了 WSL,而且这是一种和开发者们相关的方式。

我个人想要展示使用 git 和一些传统的终端开发工具,我已经写好了 Bash 的演示程序,包括了这些基础的东西(用 Python 和 Ruby 写的“Hello World”),不过我还是想要更有冲击力一些。

我回想起我在大学的时光,那时我们在 Unix(DEC Ultrix 及 SunOS)和 VAX/VMS 之间折腾,Unix 几乎全是命令行环境。在我们学校,绝大多数使用图形工作站的用户只是为了在不同的窗口打开多个终端会话而已,当然,会在桌面背景放上一张超酷的月相图。大部分学生都是使用 VT-220 终端来打开他们的会话(学校离波士顿不远,所以我们有很多 DEC 设备)。

那时,计算机系的学生们主要玩两大游戏:MUD (主要是 lpMUD 和当时刚出的 DikuMUD)和 NetHack。NetHack 和其它的 Roguelikes 类游戏被视为历史上最有影响力的游戏之一,它们是许多现在流行的地牢冒险和角色扮演类游戏的鼻祖。

NetHack 有很长的历史,现在的它包含了来自几十年前的几十万行 *nix 代码,以及后来补充的一些代码。该游戏使用 curses (及其替代品)作为终端交互方式,需要通过 lex、 yacc(或 flex 和 bison)和 cc(或 gcc),以及一堆其它的开发工具构建。

它是由 C 语言编写的,并包括了一些用 Bourne shell 编写的复杂的脚本配置功能。我觉得它是一个体现 WSL 和 Bash on Windows 10 的开发者能力的不错而有趣的方式。由于使用了 curses(在 Linux 和 WSL 中是 libncurses 库),它也可以用来展示 Windows 10 中命令行窗口中的终端模拟能力。

以前,在我们的分时 Ultrix 服务器上从源代码构建 NetHack 要花费掉我们很多时间,而现在我的个人计算机上只需要几分钟就可以搞定。我喜欢这种技术进步。在 Linux 或 WSL 上配置和编译 NetHack 有容易和复杂两种方式。为了节省时间,我们会以容易的方式来进行。

前置需求

首先,更新你的 WSL 环境,确保你的软件是最新的。在安装新的软件包之前,这是一个好的做法。

$ sudo apt update
$ sudo apt upgrade

然后,安装必须的开发工具。最简单的办法就是使用 build-essential 软件包,它包括了 Linux 开发者构建以 C/C++ 开发的软件时所需的绝大部分程序。

$ sudo apt install build-essential

这要花几分钟。如果你想更加深入地了解,你可以分别安装 gcc、gdb、make、flex、bison 以及 NetHack 文档中提到的其它工具。不过如果你是一位开发者,有时候你可能还需要一些其它工具。 build-essential 基本上提供了你所需的工具集。

然后,安装 git。如你所想,很容易:

$ sudo apt install git

就像在 Linux 中一样,你可以添加一个 git 的 PPA 来获取较新的版本,不过这里我们有一个就行了。

最后,我们需要安装 curses(实际上是 ncurses)来进行终端屏幕交互。

$ sudo apt install libncurses-dev

当我们完成这些步骤之后,就可以开始构建 NetHack 了。

构建 NetHack

官方的 NetHack 仓库放在 GitHub 上,首先我们需要把它抓取下来放到我们的主目录里面。

$ cd ~$ git clone http://github.com/NetHack/NetHack

因为 NetHack 支持很多种操作系统,所以我们需要做一些基础配置来告诉它我们使用的是 Linux,并且用开源的 gcc 代替了了 Unix 上 cc 的作用。

如我所提到的,这有好几种办法可以实现。有些人想很周到,将这些配置信息放到了 hints 文件中。相信我,使用 hints 文件会避免遇到该 GitHub 仓库中提到的很多麻烦。在 README 文件和其它文档中并没有着重提到如何使用 hints 文件,我们可以这样做:

$ cd NetHack/sys/unix
$ ./setup.sh hints/linux

这将会设置 Makefile 正确的使用 Linux 下的工具、库及其路径。这个设置脚本很强大,它做了大量的配置工作,很高兴它在 WSL 中工作的也很好。如果你很好奇这个脚本是如何写的,你可以使用你的编辑器打开它一窥究竟。

然后,开始最终的构建:

$ cd ~/NetHack
$ make all

构建完成之后,你需要安装它。这其实就是将可执行文件复制到目标位置:

$ make install

它会安装到你的 ~/nh 文件夹下, NetHack 放在 ~/nh/install/games 目录,名为 nethack。要运行它,切换到该目录(或输入完整路径)并输入:

$ cd ~/nh/install/games
$ nethack

然后,屏幕会清屏并显示你可以玩 NetHack 了。注意,所有的东西都是在这个 Ubuntu Linux 环境中完成的,根本不需要任何 Windows 特有的东西。

玩 NetHack

由于终端游戏的局限性和 NetHack 的复杂性,这里只能一带而过。对于初次接触它的人来说,还有一些神秘的地方,不过我觉得我们程序员们从来不怕挑战未知。

方向键和 vi(vim)中的一样,HJKL 是左、下、上、右。要退出游戏,你可以在地下城顶层找到楼梯出口然后使用它就可以,或者直接按下 CTRL-C 强制退出。

在 NetHack 中, @ 符号代表你自己,每一层都由房间、走廊、门,和向上及向下的楼梯组成。怪物宝箱和物品以各种 ASCII 字符组成,你慢慢就会熟悉它们。为了符合 Roguelikes 游戏规范,并没有存盘功能,你只有一条命。如果你死了就只能重玩,地下城环境是随机生成的,各种物品也是打乱放置的。

NetHack 游戏的目的是在地下城生存,收集金子和物品,尽可能的干掉各种怪物。除了这些目的之外,你就是不断在其中玩来找它们。规则大致遵循“龙与地下城(DnD)”的武器、技能等规则。

下面的 NetHack 截屏上可以看到有三个房间和两个走廊。向上的楼梯在左上角的房间里,我现在在右上角的房间,还有一些宝箱和其它物品。

如果在你的游戏中没有显示颜色,可以创建一个名为 ~/.nethackrc 的文件,并放入如下内容:

OPTIONS=color:true,dark_room:true,menucolors:true

注:如果 ASCII 字符图形不是你的菜,但是你喜欢这种类型的游戏,你可以在微软商店搜索“roguelike”来找到视觉上更好看的这种游戏。

当然,NetHack 很古老了,可能只有特定年龄段的人们喜欢它。不过,构建它用到了大量重要的开发工具和 *nix 操作系统功能,也包括终端模拟功能。从这里可以看到,从 gcc、gdb、make、bison 和 flex 到更现代一些的 git,都在 WSL 里面工作的很好。

如果你想看看 Build Tour 大会上的演示,你可以在 Build Tour 加拿大大会上看到这个讲演。WSL 的这部分演示在 6:20 开始。

希望你能喜欢在 NetHack 地下城中的探险。

C 和 C++ 都很伟大,就像其他的那些经典的开发工具一样。你甚至还可以用普通的 Bash 脚本做到很多。不过,也有很多开发者喜欢用 Python 做为他们的脚本语言。

Python

你可以在网上找到很多 Python 脚本的例子,这意味着 Python 越来越流行,也越来越有用了。当然,大多数情况下这些例子都是运行在 Linux 下的。在过去,这就需要我们有另外一台安装着 Linux 的机器来运行它们,或者使用虚拟机和多引导,否则就需要修改一些东西才能让他们运行在 Windows 下的 Python 环境中。

这是都不是无法解决的问题,但是它会日渐消磨开发人员每天的生活。通过 WSL,不用折腾你就拥有了一个兼容的、具有 Python 功能和 shell 变量的子系统。

要安装最新的 Python 开发版本和 Python 包安装器 pip,在 Bash 中执行如下命令:

$ sudo apt install python-pip python-dev
$ sudo pip install --upgrade pip

现在 Python 安装好了,我要展示给你如何从网上获取一个典型的 Linux 下的 Python 例子并让它直接工作起来。我去 Activestate Python 菜谱站找一个排名第一的 Python 例子。好吧,我走眼了,排名第一的是打印出整数名称的脚本,这看起来没啥意思,所以我选择了第二名:俄罗斯方块。我们每天都能看到 Python 出现在各种地方,所以这次让我们去玩另外一个游戏。

我打开了 nano 编辑器,从 Windows 上的浏览器中打开的页面上复制了这 275 行 Python 代码,然后粘贴到我的 WSL 终端窗口终端中的 nano 中,并保存为 tetris.py ,然后执行它:

$ python tetris.py

它马上就清屏并出现了俄罗斯方块的游戏。同 NetHack 一样,你可以使用同样的 vi 标准的方向键来移动(以前是使用鼠标和 WSAD 键来移动,而右手使用 HJKL 键更方便)。

如我所提到的,你当然可以不用 WSL 就在 Windows 中运行 Python。然而,要想快速简便,不用修改 Linux 下的 Python 代码,只需要简单的复制粘贴代码即可运行,则可以极大的提高开发者的效率。

这是真的。这并不是要替代 Windows 原生的工具,比如 Python、PowerShell、C# 等等,而是当你需要在现代的开发工作流程中快速而有效地完成一些事情时,可以避免种种折腾。

包括 Bash、Python 以及其它所有的 Linux 原生的命令行开发工具,WSL 为我的开发工作提供了所有需要的工具。这不是一个 Linux 服务器,甚至也不是一个完整的客户端,相反,它就是一个可以让我避免每天折腾,让我在 Windows 上开发更有效率、更有快感的一个东西!


重置你的 WSL 环境

随便去试吧,如果你搞坏了你的 WSL 环境,它很容易重新安装。在进行之前,请确保做好了任何重要内容的备份。

C:\> lxrun.exe /uninstall /full
C:\> lxrun.exe /install

你使用 Bash 和 WSL 的感觉如何?

我们希望 WSL ,特别是 Bash 可以在 Windows 10 中帮你带来更高的效率,减少每天的开发中的折腾。

你对 Windows 10 上的 WSL 怎么看?你喜欢使用它吗?

开发团队做了大量的工作希望让 WSL 成为一个为开发者提供的强大的终端工具。如果你有任何反馈或运行出现问题,我们推荐你查看一下 GitHub 反馈页面,以及 用户之声的反馈和投票站点。我们真的希望听到你的声音。

更多参考与延伸阅读

Linux shell 编程是一个庞大的话题,在网上有很多这方面的内容。如果你还不够熟悉它们,想要了解更多,可以看看各种 Bash 教程。可以从这一份开始

还有一些其他的参考资料也许对你有用:

哦,当然,要更多的了解 NetHack,请访问 NetHack 主站