树莓派-2-Linux-和-Windows10-学习手册-全-

树莓派 2 Linux 和 Windows10 学习手册(全)

原文:Learn Raspberry Pi 2 with Linux and Windows 10

协议:CC BY-NC-SA 4.0

一、你的第一个树莓派

这一章是我们最终动手的地方。如果您急于开始运行,决定跳过介绍,这很好;你不会错过这一章的任何关键内容。但是,请注意在不久的将来去参观一下这个介绍,因为它会给你很多关于 Pi 的背景知识,以及它的特别之处。

现在,回到脏手!我们将从打开 Pi 的包装开始,并浏览您实际启动和运行它所需的一系列东西。一旦我们把所有的东西都连接起来,我们就需要为它的运行挑选一些东西——在这个例子中,是 Raspbian Linux(稍后会详细介绍)。一旦我们运行了 Raspbian,我们仍然需要对它进行配置,有些选项是技术性的,并且是特定于 Linux 的;但是不要担心,我们也有你。为了圆满完成这一章,我们将沐浴在 Raspbian 桌面的光辉中,然后前往第二章看看我们可以用它做些什么。

你新烤的圆饼来了

好了,邮递员刚刚送来了你期待已久的包裹,在急切地撕开带衬垫的信封后,你只剩下一个小盒子,(小是关键词)。你只是情不自禁地往信封深处看,看看是否有什么东西在底部徘徊。如果目测没有发现任何东西,毫无疑问,你会继续使用古老的忠实方法,把信封倒过来,摇一摇。虽然你可能会抖掉包装单(不知何故,它们似乎总是超级粘在里面),但你不会找到其他任何东西。

亲爱的读者,当你点一杯树莓派时,这就是你将要得到的全部(见图 1-1 )。

A978-1-4842-1162-5_1_Fig1_HTML.jpg

图 1-1。

What falls out of the envelope WHY A PICTURE OF JUST A BOX AND SOME BITS?

诚实的原因是,当这一切出现时,我们的第一个想法是,一定有什么东西不见了。是的,当你订购时,网站会告诉你这是你将得到的全部,这真的很有意义。

我们要强调的是,这是你得到的全部,还不足以让你的 Pi 挂上号,投入业务。你还需要一些其他的东西(你可能已经有了一些或者全部),在开始的时候强调这一点是很重要的。在下一节中,我们将介绍您实际需要的入门工具包。

如果你还没有订购 Pi(或者正在等待它出现在邮件中),图 1-2 显示一个坐在空白 DVD 旁边。

A978-1-4842-1162-5_1_Fig2_HTML.jpg

图 1-2。

A Raspberry Pi next to a blank DVD

尽管圆周率的大小是众所周知的,而且它装在一个如此小的盒子里,但直到你真正把它拿在手里,你才会意识到它有多小!在“啊”了一声之后(以及其他碰巧听到他们声音的人),我们觉得是时候开始表演了。

这就是事情突然停止的地方。我们有了圆周率,但我们才刚刚意识到,我们根本不知道我们实际上需要什么来让它运行。尽管我们对这一切并不陌生,但我们已经让自己陷入了这一时刻,无论出于什么原因,都没有考虑到 Pi 需要任何特殊的东西(或者至少是你的普通极客类型的人不会在家里挂着的东西)。

如果你没有直接从德克斯特的实验室里拿出一柜子的杂物,你可能需要收拾一些东西。幸运的是,它们都很容易找到,你应该可以在当地的电脑商店买到你需要的任何东西。如果你不想去寻宝,许多公司会提供你需要的一切入门套件。因为这些套件变化很快,所以找到可用套件的最佳方式是上网搜索“raspberry pi starter kit”。

配料清单

为了把你的圆饼烤得完美,你需要以下原料:

  • 树莓派
  • 微型 USB 引线(用于电源)
  • USB 电源适配器(也用于电源)
  • HDMI 引线:Type A to Type A(连接显示器或电视)
  • HDMI 显示器
  • 微型 SD 卡:8 GB 至 64 GB(用于存储 Windows 物联网需要 10 级)
  • 微型 SD 卡读卡器
  • USB 键盘和鼠标

微型 USB 引线

如果你碰巧有一部安卓手机或 Kindle,很有可能你已经得到了一条线索,你可以重新使用它来驱动 Pi。这条导线实际上并不是用来传输数据的,尽管你可以从 USB 端口获取电力(你可以将其插入你的主 PC 或笔记本电脑),但你不能将 USB 连接用于其他任何事情。不同类型的 USB 连接器很难描述,如果你还没有见过一个。请看图 1-3 中的一些例子。

A978-1-4842-1162-5_1_Fig3_HTML.jpg

图 1-3。

Different types of USB connectors Warning

尽管运气好的话,您可以从 USB 端口运行原始 Pi,但 Raspberry Pi 2 消耗的功率几乎是原始 Pi 的四倍,而且由于非协商 USB 仅提供少量电流,您无法从 USB 端口运行新 Pi。相反,你需要一个大功率的电源,比如那些用来给平板电脑充电的电源。请注意,即使他们声称提供足够的电力,他们也可能不会好好对待你的 Pi。如果您的 Pi 崩溃,连接网络有问题或通常有奇怪的行为,请首先检查您的电源。

你感兴趣的连接器是左边的第一个,称为微型 USB。请小心,因为在快速检查时,微型 USB 插头很容易被误认为迷你 USB 插头(左侧第二个)。你最不想做的事情就是专程去商店,然后回来却发现你拿错了!

USB 电源适配器

如上所述,一个普通的 USB 端口可以为 A 型 Pi(没有内置以太网的那种)供电,但对于现代 Pi,你需要一个更强大的东西。

幸运的是,大量的设备已经采用 USB 作为充电方式,这意味着你可以非常便宜和容易地获得电源适配器。至于选择哪种适配器,这实际上取决于个人选择。然而,由于 B 型需要 800 毫安而没有插入任何其他东西,并且您总是希望有一点扩展空间,您可能应该争取获得一个至少可以提供 1000 毫安(或 1 安培)并且最好是 2000 毫安(2 安培)的适配器。从我们高度科学的测试(逛遍无数店铺,眯着眼看包装标签)来看,似乎 1000 ma 其实是最常见的额定值。我们确实遇到了一些额定为 500 毫安的,虽然这对于大多数 USB 设备来说已经足够了,但对于您的需求来说还不够。

HDMI 引线

在过去的几年里,HDMI 已经成为将无数设备连接到显示器和电视的事实上的标准。这真的很方便,因为这意味着如果一个设备支持 HDMI,它可以很容易地连接到任何支持它的显示器。这听起来可能不那么令人印象深刻,但就在不久前,电视和显示器还是非常独立的东西,通常没有直接的方式连接,比如说,将计算机连接到电视或 VCR 连接到显示器(尽管有趣的是,如果你回到 20 年前,所有的家用计算机都直接连接到电视(例如,Commodore 64 或 Spectrum))。当然,你可以得到特殊的硬件,一些高端设备确实提供了一系列不同的连接器,但作为一个规则,这两个世界并没有真正混合。

幸运的是,Pi 使用 HDMI,所以我们可以忽略过去的烦恼。要将您的 Pi 连接到显示器,您需要一根“A 型到 A 型”导线。A 型是您在电视机或显示器背面可以找到的尺寸;你所要做的就是找到一根导线,通过 HDMI 将某个设备连接到电视上,并且两端尺寸相同。大多数消费电子产品使用 A 型,所以如果你有一台 Xbox 360 或你的笔记本电脑有 HDMI,你很可能已经有了正确类型的线索。

支持 HDMI 的显示器

你可能已经看到了这一点,但你需要某种支持 HDMI 的显示器。由于近年来被广泛采用,几乎每台新电视都配有一个或多个 HDMI 端口,大多数新显示器也是如此。如今,在电视上看到三个或四个端口是相当常见的,因为你需要这么多来连接你所有的新数字设备。

确定您的电视或显示器是否支持 HDMI 非常容易。你所要做的就是寻找一个物理 HDMI 端口。你更有可能在你的电视上找到它,而不是在你的显示器上,但是现在许多甚至更基本的显示器似乎都支持它。

在我们的例子中,结果是我们老化的显示器不支持 HDMI,尽管客厅的电视支持。当然,作为主电视意味着人们想在上面看电视,不可否认,我们不希望盘腿坐在大电视前的地板上,试图说服一个私家侦探开机。最后,我们决定买一个支持它的新显示器。虽然我们可以买一个 DVI 转换器,但我们决定不能错过获得一个新的闪亮玩具的机会。

如果你不能重复使用你的电视或电脑显示器,你应该能够很容易地得到一台支持 HDMI 的基本电视或显示器。

微型 SD 卡

大多数计算机使用某种硬盘作为它们的主要存储形式。即使笔记本电脑大小的磁盘也比 Pi 大,尽管较新的固态硬盘(SSD)型号消耗的功率很少,但它们肯定会大大增加 Pi 所需的功率。幸运的是,我们有一个替代方案。我们可以借用相机已经使用多年的技术:闪存,而不是使用硬盘这样的重型设备。尽管这些卡在空间和性能上无法与硬盘相提并论,但它们在电力使用方面非常出色,尽管它们比以前的同类产品更小;64 GB(您的 Pi 的最大值)仍然是一个相当可观的数量,可能比您的 Pi 需要的还要多。

微型 SD 卡是标准化的,所以没有太多要说的。如果可以的话,你确实想得到一张高性能卡(通常被称为 10 级卡),但它们最终都做同样的工作。也就是说,我们听说过一些微型 SD 卡没有与 Pi 一起工作,但如果你坚持使用一个知名品牌,你会得到一个 10 级卡,你应该没事。Linux 在卡的性能上还是挺宽容的,但是 Windows 10 IoT 好像很挑剔。我们只能让它在 10 级 SD 上工作,这似乎得到了微软最新文档的支持。如果你想试用 Windows,你肯定需要一个 10 级的 SD 卡。

由于目前有许多不同类型的存储卡,图 1-4 显示了微型 SD 卡的实际外观。

A978-1-4842-1162-5_1_Fig4_HTML.jpg

图 1-4。

SD card with micro SD and adapter

最左边的卡是你典型的 SD 卡;最右边是一个微型 SD 卡。它们在智能手机(特别是基于 Android 的手机)中的使用已经变得非常流行,因为大多数手机都配有小卡(就存储空间而言),所以购买更大的卡或在手机包装中加入一张卡并不罕见。如果你碰巧有一个这样的东西,你可以把它和你的 Pi 一起使用。

微型 SD 卡读卡器

现在你有了你的微型 SD 卡,你需要一些方法来实际使用它。Pi 为您提供保护,并内置了一个微型 SD 卡插槽。然而,它在设备上实际上没有任何其他存储,所以它实际上是一个空白,直到你插入一个安装了有用的东西(如 Linux)的 SD 卡。问题是,要把 Linux 放在卡上,你需要一个已经启动并运行的设备,它还能读写卡。这是一个典型的两难处境。即使你可以借用别人已经安装了 Linux 的卡,你也不能简单地把卡换掉,因为一旦你这么做了,你就再也没有 Linux 了!

再次感谢数码相机的普及,许多电脑都内置了读卡器。许多(通常被称为媒体个人电脑)带有一系列插槽,适用于各种不同的卡类型。所以很可能你已经有了一种阅读卡片的方法。如果你还没有读卡器,你可以从当地的电脑商店买到便宜的多卡读卡器。它们通常不贵,并且支持许多不同类型的卡。在你交出你的血汗钱之前,确保它有一个微型 SD 卡插槽(由于某些原因,通常隐藏在不同的一侧)!作为参考,我们使用的适配器类似于图 1-5 中的适配器。

A978-1-4842-1162-5_1_Fig5_HTML.jpg

图 1-5。

Multicard reader (micro SD reader is on the left edge near the bottom)

USB 键盘和鼠标

最后但并非最不重要的是良好的旧键盘和鼠标。尽管 Pi 很高级,但它还没有心灵感应,所以你需要一些方法来控制它。这是常识,但是随着现代计算机通常配备无线键盘和鼠标,以及相当多的使用蓝牙而没有 USB 适配器的计算机(甚至一些有适配器的计算机也已知会导致问题),您可能会发现您当前的键盘和鼠标无法与您的新玩具一起工作(恐怕 Pi 上没有蓝牙)。这里真的没有必要像任何标准的键盘和鼠标一样详细介绍,这主要是提醒你在出去购买 Pi 制作材料之前检查一下你实际上有什么,以避免当你回到家发现你完全被卡住时的无尽沮丧。

呼,我们完了!

我们终于拥有了我们需要的一切!将所有这些东西挂在您的 Pi 上非常容易,特别是因为每个项目都有独特的形状,所以它只能放入一个插槽中(见图 1-6 中的成品 Pi)。

A978-1-4842-1162-5_1_Fig6_HTML.jpg

图 1-6。

A fully loaded Pi

如果你把所有东西都放在一起,插上电源,打开你的电视,你应该会看到…一个全黑的屏幕。

不要慌!

当你的个人电脑或笔记本电脑启动时,有一个叫 BIOS 的软件为你启动一切。它测试内存,设置基本显示,并允许您的所有设备初始化。在一些机器上(特别是苹果的),机器会有一个 EFI 而不是 BIOS。对于所有的意图和目的(至少从我们的角度来看),它们基本上是等价的。不管使用什么技术,最终是这个系统将控制权交给你的引导装载程序,这个软件负责启动你的操作系统。BIOS 本质上是非常嘈杂的,如果你出错了,它要么会发出很多哔哔声(带有一些你只能在 3 年前扔进垃圾箱的 BIOS 手册中找到的神奇数字代码),要么在屏幕上显示一些有用但神秘的消息。简而言之,它可能做不到你想要的,但至少你知道你的电脑还活着。虽然它有一个红色的小 LED“亮着”,但除非它的 SD 卡上有一个可启动的操作系统,否则 Pi 不会做任何事情。如果你期待某种闪屏或其他生命迹象(举起手;我们知道我们是),你运气不好(可能认为你有一个死了的 Pi)。

现在你知道了你需要什么来恢复 Pi 的生命(一个可引导的操作系统),是时候进入我们的主计划的第二阶段,给我们一些 Linux 了!

Linux 操作系统

由于这是一本针对初学者的书,我们将花点时间来谈谈 Linux,它来自哪里,它有什么特别之处,以及一些时常让人犯错的小陷阱。如果你已经知道这些东西(或者根本不关心),请随意跳到下一节“下载 NOOBS”对于那些想快速复习的人来说,继续读下去吧。

什么是 Linux?

啊,这个简单的问题打开了一个很多人都想方设法避免的大麻烦。原因是,在技术术语中,Linux 意味着一件事,但在一般的讲话中,它往往意味着另一件事。当谈到一般的操作系统时,我们认为微软视窗和苹果 OSX 是独立的整体。如果你说“我运行 Windows”,每个人都知道你在说什么。有了 Linux,就有点不一样了。

Linux 只是一个操作系统内核,这意味着它处理所有低级的零碎东西,如处理设备驱动程序,并提供对网络和硬盘的轻松访问。真正让 Linux 变得可用的是围绕它的所有软件。这没什么大问题,但是当你意识到人们对应该用什么软件包装它有不同的看法时,事情就变得复杂了。谈到计算,没有简单或次要的观点!

由于这个软件是开源的,任何人都可以用他们喜欢的任何方式把它组装起来,人们已经能够构建他们自己的 Linux 发行版。这是一个以 Linux 为核心的操作系统,但其周围的生态系统是为满足构建它的人的目标而建立的。例如,Red Hat Enterprise Linux (RHEL)被构建为健壮、可支持和长期稳定的。另一方面,Fedora 大约每 6 个月发布一次,每个版本都有最新最好的东西。Gentoo 要求您从源代码构建您的软件(因此它可以完全针对您的机器进行优化),Debian 竭尽全力以引入新功能为代价来保持稳定和安全。

OPEN SOURCE

在过去,当计算机价格高达数百万美元时,销售的是机器本身,而不是其上运行的应用程序。为了让你买他们的机器,一家公司为你编写软件是很常见的做法。直到计算机成为商品,价值才突然体现在软件中,公司开始保护他们编写的软件。做到这一点的一个方法是提供没有源代码的现成软件(这实际上是如何制作软件的蓝图)。这意味着你不能改变软件或做出改进来适应你不断变化的需求。

许多人认为软件应该总是附带源代码,这样人们就可以进行修改。开源围绕着人们能够自由交换、修改和集体改进软件的想法。只有当源代码被免费提供并且被允许(通过开放源码许可)进行这些修改时,才能做到这一点。

整本书都可以并且已经写了这个主题,但是你可以找到彼得几年前在他的大学里关于这个主题的演讲: http://www.youtube.com/watch?v=c-1LQIGh6cI

那么哪个最好呢?嗯,那要看你的需求了!没有完美的分布。最适合特定工作的人。对于 Pi,官方支持的平台是 Raspbian,它基于 Debian 发行版。因为它是受支持的,也因为它是最容易使用的(而且很可能是出现问题时更新和修复最快的),所以在本书中我们将坚持使用 Raspbian。如果你确实喜欢稍微不同的东西,Brendan Horan 的书(也来自 Apress),《实用树莓 Pi》将向你深入展示如何安装 Fedora,以及(如果你感觉特别勇敢)如何定制 Gentoo!

当 Linux 内核在 20 世纪 90 年代初首次亮相时,没有人真正意识到它将对计算世界产生的巨大影响。在此之前,开源软件已经存在了很长时间,并且已经发布了无数用于 UNIX 平台的工具(比如令人敬畏的 GCC 编译器)。然而,它们只是工具和软件包。他们仍然需要一个专有的操作系统来运行(当时唯一可用的操作系统)。为了与开源精神完全兼容,我们需要一个开源内核来驱动这些系统,而这正是 Linux 所提供的。虽然许多人会谈论这是如何给计算世界带来自由和希望的,但是我们将把你从这个特定的演讲中拯救出来(尽管不可否认它有相当多的真实性),并且简单地说是 Linux 内核真正把开源带到了普通大众的眼前。

现在全世界都有了 Linux,我们到底能用它做什么?几乎任何我们喜欢的东西——比如在我们的 Pi 上免费安装。

noob 简介

在这本书的第一版中,我们下载了一个 Raspbian 图像文件。当时,所有不同的 Pi 发行版都是作为图像文件分发的。你所要做的就是下载感兴趣的图像,并把它写到你的 SD 卡上。

在过去的几年里,不仅仅是 Pi 的硬件有所改进。现在,您可以下载一个 Pi 安装程序,它甚至更容易设置,并提供了一个完整的操作系统列表供您选择(尽管我们仍将使用 Raspian,请查看“为什么使用 Raspian”侧栏)。

NOOBS 的开发是为了让 Pi 用户能够以最少的麻烦和头疼来选择和安装操作系统。对于经验丰富的用户来说,写一张 SD 卡并不麻烦,但对于大多数用户来说,这是一件非常陌生的事情。这也意味着理解成像是如何工作的,以及复制一个文件和把它写成图像之间的区别。

对 NOOBS 来说,这已经成为过去。首先,不是下载一个图像文件,而是下载一个 zip 文件,这是现在几乎每个人都熟悉的东西。然后将该 zip 文件的内容直接提取到 SD 卡上。好吧,就这样,你完了!只需弹出 SD 卡,启动您的 Pi 就可以了。

那么这是如何工作的呢?嗯,在你的普通电脑上,你需要设置好一切,这样 BIOS 就能找到操作系统并启动它。Pi 的不同之处在于,它不附带传统意义上的固件,而是从 SD 卡加载所有内容。这使得启动有点慢,但是使得 Pi 基金会很容易更新一些东西,否则需要特殊的工具来更新。因此,Pi 在 SD 卡上寻找一个特定的文件,并简单地执行它。在 NOOBS 的例子中,你正在运行一个安装程序,从那里,你可以选择你想要安装的操作系统——所有这些都通过一个漂亮的图形界面!

两个角落

你可以下载两个版本的 NOOBS。第一个是完整的安装程序,简称为 NOOBS,第二个是 NOOBS 建兴。他们之间唯一的实质性区别是,NOOBS 与拉斯比安和 NOOBS 建兴不附带任何东西。请记住,NOOBS 是一个安装程序,而不是操作系统本身,所以它需要有一种方法来检索你感兴趣的操作系统。在所有情况下,如果你不想拉斯扁,NOOBS 将上网,并从互联网上下载发布。如果你真的想要拉斯扁(老实说,你可能真的想要),那么你还不如得到完整版的 NOOBS。另一方面,如果你只对其他操作系统感兴趣,下载完整版绝对没有好处,你应该坚持使用 NOOBS 精简版。

下载 noob

无论你喜欢哪个版本的 NOOBS,你都可以通过图 1-7 所示的 Raspberry Pi 下载网站获得。

A978-1-4842-1162-5_1_Fig7_HTML.jpg

图 1-7。

Pick your NOOBS

https://www.raspberrypi.org/downloads/

正如我们之前提到的,有两个版本可供下载。如果你正在阅读这本书,那么我们强烈建议你选择完整版的 NOOBS,因为你会想要安装 Raspbian。不可否认的是,你仍然可以用 NOOBS lite 来做这件事,但是如果你想安装一些 Pi,你就必须在每次安装时有效地下载 Raspbian。

WHY RASPBIAN?

正如您在下载页面上看到的,有许多发行版可供选择,尤其是如果您在其他地方使用过 Linux,您可能会倾向于选择 Raspbian 以外的发行版。然而,在下载这个奇特的发行版之前,您应该知道大多数使用 Pi 的人都运行 Raspbian——因此大多数支持、博客文章和教程(更不用说这本书)都是基于它的。这意味着如果你选择了其他的事情,如果事情没有按计划进行,你会发现很难得到帮助。

另一个更微妙的问题是,Raspberry Pi 是基于 ARM 的设备。它的工作方式和你的电脑不太一样。例如,Pi 没有 PCI 总线,所以任何希望有 PCI 总线的工具(而且不止一个)都不能工作。这些其他发行版也有不少缺陷,它们可能不如 Raspbian 维护得好。简而言之,如果你不选择拉斯边开始,你将承担更多的工作。

把 NOOBS 放到你的 SD 卡上

"把 Raspbian 放到你的 SD 卡上并不像简单地拷贝文件那么简单."–在第一版中,我们就是这样开始这一部分的。然而今天,它就像将文件复制到 SD 卡一样简单。首先,我们需要确保您的 SD 卡已准备好使用。在本例中,我们将使用 Windows,因为这是大多数人都会使用的。然而,如果你使用的是 Mac,这个过程基本上是一样的,你可能不会有麻烦。

首先让我们插入 SD 卡。在“This PC”下,我们可以看到卡已被检测到(图 1-8 ):

A978-1-4842-1162-5_1_Fig8_HTML.jpg

图 1-8。

Freshly inserted SD card

这是一张从包装上直接拿下来的卡片(说真的,我还在流血,因为我试图把它从“易开”包装上撕下来)。正如你所看到的,它上面没有文件,这是安装 NOOBS 的一个重要前提(图 1-9 ):

A978-1-4842-1162-5_1_Fig9_HTML.jpg

图 1-9。

The card is empty

到目前为止一切顺利,现在我们需要做的就是打开 NOOBS 的 zip 文件,并将内容直接提取到这个磁盘中。如果你没有做任何特别的事情,你的浏览器会将 NOOBS 下载到你的“下载”文件夹中。你正在寻找一个看起来像这样的图标(图 1-10 ):

A978-1-4842-1162-5_1_Fig10_HTML.jpg

图 1-10。

What you’ll see in Explorer

当你双击打开它时,(假设你没有安装一个不同的应用程序来处理 zip 文件,如 WinZip)你会看到看起来像一个普通的文件夹,里面有文件(图 1-11 ):

A978-1-4842-1162-5_1_Fig11_HTML.jpg

图 1-11。

The contents of the NOOBS zip file

现在我们只需要提取它。如果你点击“提取”,你会看到一个弹出菜单。你可以忽略左边的东西,你想要右边的“全部提取”图标 1-12 ):

A978-1-4842-1162-5_1_Fig12_HTML.jpg

图 1-12。

Extract all

如果你已经遵循了这些步骤,你将在这个阶段领先,因为你已经有一个干净的 SD 卡插入你的电脑了。在前面的例子中,我们向您展示了我们的 SD 卡被拾取为“E:”。我们点击浏览并选择我们的 SD 卡,你应该做同样的事情。当它返回主屏幕时,它将只显示设备名称,在我们的例子中当然是“E”:(图 1-13 ):

A978-1-4842-1162-5_1_Fig13_HTML.jpg

图 1-13。

Extract everything to the SD card

一旦你选择了你的 SD 卡,你可以按下提取按钮。Windows 会给你一个漂亮的进度条。如果你的电脑和我们的一样,这将需要一点时间,所以现在可能是一个很好的时间去拿咖啡。Windows 总共花了大约五分钟的时间将所有文件解压到 SD 卡上。我们使用的是 10 级卡,所以如果你使用的是稍旧的卡(比如 4 级卡),那么你可能会发现它会花更长的时间(图 1-14 ):

A978-1-4842-1162-5_1_Fig14_HTML.jpg

图 1-14。

This can take a while to copy, but at least it’s pretty!

完成后,它会打开您的 SD 卡,并显示您的文件。如果一切正常,它应该与我们之前在 zip 文件中看到的完全相同。如果你看到类似下面的屏幕截图,那么你就成功了。现在剩下的就是实际尝试用它启动你的 Pi(图 1-15 ):

A978-1-4842-1162-5_1_Fig15_HTML.jpg

图 1-15。

What your SD card should look like after you’re done

好吧,这有点乏味,但是相信我们,这比我们必须使用的旧方法要简单得多。所以事不宜迟,让我们看看我们是否可以预订您的 Pi(图 1-13 )!

第一次开机

终于是时候启动你的 Pi 了!有了新镜像的 SD 卡,我们终于可以开始了。插入键盘、鼠标和显示器,并将 SD 卡插入 Pi。你现在所要做的就是接上电源线,你就可以开始了!一切正常,您最初应该会看到如图 1-16 所示的屏幕。

A978-1-4842-1162-5_1_Fig16_HTML.jpg

图 1-16。

The Pi’s first boot—it lives! If you can see something similar, congratulations, your Pi is up and running! You can skip to the next section. If not, there are a few common things that might have gone wrong

首先要检查的是您的 Pi 是否有一个漂亮的红色发光电源 LED。现在我们知道这听起来是显而易见的,我们知道这可能是你检查的第一件事,但是不检查它也是最容易犯的错误。如果你的桌子看起来像我们的一样,你会有一大堆电缆。不难看出您可能插错了电缆,或者您使用的电缆实际上没有插上电源(例如,一些笔记本电脑在睡眠时会关闭 USB 电源)。不管怎样,这是你应该首先检查的,因为如果你犯了一个错误,只有你会知道。这比在论坛上进行长时间的讨论,试图获得帮助,然后才意识到哎呀!你忘了插上电源。

第二件要检查的事情是你是否在电视或显示器上选择了正确的输入。如今,大多数电视都有多个输入,显示器通常不会默认 HDMI(我们的没有),即使这是它们接收的唯一输入信号。显然,我们不能告诉你如何准确地修复或检查这个,因为这完全取决于你使用的设备。然而,浏览不同的输入来查看 Pi 是否出现应该是相当容易的。在一个有趣的例子中,尽管电视上的端口清楚地显示 HDMI2,但 Pi 实际上在 HDMI3 上是可见的。我们不知道这是为什么,但是如果我们在摆弄圆周率之前能想到浏览一下输入,我们就能避免一些痛苦。

第三件要检查的事情是 SD 卡是否完全插入其插槽。Pi 实际上什么都不会做,除非它能找到卡并从中启动,所以如果你得到的只是一个黑屏,这很可能就是原因。如果你确定卡插入正确,但你仍然没有任何运气,它可能是出了什么问题,当你复制文件到卡。在那种情况下,翻到最后一节,再来一遍。如果您仍然没有任何进展,并且您已经检查了所有的东西都插好了,您的显示器上有正确的输入,并且您有一个愉快地发光的电源 LED,那么它可能是更麻烦的事情。不幸的是,没有和你一起看着你可怜的 Pi,我们真的不能给出任何更具体的建议。幸运的是,你并不孤单;在 Raspberry Pi 论坛上有很多人愿意帮忙。要访问论坛,请前往 www.raspberrypi.org 并点击论坛链接(就在树莓派标志的左下方)。这将带你到主论坛页面;您正在寻找的特定板是使用 Raspberry Pi 的基本用法和设置。

用 NOOBS 安装拉斯扁

过一会儿,您应该会看到 NOOBS 启动并开始初始化自己(图 1-17 ):

A978-1-4842-1162-5_1_Fig17_HTML.jpg

图 1-17。

NOOBS setting itself up

在这张截图中,你可以看到 NOOBS 已经知道了 Raspbian,右边的图标(一个 SD 卡)告诉你操作系统已经在卡上了,可以使用了。现在,理论上接下来应该发生的是,你应该看到这样的屏幕(图 1-18 ):

A978-1-4842-1162-5_1_Fig18_HTML.jpg

图 1-18。

NOOBBS detected lots more operating systems to install

NOOBS 在网上找到了一些可供选择的操作系统,你可以安装它们。它们没有 SD 卡图标,而是有一个以太网连接器,显示它们“在网络上”可用——换句话说,你需要下载它们。现在我们说“理论上”的原因是因为我们不能让它开箱即用。事实上,我们不得不摆弄 IP 地址和各种各样的东西,以便让安装程序真正检测在线操作系统。事实上我们得到的是这个(图 1-19 ):

A978-1-4842-1162-5_1_Fig19_HTML.jpg

图 1-19。

NOOBS network init failed

幸运的是,我们使用的是 NOOBS 的完整版本,所以我们不能上网下载其余的操作系统也没关系。我们预计这是我们的 Pi 或我们的设置的问题,这可能是你自己不会看到的。也就是说,我们希望提到它,以防它突然出现,并向您保证,即使有这个问题,您仍然可以安装 Raspbian。

好了,让我们实际开始安装过程!您所要做的就是勾选 Rasbian 左侧的方框,然后按下“安装”按钮(图 1-20 ):

A978-1-4842-1162-5_1_Fig20_HTML.jpg

图 1-20。

Time to install Raspbian

你会得到一个最后的警告,这将删除 SD 卡,但这是一个有争议的点,因为你必须删除卡,让 NOOBS 在那里摆在首位。尽管你完全确定一切都会好起来,但再次检查总是一个好主意(图 1-21 ):

A978-1-4842-1162-5_1_Fig21_HTML.jpg

图 1-21。

Last chance to back out

一旦你点击了是,NOOBS 将开始安装拉斯扁,你所要做的就是等待。您将看到一些有用的信息屏幕(出于明显的原因,我们不会在此重复这些信息),而且,可能是时候装满那个咖啡杯了,因为从同一个 SD 卡复制大量数据是一个缓慢的过程,不管是不是 class 10 SD 卡(图 1-22 )。

A978-1-4842-1162-5_1_Fig22_HTML.jpg

图 1-22。

Raspbian is installing

最后,安装好所有东西(图 1-23 ):

A978-1-4842-1162-5_1_Fig23_HTML.jpg

图 1-23。

Finally everything is installed

现在是时候重启你的 Pi 了。这一次,当它重新启动时,NOOBS 将离开,取而代之的将是拉斯边。达到这个阶段花费了相当多的时间,但是我们保证这是值得的!

当它启动时(这次是真的),您应该会看到类似这样的内容(图 1-24 ):

A978-1-4842-1162-5_1_Fig24_HTML.jpg

图 1-24。

Finally Raspbian is booting!

配置您的 Pi

在一连串难以理解的文本之后(尽管我们确信它对某人来说意味着什么),你应该会看到如图 1-25 所示的配置。在这里,我们将配置您的 Pi 用于一般用途,以便下次您打开它时,迎接您的将是一个漂亮的桌面,而不是一些粗短的文本。

A978-1-4842-1162-5_1_Fig25_HTML.jpg

图 1-25。

First boot: time to configure your Pi!

我们在这里只讨论基本的配置选项(一旦您的 Pi 启动并运行,您随时可以返回并更改它们),因为我们希望您尽快地使用一台工作的计算机。

扩展文件系统

第一个感兴趣的选项是“扩展文件系统”。当您直接从磁盘映像安装 Raspbian 时,它只占用少量空间。开发者不知道你的 SD 卡有多大,没有人想下载 16GB 或更大的图像,这样他们就可以充分利用卡上的空间。为了解决这个问题,Raspbian 支持在安装后扩展磁盘,以充分利用磁盘空间。然而,这是 NOOBS 已经为你做的事情,所以如果你尝试这个选项,你可能会看到这个消息(图 1-26 ):

A978-1-4842-1162-5_1_Fig26_HTML.jpg

图 1-26。

The filesystem is already expanded if you used NOOBS

我们在这里提到它的原因是,在某些时候你可能会决定直接从一个镜像安装,如果你这样做,你肯定想使用这个选项!

引导至桌面

下一个选项允许我们配置 Pi 将以何种模式引导。在下一章,我们将带你对桌面进行一次简短的游览,对于书中的大多数主题,我们假设你真的坐在 Pi 前面。考虑到这一点,我们想引导到桌面。因此,选择此选项,然后从下一页的列表中选择“以用户‘pi’身份登录桌面”(图 1-27 ):

A978-1-4842-1162-5_1_Fig27_HTML.jpg

图 1-27。

Boot to the desktop

更改用户密码

接下来,我们将更改pi用户帐户的密码。这是您将在整本书中使用的帐户,对于大多数人来说,这将是您在 Pi 上需要的唯一帐户。目前,虽然密码被设置为raspberry并且是默认的,这意味着任何人都可以登录到您的 Pi。虽然保护您的 Pi 免受未授权入侵者的攻击可能不是您优先考虑的事情,但是为了以防万一,改变这一点仍然是一个很好的做法。稍后,您可能会通过互联网提供您的 Pi,在兴奋之余,您可能会忘记您实际上并没有去更改密码。坏事会发生。所以,让我们抓住机会,现在就做出改变。高亮显示“Change User Password”并按回车键,你会看到类似图 1-28 的东西。

A978-1-4842-1162-5_1_Fig28_HTML.jpg

图 1-28。

Changing your password

当你按回车键时,配置工具将执行标准的passwd命令,这就是为什么你看到的是文本提示而不是漂亮的菜单。只需输入您的新密码(记住它是区分大小写的:HeLLohelloHello不同)并按回车键。出于安全原因,密码不会显示在显示屏上,也不会显示任何星号来让您知道您确实输入了一些东西。然后会提示您再次输入密码(图 1-29);按回车键后,将得到如图 1-30 所示的确认。再次按回车键,你将回到主菜单。

A978-1-4842-1162-5_1_Fig30_HTML.jpg

图 1-30。

Password changed successfully

A978-1-4842-1162-5_1_Fig29_HTML.jpg

图 1-29。

Enter your password

设置一些国际选项

Linux 的一个优点是它对国际化有很好的支持,并且可以(相对)容易地定制您的安装来满足您的需求。我们可以配置许多项目,如图 1-31 所示。当您设置每个选项时,您将被带回到主菜单,因此要更改下一个设置,只需再次选择国际化菜单:

A978-1-4842-1162-5_1_Fig31_HTML.jpg

图 1-31。

International Settings menu

首先是配置您的语言环境。通过告诉 Linux 你在世界的哪个地方,它可以决定有用的事情,比如数字之间的分隔符和使用哪个货币符号。例如,在美国,我们可能会写 1,000.00,但在欧洲的许多地方,它会被写成 1.000,00。无论哪种方式,为了最大限度的舒适和确保一切看起来正确,我们需要设置区域。突出显示“更改区域设置”选项,然后按回车键。

现在,您将看到一个可供选择的不同地区的详细列表(参见图 1-32 )。名称中的前两个字母指定语言,而第二对字母指定地区差异。例如,en_US 将是为美国用户定制的英语,但是 en_GB 将具有特定于在英国说英语的人的设置。您应该选择最符合您需要的语言和国家对,并通过按空格键来选择它们。你可能想要 ISO-8859 和 UTF-8 两个版本。如果您决定两面下注并选择所有语言环境,请注意您将会等待很长时间,因为 Pi 会为您生成所有的语言环境设置。事实上,我们尝试了这个选项,在等待了很长时间才生成两个语言环境后,我们厌倦了并拔掉了插头。选择所需的语言环境后,按一次 Tab 键突出显示 OK 按钮,然后按 Enter 键进入下一屏幕(语言环境生成后,参见图 1-33 )。在这里你需要选择你想要默认使用的区域设置(见图 1-30 )。做出选择后,高亮显示并按 Enter 键。然后,您将看到区域设置生成过程(见图 1-34 ),完成后(这确实需要一段时间),我们将再次回到主配置页面。

A978-1-4842-1162-5_1_Fig34_HTML.jpg

图 1-34。

Generating locales

A978-1-4842-1162-5_1_Fig33_HTML.jpg

图 1-33。

Select the default language

A978-1-4842-1162-5_1_Fig32_HTML.jpg

图 1-32。

Picking your locale

更改时区

“更改时区”选项和它说的差不多。选择此选项后,您将看到一个区域列表(如图 1-35 所示)。在本例中,我们正在配置 Pete 的 Pi,因此我们选择了亚洲。下一个屏幕将给你一个微调选择的机会,并选择你的国家或城市(见图 1-36 )。一旦你找到了最接近的匹配,选择该选项并按下回车键。

A978-1-4842-1162-5_1_Fig36_HTML.jpg

图 1-36。

Pick your closest city

A978-1-4842-1162-5_1_Fig35_HTML.jpg

图 1-35。

Pick your region

配置键盘

下一个感兴趣的选项是“Configure Keyboard”。默认情况下,Raspbian 假定一个 UK 键映射,但是您可能想要其他的东西。不过,要注意的是,拉斯边知道大量的键盘,而且数量之多可能会让人困惑。例如,你知道你有一个通用的 104 键键盘还是实际上是一个 105 键的版本吗?我们也不确定,所以我们坚持使用默认的:如图 1-37 所示的通用 104 键 PC。

A978-1-4842-1162-5_1_Fig37_HTML.jpg

图 1-37。

Choosing your keyboard type

如果你能找到你确切的模型,尽一切可能自由选择它。如果你不确定,你最好跟随我们的领导,坚持默认设置。一旦你选定了键盘,按下回车键进入下一个屏幕。现在我们要选择我们想要使用的键映射。默认情况下,它列出了各种英国键盘映射(如图 1-38 所示),但是如果你没有足够幸运拥有一个英国键盘,将该栏向下移动到其他,按 Enter,然后滚动列表以找到更适合你需要的东西。一旦你找到了正确的键盘,再次按下回车键进入下一个屏幕。

A978-1-4842-1162-5_1_Fig39_HTML.jpg

图 1-39。

Customize your keyboard configuration

A978-1-4842-1162-5_1_Fig38_HTML.jpg

图 1-38。

Choose your layoutIf you’re not sure what to select from the menu (shown in Figure 1-39), you’re not alone

对于大多数人来说,键盘默认值就可以了,因为它们将包括您的特定键映射已经提供的任何特殊组合键。这是一个如果你需要做出改变的时候,你可能已经知道为什么和选择什么。如果你有任何疑问,只要保持默认选择,并按下回车键。现在你会看到另一个看起来可疑地像它的前任的菜单(如图 1-40 所示),至少在知道挑选什么方面。同样,你可能已经知道你是否需要在这里改变什么;如果你不确定,你应该通过按回车键来选择默认值。

A978-1-4842-1162-5_1_Fig40_HTML.jpg

图 1-40。

Customize your keyboard some more

下一个菜单(如图 1-41 所示)对老派的 Linux 用户来说毫无意义。过去,如果您的 GUI 决定放弃您,您可以通过按住 Ctrl + Alt + backspace 有效地“重启”会话。随着 GUI 变得越来越稳定,Linux 变得越来越主流,这个特性经常被禁用。我们已经很多年没用过它了,尽管我们碰巧认为它很有用。默认情况下是否定的,这可能就是您想要的。如果您发现自己渴望这个特殊的特性,您可以随时返回并更改它。要选择默认值(并最终返回主菜单),只需按 Enter 键。

A978-1-4842-1162-5_1_Fig41_HTML.jpg

图 1-41。

Do you want to enable the X server kill switch?

启用摄像头

此菜单允许您启用摄像机。这里特指 Pi 基金会提供的摄像头,不影响 USB 网络摄像头等其他摄像头。这是默认设置为禁用,但你可以在这里启用它,如果你碰巧有一个。我们没有在这里包括截图,因为真的没有什么可看的。

添加到栅格

Rastrack 是一个非官方项目,要求自愿注册,以帮助了解 Pi 在世界各地的使用情况。如图 1-42 中的广告词所示,这只是为了好玩,但许多人并不特别希望他们的 Pi 被跟踪。幸运的是,Rastrack 是自愿加入的,所以你可以完全忽略它,除非你想参加。

A978-1-4842-1162-5_1_Fig42_HTML.jpg

图 1-42。

Register on Rastrack

如果你想参加,只需按照简单的屏幕要求一些细节。一旦你输入了所有东西,它们将被提交给 Rastrack,你将返回到主菜单。

使…超频

爱好者长期以来一直喜欢超频他们的 CPU,也就是说,让它们运行得比设计的更快更热。Pi 也支持这一点,许多人认为它非常安全。然而,我们建议不要这样做,如果 Pi 不够快,不能满足您的开箱即用需求,那么您可能不应该使用 Pi 来做您正在做的任何事情。

另一方面,如果你真的想让你的 Pi 跑得更快,你可以从这个菜单中选择一个速度(图 1-43 ):

A978-1-4842-1162-5_1_Fig43_HTML.jpg

图 1-43。

How fast would you like to go?

高级功能

我们不会逐一介绍这些菜单项,对于许多人(如果不是大多数人的话)来说,这些菜单项中的大部分都不会用到。我们唯一感兴趣的是内存分割。作为参考,菜单如下所示(图 1-44 ):

A978-1-4842-1162-5_1_Fig44_HTML.jpg

图 1-44。

Advanced options

分配内存

“内存分割”选项需要解释一下。您的 Pi 有两个主要处理器:CPU(或中央处理器)和 GPU(或图形处理器)。CPU 负责机器的一般运行,GPU 负责处理显示器,并提供 2D 和 3D 加速等功能,以及对解码高质量视频流的硬件支持。GPU 专用于处理图形(大部分情况下),不能执行 CPU 的角色。然而,这确实意味着如果 CPU 可以将所有复杂的图形工作卸载到 GPU,CPU 就不必如此强大。通过这两者,Pi 保持了良好的低成本和低功耗要求,但没有牺牲太多的性能。

到目前为止还不错;但是这和分裂记忆有什么关系呢?Pi 2 总共配有 1GB 的 RAM,它需要同时提供 CPU 和 GPU。由于 GPU 实际上是一个独立的单元,它需要自己的内存分配。可以在两个处理器之间分配 1GB 的内存,而不是两个处理器都有专用内存。默认情况下,Pi 只为 GPU 分配少量资源。如果您想将 Pi 用作服务器,或者从未打算将显示器连接到您的 Pi,这是理想的选择。如果你不使用图形,分配额外的内存给 GPU 是没有意义的。

另一方面,如果您计划将您的 Pi 用作迷你桌面计算机或显示高质量的电影,您将希望尽可能多的内存分配给 GPU(在 Pi 2 的情况下,这意味着为 GPU 分配 256MB)。很难预测每个人将如何使用他们的 Pi,除了给 Pi 本身增加更多的内存(并提高成本)之外,没有简单的解决方案。幸运的是,我们有能力自己选择如何分配内存。

对于一般用途和“入门”类型的任务,我们建议您为 GPU 分配 64MB。要进行设置,从菜单中选择memory_split选项,按下回车键,你将得到类似于图 1-45 的东西。键入所需的内存拆分,然后按 Tab 键选中 OK 按钮,然后按 Enter 键。

A978-1-4842-1162-5_1_Fig45_HTML.jpg

图 1-45。

Choose your memory split

终于来了!配置好了!

哇,我们终于坚持到最后了!在所有这些努力之后,您现在可以重启 Pi 并(最终)开始使用它了!按 Tab 键两次以选中“Finish”按钮,然后按 Enter 键。您的 Pi 应该关闭,然后重新启动。在所有这些努力之后(在 Pi 启动时还要等待一段时间),您最终应该看到一个漂亮的图形显示,看起来应该如图 1-46 所示。

A978-1-4842-1162-5_1_Fig46_HTML.jpg

图 1-46。

At long last, we have a desktop!Congratulations!

你现在有一个功能齐全的树莓派!如果你没有一个漂亮的桌面,你可能需要调整一下你的配置。在登录提示符下,您可以使用安装过程中设置的用户名pi和密码登录。如果您随后运行以下程序,您将能够更改设置(“Boot behaviour”是您想要更改的选项):

$ sudo raspi-config

您也可以尝试使用以下命令手动启动图形界面:

$ startx

摘要

本章将带您从接触到 Pi 一直到启动和运行它。我们故意慢慢来,涵盖了所有的基础知识,因为总是那些所谓的简单的东西会绊倒人(包括我们!).我们看了盒子里有什么(更重要的是没有什么),并提供了一个购物清单,列出了烘焙 Pi 所需的所有物品。

然后,我们简单介绍了 Linux——什么是发行版,以及为什么我们决定在本书中坚持使用 Raspbian。然后我们讲述了如何下载 NOOBS,并把它存在你的 SD 卡上。

配备了一个完全加载的卡,我们启动了 Pi,并完成了初始设置和配置过程,最终我们在一个同样令人印象深刻的桌面中间看到了非常漂亮的 Raspberry Pi 徽标。

在下一章,我们将开始探索你的新桌面。我们将带您快速浏览 Raspbian 开箱即用的特性,最后我们将向您展示如何调整和定制它以满足您的需求。

二、探索场景

尽管本书的大部分内容都集中在让您熟悉命令行并真正接触 Linux 上,但是如果我们不首先向您展示如何使用您的 Pi 附带的图形界面,我们将会完全出错。它不像你在 PC 或 Mac 上看到的那样华丽,但它速度快,易于使用,可以让你做所有你习惯做的事情。当然,这一切都在一个可以放在口袋里的设备上,比它所连接的显示器或电视耗电更少。

我们从环顾桌面开始这一章,看看我们有什么有趣的东西可以玩。有些显然是有用的应用程序,而有些在这个阶段可能没那么有用(例如,除非你是用 Python 编程的,否则你不会对 Python 开发环境感兴趣)。然后我们将浏览各种菜单,看看我们找到了什么。

欢迎来到 LXDE

与 Windows 不同,Linux 没有集成特定的 GUI,而是使用单独的应用程序(在这种情况下是客户机和服务器)来提供 GUI。这个应用程序被称为 X-server,它曾经是 Linux 宇宙中最复杂、最难设置的东西。它已经变得更好,但在不久前,如果你想在你的新尖牙鼠标中使用滚轮,需要花费大量的时间和精力。不用说,这种乐趣很快就会消失。如今,X-server 几乎是一个黑匣子,你很少需要真正接触它。出于这个原因,我们在本书中不会对这个主题进行更深入的探讨,但如果你有点好奇想了解更多,请查看: http://en.wikipedia.org/wiki/X_Window_System

X-server 提供了使用 GUI 的框架,但它实际上并没有提供我们习惯看到的漂亮桌面。这些是由桌面环境提供的。同样,我们不打算讨论所有这些是如何工作的,只是说,像 Linux 世界中的其他东西一样,您可以选择您更喜欢哪一个。对于大多数人来说,这取决于他们选择哪个 Linux 发行版,尽管大多数发行版都提供了选择。更先进的有各种各样的功能和特效,可以理解的是,它们在使用的时候会消耗大量的资源。在最新最棒的台式机或笔记本电脑上,这几乎不是问题,大多数人都抓住机会让他们昂贵的机器实际上做一些工作。然而,当你运行一个不那么高规格的机器,比如 Pi 时,这就成了一个问题。

不仅仅是 Pi 会有困难——仅仅几年前的计算机还能轻松运行 Linux,但可能会在新的高度图形化的界面上有困难。当你考虑甚至是经常被扔掉的旧机器时,有了合适的显示管理器,它们可以很容易地表现为一台非常有用的 PC。然而还有更多——现代上网本的设计是低功耗的,目标是高效的电池消耗和成本。当谈到桌面时,他们也受益于极简设计。

当您需要扩展您的处理预算时,最省钱的地方就是图形界面的特性集。你真的需要那些花哨的功能吗?透明的窗户对你正在做的事情是必要的吗?你真的需要那个 3D 渲染的时钟吗?如果没有,并且您想减少一些脂肪,像 LXDE 这样的桌面环境将会适合您。

LXDE(Lightweight X11 Desktop Environment 的缩写)是为那些对能效和在低端性能的硬件上运行的需求至关重要的机器设计的。它的目标是在 CPU 周期和内存使用方面有效率,虽然一些窗口管理器 eskew 所有不必要的功能,LXDE 试图在同一时间保持功能。

虽然我们现在知道 GUI 是由许多活动部件组成的,但是在使用它的时候,这基本上是透明的。实际上,将 LXDE 作为您的 Pi 的主要环境并没有什么坏处,如果您打算花大部分时间使用 GUI,那么我们认为将它作为操作系统的核心部分也没有什么坏处。你可以简单地使用它,并接受它是可用的。记住这一点,让我们继续探索我们在使用 LXDE 时实际拥有的东西。

这是什么?

一旦您安装并设置了您的 Pi,并且第一次启动了它,您应该会看到如图 2-1 所示的屏幕。

A978-1-4842-1162-5_2_Fig1_HTML.jpg

图 2-1。

First boot of your Pi

图标的布局实际上取决于您连接到 Pi 的屏幕。这应该是非常相似的,但可能唯一的真正区别是桌面图标本身的布局。

这里有一些关键区域很难在一个大的屏幕截图中看到,所以我们将分别分解每个部分。为了简单起见(更不用说它们已经成为常见的习惯用法了),我们将用大多数人熟悉的名称来指代各种 GUI 元素。因此,我们将讨论开始菜单和任务栏。我们从屏幕左下方开始,如图 2-2 。

A978-1-4842-1162-5_2_Fig2_HTML.jpg

图 2-2。

Start button and friends

开始菜单和任务栏的左上角

左上角的第一个按钮实际上是 Pi 标志,充当开始按钮。“下一步”按钮启动默认的 web 浏览器,在 Pi 的情况下恰好是 Epiphany。像其他应用程序一样,你会发现大多数应用程序都是轻量级和高效的。下一步按钮将启动 PCManFM,LXDE 文件管理器。当你需要移动一些文件或做一些一般的整理工作时,这是你需要的工具。

目前为止一切顺利。这些应用程序与您可能习惯在您的主计算机上运行的程序没有什么不同。下一个有点不同。这是启动 LXTerminal 的按钮,这是在 Pi 上使用命令行的最佳方式(至少在图形界面中)。

接下来的两个特别有趣,对 Pi 来说相对较新(或者至少在我们写第一本书的时候它们还不存在)。第一个是 Mathematica,它是最强大的计算软件包之一,但是你需要知道你在做什么。如果你对数学和创建模型(数学模型)感兴趣,你肯定想看看这个。旁边的图标启动 Wolfram,这是 Mathematica 中使用的编程语言。这类似于 Linux 中的命令行,因为它让您可以使用 Mathematica 的引擎。这是一个很酷的特性,但是,这可能不是大多数人会使用的东西。

最后,桌面上还有唯一的图标——垃圾桶。这不需要太多的解释(当然,除非你来自 Windows 3.11),它以你期望的方式工作。

在右手边…

在任务栏之后,我们还有一些图标,如图 2-3 所示。

A978-1-4842-1162-5_2_Fig3_HTML.jpg

图 2-3。

The right hand side of the task bar

第一个是代表您的网络的两台计算机的图片。在这种情况下,我们使用有线以太网,它是连接的,所以我们得到这个图标,但图标可以改变(例如,如果电缆被拔掉,图标上会有一个十字)。

下一个图标真的不需要介绍。扬声器控制您的 Pi 上的音量。像大多数设置一样,你也可以在这里静音,但是这个真的没有什么有趣的。

第三个图标看起来只是一个空框,但它实际上充当 CPU 监控器。你给你的圆周率做的越多,这个盒子就会变得越满。它就像一个图表,显示你的 CPU 是如何随着时间的推移而使用的。你实际上可以通过快速移动鼠标指针自娱自乐(至少几分钟)。你移动得越快,使用的 CPU 就越多,你就越能填满盒子。除了娱乐和游戏之外,这个显示器非常有用,因为如果你的 Pi 开始有点反应迟钝,快速看一下显示器就可以知道你是否正在最大限度地利用你的 CPU。

紧挨着 CPU 监控器的是时钟,它不需要太多的解释。在早期版本的 Pi 中,这个任务栏的远端有一个关机按钮。这是一个非常有用的功能,你仍然可以使用它,但你需要点击“菜单”按钮,然后选择“关机”(旁边有一个漂亮的退出标志)。这将调出熟悉的关机屏幕(图 2-4 ):

A978-1-4842-1162-5_2_Fig4_HTML.jpg

图 2-4。

Clicking the shut down button

点击“关机”将会像你期望的那样重启并注销。但是有一点值得记住,Pi 运行的是多用户操作系统 Linux。这意味着事情可能在你不知道的背景下发生。例如,有人可能正在从您的 Pi 中流式传输视频。如果您关机或重新启动,可以理解的是,您会断开连接到该 Pi 的任何其他人。很可能这对你来说现在还不是问题,但是你可能应该意识到这一点。

这就是你在屏幕上看到的。现在,让我们继续开始菜单的奥秘…

开始菜单

自从 Windows 95 引入开始菜单以来,开始菜单的概念在大多数操作系统中几乎无处不在(特别是 Mac)。虽然许多人可能会对此嗤之以鼻,并指出以前可能见过它的地方,或者坚持认为 Linux 中的开始菜单与 Windows 中的完全不同,但我们试图超越这一点。事实是,不管是谁想出来的,开始菜单的概念都非常好用,这也是它被广泛采用的原因。

肥皂箱说够了,让我们看看开始菜单能为我们提供什么(图 2-5 ):

A978-1-4842-1162-5_2_Fig5_HTML.jpg

图 2-5。

The Start Menu

和以前一样,这里没有什么真正突破性的东西。第一部分列出了我们可以使用的所有应用程序,它们被整齐地组合在一起。在这种情况下,编程、互联网、游戏和带有帮助和偏好的配件排在最后。很难决定我们应该先研究这些选项中的哪一个。在我们这样做之前,我们需要包装剩下的项目,因为只剩下两个,应该不会花我们很长时间。

我们已经讨论了关闭,这相当简单。我们将查看一些设置(首选项),稍后您可以对其进行调整。列表中的最后一项是 run 命令。这让我们无需从菜单中选择命令、点击图标或打开终端就能执行特定的命令。就像在 Windows 下一样,这个选项非常方便。它还具有自动完成功能(图 2-6 ):

A978-1-4842-1162-5_2_Fig6_HTML.jpg

图 2-6。

The run command and auto complete

在这里你可以看到我们输入了“gnom ”,它突出显示了所有符合这个模式的应用程序。这可以节省你很多时间,因为随着时间的推移,你会知道你需要输入多少个字符,自动完成功能才会产生正确的答案。通常命令名(尤其是 GUI 应用程序)会很长,所以这可以节省时间!

附件

现在,让我们来看看配件下面有什么。像所有其他菜单一样,这里的项目可以随着您安装更多软件而改变,在较新版本的 Raspbian 上,它可能看起来有点不同。在我们的 Pi 上,配件菜单是这样的(图 2-7 ):

A978-1-4842-1162-5_2_Fig7_HTML.jpg

图 2-7。

The accessories menu

xaarchiver(消歧义)

与 Image Viewer 相比,XArchiver 不太可能被直接调用,但它可能是一个在普通系统上使用相当多的应用程序。此工具允许您创建和解压缩各种格式的档案,这在您从互联网下载内容时是必不可少的。XArchiver 是这样的(图 2-8 ):

A978-1-4842-1162-5_2_Fig8_HTML.jpg

图 2-8。

XArchiver when it’s opened by hand

在这里,我们将文档下载到了 Erlang 平台(当我们需要演示 XArchiver 时,这是我们首先想到的)。双击文件后,XArchiver 自动打开。到目前为止,我们使用过的唯一按钮是“全部提取”按钮,从右边数第二个。点击这个将提取所有的存档内容,这往往是你真正想要做的。

计算器

如果圆周率不附带计算器,感觉就不太对了——毕竟它几乎是所有计算机化设备的标准应用程序。有人记得计算器手表吗?我们不会把这个截图放进去,因为它看起来像一个计算器,但它仍然可以很好地完成工作。

文件管理器

如前所述,LXDE 附带了 PCManFM 文件管理器。当然你可以从任务栏访问它,所以你不太可能从这里运行它。从极简设计运动中领先,这个文件管理器是轻量级的,简单易用,但仍然有你需要的所有功能。它的工作方式与微软的 Windows 资源管理器非常相似,所以如果你来自 Windows 背景,你会感觉在 PCManFM 上如鱼得水。如果没有,只需点击几下,你就可以轻松地找到它(图 2-9 ):

A978-1-4842-1162-5_2_Fig9_HTML.jpg

图 2-9。

The PCManFM File Manager

最初打开时,PCManFM 会将您放入您的家庭区域。它会在右下角显示你有多少可用空间(在 Pi 等存储空间相对有限的设备中总是有用的),并在左上角列出最常见的地方。浏览时,您只需点击浏览文件夹,还可以使用工具栏上的导航图标来帮助您快速浏览文件。如果你想获得更多的实践经验,我们会在第五章中介绍如何操作文件。

图像查看器

图像浏览器是你可能永远不会直接打开的应用程序之一。你几乎总是通过双击一个图像文件来打开它,默认情况下会为你打开图像浏览器。虽然图像查看器可能很简单,但它并不缺乏功能,并且拥有您所期望的所有基本工具(图 2-10 ):

A978-1-4842-1162-5_2_Fig10_HTML.jpg

图 2-10。

Image Viewer’s main interface

前两个按钮让您可以在一组图像中来回移动。这实际上是非常有用的,因为这些天,很多时候人们都在访问相册而不是特定的照片。为了帮助你做到这一点,还有一个幻灯片功能,你可以通过按下播放按钮来访问。

下一部分有控制你想要如何实际查看图像。前两个是传统的缩放控件。第三个图标是“适合屏幕”,第四个是全尺寸显示(如果是数码相机的照片,这意味着你几乎肯定要滚动),最后是全屏选项,以充分利用你刚刚得到的 60 英寸平板屏幕。

第三部分是改变图像本身的控件。前两个是旋转控件(分别向左和向右旋转),第二对控件允许您水平和垂直翻转图像。当你从一个奇怪的角度拍照,并且不想把你的头倾斜 90 度来看你的照片时,这是非常方便的。

下一组是文件控件。它们分别允许您打开、保存、另存为和删除文件。最后两个图标提供了对 preferences 面板(这里没有什么有趣的东西)的访问,并允许您退出程序。

PDF 查看器

你不太可能手动启动这个应用程序,而是当你双击一个 PDF 或者试图在网络浏览器中查看它时,它就会打开。截屏中没有太多东西可以显示(除了文档可能存在的大量灰色),所以我们把它省略了,但是如果你以前看过 PDF,你不会有任何问题。

任务管理器

正如您在图 2-11 中看到的,CPU 此刻实际上是空闲的。考虑到它运行的是一个完整的操作系统(而且是一个高级操作系统),看到 CPU 没有做任何繁重的工作可能会令人惊讶。虽然与高端英特尔处理器相比,Pi 中的 ARM 芯片并不令人印象深刻,但这确实证明了如果你小心的话,你可以用少得惊人的资源运行一台完美的台式机。我们的 RAM 使用情况讲述了一个类似的故事。诚然,我们目前没有太多的开放(尽管你可以从进程列表中看到我们正在运行 VNC 远程桌面会话),但我们的使用率仍远低于 50%,新型号 B 的内存容量为 512MB,这将允许更多的应用程序同时运行。

A978-1-4842-1162-5_2_Fig11_HTML.jpg

图 2-11。

The task manager

进程列表可以很好地显示机器上正在运行什么,以及每个进程消耗了多少资源。这在您的 Pi 表现有点古怪,并且您需要查看某个应用程序是否突然决定吃掉您的所有 RAM 或让您的 CPU 着火时非常有用。如果您确实发现某个应用程序变得有点过于贪婪,您可以右键单击其名称,然后选择“Kill”,这将强制关闭它,从而有望使我们的 Pi 完全恢复健康(图 2-11 )。

末端的

终端是一个 Linux 的终端模拟器,让您可以访问虚拟控制台。我们不打算深入探讨如何实际使用这一特定应用程序,因为我们将在下一章讨论细节。可以说,这个工具是用来让您直接通过命令行访问操作系统的。对许多人来说,这是一个天使不敢涉足的地方,但对经验丰富的管理者来说,这是他们称之为家的地方。不过要想知道命令行是否适合你,你必须等到第四章。

终端是一个简单的模拟器,但完成工作。它没有一些模拟器提供的所有花哨功能,但对大多数人来说非常好,看起来像这样(图 2-12 ):

A978-1-4842-1162-5_2_Fig12_HTML.jpg

图 2-12。

LXTerminal up and running

这里我们将简要提及的一件事是提示。当字体颜色为绿色并且提示符的末尾是一个美元符号时,您知道您正在以普通用户的身份运行,并且您没有 root 权限,也就是说,您不能执行任何可能真正损害系统的命令。我们将在下一章更深入地讨论这个问题,但是我们需要在这里提到这个区别,这样下一个程序才有意义。

文字编辑器

为了与极简主义主题保持一致,Leafpad 文本编辑器做了基本的工作,仅此而已。它非常类似于微软记事本的新版本,同样易于使用。这对于写信给 Maude 阿姨或委员会抱怨隔壁的狗没有太大的好处,但当你需要做一些轻松的文本编辑时,它是完美的。

尽管它很简单,但它仍然提供了一些最有用的工具,即能够进行查找和替换,以及启用和禁用自动换行。有了这些工具,你几乎可以完成任何事情。

如果你觉得 Leafpad 对你的口味来说功能有点不足,那么你可能想翻到第六章,在那里我们会向你展示一些更强大的原生文本编辑器,你可以得到它们。

在大多数情况下,Leafpad 完全按照它在 tin 上所说的那样做-它编辑文本,如果这就是你所需要做的,Leafpad 是一个极好的选择(图 2-13 )。

A978-1-4842-1162-5_2_Fig13_HTML.jpg

图 2-13。

Leafpad has a similar look and feel to Microsoft’s Notepad

比赛

游戏菜单只有两个项目,但它们仍然令人印象深刻,有一种发泄方式总是好的。对于一些轻松有趣的游戏,你不会发现 Pi 想要的。

《我的世界》

除非你过去几年一直住在月球上,否则《我的世界》对你来说并不陌生(图 2-14 )。事实上,对许多人来说,这是一个家喻户晓的名字。甚至还有怎么玩的书!无论如何,现在有一个版本的 Pi,但要注意,虽然它不需要太多的电力来运行它,但它会以令人不安的速度榨取你的生命!我们不会在这里讨论如何玩这个游戏,但是在谷歌上快速搜索《我的世界》会给你所有你需要的,甚至更多。祝你好运!

A978-1-4842-1162-5_2_Fig14_HTML.jpg

图 2-14。

Minecraft on your Pi!

圆周率游戏

对于那些年龄足够大,还记得像诺基亚 3310 这样的手机的人来说,你会记得它们曾经配备了一系列浪费时间(并且非常容易上瘾)的游戏。像《蛇》和《太空撞击》这样的经典作品可能非常有趣。Pi games 相当于 Raspberry Pi。所有这些游戏都很容易上手,但很难放下。带一些出去转一圈,看看你更喜欢哪一个(图 2-15 ):

A978-1-4842-1162-5_2_Fig15_HTML.jpg

图 2-15。

Pi games, say goodbye to your free time

互联网

不出所料,互联网菜单包含专门用于访问互联网的应用程序。在我们的 Pi 上,互联网菜单是这样的(图 2-16 ):

A978-1-4842-1162-5_2_Fig16_HTML.jpg

图 2-16。

The Internet menu

皮店

Pi Store 的目标是类似于 Android 的应用商店。我们实际上从来没有使用过它,因为我们想要的所有东西都可以通过标准库获得。也就是说,我们正在关注它,因为当应用程序首次出现在 Android 上时,它们并不那么有趣,但今天它们是整个手机体验的关键。所以试试这个吧,你可能会找到你真正喜欢的东西(图 2-17 )。

A978-1-4842-1162-5_2_Fig17_HTML.jpg

图 2-17。

Like the app store but for Pi

树莓资源

“Raspberry Pi Resources”基本上是一个链接到大量信息(也称为 Resources 咳咳)的网页,这些信息将为您提供有关 Pi 的信息以及大量学习、教学和制作东西的想法。如果你想探索你的 Pi 能做什么,还有一些文章和其他教程值得一读(图 2-18 )。

A978-1-4842-1162-5_2_Fig18_HTML.jpg

图 2-18。

Things to do with your Pi

网络浏览器

嗯,这个很标准,所以我们不会提供截图。Epiphany 是基于 webkit 的,所以你应该可以毫无困难地在 Pi 上享受所有你喜欢的网站。当然,正如我们之前提到的,你也可以从屏幕左上角的任务栏打开浏览器。

设计

编程菜单由四个项目组成,其中两个是我们在教育菜单下遇到的(图 2-19 ):

A978-1-4842-1162-5_2_Fig19_HTML.jpg

图 2-19。

The Programming menu

我们已经简单地介绍了 Mathematica 和 Wolfram,但是值得在这里重复一下,尽管这两个工具非常伟大,但是你确实需要知道你想用它们做什么。我们很高兴在这里看到他们,但不是数学家或需要做复杂的建模,我们真的不知道如何正确地为你演示。在任何情况下,它都有一个令人敬畏(也有些可怕)的标志(图 2-20 ):

A978-1-4842-1162-5_2_Fig20_HTML.jpg

图 2-20。

Firing up Mathematica

Scratch 是由 Mitchel Resnik 领导的终身幼儿园小组在麻省理工学院媒体实验室开发的。目的是创造一种方法来教人们如何编程,而不必先教所有的细节。这使得 Scratch 中的触觉方法(可以拖放逻辑块)更容易掌握。

我们不能自称是 Scratch 的专家(事实上我们第一次遇到它是在玩 Pi 的时候),但是我们确信,随着 Pi 在整个水域的扩展,这些种类的应用程序将会产生巨大的影响。让人们接触技术,并为他们提供一个强大的系统,让他们不必先掌握所有的基础知识就可以开始工作,这在我们的书中绝对是一个赢家。

如果你不相信,看看这张截图,它肯定让我们再看一眼(图 2-21 ):

A978-1-4842-1162-5_2_Fig21_HTML.jpg

图 2-21。

Scratch programming environment

计算机编程语言

我们只剩下 Python 2 和 Python 3 了。实际上,这两者非常相似,因为它们都是 Python 编程语言的基于文本的接口。之所以有两个不同的版本,是因为有两个当前版本的 Python,由于各种原因,它们并不相互兼容。在许多方面,您可能为 Python 2 . x 版本编写的脚本在 3.x 中也能很好地工作,但是语言中有相当多的问题和变化,使得保证兼容性变得不可能。这就是为什么您会经常看到在任何给定的机器上安装了两个版本的 Python。

在撰写本文时,Python 2.x 仍然是大多数人使用的地方,许多项目仍然在使用它进行积极的开发。事实上,当我们编写新的 Python 脚本时,我们也使用 2.x,因为它有最多的库、文档、博客和论坛帖子的历史,并且通常有一个很大的社区。另一方面,Python 3.x 进行了许多调整和语言改进,但它们永远不会出现在 Python 2.x 上,当然所有的新想法和开发都集中在新系列上。最终,Python 3.x 是一条出路,如果你刚刚开始你的编程生涯,我们建议你从 Python 3.x 开始。它肯定不会有什么坏处,如果出于某种原因你需要使用它,你可以随时查看 Python 2.x,实际上从一个到另一个真的不是一个大问题。

由于的两个版本在使用方式上完全相同,我们将向您展示 Python 2(而不是 Python 3)(图 2-22 ):

A978-1-4842-1162-5_2_Fig22_HTML.jpg

图 2-22。

Firing up Python

偏好;喜好;优先;参数选择

我们不打算在这份菜单中深入探讨。这是一个非常简单明了的菜单,学习这些东西的最好方法就是摆弄它们。我们以前试图给出很好的选项覆盖面,但是我们覆盖的越多,我们似乎遗漏的就越多,我们甚至不能在我们自己之间就覆盖哪些选项达成一致。所以,这一次我们建议你挽起袖子玩一玩——毕竟,你什么都破不了!

帮助

最后但同样重要的是帮助菜单。在这里你可以找到 Debian 参考指南的快捷方式和一个专门介绍 Raspberry Pi 的帮助指南。

《Debian 参考指南》问世已久,积累了很多关于理解和使用 Debian 的智慧和知识。这里的一个额外好处是这个文档直接安装在 Pi 上。这意味着,即使您无法在线获得 Pi,您也可以获得它。显而易见,这非常有用。

Raspberry Pi 帮助基本上是基金会网站上帮助页面的链接。焦点显然是在 Pi 上,这使得当您有想要解决的特定问题时,它是一个很好的去处。因为它是一个网站,所以您需要在线才能访问这个资源(尽管如果 Pi 出现问题,您可以很容易地从另一台机器上访问它)。这里的好处是资源不断更新,你总是要起床做日期信息。

这两个资源将为您提供愉快地使用 Pi 所需的几乎所有东西。然而,网络上有大量的信息,因为 Pi 有大量的追随者。您可以找到教程、常见问题解答、项目和一般帮助。所以,如果你在文档中找不到你需要的东西,就去你最喜欢的搜索引擎看看。

摘要

这就是桌面旋风之旅的基本内容!我们真的只是触及了表面,目的只是让你对可以开始自己探索的东西感到足够舒服。请记住,Pi 存在的原因是为了让人们能够试验和学习更多关于计算的知识,所以弄脏自己的手(即使您偶尔会弄坏 Pi)真的没什么好担心的。

在这一章中,我们介绍了默认安装的,可以通过开始菜单访问的应用程序,并且我们浏览了一些对于 Linux 世界来说有些独特的界面特性。

在下一章中,我们开始真正严肃地(有点)带你回到命令行,在那里我们向你介绍一个界面,一旦你习惯了它,你会想没有它你是怎么生活的。

三、熟悉

通常我们不会以一个数字开始一章(从技术上来说,我们认为这次也没有),但我们会寻求一些老式的震撼和敬畏。看一下图 3-1 (维基百科提供)。

A978-1-4842-1162-5_3_Fig1_HTML.jpg

图 3-1。

TeleVideo 925 computer terminal

你可能想知道为什么我们认为有必要向你展示一些 80 年代早期的技术(在这个特殊的例子中是 1982 年末)。这本书第二部分的大部分内容都是关于命令行以及如何让你舒适地使用它。尽管在这几十年间情况有所改善,但技术基本上是一样的。

在这一章中,我们将快速回顾一下计算机界面的历史,以及为什么终端能够幸存下来。然后,我们将看看可供您使用的各种终端,以及您如何到达它们。然后,我们将快速解释命令提示符,并让您了解一个鲜为人知的关于可用的不同 shells 的秘密。

叶老电脑

虽然你现在可以花 25 美元买一台电脑,但在 70 年代,你可能会花至少 100,000 倍的钱来买一台具有强大处理能力的电脑。这种机器会占据整个房间(如果不是整个楼层的话),需要难以置信的大量电力,并且通常给路人留下非常深刻的印象。这些东西的所有者必须处理的一个关键问题是规模问题。

当你的电脑比它所在的建筑更值钱的时候,你要确保你能最大限度地利用它。解决这一挑战的一种方法是分时度假。这个想法是,与人类和电脑互动相比,电脑的速度快得令人难以置信。事实上,即使以今天的标准来看,它们微不足道,但它们仍能让真正想使用它们的人望尘莫及。所以这就引出了一个问题,如果计算机大部分时间都在等待操作员输入命令和数据,那么它在等待的同时会做其他事情吗?

没过多久,有人发现,如果计算机一直在等待输入,那么如果有多人输入数据,它可以得到更好的利用。这样,我们可以让多个人同时输入数据,这样我们就不再受限于一个人的速度。

好主意,但我们如何实施呢?为了让它工作,我们真的想在每个需要与计算机交谈的人面前放一个屏幕,而以现有的计算机技术,即使是一台非常基本的计算机也是不切实际的。话说回来,我们并不真的需要在他们的桌子上放一台电脑,我们只是需要一种方式让他们与楼下的大型电脑进行交流。实际上,我们只是想要一个键盘和一个有很长电缆的屏幕。

向愚蠢的终端问好

这就是哑终端出现的原因。它被称为哑终端,因为它实际上只是一个屏幕和键盘。使用从计算机本身传来的指令,它会把文本画到屏幕上。每当一个键被按下,这将被发送到服务器,然后服务器将回复更多的屏幕更新。哑终端没有任何真正的处理能力,它只是作为一个接口,这使得它们相对便宜,易于安装和维护。

随着时间的推移,技术确实得到了改善,哑终端变得更好,不那么哑了。增加了对不同颜色和亮度的支持,以及更好的重绘和管理屏幕的功能。然而,基本的概念,即哑终端只是一个远程机器的接口,从来没有真正改变太多。事实上,尽管当更现代的网络变得可用时,哑终端开始被取代(更不用说计算能力变得更便宜了),但这种方法本身继续在较新的系统中使用。这不仅仅是因为人们不得不继续使用大量的遗留系统(你在一些大型百货商店的黑屏上看到过旧的绿色吗?)但它实际上有一些非常有用的属性,甚至在今天仍然有用。

GUIS AND TUIS

你会经常听到人们提到 GUI(读作 gooeys)和 TUIs(读作 tooeys ),我们也会在整本书中提到它们。幸运的是,这对首字母缩写词非常简单,你很快就会自己使用它们(当然,假设你真的想使用它们)。

GUI 是图形用户界面的缩写。几乎所有的现代计算机系统都以某种形式使用一个。过去很容易发现 GUI,因为它几乎是任何使用鼠标的设备。近年来,由于 iPad 和 Android 智能手机等设备的出现,这些界限变得有些模糊,你可以拥有一个只用手指就能操作的 GUI。现在更容易知道 TUI 是什么,因为一般来说,任何不是 TUI 的东西都被认为是 GUI。

TUI 是基于文本的用户界面的缩写,通常与 CLI 或命令行界面互换使用。TUI 可以呈现基本的菜单系统,但是这些系统是通过键盘控制而不是鼠标来导航的。

简而言之,如果你从键盘上驱动它,并且没有鼠标指针,它就是一个 TUI。如果你可以点击,用手指指着它或者看到漂亮的图片,这就是一个图形用户界面。

现代码头

在我们刚刚谈到的哑终端和我们今天在现代 Linux 系统上使用的终端之间有相当多的进化史。为了保持你的理智(更不用说跨过无聊的门槛),我们将跳到现代,在你的 Pi 上展示远程终端是什么样子的(图 3-2 ):

A978-1-4842-1162-5_3_Fig2_HTML.jpg

图 3-2。

SSH connection to a Raspberry Pi

如你所见,我们仍然有一个基于文本的界面,我们运行的程序都将在远程服务器上运行。我们确实有一些更好的功能(首先是彩色的),我们可以把终端做得尽可能大(传统的终端往往是固定大小的)。在这个特殊的例子中,我们通过 TCP/IP 上的 SSH(Secure Shell——稍后将详细介绍)连接到 Pi。

那么为什么我们还会在意这些东西呢?

问得好!在 iPads、iPhones 和 Androids 的现代时代,我们为什么要使用基于文本的界面呢?对于大多数人来说,尤其是如果他们以前从未使用过,基于文本的界面听起来真的像是一种倒退,而不是他们特别想获得的技能。不用说,我们最喜欢古老的命令行,以下是我们认为您应该投入时间和精力掌握它的一些原因。

简单的

其中一个关键原因是简单。说到简单,基于文本的界面是很难超越的。实际上它所做的只是发送和接收文本。你不会使用终端来查看你的假日快照,但它确实给了你一个清晰的界面来给你的 Pi 发布命令。

快的

当我们这么说的时候,你可能现在不会相信我们,但是使用命令行界面将允许你更快地完成你的许多任务。这样做的原因是,你可以非常精确地在一行文本中表达大量的工作,这种事情需要多次点击或一个奇怪的复杂过程才能用鼠标表达。

轻量级选手

任何不幸试图通过慢速互联网连接远程控制台式电脑的人都会明白我们在这里的意思。通过互联网发送屏幕更新(特别是对于有很多颜色的高分辨率屏幕)本质上就是占用大量带宽。数据到达目的地也需要一段时间,这就是为什么远程会话给人无响应和阻塞的感觉。

基于文本的会话不会遇到这个问题,因为它们只发送文本。它们是为最大速度只有我们今天可用速度的一小部分的系统而设计的。因此,即使在非常慢的拨号链路上,远程终端会话也往往表现得非常好。

这也减轻了服务器的压力。维护图形界面意味着计算机必须做相当多的工作。有一个鼠标指针意味着计算机必须跟踪这个指针,并确保当它接触到一个应用程序窗口或当用户点击一个按钮时做出正确的反应。令人惊讶的大量工作在幕后进行,这就是为什么 Linux 服务器很少安装图形界面,更不用说运行了。

强大的

命令行给了你很大的权力。你可以表达复杂的思想,你可以用一种图形界面无法实现的方式发布命令。例如,您可以将命令串在一起,形成更复杂的链。您可以将一个命令的输出用作另一个命令的输入。这种技术使用了一种叫做管道的东西,我们将在下一章更全面地讨论这一点。

它总是可用的

尽管近年来情况有所好转,但 Linux 平台上最易变的软件之一往往是图形界面。它似乎总是第一件要做的事情,当你的服务器停止启动,你需要一个救援环境时,你就不太可能有图形界面可用了。

然而,终端是与 Linux(基本上是大多数其他 Unix 操作系统)对话的本地方式,因此,它是一种以某种形式随时可供您使用的工具。知道如何使用终端会让你摆脱困境,并处理那些如果你不习惯命令行就会完全难倒你的情况。

相信了吗?

希望这些亮点至少让您相信命令行还是有一些作用的。如果你不完全相信,那也没关系,除非你花时间亲自体验,否则很难真正感受到它的好处。在下一节中,我们将介绍如何真正使用命令行,解释您正在查看的内容的含义,并介绍一些基本的命令来帮助您开始您的旅程。

TERMINAL OR VIRTUAL TERMINAL?

在很大程度上,你不必担心两者之间的差异。您几乎总是会使用虚拟终端,也就是说,或者是 Linux GUI 本身内部的终端窗口,或者是通过 SSH 连接。终端和虚拟终端之间唯一真正的区别是,终端是一个单独的物理设备,如串行端口或直接连接到计算机的屏幕上(没有 GUI)。虚拟终端有一个分配给它的设备,但没有相应的物理设备。事实上,在 Linux 下,一个新的设备被创建并分配给每个新的虚拟终端。

我们之所以在这里提出这种区别,是因为一些文档(一般来说是旧的文档)可能会特别提到其中的一个。这些天来,虽然你的大部分时间将花在虚拟终端上,你不需要担心差异。

三个终端

有三种主要方法可以到达命令行。第一种是坐在机器前面,使用通常所说的控制台,第二种是在 GUI 中打开一个虚拟终端,第三种是使用 SSH 通过网络连接。

控制台

虽然控制台仅仅是另一个终端,但这个术语多年来已经获得了某种神秘的地位。当你在控制台上工作时,你是直接在机器上工作,因为它实际上是一个直接插入其中的键盘和显示器。

过去,管理员通常会限制某些用户(如 root 用户)只能坐在机器前面登录。由于计算机可能位于上锁的服务器机房,这提供了额外的安全级别。

大多数发行版都没有启用这种安全性,现在通过网络进行远程访问已经成为一种规范(有时管理员甚至没有物理访问权,或者机器在地球的另一边),这个特性就没那么有用了。

不过,如果你坐在你的 Pi 前面,你可以通过按住 control (ctrl)和 alt 键,然后按 F1 到 F6 来访问控制台。默认情况下,F7 是 GUI 所在的地方,所以一旦你使用完控制台,你就可以返回到你的 GUI。

你什么时候需要这样做?好吧,如果你不能通过网络连接到你的 Pi,并且你在使用 GUI 时遇到了麻烦,控制台将会是你新的最好的朋友。但是总的来说?你不会经常使用控制台,如果有的话。通过其他两种方法获得命令行更加容易和灵活,因为通常至少有一种方法可供您使用。

在 GUI 中打开虚拟终端

Raspbian 使用 LXDE,即“轻量级桌面环境”。顾名思义,它专注于轻量级,这正是你想要的,当你的电脑正好处于轻量级的时候!

LXDE 的本机终端称为 LXTerminal,幸运的是,它不仅是预装的,而且还出现在任务栏上,如下图所示(图 3-3 ):

A978-1-4842-1162-5_3_Fig3_HTML.jpg

图 3-3。

Finding LXTermianl

我们冒昧地双击了图标,您可以看到我们有一个只能被描述为工作终端的东西。当然,在这种情况下并没有太多东西要展示,因为根据定义,终端非常简单。如果你打算坐在 Pi 前,把它当作一台更传统的计算机,你可能会发现自己经常使用终端。如果您更多地考虑远程工作,那么您需要下一个部分,老实说,这要有趣得多…

通过 SSH 连接

SSH 是一种通过网络安全连接到您的 Pi 的好方法(参见“SSH 有什么特别之处?”).它给你虚拟终端的所有好处,但你可以从网络上的任何机器访问它。潜在地,这意味着你可以在家里从你的工作电脑连接到你的个人电脑,并在完全安全的情况下摆弄它。我们发现 SSH 是迄今为止我们与服务器交互的最常见的方式,并且由于大多数人将 Pi 用作无头设备(即,没有键盘或鼠标连接到它——甚至可能没有显示器),我们认为 SSH 也将是您的首选。

SSH 等式有两个部分。您需要一个 SSH 服务器和一个 SSH 客户机。幸运的是,这两者都是免费的,而且很容易安装。

在 Pi 上设置 SSH 服务器

这一点实际上非常简单,因为除非您在安装 Raspbian 时特别禁用了它,否则 SSH 服务器已经在运行了(Raspbian 默认启用它)。事实上,在这个阶段,你真正需要的是找出你的 Pi 的 IP 地址。

首先覆盖 Pi 的虚拟终端的好处之一是,我们现在可以使用它来计算我们的 IP 地址。Pi 利用 DHCP(动态主机配置协议)的优势,这意味着在绝大多数网络上,它将能够为自己挑选出一个 IP 地址。这不仅节省了我们的时间,也意味着您不需要想出如何选择一个合适的地址,然后配置它。现代技术的奇迹!

为了找到地址,我们将使用“sudo ifconfig”命令。这个命令(是“接口配置”的缩写)将(可能并不奇怪)显示您的网络接口的配置。这是它在我们的 Pi 上的样子(图 3-4 ):

A978-1-4842-1162-5_3_Fig4_HTML.jpg

图 3-4。

Running ifconfig on our pi

在这里,您可以看到我们有两个网络接口。本地环回设备(或其朋友的“lo ”)是一个虚拟接口,网络应用程序可以使用它在同一台机器上相互通信。由于不涉及硬件,使用 lo 接口更有效,因为它总是可用,并且以相同的方式配置。在 Linux 下,大多数系统服务(如打印甚至 GUI)都作为客户机/服务器应用程序运行,并大量使用这个接口。

现在,虽然我们对 lo 设备不太感兴趣,但我们对连接 Pi 和物理网络的网络接口更感兴趣。eth 0(0 号以太网设备的缩写——记住计算机往往从零开始计数)代表着我们与现实世界的联系。在这个阶段,我们不会用所有信息的含义来烦你,这也不是你经常会看到的东西。运行 ifconfig 最常见的原因是找出 IP 地址,这当然是我们在这里的原因。从上面的截图中,您可以看到:

inet addr: 192.168.1.132 Bcast: 192.168.1.255 Mask: 255.255.255.0

我们实际上只对 IP 或 inet 地址感兴趣,在本例中是 192.168.1.132。有了这些信息,我们应该能够从网络上的任何地方连接到 Pi。

整理 SSH 客户端

我们假设您从 Windows PC 或 Mac 进行连接。如果你用的是不同的操作系统,那么不要慌,大概有适合你下载的客户端。您仍然可以继续学习其他两个教程,因为无论您使用哪个客户端(或在哪个平台上),一般过程都是相同的。

窗户油灰

Putty 几乎是所有其他 SSH 客户机比较的标准,这是有充分理由的。它不仅功能丰富,而且碰巧是免费的。您可以从以下地址下载 Putty:

http://www.chiark.greenend.org.uk/∼sgtatham/putty/download.html

由于它对于输入来说有点长,所以您可以通过在谷歌上搜索“下载 Putty”来获得类似的结果。一旦你进入下载页面,你会想要得到页面上的第一个链接,putty.exe(图 3-5 ):

A978-1-4842-1162-5_3_Fig5_HTML.jpg

图 3-5。

Downloading Putty

Putty 是一个独立的工具,所以只要你下载了它就可以运行它,你不需要在你的机器上安装任何东西。这通常非常有用,因为这意味着您可以将它放在 u 盘上,随身携带,并且您通常可以在其他机器上运行它,而不需要管理员权限(即无需安装任何东西)。然而,如果你一直找不到 Putty(它是如此简单,令人惊讶),你可能需要下载“安装程序”版本,它会将它安装在你的机器上,并为你设置开始菜单和桌面快捷图标。

现在我们有了油灰,是时候点火了。双击图标,您可能会看到与此非常相似的内容(图 3-6 ):

A978-1-4842-1162-5_3_Fig6_HTML.jpg

图 3-6。

Windows getting excited

Windows 只是警告您该程序尚未经过数字签名。你可能以前遇到过这种情况,但是当你安装一些所谓的安全增强软件时,你最不想做的事情就是安装一些令人不快的东西。在这种情况下,Putty 的正式版本没有签名,您可以忽略此错误。如果你打算经常使用 Putty,你应该取消勾选“打开文件前总是询问”。相信我们,如果你现在不做,十次或十一次后你会做的。

在你说服 Windows 退出后,你会得到一个类似这样的连接框(图 3-7 ):

A978-1-4842-1162-5_3_Fig7_HTML.jpg

图 3-7。

Starting up Putty

默认设置可以连接到您的 Pi,您只需要提供我们之前发现的 IP 地址。将此输入“主机名(或 IP 地址)”框,然后单击打开。由于这将是这台特殊的机器第一次连接到您的 Pi,您将会得到一个类似于下面的警告(图 3-8 ):

A978-1-4842-1162-5_3_Fig8_HTML.jpg

图 3-8。

Security warning when connecting for the first time

别担心,这是宋承宪安全系统的一部分。它让你知道它以前没有见过这个特定的服务器(它不会见过,不是吗?)并向您展示密钥以供确认。我们不知道有谁记住了他们的 SSH 指纹(尽管记住前四位和后四位数字对确保你有正确的指纹有很大帮助),而且在任何情况下我们都希望看到这个警告。一旦 Putty 记住了密钥,它将在您以后每次连接时对照 IP 地址和主机名进行检查。如果远程服务器发回不同的指纹,Putty 会警告您可能有问题。通常情况下,当您重建或购买新服务器时会发生这种情况,因此您知道为什么密钥会发生变化。如果你看到一个警告,却想不出一个好的理由,那么在登录到那台机器之前要非常仔细地思考。在我们的特殊情况下,我们知道密钥将是新的,所以我们可以简单地选择“是,保存密钥”。

现在,您将回到一个有些熟悉的黑色屏幕,上面有一些文本。到目前为止只会是:

用户名:

由于我们还没有设置不同的用户帐户,我们将作为“pi”用户登录,所以只需输入 pi 并按 enter 键。目前为止一切顺利。现在我们只需要提供您在初始安装时设置的密码。现在我们知道你按照我们的建议更改了密码(你做得对吗?)但是以防万一你没有,默认密码是 raspberry。输入密码,按回车键,最后我们应该得到我们想要的命令提示符:

pi@raspberrypi ∼ $

如果您没有 Mac(或者对使用 SSH 不感兴趣),请跳到下一部分——命令提示符。

LOOK BEFORE YOU LEAP

这属于“显而易见,除非证明不是这样”的范畴,但是当你使用远程终端时,很容易迷失方向,并在错误的机器上运行命令。如果你试图重启你桌子上的 Pi,你不希望意外重启其他东西,比如公司服务器(你永远不知道你的新 Linux 技能会把你带到哪里!).

Mac 上的 SSH

如果你使用的是 Mac 而不是 PC,你将无法使用 Putty。这不成问题,因为由于它的 Unix 根,Mac 内置了一个很好的 SSH 客户端。我们需要做的就是打开一个终端窗口并运行 SSH 命令。

首先,让我们启动并运行终端。您可以在“应用程序”内的“实用程序”目录中找到它。也可以使用 Spotlight(菜单栏右上角的放大镜,输入“终端”来查找。

您会发现它与您在 Pi 上使用的终端没有太大的不同,这是有原因的。正如我们前面提到的,Mac 实际上是基于 Unix 的,就像 Linux(以及 Raspbian)一样。尽管 Mac 很好地隐藏了它的 Unix 部分(你可以使用 Mac 很多年,但永远不会碰到它),如果你喜欢 Linux 和命令行,你可能想更深入地了解它。

现在我们已经打开了终端,让我们将它连接到您的 Pi。我们将使用 ssh 命令,因为没有 GUI,所以我们必须在命令行上指定相关选项。基于我们之前的例子,你的终端应该是这样的(图 3-9 ):

A978-1-4842-1162-5_3_Fig9_HTML.jpg

图 3-9。

Connecting to your Pi over ssh

为了节省空间,上面的截图显示了整个过程,而不仅仅是一个空的终端窗口。我们现在最感兴趣的是:

$ ssh pi@192.168.1.132

命令本身是 ssh,但是我们提供了一些附加信息;我们要连接的用户和 IP 地址。可以将选项读作“服务器 192.168.1.132 上的用户 pi”。有点像电子邮件地址,这是一个很好的简洁的方式来显示我们想连接谁以及我们想连接到哪里。你当然应该用你的 Pi 地址替换我们的 IP 地址。

每当您连接到新机器时,都会看到第一个文本块:

主机' 192.168.1.132 '的真实性无法建立。

ECDSA 密钥指纹为 B4:9a:a2:62:45:E5:70:F2:F3:F6:68:E0:B7:9a:ea:01。

您确定要继续连接吗(是/否)?是

警告:将“192.168.1.132”永久添加到已知主机列表中

pi@192.168.1.132 的密码

这只是 ssh 警告您它不能确定您是否正在连接到您认为正在连接的服务器的方式,并向您显示服务器用来识别自身的密钥。在这种情况下,你可以忽略警告,说是。如果您想了解更多关于它的含义,我们在 Windows 上的 SSH 一节中简要介绍了它。在您输入密码(raspberry 是默认的)之后,您应该会看到以下提示:

pi@raspberrypi ∼ $

现在您已经有了命令提示符,我们将看看它的实际含义。

WHAT’S SO SPECIAL ABOUT SSH?

SSH 或 Secure Shell 实际上是远程访问任何 Unix 类机器的标准。它甚至受到许多网络设备的支持,如打印机和高端交换机。它之所以如此受欢迎,是因为它加密了你的计算机和服务器之间的所有数据。如果有人在监听你的连接,他们得到的只会是垃圾。它还允许您验证服务器是否是您认为的服务器。

在我们有 SSH 之前,每个人都使用 telnet。这是一个非常简单的协议,没有任何加密。这意味着,如果任何人都可以看到你的流量(想想公共机器或 WIFI 接入点),就有可能以明文形式从网络上读取你的密码。Telnet 也无法确认您所连接的机器的身份,这意味着您永远无法确定您是否无意中向他人提供了您的用户名和密码。

仍然可以在 Linux 上安装 telnet 服务器,但是不鼓励这样做。没有什么好的理由比 SSH 更喜欢 telnet,所以当您在远程服务器上工作时,应该总是使用 SSH。

欢迎使用命令行

无论您选择哪条路线到达终端,最终结果都是一样的,也就是说,您最终会看到一个类似如下的命令提示符(或简单的提示符):

pi@raspberrypi ∼ $

这里实际上有相当多的信息,但它都意味着什么呢?你也许可以从我们到目前为止在书中所做的事情中猜出大部分,但是为了完整起见,这里是它是如何分解的。

第一部分(例子中的 pi)是用户名。当您只有一个 Pi 和一个用户时,这不是特别有用(或者令人敬畏)。然而,当您最终不得不管理许多用户或者当您有不同机器的各种帐户时,它是非常有用的。这就是第二部分的用武之地(示例中的 raspberrypi ),因为它告诉我们所连接的机器的主机名。总之,这让我们知道我们是谁,我们在哪里。同样,对于一个圆周率来说不是很有用,但是这些信息总有一天会派上用场。

Caution

我们已经在其他地方强调了这一点,但它非常重要,我们要再说一遍。当您打开多个终端时,很容易在错误的服务器上运行命令。有时,在您意识到自己的错误之前,您会运行多个命令。通常不会造成伤害,但是如果您在工作中意外地重启了一个关键服务器,而您实际上是想重启您的 Pi,那么您将成为 IT 部门的头号报复对象。

提示符的下一项(或波浪符号)实际上告诉我们当前在哪个目录中。波浪号是一个特例,因为它指的是当前用户的家庭区域。你可以把它想成简写,因为它就是简写。每当您引用您的主目录(在本例中是/home/pi)时,我们可以简单地用波浪号替换它。下面是一个简单的例子:

pi@raspberrypi ∼ $ pwd

/home/pi

pi@raspberrypi ∼ $ cd ∼

pi@raspberrypi ∼ $ pwd

/home/pi

pi@raspberrypi ∼ $

这里我们使用了“pwd”(打印工作目录的缩写),它打印出了我们当前所在目录的完整路径。在我们的例子中,它输出/home/pi,因为这是 pi 用户的主目录。然后,我们使用“cd”命令(change directory 的缩写)转到目录。我们再次使用“pwd ”,并能够验证在更改目录后,我们又回到了开始的地方。我们将在下一章更彻底地解释这些命令,但是这些命令行的东西难道不是至少有点意思吗?

当在一般讲话中提到'∾'时,你称它为“主目录”。因此,如果您在我们的示例中坐在提示符下,有人问您在哪个目录中,您会说您在自己的主目录中,或者如果您想明确一点,您会说您在 pi 用户的主目录中。如果你想得到真正具体的,你甚至可以提到主机名。你不会说你是在波浪号或“摆动线”目录。

然而,当你给某人一条进入的路径时,你会说颚化符。例如,如果您希望用户转到“∨/test/”,您可以说“键入 cd 空格符斜杠测试斜杠,然后按 Enter”。这是因为在这种情况下,代字号指的是您为了方便到达某个位置而使用的特定内容,而不是实际告诉某人该位置是什么。这也有助于防止相对路径的混淆,但同样,这是下一章的内容。

Note

我们听过 tilde 发音为“tilled”和“till-duh ”,所以你应该会在野外听到这两种发音。不过有趣的是,你可能会发现无论你使用哪一个,人们都很难理解你,这甚至适用于有经验的管理员。这不是因为你读错了,只是他们不知道“1 键左边的波浪线”实际上叫做波浪线。如果你发现自己处于这种情况,称之为“摇摆不定的线”似乎是一个相当安全的赌注。

命令提示符的最后一部分显示了您的访问级别。谈到系统特权,Linux 系统是非常基本的。这通常可以归结为你要么是根用户,要么不是。如果您是 root 用户,那么您可以不受限制地做任何事情。如果你是任何其他用户,预计会发现你的能力大幅削减。如今,这种情况已不像以前那样真实,因为有一些工具,如“sudo ”,允许管理员授予以 root 权限运行某些命令的能力,而无需该用户访问 root 帐户。当然,最终,sudo 以 root 用户身份运行,它只是决定是否运行您要求它运行的命令,所以实际上它仍然遵守全有或全无规则。

从提示的角度来看,如果您是普通用户,您会得到一个美元符号作为提示。我们以 pi 用户(显然不是根用户)的身份登录,因此我们也有$号。如果我们以 root 用户身份登录,我们将是特权用户,因此我们将获得散列符号(如果您不是来自英国,则为井号)。根提示符如下所示:

root@raspberrypi ∼ #

散列符号是一个标志(也是一个警告),表示您正在以提升的权限运行,因此您应该对键入的内容非常小心。提示符还显示用户名为 root,这提供了一个额外的指示。然而,这些微妙的提示很容易被忽略(人们不倾向于研究每个命令前的提示),所以再次强调,在按回车键之前,总是检查你是谁和你在哪里。

这就是提示的全部内容。大多数 shells 允许您定制它来显示不同的信息,偶尔一些管理员会更改这一点。根据我们的经验,大多数人都不会在意,我们也很少觉得有必要自己去改变它。我们在这里提出这个问题的原因是,如果你登录到另一台 Linux 机器上,而提示完全不同,那就不必担心了。终端的工作方式完全相同,只是提示符被定制了。

不同的 Shell

好吧,当我们说所有的终端都一样工作时,也许我们把事情简单化了。事实上,有一些细微的差别,特别是在它们支持的特性上,但是通常你不会注意到。事实上,当远程机器使用不同的 shell 时,很可能会发现这一点。shell 是一个和其他程序一样的程序,但它不是一个浏览网页或阅读电子邮件的工具,它提供了一个命令行让你和操作系统进行交互。它就像一个包裹着内核的包裹物,这就是它的名字——就像花生米一样包裹着内核。

到目前为止,我们一直在使用 BASH 或 Bourne Again Shell。它是目前最流行的 shell,在每个 Linux 发行版中都有。它通常也是默认的,这就是为什么你永远不用太担心你的系统运行的是哪一个 shell。

我们之所以在这里提出这个问题,是因为就像开源世界中的其他事情一样,对于什么是最好的 shell,人们有不同的看法。有些采用了一种简单的方法,只支持最基本的特性,而 BASH 这样的 shells 自带电池,拥有的特性比你摇一摇棍子能想到的还要多。尽管 BASH 很受欢迎,但可以想象,在您杰出的 Linux 职业生涯中的某个时刻,您可能会遇到其他事情,预先警告是有备无患的。

我们不打算花更多的时间来看不同的 Shell,因为老实说,你可能永远不需要担心它。即使一台机器使用不同的 shell,您也可以启动 BASH 来替换它(大多数系统都安装了 BASH,即使您登录时使用了不同的 shell)。因为无论您使用哪种 shell,系统命令都是相同的,所以即使您无法使用 BASH,您也可能会发现您可以做任何您通常会做的事情。事实上,大多数 shell 在很大程度上是可以互换的,即使您在使用另一个 shell,您也可能不知道!

摘要

这一章向你介绍了这个码头和它丰富的(如果不是非常迷人的)历史。然后,我们讨论了终端今天是如何使用的,以及它是如何适应我们的现代需求的。然后我们看了在 Pi 上访问终端的三种主要方式,主要是控制台、虚拟终端和通过 SSH 访问网络。接下来,我们快速描述了命令提示符,并提到了一些有趣的命令来强调一点(我们绝对保证在翻页时会解释这一点),最后,我们总结了这一章,向您介绍了不同的 shells,以及它们可能(但可能不会)如何让您出错。

在下一章中,你需要知道如何愉快地浏览你的 Pi,创建文件,修改文件,删除文件等等。这是我们开始真正认真对待命令行的地方,也是您开始获得一些实际技能的地方。

四、通向成功的文件路径

在这一章中,我们来看看什么是文件系统,以及不同的操作系统是如何理解它们的。我们解释了单独的根文件系统和统一的根文件系统之间的区别,以及为什么预先知道这一点会省去您很多麻烦。

然后,我们继续查看您的 Pi 上显示的文件系统。我们探索标准布局,并解释什么去哪里,它实际上做什么。我们还将展示一些简单的命令,强调 Unix“一切都是文件”的系统设计方法的一些好处。

接下来,我们将向您展示如何在系统中移动,您将了解完全限定路径和相对路径。我们将向您展示如何创建目录和文件(然后复制、移动和删除它们),以及如何创建相当于快捷方式的 Linux。

然后,我们将以对 Linux 文件权限的探索来结束这一章,并向您展示 Linux 如何决定谁可以对您的文件做什么。我们还将涉及用户和组,并向您展示如何设置您自己的文件的所有权和文件权限。

什么是归档系统?

我们实际上已经计划从字典定义开始这一部分,然后是我们的解释。不幸的是,我们能找到的大多数定义基本上都是说“归档系统是一个归档系统”,我们将不得不跳过这一部分,直接进入我们自己的定义。然而,这确实表明,尽管文件系统说起来容易,但定义起来却困难得多。但是对我们来说,我们认为归档系统是:

一种对数据进行排序和分类的方式,使查找更容易。

这个定义涵盖了一切,从简单的收件箱(至少你知道文件在哪里,即使你不能马上把手放在上面),到你在手机上查看联系人的方式(这是一个字母系统),一直到一些更奇特的系统,如杜威十进制系统,用于在当地图书馆对非小说内容进行分类。

实际上,图书馆是文件系统的一个有趣的用例,因为大多数图书馆至少同时运行两个。一般来说,图书馆倾向于按照作者的姓(然后是名)来排列虚构的作品,而非虚构的部分是根据他们的杜威十进制数来排序的。通过同时使用两个系统,他们解决了一个基本问题。如果你有一个最喜欢的作者,并想找到更多他们的书,按作者的名字存储书籍是很棒的。不过,说到非小说类,你可能想浏览某个特定主题的精选书籍,但往往你心里没有特定的作者。如果这些书按作者名分类,你可能永远也找不到任何东西。

一些图书馆更进了一步,首先根据流派(比如科幻或奇幻)对虚构书籍进行分类,然后在这一类别中,他们根据作者姓名进行分类。这有一些非常好的好处。你仍然可以直接找到你最喜欢的作者,因为你知道他的类型,但是你也可以浏览相同类型的类似书籍。如果你正在寻找奇幻类的下一个最佳作品,你可以简单地站在那个区域快速浏览。

目前为止一切顺利。归档系统使寻找东西变得更容易,我们可以看到使用正确的归档系统对任务的重要性,否则你可能会比没有归档系统更好。但是他和电脑有什么关系呢?任何计算机的主要任务之一是处理信息,这意味着它必须能够轻松地存储和检索信息。旧的计算机系统确实使用字母系统,而且运行得非常好,但是一旦你开始建立一些文件,它就开始变得非常混乱,找到你想要的就成了一个挑战。这个问题可以通过创建一个目录(现在通常称为文件夹)来解决,在这个目录中可以放置相关的文件。这很有帮助,但同样的老问题开始在人们身上蔓延。是的,你可以有一个账户目录和一个纳税申报表目录,但是如果你是一家会计公司,你有很多账户和很多纳税申报表,那该怎么办呢?很快,您又回到了开始的地方,因为您要么拥有包含大量文件的少量目录,要么拥有仅包含一两个文件的大量目录。

文件系统结构的最后一个变化是允许目录包含其他目录,这一点至今仍为人们所熟悉。这将允许您以最合适的方式灵活地存储内容。像往常一样,有多种方法来排列给定的文件集,但总的来说,这个系统为我们提供了很好的服务,借助现代搜索技术,找到我们想要的东西比以往任何时候都更容易。

不止一个文件系统

这就是我们使用这种方法遇到的一点障碍。文件系统位于某种形式的存储之上。它可以是硬盘、u 盘、DVD 或任何数量的存储介质。每个设备实际上相互独立。这是有意义的,因为你可以从你的笔记本电脑上拿一个 u 盘,然后在你的台式机上使用它。很明显,u 盘上的文件系统和你的笔记本电脑之间没有联系,否则你的电脑就没有找到文件所需的所有信息。

每个文件系统都有一个“根目录”。这是设备上的第一个目录,它包含所有其他文件和目录。像树根一样,所有的文件和目录都从这个中心位置分支。不过这确实带来了一点问题。如果每个设备都有自己的文件系统和根目录,如何轻松地将这种结构呈现给最终用户?事实证明,它们是解决这个问题的两种方法。第一个是单独的根,第二个是统一的文件系统。

分离根

这种方法早在 MSDOS 时代就被微软采用了,并且一直沿用到今天。方法很简单。每个设备都有自己的根条目,然后用户可以使用该条目来定位感兴趣的设备,然后可以像平常一样简单地导航文件系统来找到该文件。在 Windows 下,每个根目录都有自己的字母。由于历史原因,Windows 上的系统盘被称为“C:”你会经常听到人们称之为“c 盘”。软驱被分配给 A:和 B:(有硬盘的个人电脑倾向于有两个软驱)由于很少有人有一个以上的硬盘,光驱倾向于被分配给 D:。

这个系统真的很容易使用,从来没有任何混乱的特定文件在哪里,因为你可以告诉简单地看看驱动器号。然而,这种设计有几个问题。首先,由于根设备被分配给字母,字母表中只有 26 个字母,因此您只能使用 26 个设备。即使在今天,这对家庭用户来说也几乎不是问题,但是当企业使用大型主机时,他们可能有数百台这样的设备。

第二个问题是用户必须知道他们的文件的物理位置。这实际上会增加复杂性,因为它将文件的位置与文件所在的物理设备联系在一起。如果系统中添加了一个更大的磁盘,并且文件被移动到新的位置,那么它们的根设备将会改变。任何依赖于文件位置的人(或软件)都需要更新,这可不好玩。

简而言之,尽管 Windows 使用的系统简单而有效,但在非常大的分布式系统上,它会成为一个管理难题。现在有很多方法可以解决这个问题,新的技术已经出现,将这种结构隐藏在表面之下,所以对于今天的 Windows 系统来说,这真的不是一个大问题。然而,当 Unix 占据主导地位时,这些技术还不可用,它们采用了另一种方法,即统一文件系统。

统一文件系统

基于 Unix 的 Linux 有统一的文件系统。这意味着,与拥有多个根设备的 Windows 不同,Linux 系统只有一个根设备,并且总是安装在“/”上,这是 Unix 中的根目录。如果只有一个根目录,那么 Linux 如何处理额外的设备,我们知道这些设备都包含它们自己的文件系统?

解决方案是获取新设备的根目录,然后将其附加到树中的现有目录。这就是所谓的挂载文件系统。这允许 Linux 拥有几乎无限数量的设备,因为它可以将它们连接到现有树中的任何位置。这意味着您可以装载一个设备,然后在第一个设备内的目录中装载另一个设备。从用户的角度来看,他们可以在所有这些不同的目录中移动,就好像他们都在一个大设备上一样。物理结构(即所有磁盘和磁盘上的原始数据)对最终用户完全隐藏。他们没有办法知道他们已经从一个设备穿越到另一个设备。

这解决了分离根方法突出的问题,因为无论底层机制是什么,统一文件系统都是一致的。事实上,您可以将网络文件共享甚至虚拟文件系统挂载到树中。当然,分离根方法的优点现在已经变成了统一方法的缺点。要看清事情的走向不再容易,这又会让事情变得更加混乱。像 Windows 一样,Linux 系统也随着时间的推移而发展,所以这些问题不像在其他情况下那样明显。然而,这些好处大多是在 GUI 中看到的,在使用命令行时往往不太明显。

苹果电脑必须与众不同

作为一个有趣的对比,Mac 上的 OSX 同时使用了这两种方法。在幕后,OSX 是一个基于 Unix 的系统,所以它有一个统一的文件系统。然而,除非你使用命令行(大多数 Mac 用户不会这样做),否则你永远看不到这方面的证据。当你把 u 盘连接到 Mac 电脑上时,它会以与 Linux 类似的方式安装 u 盘,但它会以与 Windows 类似的方式向用户展示 u 盘,就好像它是自己的根设备一样。然而,Mac 并不分配驱动器号,它只是设置了一个唯一的名称。

把所有的东西放在一起

诚然,这是一个相当不错的理论,你可能想知道我们承诺向你展示的所有有趣的命令在哪里。你可能还想知道为什么我们会让你厌烦这些,以及这些信息什么时候(如果有的话)会有用。我们一开始就强调这一理论的原因是,当我们开始使用 Linux 时,许多事情使我们摆脱了使用其他操作系统的先入之见。大约 15 年前,当我们中的一个人第一次安装 Linux 时,他花了几个小时咒骂才弄明白“你需要一个根“/”设备是什么意思。这不仅仅是 Linux 的问题,对 BSD 操作系统家族及其处理磁盘的替代方式的涉猎导致我们擦除了错误的磁盘,因为我们考虑的是 Linux 而不是 BSD。

因此,希望这最后一节将把你从我们刚开始时所经历的痛苦中解救出来。你不需要记住所有的理论,但是如果你在阅读完这一部分后,意识到尽管有许多相似之处,但 Linux 不是 Windows 或 Mac,那么你将会领先于这个游戏。

所有东西都作为一个文件

现在,当我们讨论这个话题时,我们通常从谈论硬盘分区开始,因为大多数人都熟悉硬盘分区,并且在 Linux 呈现它们的方式和物理设备本身之间有一个很好的简单映射。由于 Pi 在技术上没有硬盘(它拉一些线使 SD 卡看起来和感觉上像一个硬盘),这个简单的例子在 Pi 上实际上是不可用的。问题是,这个例子太好了,不能错过,所以我们要坚持经典。所以,事不宜迟,下面是描述我们的一个服务器上的磁盘设置的文件:

/dev/sda

/dev/sda1

/dev/sda2

/dev/sdb

/dev/sdb1

如您所见,这些文件都位于/dev 目录中,这是 Linux 保存所有设备文件的地方。关于这一点还有很多要说的,但是我们稍后会回到这一点,相信我们,如果我们最后讨论它,会更有意义。所以现在,让我们忽略目录,专注于我们的文件集合。您会注意到,在这个示例中,所有文件都以“sd”前缀开头。这是因为它们都是“SCSI 磁盘”,并且共享相同的驱动程序。出于兴趣,对于具有基于 IDE 的磁盘的机器,前缀是“硬盘”的“hd”。

现在我们知道我们有一些基于 SCSI 的磁盘(SATA 磁盘也显示为 SCSI ),但是从这些文件中我们还能知道什么呢?你会注意到我们有 sda 和 sdb。系统上的第一个 SCSI 磁盘分配给 sda,第二个分配给 sdb。得知第三个磁盘最终将被分配给 sdc 时,可能不会感到意外。由于我们在示例中没有看到 sdc,我们可以假设这个系统上只有两个磁盘。

现在我们真的有所进展了。我们可以看到我们的系统上有两个 SCSI 磁盘,现在我们只剩下一件事要讨论了——名称末尾的数字。在这种情况下,编号是指驱动器上的分区号。第一个分区是 1,第二个分区是 2。很好,很简单,我们确信没有真正的惊喜。有了这些附加信息,我们不仅可以指定哪个磁盘,还可以指定该磁盘上的哪个分区。

这当然引出了你为什么要关心的问题。肯定有更简单的方法来找出系统连接了哪些磁盘吧?你可能是对的,但我们并不是通过这个来发现什么连接到系统,而是看我们如何指定我们想要访问的特定设备。请记住,Linux 中的一切都是文件,所以即使是物理设备也是以这种方式表示的。当我们想访问一个硬盘或我们想访问一个特定的部分,我们这样做是访问相关的文件。

一些真实世界的例子在这里会很有用。当你想改变硬盘上的分区表时,你可以使用“fdisk”工具。fdisk 工具当然需要知道您想在哪个磁盘上工作。假设您想要对第二个磁盘进行分区,该命令如下所示:

fdisk /dev/sdb

因为我们正在对驱动器本身进行分区,所以我们希望引用整个设备,而/dev/sdb 允许我们这样做。但是,假设我们已经完成了分区,并且我们有一个大分区,我们想格式化它以供 Linux 使用。命令是 mkfs.ext4(在现代 Linux 发行版上),和以前一样,您需要告诉命令您想要格式化什么。在这种情况下,我们希望第一个分区位于第二个磁盘上,因此命令如下所示:

mkfs.ext4 /dev/sdb1

同样,这是有意义的,因为我们指的是特定设备上的特定分区。这里没有大的信仰跳跃,但我们现在可以和你分享一个小秘密。mkfs.ext4 命令并不真正关心您给它取了什么文件名。如果你忘记在末尾加上“1 ”,它会很高兴地格式化整个设备。这是一个“一切都是文件”的例子——因为一切都是文件,文件都以同样的方式访问,我们的工具只是简单地读写文件——它们既不知道也不关心它们写的是什么!

这个概念需要更多的努力才能真正理解。在幕后,Linux 为我们管理所有这些不同的设备,每一个都有自己特定的需求和驱动程序。为了让应用程序开发人员(更不用说用户)简单,Linux 隐藏了所有这些复杂性,而是将每个设备作为一个特定的文件呈现给我们。这让我们很好地回到了/dev 目录(我们告诉过你它会出现)。该目录中的文件很特殊,因为它们并不真正存在,至少不是存储在任何地方的物理文件。Linux 创建一个虚拟文件系统,然后用给定计算机上可用设备的文件填充它。因为我们的 Pi 没有任何 SATA 或 SCSI 磁盘,所以您不会在您的 Pi 上找到任何/dev/sd 文件。

文件系统布局

好了,现在让我们看看文件系统是如何在您的 Pi 上布局的。你会发现它的结构与你在任何 Linux 系统上发现的非常相似,所以这不仅会帮助你掌握你的 Pi,而且你也能浏览服务器。所以让我们陷入…

/(根目录)

这是根目录(不要与根用户的主目录混淆),代表文件层次结构的顶层。所有东西都在这个目录中或目录下,没有例外。正如我们在本章前面所讨论的,Linux 有一个统一的层次结构,这是一切的起点。

/root

这是根用户的主目录,大部分时间都与根目录(即“/”)混淆。这可能会变得更加混乱,因为如果你在根目录中,有人让你“进入根目录”,他们实际上指的是哪一个?通常你可以很容易地从上下文中判断出来,但如果不能,不要害怕要求澄清;你会惊讶这个问题出现的频率。

/等等

/etc 可以说是系统中最重要的目录之一。它不仅包含您的系统的所有配置文件,还包含您可能已经安装的应用程序(比如 Apache web 服务器)。许多不熟悉 Linux 的用户小心翼翼地备份他们的应用程序,但是经常忘记存储在/etc 中的配置。在一天结束的时候,应用程序通常可以很容易地被替换,但是从头开始进行正确的配置却是一件非常头疼的事情。这是一个你想要非常小心的目录。

/proc

/proc 是一个虚拟文件系统,内核使用它来提供从用户空间工具的简单访问。您需要了解的关于系统状态或正在运行的进程的所有信息都可以在/proc 中找到。两个常见的例子是 CPU 配置(存储在/proc/cpuinfo 中)和内存使用(存储在/proc/meminfo 中)。这些信息大部分是只读的,这是有意义的,因为它只是一个虚拟的表示。然而,有些文件确实允许双向通信,你可以在机器运行时用它来调整内核和系统设置。

/var

/var 通常是您可以找到由您的应用程序和系统本身创建的文件的地方。例如,大多数应用程序将它们的日志存储在/var/log/中,许多应用程序将锁文件存储在/var/run/中。apache web 服务器过去使用/var/www/来存储网站文件。事实上,我们在前一本书里强调了这个特性。在现代发行版中,这种文件不再位于/srv/目录中。

/boot

传统上,/boot 目录实际上位于第一个硬盘上自己的小分区中。当时,大多数计算机都不能从一个大分区启动,所以看到这些分区分开是很常见的。在现代机器上,这不再是一个问题,所以这个目录通常直接包含在根目录中。顾名思义,它保存了引导系统所需的关键文件,包括引导装载程序和 Linux 内核本身。

/bin 和/sbin

这些位置分别存储用户和管理程序。通常,普通用户的路径中只有/bin,所以他们实际上看不到/sbin 中的应用程序。有些应用程序用户可以访问,尽管它们通常只由管理员使用,但是用户需要知道它们在哪里。通常这不会造成问题,你也不需要去寻找任何东西。

/开发

我们已经在“一切作为文件”一节中提到了这个目录。它包含当前系统上每个设备或子设备的文件,并为系统工具(当然还有用户)提供了一种方便地访问特定机器上的硬件的方法。除了我们前面提到的磁盘设备,还有显卡、声卡、虚拟终端等设备。

Note

您不会在/dev 目录中找到网卡,因为它们被视为特例。要查找网络接口的信息,您需要使用“sudo ifconfig -a”命令。这将列出 Linux 知道的所有网络设备。

/home

传统上,所有用户主目录都存储在/home 下,这通常是它自己的分区、磁盘或网络共享。这个想法是将用户数据与系统数据和应用程序分开。大多数基于 Unix 的系统仍然遵循这一规则,但是有时您会将一些主目录放在其他地方,例如根用户的主目录。例如,Mac 将主目录存储在/Users 中,一些企业会根据不同用户的需求将他们放在不同的位置。虽然/home 通常只包含主目录,但并不要求主目录实际驻留在这里。

/库

该目录包含各种应用程序所需的库文件。库允许将功能打包,然后由其他应用程序共享。数据库驱动程序就是一个很好的例子。为了让这些应用程序能够找到这些库,需要将它们安装在一个已知的位置,并使用一个已知的文件名。很少需要查看这个目录,但是如果您这样做,您应该小心,因为破坏这里的内容可能会影响系统的稳定性。

/丢失+找到

我们提到这一点是为了完整性,但它本身并不是文件系统结构的一部分。相反,它是当文件系统失去对文件的跟踪时,文件被放置的地方。例如,如果磁盘损坏,您需要运行磁盘修复。有些文件可以恢复,但由于各种原因,可能无法确定该文件的来源。如果发生这种情况,Linux 将把那些迷失的灵魂放在这个目录中。我们从来没有理由查看这个目录,而且很可能你也永远不需要查看那里。最后,这个目录可以出现在任何挂载的文件系统的根目录中,而不仅仅是在/中,因为每个文件系统都必须独立地跟踪它丢失的灵魂。

/媒体

这个目录对于 Linux 来说相对较新,添加它是为了明确区分挂载的外部设备(如/mnt 中的设备)和可移动介质(如 USB 棒、相机和媒体播放器)。在 Linux 下这些通常是自动处理的,所以通常你不会手动添加或删除这个目录中的任何东西。

/mnt

作为 mount 的缩写,/mnt 目录通常是您挂载附加文件系统的地方。如果您想要附加一个网络共享或一个外部硬盘,您应该在/mnt 中创建一个目录并挂载到那里。软盘和 cdrom 在这里通常也分别称为/mnt/floppy 和/mnt/cdrom。然而,在最近几年,这个目录大多已经半途而废。

/usr

这是机器上大部分软件的最终位置,因此它通常是服务器上最大的目录(至少如果不计算用户的主目录)。虽然知道软件在你机器上的位置是有用的,因为一切都是自动为你处理的,这里的一切都应该“正常工作”。

/opt

这个目录是万能的。在一些系统中,它装满了应用程序,而在另一些系统中,它完全是空的。它通常用于第三方软件和应用程序。例如,默认情况下,Oracle 数据库服务器安装在/opt/中。您可能找不到使用这个目录的理由,但是如果您这样做的话要小心,因为在进行备份等操作时,很容易忘记/opt/中的内容。

/srv

另一个相对较新的,/srv/目录是为服务文件的服务存储数据的指定位置。例如,这是 Apache web 服务器的新家。尽管这个目录似乎存在,但是一些应用程序仍然不使用它,或者出于习惯,或者仅仅是因为每个人都习惯于其他地方的内容。如果您正在寻找曾经在/var/中的东西,这可能是接下来要寻找的一个好地方。

/sys

这个目录包含系统信息,像/proc 一样,它只存储在内存中,因为它是一个虚拟系统。它似乎没有得到太多的使用,我们自己甚至从来没有看过这个目录。然而,我们有可靠的消息称/sys 非常有用,我们应该非常乐意拥有它。

/tmp

这个目录是计算机的暂存区,各种应用程序都在这个目录中创建文件。每当使用临时文件存储时(例如在处理过程中),都会使用它。历史上,这个目录应该在重启时清空,但实际上很少这样做。随着更新的发行版转移到 systemd,/tmp 几乎肯定会在重启时消失。如果你在这里放任何东西都要非常小心,因为它不太可能在你重启 Pi 后存活。

包装它

这基本上总结了 Linux 文件系统的关键领域。毫无疑问,当你环顾你的系统时,你可能会遇到其他小角落和缝隙,但它们可能是其中的一个子集。请记住,虽然大多数系统都遵循这种结构,但大多数并不一定意味着全部,您可能会遇到一些不同之处或目录以其他方式使用的地方。

让它发挥作用

到目前为止,我们在这一章中已经讲了很多。我们已经研究了文件系统如何工作,以及 Unix 系统(尤其是 Linux)如何采用统一的方法。我们看着“所有的东西都是一个文件”,我们展示了这些特殊的文件和文件系统如何适应事物的大计划。我们总结了所有这些,概述了文件系统上的内容以及它们的作用。我们还没有做的是实际上自己使用文件系统。

到目前为止,我们已经相当“解放双手”,但这一切都将改变这一部分。我们将从向您展示如何创建目录和在文件系统中移动开始。一旦我们给了你创造的能力,我们就给你毁灭的能力,你就可以随意删除文件和目录(这并不总是一个好主意)。我们将用一个关于 Linux 文件权限以及如何读取和设置它们的快速概述来结束这一节。让我们开始吧!

我们在哪里?使用 pwd

我们首先要向您展示的是如何找出您在系统中的位置。找到方向的最简单方法是查看命令提示符。我们在上一章谈到了这一点。作为快速复习,下面是我们在主目录中时命令提示符的样子:

[pi@raspberrypi ∼]$

波浪号(又名曲线)是当前用户主目录的缩写。当我们第一次介绍这个特性时,我们已经强调了它,所以我们不会再重复了,但是让我们看看当我们在/usr/lib 目录中时它是什么样子的:

[pi@raspberrypi lib]$

这可能会带来一个问题。我们知道我们在/usr/lib 中,但是提示只显示了路径的最后一部分。这实际上是一个好主意,因为尽管你可以设置你的提示来显示整个路径(这在当时看来是一个好主意),但是当路径占据了大部分屏幕时,你很快就会变得不耐烦。但这并没有解决问题。据我们所知,我们可能在/usr/lib 或/danger/lib 中。不用说,这可能会带来不愉快的后果。所以我们需要的是‘pwd’命令。我们在上一章中也提到了这个有用的工具,但是如果你错过了它,它又出现了:

[pi@raspberrypi lib]$ pwd

/usr/lib/

[pi@raspberrypi lib]$

这个工具对于告诉我们我们在哪里非常有用,但是它不能告诉我们在同一个位置有什么。就像被蒙上眼睛,告诉你站在厨房里;这是一个很好的开始,但你实际上仍然是盲人。您肯定想知道房间里有谁和什么,为此我们需要“ls”命令。这个命令有大量的选项,所以我们将只讨论最常见的选项,也就是我们每天都在使用的选项。实际上,你可以把它们记为食谱,因为你经常会一次又一次地传递相同的选项(或者至少我们是这样)。

首先,让我们回到我们的主目录:

[pi@raspberrypi lib]$ cd ∼

我们这里有什么?使用 ls

现在让我们看看这里有什么:

[pi@raspberrypi ∼]$ ls

Desktop    python_games

[pi@raspberrypi ∼]$

虽然我们不能轻易在书中表现出来,但是 Desktop 和 python_games 都是深蓝色的。这告诉我们它们是目录。目前我们在这个目录中没有任何文件,是吗?实际上我们有,但是它们被认为是隐藏文件。在 Linux 下,任何以句点(或句号)开头的文件都被认为是隐藏的。文件本身没有什么特别的,它们通常是各种应用程序创建的各种配置或临时文件。我们通常不希望这些文件弄乱我们的显示,所以 ls 和朋友不会显示它们。但是,我们可以强制 ls 向我们显示那些带有'-a '标志的文件,如下所示:

[pi@raspberrypi ∼]$ ls

.  ..  .bash_history  .bash_logout  .bashrc  .profile  python_games

[pi@raspberrypi ∼]$

使用 Touch 创建要使用的文件

现在,我们将不再使用-a 标志,而是创建我们自己的文件来使用。由于我们还没有介绍如何创建和编辑文本文件(我们将在第七章中告诉你如何做),我们将向你介绍另一个叫做“触摸”的小工具。在 Linux 下,文件有两个时间戳——创建时间戳和最后修改时间戳。这些允许您查看文件的创建时间和最后更新时间。从管理的角度来看,这是很有用的,因为您可以看到哪些文件正在被使用,但是各种工具(如备份脚本)使用这个时间戳来判断自上次查看以来文件是否发生了更改。有时,能够在不改变文件内容的情况下更新时间戳是很有用的,这就是 touch 的用武之地。它会接触更新时间戳的文件,但是如果该文件当前不存在,那么 touch 会为您创建它。换句话说,这是一个创建空文件的好工具。因此,让我们从创建两个最初命名的文件开始:

[pi@raspberrypi ∼]$ touch raspberry

[pi@raspberrypi ∼]$ touch pi

[pi@raspberrypi ∼]$ ls

Desktop pi python_games raspberry

[pi@raspberrypi ∼]$

这就是全部了。正如你从后面的 ls 中看到的,我们现在有两个额外的文件。这次它们是灰色的,这告诉我们它们是普通文件。通过给条目着色,ls 让我们更容易看到我们在做什么。例如,任何可执行文件都将被标为绿色,但是我们将在本章的后面回到文件权限。

到目前为止,我们只有两个文件,但如果我们有十个或二十个,这里会变得有点拥挤。处理的方法当然是创建目录来存储我们的文件(可能还有其他目录),这是我们接下来要看的。

Note

目录和文件夹基本上是一回事。最初称为目录,微软开始称它们为文件夹,他们觉得这是一个更好的描述。虽然 Linux 过去使用目录这个术语,但是随着人们从 Windows 迁移过来,它已经变得更像一个桌面操作系统,文件夹这个术语也变得越来越普遍。

使用 Mkdir 来存储我们的文件

要创建目录,我们使用“mkdir”或“make directory”命令。不出所料,这将创建一个新目录。但是,如果存在同名文件或目录已经存在,您将得到一条错误消息。让我们创建一个名为“pifun”的目录来存储我们的文件:

[pi@raspberrypi ∼]$ mkdir pifun

[pi@raspberrypi ∼]$ mkdir pifun

mkdir: cannot create directory ’pifun’: File exists

[pi@raspberrypi ∼]$

如您所见,尝试创建目录两次将会导致错误。不要被“文件存在”分散注意力,这实际上可能指的是目录或文件。另一个快速 ls,我们会看到事情进展得非常顺利:

[pi@raspberrypi ∼]$ ls

Desktop pi pifun python_games raspberry

[pi@raspberrypi ∼]$

使用我们的新目录,使用 mv 命令

现在我们有了目录,让我们收拾一下我们制造的混乱。因为我们想要将文件移动到我们的新目录中(而不仅仅是创建它们的副本),我们需要使用' mv '(或' move ')命令。这个命令比我们之前讨论过的命令稍微复杂一点,因为它需要两个参数而不是一个。这是有意义的,因为我们不仅需要告诉 mv 我们想要移动的内容,还需要告诉它我们想要将文件移动到哪里。与 Linux 下的大多数文件命令一样,第一个参数是源,第二个参数是目的。让我们现在移动这些文件:

[pi@raspberrypi ∼]$ mv pi pifun

[pi@raspberrypi ∼]$ mv raspberry pifun

[pi@raspberrypi ∼]$ ls

Desktop pifun python_games

[pi@raspberrypi ∼]$

目前为止一切顺利。现在我们要确保我们的文件完整无缺地到达。有两种方法可以做到这一点。我们可以用“cd”进入 pifun 目录,然后运行 ls 命令,或者,我们可以简单地给 ls 我们想要查看的目录的路径。我们已经使用了第一种方法,所以让我们试试第二种方法:

[pi@raspberrypi ∼]$ ls pifun

pi raspberry

[pi@raspberrypi ∼]$

克隆的时间到了,如何使用 cp 命令

诚然,这不是很令人兴奋,但作为一名新上任的管理员,您将花费大量时间移动文件和检查东西的位置。到目前为止,你已经学会了如何移动一个文件,但是如果你只是想复制一个文件呢?当备份或选择一些文件准备发送给朋友时,您实际上想要保留原始文件。为此,我们使用“cp”命令,你可能已经猜对了,它是“copy”的缩写。让我们进入新目录,复制我们的一个文件:

[pi@raspberrypi ∼]$ cd pifun

[pi@raspberrypi pifun]$ cp pi pi2

[pi@raspberrypi pifun]$ ls

pi pi2 raspberry

[pi@raspberrypi pifun]$

这很好,我们现在有了 pi 和 pi2,正如我们所预期的。让我们再次尝试同样的事情,只是这一次,我们将复制一个目录:

[pi@raspberrypi pifun]$ mkdir moarpi

[pi@raspberrypi pifun]$ cp moarpi moarpi2

cp: ommiting directory ’moarpi’

[pi@raspberrypi pifun]$

那一次并没有完全按照计划进行。我们的复制尝试失败的原因是因为默认情况下“cp”将只复制单个文件。它不会复制整个目录。这背后的原因是,当您复制一个目录时,您复制了其中的所有内容,包括它的所有文件和目录。这可能是大量的数据,可能会占用大量的空间以及大量的时间来完成。强迫我们明确我们的意图(这将很快成为你的第二天性)意味着当我们想要复制一个文件,但不小心选择了一个目录时,我们将在任何复制发生之前被阻止。

这很好,但是如果您真的想要复制那个目录呢?当我们第一次看到 copy 命令时,我们提到了备份等任务,说实话,您更可能想要备份一个目录,而不是一系列特定的文件。我们可以通过告诉“cp”我们想要递归复制来获得我们想要的行为。这将把目录和目录中的任何内容复制到目的地。我们通过使用'-r '标志来指定这一点,如下所示:

[pi@raspberrypi pifun]$ cp -r moarpi moarpi2

[pi@raspberrypi pifun]$ ls

moarpi moarpi2 pi pi2 raspberry

[pi@raspberrypi pifun]$

与 copy 命令不同,当您移动一个目录时,不需要指定您要递归地这样做,这是因为移动一个没有内容的目录没有太大的意义。

毁灭的力量,使用 rm 命令

到目前为止,我们已经向您展示了如何创建文件和目录,以及如何复制和移动它们。现在,我们将向您展示如何使用 remove 或“rm”命令销毁这些文件。不言而喻,rm 命令是你的武器库中最危险的命令之一。如果你不小心的话,它很容易摧毁整个服务器,我们知道有人曾经不小心这样做过。

为了改变一下思路,让我们看看如何删除一个空目录。我们可以使用“rmdir”命令,这是“删除目录”的缩写。这个命令的问题是,它只会删除完全空的目录。如果里面只有一个文件,这个命令就会失败。这使得它使用起来非常安全,但并不实用,因为通常当你删除一个目录时,你还想删除它的所有内容。让我们一石二鸟:

[pi@raspberrypi pifun]$ rmdir moarpi2

[pi@raspberrypi pifun]$ rm moarpi

rm: cannot remove ’moarpi’: Is a directory

[pi@raspberrypi pifun]$

我们能够用' rmdir '删除 moarpi2,因为目录本身是空的,但是当我们尝试使用 rm 命令时,它拒绝合作。这是因为 rm 命令是按照与 copy 命令相似的推理编写的。由于删除一个目录比简单地复制它要危险得多,这可能是一件好事。我们可以使用相同的'-r '标志来告诉 rm 递归删除:

[pi@raspberrypi pifun]$ rm -r moarpi

[pi@raspberrypi pifun]$

成功!现在,有时当您尝试这样做时,尤其是在有许多文件和子目录的大型目录上,您可能会遇到许多问题,导致 rm 放弃。例如,某些文件可能是写保护的。您可以通过使用'-f '标志来抑制这些错误。这意味着“力量”,类似于说“该死的鱼雷!全速前进!”。这听起来是个好主意,直到你停下来想想如果你运行这个命令会发生什么(你永远不应该这样做):

[pi@raspberrypi pifun]$ rm -rf /

如果您不小心运行了该命令,rm 将会删除您系统上的所有内容。如果你碰巧有一个 USB 硬盘,或者你已经安装了一些网络共享,那么你就真的有麻烦了,因为 rm 不会把自己限制在你的内部磁盘上——它会在整个树中爬行,删除它身后的所有东西。这就是为什么你应该在日常工作中使用普通用户帐号的原因之一。您自己的用户没有足够的权限删除任何对系统至关重要的内容,但即使这样,您仍然有可能损坏所有附加的介质。无论何时使用 rm 命令,您都需要非常非常小心,并且您最好反复检查它,因为 Linux 会假设您知道您在做什么,并且它不会要求确认!

“rm”命令还可以通过提供文件的路径来删除文件。对于此操作,您不需要使用'-r '标志,因此您可以简单地执行以下操作:

[pi@raspberrypi pifun]$ rm pi2

[pi@raspberrypi pifun]$ ls

pi raspberry

[pi@raspberrypi pifun]$

简而言之,这就是你如何移动和操作文件系统。

完全限定路径和相对路径

在 Linux 中,有两种方式来指定路径。您可以给出以正斜杠开头的完全限定路径,也可以给出以文件名、目录名、一个点或两个点开头的相对路径。虽然这听起来很奇怪,但它们都是为程序提供特定位置的方法。

当路径从固定的参考点(即根目录)开始时,它被认为是完全限定的。无论您在系统的哪个位置,完全限定路径总是指向同一个位置。这就像镇中心的旧钟楼,如果你以此为参考点给任何人指路,你和你的朋友就有了一个共同的支点,知道如何到达。

另一方面,相对路径取决于你当前的位置。您可以指定路径,使用./表示当前目录,或者使用../表示下一个目录。如果你有一个看起来像../../test.txt的路径,这将只能从几个特定的位置工作。它又好又短,而且容易打字。可以使用/home/pi/test.txt 访问同一个文件。与相对路径不同,这个文件可以在文件系统的任何地方使用,不会有任何问题。

那么什么时候应该使用其中的一种呢?答案是,您应该使用最方便或对任务最有意义的选项。有时使用完全限定路径会更快或更容易。其他时候,您被深深地埋在树中,编写完全限定的路径在最好的情况下是乏味的,在最坏的情况下是完全混乱的。

用户和组

我们在这里只涉及用户和组的基础知识,这样你就有足够的知识来理解接下来的文件权限部分。用户和组是 Linux 保护您的文件的关键,在我们进入下一节之前,您需要了解它们。

在 Unix 的思维方式中,每个人都有自己的用户名。用户名标识特定系统上的特定个人或实体(例如,web 服务器可能有自己的用户名)。到目前为止,我们大部分时间都是作为“pi”用户,但我们也看到了我们可以成为“root”用户。您的用户名是 Linux 用来识别您身份的密钥。

团体也是同样的简单明了。每个用户属于一个主要组,但实际上可能是系统中任意多个组的成员。在大学系统中,一个学生的用户名可能有自己的私有组(目前在 Red Hat 和 Debian 系统中的标准做法),但是他们也可能属于一个学生组和一个研究组。他们也可能属于特定于他们部门的组。组对我们管理员来说很有用,因为我们可以将一组用户组合在一起,并将他们视为一个实体。这使得诸如文件权限之类的事情更容易管理。

当您在 Pi 上创建新用户时,您将自动创建一个同名的组。在某些系统中,用户会默认加入一个用户组——但是正如您将在下一节中看到的,这可能会导致意外地授予用户访问他们不应该拥有的文件的权限。因为根据定义,私有组是私有的,没有其他人会是成员,所以没有人可以访问你的文件,只是因为他们碰巧和你在同一个组。这就是为什么在现代系统中,您通常会看到文件的所有者和组恰好是相同的。

我们将在 BASH 的第八章中更深入地讨论用户和组。

文件权限

文件权限允许您表达您希望谁能够访问您的文件,以及他们可以对这些文件做什么。您可以设置三种不同的权限。第一个是是否有人可以阅读你的文件。第二个是他们是否可以写入你的文件,第三个是他们是否可以执行它(例如,像运行应用程序一样运行它)。

当然,仅仅能够在文件上设置这些权限并不是特别灵活。您可能希望只允许某一组人访问,而限制其他所有人。这就是用户和组发挥作用的地方。在 Linux 上,一个给定的用户实际上有三种角色。第一个是用户,指的是文件的所有者。第二个是 group,指的是拥有该文件的组。最后一个在技术上被称为世界,但它也经常被称为其他。

每个角色都有自己的权限组合,也就是说,您可以定义这三个角色中的任何一个是否可以读取、写入或执行您的文件。我们将向您展示如何做到这一点,但在此之前,我们需要向您展示如何查看哪些权限实际上是有效的,因此现在是向您展示如何对' ls '命令使用'-lh '选项的好时机。让我们现在试着运行它:

[pi@raspberrypi pifun]$ ls -lh

-rw-r˗˗r˗˗ 1 pi pi 0 Oct 7 16:29 pi

-rw-r˗˗r˗˗ 1 pi pi 0 Oct 7 16:58 pi2

-rw-r˗˗r˗˗ 1 pi pi 0 Oct 7 16:29 raspberry

[pi@raspberrypi pifun]$

'-lh '参数指定我们希望 ls 向我们显示一个文件列表(-l),并且我们希望文件大小是人类可读的格式(-h)。如果没有人类可读标志,ls 将以字节为单位向我们显示所有大小,当您处理大文件时,这不是很容易阅读。在这个例子中这并不重要,因为我们的文件是空的。

就文件权限而言,我们真正感兴趣的有两件事。第一个描述了当前生效的权限,第二个显示了哪个用户和组拥有该文件。让我们来分析一下树莓文件:

-rw-r˗˗r˗˗ 1 pi pi 0 Oct 7 16:29 raspberry

文件权限部分是:

-rw-r˗˗r˗˗

列表中有 10 个可能插槽,现在,我们只对前 9 个感兴趣。如果缺少特定的权限(或者在第一个连字符是普通文件的情况下),ls 将显示一个连字符。普通文件总是在第一个槽中有一个连字符。如果它引用一个目录,第一个槽将是一个“d ”,以强调它不是一个文件。如果文件是一个链接(或快捷方式),这个槽也可以是一个“l ”,我们将在下一节向您展示如何使用它们。不过现在我们可以忽略第一个槽,而专注于最后九个槽。

剩下的九个位置三个一组,这样我们就有三组。这些分别对应于用户、组和世界角色。每个组中的三个槽分别代表一个特定的权限,读、写和执行。在设置了权限的地方,您会看到一个字母,但是在没有设置权限的地方,您会看到连字符。如果我们的 raspberry 文件设置了所有权限,它将如下所示:

-rwxrwxrwx

让我们把它分开一点,这样更容易阅读:

-   rwx   rwx  rwx

因此,如果我们看一下前三个,我们可以看到所有者拥有读、写和执行权限。我们还可以看到,group 和 world 也拥有完全权限。为了解释这些权限的含义,我们确实需要知道谁真正拥有该文件。让我们看一下显示谁拥有该文件的那一行:

pi pi

嗯,那并不太痛苦。请记住,在现代的 Linux 机器上,用户有自己的私有组,这些组以用户的名字命名。这就是我们在这里看到的。第一个“pi”指的是所有者,当然也就是 pi 用户。默认情况下,创建文件时,组所有权设置为用户的默认组。在这种情况下,这将是我们的私有组,也称为“pi”。因此,如果我们查看原始文件条目:

-rw-r˗˗r˗˗ 1 pi pi 0 Oct 7 16:29 raspberry

我们可以理解为“pi 用户拥有读写权限。该组具有读取权限,而 world 也具有读取权限”。Linux 根据您的身份以特定的顺序应用这些权限。如果您的用户名与文件的所有者匹配,那么当您尝试访问该文件时,将应用用户权限。如果您不是所有者,但是您和文件在同一个组中,那么 Linux 会将组权限应用于您。如果您既不是所有者也不在同一个组中,Linux 将应用来自 world 角色的权限。在我们的例子中,world 和 group 的权限是相同的,所以如果您不是所有者,您将获得相同级别的访问权限。然而,只有所有者才能实际保存对文件的更改。然而,这个规则有一个例外——根用户。root 用户实际上不受文件权限的影响,可以更改系统上任何文件的权限和文件所有权,而不管所有者是谁。

“执行”权限允许您将文件作为程序执行。这是一项安全功能,因此您可以有效地阻止人们执行您不希望他们执行的命令。然而,你必须小心,因为如果一个用户可以读取你的文件,没有什么可以阻止他们复制到他们自己的文件,并使该文件可执行。对于目录,execute 位还有另一个用途。很明显,你不能执行一个目录,所以这个标志意味着用户(或者组或者世界)被允许浏览这个目录,也就是说,他们可以在这个目录上做一个“ls”。他们可能无法访问目录中的任何内容,但他们仍然可以拥有一个峰值,并查看其中隐藏的内容。如果您授予用户读取目录但不执行目录的权限,他们将能够读取目录中的文件,但不能浏览目录,他们必须事先知道文件名。

这就是事情的全部。有一个叫做“扩展文件属性”的特性,但是我们不打算在本书中讨论。它们比标准模型提供了更大的灵活性,但同样也更复杂。如果你习惯了 Windows 处理权限的方式,那么你会发现扩展文件属性更符合你的习惯。

设置文件权限

首先,我们将看看如何设置文件权限,为此,表 4-1 将非常有帮助。

表 4-1。

Setting Permissions

| 作用 | 如何申请 | 申请什么 | | --- | --- | --- | | u -用户 g -组 o -其他/世界 a -所有 | + - add - - remove = -明确设置 | r -读 w -写 x -执行 |

我们将使用更改文件权限的 chmod 命令。您可以将权限指定为上述值的组合。这些可以以三种不同的方式结合起来。您可以添加权限、取消权限和显式设置权限。不同之处在于,前两者在完成他们的工作后,将保持所有其他权限不变。如果显式设置权限,任何未指定的权限都将被撤销。

让我们从删除每个人对 pi 文件的所有权限开始:

[pi@raspberrypi pifun]$ chmod a=  pi

[pi@raspberrypi pifun]$ ls -lh

˗˗˗˗˗˗˗˗˗˗ 1 pi pi 0 Oct  8 03:52 pi

[pi@raspberrypi pifun]$

我们可以看到所有文件权限都已从文件中删除,但是该命令实际上是如何工作的呢?井权限由三部分指定。您希望将变更应用于谁,您希望如何应用变更,以及您希望变更是什么。在这种情况下,我们将更改应用于“a ”,这基本上是“ugo”的简写,即它将更改应用于每个人。我们使用了等号,这意味着我们希望显式地设置权限,但实际上我们没有提供任何权限。如果一个权限不存在,它就被认为没有被设置,因此在我们的例子中,通过不提供任何权限,我们有效地撤销了所有的权限,而不管它们以前是什么。

鉴于这是我们的文件,我们想给自己完全的权限。诚然,执行位在这种情况下用处不大(但是当你开始编写脚本时,你会发现它的价值不可估量——见第八章),但是无论如何我们还是要把它给自己。我们可以用这个命令来实现:

[pi@raspberrypi pifun]$ chmod u+rwx pi

[pi@raspberrypi pifun]$ ls -lh

-rwx˗˗˗˗˗˗ 1 pi pi 0 Oct  8 03:52 pi

[pi@raspberrypi pifun]$

让我们把这个命令拆开。我们指定我们只想要更改用户的权限,我们想要添加它们(在这种情况下这并不重要,因为我们已经事先删除了所有权限,所以等号可以完成相同的工作),我们想要读、写和执行权限。为了总结这个示例,让我们恢复对组和世界角色的读取权限:

[pi@raspberrypi pifun]$ chmod go+r pi

[pi@raspberrypi pifun]$ ls -lh

-rwxr˗˗r˗˗ 1 pi pi 0 Oct  8 03:52 pi

[pi@raspberrypi pifun]$

为了完整起见,让我们看一下最后一个例子。我们希望将权限应用于组和其他角色,我们希望将权限添加到已经存在的内容中,并且我们希望授予读取权限。这就是设置文件权限的大部分内容。还有一种替代样式,它使用数字而不是字母来指定您想要设置的权限。为了获得与我们已经获得的效果相同的效果(即没有任何效果),我们将使用:

[pi@raspberrypi pifun]$ chmod 744 pi

[pi@raspberrypi pifun]$ ls -lh

-rwxr˗˗r˗˗ 1 pi pi 0 Oct  8 03:52 pi

[pi@raspberrypi pifun]$

在这个系统中,每个权限都有自己的值。读取是 4,写入是 2,执行是 1。要设置权限,您需要将这些数字相加得到总数。例如,要设置所有权限,您需要将 4、2 和 1 相加得到 7。对于 read,你可以简单地做 4+0+0,当然得到 4。把它们放在一起,我们得到 744。该语法是大多数 Unix 系统上使用的原始语法。使用字母是一个相对较新的想法,但在一天结束时,他们都达到了相同的结果。新语法的主要好处是更清晰,更容易理解。就个人而言,我们倾向于使用数字风格,但那只是因为我们已经这样做了很长时间,它已经成为我们的第二天性。你可以随意使用你觉得最舒服的系统。

所以现在你可以像大师一样操作权限,但是我们仍然缺少第二部分,我们没有告诉你如何改变文件的所有权。这实际上比你想象的要少得多,远没有调整偶尔的文件权限那么常见。还有一个小问题。普通用户(除了 root 之外的任何人)实际上不能更改哪个用户拥有该文件。这样做的原因是,如果您不小心将该文件分配给了另一个用户,您就没有办法再取回该文件。当然,根用户可以改变系统中任何文件的所有权。

我们可以用 sudo 来模拟“根性”。如前所述,这个小命令充当某种过滤器。无论谁执行它,它总是以 root 用户身份运行,并代表他们以 root 用户身份执行命令。为了防止任何恶作剧,sudo 将根据批准的列表检查用户和他们试图运行的命令。如果您在这个列表中(pi 用户也是),您就可以执行各种各样的魔法,而无需在技术上成为 root 用户。

要使用 sudo,我们所要做的就是在命令前面加上“sudo”命令。差不多就是这样。当你第一次运行 sudo 时,它会要求你输入密码。这是您的特定用户的密码,而不是根用户的密码。目的是您可以证明您是 pi 用户,然后 sudo 将检查 pi 用户被允许做什么。这意味着,如果你的电脑上有很多用户,你想让他们执行一些更强大的命令,但不想给他们 root 访问权限,你可以设置 sudo,让他们执行特定的命令,而不必交出大厦的钥匙。

让我们首先尝试使用“chown”(或更改所有权)命令将文件交给 root 用户:

[pi@raspberrypi pifun]$ chown root pi

chown: changing ownership of ’pi’: Operation not permitted

[pi@raspberrypi pifun]$

不允许的操作是 Linux 告诉我们滚蛋的方式。要实现这一点,我们需要 root 权限,所以让 sudo 为我们工作,并再次运行命令:

[pi@raspberrypi pifun]$ sudo chown root pi

[pi@raspberrypi pifun]$ ls -lh

-rwxr˗˗r˗˗ 1 root pi 0 Oct  8 03:52 pi

[pi@raspberrypi pifun]$

成功!我们能够将所有者更改为根用户。这将适用于任何有效用户和任何您希望更改的文件或目录。还有另一个名为“chgrp”的命令,它允许您更改哪个组拥有某个特定文件,您对此不会感到惊讶。现在这个命令也有一点问题。虽然普通用户可以更改群组,但他们只能更改他们所属的群组。如果您的用户只是其私有组的成员,那么您也不能用这个命令做太多事情。

又一次是鲁特和须藤来营救了。由于 root 可以为所欲为,因此可以相应地更改组。碰巧的是,它看起来非常像我们的最后一个命令:

[pi@raspberrypi pifun]$ sudo chgrp root pi

[pi@raspberrypi pifun]$ ls -lh

-rwxr˗˗r˗˗ 1 root root 0 Oct  8 03:52 pi

[pi@raspberrypi pifun]$

就这样——文件现在属于根组和根用户。当您必须更改文件所有权时,更常见的情况是需要更改拥有该文件的用户和组。只更改组的情况相对较少(我们不记得上次使用 chgrp 命令是什么时候了)。chown 命令提供了一个快捷方式,允许我们同时设置新的所有者和新的组。现在让我们使用这个快捷方式将文件的所有权返回给我们的 pi 用户。当然,我们仍然需要使用 sudo:

[pi@raspberrypi pifun]$ sudo chown pi:pi pi

[pi@raspberrypi pifun]$ ls -lh

-rwxr˗˗r˗˗ 1 pi pi 0 Oct  8 03:52 pi

[pi@raspberrypi pifun]$

使用快捷方式,您只需指定用冒号分隔的用户和组。关于这些命令,我们需要注意的最后一点是,它们只对您提供的文件进行操作。如果您提供一个目录而不是一个文件,它将设置目录的权限,但这些更改不会过滤到所有文件。有时这是您想要的,但是更多的时候您想要传播更改。与使用-r 的 cp 和 rm 命令不同,这两个命令使用-R,(也就是说,它们使用大写字母而不是小写字母)。使用时要小心,因为通常文件权限是精确设置的,如果你在新版本中轻易地删除了它们,就没有办法挽回损失。像往常一样,在你按下回车键之前要仔细检查你输入的内容。

快捷方式和链接

Linux 允许使用 ln 命令(link 的缩写)创建链接(或快捷方式)。有两种链接,一种叫做硬链接,一种叫做软链接。软链接更像是使用“创建快捷方式”功能后在 Windows 系统上看到的内容。它创建一个文件,这个文件只是一个指向文件在磁盘上的真实位置的指针。然而,硬链接更有趣。当你使用一个硬链接时,你实际上为同一个文件创建了两个名字。这听起来像是语义,大多数现代应用程序都能够遵循软链接,很少需要使用硬链接。硬链接也仅限于单个文件系统,并且该文件系统必须支持它们(大多数 Linux 文件系统都支持)。硬链接的主要好处是硬链接与原始文件完全无法区分,它们只是指向同一位置的两个名称。为了避免混淆并允许链接跨文件系统工作,您应该使用软链接。

让我们做一个简单的例子来展示这一点:

[pi@raspberrypi pifun]$ ln pi pi1

[pi@raspberrypi pifun]$ ln -s pi pi2

[pi@raspberrypi pifun]$ ls -lh

-rw-rw-r˗˗ 2 miggyx miggyx    0 Oct  8 08:14 pi

-rw-rw-r˗˗ 2 miggyx miggyx    0 Oct  8 08:14 pi1

lrwxrwxrwx 1 miggyx miggyx    3 Oct  8 08:33 pi2 -> pi

[pi@raspberrypi pifun]$

让我们看看这里有什么。pi 和 pi1 在各方面都是相同的,但这并不奇怪,因为除了名字之外,它们是同一个文件。您会注意到,pi 和 pi1 的文件权限块后面的数字现在显示为“2”。这告诉我们,当前有两个文件名指向这个特定的文件。也没什么好惊讶的,因为是我们创建了第二个条目。更有趣的是我们用软链接创建的 pi2。首先,我们可以看到文件权限已经全部设置完毕。这不是问题,因为当 Linux 通过软链接访问真实文件时,真实文件的权限将用于定义谁可以访问该文件。软链接实际上只是指出了位置。我们还可以看到文件名本身有点不同。它显示了我们最初给软链接的文件名,但也显示了软链接指向的文件。在这种情况下,文件碰巧在同一个目录中,但它也可能在系统中的任何地方。

这就是创建链接的全部内容。当您想让一个目录或文件看起来位于新位置时,它们会很有用。例如,一个程序可能会写入一个数据目录,而您希望将该目录移动到一个更大的磁盘上。没问题,你可以把它移到更大的磁盘上,然后创建一个同名的软链接。应用程序可能甚至不会注意到。这真的可以帮你省去很多麻烦,尤其是当时间非常宝贵的时候(老实说,什么时候不是呢?).

摘要

这一章已经给了你关于文件系统的内幕消息。我们已经查看了历史,并展示了为什么我们的文件系统看起来是这样的。然后,我们讨论了它们是如何结合在一起的,以及 Linux 文件系统本身是如何构造的。然后我们继续很好地利用它,让你快速掌握创建、复制、移动和删除文件的所有基础知识。

然后,我们研究了文件权限以及它们是如何实施的,以及我们如何设置它们来满足我们的需求。我们还研究了更传统的设置文件权限的方法,如果你曾经遇到过的话。然后,我们向您展示了 Linux 如何应用这些权限,以及如何更改拥有特定文件的用户和组。然后,我们讨论了如何创建链接,以及软链接和硬链接之间的区别,从而圆满地完成了所有内容。

在下一章中,我们将向您展示您可以在 Pi 上找到的所有最常见的命令。这些命令将成为你经常使用的工具箱的一部分。事实上,我们在日常工作中使用所有这些命令。所以,向前看第五章!

五、基本命令

现在您已经有了这个不可思议的新的 Raspberry Pi,您已经安装并配置它来接受和运行一个版本的 Raspbian Linux。您已经登录,可以在系统中自由移动。你可以在你的 Pi 上做基础,但是现在觉得你已经准备好承担更多了。

这就是本章的目的:教你一整套命令,这样你就可以成为一个 Linux 用户。这些命令将涵盖一系列功能,从成为超级用户、检查磁盘空间、终止进程,到配置用户空间和监控环境变量。所有这些任务对于系统管理员来说都是常见的,并且会对系统的运行方式产生很大的影响。所以事不宜迟,我们开始吧。

成为老板

“根”是一个描述树的基部的词,其余的都是从基部生长出来的。在 Linux 和 UNIX 中,这个术语用来表示文件系统的起始点(正如我们在第四章中看到的那样)和表示系统上的主管理用户(在第三章的中有简要介绍)。要执行任何系统或管理功能,您需要被识别为 root 用户,以便拥有更改核心功能的权限。因此,root 是一把双刃剑:改变系统的无限权力和破坏系统功能的无限权力。关于在 Linux 环境中工作,我能说的最真实的事情之一就是,最终你会以 root 用户的身份发出一个命令,这个命令会破坏某些东西(如果不是所有东西的话),这会给你带来无穷无尽的麻烦,甚至可能需要你重新安装操作系统。由于这个原因(以及相关的安全原因),建议用户永远不要以 root 用户的身份登录到 shell。

为了解决这个问题,我们使用了sudo,我们在第三章和第四章中已经看到了一点。如您所知,这个工具是您能想到的任何 shell 命令的包装器。这意味着,如果您在命令前面加上sudo (,例如sudo ls),您将不再作为自己的用户执行该命令,而是作为超级用户。这确实使超级用户的工作稍微复杂了一些,但是风险也小了很多。事实上,许多 Linux 发行版不再设置 root 密码,而是在创建时赋予新用户sudo的权力。这意味着所有的管理必须通过一个拥有sudo命令的授权用户来完成,以发布所有必需的管理功能。

为了让您能够以 root 用户身份执行,sudo会要求您输入用户密码,以验证您是否就是您所说的那个人,而不仅仅是一个拥有访问权限却忘了拿键盘的人。除了要求所有用户输入密码,sudo还有一个控制文件,控制哪些用户和组可以访问sudo命令,甚至可以限制他们可以通过sudo执行哪些程序。有一个特殊的命令visudo,用于编辑这个导向文件(称为 sudoers 文件),该文件必须以 root 身份运行(所以前缀为sudo):

$ sudo visudo

这段代码启动了一个系统文本编辑器(通常是vinano)的特殊实例,其中已经加载了 sudoers 文件进行编辑。要快速浏览如何使用vinano,请查看第六章。

在 sudoers 文件中有许多控制sudo环境如何工作的东西,包括一个PATH变量(我们将在后面介绍)。然而,重要的是userauth部分下面的一行,如下所示:

root    ALL=(ALL:ALL) ALL

这一行表示所有主机上的 root 用户可以访问所有其他主机上的所有命令(主机是网络上的服务器)。这有点令人困惑,但它基本上向任何可以将自己标识为 root 的用户授予完全访问权限。还有另一句台词:

%sudo   ALL=(ALL:ALL) ALL

这一行表示sudo组的成员也可以做与根用户相同的事情:从网络上的所有主机访问可以在网络上的所有主机上执行的所有命令。您会注意到前导的%用于表示这是一个组名。其中一行的基本格式如下:

<user>  <From which hosts>=(<On which hosts>:<which commands>) < command options and commands >

这个语法一开始有点混乱,所以让我们看一下为您的pi用户创建一组特定的权限作为例子。首先,我们需要创建一个新的基本用户权限集,它看起来就像根用户一样,但是它指的是我们的pi用户。这一行看起来像:

pi    ALL=ALL   ALL

我已经删除了<on which hosts: which commands>部分,用一个通用的ALL代替它,使事情更容易理解。现在让我们假设我们不希望pi用户被要求输入密码。为此,我们在代表命令的最后一个ALL前添加了一个NOPASSWD:。这给了我们一条新的线索:

pi    ALL=ALL   NOPASSWD: ALL

如果您现在添加这个,您可以作为pi用户运行所有命令,甚至不需要提供密码。这是一个非常危险的命令,所以让我们稍微修改一下,使它成为唯一可以执行的visudo命令。为此,我们将命令的最后一个ALL替换为我们希望使用的命令,在本例中是visudo。但是我们不能只写visudo,我们需要提供应用的完整路径,也就是/usr/sbin/visudo。因此我们得到以下结果:

pi    ALL=ALL   NOPASSWD: /usr/sbin/visudo

现在您应该知道在 sudoers 文件中可以做些什么来控制如何访问sudo命令了。您可以有多个条目来控制这些命令如何运行、由谁运行以及在什么条件下运行。还有大量添加别名的功能,可以是命令、主机或用户的大量组合。这些命令的大部分语法可以从 sudoers 手册中获得。

最后,您需要注意的最后一个命令是su命令,它是 switch user 的缩写。这个命令完全按照它的意思来切换您是哪个用户,如果您不是 root 用户,它会提示您输入希望切换到的用户的密码。获得根用户权限的最有效的欺骗手段之一是结合sudosu来切换到根用户,只使用当前用户的密码而不是根用户的密码。这个命令是许多人绕过许多 Linux 发行版设置的“不知道根密码”限制的方法:

$ sudo su –

减号表示您希望获得对环境的登录,因为没有提供其他参数,所以它将尝试以超级用户的身份登录。您还可以通过在减号前添加给定用户的用户名来切换用户。您还可以使用带有–i选项的sudo命令来获得一个交互式 shell,它将实现同样的功能:

$ sudo –i

阅读各类手册

我最喜欢的来自技术世界的一句话是 RTFM,它是阅读燃烧手册的缩写。虽然我发现向别人寻求帮助是好的,但知道有一本手册可以阅读总是令人欣慰的,Linux 也不例外。大多数应用程序都有一个手动文档,可以通过使用man命令来访问!这个命令将您希望获得的手册页作为它的第一个参数。因此,如果您想查看sudoers命令的手册页,以便更好地了解如何编写 sudoers 文件,您可以键入:

$ man sudoers

然后手册页就会出现。导航手册页的方式与导航用less打开的文档的方式相同(这是一个我们将在本章中进一步介绍的命令),所以导航是用箭头和 page up 和 page down 键来完成的。您也可以通过按下/来搜索字符串,然后输入您想要搜索的内容。n键将帮助你浏览文件。因此,如果您发现自己需要更多关于命令的信息,请记得阅读 Flaming Man 页面!

系统资源监控

系统管理员需要做的一件重要事情是监控系统上的资源使用情况。虽然这些命令中的一些对您的普通 Pi 用户来说用处不大,但是有些时候能够看到您的系统正在做什么将会派上用场。

需要注意的第一个系统命令是top,这是一个用于显示系统中资源的当前使用情况以及显示哪些进程正在消耗什么级别的资源的命令。top命令非常强大,可以显示关于系统资源使用情况的大量信息。top的输出通常如图 5-1 所示。

A978-1-4842-1162-5_5_Fig1_HTML.jpg

图 5-1。

Top in action!

top命令的输出是巨大的,如果你仔细观察,所有的值都会定期更新。让我们一行一行地检查一下top的输出,这样你就能明白你在看什么了。

正常运行时间和平均负载

第一行给出了当前时间和系统正常运行时间的信息。然后显示系统上的用户数量,最后显示平均负载。负载平均是最难理解的事情之一;它是一个“元”变量,因为它指的是相对于系统的执行能力,系统内部正在发生什么。它包含 3 个值,给出当前分钟、过去 5 分钟和过去 15 分钟的平均值。平均负载代表实际计算使用和系统计算资源需求的平均值。

我所听到的认为平均负载的最好方式可能是高速公路。通常,CPU 使用率的百分比值表示当前可用计算资源的使用量。这类似于测量高速公路上目前的交通流量。平均负载比较正在使用的计算量和对 CPU 使用量的需求。这就像同时检查高速公路和它的匝道。当从“繁忙的午餐时间”的角度来看时,这两者之间的区别就来了,这意味着高速公路上有很多车,但正因为“这是一个繁忙的午餐时间”,每个人都可以上高速公路并使用它,没有人被困在匝道上等着,交通顺畅。

这就是为什么平均负载是如此强大的指标;它允许您实时查看对系统计算能力的需求,以便您可以看到需求何时开始激增,从而采取措施降低需求。

哇,一行就这么多!

任务

top输出的第二行列出了系统当前正在执行的任务:

  • 进程的总数
  • 正在运行的进程的数量
  • 在后台休眠的进程的数量
  • 停止的进程数
  • 僵尸进程的数量

这些过程中的大部分都是为了了解系统中正在发生的事情。但是僵尸进程可能是一个真正的问题。这些进程是已经完成执行,但仍然驻留在系统内存中的进程——通常是因为它们需要向产生它们的进程发送返回值,但还没有这样做,因此必须像活死人一样在那里等待,然后才能发送最后的消息并前往来世。

有一个长时间运行的僵尸进程可能表明用于产生它的应用程序(称为它的父进程)有问题。如果您在系统中看到僵尸进程,请查看是哪个进程产生了它们,并检查其运行状态和日志文件(日志文件是从写入磁盘的应用程序中输出的,因此您作为系统管理员可以看到它们在做什么),因为这可能表明存在更大的问题。

CPU 利用率百分比

top命令的第三行是 CPU 利用率百分比值。这以百分比的形式显示了当前有多少计算资源分配给了系统的哪个域。这些值如下:

  • us(用于用户应用)
  • sy(用于系统应用)
  • ni(对于已经被“改善”以便给予它们或多或少的 CPU 优先级的进程)
  • id(代表空闲)
  • wa(对于等待 I/O 完成的进程)
  • hi(用于等待硬件中断的进程)
  • si(用于等待软件中断的进程)
  • st(表示被虚拟机管理程序窃取的时间——虚拟机管理程序是运行 Xen 或 VMWare ESX 等虚拟化平台的软件)

在这些值中,通常分配给它的计算资源最多的是id,它表示可以在其他地方使用的空闲可用计算。看到wahisist的高值绝不是好迹象,因为它们表明您的系统正在等待某个特定的硬件或另一个函数完成处理。如果这些数字居高不下,您应该调查是哪些进程导致了它们,并查看是否有任何硬件问题。

内存使用

第 4 行和第 5 行代表系统的内存使用情况。第 4 行是实际的内存使用情况,第 5 行是交换空间使用情况。这两行将显示给定空间中的总内存、已用内存和空闲内存。这个最终值表示缓冲区和缓存的值。这两者是相互关联的,也是不熟悉 Linux 的用户非常担心的原因。这与 RAM 的分配方式有关。Linux 有时会占用所有可用的 RAM,并将其放入一个缓冲区,这意味着它被缓冲区占用,但以后仍可用于您的应用程序。Linux 会将这个 RAM 视为正在使用,但它只是坐在缓冲区中等待。buffers 值可能有点难以理解;这将导致另一个命令显示这些资源是如何使用的(我将在接下来介绍)。

过程表

在第五行之后是一个包含进程表的大部分,该表列出了所有正在运行的进程,并且在近乎实时的更新中,列出了哪些进程消耗了多少资源。下面显示了许多不同的列以及它们所代表的信息:

  • PID:进程的 ID 号
  • 用户:拥有流程的用户
  • PR:流程的优先级
  • 倪:这个过程值了
  • VIRT:进程消耗的虚拟内存量
  • RES:实际驻留虚拟内存的大小
  • SHR:进程正在使用的共享内存量
  • s:进程状态(例如,睡眠、运行、僵停)
  • %CPU:消耗的 CPU 的百分比
  • %MEM:消耗的内存百分比
  • TIME+:任务自启动以来使用的总 CPU 时间
  • 命令:命令的实际名称

top也有许多按键动作,可以控制这些进程的显示顺序;您可以在top的手册页中查看它们。

因此,top是一个显示系统资源使用情况的极好的命令,也是深入了解系统本身正在做什么的最佳工具之一。

使用 free 查看内存分配

如前所述,有一种比使用top更简单的方法来查看您的内存分配情况。执行此操作的命令是free命令,您可以使用希望显示的单位调用该命令(–k表示千字节,-m表示兆字节,-g表示千兆字节,等等)。为了我们的目的。兆字节是最好的,所以调用它如下:

$ free –m

您的输出应该如图 5-2 所示。

A978-1-4842-1162-5_5_Fig2_HTML.jpg

图 5-2。

Free as in free

由此,您可以看到改变usedfree值的+/- buffers and cache线。这是一个很好的方式来询问任何时候你的系统显示高达 100%的内存峰值,因为它可能只是大量的缓冲区和缓存在运行。从这两个实用程序中,您应该能够准确地了解系统中正在发生什么,以及它的资源是如何被使用的。

磁盘使用情况

既然我们已经了解了 CPU 和 RAM 的使用情况,它们是相当动态的,那么是时候了解一些更静态的东西了,即磁盘利用率。在大多数操作系统中,您可以快速方便地查看有多少可用存储空间正在使用,Linux 也不例外。显示整个系统磁盘当前使用情况的命令是df,它是 disk free 的缩写,可以在命令行上使用,不带参数,以显示您需要的所有内容。如果这样做,您的输出将类似于图 5-3 。

A978-1-4842-1162-5_5_Fig3_HTML.jpg

图 5-3。

Disk free, ouch!

图 5-3 显示磁盘空闲,并显示安装在/上的主rootfs基本上 100%满——哎哟。您可以看到系统正在使用的 1 k 数据块的数量,但是这些值并不是很明显。您还会注意到在顶部有一个权限被拒绝的错误。

幸运的是,这两个问题都有解决方案。首先是用sudo运行这个命令,这样它就可以以 root 用户身份访问整个系统。第二个是添加了–h参数。这个论点是相当普遍的:要么是–h求助,要么是–h人类,也就是说人类可读的单元。所以我们运行这个命令:

$ sudo df -h

输出应该更容易被普通人理解(见图 5-4 )。

A978-1-4842-1162-5_5_Fig4_HTML.jpg

图 5-4。

df for humans

正如您所看到的,人类可读标志已经将那些SizeUsed值改为人类可读的数字,在表示单元的末尾有一个漂亮的小标志。试验显示标志是帮助您理解来自 Linux 命令的一些复杂数据的好方法。通常情况下,您会在手册页中找到一个很大的部分,详细介绍了一个命令的所有标志。

我们已经看到了系统的全部磁盘利用率,但是假设我们想要找到一个文件夹中所有文件的详细利用率。我们可以使用另一个命令来做到这一点:du,它是 disk usage 的缩写,用于总结每个文件的磁盘使用情况,递归地表示目录。如果您运行du,它会告诉您这个文件夹中每个文件的估计使用量,以及每个子文件夹和其中每个项目及其子文件夹的估计使用量,等等。du也将利用–h获得曾经在df的人类旗帜。因此,如果我们运行它,我们会得到如下输出:

$ du –h

4.0K    ./.cache/dconf

12K     ./.cache/menus

576K    ./.cache/midori/web

4.0K    ./.cache/midori/thumbnails

24K     ./.cache/midori/icons

608K    ./.cache/midori

4.0K    ./.cache/openbox/sessions

12K     ./.cache/openbox

640K    ./.cache

12K     ./.dbus/session-bus

16K     ./.dbus

5.0M    ./.tor

12K     ./.ssh

1.8M    ./python_games

8.0K    ./.dillo

20K     ./.vnc

4.0K    ./.gvfs

124K    ./.gnupg

8.0K    ./.fltk/fltk.org

12K     ./.fltk

48K     ./Desktop

8.0K    ./.config/lxpanel/LXDE/panels

16K     ./.config/lxpanel/LXDE

20K     ./.config/lxpanel

8.0K    ./.config/pcmanfm/LXDE

12K     ./.config/pcmanfm

8.0K    ./.config/lxterminal

28K     ./.config/midori

4.0K    ./.config/enchant

28K     ./.config/openbox

104K    ./.config

76K     ./.fontconfig

16K     ./.netsurf

40K     ./.local/share/gvfs-metadata

36K     ./.local/share/webkit/icondatabase

40K     ./.local/share/webkit

88K     ./.local/share

92K     ./.local

9.0M    .

哇,对于这样一个简单的命令来说,这是一个很大的输出。它显示当前文件夹中每个文件夹的使用情况,并在底部显示总使用情况。这里我们可以利用另一个标志来缩短输出:代表 summary 的–s标志。这样做只会打印该目录及其所有内容的总分配,而不是我们刚刚看到的所有内容。所以继续执行命令;您的输出应该看起来更加整洁:

$ du -sh

9.0M    .

那好多了。您会注意到输出使用了.值来表示当前目录,因为如果没有被告知去其他地方看的话,du将在当前工作目录上工作。您可以通过在末尾添加一个目录来指定要使用的目录。下一个示例将查看保存所有系统日志的/var/log,因此我们需要使用sudo作为 root 运行该命令,因为其中一些日志文件受到保护:

$ sudo du -sh /var/log

9.8M    /var/log

这就是了!使用这两个实用程序,您可以找出系统当前的磁盘使用情况,甚至可以计算出系统的哪些部分占用了最多的空间。

管理流程

在 Linux 环境中工作时,最重要的任务之一可能是知道如何管理正在运行的进程。毕竟,计算机只是一个处理系统,如果你不能管理它正在处理的东西,你怎么能真正好地利用你的机器呢?您应该知道的第一个命令是ps命令。ps命令是进程快照的缩写,可用于列出您的用户正在运行的所有当前进程;当被调用时,您应该得到如图 5-5 所示的输出。

A978-1-4842-1162-5_5_Fig5_HTML.jpg

图 5-5。

Current processes

是的,现在有点暗淡,因为我只运行两个进程:运行我的用户 shell 的bash应用程序和ps的副本。由于这是快照,应用程序将始终捕获自身。如果我想控制当前用户运行的那些进程,这是很有用的,但是如果我想做更多,我需要给我的ps命令添加一些参数。在标准语法中显示系统中每个进程的参数是–ef,所以继续运行它,看看你的输出如何变化(见图 5-6 )。

A978-1-4842-1162-5_5_Fig6_HTML.jpg

图 5-6。

ps –ef

哇,这是一个很大的输出,以至于它离开了屏幕的顶部!当您运行ps –ef时,总是有大量的进程在您的系统上运行,因为它列出了所有的系统后台进程以及所有的用户进程。如果你想在列表中看到它们,你可以简单地在你的命令后面添加一个| less,这将允许你上下移动和操作列表(我将在本章稍后解释less命令实际上做什么):

$ ps -ef | less

pstop很像,但是需要更少的资源,并且有一些其他的优势,我们将在本章后面介绍。现在,您只需要知道ps中每一列的含义:

  • UID:代表拥有该进程的用户
  • PID:表示进程的 PID 号
  • PPID:代表创建这个进程的 PID 号
  • c:表示该进程的 CPU 利用率
  • STIME:表示该流程的开始时间
  • TTY:代表控制这个过程的终端
  • 时间:该进程消耗的累计 CPU 时间
  • CMD:该进程的命令行参数

所以你可能会说,“好吧。你已经展示了系统中的所有进程,但我现在可以用它们做什么?”这就是ps的魔力所在;这使得我们很容易挑选出一个特定进程的 PID。PID 编号非常重要,因为它是每个流程的唯一编号,也是系统引用流程的方式。这将在我们的下一个命令中用到:kill

终止一个进程

顾名思义,kill是用来杀死进程的。但是它也通过杀死进程的机制提供了许多其他有用的功能。在 Linux 和 UNIX 中,信号是从操作系统传递到应用程序的低级系统消息。信号除了是一个信号之外没有任何实际功能,应用程序需要以正确的方式响应它。并非所有信号都是如此,因为有些信号无法在应用程序中处理,但大多数信号都是如此。kill命令的功能是向应用程序发送信号。Raspbian 上的kill版本可以向应用程序发送 64 个信号。要列出它们,发出以下命令:

$ kill –l

我现在不会列出所有信号的功能,但您需要了解这些最常见的信号:

  • 信号 1 (SIGHUP):挂机的简称。告诉应用程序挂起当前连接。通常用于使应用程序重新初始化自身。
  • 信号 3 (SIGQUIT):表示该应用程序应该正常关闭并退出。
  • 信号 6 (SIGABRT):表示程序正在中止;它将立即关闭。
  • 信号 9 (SIGKILL):强制“拔掉”应用程序的信号。

这些信号是最常见的,因为它们用于执行应用程序关闭,其中九个是最常见的。kill命令的格式如下:

kill –<signal> <PID>

因此,要用最大的力量终止一个进程,请执行以下命令:

$ kill -9 <PID>

这就是那些来自ps命令的 PID 发挥作用的地方。这些 PID 数字是你将输入到kill中的数字,以便指示来自kill的信号。

正在读取/proc 中的信息

既然我们在玩 PID,那么重温一下/proc文件系统可能会很好,这在第四章中首次讨论。这是操作系统的一部分,所有的进程信息都在其中。如果您使用ls /proc,您将看到许多文件和一组编号目录。这些目录对应于每个进程 PID。如果您查看其中一个目录,您应该会看到与给定进程相关的一大堆文件。虽然您不应该随意编辑这些文件,但是这些目录中的一些文件非常有用。

可能最常用的是包含所有系统处理器信息的系统级文件。这是/proc/cpuinfo文件。您可以使用cat命令将文件的内容输出到屏幕,这是 concatenate 的缩写,通常用于将文件的内容放入缓冲区(在我们的例子中,是控制台屏幕)。继续发出这个:

$ cat /proc/cpuinfo

您的输出应该如下所示:

Processor       : ARMv6-compatible processor rev 7 (v6l)

BogoMIPS        : 697.95

Features        : swp half thumb fastmult vfp edsp java tls

CPU implementer : 0x41

CPU architecture: 7

CPU variant     : 0x0

CPU part        : 0xb76

CPU revision    : 7

Hardware        : BCM2708

Revision        : 0003

Serial          : 000000007a8a46ba

这是树莓 Pi 的处理器上的 Linux 内部信息。如果您对您的处理器的某些细节有疑问,这是值得考虑的地方。

除了cpuinfo,在/proc中还有另一个文件,您可以在诊断系统配置信息时加以利用。这是/proc/<pid>/cmdline的文件。该文件列出了用于调用进程的完整命令行参数。如果您需要使用这里使用的命令,对这个文件执行cat是最好的方法。

文件命令

如前所述,您可以使用cat命令输出文件的内容。您可以使用许多其他工具来处理系统中的文件内容。第一个是前面提到的命令:less命令。这是一个在屏幕上显示文件内容的命令,可以像文本编辑器一样移动和搜索。这是一个很棒的命令,用于处理日志文件或长命令的输出,如ps. less允许你用箭头键或 page up 和 page down 键上下移动文件。您也可以通过键入/然后输入您的搜索字符串,使用简单的单词搜索进行搜索。less会高亮显示找到的表达式实例,你可以用n键向下移动,用N键向上移动。

除了能够在文件中搜索内容之外,less还能够查看文件,并不断地在last行显示任何新内容。这对于观察不断增长的日志文件非常有用,因为你可以在不需要重新打开文件的情况下获取新行,要让less执行这个功能,只需按下F键。除此之外,你还可以通过按下G键自动导航到文件的结尾。这个过程还将获取任何已经添加到文件中的新行并显示它们。您也可以使用小写 g 来导航到特定的行号,因此如果您希望转到第一行,请按1g。最后,less能够在自身内部响应所有的命令行参数。这对于启用行号很有用,因为你可以简单地给less命令–N<enter>,它会在每行旁边显示数字。

less之后,提供惊人灵活性的命令之一是find命令,用于查找文件。它通过检查给定目录及其所有子目录中的每个文件来做到这一点。find本身是有用的,但是当与其他命令配合使用时,你将会看到它的非凡之处。它还有一个健康的选项缓存,可以互换,也可以组合。我将在这里介绍几个我认为非常有用的例子:

  • 第一个是–L,它表示遵循符号链接,默认情况下find不这么做。
  • 第二个是–maxdepth <number>,它表示这个命令将搜索多少个目录深度。只有一个?就这个及其所有子目录?
  • 第三个是–newer <file>,它显示了比给定文件更新的任何内容。
  • 第四个是–empty,顾名思义,它查找空文件。
  • 第五个是–atime <number>,其中的数字表示自文件被访问以来已经过去的天数。
  • 第六个是–name <filename>,它搜索与传入的名称完全相同的文件。
  • 最后是exec <command>,它告诉find在每个文件上执行给定的命令,这也是find的真正威力所在。您可以使用此命令查找指定的文件,然后对它们执行命令。以这种方式,使用find是执行清理旧的不需要的文件的一种奇妙的方式。我还建议,当你以这种方式使用find时,你应该先测试并彻底测试,因为一次不正确的击键可能意味着你的系统或数据的毁灭。

将这些命令组合起来,您可以实现如下所示的效果:

$ find /mnt/Volume1 –empty –name fooBar –exec rm

该命令将找到/mnt/Volume1中所有名为fooBar的空文件,然后删除它们!在管理您的 Pi 时,您可以利用find命令中的强大功能。

另一个具有重要但有限用途的命令是file命令。file命令用于遍历给定文件的内容,并确定文件的“种类”。种类在这里是一个有点松散的术语,因为file只知道适度数量的不同文件类型。然而,当您想知道这个问题的答案时,它非常有用:“我可以在文本编辑器中安全地打开那个文件吗,或者它是一个二进制应用程序?”这个特殊的命令可以为您省去很多麻烦。您还可以使用file来确定应用程序是以哪种归档格式编写的,这在您需要从归档文件中提取但不知道是哪种时非常有用!举例来说,如果您对一个二进制可执行文件如/bin/bash运行file,您应该会看到以下内容:

$ file /bin/bash

/bin/bash: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xe370a0be978f49569f115c9f41bc54688be9fe32, stripped

代码显示该文件是为 ARM 系统编译的 ELF 32 位 LSB 可执行文件,因此该文件应该与您的 Pi 兼容。这是诊断从互联网下载的应用程序可能存在的任何问题的好方法,因为它们可能是为 x86 编译的!

在这一节中,我为您准备的最后一个文件命令是那些许多人讨厌但更多人喜欢的命令之一:grepgrep是通用正则表达式解析器的缩写,最广为人知的是它是一个模式匹配器。像lessfindgrep既可以单独使用,也可以与其他命令结合使用。您可以使用grep在给定文件中搜索包含给定文本字符串的任何行。grep的基本格式是这样:

grep <pattern> <file>

这两个值都采用通配符格式,所以您可以使用grep在整个目录中的每个文件中搜索一个字符串。例如,让我们在/etc/init.d文件夹中查找单词 find:

$ grep find /etc/init.d/*

输出将是这样的:

/etc/init.d/checkfs.sh:# Include /usr/bin in path to find on_ac_power if /usr/ is on the root

/etc/init.d/checkroot.sh:# Include /usr/bin in path to find on_ac_power if /usr/ is on the root

/etc/init.d/kbd:            LIST_CONSOLES=’cd /etc/init; find -name ’tty*.conf’ -printf ’%f ’ | sed -e ’s/[⁰-9 ]//g’’

/etc/init.d/kbd:            # eventually find an associated SFM

/etc/init.d/nfs-common:# particularily heavy daemon, so we auto-enable it if we find an /etc/exports

/etc/init.d/rc:# Now find out what the current and what the previous runlevel are.

/etc/init.d/sudo:                find /var/lib/sudo -exec touch -t 198501010000 ’{}’ \;

grep也有一些很棒的命令行选项,包括–i,它使得搜索不区分大小写。grep也有–v选项。它颠倒了搜索方向,返回所有与给定搜索字符串不匹配的内容!这应该让您了解当您希望找到一条给定的信息时,grep是多么强大的一个工具,因此它是系统管理员的命令库中一个令人敬畏的部分。

组合命令

现在我们到了有趣的部分!组合命令的能力,以便您可以使用一个命令的输出,并将其交给另一个命令来处理。还有一些命令,我将在这里详细介绍,因为它们与其他命令结合使用时非常棒。但是首先你需要理解如何组合命令,谢天谢地,这是一件相当容易完成的事情。为了组合命令,我们使用管道符号(|)。

是的,就这么简单。假设我们想要 grep 一些东西,但是想要以一种更易管理的方式输出。我们将简单地编写grep,添加一个管道,然后添加一个less。通过这样做,你会发现自己在less中查看grep的输出!这是乐趣真正开始的地方。想要搜索给定目录中的所有文件名吗?使用ls列出文件,并将输出通过管道传输到grep进行搜索。在这种情况下,您甚至不需要在文件名中包含grep,因为管道将为grep提供一个所谓的缓冲区,而grep将把这个缓冲区视为文件内容!所以命令是这样的:

$ ls <directory> | grep <search string>

结合 ps 和 grep

现在,如果你想玩更多的东西,你可以把grepps –ef结合起来!这样,你可以搜索一个特定的应用程序;例如,为了搜索 SSH 应用程序sshd,我们将运行:

$ ps –ef | grep sshd

这将生成以下输出:

root      1722     1  0 19:24 ?        00:00:00 /usr/sbin/sshd

root      1956  1722  0 19:43 ?        00:00:00 sshd: pi [priv]

pi        1963  1956  0 19:43 ?        00:00:01 sshd: pi@pts/0

pi        2030  1964  0 20:33 pts/0    00:00:00 grep ˗˗color=auto sshd

添加反向 grep

啊!有问题!我们似乎已经掌握了自己的指挥权。但这没问题,我们可以简单地再次连接到grep并为grep做一个–v,这将返回给我们没有grep的每一行。这给了我们命令:

$ ps –ef | grep sshd | grep –v grep

这给出了如下输出:

root      1722     1  0 19:24 ?        00:00:00 /usr/sbin/sshd

root      1956  1722  0 19:43 ?        00:00:00 sshd: pi [priv]

pi        1963  1956  0 19:43 ?        00:00:01 sshd: pi@pts/0

削减结果

好多了!现在你可以开始看到我们可以用管道完成什么,但是我还远远没有完成你可以用它来做的事情!下面介绍下一个命令:awkawk是从一行文本中提取数据的工具。这样,您可以从正在运行的任何命令中提取各种信息。默认情况下,awk将通过分割空白来提取每个元素,空白是字符之间的任何制表符或空格。您可以使用–F <delimiter>参数设置要分割的角色。一旦你告诉awk如何拆分你的文本,你将需要输出它。有一个完整的输出命令的语法,这是一种非常复杂的艺术形式。

然而,对于您的大多数需求,只需打印正确的字段就可以了。所有的awk输出都用花括号{}括起来,通常需要用单引号括起来,这样命令行就会忽略任何空格。这意味着基本语法如下所示:

$ awk ’{ <command> }’

对任何使用awk的人来说,最有用的命令应该是print命令,因为它用于显示分隔变量。这些变量中的每一个都被视为序列中的数字,因此第一个是$1,第二个是$2,依此类推。使用它,我们可以将前面的awkps –ef结合起来,打印出第二个空格分隔的字段,PID!这为我们提供了以下命令:

$ ps –ef | grep ssh | grep –v grep | awk ’{print $2}’

哇,这些命令越来越长了!但是请检查该命令的输出:

1722

1956

1963

啊哈!你们中最敏捷的人会意识到接下来会发生什么!我们可以用管道把这个传给kill!以这种方式,我们可以使用一个psgrepawk来只获取与给定模式匹配的进程的 PID,然后将它们传递出去进行终止!

xargs 处理每个结果

这是那些永不过时的魔术之一;然而,我们不能将 PID 列表直接传递给kill,因为我们希望一次传递一个。为此,我们需要利用另一个命令xargs,它的工作方式与find中的–exec相同。它允许您将之前命令的每一行输出视为另一个命令的单独参数。要使用 xargs,我们只需让它们以与sudo相同的方式包装命令。因此,如果我们想通过kill将这些 PID 中的每一个传递给xargs,我们只需运行以下代码,就可以了:

$ ps –ef | grep ssh | grep –v grep | awk ’{print $2}’ | xargs kill –1

在这种情况下,我不会终止我的sshd进程,因为我不想重启我的 Pi。但是您应该知道如何从一个命令获取输出,并将其传递给另一个命令,以便对这些命令进一步执行。

实际上,在进行这种“shell-fu”时,还有许多其他命令非常方便第一个是wc,是字数的简称。默认情况下,wc会给出给定文本块或文件的换行、字数和字节数,但它也有一些很好的参数,比如–l,它会给出行数;–w,会给你字符数;或者–m,它会给你字数。

接下来是sort,它对输出的每一行进行排序。你经常看到sortuniq成对出现,后者是 unique 的简称。有了这两个,您可以通过管道将输出发送到sort,然后发送到uniq,在您给定的输出中,您将只有唯一的值!

使用大量命令时,最后需要注意的是输出操作符>。这个操作符与 pipe 属于同一个系列,但是它不是用于将命令输出定向到另一个命令,而是用于将输出定向到一个文件。这是一种将命令输出保存到文件的好方法,这样您就可以在以后重新访问它,或者将它用作另一个命令的参数。到目前为止,您应该已经感受到了 shell 的强大,您可以通过将命令和管道结合起来进行各种复杂的操作!

用户环境

我们将暂时停止检查命令,看看构成您工作环境的一些东西。您的环境是在每次登录时启动的,每次都一样。这是因为许多文件和命令提供了关于如何构建简单 shell 环境以及如何运行的指令。执行这些任务所涉及的关键文件之一是您的系统主控制环境脚本/etc/profile。该文件提供了作为每个用户会话基础的 shell 和环境变量的基础。

配置文件设置了许多变量,包括PATH变量。这个变量是设置 shell 环境工作方式的关键变量之一。所以我们将深入研究一下。

PATH是你整个环境中最重要的变量之一(如果不是最重要的话)。它代表系统搜索路径,基本上意味着它将在哪里寻找应用程序。举例来说,我相信您现在已经意识到,我们运行的所有命令都只是输入到 shell 中的文字,但实际上它们是位于操作系统中的全功能应用程序的名称。PATH包含一个文件夹列表,您的 shell 将自动搜索并执行其中的任何命令。这意味着您并不总是在搜索命令的确切路径;您可以根据需要通过它的名称来运行它。这里的问题是你不能确定程序是从哪里运行的,或者如果你有多个版本,哪一个正在运行。有一个命令可以解决这个问题:which命令。它输出您的 shell 用来执行给定命令的应用程序的路径。例如,让我们找到ssh应用程序的路径,我们键入which ssh,我们得到这样的结果:

$ which ssh

/usr/bin/ssh

是的,就这么简单。许多程序使用PATH来查找它们需要的信息。您的 path 变量最初设置在/etc/profile中,但是可以修改。但是在我们开始使用 path 变量之前,我们也应该了解一下它当前的设置。有两种方法可以做到这一点,首先是使用echo命令打印变量。echo将解释你给它的任何东西,然后打印到命令行,所以如果我们执行echo $PATH,则echo命令将输出PATH变量的内容,如下所示:

$ echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

好了,这就是PATH变量。路径是由冒号分隔的文件夹列表。这将我们带到查看PATH变量的第二种方式:env命令显示所有当前设置的环境变量。这是一个非常有用的命令,可以用来检查整个系统环境的当前状态。运行env应该会得到如下输出:

$ env

TERM=xterm

SHELL=/bin/bash

XDG_SESSION_COOKIE=eb95d80869be1ad62af36ec5502c41a1-1349772229.897557-1575821964

SSH_CLIENT=10.0.0.104 3643 22

SSH_TTY=/dev/pts/0

USER=pi

LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:

ALL_PROXY=SOCKS://localhost:9050

MAIL=/var/mail/pi

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games

PWD=/home/pi

LANG=en_US.UTF-8

SHLVL=1

HOME=/home/pi

LOGNAME=pi

SSH_CONNECTION=10.0.0.104 3643 10.0.0.56 22

_=/usr/bin/env

这里有许多变量,涵盖了一系列内容,包括我们正在使用的 shell(SHELL)、管理我们执行ls ( LS_COLORS)时显示的颜色的变量、路径、我的当前位置(PWD)、我的主目录(HOME)以及除了PATH之外的用户名(USER)。当试图诊断运行命令的问题时,所有这些信息都非常有用。

既然我们已经能够查看PATH变量,我们应该考虑修改它。要修改一个变量,我们需要使用export命令将它分配到我们的环境中。设置简单变量的语法如下:

$ export VARIABLE="SOMETHING"

如果您运行这个并再次运行env,您应该会看到这个新变量出现在它的输出中,如下所示:

VARIABLE=SOMETHING

如果我们要对我们的PATH变量这样做,我们会将它重置为我们设置的值,这不是我们想要的。我们也可以简单地重写整个路径,但这对于一个简单的改变来说是相当困难的。向PATH变量添加内容的最简单方法是在赋值中包含PATH变量。让我们来看一个例子:假设我们想要将/opt目录包含到我们的路径中。我们将从export PATH=开始,然后我们将使用当前的PATH变量(因为我们将使用echo)来显示它,所以我们编写"$PATH")。对于$PATH,我们将添加一个冒号作为分隔符,并添加一个新目录/opt,它给出了这个命令:

$ export PATH="$PATH:/opt"

运行时,这会将您的PATH变量改为:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/opt

牛逼;/opt被追加到末尾。这给我们带来了一个关键点;PATH有顺序,从左到右。在PATH变量左边的将在右边的之前使用。在我们的示例中,/opt将是我们搜索任何给定文件的最后一个位置。

现在您已经了解了您的用户环境和PATH是如何工作的,您应该了解您的主目录中的一个特殊文件。这是您的本地 shell 配置文件覆盖文件。在您的主目录中有许多以rc结尾的隐藏文件。这些文件通常由您的 shell 或任何应用程序执行,以加载您的个人偏好。标准 Linux BASH shell 的文件是.bashrc文件。这个文件负责我们之前看到的许多环境变量;这也是你的一些命令有颜色的原因。比如ls指令,一般位于/bin/ls(可以用which ls检查)。如果你执行这个而不是正常的ls,你将看不到颜色!这些颜色是由.bashrc文件使用alias命令特别添加的。

alias顾名思义,用来给一个 shell 命令下的一个命令或者一组命令起别名,就像程序一样。在您的.bashrc文件中,它使用了ls命令来执行:

$ ls –-color=auto

这意味着每次你发出一个ls命令,你就自动把颜色参数添加到ls中。.bashrc实现这一点的方法是添加下面这行代码:

alias ls=’ls ˗˗color=auto’

.bashrc这样的文件的伟大之处在于它们被设计成用户可修改的——毕竟,它们是你的本地系统变量。这样,您的本地环境由/etc/profile给出的基本系统值和.bashrc给出的附加值组成。

cron 命令

最后一个命令可能是系统管理员工具包中最强大和最有用的工具之一:cron命令。cron是一个计时应用程序,它根据导向文件传递给它的规则在给定的时间执行命令。cron为每个用户提供了一个名为crontab的导向文件,它会每分钟检查一次,看看是否需要执行另一个命令。要查看您当前的crontab,您只需执行以下命令:

$ crontab –l

不幸的是,您一开始就没有,所以您将从这个命令中得到的是:

no crontab for pi

不要害怕,因为我们现在将回顾创建一个crontab定时文件的基础知识。进入特殊 crontab 编辑器的命令如下:

$ crontab –e

这将打开系统标准编辑器的一个副本,并创建一个初始文件,其中包含一个漂亮的注释块,概述了一个crontab条目是如何布局的。它提供了以下示例:

0 5 * * 1 tar -zcf /var/backups/home.tgz /home/

该命令将在每周一早上 5 点对所有用户的主目录执行一次tar and zip。回想一下,tar为所有文档创建一个归档文件,z i p 将压缩该文件——结果是一个包含所有文件的压缩文件。行首的五个数字控制时间;这些数字按以下顺序代表以下内容:

  • 一小时中的分钟
  • 一天中的小时(24 小时格式)
  • 一月中的某一天
  • 一年中的月份
  • 星期几(星期日,0 到星期六,6)

从示例中可以看出,该命令在一年中的任何一个月中的任何一天的第五个小时的第零分钟运行,只要该天是星期一。通过这种组合,您可以设置任意数量的定时作业来执行系统管理功能。最棒的是,您可以使用我们之前讨论过的所有命令来为您执行这些任务!想在某个时间杀死一个进程?写下cron计时结束的时间,然后使用psgrepawkxargs和我们之前编写的kill命令!有了cron和我们之前提到的所有命令的组合,您可以完成的任务是无限的!

摘要

祝贺您,您现在应该已经走上了成为一名成熟的系统管理员的道路。你有超过 24 个单独的命令供你使用,并且有能力以新的方式组合它们来执行几乎任何你想要的任务。此外,您现在应该有了通过编辑您的crontab文件来使用cron自动执行这些命令的工具。所有这些工具构成了系统管理员管理 Linux 系统的基础,因为它们提供了编写健壮命令并自动执行它们的灵活性。

六、在命令行上编辑文件

信不信由你,在 Linux 上你最终要花大部分时间做的事情之一就是编辑文本文件。它们无处不在,你会发现它们被用于内容、应用程序源代码、配置文件和启动脚本。原因是尽管它们有些基础和枯燥,但它们对于存储人类可读信息非常有用。当你把这一点和易用性结合起来,你就知道你是赢家了。Linux 没有像 Windows 那样的注册表,应用程序很少不使用文本文件进行配置。即使 Sendmail 有一个历史上很糟糕的配置文件(事实上非常糟糕,您需要为另一个应用程序编写一个配置文件,然后该应用程序将为您创建 Sendmail 配置文件),它也将其配置文件存储为普通的旧文本。

在这一章中,我们将给你一个文本文件的简要概述,以及它们今天是如何被使用的。然后,我们将介绍本章将要涉及的两个编辑器(nano 和 vim ),然后我们将进入本章的真正内容,并向您展示如何实际完成工作。

什么是文本文件?

当计算机在磁盘上存储数据时,它可以以两种格式之一存储数据。它可以将数据存储为文本文件,也可以存储为二进制文件。很自然地,当计算机把一切都存储为二进制数据(那些好的旧的 1 和 0)时,究竟是什么使文本文件不同于二进制文件呢?毕竟,文本文件肯定也必须以二进制格式存储。如果你沿着这些思路思考,那么你是非常正确的。与其说是数据本身如何存储,不如说是数据如何读取。

欣赏这种差异的最好方法是想想你现在正在读的这一页。你能理解我写的原因是因为我们已经默认使用英语交流。这一页的内容有我们都理解的结构。我们用大写字母开始句子,我们用标点符号来表示句子何时结束或何时停下来喘口气。简而言之,我们这里有一个相当复杂的协议,但它的工作,因为我们都有能力读和写英语。我们既能理解结构(如何读写数据),也能理解语义(单词的实际意思)。那么,这句话怎么样:

早上好!你好吗?

我们马上就能看出这不是英语,毕竟,如果是英语,我们也能理解。除非你碰巧会说荷兰语(我们不会,但我们的好朋友会),否则你可能不知道它是用哪种语言写的。即使内容没有意义,但结构本身有意义。我们可以看到我们有两个句子,一个是陈述句,另一个是疑问句。在这种特殊情况下,我们可以猜测第一个单词的意思。如果我们像英语一样发音,它听起来非常类似于 good morning(这实际上是这个词的翻译)。由此我们大概可以猜到问题是“你好吗?”。

我们可以这样做的原因是,尽管我们不理解内容,但荷兰语和英语有着共同的结构或格式。我们共享一个字母表(尽管荷兰语确实有一些英语中没有的字符)和标点符号(句号、逗号和问号)。现在你可能发音不正确(毕竟它是一门外语),但是因为我们有共同的结构,即使我们不能理解它,我们至少可以处理它的内容。

图 6-1 更进一步。

A978-1-4842-1162-5_6_Fig1_HTML.jpg

图 6-1。

Some Chinese Text

至少对于这本书的一般读者来说,图 6-1 会是无法解释的。实际上,这两个句子和我们在荷兰的例子中出现的是一样的,但是这次是用简体中文写的。对于门外汉来说,没有办法从这些字符中判断出它们应该如何发音。事实上,根据不同的方言,这些汉字可以用不同的方式发音。这是因为每个字符代表一个想法而不是一个声音,一旦你认识到这个想法,你就知道该说哪个单词。这就是为什么在中国,两个不会说同一种语言的人,通过读写汉字,完全可以很好地交流。

那么,我们为什么要偏离正题去学习外语呢?嗯,文本文件就像读写英语或荷兰语。内容是否有意义取决于读者会说英语还是荷兰语。这类似于两个应用程序及其配置文件。如果您给 Sendmail 电子邮件服务器一个 Apache web 服务器配置文件,它会把它吐回给您(Sendmail 不会说 Apache),但它可以打开并读取文件。

另一方面,中文是我们的二进制格式的例子。对于大多数西方人来说,这是非常陌生的(尽管可以说它比西欧语言中使用的语音书写要高效、优雅和复杂得多)。除非你懂中文,否则你无法理解内容或隐含的结构。用计算术语来说,你所拥有的是一个只有编写它的应用程序才有意义的原始数据块。

现在你可能认为以任意格式存储数据没什么大不了的。毕竟,写它的应用程序是会读它的应用程序,只要它理解文件,这就足够了。是也不是。如果程序中断会发生什么?如果您需要读取另一台机器上的文件,该怎么办?也许供应商已经提供了一些特殊的工具来做到这一点,但是问题就在这里——您需要特殊的工具。

文本文件则不然。文本文件可以在任何文本编辑器中打开,不需要特殊工具。由于绝大多数 Linux 应用程序都使用文本文件(我们想不出任何不使用文本文件的),所以您需要阅读或更改配置文件的全部内容就是您最喜欢的文本编辑器,Linux 有多种编辑器可供选择。因此,您可以熟悉一个工具,然后使用该工具重新配置您的所有应用程序,在编写脚本时编写源代码,甚至用它来写书(这正是我们现在正在做的)。

竞争者

所以文本编辑器是你的 Linux 瑞士军刀,是你永远不想离开家的东西。当然,就像瑞士军刀一样,有许多不同的文本编辑器可供选择,也像瑞士军刀一样,有些比其他的功能更多。有时你想要一个基本的文本编辑器,让你打开文件,编辑一些文本,然后保存结果。其他时候,您可能希望进行复杂的搜索,并替换或删除到行尾。当然,你可以很容易地使用一个更有特色的编辑器来完成你的所有任务,毕竟,如果你不需要的话,你可以不使用这些特性。也就是说,根据我们的经验,人们通常至少熟悉两个文本编辑器,一个是基本的,一个是全功能的。在本书中,这分别意味着纳米和 vim。

我们要介绍的第一个文本编辑器是 nano。这是一个轻量级的,易于使用的文本编辑器,它倾向于安装在大多数系统上。一些较新版本的 nano 有更多的功能(例如编写源代码时的语法高亮显示),但实际上看起来和工作方式都是一样的。如果你能在你的 Pi 上使用 nano,你就能在任何平台上同样很好地使用它。

Nano 实际上是作为 Pico 文本编辑器的替代品而编写的,Pico 文本编辑器过去与 Pine 一起提供,Pine 是一种基于文本的电子邮件客户端。Pico 仍然可以在较老的系统(通常更老)上找到,如果您找不到 nano,您可能仍然能够找到 pico。由于这是一个简单的替换,你习惯在 nano 中使用的相同的命令和基本特性也将在 pico 中可用。结合这一点,您可以了解大多数其他 Unix 平台以及 Linux。

Nano 的主要卖点是它的易用性,但它确实有许多有用的功能。然而,这些功能是从菜单中访问的,虽然它有足够的功能来简单地编辑配置文件,但有时您需要一些功能更强大的东西。这就是 vim 编辑器的用武之地。它能做 nano 能做的所有事情,但它能做的更多,这几乎是比较的终点。Vim 还具有语法高亮、不同的配色方案、剪切和粘贴、删除文本块、缩进文本块、打开多个文件并同时显示等功能。

现在您可能会想,如果 Vim 这么好,那么您只需学习如何使用这个文本编辑器就可以省去很多麻烦。像 nano 一样,它几乎在任何地方都以某种形式存在,它们都具有相同的基本功能,接受相同的命令。我们介绍 nano 的原因是,您可以在几秒钟内启动并运行。它的特点很容易解释,让它做你想做的事情真的很容易。尽管 vim 用户可能不同意,但根据我们的经验,vim 并没有获得任何易用性奖项。也就是说,如果你真的不想学习两个编辑器,并且觉得你宁愿只学习 vim,那也没关系,你不会真的错过任何东西,只是你可能需要更长的时间才能变得有效率。

THE HOLY WAR - VI VS EMACS

信不信由你,文本编辑器圣战(正如它已经成为众所周知的)已经持续了几十年,并且令人惊讶地比 Linux vs Windows 的争论更加激烈。事实上,它已经变得如此激烈,以至于 Richard Stalman(Emacs 的创始人和 GNU 自由软件基金会的创始人)装扮成来自“Emacs 教堂”的圣 Ignucius。他曾多次指出,“虽然 vi 是魔鬼的工具”(vi 在罗马数字中是 6),“使用 vi 不是一种罪恶,而是一种忏悔”。当然,虚拟世界的人群不会坐以待毙,并形成了“虚拟世界的崇拜”。emacs 最强的特性之一是你可以写代码让它做任何你能想到的事情。这使得 vi 人群说“Emacs 是一个伟大的操作系统,只是缺少一个像样的文本编辑器!”。

没有人真的期待这场辩论会结束,尽管有时会变得非常激烈,但通常都是在良好的气氛中进行的。一天结束时,对你来说最好的文本编辑器是让你最有效率的,也是你最喜欢使用的。尽管如此,阅读一些火焰战争和阅读它的历史可以为那些寻找事情做的人提供很好的娱乐…

从纳米开始

我们从 nano 开始,原因很简单,它真的很容易使用,不需要太多解释。你可以在 nano 中做任何你需要做的事情,虽然在另一个编辑器中你可以做得更快,但是 nano 会帮助你很好地完成工作。

可以使用 Nano 命令运行 nano。好吧,这并不奇怪,但是运行 nano 本身并不那么有用。毕竟你现在有了一个文本编辑器,你想做一些编辑。除非做一些笔记,否则没有人会只是写下文字而不想事后保存。一般来说,当你打开 nano 时,你想打开一个特定的文件进行编辑。该文件可能存在,也可能不存在,但是当按下保存按钮时,你可能知道你想给它起什么名字。为了便于介绍,我们将打开 nano,告诉它我们想要编辑 test.txt。我们可以通过以下方式完成:

[pi@raspberrypi ∼] $ nano test.txt

一切正常的话,你应该得到这样的东西(图 6-2 ):

A978-1-4842-1162-5_6_Fig2_HTML.jpg

图 6-2。

Freshly opened nano with a new file

我们已经使用 SSH 连接到我们的 Pi,但是因为 nano 是一个基于终端的应用程序,所以无论您如何运行它,它看起来都是一样的。关于这类终端应用的一个有趣的事情是,它们对你的终端有多大很敏感。固定终端(如物理控制台)有固定的屏幕尺寸。当您通过 SSH 连接或使用虚拟终端时,您可以调整屏幕的大小,这将导致 nano 随之调整大小。这使得它非常灵活,无论屏幕的形状或大小如何,都能满足您的需求。

那么这一切意味着什么呢?

Nano 的屏幕一开始可能会有点混乱(尤其是底部),但大多数时候你实际上不会注意到除了文本之外的任何东西。事实上,所有其他的东西都在背景中消失了。例如,在你屏幕的左上方,你可以看到我们正在运行“GNU nano 2.0.9”。在写这本书之前,我们不知道我们运行的是什么版本的 nano,老实说,直到我们必须在这里描述它,如果有人要求我们凭记忆绘制 nano 布局,我们会很难做到这一点。事实上,我们根本做不到!

从 nano 的标题栏中还可以收集到另外两条信息。正中间的是你正在编辑的当前文件的名字。在我们的例子中,它是“/home/pi/test.txt”。不完全是惊天动地的,但同时在多个窗口上工作是很常见的,能够快速找到你的方位会派上用场。

第三条有用的信息是文件是否被修改过,即是否有任何未保存的更改。这也可以派上用场,因为虽然您可以简单地重新编写文件,但有时如果您从另一个位置编辑了文件,您不确定您所做的更改,您只想知道是否有任何更改没有反映在您正在编辑的文件中。它还可以简单地唤醒你的记忆,提醒你保存你的工作。要查看这是什么样子,只需按空格键进行更改(图 6-3 ):

A978-1-4842-1162-5_6_Fig3_HTML.jpg

图 6-3。

Modified file in nano

标题栏差不多就是这样了。在屏幕的底部实际上有两个部分。第一个是状态栏,显示重要信息(现在它告诉你这是一个新文件),第二个是快捷方式或菜单栏。我们不会对状态行说太多,因为它很容易理解。任何你需要知道的重要信息,纳米都会放在那里。更有趣的(事实上也是使用 nano 的关键)是快捷工具栏。我们在这里仔细看看(图 6-4 ):

A978-1-4842-1162-5_6_Fig4_HTML.jpg

图 6-4。

The shortcut bar

当你在 Windows 或 Mac 上工作时,你可能已经到了不用鼠标来复制和粘贴东西,而是使用键盘组合的地步。在 Windows 上,您可以使用 control 和 c 键,而在 Mac 上,您可以使用 command 键和 c 键。当您同时使用多个键时,您最终会得到一个组合键。nano 的工作方式非常相似,但不是复制和粘贴,它所有的关键功能都是由组合键驱动的。因为要记住所有可能的选项有点困难(尽管你经常使用的选项会很快被你长期记忆),nano 在快捷栏中显示它们。实际上,它只显示了最常见的命令,但我们从来没有必要偏离这些命令。

要使用任何命令,你需要使用正确的组合键。你可以通过查看快捷栏找到你需要的组合。书写“控制键”的简写方式是使用克拉或“”符号。查看快捷栏,你可以看到,如果你想获得帮助,你需要使用“G”,或者换句话说,按住控制键,并按下 g 键。

保存您的文件

保存一个空白的文本文件是非常无聊的,如果你只有一个空格,很难判断它是否保存正确。我们要在这里找一首老歌,敲入“玛丽有只小羊羔”。

与一些编辑器不同(最明显的是 vim,您稍后会遇到),nano 没有不同模式的概念。也就是说,当您键入 nano 时,它将被解释为要放入文件中的文本。另一方面,Vim 以命令模式启动,如果您只是开始输入,您将会得到一些有趣的结果。正如您所料,在每一行之后按 enter 键会将您带到下一行的开头。输入童谣后,您应该会看到类似这样的内容(图 6-5 ):

A978-1-4842-1162-5_6_Fig5_HTML.jpg

图 6-5。

Mary had a little lamb, nano style

我们把 nano 的窗口缩小了一点,这样我们就不会占用大量的空白空间。它也是一个很好的例子,说明了为什么你可能想要调整窗口的大小,以及当你实际这么做时它是什么样子的。在这种情况下,一切看起来都很好,虽然不可否认的是,要写一个合理长度的东西,你需要比这个大一点的东西。

你可能已经注意到状态线似乎已经消失了。这是因为一旦向文件中添加了任何内容,该文件就不再是新文件。我们修改过的警告仍然在右上角。是时候去掉它,让玛丽安全地进入磁盘了。

查看快捷工具栏,您可以看到我们可以使用的选项。你最常使用的是“写出”,意思是“保存文件”和“退出”。Exit 实际上是 WriteOut 的两倍,因为如果您试图在未保存更改的情况下退出 nano,它会询问您是否要保存更改。

让我们从 WriteOut 命令开始。按住 control 键并按下 O 键。Nano 现在看起来应该是这样的(图 6-6 ):

A978-1-4842-1162-5_6_Fig6_HTML.jpg

图 6-6。

Using the WriteOut command

你会注意到我们这里有两个变化。首先是我们的状态线有所回升。这次它在询问信息,或者至少它想让我们确认。现在是保存文件的时候了,nano 要求我们确认文件名。因为我们在最初启动 nano 时给了它一个名称,所以这是 nano 默认提供的名称。如果我们现在按回车键,它将保存文件,但在我们这样做之前,让我们看看快捷栏。

您可以看到它变成了一套全新的选项。这是因为快捷栏实际上是与上下文相关的,也就是说,它会根据你当时正在做的事情向你显示最相关的内容。这些选项仅在保存文件时有用(甚至可用),所以这是你看到它们的时候。除了取消(当你突然决定根本不想保存时),我们实际上从来没有使用过这些选项。

好了,回到保存文件。如果您愿意,您可以更改文件的保存名称,nano 不仅会以您的新名称保存该文件,而且当您返回编辑同一文件时,还会继续使用该名称,您应该会收到如下消息(图 6-7 ):

A978-1-4842-1162-5_6_Fig7_HTML.jpg

图 6-7。

File has been written to disk

你可以看到快捷方式栏已经恢复了它通常的样子,并且我们的状态行中有了一条新消息。您还会发现修改后的状态已经消失了。目前为止一切顺利。

让我们快速看一下,如果您在拥有一个已编辑文件的情况下尝试退出 nano 会发生什么(图 6-8 ):

A978-1-4842-1162-5_6_Fig8_HTML.jpg

图 6-8。

Exiting before saving

我们在这里所做的只是在文件中添加一个签名(尽管不可否认这可能不是 Mary 写的),然后尝试使用 control 和 x 退出 nano。这一次,状态栏给了我们一个可怕的警告,快捷栏给了我们一些减少的选择。我们可以说“是”,在这种情况下,nano 将在退出前保存更改,或者我们可以说“否”,在这种情况下,nano 仍将退出,但我们将丢失自上次保存文件以来所做的所有更改。我们也可以更好地考虑退出,改变我们的想法。在这种情况下,我们可以使用 control plus C 取消我们的退出请求,这将把我们带回 nano。

在纳米里移动

你可以通过使用光标键来移动你的文本,就像你可能习惯于使用你选择的文字处理器一样。事实上,我们在这里提到这一点的唯一原因是因为一些编辑器根本不使用这些键,因为它们让你的手离开主行太远(也就是说,它们使用起来很慢,因为你必须移动你的手很长的距离才能够到它们)。因此,与其解释光标键,我们将向您展示我们在 nano 中最常用的两个功能,这两个功能恰好都与查找内容相关。

第一件事你可能会想使用的是搜索功能,有点奇怪的命名为“在哪里”在纳米。我们可以通过按 control 和 W 键来发出命令,以进入下一步(图 6-9 ):

A978-1-4842-1162-5_6_Fig9_HTML.jpg

图 6-9。

Searching for some text

我们又有了一些新的选择。最常见的任务是简单地找到一个单词。所以让我们搜索玛丽,看看会发生什么(图 6-10 ):

A978-1-4842-1162-5_6_Fig10_HTML.jpg

图 6-10。

Nano found Mary

按下回车键后,nano 将尝试找到您搜索的文本。在我们的例子中,我们已经到了文件的末尾,这就是为什么你可以在状态栏中看到“Search Wrapped”——nano 到达了文件的末尾并绕回以从开始处继续搜索。这是一个非常方便的功能!

你要找的单词会出现不止一次,这是很常见的。如果你想要第二个玛丽,你会想重复你的搜索。只需按下 control 和 W,然后立即按下 enter 键,就可以做到这一点。Nano 会记住你上次搜索的内容,如果你不提供新词,它会用旧词再次搜索。这意味着您可以轻松地在文档中循环查找您正在寻找的特定条目。

我们要介绍的最后一个特性是一种稍微更具体的搜索形式。我们不想搜索一个单词,而是想找到一个特定的行号。在日常的文本编辑中,你实际上不会经常这么做。然而,当您开始编写脚本并且它们产生错误时,您通常会被告知错误发生在哪一行。对于短程序来说,这通常并不重要,但是如果你正在构建一个相当宏大的东西,你会希望能够快速地到达那一行。即使在中等长度的程序中也是如此,因为如果你有一个特别棘手的问题,你将不得不重新访问一段特定的代码,而且你肯定不希望每次都必须使用光标键来找到它。

要转到特定的行号,您需要像之前一样使用 control+W 开始搜索,但不是键入任何文本,而是应该使用 control + T。这将把状态行更改为(图 6-11 ):

A978-1-4842-1162-5_6_Fig11_HTML.jpg

图 6-11。

Go to a specific line number

你所要做的就是输入你想去的行号,然后按回车键。您还可以看到这里有一些其他有用的选项,允许您分别转到文件的开头和结尾。您也可以按下 command 和 T 键返回到搜索文本,或者按下 command 和 C 键取消搜索。

包装纳米

这就是我们将为 nano 介绍的全部内容,但是正如您所看到的,即使是我们介绍的有限的功能,也已经让您能够编辑配置文件,甚至编写自己的书。Nano 非常适合那些你不想分心,只想完成工作的任务。碰巧的是,这本书的大部分内容都是用 nano 编写的,这表明这个工具不仅仅是一个玩具!也就是说,现在让我们来看看 vim 编辑器能为您提供什么…

Vim 入门

Vim 比 nano 高级一点。尽管 nano 被设计得非常简单,但 vim 被设计成一个功能齐全的环境,可以执行各种任务。您甚至可以将其他应用程序(如 shell 和源代码控制)直接与 vim 集成,这意味着您可以在不离开文本编辑器的情况下完成大量工作。

这种原始力量的缺点是你必须学会如何使用它。与基本上可以立即使用的 nano 不同,vim 有模式的概念。一般来说,您要么处于正常模式,要么处于插入模式,这就是我们将在本节重点讨论的内容。

然而,我们想指出的是,即使我们自己经常使用 vim,我们也不是你所说的 vim 专家。我们知道如何使用有助于我们工作的功能,但是有大量的功能我们没有使用或者甚至不知道。由于这只是关于 vim 的初级读本,我们不认为这是一个问题,但是如果您认为 vim 是适合您的工具,那么有大量专门介绍 vim 的书籍以及大量关于它的一些更高级和更强大的特性的视频教程。

与其再打一首诗,不如让我们再给玛丽一次机会,让她回到 vim 的舞台上:

[pi@raspberrypi ∼] $ vim test.txt

不用说,启动 vim 和启动 nano 一样简单,但一旦启动,它看起来确实有点不同(图 6-12 ):

A978-1-4842-1162-5_6_Fig12_HTML.jpg

图 6-12。

Starting up vim

漂亮的标题、状态行和快捷栏都不见了。在 vim 领域,就像 Linux 本身一样,我们应该知道自己在做什么。在屏幕的左下方,您可以看到我们正在编辑的文件的名称。接下来是 6L,它告诉我们文件中有多少行,后面是 115C,它告诉我们字符数。在屏幕的另一边,我们有另一条有用的信息 1,1。这告诉我们当前所在的行和所在的列。现在它告诉我们,我们在第一行第一列。这是有意义的,因为我们刚刚打开文件,如果你看光标,肯定我们已经坐在第一个 m 的上面。

Note

根据 vim 的版本和配置方式,它通常会将您带到上次停止编辑该文件时的位置。这在编程时真的很有用,因为它能让你立即到达动作发生的地方。

您还可以在文件的最后一行下面看到几行波浪号“∨”。这些在这里提醒我们,虽然屏幕有一定的大小,但玛丽下面没有内容。这在进行某些类型的编程时特别有用,并且您希望确保没有额外的空白。这真的只是一个视觉线索,不会妨碍你。

Vim 的模式

Vim 给人的感觉有点奇怪,因为不像文字处理器和更基本的文本编辑器,使用 vim 你不能马上开始输入。这是因为 vim 有不同的模式或个性。当您第一次启动 vim 时,它处于命令模式。与 nano 使用组合键发出命令不同,vim 有大量单字母或双字母命令。你可能会认为这非常令人困惑,但是你是对的。一旦您知道了让 vim 执行您的命令的神奇按键,您就会喜欢这种控制文本编辑器的方式。然而在那之前,它可能会让你分心。

所以让我们离开命令模式,进入更舒适的状态。我们可以通过按“I”键在 vim 中复制一个 nano 风格的环境。这将使我们脱离命令模式,进入插入模式。当你处于这种模式时,你可以分辨出来,因为你在左下角得到–插入(图 6-13 ):

A978-1-4842-1162-5_6_Fig13_HTML.jpg

图 6-13。

Vim in insert mode

此时,您可以像使用 nano 一样在文本文件中移动。光标键按预期工作,您可以像在 nano 下一样添加和删除文本。当你想做除了写文本以外的事情时,这种差异就开始了。你如何保存你的改变?

保存您的更改

要在 vim 中保存您的更改,您需要做的第一件事是退出插入模式。这将把您带回到正常模式,在这里您可以发出命令,从而可以保存您的文档。首先,让我们把签字人改为约翰。这将为我们提供文档急需的更改。为了实际保存文档,我们使用以下命令:

:w

该命令实际上是一个冒号后面跟着一个小写的 W。Vim 区分大小写,因此如果您尝试这样做:W,您将得到一条错误消息,表明它不是有效的命令(图 6-14 ):

A978-1-4842-1162-5_6_Fig14_HTML.jpg

图 6-14。

Whoops, W isn’t a command

不过不必惊慌,只需再次尝试该命令,您就会没事(图 6-15 ):

A978-1-4842-1162-5_6_Fig15_HTML.jpg

图 6-15。

:w on the other hand works like a charm

如果您想在保存时更改文件名,您可以简单地在命令后键入您想使用的文件名,如下所示:

:w test2.txt

这将保存对新文件名的更改,然后继续编辑新文件。

走出维姆

这使我们只剩下一个新的功能,让您达到与 nano 相同的基本水平(我们稍后将介绍搜索)。一旦你完成了所有的编辑并保存了文件,你就会想要退出。用于此目的的命令是:

:q

只要您没有做任何更改,vim 将立即退出,您将回到命令行。然而,如果你已经做了一些改变,并且你试图这样做,你会再一次被 vim 激怒(图 6-16 ):

A978-1-4842-1162-5_6_Fig16_HTML.jpg

图 6-16。

To quit without saving you’ll need an override

幸运的是,vim 已经告诉我们如何修复这个问题,但是基本上,如果您想在不保存更改的情况下退出,您需要明确地告诉 vim 这是您想要做的:

:q!

这就是离开维姆的全部!

在 Vim 中搜索

在这一节中,我们将只介绍基础知识,并向您展示如何进行与 nano 中相同的搜索。事实上,vim 具有非常高级的搜索功能(一开始可以使用正则表达式——参见 boxout ),但是当您在使用中变得更加高级时,您可能会依赖这些功能,但是您可能仍然会发现您大部分时间都在做简单的事情。

要在 vim 中搜索一个单词,您需要做的就是在它前面加上一个正斜杠。要尝试这样做,请在命令模式下(轻按两次 escape 键以确保您处于正确的模式)键入:

/Mary

这将找到 Mary 的所有实例,并为您突出显示它们(图 6-17 ):

A978-1-4842-1162-5_6_Fig17_HTML.jpg

图 6-17。

Vim found Mary

你可以看到“搜索触及底部,继续在顶部”的信息,这相当于纳米的“搜索包装”。使用 vim 需要注意的一点是,因为它使用正则表达式进行搜索,所以默认情况下也是区分大小写的。这意味着如果你搜索的是 mary 而不是 Mary,你会收到投诉(图 6-18 ):

A978-1-4842-1162-5_6_Fig18_HTML.jpg

图 6-18。

Vim can’t find mary

vim 优于 nano 的一个方面是如何进行重复搜索。要移动到下一个搜索结果,您只需按“n”键。在上面的示例文本中,如果您使用/Mary 搜索 Mary,然后一直按“n ”,您将看到 vim 会为您循环搜索结果。我们无法在出版物中展示这种影响,但如果你不想做其他事情,这是一个很好的分散注意力的几秒钟。如果你想在相反的方向搜索(例如,向文件的顶部而不是底部),只需使用大写字母“N”即可。

REGULAR EXPRESSIONS

右手中的正则表达式就像魔术一样。他们处理复杂的文本处理任务,就像一把热电锯穿过温热的黄油。他们还经常被用来给系统管理员尿床的噩梦,并吓唬小孩子。一旦你知道如何使用正则表达式,它就非常强大,但是这种强大是有代价的。尽管如此,正则表达式的基本知识将对您非常有用,您可以在 vim 中直接使用它们来搜索、替换和操作您的文本。

我们在这里没有足够的空间来讨论正则表达式(通常简称为 regex ),但是互联网上有一些很棒的资源可以帮助您入门,更不用说关于这个主题的完整书籍了。一个很好的起点是 Jan Goyvaerts 的网站 http://www.regular-expressions.info/ 。这个网站不仅充满了有用和有帮助的信息(它经常是我们的第一站),而且 Jan 还编写了一些非常强大的软件。我们在很多年前购买了 RegexBuddy,当我们试图调试一些复杂的正则表达式时,它仍然是我们的第一选择。如果你想要一个简单的工具来测试你的正则表达式,看看 http://rubular.com/ ,它用 Ruby 做实时正则表达式解析。

我们在 nano 中讨论的最后一件事是移动到特定的行号。这在 vim 中实际上要容易得多,可能是因为这是程序员必须一直做的事情。要跳转到特定的行号,只需将行号放在冒号后面。例如,要跳到第 5 行,您需要做的就是:

:5

一旦你按下回车键,你将被直接带到第 5 行。和以前一样,这个特性对于普通编辑来说不是特别有用,但是当你摆弄一个 simplify 拒绝按照你知道的方式工作的程序时,它就非常方便了!

在维姆四处走动

虽然我们已经向您展示了如何在文本文件中移动,但是我们还没有利用 vim 的强大功能。Vim 提供了额外的命令,可以让我们更快地浏览文本。

在命令模式下,你仍然可以使用光标键来移动你的文本,这很好也很方便。实际上,您可以使用另外两个命令,即“h”和“l”键来做同样的事情。h 键将光标向后移动一个字符,l 键将光标向前移动一个字符。诚然,这不是很令人兴奋,但我们现在可以引入' b '和' w '命令。它们的工作方式和前面的命令一样,不仅仅是后退一个字符,而是跳到单词的开头。突然,这变得更有用了,因为现在如果你有一长串的文本,而不是长时间按住光标键(很诱人,不是吗?),一次跳一个字就可以大大加快进程。

不过,我们可以更进一步。如果你想跳到一行的开头,你可以按“0”(零)键。要到达行尾,只需使用$(在我们的例子中,这意味着按住 shift 键并按下 4 键)。这非常有用,因为很多时候你想找到一行的开头或结尾,现在你只需按一个键就可以了。

让我们把它放在一个表格里,这样会更清楚一点:

| 行首 | 后退一个单词 | 后退一个字母 | 转发一封信 | 前进一个单词 | 行结束 | | --- | --- | --- | --- | --- | --- | | Zero | b | h | l | w | $ |

所以我们现在有一个渐进的方法来将光标从线的一端移动到另一端。我们再也不用摆弄回车键或空格键,或者等着光标在屏幕上滚动时睡着。这仅仅是个开始,因为这些键不仅仅可以用来移动文件,还可以用来指定输入 vim 的命令的范围。

在 Vim 中删除

要删除一个字符,你只需要按“x”键。这将删除当时光标下的任何字母。这本身有时是有用的(通常是在修改一个错别字的时候),但是它并没有给你带来比进入插入模式更大的优势。然而,“d”键提供了一个非常强大的删除命令,您现在可以结合您新获得的移动光标的知识来做一些非常令人印象深刻的事情。

我们要尝试的第一个删除命令是“dd”。让我们从删除文件中的第一行开始。为了确保我们都在正确的位置,使用下面的命令返回到第一行:

:1

现在,我们将通过键入以下命令来删除当前行:

dd

你的诗现在应该短一些,看起来像这样(图 6-19 ):

A978-1-4842-1162-5_6_Fig19_HTML.jpg

图 6-19。

Deleting the first line

既然我们已经毁了我们的诗,现在是引入 vim 中另一个非常有用的特性——“撤销”命令的好时机。要取消我们刚才所做的更改,只需按“u”键,Mary 就会恢复往日的光彩。这不仅可以防止意外删除错误行时的恐慌,还意味着我们可以用许多有趣的方式删除这一行的一部分。

如果您想要删除多行代码,您可以通过在命令前面加上一个数字来告诉 vim 您想要它执行一个特定命令的次数。例如,如果我们想从我们的诗中删除三行,我们可以这样做:

3dd

这相当于按下 d 键六次,并给你这个快乐的结果(图 6-20 ):

A978-1-4842-1162-5_6_Fig20_HTML.jpg

图 6-20。

Deleting three lines in one go

您可以在左下角看到,正如我们所希望的那样,现在“少了 3 行”。让我们用“u”键恢复 Mary,并尝试其他方法。将光标放在第一行的开头,尝试执行以下命令:

dw

这个命令结合了删除命令和我们前面看到的移动命令。在这种情况下,我们将它与“w”结合,表示“向右一个单词”。我们可以在这里看到该命令的效果(图 6-21 ):

A978-1-4842-1162-5_6_Fig21_HTML.jpg

图 6-21。

Deleting a single word

我们没有移动光标本身,而是有效地选择了我们想要删除的文本。在这种情况下,“d”将从光标的当前位置开始删除,直到下一个单词的第一个字母。我们可以通过多次按下“x”键轻松实现这一效果,但使用“dw”显然更快、更精确。让我们再更进一步,结合我们所知道的。我们知道,通过在命令前面加上一个数字,我们可以让 vim 多次执行一个命令。我们还知道,我们可以将“d”命令与“w”结合起来删除一个完整的单词。让我们唤醒 Mary(再次按下“u”键)并尝试这个新的改进命令(图 6-22 ):

A978-1-4842-1162-5_6_Fig22_HTML.jpg

图 6-22。

Deleting two words at once

2dw

那不是很有趣吗?我们已经能够组合一系列命令来表达一些相当复杂的任务。你当然可以以任何方式组合这些。例如,如果您想删除行尾的所有内容,可以使用 d$。如果您想删除从该行开始的所有内容,可以使用 d0。能够以这种方式组合命令使得 vim 成为处理文本的强大工具。尽管这些特性在处理英语散文时用处有限,但当你开始处理编程语言时,它们确实变得非常有用。

杂项小命令

在我们继续研究 Vim 的可视化模式的一些特性之前,我们将快速概述一下其他一些将会派上用场的简单命令。“I”进入插入模式,但有时您想在当前行的上方或下方书写。你可以通过分别使用 O 和 O 得到这个效果。这两种方法都会插入一个新行,然后切换到插入模式。有时你不需要实际编辑文件的内容,你只需要改变一个字母。这可能是因为打字错误,或者你只是想增加一个数字。您可以使用“r”键来完成此操作。这允许您用任何其他字符替换光标下的字符。只需按下“r ”,然后输入要替换的字符。简单却很有效!

视觉模式

我们自己并不经常使用视觉模式,但是当我们使用它的时候,它通常会节省我们大量的时间和精力。此模式允许您选择或突出显示文本块,以便进一步处理。这类似于在文字处理器中用鼠标高亮显示文本。有两种方法可以进入视觉模式,按“V”键或“V”键。如果你使用大写的 V,你将能够根据行选择一个文本块。使用小写 v,您可以获得额外的精度,因为您可以基于单个字母而不是整行进行选择。总的结果是一样的,你的选择只取决于哪一个对你来说最方便。

那么视觉模式到底能做什么呢?它本身并不做任何事情,它只是提供了一种简单的方法来告诉 vim 下面的命令应该应用于什么文本。按照我们之前的例子,让我们选择玛丽的诗的一大块。您不需要突出显示我们拥有的确切文本,而是尝试获得一个相当随机的块(图 6-23 ):

A978-1-4842-1162-5_6_Fig23_HTML.jpg

图 6-23。

Highlighting text in visual mode

正如你从突出显示中看到的,我们使用了小写的“v”选项,因为我们想要突出显示某个特定的单词。除了一种戏剧性的感觉之外,没有其他真正的原因,所以它可能很容易是一串用“V”选择的线条。现在让我们应用我们最喜欢的命令,删除命令。按“d”你会发现高亮文本神奇地消失了。在这种情况下,您不需要向 vim 提供额外的信息来告诉它删除什么,因为实际上您已经通过在第一个位置高亮显示文本告诉了它。

当然,除了删除文本,你还可以做其他有趣的事情(尽管删除文本很有趣)。例如,如果要缩进这首诗的前两行,可以用 V 突出显示前两行,然后使用大于号和小于号( >和< respectively) as appropriate. We can’t show you how that would look in print (honestly moving huge chunks of text back and forth is surprisingly theraputic) but we can show you the end result of this command (Figure 6-24 ):

A978-1-4842-1162-5_6_Fig24_HTML.jpg

图 6-24。

Indenting highlighted text

还有一个非常有用的特性我们还没有谈到,它非常适合视觉模式——复制和粘贴。

复制并粘贴 Vim 样式

在终端中复制和粘贴是一个不确定的命题。原因是运行在终端中的应用程序实际上生活在它自己的小世界中。例如,如果您从笔记本电脑的终端上复制文本,该文本将被复制到笔记本电脑的剪贴板上。远程应用程序(在本例中是 vim)不知道您这样做了。同样,如果你把笔记本电脑上的内容粘贴到 vim 中,vim 会简单地接收到一组击键,它不会知道这些内容来自剪贴板。一般来说这是可以的。如果你只是想移动一些文本,那么以这种方式使用剪贴板可能是好的。

有些时候,这并不能如你所愿。例如,如果你有一个分屏,你有两个并排的文件,你想选择左边的第一段,你现在有点卡住了。终端只是向你展示服务器上的内容,它只是一个显示器,因此终端并不真正了解它在显示什么。如果你试着复制和粘贴左手边,你会发现右手边也跟着来了。这远非理想(更不用说高度刺激性)。

您可能遇到的另一个问题是,您可能希望 vim 对文本做一些事情。如果你只是想粘贴一次,没什么大不了的,但是如果你想粘贴正好 10004 次呢?Vim 在那里帮不了你,因为它对你的本地剪贴板没有概念。你会发现,当这些问题突然出现时,它们会变得相当小众,你可以绕过它们。然而,这很可能会激怒你,因为你会想“要是我能复制这篇文章就好了!”当你坐在那里试图解决问题的时候。

我们需要的是一个远程剪贴板,远程应用程序可以在这里存储数据进行处理。这方面没有标准,但是许多基于终端的应用程序提供了一个解决方案,在 vim 的例子中,它提供了拖拽和粘贴功能。要提取某些内容,您需要使用“y”键。这使用了与' d '命令相同的修饰符,因此您可以非常愉快地用' yy '复制一整行(记住,字母只是对折),用' yw '复制一个单词。同样像删除命令一样,我们也可以在可视模式下使用它。

首先,只需突出显示您想要复制的文本。为了简单起见,我们再来看看上面两行。用“V”键高亮显示后,按“y”键将其拖入剪贴板。这是第一阶段的完成,现在我们要做的就是把它粘贴回我们的文件。有两种方法可以将 paste 命令与' P '或' P '一起使用。与“V”和“V”命令一样,大写和小写版本通常以某种方式相关联。在这种情况下,“P”键在当前行之前插入内容,而“P”键在当前行之后插入内容。在点击其中一个键之前,请随意将光标移动到文件中的任何位置。效果确实如您所料,vim 只是将内容粘贴进去。当然,您可以将这些命令与数字前缀结合起来,重复插入内容的次数。下面是如果你结束 40p 会发生什么(图 6-25 ):

A978-1-4842-1162-5_6_Fig25_HTML.jpg

图 6-25。

Mass pasting

虽然你还不知道,但你实际上已经学会了剪切和复制文本。每当您使用“d”键时,您会从文件中删除文本,但副本会放在剪贴板中。如果您选择了一行并用' dd '删除它,您可以用' P '恢复它。请记住,如果您使用' p '键,因为您已经删除了该行,您实际上将在您当前所在的行之后插入原始行。如果要将其恢复到原始位置,必须使用' P '键粘贴到当前行之前。

摘要

在本章中,我们已经了解了文本文件和二进制文件的区别,以及为什么文本文件是配置软件的通用语言。我们已经讨论了您在旅行中可能会遇到的两个关键文本编辑器,并且我们已经为您提供了这两个编辑器的良好基础。当然,我们不能向你展示所有可能的事情,但是现在你应该可以自己探索和尝试新事物了。

在下一章中,我们将介绍 BASH shell,并向您展示一些系统管理员需要了解的更重要的事情…

七、管理您的 Pi

所以现在你有了这个神奇的圆周率,安装了 Raspbian,登录并以你喜欢的方式得到了你的圆周率,甚至在头脑中有一些事情要做。尽管您对 Linux 越来越熟悉,但问题是每次您的 Pi 关闭或断电时,您都需要回到它那里,登录并进行物理设置,然后才能再次使用它。嗯,不会再有了!

这一章是关于系统管理和一些基本的应用程序功能,这些功能将允许您管理系统在启动时的运行方式。为了提供帮助,我们还将为您提供一个用 BASH 语言编写代码的速成班,以便您可以创建自己的启动脚本来启动应用程序(我们也将介绍什么是脚本)。最后,我们将介绍系统的一些基本安全性,包括用户管理,以便您可以更改密码和向系统添加新用户。

远程访问 Pi

对于来自 Windows 或 OSX 环境的人来说,在 Linux 环境中工作最难适应的事情之一可能就是在 shell 中工作。首先,这并不美好,但更重要的是,人类是非常习惯于操纵事物来达到某种结果的生物。这意味着基于 GUI 的环境更直观——首先。由于来自 Windows 环境,我可以肯定地说,命令行是一个非常好的工作环境。与键盘和鼠标操作相比,点击、拖动和执行上下文操作所能完成的工作量是惊人的。能够纯粹从命令行在系统中工作确实是一项巨大的财富。但是你需要熟悉它,而唯一的方法就是练习!

当我们需要讨论管理您的 Pi 时,为什么我要讨论命令行呢?因为大多数 Linux 管理是通过命令行实现的,您想要使用的大多数(如果不是全部)系统功能都可以从命令行获得。此外,通过命令行访问您的系统比通过 GUI 访问要容易得多,而且占用的资源也少得多。要通过命令行远程访问您的系统,您只需使用安全 Shell(或简称 SSH),这是您在第三章第一次看到的。您还需要确保系统的网络访问在启动时也是可用的。这两个功能提供了从任何地方管理系统的基本功能,因为您已经启用了网络,然后可以使用 SSH 连接到您的系统。因此,让我们更仔细地检查一下这两个函数,以便您理解如何确保您可以始终访问您的 Pi 来管理它。

建立关系网

如果您和大多数人一样,有一个路由器为系统中的多个设备提供网络访问,您可能会意识到您的路由器会自动为所有设备提供网络 IP 地址。它不是通过任何魔法,而是通过一种叫做 DHCP 的特殊协议来实现的,DHCP 代表动态主机控制协议。DHCP 的目的是自动为机器分配 IP 地址,这意味着不需要手动分配。当 DHCP 被配置时,它会被网络服务自动调用。我们将在第九章 WiPi 中更详细地介绍如何配置网络。

但是,如果出于某种原因,您需要手动调用 DHCP 为您分配一个 IP 地址并让您连接到网络,您需要使用dhclient命令。您将需要以 root 用户身份运行它,因为您需要使用大多数这些命令,因为您正在更改核心系统功能。如果您只是照原样运行dhclient,您将尝试为系统上的每个接口获取一个新的 IP 地址,这可能并不理想。您实际上可以指定一个特定的接口供dhclient使用,只需将它作为命令的第一个参数(即dhclient eth0)。

域名服务器(Domain Name Server)

在使用您的系统网络时,可能需要记住的最重要的事情之一是 DNS,它是域名系统的缩写。DNS 是互联网上的每个系统能够将 URL(例如, www.apress.com )转换成 IP 地址(例如,173.203.147.183)的方式。Linux 机器上的 DNS 通过知道它应该将查询定向到哪里来工作。这由文件/etc/resolv.conf控制,该文件包含一个名称服务器指令,告诉您的系统应该查询的名称服务器的位置。通常这是你的路由器,但它也可以是互联网 DNS 服务器,如谷歌的 8.8.8.8。这些会这样出现在resolv.conf里:

nameserver 10.0.0.1

SSH 是一种可以远程获得到 Pi Shell 的安全和加密连接的方法,而不需要对它做任何物理上的事情。SSH 的安装和运行,以及访问你的系统的基本命令,在第三章中有所介绍,所以我们不会涉及太多细节,而是会深入 SSH 的功能。SSH 由在 Pi 上引导时运行的sshd守护进程提供。您可以用与您的系统相同的方式启动和停止这个命令,即使用sshd init 脚本。所有系统初始化脚本通常位于/etc/init.d/中,它们通常以 root 用户身份运行。要使用它们,请将您想要采取的操作(启动、停止和重新启动)添加到脚本的第一个参数中。所以要重启 SSH,运行/etc/init.d/ssh restart。此外,这些脚本是您的系统用于在引导时运行程序或命令的脚本。因此,让我们看看如何利用它来编写您自己的 init 脚本。

BASH:基本编码

除了“嘿,你能帮我修电脑吗?”我最常被问到的计算问题是“你能教我如何用 C 写这个应用程序吗?”。我的同事、朋友或亲戚没有一个月不来找我,让我教他们如何写软件。通常,他们会问如何用 c 编写应用程序的快速纲要。这在很大程度上不是一个不合理的问题,但通常当我问他们想做什么时,他们会想做一些简单的事情。虽然我很乐意提倡学习 C,但是有一种更简单的方法可以让他们了解软件设计的奇妙世界,而不用承担学习 C 的任务(对于他们通常追求的东西来说,这是一种过度的追求)。

这是本章这一部分的目标。我们旨在向您介绍编码、基本逻辑结构和一些基本的软件设计原则,以便您能够完成工作。我们将通过向您介绍 BASH 来实现这一目标。虽然许多人会嗤之以鼻,但 BASH 是介绍编程核心基础知识的完美方式。BASH 也是世界上使用最广泛的软件语言之一,因为 Linux 系统上的大多数应用程序都有某种程度的 BASH 软件,在这个过程中执行某种中介功能。

什么是 BASH?

如第三章所述,BASH 是 Bourne Again Shell 的缩写,是大多数 Linux 和 UNIX 环境的默认 Shell 环境。当您通过命令行登录到您的系统并看到提示时,这个提示是由 BASH shell 提供给您的。Shell 将接受命令和指令,并处理它们以执行系统功能。在通过命令行使用或管理系统时,您通常发出的大多数命令都是调用其他应用程序以便生成输出的命令。

虽然这看起来是一种非常明显和简单的方式,但它也是演示任何软件应用程序如何工作的核心规则的一种极好的方式。你接受一个给定的输入,对它进行某种计算,产生一个响应(称为输出)。事实上,这个过程是许多人认为理所当然的生活和工作的许多功能的基本过程。正是这个输入、计算、输出的基本模型,将构成我们理解编程如何运作的基本模型。

那么回到第一个问题:BASH 是什么?BASH 是一个 shell,shell 是一种获取输入并根据输入进行计算以生成输出的方法。BASH 有许多工具,允许您使用几乎所有编程语言的相同基本逻辑结构。这就是 BASH 作为编程语言和 shell 的工作方式——您可以编写许多这样的逻辑操作和命令,然后用它们来组成计算。现在,您对 BASH 是什么、shell 是什么、任何计算机程序的广泛用途是什么,以及如何使用所有这些函数来执行输入、计算和输出的基本操作有了初步的了解。现在,您已经对我们想要实现的目标有了一个非常宽泛的了解,我们可以将这些知识作为学习如何用 BASH 编写程序的基础。

从 BASH 开始

所以你知道什么是 BASH,什么是 shell,以及程序的基本逻辑是如何工作的,这通常被许多人认为是鹤立鸡群。事实上,一些面试官评论说,虽然他们的雇主对潜在的软件工程师有严格的提问,他们都可以支持我们所涵盖的内容,但他们抱怨说,许多员工和毕业生无法在一张纸上形成基本程序的逻辑。他们进而提出了一个编码测试,一个任何软件工程师都应该能够快速解决的非常简单的测试。这项测试被称为“嘶嘶嗡测试”,是基于一个同名的儿童游戏。基本原则是,你必须从 1 数到 100,对每个 3 的倍数说 Fizz,对每个 5 的倍数说 Buzz,最后对每个 3 和 5 的倍数说 FizzBuzz。听起来很简单;那是因为它是。毕竟,大多数编码只是构建小的逻辑块,并将它们附加到其他逻辑块上;将许许多多小的输入、计算和输出节点混合在一起,形成一个更大的计算系统,执行更大的输入、计算和输出过程。

为此,我们将从在 BASH 中编写我们自己的 FizzBuzz 问题解决方案开始,这样你们都可以通过基本的软件工程师能力测试!没错;我们将在 BASH 中编程。BASH 解释器提供的命令与常见的编程逻辑元素具有相同的功能。这些命令可以与普通的 shell 命令结合起来形成完整的程序。所以,让我们开始写吧(我们在第六章的中讨论了文本编辑器,所以你可以使用任何你喜欢的)。您所需要的就是能够编辑一个文件,然后在命令行上执行它。继续打开您最喜欢的文本编辑器,写下以下内容:

#!/bin/bash

这是任何想用 BASH 编写程序的人应该写的第一件事。这被称为 shebang,它是一个特殊的符号,当放在任何文件的第一行时,意味着它是我们要使用的脚本解释引擎的路径。在这种情况下,我们将使用 BASH 的解释器,它位于 Pi 和几乎所有其他 Linux 和 UNIX 操作系统的/bin/bash中。这将告诉外部命令提示符 shell,当它运行这个程序时,应该使用/bin/bash解释器来执行它。对于任何一种解释语言,你都应该在给定程序的开始部分包含某种形式的 shebang。

解释型与编译型

这很好地把我带到了下一个问题:解释语言与编译语言。出于这些目的,您不需要对编译语言有很深的了解,但知道它们的存在并了解解释语言和编译语言之间的一些差异总是好的。因此,尽管这两套语言都允许你编写自己的程序供计算机执行,但它们在这方面的方式是完全不同的。

解释语言(有时称为脚本语言)写下一系列编程命令,这些命令被提供给解释引擎(例如 shebang 提供的),解释引擎将推断它们的计算含义并执行程序想要的功能。这是一个相当于蛋糕食谱的纸笔,你写下制作蛋糕的确切方法,翻译为你烹饪并输出美味可口的蛋糕。

Note

这个食谱的性质也很像一个剧本,因为只要你有剧本并且能读懂它,你每次都会执行相同的动作。这就是解释语言通常被称为脚本语言的原因:它们的最终输出是一组文本,每次都可以用相同的方式创建编程输出。

编译语言采取了不同的方法。他们也有一个配方(称为源代码),但不是配方运行,而是它将被带到一个称为编译器的专门软件,该软件将获取配方并从中创建一个可执行包(称为二进制文件)。这个二进制包是用计算机自己的机器语言编写的,所以当执行时,它自己执行所有的动作。这相当于为一个专门的蛋糕制作系统编写计划,然后将它安装到您的系统中,并让它制作蛋糕。在这两种情况下,你都得到了蛋糕,但从你说开始的那一刻起,翻译的蛋糕可能需要更长一点的时间来制作。另一方面,创造专门的蛋糕制作机器需要更多的努力。现在你应该明白为什么我说像 C 这样的语言对于小问题来说是多余的了——C 是一种编译语言。

BASH 中的输出

回到我们的应用程序:如果你保存并运行你的程序,它不会为你做任何事情。所以首要任务应该是让你的程序输出一些东西。这是通过echo语句完成的,该语句也可以从命令提示符 shell 中获得;您使用echo让系统输出一组给定的文本。因此,让我们在您的脚本中添加一个输出,让它向世界上的每个人问好。修改您的脚本,使其看起来像这样:

#!/bin/bash

echo "Hello World!"

现在继续执行您的脚本;为此,您需要更改脚本的文件权限以允许它被执行。我的脚本名为fizzbuzz.sh,因此使其可执行并执行它所需的命令如下:

$ chmod +x fizzbuzz.sh

$ ./fizzbuzz.sh

该代码将生成以下输出:

Hello World!

恭喜你!您刚刚编写了世界上最简单的程序,Hello World 程序,这是大多数软件工程学生被要求创建的第一个程序。它展示了如何开始构建一个小软件,并完成任何软件程序的基本任务:它生成输出。在这种情况下,链是我们给它一个输入“请输出‘Hello World!’系统计算出这个值,然后给出我们想要的输出:Hello World!我用一对引号将Hello World!括起来。(这样做是为了让Hello World!行被当作一个字符串,而不是其他要执行的命令。)所有语言都需要区分什么是数据,什么是实际的编程逻辑。本例中的引号表明,引号内的所有内容都被视为一个文本字符串。

你可能会问,“那么如果我想输出一个引号呢?假设我想输出引号中的"Hello World!"。"没问题,我们会保护你的!所有的系统都有一个叫做逃逸的概念。转义是一种特殊的字符,它告诉解释器或编译器忽略下一个字符的特殊属性,只把它当作给定字符串的一部分。在大多数系统中,转义字符是反斜杠()。因此,如果我们想让我们的Hello World!有引号,我们将修改如下:

#!/bin/bash

echo "\"Hello World!\""

这表明我们想要转义那些内部的引号对,所以如果我们执行,我们应该看到如下内容:

$ ./fizzbuzz.sh

"Hello World!"

太棒了!如果您想在代码中输出一个反斜杠,您甚至可以进行转义。在编写软件时请记住这一点,因为这是人们最常犯的错误之一——代码中有未转义字符,这会导致软件的其他部分出现问题,因为字符串混淆了。

Note

大概最常见的转义字符是\n,是 newline 的简称。这可用于在下一行输出文本。

顺便说一下,这是具有语法突出显示的文本编辑器进入自己的领域的地方,因为它们在显示哪些字符是字符串的一部分,哪些不是字符串的一部分方面有很大的帮助。Vim 有语法高亮,nano 也有(但不是通过 SSH);不幸的是,默认的 GUI 编辑器 LeafPad 没有,但是有很多编辑器,你只需要找到一个适合你的。它们还有括号匹配、大括号匹配等其他功能,但现阶段对我们帮助不大。

概述

那么到目前为止我们学到了什么?我们已经介绍了如何使用 shebang 启动 BASH 应用程序,这样我们就可以选择合适的解释器。您学习了如何将基本输出打印到屏幕上,以及如何在字符串中使用转义符。这很好地把我们带到了列表的下一点:变量。

变量

变量是给定数据的抽象表示。你说什么变量是计算机存储给定信息的一种方式,以便可以再次检索。这是程序中大多数信息存储和操作的方式,因为大多数程序不像我们简单的Hello World!那样工作,它们接受各种形式的信息,并将其转化为其他信息。所以让我们离开第一个例子,回到编写 FizzBuzz 应用程序的问题上来。我们需要从 1 数到 100。

我们可以简单地写出每个数字,每行一个,然后对每个数字进行 FizzBuzz 计算,但这并不是编写这个程序的好的逻辑方式。我们需要的是一个可以包含“数”的抽象变量;然后,我们可以对这个“数字”运行 FizzBuzz 测试,然后我们将简单地将“数字”增加 1,冲洗并重复,直到数字 100 被测试。那我们就完了。

现在你应该对变量有所了解了。这是一种我们可以表示任何单一信息的方式。我们不一定要有具体的信息,因为变量就是——本质上的变量?然而,有一些变量的限制需要考虑。首先,在更广阔的编程世界中,定义了许多不同类型的变量,例如布尔型、整型、双精度整型、长整型、字符型、字符串型、浮点型、向量型、数组型等等。对于 BASH,只有几种变量类型,但是我们应该知道其他变量类型中最重要的,因为这在其他编程语言中也会起作用:

  • 首先是 integer,它是一个数值变量,只用来表示一个数字(在大多数情况下,只表示一个整数)。定义这种类型是为了方便使用数学和其他数字函数,如加、减、乘等。
  • 第二个是字符串,它是一种书写数据,代表一长串书写字符。字符串通常与用户输入和输出相关,因为由于文本字符串中包含的内容的高度可变性,在应用程序中处理它们太麻烦了。
  • 第三个是数组,这是一种特殊类型的变量,因为它是元变量,基本上是许多其他变量的载体。数组中的子变量称为元素,通过在数组变量的末尾添加一对方括号和一个与所讨论的数组元素相对应的数字来引用。数组不是从 1 开始的;相反,它们从 0 开始,因为 0 在逻辑上是计数序列中的第一个数字。所以如果你想从一个数组中获取第四个元素,你需要在数组变量的末尾加上[3]

现在你知道了什么是变量,我们可以开始形成解决 FizzBuzz 问题的基本程序逻辑了。

逻辑运算:如果

现在我们既有能力输出东西,也有能力存储东西,这涵盖了计算机程序输入和输出的第一部分和最后一部分。我们现在需要做的是对变量进行一些计算,这样我们就可以让程序做一些有意义的事情。这就是我们展开逻辑运算的地方。在编程中,有两个基本的逻辑运算你需要熟悉。这两个逻辑操作构成了在任何地方进行的大多数编程的基础。他们这样做是因为他们允许人们执行测试,并根据测试的结果采取不同的行动。

这些语句中的第一个是if语句。一个if语句的执行就像它的名字所暗示的那样——如果某事为真,就执行一个动作。正是if语句的测试性质为它提供了所有的力量,因为当与变量结合使用时,我们可以测试任何我们想要的东西。所以看看 FizzBuzz 的例子,我们知道我们有初始变量“number ”,它代表 1 到 100 之间的计数。我们需要对“number”进行测试,看看它是能被 3 整除、能被 5 整除,还是能被 3 和 5 整除。如果它匹配这些条件中的一个,我们需要输出正确的单词。

所以现在你需要理解一个if语句是如何写入程序的。在 BASH 中,基本语法如下:

if [ <TEST> ]; then

DO SOMETHING

fi

前面是一个简单的 BASH if语句,实际上并没有那么复杂。你会注意到,随着if和测试和做某事,还有一个fifi表示要执行的事情的结束,因为您可以在一个if语句中执行多个动作。所以,现在我们有了我们的if语句,所以我们需要让它做事情。所以我们来快速看一下一些数学运算。

Note

记得左方括号两边各留一个空格,右方括号前留一个空格,分号后留一个空格;否则,您将会得到一个语法错误。

基于测试的算法

我们知道我们需要有一个相等的测试,那么有人如何确认任何一个给定的数是否能被另一个给定的数整除呢?简单的答案是检查当除以一个给定的数时,结果是一个没有任何“余数”的“整数”事实上,这是一个听起来很难编程的概念。尽管乘法、加法、减法甚至除法都会给出有限的可检验的答案,但检查一个数是否能被另一个数整除则需要不同的运算。谢天谢地,有一个专门为这个问题设计的数学运算:模数。模数返回任意两个数相除的余数,用符号%表示。所以模数给你这样的结果:

12 % 3 = 0

12 % 5 = 2

突然我们的测试出现了:如果数模 3 等于 0,我们输出 Fizz,如果数模 5 等于 0,我们输出 Buzz,如果数模 3 和 5 等于 0,我们输出 FizzBuzz。因此,如果我们将所有这些结合起来,我们会得到以下结果:

if [ number % 3 = 0 ]; then

echo "Fizz"

fi

if [ number % 5 = 0 ]; then

echo "Buzz"

fi

if [ number % 3 = 0 ]; then

if [ number % 5 = 0 ]; then

echo "FizzBuzz"

fi

fi

好吧,这是一个看起来不错的尝试,但是为了使 BASH 成为有效的可执行 BASH,我们仍然需要解决一些与 BASH 相关的问题。

让我们从简单的变量开始。在 BASH 中,变量有两种操作模式。首先是赋值模式,当我们创建一个新变量并给它赋值时就会出现。在这些实例中,变量的工作方式与前面的数字一样,所以我们可以这样将number变量创建为 1:

number=1

这很好,看起来就像我们的例子,但是当我们想要使用number变量的当前值时,我们需要访问该变量,这是在解引用模式下完成的。在 BASH 中,这意味着在我们想要使用值的每个变量前面添加一个美元符号($)。

概括地说,变量有两种模式:一种是加载变量(称为赋值),另一种是从变量中取出值(称为解引用)。在第一种模式中,我们按原样使用变量;在第二个例子中,我们在变量前面使用了一个$。好的,没问题。让我们更新代码:

if [ $number % 3 = 0 ]; then

echo "Fizz"

fi

if [ $number % 5 = 0 ]; then

echo "Buzz"

fi

if [ $number % 3 = 0 ]; then

if [ $number % 5 = 0 ]; then

echo "FizzBuzz"

fi

fi

所以我们的代码看起来稍微好一点,但是你可能已经注意到了当我们给一个数字赋值 1 时发生的下一个问题。等号(=)用于给变量赋值,因此在这种情况下,我们似乎试图给变量 5 赋值 0,这将导致if中的测试出现各种问题。大多数语言都使用一对等号(==)来表示对等式的测试,但是在 BASH 中,我们有许多特殊的算术测试操作符来测试这一点:

  • -eq为了平等
  • -ne为不相等
  • -gt对于大于
  • -lt因少于那个
  • -ge对于大于或等于
  • -le小于或等于

我们可以在代码中利用这些操作符来比较模数和 0 的结果。因此,再次对您的代码进行这些更改,您应该得到以下内容:

if [ $number % 3 -eq 0 ]; then

echo "Fizz"

fi

if [ $number % 5 -eq 0 ]; then

echo "Buzz"

fi

if [ $number % 3 -eq 0 ]; then

if [ $number % 5 -eq 0 ]; then

echo "FizzBuzz"

fi

fi

最后,当进行算术运算(比如模数)时,我们需要告诉 BASH 这意味着是算术运算。为此,我们使用一个$和一对括号将实际的算术位括起来,因此5 % 3的操作意味着我们需要$((5 % 4)),我们可以进行更改:

if [ $(($number % 3)) -eq 0 ]; then

echo "Fizz"

fi

if [ $(($number % 5)) -eq 0 ]; then

echo "Buzz"

fi

if [ $(($number % 3)) -eq 0 ]; then

if [ $(($number % 5)) -eq 0 ]; then

echo "FizzBuzz"

fi

fi

你有它;您已经为 FizzBuzz 应用程序编写了三个简单的测试;并使用了if语句、变量、打印和特殊算术运算符。这有很多代码,所以让我们测试一下,确保我们现在得到的能够工作!

我们现在可以通过创建一个只有一个值的number变量来做这个简单的测试。让我们把它指定为 15,这样我们可以保证一些输出。添加了number变量后,您的脚本应该如下所示:

#!/bin/bash

number=15

if [ $(($number % 3)) -eq 0 ]; then

echo "Fizz"

fi

if [ $(($number % 5)) -eq 0 ]; then

echo "Buzz"

fi

if [ $(($number % 3)) -eq 0 ]; then

if [ $(($number % 5)) -eq 0 ]; then

echo "FizzBuzz"

fi

fi

执行时,输出如下:

$ ./fizzbuzz.sh

Fizz

Buzz

FizzBuzz

解决纷争

哦亲爱的。这种输出是一个问题。我们同时说出了这三个词,而不仅仅是当数字被 3 和 5 整除时发出的嘶嘶的声音。我们刚刚失败了!啊!好的,深呼吸几次;这不是世界末日。事实上,这是一个引入新特性的好时机。当测试为真时,if语句会做一些事情,但是我们还可以添加另一部分:elseelseif的另一面,逻辑是这样的:如果测试为真,就做一些事情,否则就做另一件事情。我们可以结合使用这两种方法来测试 FizzBuzz。一个ifelse语句的语法如下:

if [ TEST ]; then

DO SOMETHING

else

DO A DIFFERENT THING

fi

语法几乎与原始的if语句完全相同,因此很容易进行一些修改,使您的if语句变成ifelse语句。但是现在我们遇到了更大的问题——这也是大多数人在编程时遇到问题的原因;这是逻辑顺序流程。我们需要创建一个测试序列,以便我们可以确定某个东西是被 3 整除、被 5 整除还是被两者整除;并且在每种情况下执行完全不同的动作。这种想法使得编程对许多人来说如此困难,而且没有诀窍:你只需要简单地解决它。所以让我们一起来解决这个问题。

如果我们找到能被 3 或 5 整除的东西,并在检查它是否能被这两者整除之前输出它,我们会遇到输出嘶嘶声、嗡嗡声和嘶嘶声的可能性,这不是我们想要的。让我们先来测试一下这两者:

if [ $(($number % 3)) -eq 0 ]; then

if [ $(($number % 5)) -eq 0 ]; then

echo "FizzBuzz"

fi

fi

好了,现在我们有了 FizzBuzz,但是如果答案能被 3 整除却不能被 5 整除呢(Fizz 就是这种情况)?然后我们可以输出气泡。因此,如果我们在被 5 整除的测试中添加一个else,我们将保证得到一个被 3 整除而不是被 5 整除的数。这意味着我们避免了同时输出 Fizz 和 FizzBuzz 的问题。我们可以在这里使用新的else语句来实现这一点,所以当我们将else添加到可被 5 整除的测试中时,我们得到这样的结果:

if [ $(($number % 3)) -eq 0 ]; then

if [ $(($number % 5)) -eq 0 ]; then

echo "FizzBuzz"

else

echo "Fizz"

fi

fi

太棒了。现在我们只剩下一种情况:当一个数不能被 3 整除,但能被 5 整除。我们可以在另一个else语句中做这个测试。通过将此作为else语句的一部分,并添加第二个可被 5 整除的测试,我们可以确保当一个数字可被 5 整除时,当我们输出它时,它还没有被 3 整除。这意味着我们避免了以前遇到的问题,所以添加这个测试,您的代码变成如下所示:

if [ $(($number % 3)) -eq 0 ]; then

if [ $(($number % 5)) -eq 0 ]; then

echo "FizzBuzz"

else

echo "Fizz"

fi

else

if [ $(($number % 5)) -eq 0 ]; then

echo "Buzz"

fi

fi

这应该可以了!我们要进行一系列新的测试。继续替换脚本中的旧语句,并运行这个新语句:

$ ./fizzbuzz.sh

FizzBuzz

完美!这是 15 的正确结果!您可以更改number的值,再执行几次来进行测试,但是这个测试应该经得起考验,因为我们已经仔细考虑了我们的编程。现在我们需要计算从 1 到 100 的数字。为此,我们将使用第二个逻辑运算!

逻辑运算:循环

循环是一种特殊类型的逻辑操作,其核心功能类似于if语句,但如果语句为真,它将一遍又一遍地运行语句,而不是运行代码,只要语句为真。这就是我们如何将数字的值一次又一次地增加 1,一直数到 100。BASH 中的循环使用以下语法:

while [ TEST ]; do

DO SOMETHING

done

从设计上来说,循环与if语句非常相似。两者都在测试某个条件是否为真,然后都将执行一段代码。不同之处在于,if语句将只执行一次,而while循环将一直执行到某个条件不再为真。这给 be 带来了关于循环的第一个也是最大的警告:如果你忘了为你的循环设置一个离开条件,那么你将永远不会离开它。这就是所谓的无限循环,在这个循环中,你的程序会被卡住,什么都不做,永远运行下去。在少数情况下,这是可取的,但并不多。幸运的是,我们有 Ctrl+C 快捷方式,它将发送一个终止信号给我们正在运行的程序,我们可以用它来使程序脱离无限循环。

你可能会想,“哦,这就是为什么这么多程序被卡住了!”这是 100%真实的。有时你可能没有考虑到的情况会出现,你的程序可能会永远循环运行,所以你要小心了。

对于我们的 FizzBuzz 程序,我们想从 1 数到 100,所以我们可以对小于或等于 100 的数字进行简单的测试。因此,对于我们的数字小于或等于 100 的所有情况,我们将执行循环。因此,让我们继续围绕现有的测试块编写循环。完成后,它应该如下所示。先不要执行它,因为我们没有办法将数字从 1 增加到 100(这意味着我们会得到一个无限循环,因为我们永远不可能达到 100 并离开循环)。

#!/bin/bash

number=1

while [ $number –le 100 ]; do

if [ $(($number % 3)) -eq 0 ]; then

if [ $(($number % 5)) -eq 0 ]; then

echo "FizzBuzz"

else

echo "Fizz"

fi

else

if [ $(($number % 5)) -eq 0 ]; then

echo "Buzz"

fi

fi

done

好了,我们有了代码块,现在我们需要添加递增的数字。我们只需要在每次循环时将number的值增加 1。但是我们也想在改变数字之前执行所有的计算。我们可以通过使用已经有的算术运算和赋值运算来实现这一点。我们可以将这个代码块添加到代码底部的done语句之前:

number=$(($number +1))

一旦你做了这个改变,执行你的脚本!它将运行并给出如下输出:

Fizz

Buzz

Fizz

Fizz

Buzz

Fizz

FizzBuzz

...

这很棒,看起来它工作了,但是我们应该继续下去,为循环中的每一次旅行打印当前的值number。我们可以在 Fizz 或 Buzz 或 FizzBuzz 之前输出开始时的值,但这意味着每行都有数字。如果我们能把它整合到我们的echo声明中就更好了。为此,我们只需在要打印的文本字符串中添加$number变量。您之前已经了解到,引号意味着所有内容都被视为一个文本字符串,但是有一个标记可以取代它:符号操作符$。当您想要从文本块中的变量打印出数据时,这个操作符可以使您的工作变得更容易。

我们还应该添加一个最终的else语句,它将负责所有“其他”数字的输出。试着自己解决这个问题;然后对照以下代码进行检查:

#!/bin/bash

number=1

while [ $number -le 100 ]; do

if [ $(($number % 3)) -eq 0 ]; then

if [ $(($number % 5)) -eq 0 ]; then

echo "$number - FizzBuzz"

else

echo "$number - Fizz"

fi

else

if [ $(($number % 5)) -eq 0 ]; then

echo "$number - Buzz"

else

echo $number

fi

fi

number=$(($number +1))

done

这就是了!可行的 FizzBuzz 解决方案。恭喜你!

解决纷争

你的代码有问题可能有点像噩梦。也许您可以使用的最好的工具是echo命令。您可以输出任何您想要的东西,所以如果您不确定您的应用程序在代码中的位置,编写一个echo来输出内容,然后检查。是不是没有正确进入循环?输出进入测试的变量并手动比较。不确定为什么if声明不起作用?添加一个else,输出完整的测试用例,看看你进去的是否正确。使用这些输出来跟踪您在代码中的位置是进行诊断的最佳方式。否则,注意任何错误;大多数应该提供一个行号,并告诉你(在某种程度上)哪一行有什么问题。如果你有疑问,请随意搜索,因为几乎可以肯定的是,在你之前,某个地方的某个人也犯过同样的错误,并寻求解决方案。

实用 BASH:一个 Init 脚本

您现在应该知道,大多数 Linux 应用程序都是由一个叫做init脚本的特殊脚本启动的。这些脚本并不神奇;它们只是 BASH 中的脚本,接受给定的值,并根据命令执行一系列动作——就像任何好的程序一样。init脚本中确实有少量特殊信息,但这些实际上都不是程序逻辑。

让我们一起浏览一遍,并检查这些init脚本中的一个是如何工作的。以下是XBMCinit脚本,你将在本书后面再次看到:

#! /bin/bash

### BEGIN INIT INFO

# Provides:          xbmc

# Required-Start:    $all

# Required-Stop:     $all

# Default-Start:     2 3 4 5

# Default-Stop:      0 1 6

# Short-Description: Start XBMC

# Description:       Start XBMC

### END INIT INFO

DAEMON=/usr/bin/xinit

DAEMON_OPTS="/usr/lib/xbmc/xbmc.bin"

NAME=xbmc

DESC=XBMC

RUN_AS=root

PID_FILE=/var/run/xbmc.pid

test -x $DAEMON || exit 0

set -e

case "$1" in

start)

echo "Starting $DESC"

start-stop-daemon ˗˗start -c $RUN_AS ˗˗background ˗˗pidfile $PID_FILE ˗˗make-pidfile ˗˗exec $DAEMON ˗˗ $DAEMON_OPTS

;;

stop)

echo "Stopping $DESC"

start-stop-daemon ˗˗stop ˗˗pidfile $PID_FILE

;;

restart|force-reload)

echo "Restarting $DESC"

start-stop-daemon ˗˗stop ˗˗pidfile $PID_FILE

sleep 5

start-stop-daemon ˗˗start -c $RUN_AS ˗˗background ˗˗pidfile $PID_FILE ˗˗make-pidfile ˗˗exec $DAEMON ˗˗ $DAEMON_OPTS

;;

*)

echo "Usage: /etc/init.d/$NAME{start|stop|restart|force-reload}" >&2

exit 1

;;

esac

exit 0

您会注意到的第一件事是有许多行是以#开头的。这几行是注释;因为#是 BASH 中的注释符号,所以任何以#开头的行都不会作为应用程序的一部分执行。事实上,INIT INFO的开头几行对于一个init剧本来说非常重要。这些是特殊的注释,可以被处理以显示由脚本控制的应用程序是如何运行的。这些积木看起来像这样:

### BEGIN INIT INFO

# Provides:          xbmc

# Required-Start:    $all

# Required-Stop:     $all

# Default-Start:     2 3 4 5

# Default-Stop:      0 1 6

# Short-Description: Start XBMC

# Description:       Start XBMC

### END INIT INFO

这些块提供了一些描述,并说明它们为哪个应用提供了功能;在这种情况下,提供的应用是XBMC。他们还提到在这个应用程序可以启动或停止之前需要运行什么应用程序。$all符号表示该应用程序将最后启动,这样可以保证它所依赖的所有其他应用程序都在它之前启动。可能更重要的一组操作符是Default-StartDefault-Stop。这些操作符与 Linux 系统的运行级别相关联,管理 Linux 系统引导过程的各个阶段。

Linux 规范定义了以下运行级别:

  • 0 级:Halt 关机和断电
  • 级别 1:单用户模式;仅基本系统功能(用于维修)
  • 级别 2 % 3:多用户;添加网络和多用户功能
  • 级别 4:用户定义
  • 5 级:正常系统运行状态
  • 第 6 级:重启

启动和停止开关旁边的数字与这些级别相关,因此XBMC将在运行级别 2-5 启动,并在级别 0、1 和 6 关闭。

选择并搭配案例陈述

一旦所有初始化完成,脚本设置了一些初始变量,它执行一些快速测试,然后继续执行case语句。一条case语句非常类似于针对同一个变量的一系列运行的if语句。只要你有一个给定的变量,对于这个变量的一系列给定值中的每一个,你就执行了一个函数。在大多数init脚本中,这用于确认它要执行哪个动作。

这个start脚本中的case语句正在处理特殊的$1变量。此变量表示从命令行传递给脚本的第一件事;因此,当尝试启动xbmc应用程序时,您将执行以下命令:

/etc/init.d/xbmc start

这给了$1变量start的值。case语句为case语句的潜在价值提供了许多不同的选项:

  • start:不言自明。
  • stop:不言自明。
  • restart|force-reload:restartforce-reload的值,在一个过程中执行停止申请,然后执行启动申请。它们之间的管道(|)用于表示 OR 操作,这意味着如果这里的任何一个值匹配,我们就认为这是一个匹配。
  • 还有别的吗?

在每个case值之后,有一小段在这种情况下执行的代码,后面跟着一对分号。这些分号就像一个fi,用来表示一个case语句代码块的结束。

应用程序中的应用程序:分叉

一旦进入case语句,您可以看到每一行都将使用start-stop-daemon执行一些操作。但这不是一个变量或任何特殊的东西;这是另一个程序。BASH 最强大的部分是我们还没有接触到的部分。BASH 能够通过使用程序名在程序中执行任何命令行过程。因为 BASH 是我们在其余大部分时间使用的 shell,所以这实际上很有意义。

一个init脚本的最后一个功能:它将使用start-stop-daemon为您创建一个新的进程。这个动作被称为分叉,因为你正在从当前运行的应用程序中分叉一些东西。start-stop-daemon是一个小应用程序,用于派生进程并为你管理它们的运行。start脚本收集它的参数,计算出需要执行什么动作,然后告诉start-stop-daemon需要对哪个应用程序采取什么动作。

现在您已经掌握了这些知识,您应该能够编写自己的简单的init脚本来启动和停止任何您想要的进程,方法是提供开始注释块来描述脚本应该如何加载,使用case语句来确定要采取的操作,最后执行start-stop-daemon进程来启动和管理您的应用程序!

更新运行文件

现在,您已经准备好了一个完整的工作脚本。你需要使用chmod在你的文件上设置可执行标志,然后你可以用startstop命令测试它。它确实如预期的那样——太棒了!现在我们需要将它添加到系统的引导逻辑中。从历史上看,这涉及到以一种特殊的方式将文件链接到不同的运行级别。然而,有了update-rc.d应用程序,这变得容易多了。update-rc.d应用程序利用了我们添加到 BASH 脚本中的特殊注释头,以便知道哪个运行级别应该有哪个快捷方式。

要将init脚本添加到引导序列中,我们需要做的就是发出带有我们想要的init脚本名称的update-rc.d命令,在本例中是xbmc。然后我们需要添加参数,说明我们应该使用脚本中注释的默认值;这个论点不出所料defaults。这给了我们命令update-rc.d xbmc defaults,它需要以 root 用户身份执行。运行时,输出应该如下所示:

$ sudo update-rc.d xbmc defaults

update-rc.d: using dependency based boot sequencing

仅此而已;如果您重新启动,您的应用程序应该在启动时运行!

创建您自己的初始化脚本

我们已经讲述了如何创建init脚本;现在我们可以创建一个。这个过程相对简单,因为我们只需要重新创建结构,并在正确的位置输入我们自己的代码来执行我们需要的功能。你可以让这些init脚本做任何你想做的事情,但是对于这个例子,我将用touch命令创建一个文件,然后在完成后用rm删除它。touch命令用于在磁盘上创建一个空文件;如果它在现有文件上运行,它将更改文件的上次修改时间。如前所述,你可以让你的程序由start-stop-daemon管理,或者你可以简单地执行系统功能,就像我在我的例子中将要做的那样。

正如您所记得的,我们在这个脚本中首先需要的是 shebang,它是所有 BASH 脚本的起点,因此也是最好的起点。

#! /bin/bash

现在我们有了自己的脚本,回想一下我们之前使用的XBMC start 脚本:该脚本中的第一件事是开始注释块,它为我们提供了关于哪些init级别将运行该脚本的细节,等等。所以接下来让我们补充一下。你应该在这里填写你自己的所有细节。我的脚本将被称为touchfile.sh,并将提供触摸文件服务。我的脚本的开始部分将如下所示:

### BEGIN INIT INFO

# Provides:          touchfile

# Required-Start:    $all

# Required-Stop:     $all

# Default-Start:     2 3 4 5

# Default-Stop:      0 1 6

# Short-Description: Run TouchFile

# Description:       Run TouchFile

### END INIT INFO

现在我已经定义了注释块,我可以定义我的变量了。它们将是覆盖我的应用程序的变量。任何你能想到的启动它所需要的可以配置的东西都应该被定义为一个变量。在我的touchfile命令中,我需要定义为变量的东西是我的touchfile的文件名。请记住,这是您的代码,因此您可以将您想要的任何内容定义为变量。我的变量是这个:

TOUCHFILE="/var/tmp/touch.file"

既然已经定义了我的touchfile,我需要添加case语句来覆盖可用的动作。在这种情况下,我希望有以下操作:

  • Start:触摸文件
  • Stop:删除被触摸的文件
  • Restart:移除然后重新触摸文件
  • Reload:触摸文件
  • 告诉人们如何使用这个文件

这意味着我的案例中有四个case陈述。我将把case语句(执行动作的 sans 代码)定义如下:

case "$1" in

start)

;;

stop)

;;

restart)

;;

reload)

;;

*)

;;

esac

exit 0

现在我们已经有了case条目,我们只需要让它们做一些事情。我之前提到了在每种情况下我想要做的事情,所以让我们把命令写到每个块中,并把它们组合到我们已经有的脚本中。这将为我们提供以下脚本:

#!/bin/bash

### BEGIN INIT INFO

# Provides:          touchfile

# Required-Start:    $all

# Required-Stop:     $all

# Default-Start:     2 3 4 5

# Default-Stop:      0 1 6

# Short-Description: Run TouchFile

# Description:       Run TouchFile

### END INIT INFO

TOUCHFILE="/var/tmp/touch.file"

case "$1" in

start)

echo "Creating $TOUCHFILE"

touch $TOUCHFILE

;;

stop)

echo "Removing $TOUCHFILE"

rm $TOUCHFILE

;;

restart)

echo "Recreating $TOUCHFILE"

rm $TOUCHFILE

touch $TOUCHFILE

;;

reload)

echo "Re-Touching $TOUCHFILE"

touch $TOUCHFILE

;;

*)

echo " Usage: touchfile.sh <start|stop|restart|reload>"

;;

esac

exit 0

就这样。代码是一个简单的init脚本,它接受startstoprestartreload命令,输出它正在做的事情,并根据我们提供的参数执行动作。这可以放在/etc/init.d中,并且可以用chmod +x设置为可执行。一旦完成,您就可以测试脚本以确保它能够工作。最后,您可以像我们之前所做的那样,使用update-rc.d将它添加到您的系统引导过程中。通过这种方式,您可以编写自己的启动脚本来运行您设计的应用程序。

安全性和用户管理

安全性是系统管理中最容易被忽视的领域之一。因为它被许多人认为是一种黑色艺术,所以经常被忽视。

拉斯比安的安全规则

有一些非常简单的方法可以让你的系统安全;只要遵循几条规则:

  • 不要以 root 用户身份登录,但如果必须登录,请在登录后注销。
  • 对于管理任务,尽可能使用sudo
  • 选择一个重要的密码——一个足够长且足够复杂的密码,如果不花很长时间,它是不容易被猜到或用手算出的。
  • 定期更改您的密码。
  • 定期查看您的系统日志,特别是/var/log/auth.log,因为它列出了您系统的所有用户认证。
  • 如果您不需要运行应用程序,就不要运行它。
  • 尽可能少地将您的系统暴露在互联网上。
  • 尽可能限制文件权限。

这些规则中的大部分看起来像是常识,因为它们确实如此。然而,大多数人似乎陷入了认为他们不会受到攻击的陷阱,并忽视了大多数建议。现在你知道了这些规则,你可能会说,“只要你告诉我怎么做,我就会改变我的密码!”从 Linux 命令行更改密码相对容易:您只需使用passwd命令,系统会提示您输入新密码(两次,这样您就不会在第一次不小心拼错了)。

您还可以作为 root 用户更改其他用户的密码。为此,只需将您要更改的用户名作为命令的第一个参数。这在配置新用户详细信息或重置密码时非常有用。

添加新用户

因为您不应该一直使用 root,所以能够创建新用户并理解用户创建是如何发生的非常重要。在 Linux 操作系统中,用户由文件/etc/passwd管理。您可以自己看一下,您会看到类似这样的几行:

root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/bin/sh

这些行显示用户,X 表示密码,用户的 ID 号,用户的组 ID 号,用户的组标识符,用户主目录的路径,以及用户的 shell。这些是用户在 Linux 环境中工作所需要的基础知识。

虽然该文件有一个密码字段,但它不再被使用,通常包含一个占位符(在本例中为X)。密码存储在影子文件/etc/shadow中。影子文件被分离,以便只有 root 用户可以访问密码数据,所有更常见的用户数据都可以被其他更通用的系统应用程序读取。

现在您已经了解了 Linux 是如何存储用户的,添加一个名为raspberry的新用户。要添加这个用户,我们将使用useradd命令和一些参数。还有另一个命令adduser,它执行用户添加,但是它不会提供参数,而是提示您输入细节。当你忘记了useradd的一个必要参数时,这个命令非常有用。

首先我们想要指定用户的主目录,这是通过–d标志和我们想要使用的目录的完整路径来完成的。大部分用户的主目录都是/home/<username>,树莓我们也会这么做。目前,/home/raspberry还不存在,但是在你冲出去添加它之前,我们可以用–m标志告诉useradd帮我们添加!这给了我们这个命令:

$ sudo useradd –d /home/raspberry –m raspberry

我们可以更进一步,甚至用–g <groupname>指定组,为用户设置主要组。或者甚至用–s <shell path>指定用户将使用的 shell,或者最后用–p <password>指定密码。一旦您执行了您的命令,您就可以去检查对/etc/passwd的更改,在您的文件底部您应该会看到类似这样的内容:

raspberry:x:1001:1001::/home/raspberry:/bin/sh

就是这样;您现在已经成功添加了一个新用户!如果您没有指定密码,您可以使用我们前面提到的passwd命令来更改您的新用户的密码,然后您就可以开始了。然而,假设您忘记了用–s设置 shell 路径,并且您想改变它,所以您从/bin/bash而不是/bin/sh开始。嗯,首先你可以编辑passwd文件来改变 Shell,或者你可以使用usermod命令。usermod命令的功能与useradd命令完全相同,包括参数;它只是调整数值。因此,运行以下命令:

$ sudo usermod -s /bin/bash raspberry

我们可以预期影子文件将被更改,是的,它是:

raspberry:x:1001:1001::/home/raspberry:/bin/bash

太棒了!有了这些工具,您应该能够创建新的用户帐户来允许人们访问您的 Pi。

摘要

这一章涵盖了相当多的内容。我们介绍了 SSH、DHCP 和 DNS。我们讲述了这些系统如何工作以及守护进程如何通过init脚本启动的一些基础知识。然后我们深入学习 BASH,这样我们就可以编写我们自己的init脚本。最后,我们讨论了一些常见的安全注意事项;然后继续讲述 Linux 系统如何管理用户及其密码的基础知识。我们甚至创建了一个全新的用户供使用。

这些技能应该使您能够管理您的 Pi 的启动和联网,并且应该已经向您介绍了软件开发的奇妙世界!

八、一盏你自己的灯

很多来到 Linux 的人都想知道的一个关键问题是,如何通过建立一个自己的小网站来建立自己。许多人很难找到开始的地方。哪些操作系统、哪些应用程序、哪些硬件,以及具体如何做到这一切?所有这些都是合理的问题,因为更大的 Linux 环境有如此多的方面,以至于很容易迷失。

我们的目标是为您提供能够在 Linux 环境中导航的第一批垫脚石。这条道路上的一个关键步骤是向您展示如何安装、配置和维护 web 服务器。虽然您可以将这个服务器连接到 Internet,但是在这些例子中,我们将只介绍如何将您的 Pi 用作本地网络服务器(换句话说,用于运行内部网)。此外,还有一个额外的挑战就是学习如何制作一个基本的交互式网站。虽然这可能看起来很难接受,并且其他人花费了整本书和生活来寻找这个问题的绝对最优的解决方案,我们的目标是在一章中涵盖它。

为此,我们将使用一盏灯。不,不是那些卧室发光设备中的一个,而是一个 Linux,Apache,MySQL 和 PHP 系统,旨在使传递网络内容变得容易。这是创建您自己的 web 服务器的最简单的方法之一,在最初的 LAMP 上有许多变体,包括但不限于以下内容:

  • WAMP (Windows、Apache、MySQL、PHP)
  • MAMP (Mac OS、Apache、MySQL、PHP)
  • 用 Python 或 Perl 替换 Ps
  • 用 MariaDB 替换 M

因此,从人们所做的大量混合、匹配和改进中可以看出,这是一个让强大的 web 服务器运行起来的好方法。最重要的是,它设置简单,可以在任何硬件上运行。

Pi 最常被引用的潜在用途之一是支持构建、运行和维护网站的能力。还有什么比教他们如何用最小的成本制作自己的网站更能激励一代年轻开发者的呢!

第一步

现在是时候面对现实了,我们可以在这里完成什么。在这一章中,我们将向你提供建立一个完整的网站堆栈的技巧,并向你展示如何使用 PHP 将 MySQL 数据库的功能集成到一个网站中,以动态生成网站内容。然而,有几件事我们不能在这里为你做:

  • 设置和配置 DNS 或域名
  • 高级 SQL 和数据库管理
  • HTML 和 HTML 开发方法的全面覆盖
  • 全面覆盖 PHP 开发和 PHP 开发方法
  • Java Script 语言
  • 半铸钢ˌ钢性铸铁(Cast Semi-Steel)

你可以利用许多资源来获得这些其他领域的帮助,包括其他重要的文章。我们还有工作要做,所以让我们开始吧。

l 代表 Linux

设置灯组只有几个先决条件。你需要

  • 安装并配置 Raspbian 操作系统(LAMP 的 L)
  • 将内存分割设置为 240/16(运行sudo raspi-config)
  • 熟悉使用命令行在 Raspbian 操作系统中工作
  • 对如何编写简单的软件有一个基本的了解
  • 让您的 Pi 连接到网络和互联网(否则我们如何提供内容?)

树莓灯只有几个其他的附带条件。我们将在 shell 中完成所有这些工作。鉴于网站将从 Pi 之外被查看,没有必要使用任何额外的资源来运行 GUI。既然我们知道我们需要做什么,那就开始吧。

a 代表阿帕奇

可能任何 web 服务器最重要的部分就是 web 服务器应用程序。web 服务器是一个应用程序,它接受对网站的请求,然后返回所请求的网页内容。大多数 web 服务器还可以提供大量其他功能,这些功能有助于增强它们向最终用户提供 web 内容的能力。对于我们的 LAMP 堆栈,我们将使用 Apache web 服务器。

许多人认为 Apache 是世界上首屈一指的 web 服务器。它于 1995 年首次发布,并因向大众提供简单、强大、免费的 Web 服务器而在万维网的发展中发挥了作用而闻名。

作为这一事实的佐证,据估计,Apache 提供了世界上大约 54%到 58%的网站。

关于 Apache 的命名有两个故事:

  • 第一个原因是,多年前首次开发时,它被命名为“一个拼凑的 web 服务器”。
  • 第二个(从讲故事的角度来看更好)是,据说阿帕奇是以美国的阿帕奇部落命名的。

以一个部落命名并不是用词不当,因为表现得像一个部落是 Apache 的关键特性之一。Apache 启动时的第一个任务是创建自己的“工人”小部落,负责网站内容的实际服务。既然您对 Apache 有了更清晰的理解,那么第一步就是安装、启动并运行 Apache。

对于我们的安装,我们将(一如既往地)依赖始终如一的apt-get工具:

$ sudo apt-get install apache2

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

apache2-mpm-worker apache2-utils apache2.2-bin apache2.2-common libapr1

libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap ssl-cert

Suggested packages:

apache2-doc apache2-suexec apache2-suexec-custom openssl-blacklist

The following NEW packages will be installed:

apache2 apache2-mpm-worker apache2-utils apache2.2-bin apache2.2-common

libapr1 libaprutil1 libaprutil1-dbd-sqlite3 libaprutil1-ldap ssl-cert

0 upgraded, 10 newly installed, 0 to remove and 71 not upgraded.

Need to get 1,348 kB of archives.

After this operation, 4,990 kB of additional disk space will be used.

Do you want to continue [Y/n]?

现在您已经安装了 Apache,我们应该去验证它是否已经启动并运行。有几种方法可以做到这一点。首先,运行以下命令:

$ ps -ef | grep apache

root      2306     1  0 Sep17 ?        00:00:09 /usr/sbin/apache2 -k start

www-data  2309  2306  0 Sep17 ?        00:00:00 /usr/sbin/apache2 -k start

www-data  2311  2306  0 Sep17 ?        00:00:00 /usr/sbin/apache2 -k start

www-data  2315  2306  0 Sep17 ?        00:00:00 /usr/sbin/apache2 -k start

从这个输出中,您可以看到 Apache 确实已经启动并运行了。从这一点来看,还有几件重要的事情需要注意。下面一行列出的第一个过程不同于其他过程:

root 2306 1 0 Sep17 ? 00:00:09 /usr/sbin/apache2 -k start

这就是前面提到的阿帕奇部落的酋长。它归 root 所有(如第一列所示),其进程 ID (PID)是 2306。另外三个由名为www-data的用户拥有,这是一个专门针对 Apache 的用户。虽然每个工作进程都有不同的 PID,但是它们都有一个 PPID(父进程 ID)2306,这意味着 Apache 主进程创建了它们(其 PID 是 2306)。

现在是第二个更有趣的测试。在这个测试中,我们实际上会让 Apache 显示它的默认起始网页!为此,您可以登录 GUI 或者使用ifconfig获取系统的 IP 地址。您的输出应该如下所示,并突出显示相关的 IP 地址:

$ ifconfig

eth0      Link encap:Ethernet  HWaddr b8:27:eb:8a:46:ba

inet addr:``10.0.0.20

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:213812 errors:0 dropped:0 overruns:0 frame:0

TX packets:5119 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:19226371 (18.3 MiB)  TX bytes:495394 (483.7 KiB)

lo        Link encap:Local Loopback

inet addr:``127.0.0.1

UP LOOPBACK RUNNING  MTU:16436  Metric:1

RX packets:8 errors:0 dropped:0 overruns:0 frame:0

TX packets:8 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:0

RX bytes:1104 (1.0 KiB)  TX bytes:1104 (1.0 KiB)

假设您的系统(像我的一样)连接到网络,您可以使用第一个 IP 地址(10.0.0.20)。eth0块中的地址代表其网络端口。lo块中的地址为环回地址,用于内部自参考,始终为 127.0.0.1。

下一个测试是访问 Apache 默认网页;为此,您只需在浏览器中输入这些 IP 地址中的一个(当然,假设您与 Pi 在同一个网络上!).如果您想使用 Pi 的板载浏览器进行测试,那也完全没问题,您可以选择任何一个地址(10.0.0.20 或 127.0.0.1)。你还在等什么?打开浏览器窗口,查看默认网页,如图 8-1 所示。

A978-1-4842-1162-5_8_Fig1_HTML.jpg

图 8-1。

It works!

正如你现在应该知道的,它起作用了!这是 Apache web 服务器的默认网页,因为它表明还没有添加任何内容,我们将在后面介绍。现在,让我们看看这个缺省页面是如何生成的,因为这将让您对 Apache 的真正工作原理有所了解。

Apache 配置

坦率地说,了解 Apache 配置有点像一场噩梦。如果你感兴趣,就去看看/etc/apache2中的内容,了解我的意思。这里有许多具有不同含义的文件夹,这些文件夹之间的相互关系会改变 Apache 服务器实例的工作方式。谢天谢地,一旦你明白你需要在哪里做出改变,一切都变得容易多了。

Apache 配置中第一个值得注意的文件是apache2.conf文件。这是一个控制配置文件,它说明了其他各个部分的位置,以及应用程序应该如何加载它们。第二件要注意的事情是mods-availablemods-enabled文件夹。如果你看一下mods-available文件,你会发现有大量的.load.conf文件。这些文件分别表示 Apache 应该从哪里加载一个模块以及这个模块需要的任何配置信息。

接下来是mods-enabled,最初看这个文件夹会让它看起来就像mods-available。然而,如果你在这个目录上运行一个ls –l,你会看到这个:

$ ls -l /etc/apache2/mods-enabled/

total 0

lrwxrwxrwx 1 root root 28 Sep 17 21:44 alias.conf -> ../mods-available/alias.conf

lrwxrwxrwx 1 root root 28 Sep 17 21:44 alias.load -> ../mods-available/alias.load

lrwxrwxrwx 1 root root 33 Sep 17 21:44 auth_basic.load -> ../mods-available/auth_basic.load

lrwxrwxrwx 1 root root 33 Sep 17 21:44 authn_file.load -> ../mods-available/authn_file.load

...

这表明,实际上,mods-enabled中的每个文件实际上都是指向mods-available中的一个文件的链接!这是 Apache 配置的第一个复杂性,尽管在任何给定的时间都有许多可用的模块,但实际上只有一定数量的模块被加载。像这样使用符号链接意味着在给定时间只需要保存和维护配置的一个副本。更重要的是,对其中一个的任何更改都会影响到两个。

如果你查看sites-availablesites-enabled文件夹,你会看到相同的布局,除了可能有更少的站点。这将我们带到我们搜索的真正目标:Apache 系统中第一个可用的默认站点。所以要么开/etc/apache2/sites-available/default要么开/etc/apache2/sites-enabled/000-default,因为无所谓;他们是一回事!所以,现在你在里面了,回顾一下配置中的每一个东西的含义。如果你想添加额外的网站或者修改网站的显示方式,其中的许多对你来说是很重要的。

<VirtualHost *:80>

ServerAdmin webmaster@localhost

DocumentRoot /var/www

<Directory />

Options FollowSymLinks

AllowOverride None

</Directory>

<Directory /var/www/>

Options Indexes FollowSymLinks MultiViews

AllowOverride None

Order allow,deny

allow from all

</Directory>

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/

<Directory "/usr/lib/cgi-bin">

AllowOverride None

Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch

Order allow,deny

Allow from all

</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log

# Possible values include: debug, info, notice, warn, error, crit,

# alert, emerg.

LogLevel warn

CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

第一行可能是最重要的一行;它指定该 web 服务器可用于端口 80 上的任何传入地址。更改这意味着您可以在同一个站点上运行多个 web 服务器,方法是使用不同的端口来引用每个服务器。

Note

通过在 URL 末尾添加:<port number>,您可以在连接到几乎任何应用程序时指定一个端口。

VirtualHost地址之后,下一个相关的东西是DocumentRoot。这很关键,因为它说明了 Apache 将从哪里加载所有 web 服务器内容。这意味着任何在/var/www文件夹中的东西都可以通过基本网站的 80 端口获得。例如,如果你进入/var/www文件夹,你会看到一个文件:index.html。如果您检查这个文件,您会看到一些非常熟悉的内容:

<html><body><h1>It works!</h1>

<p>This is the default web page for this server.</p>

<p>The web server software is running but no content has been added, yet.</p>

</body></html>

是的,这就是用来生成 Apache 当前显示的基本起始页的网站内容。我试着这样想:web 服务器为您提供对该文件夹(及其所有子文件夹和文档)的访问。为了证明这一点,请尝试以 root 用户身份执行以下命令:

$ echo "Hello World" > /var/www/foo

Note

执行sudo su –可以获得 root。

一旦你成功执行了这个命令,将你的浏览器指向http://<IP Address>/foo,你应该会看到hello world显示在那里。你可能想知道为什么我们不需要在对我们网站的第一个请求中使用index.html(即使用 http://10.0.0.2/index.html )。这是因为名为“index”的文件比较特殊。如果没有其他内容可用,则它们是显示的默认页面。

您应该知道的配置的下一部分是Directory配置部分。这些是目录列表,可以提供关于如何访问它们甚至谁可以访问它们的特殊规则。在这个实例中,Apache 对两个目录进行了配置设置:根目录//var/www。虽然您可以对目录值做许多非常有趣的事情,但是在这里我们不需要做太多。要了解更多信息,您应该访问 Apache 网站,通读那里提供的更详细的文档。

在目录细节之后是ScriptAlias,它控制应用程序如何访问 CGI 脚本。ScriptAlias是一个特殊的目录,这些 CGI 程序在其中运行和执行。由于 PHP 是一个很像 BASH 的脚本系统(在第七章的中讨论过),你可能认为这有直接的关系,但事实并非如此。PHP 由一个特殊的解释模块(modphp)运行,而不是由一个单独的 CGI 程序运行。

ScriptAlias下面的目录值与之相关。最容易泄露是这两个引用/usr/lib/cgi-bin/。这个目录包含了+ExecCGI指令。同样,这与脚本和 PHP 之类的东西是如何执行的有关。最后,配置文件以几个非常有用的配置行结束。这些值是 Apache 服务器的日志文件指令;它们说明了日志文件将放在哪里,以及它们将写入哪些文件。这里包括了访问日志(这样你就可以监控每个访问你的人)和更多的标准错误日志。中间的LogLevel指令决定了关于服务器运行的日志应该在哪个级别输出,现在它被设置在WARN,这是合理的。

考虑到您以后在使用 PHP 时可能需要利用这些日志,您现在应该熟悉它们了。但是,首先让我们对 Apache 将包含的日志做一个小小的更改。让我们将日志级别更改为 notice,继续进行更改,然后保存新编辑的文件。一旦文件被更改,我们需要告诉 Apache 这一点,这样它将重新加载配置。与对您的网站进行内容更改不同,我们需要将配置更改通知 Apache。幸运的是,Apache 通过包含一个我们可以向它发出的重载函数使这变得容易了。继续发出这个:

$ sudo /etc/init.d/apache2 reload

[....] Reloading web server config: apache2apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1 for ServerName

. ok

这告诉 Apache 重新加载它的配置并再次运行。现在看看日志文件,看看我们所做的更改。Apache 日志目录是/var/log/apache2,我们感兴趣的文件是error.log。一旦你往里面看,你应该会看到这样的东西:

[Tue Sep 18 22:46:56 2012] [notice] SIGUSR1 received.  Doing graceful restart

apache2: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1 for ServerName

[Tue Sep 18 22:46:56 2012] [notice] Apache/2.2.22 (Debian) configured ˗˗ resuming normal operations

这表示我的 Apache 实例收到了一个信号,它执行了一次优雅的重启;然后,它在同一秒钟内恢复正常运行。这是我们刚才执行的配置重新加载。我们还可以查看访问日志,看到我们自己正在访问 web 服务器上的内容,然后打开/var/log/apache2中的access.log文件进行查看。您应该会看到类似这样的内容:

10.0.0.104 - - [18/Sep/2012:20:31:17 +1000] "GET / HTTP/1.1" 200 482 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.10 (KHTML, like Gecko) Chrome/23.0.1262.0 Safari/537.10"

10.0.0.104 - - [18/Sep/2012:22:21:22 +1000] "GET /favicon.ico HTTP/1.1" 404 498 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.10 (KHTML, like Gecko) Chrome/23.0.1262.0 Safari/537.10"

10.0.0.104 - - [18/Sep/2012:22:28:36 +1000] "GET /foo HTTP/1.1" 200 274 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.10 (KHTML, like Gecko) Chrome/23.0.1262.0 Safari/537.10"

这几行显示 IP 10.0.0.104 上有人在 web 服务器的/上发出了一个GET请求,这个请求是/var/www文件夹和其中的index.html文件(因为 index 是默认文件)。它还显示有人正在访问这个目录中的 foo 文件。他们都是我按顺序访问网站。您还会注意到,在中间有一个请求,是对一个favicon.ico的请求。这表示我的浏览器试图请求该网站的收藏夹图标;不幸的是,没有。

解决纷争

在很大程度上,设置 Apache 服务器是轻而易举的事情。只有当你开始做很多改变时,你可能会遇到麻烦。但是,如果您发现自己遇到了问题,请尝试以下方法。检查您是否可以看到 Apache 进程使用ps –ef运行。如果 Apache 没有运行,请尝试启动它。如果失败,请尝试检查错误日志文件,因为它将包含 Apache 遇到的任何错误的信息。错误日志中的大多数条目都是不言自明的。然而,如果你发现自己不知所措,那就去 Apache 网站,那里有大量的帮助可以提供给那些有需要的人。

m 代表 MySQL

现在你已经建立并运行了你的 web 服务器,你可能会问,“我发现你可以通过把内容写入 web 服务器来创建一个网站,然后它就会显示出来。我可能还需要什么软件?”这是真的。现在,你可以用基本的超文本标记语言(HTML)写一个网页,然后就完事了。单独用 HTML 编写的问题是 HTML 是静态的,这意味着任何时候你想改变显示的内容,你都需要打开并编辑文件来改变内容。当你想向不同的人展示不同的东西时,这不是很好的管理。你需要手动坐在那里编辑一大堆东西——这毫无意义。

这是我们开始看到整个灯堆的力量。我们有 Apache 来提供内容,PHP 将处理动态部分,MySQL 数据库实际上将包含您想要显示的各种不同的信息。只有当你拥有所有这些组件并一起工作时,你才能看到灯具系统的真正力量。

安装 MySQL

数据库是一个便于存储和检索数据的系统。它们接受大量的输入,然后对数据进行结构化,以便可以通过查询轻松检索信息。所有 SQL 数据库都是以结构化查询语言命名的,它们使用结构化查询语言来处理信息检索请求。MySQL 是世界上部署最广泛的开源数据库。这就是所谓的关系数据库系统,因为它易于建立和使用,因此被广泛采用。为了安装 MySQL,我们将再次求助于我们的老朋友apt-get;这一次,我们将安装mysql-server包。执行以下操作:

$ sudo apt-get install mysql-server

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

heirloom-mailx libaio1 libdbd-mysql-perl libdbi-perl libhtml-template-perl

libmysqlclient16 libnet-daemon-perl libplrpc-perl mysql-client-5.5

mysql-common mysql-server-5.5 mysql-server-core-5.5

Suggested packages:

libipc-sharedcache-perl libterm-readkey-perl tinyca

The following NEW packages will be installed:

heirloom-mailx libaio1 libdbd-mysql-perl libdbi-perl libhtml-template-perl

libmysqlclient16 libnet-daemon-perl libplrpc-perl mysql-client-5.5

mysql-common mysql-server mysql-server-5.5 mysql-server-core-5.5

0 upgraded, 13 newly installed, 0 to remove and 84 not upgraded.

Need to get 9,770 kB of archives.

After this operation, 91.5 MB of additional disk space will be used.

Do you want to continue [Y/n]?

一旦实际的 MySQL 安装完成,您将被要求为您的数据库提供一个 root 密码;这是您的数据库的主管理员密码。一定要记住;你以后会需要它的。现在安装已经完成,请确认该过程已经开始,如下所示:

$ ps –ef | grep mysql

输出应该显示一些不同的东西,包括 MySQL 守护进程,这里突出显示了它:

root      5254     1  0 20:23 ?        00:00:00 /bin/sh /usr/bin/mysqld_safe

mysql     5592  5254  3 20:23 ?        00:00:03 /usr/sbin/mysqld ˗˗basedir=/usr ˗˗datadir=/var/lib/mysql ˗˗plugin-dir=/usr/lib/mysql/plugin ˗˗user=mysql ˗˗pid-file=/var/run/mysqld/mysqld.pid ˗˗socket=/var/run/mysqld/mysqld.sock ˗˗port=3306

root      5593  5254  0 20:23 ?        00:00:00 logger -t mysqld -p daemon.error

这是一个很大的进程命令,但它确实表明 MySQL 已经启动并运行了。我们可以查看 MySQL 的配置,但幸运的是,该系统将满足我们所有的基本需求,不需要修改配置。鉴于此,让我们开始研究一些插入和检索数据的基本方法。

结构化查询语言

结构化查询语言(SQL)是一种用于在 SQL 数据库中插入和检索信息的语言。在 SQL 中,您可以执行许多不同的查询,从简单到极其复杂。考虑到(和其他东西一样)许多其他资源花费了更多的时间和更多的关于语法和起源的细节,我们在这里就不讨论了。此外,出于我们的目的,我们只需要五种类型的查询:

  • 基本管理命令
  • 插入新数据
  • 查找数据
  • 更新数据
  • 删除数据

虽然这听起来非常简单,但是如果你想做一些更复杂的事情,很容易迷失在语法中。如果是这种情况,并且您希望做一些比我们在这里介绍的稍微复杂的事情,请访问 MySQL 网页,因为它们有完整的文档说明如何准确地执行每个查询,以及每个命令需要的大量选项。如果你想了解更多关于 web 开发的知识,看看 Jason W. Gilmore 的《PHP 和 MySQL 5 入门》。

反正足够的植入式广告;让我们从基本的管理工作开始,做一个数据库。这个的语法非常简单:

create database <database name>

要在 MySQL 实例上执行命令,您需要连接到它并进入mysql shell。执行此操作的命令如下:

mysql –uroot –p

因此,进入 shell,提供您的 root 密码,并执行create database pi;,这会生成以下输出:

mysql> create database pi;

Query OK, 1 row affected (0.00 sec)

好吧,太棒了。我们有一个数据库叫做pi。在 SQL 数据库系统中,数据库是最高级别的构造。下面是一个表,它是保存数据的对象(一个数据库保存多个表)。表中的每一项数据都称为一行。所以我们的下一步是创建一个表;问题是我们需要给我们的表一些结构。我们需要告诉它应该保存什么样的数据,以及我们将如何布置这些数据,这意味着我们需要一个项目。现在最明显的是一个简单的待办事项列表,所以让我们做一个。

Note

所有 MySQL 命令都以分号(;)结尾。它表示这是一个语句的结束。这样做是因为您可以将一个命令的行放在多行中,这样更容易理解。

创建表格

很快地,我稍微偏离了正常的项目计划方法,这样我们可以一起运行一个基本的数据库设置。当进行一个大项目时,最好提前做好计划,并在向数据库中添加任何数据之前很久就完全了解将会有什么内容进入数据库。

因此,对于我们的待办事项列表,我们希望为每个“待办事项”保留以下信息:

  • 描述
  • 执行任务的人(所有者)
  • 截止日期(日期)
  • 位置
  • 重要
  • 谁设置的任务(创建者)

好,有了这些信息,我们就有了粗略的表格结构;现在让我们继续创建它。创建表的语法如下:

create table <tablename> (

<column name> <column type>,

<column name> <column type>,

...

<column name> <column type>

);

这是基本的语法,但是在创建表时,我们还需要确保最后一件事:一个键。鉴于我们需要确保每次都能获得正确的价值,我们需要让每一份数据都具有独特性。除了一两个小的变化之外,这些任务中的许多可能以几乎相同的方式结束。出于这个原因,我们将需要所谓的主键,它是每一行的唯一标识符。在这种情况下,最好只使用一个简单的计数,它会随着我们添加的每一行而自动增加。现在我们知道我们想要什么;让我们把它充实到前面的语法中,看看我们有什么。

create table todolist (

idnumber <column type>,

description <column type>,

owner <column type>,

date <colunm type>,

location <column type>,

importance <column type>,

creator <column type

);

好了,看起来更好了,但是我们仍然没有那些<column types>,也没有任何东西会说我们的idnumber是主键,或者应该为每个新行自动更新。这很好地向我们介绍了列类型是什么。MySQL 将需要知道我们的每个数据元素将是什么类型的值,这样它就可以知道如何存储它们以及它们可以参与什么类型的查询。MySQL 中至少有 30 种不同的数据类型,它们可以执行各种操作,但是对于我们的简单目的来说,我们只需要关心三种:一种是称为VARCHAR的文本或文本串,并被赋予最大字符数,第二种是称为INT,的数字或整数,最后一种是称为DATE的日期值。假设我们现在知道了一些数据类型,我们可以将它们设置到我们的create table命令中。现在就开始吧,记住文本字符串(VARCHAR)需要被赋予最大长度的字符数:

create table todolist (

idnumber INT,

description VARCHAR(200),

owner VARCHAR(40),

date DATE,

location VARCHAR(40),

importance VARCHAR(10),

creator VARCHAR(40)

) ;

这看起来更好,可能会运行,但请记住,我们希望该号码是我们的唯一标识符,并自动更新,以使我们的生活更容易。idnumber自动递增(更新为+1)的语法是PRIMARY KEY NOT NULL AUTO_INCREMENT。这给了我们最后的命令:

create table todolist (

idnumber INT PRIMARY KEY NOT NULL AUTO_INCREMENT,

description VARCHAR(200),

owner VARCHAR(40),

date DATE,

location VARCHAR(40),

importance VARCHAR(10),

creator VARCHAR(40)

);

所以,继续运行它:

ERROR 1046 (3D000): No database selected

哦,哎呀。我们需要告诉 MySQL 我们正在使用哪个数据库,因此这个表将驻留在哪个数据库下。要改变我们正在使用的数据库,我们需要使用USE命令。要更改为使用 Pi 数据库,我们只需执行USE pi;,MySQL 会告诉我们数据库已经更改。如果你忘记了你的数据库名,你可以使用SHOW命令来查看东西,SHOW DATABASES;会显示你系统上的所有数据库。现在继续,再次执行表创建。这次你应该看到这个:

Query OK, 0 rows affected (0.91 sec)

太好了,我们有桌子了。我们来看看,看能不能看出来。发出SHOW命令,但这次是针对表。您应该看到下面的输出,它列出了 Pi 数据库中的所有表:

mysql> SHOW TABLES;

+˗˗˗˗˗˗˗˗˗˗˗˗˗˗+

| Tables_in_pi |

+˗˗˗˗˗˗˗˗˗˗˗˗˗˗+

| todolist     |

+˗˗˗˗˗˗˗˗˗˗˗˗˗˗+

1 row in set (0.00 sec)

雅虎!现在,比方说,你已经忘记了桌子到底是什么样子;您将希望 MySQL 描述该表是如何组成的。您可以使用DESCRIBE命令来做到这一点,所以让我们试着描述一下我们的新todolist表,这样我们就可以看到 MySQL 是如何理解它的。

mysql> DESCRIBE todolist;

+-------------+--------------+------+-----+---------+----------------+

| Field       | Type         | Null | Key | Default | Extra          |

+-------------+--------------+------+-----+---------+----------------+

| idnumber    | int(11)      | NO   | PRI | NULL    | auto_increment |

| description | varchar(200) | YES  |     | NULL    |                |

| owner       | varchar(40)  | YES  |     | NULL    |                |

| date        | date         | YES  |     | NULL    |                |

| location    | varchar(40)  | YES  |     | NULL    |                |

| importance  | varchar(10)  | YES  |     | NULL    |                |

| creator     | varchar(40)  | YES  |     | NULL    |                |

+-------------+--------------+------+-----+---------+----------------+

7 rows in set (0.00 sec)

牛逼;你甚至可以看到我们的idnumberPRI键,在末尾有自动递增!一切注册成功。我们已经成功地创建了一个数据库和一个表。我们给我们的桌子赋予了结构。现在是时候好好利用它了,但是在我们开始处理数据之前,我还想介绍最后一个管理命令:创建一个非 root 用户。这样,我们就不必经常使用根用户,这将减少潜在的安全风险。该命令(称为GRANT)的语法如下:

GRANT ALL ON <databse>.<table> TO ’<username>’@’<user location>’ IDENTIFIED BY ’<password>’;

因此,假设我们想授予系统上的默认 pi 用户使用密码 raspberry 访问 todolist 表的权限。该命令将变成这样:

GRANT ALL ON pi.todolist TO ’pi’@’localhost’ IDENTIFIED BY ’raspberry’;

运行这个命令,然后通过键入quit退出 MySQL shell。现在尝试用新的用户名和密码重新登录。记住,它的语法是:

$ mysql –u<username> -p

Note

当在 MySQL 中输入任何不是 MySQL 已经“理解”的文本数据时(例如,表名和列名),都需要引号。

插入数据

现在你作为pi用户重新登录,让我们开始学习一些将数据插入 MySQL 的实际命令。第一个命令是插入数据的命令。如果没有可用的数据,我们还能指望如何处理 MySQL 数据呢!插入数据的命令是名副其实的INSERT命令。INSERT的基本语法如下:

INSERT INTO <TABLE> (<FIELD1>, <FIELD2>, ... <FIELDX>) VALUES (’<VAL1>’, ’<VAL2>’, ... ’<VALX>’);

现在我们知道了插入应该是什么样子,让我们继续在数据库中创建一个。让我们在待办事项列表中插入一对任务。第一个将是我写的这一章。所以命令应该是这样的(确保我们输入了USE pi):

INSERT INTO todolist (description, owner, date, location, importance, creator) VALUES (’Finish LAMP Chapter’, ’David’, ’2012-09-22’, ’Australia’, ’HIGH’, ’David’);

Query OK, 1 row affected (0.43 sec)

奏效了。让我们添加另一个,只是为了更好的措施。让我们现在让彼得做点什么:

INSERT INTO todolist (description, owner, date, location, importance, creator) VALUES (’Finish GUI Chapter’, ’Peter’, ’2012-09-22’, ’Hong Kong’, ’HIGH’, ’David’);

Query OK, 1 row affected (0.48 sec)

现在我们有两张唱片可以玩了。但是我们如何确定他们是正确的呢?假设我们甚至没有将它们添加到我们的insert语句中,我们如何检查idnumber是否增加了?为此,我们需要向我们的 SQL 数据库发出一个查询!

查询数据库

与大多数其他语句不同,数据查询不是用QUERY命令完成的。这是因为我们一直在执行的所有命令都被认为是查询本身。检索数据的命令称为SELECT,其语法如下:

SELECT <Fields1>, <Field2>... <FieldX> FROM <TABLENAME> WHERE <INFORMATION QUERY>

是的,我知道语法有点奇怪,但是一旦我们把它填好,你会对它为什么是这样有更多的了解。首先,让我们把所有东西都拿走。通常,您可以输入您希望得到的字段名,这限制了传输的额外数据量,但是在这种情况下,我们可以使用特殊的通配符*。因此,为了查询我们的todolist表中的所有内容,我们将执行以下命令:

mysql> SELECT * FROM todolist;

+----------+---------------------+-------+------------+-----------+------------+---------+

| idnumber | description         | owner | date       | location  | importance | creator |

+----------+---------------------+-------+------------+-----------+------------+---------+

|        1 | Finish LAMP Chapter | David | 2012-09-22 | Australia | HIGH       | David   |

|        2 | Finish GUI Chapter  | Peter | 2012-09-22 | Hong Kong | HIGH       | David   |

+----------+---------------------+-------+------------+-----------+------------+---------+

2 rows in set (0.00 sec)

你会注意到我省略了WHERE,这已经完成了,因为我们想要的东西没有实际的限制,我们想要一切。在这之后,你可以看到我们输入的所有内容都是我们给定的格式,更重要的是 ID 号在递增!这将验证我们之前插入的所有内容。现在你已经理解了非常基本的语法,我们可以做一些稍微高级一点的查询。比方说,我想找出谁应该为分配给我(大卫)的任务负责。在这种情况下,相关的信息是创造者,因为这就是我们想要的,责备谁。这将给出查询的前半部分:

SELECT creator FROM todolist

现在,我们需要的下一部分是指定所有者必须是 David 的部分。其语法非常简单,给出了最终的查询:

SELECT creator FROM todolist WHERE owner = "David";

+---------+

| creator |

+---------+

| David   |

+---------+

1 row in set (0.00 sec)

太美了。我现在知道,这种混乱只能怪我自己。同样,让我们试试另一个。我想知道今天(在本例中是 9 月 20 日)之后到期的所有任务的描述和优先级。所以我们再次开始构建我们的查询。这次我们需要描述和重要性字段,所以它们进去了。我们还希望日期大于 2012 年 9 月 20 日。幸运的是,MySQL 理解日期数据,所以我们需要做的就是给它我们的日期和大于号,也就是>。这将为您提供以下查询:

mysql> SELECT description, importance FROM todolist WHERE date > "2012-09-20";

+---------------------+------------+

| description         | importance |

+---------------------+------------+

| Finish LAMP Chapter | HIGH       |

| Finish GUI Chapter  | HIGH       |

+---------------------+------------+

2 rows in set (0.01 sec)

一个SELECT查询的最后一个简单部分可能稍后会有关联。这是可以添加到查询末尾的ORDER BY语句。以我们的最后一个为例;假设我们希望它们按照添加的顺序排序(由idnumber)。这将使我们的疑问变成这样:

mysql> SELECT description, importance, idnumber FROM todolist WHERE date > "2012-09-20" ORDER BY idnumber;

+---------------------+------------+----------+

| description         | importance | idnumber |

+---------------------+------------+----------+

| Finish LAMP Chapter | HIGH       |        1 |

| Finish GUI Chapter  | HIGH       |        2 |

+---------------------+------------+----------+

2 rows in set (0.00 sec)

就这样,排序完毕。好的,所以我们看不到它,因为它是按升序排列的,之前也是这样显示的。为了撤销(或强制)订单,我们可以在语句的末尾添加一个ASCDESC,所以让我们使用与之前相同的查询来尝试一下,并观察变化:

mysql> SELECT description, importance, idnumber FROM todolist WHERE date > "2012-09-20" ORDER BY idnumber DESC;

+---------------------+------------+----------+

| description         | importance | idnumber |

+---------------------+------------+----------+

| Finish GUI Chapter  | HIGH       |        2 |

| Finish LAMP Chapter | HIGH       |        1 |

+---------------------+------------+----------+

2 rows in set (0.00 sec)

那更好;您现在可以看到顺序的变化了!让东西按顺序返回是很棒的,因为这意味着数据库系统正在为您进行排序——这是编程很容易做到的事情。如果我们试图编写这样的排序,可能会比数据库执行起来花费更长的时间。现在我们已经讲述了第二个基本命令,我们可以插入和检索数据。我们将研究的下一个命令是更新数据的命令。

更新数据库

现在我们已经过了使用SELECT命令进行查询的愚蠢阶段,我们又回到了使用UPDATE命令命名的领域。更新在某种程度上是插入和SELECT查询的混合,这是理所当然的,因为我们既需要找到某个东西,又需要更新那个东西。UPDATE的基本语法是这样的:

UPDATE <table name> SET <column name1> = "<value1>",<column name2> = "<value2>"... <column nameX> = "<valueX>" WHERE <Information Query>

让我们来看一个例子。比方说,我需要延长这一章的最后期限,因为我工作太努力了,想放松一晚上。这意味着我想把我的截止日期从 22 号增加到 23 号。所以我们知道我们想要更新什么,这给了我们这个命令:

UPDATE todolist SET date="2012-09-23" WHERE

现在我们只需要一个查询;我们不能选择 22 号的东西,因为有两件东西使用了那个日期;严重性和创造者也是如此。我们可以使用所有者或描述或idnumber。在这种情况下,我会选择 ID 号,因为我们已经将它设置为主键,因此是完全唯一的标识符。这使得我们的UPDATE查询变成

mysql> UPDATE todolist SET date="2012-09-23" WHERE idnumber=1;

Query OK, 1 row affected, 1 warning (0.48 sec)

Rows matched: 1  Changed: 1  Warnings: 0

你会注意到我没有在第一个数字的末尾加上引号。这是因为 MySQL 将数字视为INT不同于将数字视为VARCHAR;虽然这似乎是语义。这是一个重要的区别,因为数学运算不能针对VARCHAR,执行,但可以针对INT。MySQL 没有显示数据的实际输出;要查看它,我们需要发出另一个 select 命令,所以让我们继续检查更改:

mysql> SELECT * FROM todolist WHERE idnumber=1;

+----------+---------------------+-------+------------+-----------+------------+---------+

| idnumber | description         | owner | date       | location  | importance | creator |

+----------+---------------------+-------+------------+-----------+------------+---------+

|        1 | Finish LAMP Chapter | David | 2012-09-23 | Australia | HIGH       | David   |

+----------+---------------------+-------+------------+-----------+------------+---------+

1 row in set (0.00 sec)

这就是你要的。我刚刚给自己放了一晚上假。但正因为如此,彼得和我都必须更加努力地完成剩下的章节。这意味着我们需要将两个章节的重要性设置为最高!第一部分很简单:

UPDATE todolist SET importance="HIGHEST" WHERE

这是我们可以再次改变查询方式的地方。我们希望做所有的事情吗?并通过移除WHERE将一切设置为HIGHEST?让我们搜索HIGH,并将其设为HIGHEST,这是我们最后的查询:

mysql>  UPDATE todolist SET importance="HIGHEST" WHERE importance="HIGH";

Query OK, 2 rows affected (0.49 sec)

Rows matched: 2  Changed: 2  Warnings: 0

同样没有输出,因此我们必须再次检索数据:

mysql> SELECT * FROM todolist;

+----------+---------------------+-------+------------+-----------+------------+---------+

| idnumber | description         | owner | date       | location  | importance | creator |

+----------+---------------------+-------+------------+-----------+------------+---------+

|        1 | Finish LAMP Chapter | David | 2012-09-23 | Australia | HIGHEST    | David   |

|        2 | Finish GUI Chapter  | Peter | 2012-09-22 | Hong Kong | HIGHEST    | David   |

+----------+---------------------+-------+------------+-----------+------------+---------+

2 rows in set (0.00 sec)

我们能够将这两个HIGH值更新为HIGHEST。现在是剩下的最后一项任务:删除。

删除数据

我们希望能够删除任务,因为他们已经完成。DELETE命令的语法构造与SELECT命令几乎完全一样:

DELETE FROM <table name> WHERE <information query>;

这是最后一个例子。假设我休息一晚的原因不是我累了;因为我提前看完了这一章!呜哇!所以让我们建立删除。再次让我们通过idnumber来确定。命令应该是这样的:

mysql> DELETE FROM todolist WHERE idnumber=1;

Query OK, 1 row affected (0.42 sec)

UPDATE一样,除了简短的输出说我们删除了一行之外,没有返回任何信息。让我们再次发出一个SELECT,看看发生了什么变化:

mysql> SELECT * FROM todolist;

+----------+--------------------+-------+------------+-----------+------------+---------+

| idnumber | description        | owner | date       | location  | importance | creator |

+----------+--------------------+-------+------------+-----------+------------+---------+

|        2 | Finish GUI Chapter | Peter | 2012-09-22 | Hong Kong | HIGHEST    | David   |

+----------+--------------------+-------+------------+-----------+------------+---------+

1 row in set (0.01 sec)

只有彼得的那一章还在,他必须最努力地工作,因为它在最上面。好吧,让我们友好一点——最后一个命令。这个去掉了一张桌子;它被称为DROP命令,非常简单:

DROP TABLE <table name>;

让我们删除我们的todolist表,因为我们已经完成了这些 MySQL 示例,我们不希望它占用空间:

mysql> DROP TABLE todolist;

Query OK, 0 rows affected (0.49 sec)

好了,现在我们只剩下 pi 数据库了。如果你想删除它,你只需要在DROP命令中将世界TABLE替换为单词DATABASE。这取决于你;我们以后会重用这个。现在,让我们来看看 LAMP 堆栈的最后一部分:PHP。

p 代表 PHP

PHP 是一个允许你在网页中添加动态功能的系统。最初,所有的网页都是由 HTML 单独制作的,这不允许基于输入和动作的太多灵活性。HTML 只是显示一个静态的内容页面,需要修改以显示不同的内容。为了解决这个最初的问题,开发了公共网关接口(CGI)。这为 web 服务器接受请求提供了一种方法,允许它们返回内容。

最初,大多数 CGI 是成熟的应用程序,根据它们的输入输出不同的 HTML 片段,这些应用程序的整个部分都致力于一遍又一遍地输出大块的相同 HTML。这就是 PHP 开发的由来。PHP 被设计成一种语言,在这种语言中,人们可以将实际的动态代码片段添加到静态 HTML 中,然后很快:一个动态网页就形成了。

自从 PHP 诞生以来,它已经变得非常普及,安装量达到了 2000 万。这一成功在很大程度上是因为与原始的应用程序表单 CGIs 相比,PHP 可以轻松地用作 CGI。现在你已经了解了 PHP 是什么,让我们把它安装到树莓 Pi 上。和以往一样,我们将依靠apt-get的服务来为我们获取和安装 PHP。要运行的命令是:

$ sudo apt-get install php5

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

apache2-mpm-prefork libapache2-mod-php5 libonig2 libqdbm14 php5-cli php5-common

Suggested packages:

php-pear

The following packages will be REMOVED:

apache2-mpm-worker

The following NEW packages will be installed:

apache2-mpm-prefork libapache2-mod-php5 libonig2 libqdbm14 php5 php5-cli php5-common

0 upgraded, 7 newly installed, 1 to remove and 84 not upgraded.

Need to get 5,707 kB of archives.

After this operation, 16.3 MB of additional disk space will be used.

Do you want to continue [Y/n]?

注意,PHP 正在修改我们的 Apache 安装。这是为了将 Apache tribesman 模块替换为那些更适合使用 PHP 的模块。一旦 PHP 完成安装,我们就要继续测试它是否正常工作。我们可以编写一个简单的 PHP 页面,它将显示我们所有的安装设置,并确认 PHP 已经启动并运行。为了测试这个第一页,我们需要用一个新的index.php替换/var/www中的index.html,其中包含以下代码行:

<?php phpinfo(); ?>

一旦您删除了index.html并添加了index.php,将您的浏览器指向您的 Apache 服务器。图 8-2 将是你的奖励。

A978-1-4842-1162-5_8_Fig2_HTML.jpg

图 8-2。

PHP info page

这是 PHP 信息页面,它描述了新安装的 PHP 实例的整个当前配置。因为我们正在查看它,这也证明了 PHP 解释器工作正常。这也表明index.php已经被 Apache 选中为默认页面。我们添加的生成代码如下:

<?php phpinfo(); ?>

这是 PHP 代码的一个很好的例子;首先,我们有开始标记,显示这是 PHP,并被解释为 PHP(<?php?>关闭),我们有一个对phpinfo();的函数调用,显示我们所有的数据。

函数是对我们通过调用函数名运行的一段预定义代码的引用。函数总是以一对括号结束,括号中可以包含数据(将传递到函数中使用的变量)。除了函数,PHP 还使用数组,就像你在第七章中看到的数组一样。概括地说,数组是包含许多值而不是一个值的变量。数组可以作为一个整体来操作,也可以由每个单独的元素来操作。要访问数组元素,需要在数组变量的末尾添加一对方括号,并输入想要访问的元素的编号。这些元素编号从第一个元素 0 开始递增。

PHP 需要知道的其他重要事情是:

  • 所有 PHP 语句都以分号结尾
  • 所有 PHP 变量都以一个$符号开始(回想一下第七章中【BASH 的变量);PHP 变量也用于同样的目的)
  • 所有 PHP 数组变量都以一个@符号开始
  • 所有 PHP 函数的内部代码都用花括号{}括起来

接下来,我们需要浏览一下 PHJP 信息页面;从搜索 MySQL 开始。哦,亲爱的,没有提到它。PHP 将需要了解如何与 MySQL 通信,以便我们能够在网页上显示数据库内容。谢天谢地,又来救援了。这一次,我们需要安装php5-mysql包:

$ sudo apt-get install php5-mysql

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

libmysqlclient18

The following NEW packages will be installed:

libmysqlclient18 php5-mysql

0 upgraded, 2 newly installed, 0 to remove and 84 not upgraded.

Need to get 711 kB of archives.

After this operation, 3,547 kB of additional disk space will be used.

Do you want to continue [Y/n]?

同样,您将看到这次安装添加了一个用于通信的新 MySQL 客户端库和新的 PHP MySQL interleave。它还会自动重启 Apache web 服务器,并为您更改几个 PHP 配置文件。再一次,打开浏览器,进入 Apache web 页面,搜索 MySQL,就这样!(参见图 8-3 )。

A978-1-4842-1162-5_8_Fig3_HTML.jpg

图 8-3。

PHP MySQL config info

我们确认了以下内容:

  • 我们有一个工作的 PHP 系统
  • Apache 可以呈现 PHP
  • MySQL 和 PHP 知道如何通信

这意味着我们刚刚完成创建一个工作灯设置!现在让我们使用它。

简单的 Web 应用程序

现在我们已经建立了新的灯堆栈,它已经在您的 Pi 上运行了,是时候好好利用它了。好的用途可以是你想要的任何东西,因为你现在有了自己的 web 服务器,可以在上面编写 web 应用程序。然而,对于你们中的许多人来说,这似乎是一项艰巨的任务,因为你们不熟悉 PHP 甚至 HTML。不要害怕;就像一般的 Linux 一样,这一开始看起来令人生畏,并且有错综复杂的地方,但是没有什么是不可克服的,也没有什么是你不需要一点帮助就能克服的。我总是发现最好的学习方法是实际去做,这意味着我们可以一起承担一个项目,这将说明如何使用您的新 LAMP 堆栈来创建一个 web 应用程序。

为了构建一个 web 应用程序,我们需要了解 HTML 和 PHP。最后一件事:这将是一个基本的网页,可能看起来有点粗糙。有很多方法可以改善你的网页的视觉效果,但是有整本书都致力于此,它们将涵盖更多的内容和交互。所以考虑到这一点,让我们来看看理解 HTML。

超文本标记语言

超文本标记语言(HTML)是创造互联网的语言。HTML 为所有传输的 web 应用程序内容提供了基础,它由一系列标签组成,并作为 HTML 文档发送到您的浏览器。然后,您的浏览器使用这些标签来组装您的网页版本。这意味着网页内容可以非常小,任何有能力解码 HTML 标签的系统都可以看到。这里的缺点是,不同的软件可以显示略有差异的网站。

HTML 标签是由尖括号括起来的单词。这些标签是用所谓的标记语言编写的。HTML 标签有两种类型,单独的或者成对的,成对的更常见。这里有两组 HTML 标签。

  • 一个开始和一个结束的 HTML 标签(这些标签告诉你的浏览器 HTML 页面从哪里开始和结束)
  • <hr/>:一个单独的hr标签(<hr/>会在你的网页上画一条线,因为它代表标题规则)

第二个 HTML 标签前面的斜线表示这是这个标签的结尾。标签末尾的斜线表示它应该独立存在。看看一个很基础的网站:

<html>

<head>

<title>Pi Brand - Todo List App</title>

</head>

<body>

<h1>Pi Todo List App</h1>

</body>

</html>

如果你把它放到 Pi 上的index.php中,打开你的浏览器,你会看到一个基本的白色页面,上面用黑色大字体写着短语 Pi Todo List App。此外,你的浏览器顶部也应该显示同样的信息。这个网站完全由我们刚刚输入的 HTML 标签生成。让我们来看一下这些,作为对网站工作原理的解释:

  • 首先,您会看到所有的内容都被包装在一对 HTML 标记中,这表示其中的所有内容都是 HTML。
  • 下一级是headbody标签,它们代表下一级标签、页面的标题信息和页面的实际主体。
  • title标签用于设置页面顶部的标题栏。
  • 正文中有一对h1标签,它们是一大块文本。h1是 header 1 的缩写,代表 header 标签的最大尺寸。你可以使用几乎无限数量的hx标签;只要定义了它们,大部分浏览器只会走到h4或者h5而不会单独定义一个。

所以我们现在已经讨论了五个基本的 HTML 标签,但是还有更多。要参考大量常见的 HTML 标签、一些例子和很棒的教程,可以去wc3schools.com或者看看 Craig Cook 和 David Schultz 的“用 CSS 和 XHTML 开始 HTML”。

这里还有一些 HTML 标签以及它们的用法:

  • <p>:段落标签,用于将文本创建到段落块中
  • <br> : Break 标签,用于在页面中插入一个分隔符
  • <hr>:水平标尺,在屏幕上创建一条水平线
  • <a>:超链接标签,用于链接到另一个页面
  • <img>:图像标签,用于向页面添加图像
  • 表格标签
    • <table>:表格的顶层标签
    • <th>:表格标题行的元素
    • <tr>:表格的行
    • <td>:表格行内的单元格
  • 表单标签
    • <form>:表单的顶层元素
    • <input>:表单的输入元素

这些是一些基本的 HTML 标签,我们将在项目中使用它们来创建输出,并将输入驱动到待办事项列表中。除了 raw 标记之外,还有许多不同的选项可以用来改变这些元素显示的各个方面;不幸的是,要涵盖每一个元素需要的时间比本书的其余部分都要多,所以我们将不得不在它们出现的时候讨论它们。现在,您已经熟悉了 HTML 的功能和其中一些标签的外观,我们可以继续尝试在这里添加一些 PHP。但是首先,让我们来看看实际设计我们的网页。

开始我们的页面

我们的网页的基本概念将是一个网站分为两部分;首先将是一个包含待办事项列表的页面,列出了数据库中的所有元素。接下来将是一个表单,用于向底部的数据库提交新元素。我们还将添加一个复选框,允许您删除不再需要的元素。现在我们已经有了基本的布局,还需要做出一些关于如何处理页面的功能决策。由于设计和输出将保持不变,只进行一些处理来连接到数据库以加载元素或删除元素,因此我们可以继续前进并拥有一个页面,该页面将尝试执行它需要的任何操作(在显示页面之前进行添加和删除)。

现在我们可以开始写出这一页了。首先,将所有内容添加到页面,并获得输出。然而,首先我们需要建立我们的数据库,以便我们有数据显示。我们已经创建了 Pi 数据库,并且有了之前的待办事项列表结构,所以让我们使用它们。该表的create声明如下:

create table todolist (

idnumber INT PRIMARY KEY NOT NULL AUTO_INCREMENT,

description VARCHAR(200),

owner VARCHAR(40),

date DATE,

location VARCHAR(40),

importance VARCHAR(10),

creator VARCHAR(40)

);

既然我们有了要处理的数据集和数据布局,我们就可以开始添加显示元素了。因为我们的数据是表格形式的,所以我们可以使用表格元素来显示它。这将使安排数据变得容易得多。所以,我们有了之前的基本页面布局;接下来,我们应该建立我们的数据连接。MySQL PHP 连接使用mysqli接口。因此,为了建立到数据库的连接,我们必须创建一个新的mysqli,它包含我们的数据库和连接的详细信息:

<?php

$mysqli = new mysqli(’localhost’, ’pi’, ’raspberry’, ’pi’);

if ($mysqli->connect_error) {

die(’Connect Error (’ . $mysqli->connect_errno . ’) ’

. $mysqli->connect_error);

}

$mysqli->close();

?>

前面是一小段 PHP 代码,它执行以下操作:

  • 创建一个新的mysqli对象来连接到系统,在本地机器上使用用户名pi和密码raspberry可以使用这个对象。
  • 检查与数据库的连接是否成功;如果没有,则显示一条错误消息。
  • 关闭连接,因为我们不想留下一个潜在的未使用的打开的连接。

现在我们有了这个数据库连接的代码块,将它添加到index.php中的原始代码块:

<html>

<head>

<title>Pi Brand - Todo List App</title>

</head>

<body>

<h1>Pi Todo List App</h1>

<?php

$mysqli = new mysqli(’localhost’, ’pi’, ’raspberry’, ’pi’);

if ($mysqli->connect_error) {

die(’Connect Error (’ . $mysqli->connect_errno . ’) ’

. $mysqli->connect_error);

}

$mysqli->close();

?>

</body>

</html>

显示数据库内容

我们现在有了之前的 HTML 的原始片段,并添加了一个小的mysqli连接对象。除非出现错误,否则这不会有太大作用,因为不会显示任何其他内容。现在是时候添加另一个代码块来显示待办事项列表了。这将采取两种形式:台块和台头。然后,我们需要显示 MySQL 表中的所有内容。显示它们意味着创建一个循环来显示每一行的内容,并将它放在正确的 HTML 标记集中。让我们从基本的 HTML 表格布局开始:

<table>

<tr>

<th>Description</th>

<th>Owner</th>

<th>Due Date</th>

<th>Location</th>

<th>Importance</th>

<th>Creator</th>

</tr>

...

</table>

这段代码显示了表格及其第一行,它们都被标记为表格标题元素。现在添加 PHP 来显示 MySQL 表中的所有内容:

<?php

$result = $mysqli->query("SELECT * FROM todolist");

while($row = $result->fetch_assoc()){

print "<tr>";

print "<td>".$row["description"]."</td>";

print "<td>".$row["owner"]."</td>";

print "<td>".$row["date"]."</td>";

print "<td>".$row["location"]."</td>";

print "<td>".$row["importance"]."</td>";

print "<td>".$row["creator"]."</td>";

print "</tr>";

}

?>

PHP 部分很好地完成了这一任务。首先,它创建一个新变量$ result,它包含在mysqli上执行查询的输出。查询的当然是SELECT * FROM todolist。然后,$result->fetch_assoc()调用在while循环中逐一传递结果的每一行,并将其分配给row变量。对于输出的每一行,我们打印我们请求的每个字段的行值。您可以看到 PHP 的输出部分和原始 HTML 之间的相似之处。这是故意的,因为我们希望 PHP 的输出与表头结合起来。

现在,我们应该将它添加回原始代码块,但是在这样做的时候,我们需要再做一处修改,即将$mysqli->close();移动到新代码块的底部,就在 PHP 代码段结束之前。需要进行这种移动,因为否则我们将在实际从数据库中提取数据之前关闭数据库连接。

...

<body>

<h1>Pi Todo List App</h1>

<?php

$mysqli = new mysqli(’localhost’, ’pi’, ’raspberry’, ’pi’);

if ($mysqli->connect_error) {

die(’Connect Error (’ . $mysqli->connect_errno . ’) ’

. $mysqli->connect_error);

}

?>

<table>

<tr>

<th>Description</th>

<th>Owner</th>

<th>Due Date</th>

<th>Location</th>

<th>Importance</th>

<th>Creator</th>

</tr>

<?php

$result = $mysqli->query("SELECT * FROM todolist");

while($row = $result->fetch_assoc()){

print "<tr>";

print "<td>".$row["description"]."</td>";

print "<td>".$row["owner"]."</td>";

print "<td>".$row["date"]."</td>";

print "<td>".$row["location"]."</td>";

print "<td>".$row["importance"]."</td>";

print "<td>".$row["creator"]."</td>";

print "</tr>";

}

$mysqli->close();

?>

</table>

</body>

</html>

网站数据插入

这个 HTML 现在与 PHP 协同工作,生成一整页的内容。静态 HTML 提供了一个框架,然后我们有两部分 PHP:一部分用于建立连接,另一部分用于从待办事项列表中提取结果并将其添加到页面中。现在我们已经有了基本的显示工作,我们需要添加一个表单来给自己一个提交新内容的表单。这个基本表单应该为我们将要插入到表中的每个元素提供一个输入流。我们还需要另外一个元素,一个特殊的隐藏元素,它将告诉我们的处理器对数据做什么。在这种情况下,我喜欢使用一个名为"action"的变量,并根据需要对其赋值。我们需要的最后一个元素是提交元素,它允许我们将数据推送到服务器进行处理。除了所有这些元素,我们还需要给表单一个actionmethod变量,说明如何在我们的 web 服务器上调用 CGI,以及应该使用什么方法。这块积木拼起来看起来像这样:

...

</table>

<form action="index.php" method="POST">

<input type="hidden" name="action" value="insert" />

Description: <input name="description" /><br/>

Owner: <input name="owner" /><br/>

Date: <input name="date" /><br/>

Location: <input name="location" /><br/>

Importance: <input name="importance" /><br/>

Creator: <input name="creator" /><br/>

<input type="submit" />

</form>

</body>

</html>

然后可以将这个代码块添加到表格下方,甚至用一个<hr />标记分隔,这意味着您将拥有一个显示内容的表格,并且在表格下方有一个区域,您可以添加新内容。当把它们放在一起并安装到 web 服务器上时,它生成的内容将如图 8-4 所示。

A978-1-4842-1162-5_8_Fig4_HTML.jpg

图 8-4。

To-do list app with insert table

如果您按下 submit 按钮,您将回到页面上,但是您可以看到该页面在 URL 中被引用。这是发送 CGI 命令以在此页面上运行的动作块。所以现在我们需要在 PHP 中添加一些 CGI 处理来处理这些数据。

回想一下,我们之前设置了一个方法POST,这是我们可以用来将数据从页面传递到 CGI 系统进行处理的两种方法之一。另一种方法是GET,两者之间的区别是有限的,因为两者都以基本相同的方式传递数据。实际上,唯一的区别是GET会在网址上显示内容数据,而POST会将其隐藏。您可以通过将POST更改为GET,然后按下提交按钮来验证这一点。你的网址看起来会像http://10.0.0.20/index.php?action=insert&description=&owner=&date=&location=&importance=&creator =

实际上有大量的数据需要被传输和处理。幸运的是,PHP 有办法让这变得容易得多;它有特殊的变量,这些变量会自动填充来自 CGI 请求的数据。您可以访问三个特殊的变量(就像我们访问 SQL 关联变量一样):_POST_GET_REQUEST

为了处理我们的 CGI,我们需要做很多事情。首先检查action变量是否置位,是否包含数据;当我们按下 submit 按钮时,它将被设置为 insert(稍后有一个 remove 动作)。一旦我们确保动作被设置,我们可以检查它被设置为什么。一旦我们知道我们正在执行哪个操作,我们就可以简单地分离输出的剩余部分,然后在数据库上执行所需的操作。最后,如果我们在主页面加载之前这样做,我们实际上会自动显示最新版本的数据!

我们的 CGI 应该看起来像这样:

if(isset($_REQUEST["action"])){

switch($_REQUEST["action"]){

case "insert":

$SQL="INSERT INTO todolist (description, owner, date, location, importance, creator) VALUES (";

$SQL=$SQL."’".$_REQUEST["description"]."’,";

$SQL=$SQL."’".$_REQUEST["owner"]."’,";

$SQL=$SQL."’".$_REQUEST["date"]."’,";

$SQL=$SQL."’".$_REQUEST["location"]."’,";

$SQL=$SQL."’".$_REQUEST["importance"]."’,";

$SQL=$SQL."’".$_REQUEST["creator"]."’";

$SQL=$SQL.");";

if ($mysqli->query($SQL)=== FALSE) {

printf("Error – Unable to insert data to table " . $mysqli->error);

}

break;

case "delete":

print "Delete function yet to be added!";

break;

}

}

首先要看表单内隐藏字段指定的action变量是否被设置。如果是,我们就可以确定需要执行一个动作。接下来,如果动作被设置,我们进入一个switch(或case)语句来计算出我们正在执行哪个功能。我已经为插入和删除添加了一个用例,但是删除函数只是打印,我们稍后将添加它。此外,如果没有一个针对它的submit方法和一个表单中的动作字段,我们将如何访问它呢?

插入到数据库中

在插入的情况下,我们只需要创建和构建 SQL 命令。我们试图构建的命令与前面的 SQL 插入完全一样。首先,我展示了静态内容:INSERT语句的框架、表名以及我们将要写入的字段。然后,我开始一个接一个地给这个语句添加变量。你可以看到增加的内容有很多有趣的东西,因为每个变量都需要用单引号括起来,并且在末尾有一个逗号。每一小段文本都需要这样对待,这意味着用一对双引号将它们括起来,如下所示:

$SQL=$SQL."’".$_REQUEST["description"]."’,";

这会将当前SQL值(由$SQL=$SQL给出)的值赋给SQL变量,然后给它(由句点标记)加上一个单引号(由"’"给出)和REQUEST变量描述的值,然后加上一个单引号,再加上一个逗号。我知道这看起来工作量很大,但我们已经能够提取出我们需要的每个变量,并在一个小变量中包含整个 SQL 语句。

Caution

在这一点上,还需要注意的是,上述内容并不安全。这些变量实际上可以是任何东西,您可以使用一些特殊的函数来对这些值进行健全性检查。执行这些健全性检查的推荐函数是mysqli_real_escape_string

一旦我们创建了 SQL 变量,我们需要通过简单地再次调用mysqli查询函数来插入它。在这个例子中,我还添加了一个检查来查看查询的执行是否失败。仅此而已;这段代码将处理从 PHP 插入数据库的 CGI。剩下的工作就是将代码块正确地插入到代码中的正确位置。我选择将它附加到我们添加的第一个 PHP 代码块中,而不是给它自己的代码块。这意味着页面的流程首先是绘制页面的标题,然后创建数据库连接并执行任何 CGI 操作,然后显示待办事项列表的实际内容,最后显示最终的表单。一旦输入了代码,您就可以通过将值放入表单并按 submit 来测试它是否工作。这应该继续并添加一个额外的行将显示在你的表中,如图 8-5 所示。

A978-1-4842-1162-5_8_Fig5_HTML.jpg

图 8-5。

All work and no play...

删除条目

既然添加功能已经工作,我们需要创建一个删除功能。如同生活中的所有事情一样,有许多方法可以接近它。最简单的方法是为每个单独的行添加一个表单和删除选项,这意味着如果要删除,需要一次发出一个。第二个选项是有一系列的复选框,这些复选框将删除所有选中的元素。我是第二种选择的支持者,因为它在删除时提供了更多的灵活性。

我们需要做两个改变来实现这个过程。第一个变化是在表周围添加一个表单,它将成为删除表单,一个带有删除操作的隐藏字段,表单下面的提交按钮,以及每个元素的复选框。要添加复选框,我们还需要在表格标题行的开头添加一个空元素。图 8-6 是添加了复选框和提交按钮的页面的外观。

A978-1-4842-1162-5_8_Fig6_HTML.jpg

图 8-6。

Now with extra check boxes

表单内容生成的代码部分如下所示。您可以看到另一个包装表格的表单具有相同的方法和操作。接下来是新的隐藏输入值,它将操作设置为 delete,允许我们访问case语句中的正确部分。可能最重要的变化是添加了空的td对和类型复选框的额外输入。这个复选框可能是我们已经添加的最复杂的元素集—它包含复选框的类型,即专门配置为可作为数组访问的值,这是通过在前后添加方括号来实现的。最后一个元素是值,我已经将它设置为复选框的值。这意味着当我们进入 CGI 模式时,我们将获取复选框的数组值,它将包含我们希望删除的元素的idnumber值列表。

以下是我们为添加复选框而对表单所做的所有更改的简短摘要:

...

<h1>Pi Todo List App</h1>

<form action="index.php" method="POST">

<input type="hidden" name="action" value="delete" />

<table>

<tr>

<td></td>

...

</tr>

<?php

$result = $mysqli->query("SELECT * FROM todolist");

while($row= $result->fetch_assoc()){

print "<tr>";

print "<td><input type=’checkbox’ name=’checkboxes[]’ value=’".$row["idnumber"]."’ /></td>";

print "<td>".$row["description"]."</td>";

print "<td>".$row["owner"]."</td>";

print "<td>".$row["date"]."</td>";

print "<td>".$row["location"]."</td>";

print "<td>".$row["importance"]."</td>";

print "<td>".$row["creator"]."</td>";

print "</tr>";

}

$mysqli->close();

?>

</table>

<input type="submit"/>

</form>

...

从数据库中删除数据

我们要做最后一个更改,即在case语句中添加删除处理。我们可以使用与insert语句类似的逻辑,创建一个 SQL 变量,然后一个接一个地为idnumber添加 remove。在这种情况下,我们将需要一个for循环,该循环将遍历_REQUEST[’checkboxes’]变量的每个元素,我们可以从变量上运行的 count 函数中获得这些元素。这给了我们一个完整的for循环,如下所示:

for($i=0; $i < count($_REQUEST[’checkboxes’]); $i++){

一旦我们进入循环,我们只需要每次在循环中取出_REQUEST[’checkboxes’]数组的第$i个元素。此外,我们需要在每个元素的末尾添加一个or,这样我们就可以在idnumber之前删除每个元素;我们使用or,因为我们希望它删除变量,如果idnumber是第一个数字,第二个数字,或者第三个数字,等等。

然而,我们对or有一个问题:我们将把它添加到最后一个我们不想要的元素的末尾。我们将需要使用rtrim功能从末端修剪掉orrtrim函数将从字符串的右边删除一个给定值,这将给出我们想要的 SQL。最后,我们执行与 insert 中相同的查询操作,并将再次检查是否有错误。这会给我们一个类似这样的代码块:

$SQL="DELETE FROM todolist WHERE";

for($i=0; $i < count($_REQUEST[’checkboxes’]); $i++){

$SQL=$SQL . " idnumber=" . $_REQUEST[’checkboxes’][$i] . " or";

}

$SQL= rtrim($SQL, "or");

if ($mysqli->query($SQL)== FALSE) {

printf("Error Unable to delete value " . $mysqli->error);

}

图 8-7 为最终结果。我已经使用 delete 删除了原来的条目,所以我们只剩下一个。请记住,本书中的所有示例都可以通过 Apress 网站在线获得。如果你不确定这些代码是如何组装的,请下载一份看看!

A978-1-4842-1162-5_8_Fig7_HTML.jpg

图 8-7。

Lowering my workload

解决纷争

现在,让我们来看看解决一些问题的一些方法。首先,尝试按顺序更改每个代码,然后重新加载页面。您可以使用view source命令查看 PHP 生成的完整 HTML,并查看值是否正确显示。如果您不能做到这一点,可以看看错误日志(从一开始我们配置 Apache 时的日志开始)。这个文件将列出所有发生的 PHP 错误。看一下,确保你的引号正确地打开和关闭,并且没有留下任何悬置。检查你的每条语句的末尾是否有一个分号(我总是忘记这个)。检查圆括号、方括号和圆括号是否正确打开和关闭,没有重叠。

PHP 和 web 开发中的许多东西都是反复试验的。您应该检查您添加的每个语句或代码块是否按预期运行和生成。您可以使用print语句在生成变量时输出变量,以查看您到底在做什么,这是诊断 SQL 语句问题的一个好方法。最后,请记住,您可以访问整个系统,继续测试将值插入到 SQL 中,并根据需要删除它们;使用系统找出它在做什么,什么导致了你的问题。

从这里去哪里?

我们已经完成了所有这些开发,我们有一个功能性的待办事项列表,您可以使用它来显示、添加和删除条目。我们使用了各种不同的编程工具来做事情,但是从这里我们可以做很多事情。以下是你可以对你的待办事项列表做出的一些改变:

  • 向每个插入值添加isset();检查,以检查您实际插入的是值,而不仅仅是空格。
  • mysqli_real_escape_string函数包装每个插入的值。这将增加待办事项列表的安全性,因为它防止人们将“讨厌的”值写入您的应用程序,这些值将作为单独的 SQL 查询执行。
  • 更改每个提交元素的value选项,让它们说明我们使用它们的目的:插入或删除。
  • 在表单元素周围创建一个表格用于插入,并为每个标签和插入字段指定它们自己的行和单元格。把它们放在桌子里会让展示更加统一。
  • 开始研究 CSS,因为它可以让你的待办事项列表看起来有很大的不同。推特“自举”是一个很好的起点。

摘要

所以从我们开始以来,我们已经走了很长的路。我们已经做了很多。我们已经安装并配置了 Apache、MySQL 和 PHP。您已经学习了如何创建简单的 SQL 语句来创建和删除数据库和表,然后学习了如何在这些表中插入和删除数据。最后,您已经学习了如何从 Apache web 服务器显示 web 内容。然后,我们将所有内容结合起来,通过一些 PHP 和 HTML 生成一个完整的应用程序,提供对数据库待办事项列表的访问。

这是一项不朽的事业,因为我们不仅安装了三个不同的应用程序,创建了一个互连的应用程序堆栈,还使用了三种语言,在应用程序堆栈之上创建了一个应用程序。

祝贺您——干得好!

九、WiPi:无线计算

树莓派的最大优势之一是它很小,可以放入任何你想得到的小角落或缝隙。这就是为什么它一直被吹捧为人们在设计时使用的最佳选择——它可以放在任何地方,只要有合适的外围设备,几乎可以完成任何任务。此外,它的低功耗意味着在这些情况下使用它的障碍更少,因为它不需要大量的电气管道来“工作”也就是说,树莓派是一个超级小机器,为你的钱提供了巨大的帮助!

然而,这并非没有一些附加条件(见图 9-1 )!如果没有少量的外部电力供应,所有这些电力都是徒劳的。虽然 5 伏并不多,但它确实需要神奇地进入你的树莓派中才能打开灯。除了需要电源之外,Pi 本身几乎没有用处,因为除了让电源 LED 点亮和熄灭之外,Pi 在 5 伏电压下几乎没有什么作用。您需要连接设备以使 Pi 有用。要将 Pi 用作简单的家用电脑,您需要(至少)具备以下条件:

A978-1-4842-1162-5_9_Fig1_HTML.jpg

图 9-1。

Constrained Pi

  • HDMI 或复合视频电缆
  • 用于互联网和网络访问的以太网电缆
  • 用来输入数据的键盘
  • 提供存储的 SD 卡

突然,你明白我的意思了;树莓派,这个小小的独立超级机器实际上被束缚住了。受限于人类可用性和交互性的需求,这些约束意味着将大量电缆连接到您的 Pi,只是为了从中获得一些基本功能。正如您可能猜到的那样,一切还没有结束!有很多方法可以分离你的 Pi,让它更具移动性,让你可以更灵活地使用它。这就是本章的目的:为您提供工具和一些背景知识来移除约束您的 Raspberry Pi 的电线。

准备 WiPi

除了在您的 SD 卡上加载一份 Raspbian 之外,您还需要确保您的 Raspbian 版本已经升级,因为九月份的版本在 WiFi 访问管理方面有了重大改进。要启动这个系统,首先需要运行几个快速命令:

$ sudo apt-get update

$ sudo apt-get upgrade

这两个命令将首先告诉您的apt-get实例进行更新,以了解哪些版本的软件可供您使用。第二个将告诉apt-get比较并安装系统上当前安装的所有软件的每个升级版本。可以想象,定期运行这些命令是一个非常好的主意,因为它可以让您的系统运行最新版本的软件。

简单约束移除

在你开始随意切断电缆之前,你需要明白你想用你的 Pi 实现什么。这将自动对你想用它做什么设置一些限制。我不能预先假定你想用你的圆周率做什么,因为真的有这么多选择。因此,鉴于此,我将尝试在这里提供一些个人的方法,你可以切断绳索(不是字面上的)和解开你的 Pi。你很可能能够利用你新学到的电缆切割技巧和后面章节中的一些内容来改进设计,或者使它们更好地满足你的目的。

移除人工输入设备

从最容易和最低挂的水果开始:显示器,键盘和音频电缆。我知道说一下子去掉三个外围设备是最容易的,这听起来很可笑,但是你真的在等式中去掉了非常不同的东西:你。到目前为止,最容易切断的连接是人机交互设备。事实上,这本书的大部分内容都是为了给你在没有显示器、键盘或扬声器的帮助下使用 Pi 的技巧。这并不是说你不能没有;您可以随时根据需要将它们插回去,以诊断任何真正关键的问题,但是您可以从移除它们并远程管理您的 Pi 开始。这里使用 SSH 是关键,因为您可以使用 SSH 通过网络连接远程连接到您的 Pi。一旦您连接到您的 Pi,您就有完全的命令行访问权来执行您需要的任何任务。还有一个额外的好处是,您可以使用sudo raspi-config改变 Pi 中的内存分配,并将memory_split的值设置为 240/16,这将把大部分内存放入空闲 RAM 供您的系统使用,并尽可能少地放入您通常不会使用的图形显示中。

在你认为这意味着不再使用显示器和键盘之前,停下来。您想用 Pi 做的所有事情都应该在一个工作环境中进行测试和配置,包括键盘、显示器、鼠标等等,所有这些都可以使用。一旦您的系统进入不受您干扰的工作状态,您就可以打开和关闭电源,而无需在每次您知道应该能够移除所有人机界面设备时跳回来进行管理。这对任何人来说都是一个很好的开始:能够移除所有电缆并远程与您的系统交互。这也意味着你可以做其他事情,如通过你的手机或互联网上的工作系统管理你的树莓派。一旦你有了跨越互联网来管理你的机器的感觉,我保证你会问自己以前没有它你是怎么做的。

添加远程 GUI

好吧,虽然我很乐意承认在控制台内工作有一些真正的好处——只是在远程环境中,有些人就是想不通。而且在很多情况下,不管出于什么原因,这都是不切实际的。在这些情况下,最好使用一种叫做虚拟网络计算(VNC)的工具,让您能够从另一台机器上与您的 Pi 桌面进行交互。

为此,您需要在您的 Pi 上安装一个 VNC 服务器,并且在您的机器上需要一个客户机。有许多不同的 VNC 解决方案,只要他们遵守 VNC 协议,他们应该都是兼容的。对于您的 Pi,您将使用 tightvnc,因为它的目标是高效和“紧凑”您可以在 www.tightvnc.com 下载 Windows 和 Linux 系统的客户端。但是在您进入客户机之前,首先要在您的 Pi 上安装服务器。运行以下命令:

$ sudo apt-get install tightvncserver

此命令将使用包管理工具安装 tightvnc 您的输出应该类似于以下内容:

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

x11-xserver-utils xfonts-base xfonts-encodings xfonts-utils

Suggested packages:

tightvnc-java nickle cairo-5c xorg-docs-core

The following NEW packages will be installed:

tightvncserver x11-xserver-utils xfonts-base xfonts-encodings xfonts-utils

0 upgraded, 5 newly installed, 0 to remove and 91 not upgraded.

Need to get 7,824 kB of archives.

After this operation, 11.7 MB of additional disk space will be used.

Do you want to continue [Y/n]?

一旦您安装了紧密的 VNC 服务器,您需要启动它并让它运行,这样您就可以连接。所以继续执行这个命令:

$ tightvncserver

然后会提示您输入一对密码:一个是实际的 VNC 密码,允许您使用鼠标和键盘来操作屏幕;第二个是可选的“仅查看”密码,允许您查看屏幕上的内容,但不能进行交互。执行后,您应该会看到以下内容:

You will require a password to access your desktops.

Password:

Warning: password truncated to the length of 8.

Verify:

Would you like to enter a view-only password (y/n)? n

New ’X’ desktop is raspberrypi:1

Creating default startup script /home/pi/.vnc/xstartup

Starting applications specified in /home/pi/.vnc/xstartup

Log file is /home/pi/.vnc/raspberrypi:1.log

现在您需要做的就是在您希望浏览的机器上连接 tightvnc 客户机。继续启动客户端。我在 Windows 环境下工作,你应该会看到如图 9-2 所示的屏幕。

A978-1-4842-1162-5_9_Fig2_HTML.jpg

图 9-2。

TightVNC Client

在图 9-2 中,你可以看到我已经输入了我的树莓派的 IP 地址和:1。通常 IP 地址后的一个冒号代表一个端口号,但在这种情况下,它代表一个屏幕号。如果你回过头来看一下从紧 VNC 启动的输出,你可以看到它说它创建了一个新的桌面raspberrypi:1,这就是我已经连接到的。现在,按下连接键,屏幕上就会出现可爱的粉红色树莓,你可以在树莓 Pi 环境中四处移动。

然而,如果您重新启动,您将再次失去 VNC 服务器,并且运行tightvncserver将再次要求您提供凭证。这不是执行此操作的最佳方式,因此,如果您希望重新启动服务器,可以运行以下命令:

$ vncserver :1 -geometry 1920x1080 -depth 24

该命令要求在尺寸为 1920 x 1080 的屏幕:1上运行一个vncserver,这是您的 Pi(全 1080p 高清)的最大分辨率,并将颜色深度设置为 24 位。如果需要,您可以降低这些值以适合您的客户端屏幕尺寸,或者降低您的 Pi 在托管 VNC 连接时使用的资源数量。除此之外,您可能希望在引导时运行您的 VNC 服务器,这样您就不需要 SSH 来建立视频连接。毕竟那只是多余的!简单的方法是将vncserver命令添加到/etc/rc.local中,因为该文件中的所有内容都会在引导过程中执行。

默认情况下,您的rc.local文件将如下所示:

#!/bin/sh -e

#

# rc.local

#

# This script is executed at the end of each multiuser runlevel.

# Make sure that the script will "exit 0" on success or any other

# value on error.

#

# In order to enable or disable this script just change the execution

# bits.

#

# By default this script does nothing.

# Print the IP address

_IP=$(hostname -I) || true

if [ "$_IP" ]; then

printf "My IP address is %s\n" "$_IP"

fi

exit 0

然后,您可以在exit 0之前添加下面一行来启动 tightvnc:

vncserver :1 -geometry 1920x1080 -depth 24

如果您想要一个正确的启动过程,您可以使用类似下面的脚本作为文件/etc/init.d/tightvnc:

### BEGIN INIT INFO

# Provides: tightvnc

# Required-Start: $remote_fs $syslog

# Required-Stop: $remote_fs $syslog

# Default-Start: 2 3 4 5

# Default-Stop: 0 1 6

# Short-Description: Start Tight VNC Server at boot time

# Description: Start Tight VNC Server at boot time.

### END INIT INFO

#! /bin/sh

# /etc/init.d/tightvnc

USER=pi

HOME=/home/pi

export USER HOME

case "$1" in

start)

echo "Starting Tight VNC Server"

/usr/bin/vncserver :1 -geometry 1920x1080 -depth 24

;;

stop)

echo "Stopping Tight VNC Server"

/usr/bin/vncserver -kill :1

;;

*)

echo "Usage: /etc/init.d/tightvnc {start|stop}"

exit 1

;;

esac

exit 0

创建此文件后,您需要执行以下命令来执行脚本:

$ sudo chmod +x /etc/init.d/tightvnc

然后就可以用/etc/init.d/tightvnc开始和停止脚本了。请注意,第一次运行该脚本时,您必须再次输入 VNC 密码,因为该脚本是以 root 用户而不是 Pi 用户的身份运行的。最后,您可以将脚本设置为自动启动,如下所示:

$ sudo update-rc.d tightvnc defaults:

update-rc.d: using dependency based boot sequencing

既然您已经在 Pi 上安装并配置了 VNC,并且能够消除使用 Pi 对人工输入设备的依赖,那么您就可以进入下一个领域了。

真正的带 WiFi 的 WiPi

从您早期使用 VNC 和 SSH 的工作中,您将逐渐意识到,在删除人工输入设备的过程中,您已经增加了对网络连接的依赖性。这种依赖性以管理的形式出现,因为你不能再通过键盘和显示器直接交互;您需要另一种访问方法:以太网连接。当然,这仍然是一根电线,所以你最好保留输入设备,对吗?这里有一个非常明显的解决方案——WiFi——但令许多人懊恼的是,Raspberry Pi 没有自带 WiFi。如果您想使用无线适配器,您需要出去为您的 Pi 购买一个无线适配器。

好吧,很简单,你说,然后你去当地的计算机硬件商店买一个无线适配器。你环顾四周。有这么多可用的无线适配器!那么,这几十种中哪一种最适合 Pi 呢?他们都可以和 Pi 一起工作吗?虽然大多数人会凭直觉去挑选最便宜的,适合他们家里 WiFi 设置的,但这不是正确的做法,因为还有其他因素在起作用。

首先,所有的 USB 设备都需要电源,正如你所知,树莓 Pi 需要 5 伏的电源。这意味着您将需要一个运行在较低电量的无线设备(如果您在 Pi 的 USB 上放置太多的消耗,您可能会使它崩溃),或者您将需要投资一个连接到外部电源的供电 USB 设备(对您的目的来说不是很好,但我将在稍后介绍这一点,因为它们还有其他用途)。所以你需要留意权力;您还需要注意兼容性,因为一些陌生的无线适配器可能不支持 Linux 系统。我已经包含了一些来自 Raspberry Pi 社区的数据,这些数据是关于他们使用各种无线适配器的体验,以补充我自己的数据。

如图 9-3 所示,我选择使用从当地技术商店购买的 D-Link DWA-131 无线适配器。本例的其余部分将介绍使用 DWA-131 让您的 Pi 与您的本地无线网络通信的一些基础知识。

A978-1-4842-1162-5_9_Fig3_HTML.jpg

图 9-3。

D-Link DWA-131 802.11n wireless N nano adapter Note

当您连接无线适配器时,您的 Pi 可能会重新启动,因此请事先保存所有工作。

这并不意味着您需要单独使用这个特定的适配器;一旦您成功地让无线适配器正确注册,大多数无线适配器与您的 Pi 一起工作的设置过程应该是相同的。所以事不宜迟,开始并插入无线适配器,开始工作。板卡的当前状态如图 9-4 所示。

A978-1-4842-1162-5_9_Fig4_HTML.jpg

图 9-4。

Three down, two to go!

正如你所看到的,我仍然有我的以太网电缆连接到现在。我将向您展示如何从命令行和 GUI 在您的 Pi 上配置无线。在您直接进入配置之前,您需要确切地知道您正在处理什么,所以进入 shell 并运行lsusb命令,它就像ls命令一样,但是用于 USB 设备。

$ lsusb

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.

Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.

Bus 001 Device 004: ID 07d1:3303 D-Link System DWA-131 802.11n Wireless N Nano Adapter(rev.A1) [Realtek RTL8192SU]

完美!您可以从这个命令中看到,我的无线适配器已经被系统识别,应该可以正常工作了——太棒了。如果没有,不要害怕;您只需要为您的特定网卡安装驱动程序。少量的谷歌研究,你应该可以找到无线网卡的芯片组。芯片组是指无线适配器内“运行”无线适配器的小硅芯片。芯片组通常是由完全不同的公司制造的,与设备上显示的公司不同,您需要与芯片组进行交互,从而决定您需要找到哪些驱动程序。一旦你找到了芯片组,快速搜索应该会指出你需要安装什么驱动程序包。一旦您安装了您的驱动程序包,并且您可以在lsusb中看到您的无线适配器,您就可以进入下一步。

因为您已经安装并注册了设备,所以您应该检查该设备是否已正确注册为网络设备。在使用 Linux 时,最常用的网络管理工具是ifconfig。所以继续运行ifconfig并检查输出:

$ ifconfig

eth0      Link encap:Ethernet  HWaddr b8:27:eb:8a:46:ba

inet addr:10.0.0.20  Bcast:10.0.0.255  Mask:255.255.255.0

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:6558 errors:0 dropped:0 overruns:0 frame:0

TX packets:268 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:374403 (365.6 KiB)  TX bytes:28129 (27.4 KiB)

lo        Link encap:Local Loopback

inet addr:127.0.0.1  Mask:255.0.0.0

UP LOOPBACK RUNNING  MTU:16436  Metric:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:0

RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

wlan0     Link encap:Ethernet  HWaddr 90:94:e4:51:81:7a

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:0 errors:0 dropped:0 overruns:0 frame:0

TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

之前的配置实际上显示了三个设备的信息,而不仅仅是无线适配器的信息(其中两个您在第三章中看到过):

  • 它首先显示了作为物理以太网设备的eth0设备。
  • 接下来是lo适配器;回想一下,这是系统的内部自引用设备,当您想要将流量从其自身寻址到 Pi(或任何系统)内部时,可以使用该设备。
  • 最后你有wlan0,这是无线设备。您应该能够注意到eth0lo设备与wlan设备之间的一些差异——它没有 IP 地址(用inet addr表示)或掩码。这些是您需要配置的内容,以便让它与您的无线网络进行对话,以及您的无线网络 SSID 和安全安排的详细信息。所以这将是你的下一步。

如果您的适配器没有出现,但是在lsusb中注册了,重新启动并执行相同的故障诊断步骤。系统可能能够识别您的设备,但无法与之正确连接。为您的系统安装一个驱动程序包可能是这里的解决方案。

首先,让这变得简单,通过 GUI 进行配置,具有讽刺意味的是,这涉及到通过命令行安装某些东西。继续启动apt-get来安装wpa-gui。WPA GUI 是最近添加到 Raspbian 中的一个应用程序,它使无线设备的安装和配置变得非常非常简单。事实上,这是最近的事,这一章需要重写以包含它,因为在第一轮写作中使用的 Raspbian 版本不包含它!如果您不确定是否有正确的版本,您应该运行这个命令,因为这样做没有坏处。安装该应用程序的命令如下:

$ sudo apt-get install wpagui

如果您有包含wpagui的 Raspbian 的最新版本,您将看到下面的输出,表明该包已经安装:

Reading package lists... Done

Building dependency tree

Reading state information... Done

wpagui is already the newest version.

0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

如果您尚未安装该软件包,您的安装将如下所示:

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

libaudio2 liblcms1 libmng1 libqt4-svg libqtcore4 libqtgui4 menu

Suggested packages:

nas liblcms-utils qt4-qtconfig menu-l10n

The following NEW packages will be installed:

libaudio2 liblcms1 libmng1 libqt4-svg libqtcore4 libqtgui4 menu wpagui

0 upgraded, 8 newly installed, 0 to remove and 96 not upgraded.

Need to get 8,921 kB of archives.

After this operation, 22.6 MB of additional disk space will be used.

Do you want to continue [Y/n]?

太棒了!现在你已经安装了wpagui,你应该可以通过用户界面很好地利用它。但是在您开始之前,请继续重新启动您的 Pi,因为您已经对 Pi 管理网络连接的方式进行了重大更改,并且您希望在继续之前确保它是防爆的。穿好了吗?你可以运行ifconfig并且输出看起来是一样的,很棒。

现在您可以开始配置您的无线适配器。您将从 GUI 开始,然后看看如何通过命令行来完成。

Note

如果您注意到您的 Pi 变慢或无法连接到 WiFi,可能是您的键盘消耗了太多的电量。尝试移除它并使用 VNC 或 SSH 来配置您的无线网络。

GUI WiFi 配置

登录 GUI,应该会有一个名为 WiFi Config 的新图标,如图 9-5 所示。

A978-1-4842-1162-5_9_Fig5_HTML.jpg

图 9-5。

WiFi Config icon

双击此图标打开应用程序,您应该会看到 wpagui 窗口,如图 9-6 所示。

A978-1-4842-1162-5_9_Fig6_HTML.jpg

图 9-6。

wpa_gui window

在 wpagui 窗口中,按下扫描按钮。这需要一些时间,但是会弹出另一个窗口,如图 9-7 所示。

A978-1-4842-1162-5_9_Fig7_HTML.jpg

图 9-7。

Scan results window

这个窗口应该大家都很熟悉。这是选择无线网络的窗口。找到您的特定网络,然后双击它以打开配置窗口(参见图 9-8 )。

A978-1-4842-1162-5_9_Fig8_HTML.jpg

图 9-8。

Network details

我假设您应该准备好了设置配置的详细信息。大部分都是直观的,但有几件事你需要注意:

  • SSID 是您的无线网络的“名称”,因此您需要键入此名称。
  • 接下来是身份验证,它指定了您正在使用的身份验证类型:WEP、WPA、WPA2 等等。
  • 接下来是加密,它选择您将使用的加密模式。
  • 最后是 PSK,代表预共享密钥。这是你的 WiFi 密码。

现在转到“无线安全”选项卡,设置您用于 WiFi 的身份验证方法、加密方法和密码。这些信息通常在路由器的配置系统中,但也可以写在路由器本身或路由器手册中。现在点击添加。您的无线设置应该保存到系统中,系统将获取这些设置并开始尝试连接到您的适配器;过一会儿,您应该会看到类似图 9-9 的内容。

A978-1-4842-1162-5_9_Fig9_HTML.jpg

图 9-9。

WiFi connected!

如果您没有看到这一点,请查看鼠标悬停消息,它会让您了解您的连接出现了什么问题。检查您的设置是否正确,以及您是否选择了正确的安全方法。如果有疑问,请打开您的路由器配置进行仔细检查。最后,您可以回到控制台,再次发出ifconfig来检查您的无线适配器设置!

wlan0     Link encap:Ethernet  HWaddr 90:94:e4:51:81:7a

inet addr:10.0.0.59  Bcast:10.0.0.255  Mask:255.255.255.0

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:772 errors:0 dropped:10 overruns:0 frame:0

TX packets:35 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:100749 (98.3 KiB)  TX bytes:4254 (4.1 KiB)

这看起来更像你所期望的;它有一个 IP 地址、掩码等等。它还显示它一直在无误地发送和接收数据包(即 RX 和 TX 数据包编号)。最后的测试是从第二台机器 ping 那个 IP 地址,就这样。现在,您可以移除以太网电缆了。作为最后的测试,继续并重新启动;重新启动后,您应该能够 ping 通系统的wlan0 IP 地址,这表明您已经成功地保存了重新启动后存储的无线适配器详细信息。现在,您可以移除下一根电缆并重新启动,以确保您的系统默认使用无线适配器。

从命令行管理 WiFi

对于那些不太想使用 GUI 或者认为自己是真正的 Linux 传统的纯粹主义者(只使用命令行来管理系统)的人来说,这正是适合你的地方!为此,您将修改网络管理器配置。NetworkManager 系统决定如何管理以太网设备的基本方法有两种:

  • 它检查是否设置了/etc/NetworkManager/NetworkManager.conf中的managed标志。
  • 它接管在/etc/network/interfaces中配置的任何东西的管理;这些设置说明应该如何管理该设备。

您不希望 NetworkManager 系统从上面接管您的设置,所以您需要确保它不会这样做。只有在您之前安装了 GUI,或者 NetworkManager 与您的 Raspbian 映像捆绑在一起时,这才会是一个问题,但是最好是彻底的。所以继续检查/etc/NetworkManager/NetworkManager.conf并确保managed标志被设置为false。该文件应该类似于:

[main]

plugins=ifupdown,keyfile

[ifupdown]

managed=false

一旦完成,继续重新启动您的 Pi;您希望确保 Pi 正确启动,并且所有现有的以太网连接在第一次重新启动后都工作正常。现在您需要将配置添加到/etc/network/interfaces中,以便它知道如何管理设备并连接到您的 WiFi。所以请继续打开/etc/network/interfaces。您将看到该文件已经部分填充了以下行:

auto lo

iface lo inet loopback

iface eth0 inet dhcp

根据您的系统是否已经进行了一些无线配置,您可能还会在文件中看到以下几行。

allow-hotplug wlan0

iface wlan0 inet manual

wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf

iface default inet dhcp

这些行分别对应于 loopback 和eth0设备,并提供一些关于它们管理的简单细节;在这种情况下,环回是一个自动管理的环回设备,eth0设备通过 DHCP 获得一个 IP 地址。您的wlan0设备可能也有一些现有配置;如果它们存在,您应该通过在它们前面添加一个#来注释掉它们,或者从文件中删除它们。您现在需要为wlan0无线设备添加一个新的配置,所以继续将以下内容添加到您的配置中现有内容的下方:

auto wlan0

iface wlan0 inet dhcp

wpa-ssid <Your WiFi SSID>

wpa-psk <Your WiFi password>

这个块表示您将拥有一个自动管理的wlan0设备,它通过 DHCP 获取其连接信息。你还把 SSID 和 PSK 传给它。此配置将适用于 WPA 和 WPA2 网络安全实施。完成后,就该测试您的新设备了,所以继续运行下面的代码,这将启动界面。这可能需要一些时间,但是您的输出应该类似于我的输出:

$ sudo ifdown wlan0

$ sudo ifup wlan0

Internet Systems Consortium DHCP Client 4.2.2

Copyright 2004-2011 Internet Systems Consortium.

All rights reserved.

For info, please visithttps://www.isc.org/software/dhcp/

Listening on LPF/wlan0/90:94:e4:51:81:7a

Sending on   LPF/wlan0/90:94:e4:51:81:7a

Sending on   Socket/fallback

DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 8

DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 15

DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 9

DHCPREQUEST on wlan0 to 255.255.255.255 port 67

DHCPOFFER from 10.0.0.1

DHCPACK from 10.0.0.1

bound to 10.0.0.59 ˗˗ renewal in 444671 seconds.

所有这些都表明,该设备已经连接到我的无线网络,并通过 DHCP 获得了一个 IP 地址,这正是你告诉它要做的!现在假设你不想用 DHCP,而是宁愿给你的 WiFi 适配器一个静态 IP 地址。你只需要将iface行改为static而不是dhcp,然后添加你的 IP 地址、子网掩码和网关的详细信息。您的配置将改为如下所示:

auto wlan0

iface wlan0 inet static

address 10.0.0.57

netmask 255.255.255.0

gateway 10.0.0.1

wpa-ssid <Your WiFi SSID>

wpa-psk <Your WiFi password>

现在您已经成功地在系统上配置了无线,您可以继续并重新启动您的 Pi 来检查无线适配器是否自动启动。如果没有,返回并确保您设置了auto wlan0并且您在网络管理器配置文件中启用了managed=false标志。

如果这不起作用,请检查 SSID 和 WiFi 密码的配置设置。您可以使用ifup wlan0确认是否可以启动您的无线适配器;如果在连接和获取 IP 地址时出现问题,您的系统应该在这里显示出来,让您有机会找出问题所在。最后,如果你只是不能让它运行,尝试删除任何其他连接的 USB 设备;它们会从您的 WiFi 适配器吸取宝贵的能量。

命令行上最后一件可能对您有帮助的事情是iw系列命令:

  • 您可以使用scan选项运行iwlist来扫描附近无线热点的信息。
  • 或者您可以使用iwconfig来获取关于您的无线适配器的配置细节。

只剩一个

恭喜你,你即将拥有一个完全无线的树莓派!您已经成功消除了对以太网电缆的需求,现在您可以无线访问您的 Pi。现在应该只剩下一根电缆了!(参见图 9-10 )。

A978-1-4842-1162-5_9_Fig10_HTML.jpg

图 9-10。

Last cable standing

消除对电源的需求

你能做的很少,以简化为你的树莓派供电的需求;它需要它,而这个问题的解决方案是有限的。到目前为止,最容易和方便的是获得一个大的 USB 电池。如今,这种充电器几乎随处可见,可以为人们经常随身携带的许多设备充电。这里的简单解决方案是将您的 Pi 连接到这些电池中的一个来使用,因为这种电池应该保证向您的 Pi 输出正确的功率水平,因为它们是为 USB 设备供电而设计的。当考虑用电池给你的 Pi 供电时,重要的是要确定它们能提供 1 安培的功率,因为一些 USB 电池可以充电,但不能提供足够的电量给 Pi 供电。图 9-11 显示了最终的 WiPi。

A978-1-4842-1162-5_9_Fig11_HTML.jpg

图 9-11。

WiPi at long last!

有一些将可充电电池和太阳能电池板结合起来的方法,对你来说会走得更远,但这些都超出了本书的范围。

供电 USB 适配器

我之前提到过,如果你在你的 Pi 的 USB 上放太多的电源,你可能会使它崩溃,因为它自己只有有限的电源。解决方案是把你的手放在一个通电的 USB 集线器上。这些供电集线器通常有一个输出连接和多个输入连接,还会有一个电源连接来供电。其原理是,人们很少使用 USB 的全部数据传输量,但经常会耗尽电量,因此,有一种方法可以用市电电源补充 USB 设备的电量,这是一种很好的方法,可以让人们更加灵活地使用他们的设备。如果您发现当您连接您的设备时,您的 Pi 会自动关闭,这是一个公平的赌注,您将需要类似这样的东西来帮助分散电力负载(见图 9-12 )。

A978-1-4842-1162-5_9_Fig12_HTML.jpg

图 9-12。

Powered USB hub in action

摘要

做了这么多工作,你应该已经看到了很大的回报。您现在应该知道如何配置您的 Pi 以使其无线化。除了正常的 SSH 连接之外,您应该能够通过 VNC 客户端设置并连接到您的 Pi。您已经学习了如何配置您的 Raspberry Pi 来获取无线适配器,并可以将其连接到您现有的无线网络。最后,您应该了解 Pi 在功耗方面的一些限制,以及如何解决这些问题。

十、树莓派

每个人都想成为詹姆斯·邦德。或者至少我知道我有。他似乎陷入了各种各样的情况;然后拿出一个方便的小工具来拯救世界。正如我们所展示的,树莓派对于这样一个小小的硬件来说是极其通用的。这使得它成为一个特工的完美工具,因为只需要一点点能量,你就可以提供一个成熟的技术解决方案,而花费的成本只是雇佣约翰·克立斯的一小部分(不可否认,Pi 并不那么有趣)。考虑到这一点,我们现在可以穿上晚礼服,开始秘密特工的工作了。

所有优秀的特工都知道,你需要能够发现并警惕秘密藏身处的入侵者。因此,这是向您介绍树莓 sPi 的最佳时机!树莓 sPi 是一个间谍相机和警报系统的组合,是发现卑鄙的入侵者进入你的密室的完美解决方案!或者通过互联网监控你的宠物。这里的基本概念是我们将配置我们的 Raspberry Pi。所以事不宜迟,我们开始吧。

所需材料

以下是本项目所需的材料(也见图 10-1 ):

A978-1-4842-1162-5_10_Fig1_HTML.jpg

图 10-1。

The Raspberry sPi kit

  • 1 个树莓派
  • 1 根微型 USB 电缆(用于电源)
  • 1x 以太网电缆
  • 1 个 USB 网络摄像头
  • 1 张 SD 卡

在这一点上,你应该注意到并不是所有的网络摄像头都与 Raspberry Pi 兼容。此文档是用 Logitech C525 网络摄像头创建的。值得庆幸的是,Pi 社区维护了一个兼容硬件的列表,可在 http://elinux.org/RPi_VerifiedPeripherals#USB_Webcams 获得。如果您有疑问,请在那里查看哪些外设可以与您的 Pi 配合使用。

预设

这里没什么特别的;只需连接微型 USB 以获取电源,连接以太网以访问网络,连接 SD 以进行存储,并确保相机保持独立——我们稍后会这样做。此过程的其余部分假设您熟悉以下内容:

  • 安装 Raspbian 操作系统
  • 了解如何在 Raspbian Linux 环境下工作

如果你对这两者都不熟悉,那也没关系。这就是这本书的目的,所以请回过头来阅读第一章以了解如何开始使用 Raspbian,以及这本书的第二部分以熟悉在 Raspbian Linux 环境中工作。

入门指南

所以,事不宜迟,我们开始吧。继续加载 Raspbian 并将您的 Pi 连接到您的网络。浏览 Raspbian 设置过程,并确保启用 SSH,因为稍后您将需要远程登录。(我们看不到詹姆斯·邦德带着键盘、HDMI 线和显示器,不是吗?)一旦你设置好了,继续 SSH 到你的 Pi(在第三章中讨论)。

好的,一旦你登录,继续发出命令dmesg并查看输出。

dmesg-一般信息

dmesg命令是一个名为驱动程序消息的工具,它向内核显示所有消息的日志输出,包括来自设备和连接到您系统的驱动程序的消息。dmesg在确定连接了哪些设备,以及您应该在哪里以及如何与它们交互方面非常有用。它还列出了在诊断低级问题时非常有用的驱动程序和内核消息。那么,让我们来看看输出的相关部分。

Note

less是更。如果您发现某个命令的输出超出了屏幕的顶部,您再也看不到它了,重新发出该命令,然后通过管道将其发送到less (,即dmesg | less。这应该允许您使用箭头键和空格键向下翻页来浏览任何命令的输出。

[    1.998581] Waiting for root device /dev/mmcblk0p2...

[    2.071268] mmc0: new high speed SD card at address 7d37

[    2.079917] mmcblk0: mmc0:7d37 SD02G 1.83 GiB

[    2.088723]  mmcblk0: p1 p2

[    2.132278] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)

[    2.145275] VFS: Mounted root (ext4 filesystem) on device 179:2.

[    2.155272] Freeing init memory: 200K

[    2.187333] usb 1-1: new high speed USB device number 2 using dwc_otg

[    2.418045] usb 1-1: New USB device found, idVendor=0424, idProduct=9512

[    2.427750] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0

[    2.438708] hub 1-1:1.0: USB hub found

[    2.445041] hub 1-1:1.0: 3 ports detected

[    2.727674] usb 1-1.1: new high speed USB device number 3 using dwc_otg

[    2.837920] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00

[    2.857413] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0

[    2.878968] smsc95xx v1.0.4

[    2.942985] smsc95xx 1-1.1:1.0: eth0: register ’smsc95xx’ at usb-bcm2708_usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:8a:46:ba

[   11.006171] EXT4-fs (mmcblk0p2): re-mounted. Opts: (null)

[   11.426960] ### snd_bcm2835_alsa_probe c05c88e0 ############### PROBING FOR bcm2835 ALSA device (0):(1) ###############

[   11.442869] Creating card...

[   11.448268] Creating device/chip ..

[   11.454771] Adding controls ..

[   11.460340] Registering card ....

[   11.475463] bcm2835 ALSA CARD CREATED!

[   11.487786] ### BCM2835 ALSA driver init OK ###

[   18.493739] smsc95xx 1-1.1:1.0: eth0: link up, 100Mbps, full-duplex, lpa 0x45E1

[   24.672322] Adding 102396k swap on /var/swap.  Priority:-1 extents:1 across:102396k SS

如您所见,dmesg的输出有点令人不快,难以理解。许多信息依赖于对dmesg系统如何工作的一些基本原则的理解。首先是方括号[]内的数值。该值是一个定时器值,用于记录自系统启动以来经过的时间。这是一个很好的方法来跟踪你系统中的事件顺序,并把最近发生的和过去发生的区分开来。

接下来是内容本身。这些行中的大部分单独在诊断上是没有用的,但是它们合在一起形成了一幅非常有趣的画面,描绘了我的 Pi 中到底发生了什么。让我们从第一行开始:

waiting on root device /dev/mmcblk0p2

前几行很明显:系统在等待什么,但什么是/dev/mmcblk0p2?好吧,第一个赠品是/dev;这是 Linux 操作系统列出所有设备的地方,所以我们知道/dev/mmcblk0p2是一个设备。其次是mmcblk0p2,它看起来像一串垃圾,但实际上是一系列缩写。

  • mmc表示多媒体卡(闪存设备标准)
  • blk表示块存储设备
  • 0表示这种类型的第一个逻辑设备
  • p2表示装置的两个隔板

所以我们在等 SD 卡。第二到第四行是我们正在等待的:SD 卡注册,你可以看到它实际上注册为我们提到的每一个子设备,按顺序没有减少!之后,接下来的两行是在这个设备上挂载可读文件系统的设备。继续往下,您可以看到 Pi 的 USB 设备的注册(第 8-15 行),它的以太网端口(第 16、17 和 26 行),最后是一个高级 Linux 声音架构(ALSA)设备,它是音频端口(第 19-25 行)。

现在你明白了我们为什么不一开始就连接网络摄像头,我想看看dmesg输出。既然你知道要找什么,现在继续连接你的网络摄像头并再次运行dmesg。看看出现的新系列。这些应该都和你新附加的网络摄像头有关!下面是我附加我的输出:

[ 8168.793423] usb 1-1.2: new high speed USB device number 4 using dwc_otg

[ 8169.147691] usb 1-1.2: New USB device found, idVendor=046d, idProduct=081d

[ 8169.147736] usb 1-1.2: New USB device strings: Mfr=0, Product=0, SerialNumber=1

[ 8169.147758] usb 1-1.2: SerialNumber: 8627F4C0

[ 8169.314171] Linux video capture interface: v2.00

[ 8169.336482] uvcvideo: Found UVC 1.00 device <unnamed> (046d:081d)

[ 8169.402071] input: UVC Camera (046d:081d) as /devices/platform/bcm2708_usb/usb1/1-1/1-1.2/1-1.2:1.2/input/input0

[ 8169.402280] usbcore: registered new interface driver uvcvideo

[ 8169.402299] USB Video Class driver (1.1.1)

[ 8169.460903] usbcore: registered new interface driver snd-usb-audio

那么,从这些线条中你能看出什么?首先,您可以在dmesg日志中看到这个特定条目的时间差异很大,它代表了从启动到我连接设备之间的延迟。接下来,您将认识到前四行代表 USB 端口接收新连接的设备;事实上,第一行引用了用于完成这个任务的模块dwc_otg(DesignWare Cores 的缩写——On The Go)。第 5 行显示它是一个视频捕获接口,第 6 行显示模块uvcvideo找到了一个它识别并注册的 USB 视频类(UVC)设备。最后,我们还可以看到网络摄像头的麦克风也已经在最后一行注册为snd-usb-audio设备。从这里我们可以看到我的网络摄像头已经连接上了,并通过驱动程序注册到了操作系统中。

既然设备已经注册,我们需要一种方法来引用它,以便它可以被应用程序使用。您会注意到,dmesg输出实际上并没有指定我们添加了哪个设备,所以让我们看一下,看我们是否能以另一种方式匹配它。先来列举一下/ dev的内容(结果如图 10-2 )。

A978-1-4842-1162-5_10_Fig2_HTML.jpg

图 10-2。

Contents of /dev directory

$ ls /dev/

那是一些设备。我们可以马上删除一些:所有的tty设备,因为它们是电传打字设备;所有的ram设备,因为那是 Pi 的 RAM 所有的loop设备,因为它们是回环连接器;所有的memblck设备,因为它们与 SD 卡相关;所有的vcs设备,因为它们是虚拟控制台。还是有几个,但是最好看的是video0。我们在找一个网络摄像头,对吗?它注册为视频捕获设备,不是吗?好吧,我们认为这是对的——但是我们怎么知道呢?

udev,更确切地说是udev管理函数,是 Linux 内核的设备管理器。它控制设备如何以及在哪里注册自己,以便它们可以作为操作系统的一部分被应用程序访问。在 Debian(以及 Raspbian)中,udev的内部工作方式可以通过udevadm命令访问,所以让我们开始使用它吧。执行以下操作:

$ udevadm info -a -p  $(udevadm info -q path -n /dev/video0)

P: /devices/platform/bcm2708_usb/usb1/1-1/1-1.2/1-1.2:1.2/video4linux/video0

N: video0

S: v4l/by-id/usb-046d_081d_8627F4C0-video-index0

S: v4l/by-path/platform-bcm2708_usb-usb-0:1.2:1.2-video-index0

E: DEVLINKS=/dev/v4l/by-id/usb-046d_081d_8627F4C0-video-index0 /dev/v4l/by-path/platform-bcm2708_usb-usb-0:1.2:1.2-video-index0

E: DEVNAME=/dev/video0

E: DEVPATH=/devices/platform/bcm2708_usb/usb1/1-1/1-1.2/1-1.2:1.2/video4linux/video0

E: ID_BUS=usb

E: ID_MODEL=081d

E: ID_MODEL_ENC=081d

E: ID_MODEL_ID=081d

E: ID_PATH=platform-bcm2708_usb-usb-0:1.2:1.2

E: ID_PATH_TAG=platform-bcm2708_usb-usb-0_1_2_1_2

E: ID_REVISION=0010

E: ID_SERIAL=046d_081d_8627F4C0

E: ID_SERIAL_SHORT=8627F4C0

E: ID_TYPE=video

E: ID_USB_DRIVER=uvcvideo

E: ID_USB_INTERFACES=:010100:010200:0e0100:0e0200:

E: ID_USB_INTERFACE_NUM=02

E: ID_V4L_CAPABILITIES=:capture:

E: ID_V4L_PRODUCT=UVC Camera (046d:081d)

E: ID_V4L_VERSION=2

E: ID_VENDOR=046d

E: ID_VENDOR_ENC=046d

E: ID_VENDOR_ID=046d

E: MAJOR=81

E: MINOR=0

E: SUBSYSTEM=video4linux

E: TAGS=:udev-acl:

E: UDEV_LOG=3

E: USEC_INITIALIZED=8168852755

哇,好吧,这是一大块看起来很吓人的输出。我相信你现在已经猜到了,我们刚刚请求udev系统给我们一个信息查询,查询与名为/dev/video0的设备相关的所有信息,它确实有。然而,在过度换气开始之前,实际上看一看前几行。第一行应该很熟悉——这是我们在dmesg中看到的连接网络摄像头时的设备标识符!事实上,这里的大部分信息都是在dmesg块中引用的数据。好了,既然我们可以将来自dmesg的设备与我们系统中的设备进行匹配,那么可以有把握地说,我们附加的 USB 网络摄像头在文件系统中的名称是/dev/video0

解决纷争

如果和我的不同,你的网络摄像头在dmesg中注册内核时出现问题,你可能需要安装一个驱动程序。你应该向制造商查询,并上网查看是否有适用于你的摄像头的驱动程序。如果是这样,安装驱动程序,然后尝试重新连接您的网络摄像头,看看它是否可以注册。你甚至可能很幸运,你的设备驱动程序会有一个内核列表,在这个列表中,网络摄像头被注册在dmesg/dev中——就像前面例子中我的 SD 卡一样。

此外,如果您没有列出像/dev/video0这样的设备,您应该检查其他设备是否与来自dmesg的与您的设备相关的输出相匹配。当 Linux 试图在/dev文件系统的布局上变得明智时,制造商和软件工程师可以做一些有趣的事情来试图脱颖而出——结果是你坐在那里尖叫着你怎么找不到一个设备。因此,请耐心地四处看看,并使用排除法来尝试找出您的设备连接到了哪里。这里的目标是确保您知道哪个/dev文件引用了您的网络摄像头。

动作捕捉

好的,系统配置完毕,检查完毕。已连接网络摄像头,请检查。现在让我们让这一切真正做点什么吧!为了进行网络摄像头捕捉,我们将使用 Linux 动作捕捉,讽刺地命名为运动。因此,让我们继续安装它。运行以下命令,指示 apt-get 下载并安装 motion 包:

$ sudo apt-get install motion

您的输出应该如下所示:

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

ffmpeg libav-tools libavcodec53 libavdevice53 libavfilter2 libavformat53 libavutil51 libdc1394-22 libdirac-You

libjack-jackd2-0 libmp3lame0 libpostproc52 libpq5 libraw1394-11 libschroedinger-1.0-0 libspeex1 libswscale2 libtheora0 libva1

libvpx1 libx264-123 libxvidcore4

Suggested packages:

jackd2 libraw1394-doc speex mysql-client postgresql-client

The following NEW packages will be installed:

ffmpeg libav-tools libavcodec53 libavdevice53 libavfilter2 libavformat53 libavutil51 libdc1394-22 libdirac-encoder0 libgsm1

libjack-jackd2-0 libmp3lame0 libpostproc52 libpq5 libraw1394-11 libschroedinger-1.0-0 libspeex1 libswscale2 libtheora0 libva1

libvpx1 libx264-123 libxvidcore4 motion

0 upgraded, 24 newly installed, 0 to remove and 71 not upgraded.

Need to get 8,365 kB of archives.

After this operation, 17.6 MB of additional disk space will be used.

Do you want to continue [Y/n]? y

我不知道你怎么想,但是我太兴奋了,不想为所有的设置和配置费心;让我们启动 motion,看看它会做什么!以此开始:

$ motion –s

摄像机上的灯亮了,开拍!开始挥舞和移动,因为你想它抓住你!

[1] Changes:  3374 - noise level: 15

[1] Changes:  3198 - noise level: 15

[1] Changes:  3011 - noise level: 15

[1] Changes:  2922 - noise level: 15

[1] Changes:  2555 - noise level: 15

[1] Changes:  2390 - noise level: 15

[1] Changes:  2491 - noise level: 15

[1] Changes:  2874 - noise level: 15

[1] Changes:  2817 - noise level: 15

[1] Changes:  3238 - noise level: 15

[1] Changes:  3093 - noise level: 15

[1] Motion detected - starting event 1

[1] File of type 1 saved to: ./01-20120910203217-05.jpg

[1] Changes:  2912 - noise level: 15

[1] File of type 1 saved to: ./01-20120910203217-06.jpg

[1] Changes:  2480 - noise level: 15

[1] File of type 1 saved to: ./01-20120910203217-07.jpg

就这样,你可以看到它捕捉图像中的变化,并记录你移动时噪声水平的任何变化。最后,它捕捉图像!如果根据您的 SD 卡速度,可能需要一段时间来写出图像文件,请耐心等待。太棒了,工作起来很有魅力,要取消应用程序,您可以继续按 Ctrl+C。如果您愿意,您可以继续使用控制台登录,查看它捕获的任何图像。检查输出通常是一个好主意,因为您的网络摄像头驱动程序可能需要微调,或者可能不会生成有效的输出。如果不想出线缆和 HDMI,可以用scp之类的工具把这些图片复制下来。从 Windows 机器上,您可以使用 winscp 之类的工具来复制任何文件。如果要复制到 Mac 或 Linux 系统,只需发出以下命令来复制文件:

$ scp <raspberry pi’s ip>:/home/pi/*.jpg

Note

请记住scp命令末尾的句号,这很重要,因为它是命令的目的标识符。

这个命令说要从目录/home/pi中 IP 标识的 Raspberry Pi 上的服务器复制pi用户的主目录和你登录时第一个会到的地方(我说我激动了吧?)并匹配任何以.jpg结尾的文件。末尾的最后一个句点是目的地:在 Linux 中,句点是对当前目录的引用,所以这就是我们要复制的地方。

好了,现在我们已经玩转了图片,让我们进入正题。树莓 sPi 的目标是在没有干预的情况下发挥其功能;这意味着我们将需要有运动应用功能,而不需要我们告诉它。拉斯边已经帮我们处理了大部分的事情,但是还有一些小事我们需要做。

Note

您将需要以 root 用户身份编辑这些文件,所以记得用sudo启动您的文本编辑器。

首先打开并编辑文件/etc/default/motion,将行start_motion_daemon=no改为start_motion_daemon=yes;这个文件决定了当我们发出守护进程的start命令时,守护进程是否会启动,让它按命令运行正是我们想要的。现在我们处理配置,所以继续打开它。文件是/etc/motion/motion.conf,所以打开它。首先你会注意到守护模式将被设置为off,所以继续设置为on,因为我们希望 motion 作为守护启动,这意味着它将在后台运行。接下来要检查的是videodevice行,确保列出的设备与我们之前确认的设备相匹配(对我们大多数人来说,应该是/dev/video0)。

接下来,我们开始深入了解具体情况。首先我们可以修改heightwidthframerate。默认设置是以 320 x 240 的分辨率每秒捕捉两幅图像。这将创建一个大约 12 Kb 大小的文件,您可以通过检查我们之前在运动捕捉测试期间生成的文件来进行检查。你可以在你认为合适的时候增加这个数字;请记住,不要超过您的网络摄像头的最大可用分辨率,并且每个文件的大小都会随着分辨率的增加而增加。

接下来是threshold。阈值是捕获图像所需的变化量。您现在可以保留这个值,但以后要记住它,因为您可能希望使捕获更灵敏或更不灵敏。

接下来是ffmpeg_cap_new,它决定你是否要捕捉一个视频文件。我已经把这个关掉了,但是如果你想生成你的动作捕捉的视频文件,你可以开着它。这些文件生成为。swf 文件(想想 YouTube)但是你可以通过编辑ffmpeg_video_codec变量来改变它们。

最后,您可以更改target_dir,它表示当作为守护进程运行时,您将把图像文件输出到哪里。这一点很重要,因为你需要知道从哪里复制文件。此外,重要的是要意识到/tmp目录只是一个临时空间。每次重新启动操作系统时,这个临时空间都会被清空。

这种功能对我们来说是完美的,因为我们不想处理额外的文件,这些文件会留在磁盘上,直到我们把它清理掉;只需重新启动您的树莓 sPi,您就可以再次出发。然而,在某些情况下,我们可能希望在系统重启后保存这些文件——但以后会保存更多。

最后,保存所有更改并退出,这样我们就可以测试新配置了!我的配置显示在这里供您参考:

daemon on

process_id_file /var/run/motion/motion.pid

setup_mode off

videodevice /dev/video0

v4l2_palette 8

input 8

norm 0

frequency 0

rotate 0

width 320

height 240

framerate 2

minimum_frame_time 0

netcam_tolerant_check off

auto_brightness off

brightness 0

contrast 0

saturation 0

hue 0

roundrobin_frames 1

roundrobin_skip 1

switchfilter off

threshold 1500

threshold_tune off

noise_level 32

noise_tune on

despeckle EedDl

smart_mask_speed 0

lightswitch 0

minimum_motion_frames 1

pre_capture 0

post_capture 0

gap 60

max_mpeg_time 0

output_all off

output_normal on

output_motion off

quality 75

ppm off

ffmpeg_cap_new off

ffmpeg_cap_motion off

ffmpeg_timelapse 0

ffmpeg_timelapse_mode daily

ffmpeg_bps 500000

ffmpeg_variable_bitrate 0

ffmpeg_video_codec swf

ffmpeg_deinterlace off

snapshot_interval 0

locate off

text_right %Y-%m-%d\n%T-%q

text_changes off

text_event %Y%m%d%H%M%S

target_dir /tmp/motion

snapshot_filename %v-%Y%m%d%H%M%S-snapshot

jpeg_filename %v-%Y%m%d%H%M%S-%q

movie_filename %v-%Y%m%d%H%M%S

timelapse_filename %Y%m%d-timelapse

webcam_port 8081

webcam_quality 50

webcam_motion off

webcam_maxrate 1

webcam_localhost on

webcam_limit 0

control_port 8080

control_localhost on

control_html_output on

track_type 0

track_auto off

track_motorx 0

track_motory 0

track_maxx 0

track_maxy 0

track_iomojo_id 0

track_step_angle_x 10

track_step_angle_y 10

track_move_wait 10

track_speed 255

track_stepsize 40

这个测试将和之前的一样。我们只想启动 motion,并检查它是否能运行和捕捉图像。然而,这一次我们想要使用配置文件和 Linux start 命令,因为它允许我们模拟 Raspberry sPi 的加电。所以继续执行sudo /etc/init.d/motion start这应该开始运动。你应该看到你的相机灯亮了,如果你四处走动,你应该开始看到图像捕捉几乎立即出现在/tmp/motion(或任何你指向 target_dir 的地方)。您还可以通过键入以下命令来检查正在运行的运动进程,从而检查该进程是否正在运行:

$ ps –ef | grep motion

解决纷争

还不工作?回到连接网络摄像头的部分,拔下它,插回,并检查来自dmesg的输出。验证您在dmesg中看到的输出与您在检查您所说的网络摄像头设备时从udev中得到的匹配。运动套件安装正确吗?检查来自apt-get的输出,看它是否做到了;如果没有,请尝试重新安装或尝试以下方法:

$ apt-get ʧ˗reinstall install motion

motion –s在命令行执行 motion 会运行吗?如果没有,检查屏幕上的消息,这将有助于您了解哪里出错了。

如果都失败了,检查你的运动配置文件。你是不是不小心设置错了一个变量?是不是忘了把/etc/default/motion里的值设置成yes?运动守护程序正在运行,但你看不到图像出现在你给定的输出目录?如果没有,检查文件/var/log/messages/var/log/syslog,这是来自系统启动的守护进程的消息的存储库,包括 motion。之前屏幕上的输出现在应该在这个文件中。

我在测试这个设置时遇到的一个问题是,motion 守护程序无法写入到/tmp/motion目录,因为这个目录最初是由 root 用户创建的。我在/var/log/syslog中找到了下面一行,它清楚地显示了这个问题。

Mar 24 20:58:22 raspberrypi motion: [1] Error opening file /tmp/motion/01-20150324205822-01.jpg with mode w: Permission denied

为了解决这个问题,我必须更改该目录的权限,以授予“motion”用户启动 motion 守护程序的访问权限。这是通过下面的chown命令完成的

sudo chown motion /tmp/motion/

提醒自己

到目前为止,我们已经连接了一个网络摄像头,配置了网络摄像头,安装了运动检测软件,并将其配置为随着您的树莓 sPi 自动启动。现在我们有一个完全成熟的监控系统,你可以用它来监控你的敌人,并在入侵者进入你的密室时通知你。嗯,差不多了。您现在需要创建一个系统,允许您向自己发送消息,这样当入侵者进入时,您可以收到警报。

为此,我们将利用有史以来最古老、最有效的信息传递系统之一:电子邮件。然而,我们不会去建立我们自己的邮件服务器和域名;这是一个很大的任务,远远超出了我们在本章要做的范围。相反,我们的目标是建立一个轻量级的邮件客户端,将消息转发到邮件服务,然后通过你用来接收电子邮件的任何方便的间谍工具发送给你。既然你理解了这个计划,我们就开始吧。

安装 SSMTP

我们将用来把邮件发送到邮件服务器的应用程序叫做 SSMTP。SSMTP 是一个高度简化的邮件传输代理(MTA ),当系统管理员需要能够从服务器发送邮件时使用,但不需要设置为完全成熟的邮件域。这里的优势应该是显而易见的:一个明显不太密集的设置过程和低得多的开销——所有这些都应该让你尖叫树莓 Pi。

考虑到这些,我们开始吧。首先发出命令下载并安装 SSMTP 应用程序,然后安装它:

$ sudo apt-get install ssmtp

您的输出应该类似于我的:

$ sudo apt-get install ssmtp

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

libgnutls-openssl27

The following NEW packages will be installed:

libgnutls-openssl27 ssmtp

0 upgraded, 2 newly installed, 0 to remove and 71 not upgraded.

Need to get 272 kB of archives.

After this operation, 279 kB of additional disk space will be used.

Do you want to continue [Y/n]?

一旦我们安装了 SSMTP,我们需要配置它。SSMTP 配置文件是/etc/ssmtp/ssmtp.conf。用你最喜欢的文本编辑器打开它,然后开始。

我们需要配置的第一件事是邮件的目的地。大多数阅读这本书的人会有一些不同的和具体的位置,他们希望他们的邮件去。尽管所有优秀的间谍都希望尽可能高效,但我只能处理我面前的事情,所以我们将为每个人配置最通用和免费的选项:Gmail。

因此,我们需要配置邮件要发送到哪里;在 SSMTP,这由mailhub值决定。该值是我们将用来发送出站邮件的域的邮件服务器的 DNS 名称。这个名字传统上是mail.<yourdomain>.<whatever>,但对我们来说将是smtp.gmail.com:587,这是谷歌的 SMTP 服务器。

设置好 Gmail 服务器后,你可能已经注意到我们在末尾加了一个:587。你们当中好学的人会认出这是一个端口号。更细心的人会知道 587 不是 SMTP 的默认端口(它是端口 25)。这是专用于传输层安全性(TLS)电子邮件的端口(SSL 上的安全电子邮件)。这意味着我们需要添加另一对选项来确保我们拥有加密的通信:

UseTLS=YES

UseSTARTTLS=YES

下一个要配置的选项是hostname选项,这是 Raspberry sPi 列出的主机名。如果您有域,请列出 sPi 的主机名。如果没有,就给它一个raspberry.spi之类的。下一个选项应该是FromLineOverride=yes,如果我们愿意,它允许我们在电子邮件上设置“发件人”字段。

最后,最后一组选项与身份验证相关。这里有三个选项需要配置。前两个是最明显的:用户名和密码。所以继续添加AuthUser=username@gmail.comAuthPass=password。第三个选项有点复杂,是AuthMethod选项,用于指定允许用户向服务器注册的认证方法。我们将为 Google 使用的方法是LOGIN方法。尽管其他邮件服务器可能不要求指定这个,但是在 Google 中我们应该设置AuthMethod=LOGIN

就是这样;您的配置现在应该看起来像这样:

root=

Mailhub=smtp.gmail.com:587

UseTLS=YES

UseSTARTTLS=YES

Hostname=raspberry.spi

FromLineOverride=yes

AuthUser=username@gmail.com

AuthPass=password

AuthMethod=LOGIN

Note

这是不言而喻的,但是你应该总是有一个安全的根密码。

要做的最后一个更改是保护这些数据,这样除了我们想要的人之外,没有人可以读取该文件。这非常重要,因为你已经把宝贵的 GMail 密码放在文件里了!解决方案是更改权限,这样除了目标用户,没有人可以读取它。执行以下操作:

$ sudo chmod 640 /etc/ssmtp/ssmtp.conf

这将更改该文件,以便只有 root 用户可以访问它,并且只有邮件组的成员可以访问它。

一旦配置了 SSMTP,您需要做的就是调用它来发送电子邮件,并让它发送捕获的...等等。我们需要更多的东西。我们需要一种方法来调用 SSMTP,以便我们可以告诉它将文件发送到我们的电子邮件,并提醒我们注意入侵者。我们需要一个可以从命令行完成所有这些工作的工具。这里最好的工具是一个叫做mutt的工具。

安装和使用 mutt

这个工具是一个基于文本的电子邮件客户端,有一句绝妙的格言“所有的邮件客户端都很烂”。这个就差一点了。”(我们使用它的原因不是很明显吗?与其他邮件客户端相比,mutt的另一个好处是它很乐意发送文件系统中文件的附件——这是我们让 sPi 发送入侵者图像的关键。

现在您知道我们正在安装的是mutt,继续使用以下命令安装它:

$ sudo apt-get install mutt

您的输出应该如下所示:

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

libgpgme11 libpth20 libtokyocabinet9

Suggested packages:

gpgsm gnupg2 urlview mixmaster

The following NEW packages will be installed:

libgpgme11 libpth20 libtokyocabinet9 mutt

0 upgraded, 4 newly installed, 0 to remove and 71 not upgraded.

Need to get 1,985 kB of archives.

After this operation, 7,181 kB of additional disk space will be used.

mutt安装好了吗?很好。正如我前面提到的,mutt被设计成小巧、简单、易于使用和配置——这是崇高的目标。记住这一点,mutt 的设置过程非常简单:我们只需要告诉mutt如何使用我们的 MTA(也就是 SSMTP)。为此,我们需要创建一个隐藏在 Pi 用户主目录中的文件。文件是.muttrc,它将只包含一行:

set sendmail="/usr/sbin/ssmtp""

代替使用文本编辑器,我们将使用一个“欺骗”来做这件事。运行以下命令:

$ echo "set sendmail=\"/usr/sbin/ssmtp\"" > ∼/.muttrc

就这样。

Note

引号前的反斜杠是转义符。

您可以在 root 用户的主目录中查找文件.muttrc并检查其内容。是的,它就在那里,和预期的一模一样。.muttrc文件是一个配置文件,由mutt用来在启动时自动加载重要的配置选项。许多不同的应用程序使用以rc结尾的隐藏文件,所以如果你想知道一个应用程序是如何存储某些配置选项的,可以在你的主目录中查找以句号打头并以rc结尾的文件。

测试警报系统

既然我们已经安装并配置了 SSMTP 和mutt,我们需要对它们进行组合测试。奇怪的是,使用mutt的方法是运行mutt命令。语法相当简单,所以从命令行给自己发一封电子邮件。执行以下命令:

$ echo "the quick brown fox jumps over the lazy dog" | sudo mutt –s "[INTRUDER ALERT] Test of intruder system" <your email>@gmail.com

我知道这是一个很长的命令,但是不要担心,因为我马上会解释它。继续检查你的电子邮件;你应该有一个来自用户根的,如图 10-3 所示!

A978-1-4842-1162-5_10_Fig3_HTML.jpg

图 10-3。

E-mail from the Rasperry sPi

现在我将解释语法,以及我们将如何使用它从 sPi 发送警报消息。前面的消息可以分解成几个更小的片段。我使用的基本语法是:

echo <mail content> | mutt –s <subject> <recipient>

你可能想知道echo的用法。您需要生成将作为输出传递的值,然后让管道将其导入mutt,而不是作为参数提供。

Note

通过用引号将整个句子括起来,可以在 shell 命令中包含带有空格的整个句子。您甚至可以在命令中转义引号,以便在引号中创建引号!

我们还需要能够通过电子邮件发送附件。因为它提供了在发出的电子邮件中附加文件的功能。我选择使用mutt来创建 Raspberry sPi 的原因是因为它不仅易于配置,而且还提供了发送附件的能力。

用我们刚刚发送的电子邮件发送附件的语法如下:

echo <mail content> | mutt –s <subject> -a <filename> ˗˗ <recipient>

是的,就这么简单!–a表示附件,–-用于将附件与收件人分开。

解决纷争

一切都按预期进行了吗?如果没有,尝试从头开始配置 SSMTP 和mutt。当您发送电子邮件时,它是否会输出有关登录详细信息的错误?如果是这样,请仔细检查您的用户名和密码。这是关于不支持的登录类型的错误吗?如果是,检查 TLS 设置和AuthMethod设置。你的邮件服务器拼错了吗?它们的尾部是空白吗?即任何条目末尾的空格或制表符。当您更改权限时,您是否将它们移动得太远,以至于现在您无法再读取该文件?

如果您尝试以pi用户的身份发送电子邮件,而没有发送sudo,您也可能会遇到错误,因为pi用户不是您系统上mail组的成员。如果您希望允许pi用户或任何其他用户,您需要使用gpasswd添加他们,语法如下:

$ gpasswd –a <username> mail

好吧,都搞定了?你可以捕捉到入侵者的存在。你可以通过树莓 sPi 来提醒自己。您可以通过 sPi 将捕获的入侵者图像发送给自己。那还剩下什么?全部自动化。

将这一切结合在一起

到目前为止,我们已经完成了以下工作:

  • 将网络摄像头连接到树莓 sPi
  • 已安装并配置显示器应用程序以使用网络摄像头
  • 使用网络摄像头和显示器应用程序作为运动传感器并捕捉图像
  • 将 SSMTP 安装并配置为 MTA
  • 安装并配置mutt邮件应用程序以使用 SSMTP
  • 使用 SSMTP 和mutt从命令行向我们自己发送电子邮件

剩下的问题是,我们已经通过人工干预完成了大部分工作。我们需要一种解决方案,能够让图像捕获自动触发发送给我们的附有图像的电子邮件。尽管我确信有人已经想出了解决这个问题的软件方案,但是我们没有理由不能自己写一个解决方案!

理解问题

任何软件设计问题的第一步,不管多么小的工作,都是理解软件解决方案的确切需求是什么。让我们从列出我们的目标开始:

  • 新图像的捕获应该触发解决方案
  • 应发送包含任何新捕获图像的电子邮件
  • 应自动运行,无需手动启动

好吧,这似乎是我们需要的解决方案。但是,有了这两个主要要求,还有其他一些事情需要考虑。这些额外要求是:

  • 应该只发送新图像
  • 应该只发送由运动捕获的图像
  • 应用程序应该一直运行,不需要手动启动,就像 motion 一样

好吧,这似乎好一点了;我们现在非常确定我们的软件解决方案应该做什么。但是它应该如何做呢?也许我们应该对我们将要编写的应用程序如何实现其目标有一点具体的说明。

开发应用程序时我们应该考虑的一些事情包括:

  • 我们应该发送图像被捕获的时间
  • 我们应该定期检查和发送,但是考虑到电子邮件有延迟,半定期检查就足够了

好了,现在我们做饭。这些看起来像是构建我们的应用程序时需要记住的一些好的需求。我们明确了我们想要什么,以及我们应该如何实现它。既然我们确切地知道了我们的应用程序需要什么,我们就可以进入下一步了。

做决定

在确定了我们想要达到的目标后,下一步是决定如何达到目标。所以,第一个决定:我们应该怎么写?嗯,我们在这里想要实现的大部分是对 shell 命令的操作。我们希望列出图像文件,然后在另一个 shell 命令中使用这些图像文件向我们发送电子邮件警报。此外,您在本书的前面学习了 bash,因此它非常适合我们想要开发的内容。

好的,我们知道我们将用什么语言工作。接下来,我们将如何开始这一个?我认为有两种选择,这两种选择都将决定我们的发展方向:

  • 一种是从motion的启动脚本中执行应用程序,因为我们希望它们一起运行。这意味着我们可以确保它们同时运行,并且脚本需要一直运行,然后定期检查。
  • 第二个选项是让脚本定期自动执行。这意味着我们不需要启动它并保持脚本永久运行。这也意味着,如果最坏的情况发生,脚本死亡,我们不需要处理,并重新启动它,因为它会自动再次启动。这确实意味着我们需要一些东西来执行计时器上的脚本,但这可以由 cron 守护进程来处理。

所以,我们有两个选择来决定,但是让我们把这个决定推迟一会儿,因为我们需要首先考虑另一件事。

我们将如何处理这些图像?我们又有两个选择:

  • 首先是在发送后删除每张图片。这很好,因为这意味着我们可以节省空间,因为我们清理自己。
  • 第二种选择是跟踪我们所有的图片,只发送新的图片。这意味着要跟踪我们库存的图片,这样我们才能决定发送哪些图片。

所以,现在你明白了选项,是时候做决定了。我知道这很难决定,所以让我来帮你。不是四个可能的脚本,让我们把它缩小到两个:

  • 一个脚本将从cron运行,将搜索图像,发送它们,然后删除它们
  • 一个脚本,将开始与motion守护进程,将监测所有的文件,保持运行计数,然后识别何时有一个新的图像。

好了,现在我们有了两个工作设计,让我们进入下一步。

设计解决方案

“等等;你有两个解决方案,但你实际上没有选择一个。你这个大怪人。”我听你这么说,这是真的;我没有。因为我们有两种非常不同的方法来实现我们的目标,所以我们觉得最好是两种都涵盖,给你选择,并分享一些指导。所以,我们先来看看两者的共性;首先,它们都需要有一个文件夹的引用,用来存放motion捕获的文件。我们可以把它保存在一个变量中,当我们改变输出文件夹的时候再编辑它,但是要改变两个完整的文件,这需要很大的努力。这不是 Linux 的方式。所以让我们从motion配置文件中加载它,然后完成它。这意味着我们需要两个变量:一个变量将包含motion配置文件,第二个变量我们将动态创建以包含文件位置。使用MOTIONCONF=/etc/motion/motion.conf,包含文件名的变量足够简单。

Note

接下来的所有工作都是以根用户的身份完成的(您可以sudo su获得一个根 shell ),因为正是根用户将产生motion

下一步是取出变量,最好的方法是结合使用两个命令:一个是grep,它将在包含特定模式的文件中查找任何信息,在本例中是包含行target_dir的任何行,但是我们还需要确保避免注释,所以我们需要获取以target_dir开头的行。这可以通过简单地添加一个额外的符号来实现,这样grep就可以知道我们正在寻找一个以我们想要的值开始的值。这给了我们一个grep "^target_dir" $MOTIONCONF的命令。如果执行此命令,您将看到以下结果:

root @raspberrypi ∼ $ grep "^target_dir" $MOTIONCONF

target_dir /tmp/motion

现在,我们命令的下一个问题出现了:我们需要去掉target_dir部分,这样我们就只有我们想要的位置了。要删除第一部分,我们需要使用awk命令,默认情况下,它会在空白值处分割给定的数据。这是完美的,然后我们只需要打印结果的第二个值。因此,在我们的命令中构建这个,我们得到这个: ''

root@raspberrypi ∼ $ grep "^target_dir" $MOTIONCONF | awk ’{ print $2}’

/tmp/motion

现在剩下的就是将结果放入一个变量中,这是用反勾符号完成的,给我们一个最终的结果:

MOTIONDIR=’ grep "^target_dir" $MOTIONCONF | awk ’{ print $2}’’

现在,有一件事你可能没有考虑到:如果这个目录没有创建,motion 会在捕捉到第一张图片时创建它,但这可能需要几个小时。我们现在就需要它,所以让我们检查一下它是否存在,如果不存在,就创建它。查看目录是否存在的检查是if [ -d < directory name > ]。我们还需要添加一个注释来查看该目录是否不存在,所以在–d前添加一个感叹号,表示不存在。最后,将这个与一个mkdir混合,你应该得到下面的if语句:

if [ ! -d $MOTIONDIR ]; then

mkdir $MOTIONDIR

fi

在创建目录的同时,您需要确保它属于正确的用户。motion守护进程是由 root 运行的,但是这个所有权被传递给了motion,所以您需要给这个命令添加一个chown,它给出了这个值:

if [ ! -d $MOTIONDIR ]; then

mkdir $MOTIONDIR

chown motion $MOTIONDIR

fi

好了,现在我们有了文件所在的目录,我们需要写一些代码来检查它并计算文件的数量。通常,您会认为“好极了,让我们使用ls来列出目录中的文件。”但是这在没有文件的情况下没有帮助,因为ls会给我们一个错误。为此,我们需要使用find命令。找到所有的。jpg 文件,我们需要向find the following添加一对参数:

  • 表示不要在任何子目录中进行搜索
  • –type f告诉它只搜索文件

我还将命令放在一对括号中,这意味着该文件将被视为一个数组。这给了我们这个命令:

LISTFILES=(’find $MOTIONDIR –maxdepth 1 –type f’)

现在,如果有非图像文件,我们还应该添加一个grep来只取出。jpg 文件。一个简单的grep用于任何以。jpg(使用$操作符)应该足够了。这将为我们提供以下信息:

LISTFILES=(’find $MOTIONDIR –maxdepth 1 –type f | grep jpg$’)

现在我们需要使用wc -l命令获得列表中文件的数量。这将列出一个目录中的所有文件,如果我们用-l参数把它传给wc,我们将得到一个给定文件夹中文件的数量。这给了我们下一行:

NUMFILES=’ find $MOTIONDIR -maxdepth 1 -type f | grep jpg$ | wc -l’

我们现在可以编写最后一段两个脚本通用的代码:发送图像文件和消息的mutt邮件程序行。我们发送的原始文件很好,但是我在这里做了一点修改,为附件添加了一个变量名,即变量IMAGEFILE。我还添加了一个新的–F /root/.muttrc选项,强制mutt使用我们创建的根muttrc文件。新邮件行是这样的:

echo -e "Warning,\nAn intruder was detected at ’date’\nPlease see the image attached for details"| mutt –F /root/.muttrc –s "[INTURDER ALERT] Intruder Detected" -a $IMAGEFILE ˗˗ you@gmail.com

如你所见,有点拗口。我添加了一些漂亮的正文,如下所示:

Warning,

An intruder was detected at Sat Sep 15 22:50:32 EST 2012

Please see the image attached for details

您可能会问自己,我是如何在那里获得这些换行符的,以及我是如何在电子邮件中获得非常好的日期和时间输出的。日期和时间来自 shell date命令,我将它放在反勾号中以给出输出。我还添加了一些\n,它们是对换行符的引用,但是只有当你给 echo 一个–e参数来告诉它解释特殊的转义值的时候。现在我们有了一个代码块,让我们从 1 号脚本开始,cron 执行了 run once 脚本。

脚本 1

首先,让我们回顾一下到目前为止我们所拥有的;我们可以得到正确的工作目录中文件的数量。下一步是检查该数字是否显示确实有文件要处理,也就是说> 0。这意味着我们需要下面的if语句:

if [ $NUMFILES -gt 0 ]; then

有了我们的if语句,我们现在应该知道是否有需要紧急发送的文件。现在我们只需要遍历列表,将每个列表作为电子邮件发送,然后删除它。要遍历任何东西,需要使用循环;在这种情况下,我们将使用一个for循环。这个循环将把列表中的每张图片作为它自己的变量分开,允许我们一个接一个地对每张图片采取行动。该循环将如下所示,其中IMAGEFILE是列表中的当前图像;每次for循环再次开始时,该图像变为列表中的下一个图像。当列表中没有更多的图像需要处理时,for循环将会结束。

for IMAGEFILE in $LISTFILES

Note

记得chmod +x你的脚本,以便它可以被执行!

好吧,就这样。我们有所有的代码块,所以让我们组装。最终的脚本应该是这样的:

#!/bin/bash

MOTIONCONF=/etc/motion/motion.conf

MOTIONDIR=’ sudo grep "^target_dir" $MOTIONCONF | awk ’{ print $2}’’

if [ ! -d $MOTIONDIR ]; then

mkdir $MOTIONDIR

chown motion $MOTIONDIR

fi

LISTFILES=(’find $MOTIONDIR -maxdepth 1 -type f | grep jpg$’)

NUMFILES=’ find $MOTIONDIR -maxdepth 1 -type f | grep jpg$ | wc -l’

if [ $NUMFILES -gt 0 ]; then

for IMAGEFILE in $LISTFILES

do

echo -e "Warning,\nAn intruder was detected at ’date’\nPlease see the image attached for details" \

| mutt -s "[INTURDER ALERT] Intruder Detected" \

–F /root/.muttrc \

-a $IMAGEFILE ˗˗ <your email>

rm $IMAGEFILE

done

fi

脚本 2

因为我们已经讨论完了剧本 1,所以让我们开始写剧本 2。这个稍微复杂一点。我们需要做的第一件事是添加一个计数器,它会告诉我们已经处理了多少图像。最初,我们可以将其设置为 0。所以我们用LASTCOUNT=$ NUMFILES来初始化这个变量。下一步是创建一个简单的循环,让应用程序永远运行下去;事实上,这是最简单的一种循环,简单来说就是while true(关于while循环的更多信息,参见第七章)。

现在在循环中,我们需要更新LASTCOUNTNUMFILES,所以让这些命令再次运行来更新它们的值。我们需要进行比较,看看我们是否添加了新的东西(例如,NUMFILES大于LASTCOUNT)。如果是,我们需要读出最新的文件并发送出去。通常,这听起来像是一个if语句的位置,但在这种情况下,我们将使用一个while循环,因为我们希望在LASTCOUNT大于NUMFILES时执行操作,所以我们的第二个内部while循环是这样的:

while [ $LASTCOUNT -lt $NUMFILES ]

现在我们只需要更新;首先,我们需要给每个新图像一个文件名。谢天谢地,它们是按顺序排列的,因为运动包是按顺序给它们命名的。这意味着我们只需要去掉顶部的 X 来弥补差额。这意味着我们需要一个迭代器值,这样我们就可以计算出前 X 个值。因此,在第二个循环之外但在第一个循环之内创建一个设置为 0 的ITERATOR,所以我们在每一轮都重置它。

现在我们有了这个迭代器,我们可以用它和LISTFILES来提取每个数字。因为我们将LISTFILES视为一个数组,所以我们只需要使用ITERATOR来访问该数组元素。我们需要用一对花括号将整个数组输出括起来,因为这将执行数组解引用并给出输出值:

IMAGEFILE=${LISTFILES[$ITERATOR]}

最后,我们需要增加LASTCOUNTITERATOR,这样它们就可以在我们处理每张图像时计数。这是通过以下方式完成的:

LASTCOUNT=’expr $LASTCOUNT + 1’ and ITERATOR=’expr $ITERATOR + 1’

expr函数将给定的值视为数学表达式并返回它们的结果,这在我们想要将值增加 1 时非常理想。

所以,现在我们需要组装每一项代码。当它们放在一起时,应该是这样的:

#!/bin/bash

MOTIONCONF=/etc/motion/motion.conf

MOTIONDIR=’ sudo grep "^target_dir" $MOTIONCONF | awk ’{ print $2}’’

if [ ! -d $MOTIONDIR ]; then

mkdir $MOTIONDIR

chown motion $MOTIONDIR

fi

LISTFILES=’find $MOTIONDIR -maxdepth 1 -type f | grep jpg$’

NUMFILES=’find $MOTIONDIR -maxdepth 1 -type f | grep jpg$ | wc -l’

LASTCOUNT=0

while true

do

LISTFILES=(’find $MOTIONDIR -maxdepth 1 -type f | grep jpg$’)

NUMFILES=’find $MOTIONDIR -maxdepth 1 -type f | grep jpg$ | wc -l’

ITERATOR=0

while [ $LASTCOUNT -lt $NUMFILES ];

do

IMAGEFILE=${LISTFILES[$ITERATOR]}

echo -e "Warning,\nAn intruder was detected at ’date’\nPlease see the image attached for details" \

| mutt –F /root/.muttrc \

-s "[INTURDER ALERT] Intruder Detected" \

-a $IMAGEFILE ˗˗ <your email> LASTCOUNT=’expr $LASTCOUNT + 1’ ITERATOR=’expr $ITERATOR + 1’ done sleep 1

done

测试

所以,让我们来看看这个超级剧本。确保 motion 启动并运行,然后执行您的脚本。

Note

若要取消运行脚本,请按 Ctrl + c 停止执行。这是停止脚本 2 的唯一方法。

您不应该期望看到任何输出,所以只需查看您的电子邮件收件箱(见图 10-4 )。

A978-1-4842-1162-5_10_Fig4_HTML.jpg

图 10-4。

One full inbox!

如你所见,这很有效。事实上,它工作得相当好;我有 18 封来自入侵检测系统的未读邮件。完美!现在,我们已经测试了该脚本可以向我们发送来自 motion 的新图像的电子邮件,我们需要配置该脚本,以便它可以自动启动——这是仍未满足的最后一个要求。回过头来看,我们决定以不同的方式启动这两个脚本:脚本 1 将被添加到cron中,脚本 2 将被添加到运动启动脚本中,这样它将与运动一起运行!

对于脚本 1,事情相当简单。cron将自动评估它是否应该每分钟运行一次,所以我们需要做的就是有一个将一直运行的cron作业。所以以 root 用户身份(因为我们想以 root 用户身份运行它),打开带有crontab –ecron表,并输入以下内容:

* * * * * /root/script1.sh

就是这样;我们没有添加脚本 1 来每分钟从一个crontab条目开始运行。这样我们每分钟都会检查一下/tmp/motion里有没有文件,发给我们然后删除,这就满足了我们所有的要求。

第二个脚本的launch方法需要修改动作/etc/init.d/motionlaunch脚本,所以继续打开它作为 root 编辑。任何这些启动脚本的基本格式都有一个大型 case 语句,用于处理要执行的给定操作,如启动、停止、重启或任何其他数量的必需 case。所以找线start,这是我们要增强的动作。在这里,我们可以看到有许多嵌套的检查和准备工作;我们希望我们的脚本只在 motion 之后启动,这是由start - stop - daemon命令调用的。

因此,在这之后,继续添加一个链接到您的脚本;然后在末尾加一个&。“与”符号表示“运行这个脚本,然后让它在后台运行。”如果我们不这样做,启动脚本会认为它的下一个功能是等待脚本结束,但它不会!您最终更新的开始部分应该如下所示:

start)

if check_daemon_enabled ; then

if ! [ -d /var/run/motion ]; then

mkdir /var/run/motion

fi

chown motion:motion /var/run/motion

log_daemon_msg "Starting $DESC" "$NAME"

if start-stop-daemon ˗˗start ˗˗oknodo ˗˗exec $DAEMON -b ˗˗chuid motion ; then

/root/script2.sh &

log_end_msg 0

else

log_end_msg 1

RET=1

fi

fi

;;

一旦你完成了编辑,就去重启你的 Pi;然后重新登录并执行检查,看看脚本是否正在运行!是吗?太棒了,你现在有了自己的全自动树莓 sPi!

$ ps -ef | grep script

root      2058     1  0 11:23 pts/0    00:00:00 /bin/bash /home/pi/script2.sh

解决纷争

我相信您现在已经意识到,在进行软件开发时,有太多的事情可能会出错。所以有足够的空间进行故障排除。这让我给你建议去哪里找有点困难。也就是说,你可以做很多事情来简化诊断。

我开始写脚本的原因是写出每一小段代码,然后添加进去。这是所谓的隔离测试的一个版本,它涉及尽可能多地隔离代码的特定部分,以使用受控输入来执行它,然后评估输出,以查看它们是否如您所愿地工作。

可以想象,一个模块一个模块地做意味着您可以在应用程序成长的过程中测试它的每一点。

下一件事是利用echo命令输出一个工作值或代码中的一个位置。您可以看到应用程序正在处理什么,以及它在代码中的什么位置运行,这让您可以发现意外的值以及软件在什么地方出现了故障。

最后,如果所有其他方法都失败了,将 shell 从#!/bin/bash更改为#!/bin/bash –x。添加–x会将 bash 实例置于调试模式,并输出它经历的每个变量、每个操作和每个更改。虽然可能会有很多输出,但这是查看一个麻烦的应用程序中发生了什么的理想方式。

从这里去哪里

哇哦。我们已经从起点走了很长一段路。我们有:

  • 将网络摄像头连接到我们的树莓 sPi
  • 已安装并配置显示器应用程序以使用网络摄像头
  • 使用网络摄像头和显示器应用程序作为运动传感器并捕捉图像
  • 将 ssmtp 安装和配置为 MTA
  • 安装并配置mutt邮件应用程序以使用 SSMTP
  • 使用 SSMTP 和mutt从命令行发送电子邮件给我们自己
  • 写了两个脚本来自动获取任何新的图像文件,然后使用上述所有内容通过电子邮件发送给我们自己

这是相当大的成就,但是现在呢?作为间谍,你们都知道适应性是成功的关键。我们在这里所经历的应该是一个如何利用 motion、SSMTPmutt等软件的指南。你现在应该也熟悉了使用dmesg,以及如何定位新加载的设备,并将它们集成到你的系统中。最后,您应该看到如何使用 bash 编写的脚本来填补应用程序堆栈中的空白并解决复杂的问题。那么你在这里能做什么?

  • 你可以添加一个无线适配器,这样你就不需要布线,给你一个无线树莓 sPi,你可以藏在最无害的地方。

  • 您可以添加一个 USB 电池组,这样就不需要使用电源插座了。

  • 您可以在/tmp之外更改文件存储的目录。这样,您可以将图像保存到磁盘上,以便日后查看。

  • Or you can go full Bond. I’ve taken my inspiration further afield, modified the software to capture full video, and disabled the image capture. I changed the storage location to be away from /tmp and I’ve attached a USB battery pack. I then added a little tape to hold this all together and mounted the webcam inside a hat (see Figure 10-5).

    A978-1-4842-1162-5_10_Fig5_HTML.jpg

    图 10-5。

    Maybe I should have invested in a stetson!

摘要

你应该能看懂dmesg的输出,知道udev是怎么工作的。您还应该能够配置运动应用程序、SSMTP 应用程序和mutt应用程序。最后,您应该能够发送具有不同收件人、正文、主题和附件的电子邮件。

十一、Pi 媒体中心

树莓派的美妙之处在于它是一个非常灵活的设备,它的潜在用途几乎是无限的。您可以使用 Pi 做任何事情,它有一系列外围输入端口,可以很好地使用。

您还应该知道,虽然您的 Pi 可以通过标准 HDMI 显示,但设备的功能并不止于此。它可以以 1920 x 1080 的分辨率显示,通常称为 1080P,这是高清的基准水平。你小小的 Raspberry Pi 能够以全高清分辨率显示视频,由于 HDMI 的声音交错,它还可以在视频的同一频道播放音频。这是本章的目标;我们将利用 Pi 的媒体播放功能来创建两种不同的 Pi 媒体中心。一个是视频播放中心,你可以用它在网络上播放视频。它可以连接到你的电视上,并允许你接入互联网观看视频。第二个是无线播放设备,使您能够远程流式播放您的音乐收藏,并通过网络播放。

与 XBMC 的视频

如前所述,树莓派的一大优势是它可以全高清播放,但我们需要一种方式来利用这一点,这就是 XBMC 的用武之地。

XBMC(XBox Media Center 的缩写)最初是作为最初(胖)XBox 的媒体中心而设计的。人们非常喜欢这个项目,后来它被移植到了世界上几乎所有的操作系统上,包括但不限于 Windows、Android、OS X 和 iOS。甚至有一个名为 XMBCbuntu 的成熟的独立版本,它是 Ubuntu 的一个端口,已经安装、预配置了 XBMC,可以开箱即用。鉴于其广泛的用途、开放源代码的特性和易于使用的特性,它已经被移植和派生了很多次,包括 MediaPortal、Plex、Voddlern 和 Boxee。这显示了媒体中心系统有多受欢迎;再举一个例子,Boxee 制造了一款名为 Boxee Box 的小型设备,售价高达 200 美元。我们正在创造的是一个同样强大的工具,而且只需要 35 美元——圆周率的价格。既然你们都对媒体中心光明灿烂的未来感到兴奋,是时候好好利用它了。

您已经读到了这本书的结尾,所以是时候从应用程序源代码开始进行一次正确的 Linux 安装了。虽然大多数应用程序都是通过apt-get预打包的,但也有一些不是这样,它们需要编译。从源代码安装 XBMC 是一个有点复杂的过程,非常耗时。我们选择从源代码编译它,因为它不仅可以帮助您完成在 Linux 中运行应用程序的一种更复杂的方法,而且还意味着我们的 XBMC 安装针对我们的系统进行了优化,因为我们已经在自己的系统上构建了它。历史上,从源代码进行编译被认为是一个艰巨的过程,但是随着使用 Linux 的人数的增长,对简单易用的安装工具的需求也在增长,预编译二进制安装系统如apt-get也在兴起。但是和所有事情一样,有时使用预编译并不如从头开始,随着时间的推移,编译工具已经发展起来,变得更加容易使用。当有人指导你完成这个过程时,也更容易做到——这就是本书的全部内容。

所以让我们开始吧。首先,我已经离开了 Raspbian 的主要版本,转而使用 Raspbian 的一个稍微精简的版本,名为 Pisces,可以从 Raspbian 的 www.raspbian.org/PiscesImages 获得。我用双鱼座,因为它已经被削减,不包括太多的开销,这意味着更多的权力做我们想做的事情:播放电影!下载并安装这个映像到 SD 卡上(你需要一个 4 GB 的空间),然后启动并把操作系统连接到互联网上,这样你就可以使用它了。默认用户是raspbian,密码也是raspbian,也是 root 密码。

OSMC

让 XBMC 在您的 Pi 上工作有一个简单得多的方法:使用一个名为 OSMC 的 Raspbian 预构建版本(以前的 RaspMC)。你可以下载一个 OSMC 的安装程序,然后把它放到 SD 卡上,就像你在 Raspbian 上做的那样。你可以从 https://osmc.tv/ 下载这张图片。此安装非常简单,需要 15-25 分钟。您只需将您的 Pi 连接到您的网络,打开它,然后安装程序就会运行。它会从网上下载所有需要的东西,然后自己安装。这是目前为止让 XBMC 在你的 Pi 上运行的最简单的方法。对于那些选择使用 OSMC 的人,你可以跳到本章的“开始和使用 XBMC”一节。

Note

如果ifconfig缺失,使用apt-get安装net-tools包。更多关于apt-get的信息,请参见第三章。

一旦你进入了操作系统,是时候发出一些命令并开始安装 XBMC 了。这是一个非常漫长的过程:编译器比使用apt-get要慢得多,因为apt-get安装的所有软件都是预编译的,因此省去了一些步骤。在这种情况下,编译需要大约 12 个小时——是的,几个小时,半天。我发现最好让最终编译通宵运行,这样我就不会忍不住一坐就是几个小时。

由于 ARM 处理器的性质和工作速度,这个过程需要很长时间。这意味着编译需要更长的时间,但我们可以在更低的功率水平上做同样多的工作。

要构建的设置

让我们从构建开始。第一步是确保我们可以将尽可能多的能力和内存转移到编译器上。在核心 Raspbian 中,我们使用了rapsi-config命令,但是 Pisces 没有这个控制脚本,所以您必须手动更改它,用不同的文件替换start.elf文件,这将改变系统资源的分配方式。运行以下命令:

$ sudo cp /boot/arm224_start.elf /boot/start.elf

这将把分配给系统 224 MB 和分配给显卡 32 MB 的版本复制到系统中使用。现在,我们需要在系统中注册这一配置更改,然后通过发出以下两个命令重新启动,使更改生效:

$ sudo rpi-update

$ sudo reboot

一旦您的系统重新启动,并且备份并运行,最好升级操作系统,以确保它运行的是最新版本的软件。为此,我们将利用apt-get,告诉它用来自互联网的最新版本的配置更新自己,然后升级您系统上所有可用的软件包。为此,发出以下命令:

$ sudo apt-get update

$ sudo apt-get upgrade

这个执行需要一点时间,因为它需要下载、解包和替换大量的系统组件。所以让它运行起来,然后去喝杯咖啡;回来的时候应该就完成了,可以继续下一步了。

Note

其中一些软件包可能已经安装在您的系统上。我们包括它们,因为它们可能不是为每个人安装的。

下一步是安装软件包,给我们编译的能力;它们包括基本的构建工具、自动配置工具、压缩和解压缩工具等等。要安装这些工具,请运行以下命令:

$ sudo apt-get install build-essential autoconf ccache gawk gperf mesa-utils zip unzip

Reading package lists... Done

Building dependency tree

Reading state information... Done

build-essential is already the newest version.

The following packages were automatically installed and are no longer required:

libcdio-cdda0 libcdio-paranoia0 libcdio10 libcelt0-0 libdb4.8 librpmio2

Use ’apt-get autoremove’ to remove them.

The following extra packages will be installed:

automake autotools-dev libglew1.7 libsigsegv2

Suggested packages:

autoconf2.13 autoconf-archive gnu-standards autoconf-doc libtool gettext distcc gawk-doc glew-utils

The following NEW packages will be installed:

autoconf automake autotools-dev ccache gawk gperf libglew1.7 libsigsegv2 mesa-utils

The following packages will be upgraded:

unzip zip

2 upgraded, 9 newly installed, 0 to remove and 187 not upgraded.

Need to get 2,647 kB/3,174 kB of archives.

After this operation, 7,143 kB of additional disk space will be used.

Do you want to continue [Y/n]?

一旦您安装了这些基本的软件包,就可以继续进行更大的安装工作了。我们现在需要安装一些软件包,这些软件包将安装视频和解码器库以及专门的图形库。除了所有这些之外,您还需要安装一些其他的软件包,以便能够远程连接到 XBMC。这个命令非常长,所以我建议您从 Apress 网站下载源代码。该包中有一个脚本将为您执行这些命令。安装如此庞大数量的软件包的命令如下:

$ sudo apt-get install autotools-dev comerr-dev dpkg-dev libalsaplayer-dev \

libapt-pkg-dev libasound2-dev libass-dev libatk1.0-dev \

libavahi-client-dev libavahi-common-dev libavcodec-dev libavformat-dev \

libavutil-dev libbison-dev libbluray-dev libboost1.49-dev \

libbz2-dev libc-dev-bin libc6-dev libcaca-dev libcairo2-dev \

libcdio-dev libclalsadrv-dev libcrypto++-dev libcups2-dev libcurl3-gnutls-dev \

libdbus-1-dev libdbus-glib-1-dev libdirectfb-dev libdrm-dev libegl1-mesa-dev \

libelf-dev libenca-dev libept-dev libevent-dev libexpat1-dev libflac-dev \

libfontconfig1-dev libfreetype6-dev libfribidi-dev libgconf2-dev \

libgcrypt11-dev libgdk-pixbuf2.0-dev libgl1-mesa-dev libgles2-mesa-dev \

libglew-dev libglewmx-dev libglib2.0-dev libglu1-mesa-dev \

libgnome-keyring-dev libgnutls-dev libgpg-error-dev libgtk2.0-dev libhal-dev \

libhunspell-dev libice-dev libicu-dev libidn11-dev libiso9660-dev \

libjasper-dev libjbig-dev libjconv-dev libjpeg8-dev libkrb5-dev \

libldap2-dev libltdl-dev liblzo2-dev libmad0-dev libmicrohttpd-dev \

libmodplug-dev libmp3lame-dev libmpeg2-4-dev libmysqlclient-dev \

libncurses5-dev libnspr4-dev libnss3-dev libogg-dev libopenal-dev \

libp11-kit-dev libpam0g-dev libpango1.0-dev libpcre++-dev libpcre3-dev \

libpixman-1-dev libpng12-dev libprotobuf-dev libpthread-stubs0-dev \

libpulse-dev librtmp-dev libsamplerate0-dev \

libsdl-image1.2-dev libsdl1.2-dev libslang2-dev \

libsm-dev libsmbclient-dev libspeex-dev \

libsqlite3-dev libssh-dev libssh2-1-dev libssl-dev libstdc++6-4.6-dev \

libtagcoll2-dev libtasn1-3-dev libtiff4-dev libtinfo-dev libtinyxml-dev \

libts-dev libudev-dev libv8-dev libva-dev libvdpau-dev \

libvorbis-dev libvpx-dev libwebp-dev libwibble-dev \

libx11-dev libx11-xcb-dev libxapian-dev libxau-dev \

libxcb-glx0-dev libxcb-render0-dev libxcb-shm0-dev \

libxcb1-dev libxcomposite-dev libxcursor-dev libxdamage-dev \

libxdmcp-dev libxext-dev libxfixes-dev libxft-dev libxi-dev \

libxinerama-dev libxml2-dev libxmu-dev libxrandr-dev \

libxrender-dev libxslt1-dev libxss-dev libxt-dev \

libxtst-dev libxxf86vm-dev libyajl-dev libzip-dev linux-libc-dev \

lzma-dev mesa-common-dev python-dev python2.7-dev x11proto-composite-dev \

x11proto-core-dev x11proto-damage-dev x11proto-dri2-dev x11proto-fixes-dev \

x11proto-gl-dev x11proto-input-dev x11proto-kb-dev x11proto-randr-dev \

x11proto-record-dev x11proto-render-dev x11proto-scrnsaver-dev \

x11proto-xext-dev x11proto-xf86vidmode-dev x11proto-xinerama-dev xtrans-dev \

zlib1g-dev

这份包裹清单末尾有许多斜线;它们是换行符,表示应该执行当前的命令,然后会有另一行命令跟在后面。当你需要把长命令分成很多行时,换行符非常有用,就像我在这里做的那样。这个命令需要一段时间来运行,因为有大量的软件包需要下载和安装。所以执行这个命令,去做晚饭,然后回来。

一旦你安装了所有这些软件包,你需要复制一些特殊的文件到适当的位置,并创建其他链接到正确位置的文件,这样它们就可以被使用了。同样,它们将包含在我们创建的脚本中,以帮助简化这些命令的执行。

第一个是将 VideCoreIV include 文件从 Raspberry Pi 固件复制到/usr/include中。该目录是一个特殊的目录,编译器将从该目录中搜索要包含在构建中的库和文件。要将所有这些文件复制到正确的位置,请执行以下命令:

$ sudo cp -R /opt/vc/include/* /usr/include

$ sudo cp /opt/vc/include/interface/vcos/pthreads/* /usr/include/interface/vcos

现在,除了将这些文件复制到适当的位置之外,我们还需要将一些文件正确地链接到正确的位置,以便它们可以被读取。在上一个步骤中,我们复制了主要是源代码的包含文件,这次我们需要将固件的预编译部分链接到正确的位置,以便编译器在编译时读取。我们不是复制,而是链接,因为我们很乐意使用文件的当前位置并节省一些空间。运行以下命令:

$ sudo ln -fs /opt/vc/lib/libEGL.so /usr/lib/libEGL.so

$ sudo ln -fs /opt/vc/lib/libEGL.so /usr/lib/arm-linux-gnueabihf/libEGL.so

$ sudo ln -fs /opt/vc/lib/libEGL.so /usr/lib/arm-linux-gnueabihf/libEGL.so.1

$ sudo ln -fs /opt/vc/lib/libEGL_static.a /usr/lib/libEGL_static.a

$ sudo ln -fs /opt/vc/lib/libEGL_static.a /usr/lib/arm-linux-gnueabihf/libEGL_static.a

$ sudo ln -fs /opt/vc/lib/libGLESv2.so /usr/lib/libGLESv2.so

$ sudo ln -fs /opt/vc/lib/libGLESv2.so /usr/lib/arm-linux-gnueabihf/libGLESv2.so

$ sudo ln -fs /opt/vc/lib/libGLESv2.so /usr/lib/arm-linux-gnueabihf/libGLESv2.so.2

$ sudo ln -fs /opt/vc/lib/libGLESv2_static.a /usr/lib/libGLESv2_static.a

$ sudo ln -fs /opt/vc/lib/libGLESv2_static.a /usr/lib/arm-linux-gnueabihf/libGLESv2_static.a

$ sudo ln -fs /opt/vc/lib/libbcm_host.so /usr/lib/libbcm_host.so

$ sudo ln -fs /opt/vc/lib/libbcm_host.so /usr/lib/arm-linux-gnueabihf/libbcm_host.so

$ sudo ln -fs /opt/vc/lib/libvchiq_arm.a /usr/lib/libvchiq_arm.a

$ sudo ln -fs /opt/vc/lib/libvchiq_arm.a /usr/lib/arm-linux-gnueabihf/libvchiq_arm.a

$ sudo ln -fs /opt/vc/lib/libvchiq_arm.so /usr/lib/libvchiq_arm.so

$ sudo ln -fs /opt/vc/lib/libvchiq_arm.so /usr/lib/arm-linux-gnueabihf/libvchiq_arm.so

$ sudo ln -fs /opt/vc/lib/libvcos.a /usr/lib/libvcos.a

$ sudo ln -fs /opt/vc/lib/libvcos.a /usr/lib/arm-linux-gnueabihf/libvcos.a

$ sudo ln -fs /opt/vc/lib/libvcos.so /usr/lib/libvcos.so

$ sudo ln -fs /opt/vc/lib/libvcos.so /usr/lib/arm-linux-gnueabihf/libvcos.so

Note

我们发现,这些链接可以被其他进程删除,有时通过重新启动;如果有,您需要重新创建它们。

现在,您已经将所有文件链接到正确的位置,接下来获取源代码。使用以下命令将目录更改为您的主目录:

$ cd ∼

如果您不能键入波浪号(),您可以尝试使用dpkg-reconfigure keyboard-configuration重新配置 Pi 键盘布局,然后重新启动 Pi。你也可以只使用cd而不使用参数,因为它也会带你到你的主目录。波浪号只是一个引用当前用户主目录的符号。

现在您已经进入了您的主目录,是时候下载源代码了,这样您就可以使用它并正确地编译一切。令人欣慰的是,一个现代工具的出现使得下载源代码变得更加容易:Git,它是以 Linux 内核的 Linus Torvalds 命名的。Git 用于源代码管理和版本控制;所有用户都可以下载一组源代码的当前源代码版本,并将修改提交回中央存储库。

Note

这意味着我们总是下载最新的版本,但是如果 Git 中的当前版本有问题,我们可能会得到一个不太稳定的版本。大多数开发人员努力让他们的 Git 仓库保持良好的工作状态,但是这是需要注意的。

此时,我们要做的就是将源代码下载到我们的主目录中来使用它。为此,使用git命令,告诉它将源代码库克隆到系统上。我们还在命令中添加了–-depth 1,表示我们只想克隆源代码的最近 1 次修订(代码的绝对最新版本),避免获得大量额外的和不需要的历史代码。

通过运行以下命令启动克隆:

$ git clone ˗˗depth 1 git://github.com/xbmc/xbmc-rbp.git

Cloning into ’xbmc-rbp’...

remote: Counting objects: 35172, done.

remote: Compressing objects: 100% (22895/22895), done.

remote: Total 35172 (delta 15265), reused 27885 (delta 10698)

Receiving objects: 100% (35172/35172), 158.26 MiB | 385 KiB/s, done.

Resolving deltas: 100% (15265/15265), done.

既然我们已经克隆了 XBMC 的源代码,我们需要开始构建应用程序。这是迄今为止耗时最长的部分。将目录更改为新创建的xbmc-rbp目录,因为我们还需要完成最后几个步骤。

使用 Sed 和正则表达式更改文件

在我们开始构建我们的 XBMC 应用程序之前,我们需要对源代码做一些小的调整,以便它按照我们想要的方式编译。我们将使用名为 Sed(流编辑器的缩写)的工具,而不是手动进行这些更改。顾名思义,它接受一个文本流,然后对该文本进行编辑。Sed 的棘手之处在于它使用了一种高度专业化的语言,称为正则表达式,用于执行相当于查找和替换的功能。

正则表达式是从验证一组给定的数据以查看它是否符合给定的标准并在找到给定的例子时进行编辑的需要中发展而来的。虽然在编辑文本时,简单的查找和替换对于大多数人来说已经足够了,但是当您只想编辑给定句子中以 T 开头的第三个字母的单词时,如何执行查找和替换呢?电子邮件可能是正则表达式最简单的例子之一。您希望确认一个给定的字符串是一封有效的电子邮件:一封电子邮件将包含一个用户名(它来自谁)、一个域(它来自哪里,例如 Hotmail 或 Gmail),并且在它们之间将有一个 at ( @)符号。好的,我们可以只用一个通配符来实现,比如*。所以看起来像*@*的东西会是一封电子邮件,对吗?我们用来表示任何东西的*会拾取任何东西。甚至空格、数字、奇怪的符号等等。因此,我们需要一种方法来挑选由一串有效的电子邮件字符(字母、数字、句点、下划线)组成的内容,然后是@,,最后是有效的域。这将是一个字母集合,后跟一个句点,然后可能是另一组(或几组)字母。描述这些是令人疲惫的,这就是为什么我们有专门的语言来执行它们。

现在您已经理解了我们想要实现的目标,运行下面两个命令来修改文件tools/rbp/setup-sdk.sh。这些sed命令利用了–i选项,它表示编辑给定的文件:

$ sed -i ’s/USE_BUILDROOT=1/USE_BUILDROOT=0/’ tools/rbp/setup-sdk.sh

$ sed-I ' s/tool chain = /usr /local /BCM-gcc/tool chain = /usr/' tools/RBP/setup-SDK . sh。这些命令将变量USE_BUILDROOT从值1更改为值0,并使用TOOLCHAIN=/usr替换短语TOOLCHAIN=/usr/local/bcm-gcc的任何实例。编辑完tools/rbp/setup-sdk.sh文件后,您应该使用以下命令执行它:

$ sudo sh tools/rbp/setup-sdk.sh

该命令将生成一个 makefile,但不会在屏幕上显示任何内容。一旦完成,就该编辑新创建的tools/rbp/depends/xbmc/Makefile。然后,您需要做的就是在文件上运行最后一个sed,将一个#添加到任何cd $(SOURCE); $(CONFIGURE)实例的开头:

$ sed -i ’s/cd $(SOURCE); $(CONFIGURE)/#cd $(SOURCE); $(CONFIGURE)/’ tools/rbp/depends/xbmc/Makefile

$ sudo sed -i ’s/#include "vchost_config.h"/#include "linux\/vchost_config.h"/’ \ /usr/include/interface/vmcs_host/vcgencmd.h

$ sed -i ’s/-DSQUISH_USE_SSE=2 -msse2//’ lib/libsquish/Makefile.in

$ sed -i ’s/-DSQUISH_USE_SSE=2 -msse2//’ lib/libsquish/Makefile

我们所做的是改变我们的系统编译 XBMC 软件的方式,让它使用我们的一些系统库,而不是使用那些可以在 XBMC 源代码中找到的系统库。

既然 Makefile 已经创建好了,现在是编译的时候了!

编译源代码

大多数编译使用一个非常简单的逻辑:运行命令./configure来生成一个配置文件,它知道系统的组成。这会生成一个名为 makefile 的文件。这个文件使用稍微专业一点的语言,描述了对集合进行编译的方式。它本身不是一个执行代码的脚本;它是 make 应用程序将使用的方向的集合。

不幸是,这个编译器稍微高级一些。在运行配置和编译之前,我们需要使我们的配置工具与我们试图进行的设置相匹配。这需要一点时间来执行,所以开始吧,再喝一杯。

要执行的命令如下:

$ make -C tools/rbp/depends/xbmc/

该命令将在目录tools/rbp/depends/xbmc/中运行 make,这将生成配置文件。这个输出很长,但是当它成功完成时,您应该在控制台窗口上看到类似这样的内容:

examples/Makefile.am: installing ’./depcomp’

Makefile.am: installing ’./INSTALL’

autoreconf: Leaving directory ’lib/libdvd/libdvdnav’

Please (re)run configure...

#cd ../../../../; ./configure ˗˗prefix=/opt/xbmc-bcm/xbmc-bin ˗˗build=i686-linux ˗˗host=arm-bcm2708-linux-gnueabi ˗˗enable-gles ˗˗disable-sdl ˗˗disable-x11 ˗˗disable-xrandr ˗˗disable-openmax ˗˗disable-optical-drive ˗˗disable-dvdcss ˗˗disable-joystick ˗˗disable-debug ˗˗disable-crystalhd ˗˗disable-vtbdecoder ˗˗disable-vaapi ˗˗disable-vdpau ˗˗disable-pulse ˗˗disable-projectm ˗˗with-platform=raspberry-pi ˗˗disable-optimizations ˗˗enable-rpi-cec-api

#cd ../../../../; make -j 1

#cd ../../../../; make install

make: Leaving directory ’/home/raspbian/xbmc-rbp/tools/rbp/depends/xbmc’

既然配置实用程序的编译已经完成了执行配置的时间。这个configure命令非常长,同样,您可以在 Apress 源代码库中找到执行该命令的代码,这个configure命令是:

$ ./configure ˗˗prefix=/usr ˗˗build=arm-linux-gnueabihf ˗˗host=arm-linux-gnueabihf \

˗˗localstatedir=/var/lib ˗˗with-platform=raspberry-pi ˗˗disable-gl ˗˗enable-gles \

˗˗disable-x11 ˗˗disable-sdl ˗˗enable-ccache ˗˗enable-optimizations \

˗˗enable-external-libraries ˗˗disable-goom ˗˗disable-hal ˗˗disable-pulse \

˗˗disable-vaapi ˗˗disable-vdpau ˗˗disable-xrandr ˗˗disable-airplay \

˗˗disable-alsa ˗˗enable-avahi ˗˗disable-libbluray ˗˗disable-dvdcss \

˗˗disable-debug ˗˗disable-joystick ˗˗enable-mid ˗˗disable-nfs ˗˗disable-profiling \

˗˗disable-projectm ˗˗enable-rsxs ˗˗enable-rtmp ˗˗disable-vaapi \

˗˗disable-vdadecoder ˗˗disable-external-ffmpeg  ˗˗disable-optical-drive

configure命令指定多个参数,这些参数指定了安装的位置(˗˗prefix=/usr)、要构建的架构(˗˗build=arm-linux-gnueabihf)、保存其运行文件的位置(˗˗localstatedir=/var/lib)和平台(˗˗with-platform=raspberry-pi),以及一系列禁用和电子邮件选项,以删除 CD 驱动器和操纵杆等功能,并启用优化和 Avahi 外围设备自动检测等功能。最终,当命令执行完毕时,屏幕上的输出应该如下所示:

XBMC Configuration:

Debugging:    No

Profiling:    No

Optimization: Yes

Crosscomp.:   No

target ARCH:  arm

target CPU:   arm1176jzf-s

OpenGLES:     Yes

ALSA:         No

DBUS:         Yes

VDPAU:        No

VAAPI:        No

CrystalHD:    No

VDADecoder:   No

VTBDecoder:   No

OpenMax:      No

Joystick:     No

XRandR:       No

GOOM:         No

RSXS:         Yes

ProjectM:     No

Skin Touched: No

X11:          No

Bluray:       No

TexturePacker:Yes

MID Support:  Yes

ccache:       Yes

ALSA Support: No

PulseAudio:   No

HAL Support:  No

DVDCSS:       No

Avahi:        Yes

Non-free:     Yes

ASAP Codec:   No

MySQL:        Yes

Webserver:    Yes

libRTMP support:      Yes

libsmbclient support: Yes

libnfs client support:No

libafpclient support: No

AirPLay support:      No

AirTunes support:     No

Optical drive:        No

libudev support:      Yes

libusb support:       No

libcec support:       No

libmp3lame support:   Yes

libvorbisenc support: Yes

libcap support:       No

External FFmpeg:      No

prefix:       /usr

该配置指定了我们在安装中要求的所有标志,旨在充分利用 Raspberry Pi。现在,我们已经完成了实际编译的配置。这个命令本身对于它要做的事情来说非常虎头蛇尾:告诉系统花接下来的 12 个小时为我们的系统生成代码。与这个编译要运行多长时间相比,所有这些花费一点时间的工作根本不算什么。所以准备好,执行这个简单的四个字母的命令m a k e:

$ make

如果您看到类似下面这样的行,请不要惊慌:

/tmp/ccGvUe1g.s:507: Warning: swp{b} use is deprecated for this architecture

唯一会停止编译的是一个严重错误或成功。这些警告与 XBMC 编译中使用的一些函数有关,这些函数对我们的 Pi 来说有点老了。编译成功后,您应该会看到以下内容:

XBMC built successfully

这表明我们已经成功地构建了 XBMC,可以进行这个过程中的最后一步了,那就是安装我们新编译的软件。make 系统实际上也会负责安装。要安装,您只需运行make install,它会将所有新编译的二进制文件复制到您操作系统中的正确位置。您需要给它加上前缀sudo,因为我们要复制的位置(/usr)也是一个系统位置,只有 root 用户被授予写权限。您的输出应该如下所示:

$ sudo make install

Copying XBMC binary to /usr/lib/xbmc/xbmc.bin

You can run XBMC with the command ’xbmc’

Copying support and legal files...

Done!

Copying system files to /usr/share/xbmc

我们完了。虽然它很长,需要一点点工作来开始,但实际的编译过程相对来说是没有痛苦的,你知道,除了等待的痛苦。现在 XBMC 已经安装好了,我们该如何使用它呢?

解决纷争

在我们开始运行 XBMC 之前,我们应该先看看您可能会遇到的一些问题。这些步骤中的大部分应该会自行完成,因为这种设置是通用的,可以在任何 Pi 上工作,因为它们都共享相同的硬件。如果你有疑问,删除 xbmc-rbp 目录并重新开始。确保您完整地执行了副本和链接。我发现在进行 git 克隆时,有些东西有时会卡住而不能移动。

在这种情况下,最好使用 Ctrl + C 停止当前作业,删除目录,重新启动,然后重新开始。在编译和安装阶段最好从系统中移除外围设备,因为太多的外围设备会导致我的系统出现负载问题。此外,您应该确保您的命令输出(如configure)与给定的相匹配,因为这些标志在编译时可以发挥更大的作用,并为您省去一个令人头疼的问题和另一个 12 小时的编译工作。最后,确保所有的apt-get都成功运行并完成,因为这些包需要提供您的 Pi 在构建 XBMC 时将使用的库。

启动和使用 XBMC

既然我们已经完成了大型编译过程,是时候启动 XBMC 了!不过,首先,我们需要重置之前设置的选项,将更多的内存放入系统 RAM。我们将需要去图形设备,因为我们想做一些严重的显示工作与 XBMC。执行以下命令来切换 Pi 引导系统:

$ sudo cp /boot/arm128_start.elf /boot/start.elf

返回并检查前面提到的链接文件是否正确。现在我们还可以对/boot/config.txt文件进行一些修改,因为它控制了 Pi 的底层硬件如何运行。要做的最简单的改变是添加行disable_overscan=1,因为它将消除进行过扫描处理的需要,因为过扫描处理将使我们回放的视频量更大,从而消耗更多资源。完成这些更改后,发出以下命令,最后一次重新配置并重新启动 Pi:

$ sudo rpi-update

$ sudo reboot

现在,您已经将设置更改回 50/50 资源分配,通过以 root 用户身份登录并发出以下命令来启动 XBMC:

$ /usr/lib/xbmc/xbmc.bin

你的屏幕会定格片刻,图 11-1 会问候你。

A978-1-4842-1162-5_11_Fig1_HTML.jpg

图 11-1。

XBMC boot screen

你应该会看到 XBMC 菜单,看起来如图 11-2 。

A978-1-4842-1162-5_11_Fig2_HTML.jpg

图 11-2。

XBMC main menu

在主菜单中,有选择不同播放类型的选项,XBMC 是一个完全图形化的系统,当你在其中时,它会为你提供获取文件的选项和位置。只要您的媒体可以在网络上访问,XBMC 应该能够访问它并播放它!现在关于回放的话题,你可能会坐在那里想,“我会一直用这个键盘来回放吗?”答案是响亮的不!有两种解决方案:

  • 购买一个 USB 遥控器,并将其连接到您的 Pi。
  • 第二种更偷偷摸摸:用你的智能手机!

大多数智能手机都有下载 XBMC 遥控应用程序的功能,只需与 XBMC 系统配对即可运行。为此,我们需要在 XBMC 内启用两个选项,以允许它接收远程控制。进入“设置”菜单,然后进入“服务”,将遥控器设置更改为“允许其他系统上的程序控制 XBMC”一旦你允许远程控制,你需要进入网络服务器并设置“允许通过 HTTP 控制 XBMC”;您还应该继续设置用户名和密码,这样只有拥有密码的人才能控制您的 XMBC 实例,而不是网络上任何使用 XBMC 应用程序的人!

一旦您启用了这些远程控制选项,只需从您喜爱的应用程序商店下载应用程序,然后在应用程序中设置选项即可。你应该只需要给应用程序你的 Pi 的本地地址,你可以通过系统➤系统信息菜单看到,设置端口为 8080,并提供 XBMC 的实例名和用户名/密码,如图 11-3 所示。

A978-1-4842-1162-5_11_Fig3_HTML.jpg

图 11-3。

XBMC remote application

一旦你给出了所有的细节,你的手机应该变成你的 XBMC 实例的遥控器!配有一整套方向按钮和回放控制,如图 11-4 所示。

A978-1-4842-1162-5_11_Fig4_HTML.jpg

图 11-4。

XBMC remote in action!

靴子上的 XBMC

虽然到目前为止我们已经手动启动了 XBMC,但大多数人会希望它自动发生,因为你每次想要启动它时都需要将键盘插入媒体中心,这有什么意义呢?

下面是一个简单的start脚本,它将允许您使用start脚本执行 XBMC。在文件/etc/init.d/xbmc中创建这个文件(像所有其他长文件一样,它可以在本书的 press 库中找到):

#! /bin/sh

### BEGIN INIT INFO

# Provides:          xbmc

# Required-Start:    $all

# Required-Stop:     $all

# Default-Start:     2 3 4 5

# Default-Stop:      0 1 6

# Short-Description: Start XBMC

# Description:       Start XBMC

### END INIT INFO

DAEMON=/usr/bin/xinit

DAEMON_OPTS="/usr/lib/xbmc/xbmc.bin"

NAME=xbmc

DESC=XBMC

RUN_AS=root

PID_FILE=/var/run/xbmc.pid

test -x $DAEMON || exit 0

set -e

case "$1" in

start)

echo "Starting $DESC"

start-stop-daemon ˗˗start -c $RUN_AS ˗˗background ˗˗pidfile $PID_FILE  ˗˗make-pidfile ˗˗exec $DAEMON ˗˗ $DAEMON_OPTS

;;

stop)

echo "Stopping $DESC"

start-stop-daemon ˗˗stop ˗˗pidfile $PID_FILE

;;

restart|force-reload)

echo "Restarting $DESC"

start-stop-daemon ˗˗stop ˗˗pidfile $PID_FILE

sleep 5

start-stop-daemon ˗˗start -c $RUN_AS ˗˗background ˗˗pidfile $PID_FILE  ˗˗make-pidfile ˗˗exec $DAEMON ˗˗ $DAEMON_OPTS

;;

*)

echo "Usage: /etc/init.d/$NAME{start|stop|restart|force-reload}" >&2

exit 1

;;

esac

exit 0

创建该文件后,运行以下命令使其可执行,并将其加载到 Pi 的引导进程中:

$ sudo chmod +x /etc/init.d/xbmc

$ sudo update-rc.d xbmc defaults

现在继续并重新启动您的系统;它会自动把你带到 XBMC!恭喜你;至此,您应该已经拥有了一个功能齐全的 XBMC 实例,并且可以使用 smartphone remote!

解决纷争

因为您成功地从源代码编译,所以启动和运行您的 XBMC 实例应该没有任何问题。首先要检查的是编译确实完全完成了,安装也是如此。他们是两个最有可能的罪犯。如果启动 XBMC 实例,您可能会看到如下警告:

libEGL warning: DRI2: xcb_connect failed

如果这样做,您必须重新运行以前的复制和链接命令。此问题与无法加载这些库文件有关。

使用 Airplay 播放流媒体音乐

人们通常希望将 Raspberry Pi 用作流媒体音乐系统,这意味着它连接到一组扬声器,可以远程控制,并从中央控制系统向其传输音乐。已经有大量的系统可以进行这种播放,但对我们来说,计划是利用苹果 AirPlay 协议。你可以继续在双鱼座工作,或者你可以回复到最初的拉斯扁。这种安装方式在两种设备上都是一样的。

这种设置比视频更新容易得多;我们仍然需要做一些编译工作,但是我们不需要运行./configure,因为活动的部分要少得多。此外,我们希望能够播放音频到给定的设备,所以你需要确保你有扬声器连接。

首先要做的是安装以下前驱包:

$ sudo apt-get install build-essential libssl-dev libcrypt-openssl-rsa-perl libao-dev libio-socket-inet6-perl libwww-perl avahi-utils pkg-config alsa-utils libwww-perl avahi-utils

Reading package lists... Done

Building dependency tree

Reading state information... Done

build-essential is already the newest version.

libio-socket-inet6-perl is already the newest version.

libio-socket-inet6-perl set to manually installed.

libssl-dev is already the newest version.

libwww-perl is already the newest version.

libwww-perl set to manually installed.

pkg-config is already the newest version.

pkg-config set to manually installed.

The following packages were automatically installed and are no longer required:

libcdio-cdda0 libcdio-paranoia0 libcdio10 libcelt0-0 libdb4.8 librpmio2

Use ’apt-get autoremove’ to remove them.

The following extra packages will be installed:

alsa-base avahi-daemon libao-common libao4 libavahi-core7 libcrypt-openssl-bignum-perl libdaemon0 libnss-mdns

Suggested packages:

alsa-oss oss-compat avahi-autoipd libaudio2 libesd0 libesd-alsa0

The following NEW packages will be installed:

alsa-base alsa-utils avahi-daemon avahi-utils libao-common libao-dev libao4 libavahi-core7 libcrypt-openssl-bignum-perl libcrypt-openssl-rsa-perl libdaemon0

libnss-mdns

0 upgraded, 12 newly installed, 0 to remove and 139 not upgraded.

Need to get 1,699 kB of archives.

After this operation, 3,702 kB of additional disk space will be used.

Do you want to continue [Y/n]?

一旦你安装了所有这些软件包,加载声音模块到系统中来利用它。要加载一个模块,使用modprobe命令。在这个实例中,加载snd_bcm2835模块,它是 Pi 中的 Broadcom 声音适配器。发出以下命令:

$ sudo modprobe snd_bcm2835

该命令将会运行,但是它不会生成任何输出来告诉我们执行的状态或其他任何信息。我们需要检查模块是否已经加载。就像ls命令用于目录和lsusb用于列出 USB 设备一样,还有一个lsmod命令用于列出当前安装在系统中的模块。发出lsmod命令,检查您是否可以看到snd_bcm2835模块加载到您的系统中(像我的一样):

$ lsmod

Module                  Size  Used by

snd_bcm2835            21485  0

snd_pcm                82208  1 snd_bcm2835

snd_page_alloc          5383  1 snd_pcm

snd_seq                59808  0

snd_seq_device          6920  1 snd_seq

snd_timer              21905  2 snd_seq,snd_pcm

snd                    57668  5 snd_timer,snd_seq_device,snd_seq,snd_pcm,snd_bcm2835

ipv6                  290227  34

r8712u                182646  0

spi_bcm2708             4815  0

i2c_bcm2708             3818  0

因为您是第一次加载声音模块,所以您还需要选择正在使用的音频设备(因为以前没有使用过)。要改变器件,使用如下的amixer命令:

$ sudo amixer cset numid=3 1

numid=3,iface=MIXER,name=’PCM Playback Route’

; type=INTEGER,access=rw˗˗˗˗˗˗,values=1,min=0,max=3,step=0

: values=1

我们将 PCM 播放路径的numid=3值更改为等于 3.5 插孔的值1。你可以把末端的1改成2,这表示你应该使用 HDMI 的内置音频通道来发送声音。

既然硬件已经整理好了,是时候通过从互联网上的存储库下载 shairport 软件来处理软件了。到目前为止,最简单的方法是使用wget(Web GET 的缩写)命令下载给定 URL 上的所有可用内容。通过这种方式,我们可以用一个简单的 URL 从互联网上下载整个软件包。执行以下操作:

$ wgethttps://github.com/albertz/shairport/zipball/master

˗˗2012-09-30 18:13:36˗˗https://github.com/albertz/shairport/zipball/master

Resolving github.com (github.com)... 207.97.227.239

Connecting to github.com (github.com)|207.97.227.239|:443... connected.

HTTP request sent, awaiting response... 302 Found

Location:https://nodeload.github.com/albertz/shairport/zipball/master

˗˗2012-09-30 18:13:42˗˗https://nodeload.github.com/albertz/shairport/zipball/master

Resolving nodeload.github.com (nodeload.github.com)... 207.97.227.252

Connecting to nodeload.github.com (nodeload.github.com)|207.97.227.252|:443... connected.

HTTP request sent, awaiting response... 200 OK

Length: 46413 (45K) [application/zip]

Saving to: ’master’

100%[==================================================>] 46,413      60.1K/s   in 0.8s

2012-09-30 18:13:50 (60.1 KB/s) - ’master’ saved [46413/46413]

现在我们已经下载了 shairport 软件,我们需要使用它。文件名为master,我们整理一下,正确命名。只需使用move命令来更改文件名。一旦你移动了文件,用unzip命令和cd解压到新创建的albertz-shairport-b58f156目录中:

$ mv master albertz-shairport-b58f156.zip

$ unzip albertz-shairport-b58f156.zip

$ cd albertz-shairport-3892180

现在您需要构建应用程序,所以运行make命令。幸运的是,这个应用程序比 XBMC 的简单得多,因此不需要预先配置。

$ make

cc -O2 -Wall   -c alac.c -o alac.o

cc -O2 -Wall   -DHAIRTUNES_STANDALONE hairtunes.c alac.o -o hairtunes -lm -lpthread -lssl -lcrypto -lao

cc -O2 -Wall   -c socketlib.c -o socketlib.o

cc -O2 -Wall   -c shairport.c -o shairport.o

cc -O2 -Wall   -c hairtunes.c -o hairtunes.o

cc -O2 -Wall   socketlib.o shairport.o alac.o hairtunes.o -o shairport -lm -lpthread -lssl -lcrypto -lao

一旦编译完成,就是测试的时候了;shairport 是通过执行shairport.pl文件来运行的。请按如下方式执行:

$ ./shairport.pl

Can’t locate Net/SDP.pm in @INC (@INC contains: /usr/lib/perl5/site_perl /usr/share/perl5/site_perl /usr/lib/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib/perl5/core_perl /usr/share/perl5/core_perl .) at ./shairport.pl line 45.

呜呜!有一个错误与 Perl 系统执行安装所需的特定代码模块不可用有关。在这种情况下,我们需要安装的是 Net/SDP 模块。

不幸的是,apt-get不能修复这个问题,所以你必须从 Perl CPAN 库(它很像一个巨大的 Perl 软件库,开发者可以借用和使用)下载模块,然后安装它。你将再次使用wget从网上下载文件。发出以下命令:

$ wgethttp://search.cpan.org/CPAN/authors/id/N/NJ/NJH/Net-SDP-0.07.tar.gz

˗˗2012-09-30 19:01:11˗˗http://search.cpan.org/CPAN/authors/id/N/NJ/NJH/Net-SDP-0.07.tar.gz

Resolving search.cpan.org (search.cpan.org)... 199.15.176.161

Connecting to search.cpan.org (search.cpan.org)|199.15.176.161|:80... connected.

HTTP request sent, awaiting response... 302 Found

Location:http://mirror.westfield.com.au/cpan/authors/id/N/NJ/NJH/Net-SDP-0.07.tar.gz

˗˗2012-09-30 19:01:11˗˗http://mirror.westfield.com.au/cpan/authors/id/N/NJ/NJH/Net-SDP-0.07.tar.gz

Resolving mirror.westfield.com.au (mirror.westfield.com.au)... 203.42.62.21

Connecting to mirror.westfield.com.au (mirror.westfield.com.au)|203.42.62.21|:80... connected.

HTTP request sent, awaiting response... 200 OK

Length: 20679 (20K) [application/x-gzip]

Saving to: ’Net-SDP-0.07.tar.gz’

100%[===========================================================================>] 20,679      ˗˗.-K/s   in 0.05s

2012-09-30 19:01:12 (382 KB/s) - ’Net-SDP-0.07.tar.gz’ saved [20679/20679]

一旦文件被下载,您需要用tar命令提取它。发出一个带有参数–zxvftar命令来解压文件,解压缩这个 tarball。然后切换到新创建的Net-SDP-0.07目录:

$ tar –zxvf Net-SDP-0.07.tar.gz

$ cd Net-SDP-0.07

现在包已经在这里了,您只需要在这里向 Perl 构建系统发出命令。第一个是执行Build.PL脚本来生成构建文件:

$ perl Build.PL

Created MYMETA.yml and MYMETA.json

Creating new ’Build’ script for ’Net-SDP’ version ’0.07’

一旦创建了构建文件,您需要用下面的代码运行它:

$ ./Build

Building Net-SDP

构建完成后,通过向build脚本发出test命令来运行内置测试以确保没有问题:

$ ./Build test

t/00use.t ....... ok

t/10generate.t .. ok

t/10parse.t ..... ok

t/20repeat.t .... ok

t/30asstring.t .. ok

All tests successful.

Files=5, Tests=69,  5 wallclock secs ( 0.97 usr  0.05 sys +  3.40 cusr  0.29 csys =  4.71 CPU)

Result: PASS

最后,您需要安装模块,因此向build脚本发出install命令(您可能需要在命令后按 Enter 来完成安装并显示):

$ sudo ./Build install

[sudo] password for raspbian:

Building Net-SDP

Installing /usr/local/man/man1/sdp2rat.1p

Installing /usr/local/share/perl/5.14.2/Net/SDP.pm

Installing /usr/local/share/perl/5.14.2/Net/SDP/Time.pm

Installing /usr/local/share/perl/5.14.2/Net/SDP/Media.pm

Installing /usr/local/man/man3/Net::SDP::Media.3pm

Installing /usr/local/man/man3/Net::SDP::Time.3pm

Installing /usr/local/man/man3/Net::SDP.3pm

Installing /usr/local/bin/sdp2rat

一旦构建完成,再次运行shairport.pl脚本是一件简单的事情,这一次它应该可以工作了!输出应该如下所示:

$ cd..

$ ./shairport.pl

Established under name ’891BEA3BF8A1@ShairPort 2113 on pisces’

现在,您需要与应用程序建立连接,并测试您是否可以向它发送音乐。打开 iTunes,然后在 iTunes 的右下角更改输出目的地(参见图 11-5 )。您应该会在那里看到一个 shairport 名称。选择它,然后按下播放您最喜爱的歌曲和 presto:流媒体音乐!

A978-1-4842-1162-5_11_Fig5_HTML.jpg

图 11-5。

ShairPort enabled

解决纷争

和 XBMC 一样,这个过程相当容易,因为 Raspberry Pi 有一个固定的硬件平台,如果没有所有这些变量,就没有那么多需要担心的事情——事情应该会正常工作。

如果您发现扬声器连接后没有声音,请检查您是否正确发出了modprobeamixer命令,因为这两个命令都是实现音频功能所必需的。

除了这个问题之外,大多数命令都应该可以工作。如果没有,您应该删除任何下载的内容并重新开始。

机场开机

与使用 XBMC 实例一样,如果不需要手动登录到您的 Pi 并启动应用程序,大多数人不会希望在他们的系统中启动 shairport。这对于我们来说很容易,因为 shairport 安装程序已经捆绑了所有需要的文件!为此,首先安装 shairport 系统:运行sudo make install,您的输出应该如下所示:

$ sudo make install

install -D -m 0755 hairtunes /usr/local/bin/hairtunes

install -D -m 0755 shairport.pl /usr/local/bin/shairport.pl

install -D -m 0755 shairport /usr/local/bin/shairport

安装完成后,您可以将提供的init脚本复制到正确的位置:

$ sudo cp shairport.init.sample /etc/init.d/shairport

既然文件已经被复制,您需要做一个小的修改:在启动 shairport 应用程序之前,将前面的modprobe命令——】添加到/etc/init.d/shairport文件中。start部分应该是这样的:

start() {

echo -n "Starting shairport: "

modprobe snd_bcm2835

start-stop-daemon ˗˗start ˗˗quiet ˗˗pidfile "$PIDFILE" \

˗˗exec "$DAEMON" -b ˗˗oknodo ˗˗ $DAEMON_ARGS

log_end_msg $?

}

我们需要运行的最后一个命令是:

$ sudo chmod +x /etc/init.d/shairport

$ sudo update-rc.d shairport defaults

这些命令使新的start脚本可写,并更新引导序列以包含新的 shairport 脚本!重新启动您的 Pi,shairport 应该会在启动时为您启动并运行!恭喜你。

摘要

在这一全面的章节中,您安装了整个 precursor 应用程序课程,并学习了如何下载源代码、配置源代码和编译源代码。这是相当多的工作,XBMC 编译花费了超过 12 个小时!

您还创建并安装了start脚本来让这些新的媒体回放系统在引导时在 Pi 上运行,避免了手动干预的需要。

最后,您将XBMC实例连接到智能手机的远程控制应用程序。这一章的工作量令人难以置信,干得好!

十二、安装 Windows 10!

等等什么?Windows 10?这不是 Linux 的书吗?嗯,是的,这本书的重点是坚定地学习使用 Raspberry Pi 的 Linux,但让许多人兴奋的一个整洁的功能是它新发现的运行 Windows 10 的能力。现在,如果你开始认为我们只是有点异端,那么不要担心,我们在这本书里只是触及了表面。事实上,我们将向您展示如何安装、启动并运行它,这就是基本内容。

那么,为什么我们要用这个来占用宝贵的空间呢?嗯,我们希望你了解树莓 Pi 的所有功能,即使你现在可能不想使用 Windows 10,谁知道微软将来会推出什么呢?简而言之,尽管我们热爱 Linux 和开源,但我们也很务实,这意味着使用我们所能使用的最好的工具。在这一章中,我们只是为你的工具箱提供了一个新的工具。

我以为 Windows 不能在 Pi 上运行?

对于那些读过第一版的人来说(顺便谢谢你!),你可能记得我们在介绍中花了相当多的时间解释,虽然 Raspberry Pi 是基于 ARM 的设备,但它实际上不能运行 Windows RT(微软基于 ARM 的 Windows 版本,常见于平板电脑等设备上)。不用说,如果你检查这个版本中的介绍,特定的方框已被取代!

现在,在您对在 Pi 上运行 Windows 感到兴奋之前,您需要知道的第一件事是,支持 Pi 的 Windows 版本不是您可能希望在 PC 上运行的版本(特别是如果您之前已经“升级”到 Windows 8)。相反,它是一个高度精简的 Windows 版本,只让你可以使用基本功能。你得到了一个强大的 API 来编写软件,但它实际上是为数据收集设备或远程传感器提供动力,而不是台式机。

好吧,所以缺乏一个完整的桌面环境有点令人失望。我不是一个 Windows 的大用户,甚至我也很失望我不能把我的 Pi 变成一个方便的远程桌面机器。然而,也有一些好消息 Windows 10 的物联网版本将完全免费下载并在 Pi 上使用!

Note

本章涵盖的所有这些东西都取自互联网,并且是基于被认为是当前最好的资源。很有可能,当你读到这些的时候,这个平台已经转移了,而这也不再那么相关了。

为什么包括它?嗯,这一转变(Pi 上的 Windows)值得一提,据我所知,微软自己的页面上列出的一些说明和要求实际上是不正确的。所以以此为指导,但是当你读到这里的时候,你可能会发现更新更准确的东西。

查看他们的主要网站,了解最新和最棒的:

https://dev.windows.com/en-us/iot

什么样的互联网?

物联网(简称 IoT)正在席卷全球,尤其是在最近一年左右。以前互联网上充满了数据。你可以毫无困难地搜索餐馆、收发信息、进行网上银行业务,但最终你只是在移动数据。肯定有用,但不是特别令人兴奋。

走进物联网。通过这种方式来看待互联网,它不再是简单的共享数据的机器,而是可以通过网络与控制器通信的传感器或设备等事物的集合。

例如,你可以给你的树莓派增加一个温度传感器,把它放在某个橱柜里,它会很高兴地坐在那里报告当前的温度。如果你想跟踪和控制温度,比如自己酿造啤酒,这可能会很有用。事实上,我实际上使用我为这本书的第一版买的 Pi 来控制使用固态继电器的建筑中的锅炉。

因此,当我们谈论物联网时,我们真正谈论的是让计算机与周围的世界互动。从感知(如温度、光线甚至辐射)到行动(开关锅炉或打开或关闭大门),这开启了一种全新的互联网使用方式。

物联网面临的一个挑战是,你需要一些东西来实际感知或做一些事情。你可以用一台大盒子的个人电脑,但那并不理想。它们消耗大量电力(尤其是如果你只是想读取温度传感器),需要冷却,通常有噪音,占用大量空间,并且在现代家庭中有些难看。此外,它们很重,真的不是那种你想放在树上或车库顶层的东西。

你需要的是小巧、便携、可靠的东西。理想情况下,你不希望有移动部件(所以没有风扇会在半夜死在你的身上,离你住的地方 50 英里),低功耗要求,并考虑到它可能在恶劣的环境中,你真的不想为它付出太多。如果这听起来像树莓 Pi,那么你不是唯一这样想的人——事实上,Pi 与如此广泛的传感器和设备接口的能力使其成为物联网开发的一个非常受欢迎的系统。你不仅可以访问所有这些设备,还可以使用完整的操作系统,这是像 Arduino 这样的东西无法提供给你的。

但是为什么是 Windows 呢?

就我个人而言,我不太可能使用 Windows,但那是因为我已经使用 Linux 将近 20 年了。我对 Linux 很满意,我喜欢它的工作方式。然而,我最好的朋友之一没有跟随我的领导,留在了 Windows。现在他是一个 Windows 专家,他不太可能想要使用 Linux,尤其是当开始使用一些新的东西时,人们热衷于使用他们熟悉的东西。

如果你不认为这是一个足够好的理由,也许是 Windows 的物联网版本提供了一个完整而全面的 API(。有人能接触到硬件吗?)并与微软的 Azure 云平台很好地集成在一起。这个平台的一个主要好处是一切都是现成的(或者至少在完整版本发布时是这样)。对于 Linux,你需要自己把这些碎片拼凑起来。现在这对你来说可能不是问题,但是让别人替你处理这些事情还是有好处的。

微软也在花大力气围绕物联网建立一个社区。尽管它仍处于技术预览阶段,但你已经可以在网上尝试一些项目了。我们不打算在这里讨论这些,但是如果仅仅是为了了解你的敌人(或者了解其他人是如何解决问题的),这是值得一试的。

入门指南

就像使用 Pi 本身一样,如果我们想让您的 Pi 在 Windows 中启动,我们需要做一些事情。下面是您将需要的东西的快速列表(改编自开发者网站):

  • 运行 Windows 8 的机器
  • 你的圆周率 2
  • 8GB 微型 SD 卡(至少 8GB)–10 级
  • HDMI 电缆
  • 以太网电缆

Windows 8

现在,如果你看看开发者的网站,它声称你需要在你的电脑上安装 Windows 10 才能使用这些工具。它还声称,你必须直接在硬件上运行,而不是在虚拟机上运行(即,你需要 Windows 作为你的主要操作系统——你不能使用 Virtualbox 或 VMWare)。

从我的测试来看,这似乎不是真的。事实上,这些工具在 VMWare 上的 Windows 8.1 下运行得很好,我在将闪存映像写入 SD 卡时没有遇到任何问题。因此,如果你也这样做,你可能会没事。微软可能会在未来做出一些需要 Windows 10 的改变,但 VMWare 至少在处理 SD 读卡器方面没有问题。

你的圆周率 2

好吧,这很重要。Windows 10 需要最新最大的 Pi。最初的 Pi(所有版本)simple 无法胜任这项任务,Windows 也无法运行。您至少需要 Pi 2,尽管可能会继续支持 Pi 的更高版本。微软似乎非常热衷于物联网,我预计他们将在未来很长一段时间内支持 Pi。

8GB SD 卡

你应该已经有了这个。当然,你可能对事物的设置方式很满意,并不热衷于仅仅为了给 Windows 一个旋转而破坏它。在那种情况下,你需要第二张卡。

微软的最低要求是需要 8GB,并且至少应该是 10 级。等级指的是卡的速度,但是现在等级 10 的卡更常见而不是例外。大多数相机需要高速卡,这样它们就可以快速安全地存储大图像,否则会让相机感觉很慢。因此,在你最喜欢的当地商店里找到一张 10 级卡片应该不会有任何困难。

Caution

当我第一次尝试测试时,我使用了一个显然不是 class 10 的 SD 卡。它能够写入图像,尽管它会引导 Pi,但它会以黑屏结束,并且永远不会继续。后来在网上搜索了一下,我发现这是 SD 卡速度慢的一个已知问题,这就是为什么需要 10 级的原因。所以,在你花几个小时试着调试它之前,不要让自己太沮丧,确保你的卡是 10 级的。

HDMI 电缆

关于这个没什么好说的。如果你已经阅读了这本书,那么你已经有了它,如果没有,那么你只需要用它来“看到”Windows 已经在 Pi 上启动了。Windows IoT 下载中包含一个工具,可以让您检测本地网络上的 Pi,因此如果您的电缆在其他地方很忙,您可以只使用以太网。

以太网电缆

类似于 HDMI 电缆,如果你真的不在乎看到网络上的 Pi,并且你真的只是好奇看看 Pi 是否真的可以启动 Windows,那么你可以使用这种电缆。如果你没有 HDMI 电缆,检测网络上的 Pi 将是确定它是否工作的唯一方法。

下载工具

出于他们自己最清楚的原因,微软已经将物联网下载作为 ISO 映像提供。这意味着它看起来和感觉上都像 CD 或 DVD,事实上,如果你愿意,你可以把它刻录成 DVD。然而,它只包含一个可执行文件,所以我不明白他们为什么要这么麻烦。在任何情况下,您都需要 ISO 映像和工具来访问它。在 Windows 8.1 上,(它在 Windows 7 和更低版本上不工作)Windows 将为您处理此事,并将 ISO 映像作为虚拟 DVD 打开-您不需要将其实际刻录到光盘上。

在撰写本文时,您可以从物联网开发中心下载图片,网址是:

http://go.microsoft.com/fwlink/?LinkId=616847

如果那个链接对你不起作用,在谷歌搜索“Windows 10 Raspberry Pi 2 下载”会为你找到链接。

安装物联网工具

一旦你下载了图像,你应该得到一个类似图 12-1 的文件。

A978-1-4842-1162-5_12_Fig1_HTML.jpg

图 12-1。

Windows can see it’s an ISO image

如果您看到这个图标,那么您知道 Windows 能够打开它。不过,你至少需要 Windows 8.1 才能让它工作。

当你双击这个图标时,Windows 会把这个映像作为一个虚拟设备挂载,并假装它是一个真正的 DVD。图像上只有一个文件,这是我们需要运行的文件。您应该会看到类似图 12-2 的内容:

A978-1-4842-1162-5_12_Fig2_HTML.jpg

图 12-2。

Opening the ISO image

实际上,我没有将 DVD 驱动器连接到这台机器上(无论如何,它都是一台虚拟机),所以您可以看到 Windows 正在幕后处理这个问题。让我们通过双击安装程序来安装工具。你应该得到如图 12-3 所示的安装程序:

A978-1-4842-1162-5_12_Fig3_HTML.jpg

图 12-3。

Installing the IoT tool set

和大多数 Windows 安装程序一样(尽管你是否应该这么做还有待商榷),你可以简单地通过点击下一步并同意一切来完成。转了一会儿之后,安装程序应该会告诉你所有的东西都已经安装好了,你可以退出了。现在一切都可以使用了。

盒子里有什么?

据我所知,你有三件感兴趣的事。首先是一个方便的工具写出固件图像到你的 SD 卡。第二个是你要实际编写的固件镜像,包含 Windows 10 的物联网版本。最后是一个非常小的工具,它可以检测网络上的物联网 Pi 并告诉您它的状态。

让我们带他们去兜一圈…

将固件写入 SD 卡

当您最初在 Pi 上安装 NOOBS 或 Raspbian 时,您已经在 Linux 下完成了这项工作。尽管那时你使用的是一套不同的(经过测试的)工具,并且可能是在 Linux 或 Mac 下完成的。固件映像似乎就是这样,一个我们写入 SD 卡的简单映像,但为了以防微软做一些特殊的事情,我们将使用他们的工具。

首先我们需要找到它。在我的机器上,它安装在以下位置:

c:\ Program Files(x86)\ Microsoft IoT

如果浏览到该目录,您应该会看到类似图 12-4 的内容。

A978-1-4842-1162-5_12_Fig4_HTML.jpg

图 12-4。

Finding the IoT tools

我们感兴趣的应用程序是“IoTCoreImageHelper ”,它实际上只是“Image Writer”的一个好听的名字。双击这个应用程序来启动它,你会得到一个界面简单干净的漂亮的小应用程序(图 12-5 ):

A978-1-4842-1162-5_12_Fig5_HTML.jpg

图 12-5。

Burning the image onto your SD card

正如你所看到的,我已经填写了基本信息,然后截图了。值得注意的是,最初,SD 卡没有出现,我开始怀疑微软网站是否真的需要一个真正的物理机器来写入 sd 卡。然而,事实证明,我只是忘记了插入 SD 读卡器(哎呀), VMWare 一检测到它,我就可以按下刷新按钮并立即看到卡。因此,一定要确保 Windows 可以看到该设备,并且它显示在“这台电脑”下(尽管对我来说,它将始终显示在“我的电脑”旁边)。我还必须重新插入 SD 卡,以便 Windows 能够看到它,尽管它已经正确地检测到了读卡器。为什么呢?谁知道呢,但有时候扭动电线确实能解决问题。

您需要做的最后一件事是选择您想要写入卡的闪存映像文件。这与 FFU 下的工具位于同一个文件夹中(图 12-6 ):

A978-1-4842-1162-5_12_Fig6_HTML.jpg

图 12-6。

The rather originally named flash file

c:\ Program Files(x86)\ Microsoft IoT \ FFU \ raspberrypi 2

一旦你选择了路径,你所要做的就是按下“闪光”按钮,它就会写到你的卡上。您将得到最后一个提示,提示您即将粉碎您的 SD 卡(见图 12-7 ):

A978-1-4842-1162-5_12_Fig7_HTML.jpg

图 12-7。

Are you sure you want to erase the card?

现在,根据您使用的 Windows 版本,您将收到一个警告,询问您是否可以“对这台计算机进行更改”。实际上,它不会改变机器,但是它需要提升权限才能直接写入设备(如果您想直接使用设备,Linux 也需要提升权限)。因此,如果您收到以下警告,只需说“是”并继续(图 12-8 ):

A978-1-4842-1162-5_12_Fig8_HTML.jpg

图 12-8。

You need to give the program a higher level of access so it can write directly to the SD Card

看起来这个闪亮的新工具实际上是一个旧的控制台(基于文本)应用程序的前端,因为当它编写时,你会在控制台屏幕上看到更新。虽然您可以自己手动运行这个命令,避免使用图形界面,但是您需要自己设计标志和选项。无论如何,当您看到弹出以下窗口时,不要感到惊讶或担心(图 12-9 ):

A978-1-4842-1162-5_12_Fig9_HTML.jpg

图 12-9。

Writing the image to the SD card

这可能需要相当长的时间来写入图像文件,尤其是如果你使用 USB 2。即使在使用 USB 3 时,仍然花了足足十分钟才成功写入此图像。如果它看起来很慢,不要担心,它最终会到达那里。

一旦完成,您现在就可以启动您的 Pi 了。

点燃码头

现在你已经在 SD 卡上安装了 Windows,是时候让它实际工作了。像 NOOBS 或拉斯边一样,这一点真的很简单——你所要做的就是插入 SD 卡并给 Pi 加电。这就是事情的全部。

打开电源后,您应该会看到一个黑屏,中间有以下标志,一切正常,一个小小的“请稍候”标志会出现在它的正下方(图 12-10 ):

A978-1-4842-1162-5_12_Fig10_HTML.jpg

图 12-10。

Windows boot logo

旋转一会儿后,屏幕会变黑一会儿。这是完全正常的,会持续几分钟。一旦它完成了它需要做的事情(像 Raspbian 一样,在第一次引导时会做一些初始设置,比如扩展分区大小),它将重新引导并启动默认的测试应用程序。

不过,在我们开始之前,您可能会遇到其他情况。当屏幕变黑时,它不是在几分钟后重启,而是保持黑色。现在还不清楚你要等多久,但我设法看完了整集《流言终结者》,私家侦探一声不吭。我决定我应该重启它,再试一次。这一次,它在一分钟左右后重新启动,但它没有加载默认应用程序,而是回到了相同的标志,在变黑和重新启动之前做了一点旋转。冲洗并重复。

正如我之前简单提到的,如果你不使用高速(特别是至少 10 级)SD 卡,这是一个已知的问题。我没有注意到我用的卡实际上不是 10 级的,因为我总是买 10 级的,所以我没有想到要检查一下。

所以,如果你的 Pi 陷入了重启的时间循环,或者它一直呆在黑暗中,那很可能是你的 SD 卡。当我把我的换成真正的 10 级时,第一次就成功了。套用流言终结者的话,我犯这些错误是为了让你们不用犯。

配置时间

现在假设你没有得到死亡的黑屏,你应该得到一个类似这样的屏幕(图 12-11 ):

A978-1-4842-1162-5_12_Fig11_HTML.jpg

图 12-11。

Windows getting things ready

考虑到在另一个 SD 卡上浪费的时间,你可以想象我看到这个屏幕有多开心。如果您也看到这种情况,那么您的 Pi 只需要几分钟就可以进行配置了。这是紧接着这个屏幕的屏幕(图 12-12 ):

A978-1-4842-1162-5_12_Fig12_HTML.jpg

图 12-12。

Welcome to Windows on Pi

这张截屏看起来有点难,但它主要是向您展示我浏览过的屏幕。在左边我们有一个语言列表,在右下角有一个“下一步”按钮。对我来说幸运的是,英语是我想要的,所以我所要做的就是点击下一个按钮。当然,如果你喜欢另一种语言,你可以在这里设置。

右上角是关于 Pi 的一些基本信息,比如它的名称、IP 地址和它运行的操作系统版本。一旦您按下“下一步”,您将进入显示您的 Pi 完全运行的最终屏幕(图 12-13 ):

A978-1-4842-1162-5_12_Fig13_HTML.jpg

图 12-13。

Fully booted Pi

为了节省空间,我从页面中间截取了一个片段。顶部的选项相当简单明了,所以我将把它们留给你去探索。这个页面提供的信息比配置页面多一点,但是我们在这个阶段并不感兴趣。事实上,唯一真正的区别是 Pi 的漂亮图片和连接设备的列表。

关于这个页面的一个有用的特性是,它为你提供了一个到微软“设备上的窗口”页面的链接,这将帮助你开始为你的 Pi 开发软件。在浏览的时候,我甚至看到了编写你自己的设备驱动的教程,所以每个人都可以在上面找到一些东西。无论如何,恭喜你——你是第一个在树莓派上运行 Windows 的人!我不得不承认第一次看到这个启动的时候非常酷,甚至我也很想看看微软会把这个平台带到哪里去!

检测网络上的 Pi。

在我们结束之前,让我们回到工具箱中的另一个工具“WindowsIoTCoreWatcher”。它实际上是一种通过网络检测圆周率的方法。如果你回到这个文件夹(查看本章的第一部分来提醒你它在哪里),你可以双击它的图标来启动它。

如果您的 Pi 运行良好,您应该会看到类似这样的内容(图 12-14 ):

A978-1-4842-1162-5_12_Fig14_HTML.jpg

图 12-14。

IoT Core Watcher lets you spy on your Pi

这就是我如何能够在所有黑屏和重启问题之后确定我的 Pi 是半存活的——它显示在这个列表中。当然,它不能告诉您太多,但至少让您知道 Pi 已经启动并运行,最重要的是它的 IP 地址是什么。一旦你开发了自己的应用程序并开始部署系统,能够快速找到你的 Pi(特别是找到合适的 Pi,因为你可能有很多 Pi)这个应用程序会变得非常方便。

接下来呢?

现在你已经安装了 Windows,你能用它做什么呢?好了,基本设置,老实说不是很多。然而,在主应用程序屏幕的左上角有一个“教程”标签。如果你点击它,你将能够找到一些你可以尝试开始的项目。这些是基于硬件的项目,如“Blinky”,涉及打开和关闭 LED。当然,还有更复杂的项目。

如前所述,您可以访问一个开发人员网站:

https://dev.windows.com/en-us/iot

这个网站包含了大量关于在 Windows 上构建设备的信息、教程和建议。由于这主要是一本关于 Linux 的书,所以我们不会在这方面做更多的详细说明,但是希望这能激起你对物联网的兴趣,也许只是为你的弓增加一根额外的弦。

摘要

这一章是在 Raspberry Pi 上为物联网设置 Windows 10 的快速演练。这个东西仍在预览中,所以事情可能会有变化,但基本内容可能会非常相似。

我们下载了包含工具集和固件的 ISO 映像,提取并安装该工具集,然后使用提供的工具将映像写入您的 SD 卡。

然后,我们启动 Pi,进行一些基本配置,并使用工具集中的 IoT watcher 应用程序来验证 Pi 已经启动并正在运行。我们通过在 Pi 上突出显示 Windows 的最佳访问网站来结束这一部分。

Pi 上的 Windows 仍然有点争议,但我认为它是将 Raspberry Pi 作为计算平台的一大进步。当然,它最初只是为了学习计算机如何工作,但它已经远远超出了这些最初的目标。它有强大的 Linux 支持,现在微软也加入了他们自己对该平台的支持。这对 Raspberry Pi、我们、用户和开发者来说都不会是坏事。

十三、TOR

在这本书的过程中,我们讨论了许多不同的方法,你可以用它们来解决日常生活中的问题。这些项目中的许多都是关于寻找在家里使用你的树莓 Pi 来解决小问题的方法。在这一章中,我们将讨论 Tor 软件的使用,它不仅可以在家里使用,还可以在外出时保护你的隐私。

出于保护你的隐私的目的,最好先了解一下 TOR 是什么以及它是如何工作的。TOR 是洋葱路由器的缩写,这是一款允许匿名互联网通信以保护您隐私的软件。现在,你们中的许多人会问“为什么我在家里需要这个”,事实是,在正常情况下,人们不应该在家里需要隐私保护。遗憾的是,在某些情况下,您可能希望确保匿名和隐私。最近有一些公开的案件,ISP 一直在使用间谍软件,并注入永久跟踪 cookies 到他们的客户的互联网流量。这样做是因为用户的浏览习惯可以卖给广告公司,广告公司可以利用这些数据来创建更有针对性的广告资料。

除了 ISP 对你的监控,TOR 软件的下一个主要用途是在旅行中。这正是树莓派因其尺寸、便携性和低功耗需求而大放异彩的地方。假设您正在旅行,需要连接到您的银行快速转账,以继续您在旅途中的享受生活。目前,你住在一个小旅馆里,旅馆里的任何成员都可以使用两台公共计算机。你可以想象,这些可能不是最好的电脑使用,因为你不知道什么病毒或其他恶意软件安装在这台电脑上。此外,您无法知道网络上还潜伏着什么其他东西来恶意获取您的银行信息。这就是 TOR 和您的 Raspberry Pi 的用武之地,您可以安静地连接您的 Pi 来代替 PC,使用它的 USB 来连接电源、显示器、以太网、鼠标和键盘来连接到您已知的安全环境。然后,您可以使用 TOR 系统(我们将在本章中介绍安装和配置)匿名安全地进行浏览。

如果酒店提供 WiFi 并有支持 HDMI 的电视,您可以使用无线适配器(就像我们在第九章 : WiPi 中提到的那种)和一个小型便携式鼠标和键盘将您的 Pi 连接到电视和更大的互联网。这样,您可以在舒适的酒店房间里浏览,同时仍然保持安全。

TOR 是什么

到目前为止,我可以想象你们都在说“哇。这个神奇的软件是什么,它是如何保护我的隐私的?”。洋葱路由器不仅仅是一个有趣的史莱克参考,它让人们深入了解软件是如何工作的(见图 13-1 和 13-2 )。

A978-1-4842-1162-5_13_Fig2_HTML.jpg

图 13-2。

How Tor Works, part 2

A978-1-4842-1162-5_13_Fig1_HTML.jpg

图 13-1。

How Tor Works, part 1

TOR 的工作原理是,在互联网上分布着许多专门的用户运行服务器(称为中继),你可以连接到这些服务器,还有一个目录服务器,它知道所有不同的中继服务器。您(最终用户)连接到目录服务器,下载所有中继的列表,并创建由许多不同中继组成的“虚拟电路”。

然后,该软件接受一个互联网请求,并对其进行多层加密(见这里的洋葱隐喻)!).然后,分层加密数据的大块(洋葱状)被发送到虚拟电路中的第一个继电器,第一个继电器移除顶层加密,向它展示电路中的第二个继电器。第一个继电器将现在稍微小一点的洋葱转发到第二个继电器,重复这个过程,直到它到达电路中的最后一个继电器。

然后,电路中的最后一个中继可以将原始的未加密互联网流量发送到最终目的地。然后,流量可以使用与之前相同的加密方法沿着相同的路径反向传输。由于每个节点只知道序列中的下一个节点,所以电路中的任何一个继电器都无法确定起点和终点在哪里。由于各个中继之间的所有通信都是加密的,因此通信内容不会被窃听。

正如你所看到的,洋葱式 TOR 系统提供了一个很好的解决方案来实现匿名和安全的互联网连接。然而,它确实有一个弱点;只有当在任何给定时间 TOR 网络上有大量用户时,TOR 才能提供足够的安全性。除非在给定时间有许多用户使用各种中继,否则理论上在端节点或目的地的某个人有可能辨别出原始用户。如果你回想一下前面 TOR 如何工作的例子,想象一下如果所有这些节点中只有一个用户。知道了谁在网络上,就很容易看到那个唯一的人在向哪里发送流量。值得庆幸的是,对于每一个使用 TOR 的人来说,在一天中的任何给定时间,都有大约 200 万人从世界各地直接连接到 TOR。

安装 TOR

和你想使用的任何软件一样,我们首先需要安装它。在安装任何新的软件包之前,我们应该将您的系统软件更新到最新版本,这样您就可以继续运行以下命令来更新您的系统。当然,如果您最近更新了,您可能不需要运行这些命令。请记住,如果您必须运行 rpi-update,您可能需要重新启动以下程序。

sudo apt-get update

sudo apt-get upgrade

sudo rpi-update

随着您的系统更新,我们可以期待得到 TOR 安装和工作。有很多方法可以安装 TOR 供您使用,最简单的方法(根据 TOR 项目网页)是安装 TOR 浏览器包。这个包附带安装的 TOR 应用程序和一个专门的浏览器,该浏览器被配置为与 TOR 应用程序一起工作。对我们来说不幸的是,这个包还不能和 Raspberry Pi 一起工作,所以我们必须采取一个稍微不同的方法。

首先,让我们安装核心 TOR 应用程序,它执行我们前面讨论的所有路由和中继发现。为此,请运行以下命令:

sudo apt-get install tor

Reading package lists... Done

Building dependency tree

Reading state information... Done

The following extra packages will be installed:

tor-geoipdb torsocks

Suggested packages:

mixmaster xul-ext-torbutton socat tor-arm polipo privoxy apparmor-utils

The following NEW packages will be installed:

tor tor-geoipdb torsocks

0 upgraded, 3 newly installed, 0 to remove and 4 not upgraded.

Need to get 2,589 kB of archives.

After this operation, 7,024 kB of additional disk space will be used.

Do you want to continue [Y/n]? y

一旦安装过程完成,TOR 应用程序将自动启动并运行。我们应该做的第一件事是检查进程是否正在运行,因此运行以下命令来列出所有正在运行的进程,并专门搜索 to 进程

ps –ef | grep /usr/bin/tor

您应该会在控制台中看到如下内容:

109      14591     1  1 22:01 ?        00:00:09 /usr/bin/tor ˗˗defaults-torrc /usr/share/tor/tor-service-defaults-torrc ˗˗hush

这表明 TOR 应用程序已经启动并正在运行。既然我们已经确认应用程序正在运行,我们应该去调查日志。您可以使用下面的命令打开日志(记住,按 q 退出 less 应用程序)

less /var/log/tor/log

当查看日志时,您会希望在文件的底部看到类似这样的内容。这些行表示 TOR 已经能够获得足够的目录信息来建立电路,它能够连接到 TOR 网络并成功地打开电路。这些是 TOR 应用程序需要执行的基本功能,并表明一切就绪,可以使用了。

Jul 08 22:02:10.000 [notice] We now have enough directory information to build circuits.

Jul 08 22:02:10.000 [notice] Bootstrapped 80%: Connecting to the Tor network.

Jul 08 22:02:10.000 [notice] Bootstrapped 90%: Establishing a Tor circuit.

Jul 08 22:02:12.000 [notice] Tor has successfully opened a circuit. Looks like client functionality is working.

Jul 08 22:02:12.000 [notice] Bootstrapped 100%: Done.

使用 TOR

所以,现在我们已经安装了 TOR,我们需要开始使用它。正如我们之前讨论的,我们无法使用预安装和配置的浏览器。因此,我们需要手动配置我们的浏览器来使用 TOR。我们将配置包含在名为 Epiphany 的 Raspberry Pi 中的默认浏览器,通过 TOR 项目建议的方法使用 TOR;将您的 Linux 系统设置为使用 TOR 作为透明代理。

因此,开始这个过程的第一步是稍微改变 TOR 应用程序的设置。我们想把 TOR 设置成一个“透明代理”,这基本上意味着一个通向更广阔的互联网的通道。我们还希望 TOR 能够进行 DNS 解析,这实际上意味着允许 TOR 解决如何访问 www。阿普瑞斯。com 。为此,我们将以下 4 行添加到/etc/tor/torrc

VirtualAddrNetworkIPv4 10.192.0.0/10

AutomapHostsOnResolve 1

TransPort 9040

DNSPort 53

完成这些更改后,我们需要使用以下命令重启 TOR 应用程序:

sudo /etc/init.d/tor restart

一旦 TOR 守护进程重新启动,最好返回并检查日志以确认一切正常。所以回过头来检查/var/log/tor/log,看看我们在本章的安装 tor 一节中寻找的关于成功引导的相同消息。下一步是设置系统 DNS 以使用 TOR 代理,但是在我们继续进行更改之前,我们需要备份当前设置——以备我们想要返回时使用。我们使用以下内容创建备份:

sudo cp /etc/resolv.conf /etc/resolv.conf.bkp

要返回,只需用原始文件替换 resolv 文件

sudo cp /etc/resolv.conf.bkp /etc/resolv.conf

现在备份已经完成,我们可以继续将名称服务器条目更改为 127.0.0.1,如下所示:

nameserver 127.0.0.1

这是计算中的一个特殊地址,称为回送地址,实际上是一个自引用。使用这个地址的结果是,当任何 DNS 解析被执行时,它将到达 TOR 并被路由出去。有了环回地址,我们需要设置一种方法,通过 TOR 路由所有出站网络连接。为此,我们将使用一个名为 iptables 的应用程序来设置一些本地防火墙规则,以便通过 TOR 路由数据。下面是 TOR 项目编写的一个小脚本,用于路由 TOR 上的所有输出连接。在开始之前,我们需要确保排除任何本地网络地址通过 TOR 路由。如果您通过 SSH 连接,这是非常必要的,因为您可能最终会通过 TOR 将所有打算发送到本地网络的数据发送出去——在那里它将无法工作。

这种变化只是暂时的,将在重新启动时消失。如果您想使这一更改永久生效,那么您需要编辑/etc/resolvconf.conf 并取消对 name_servers=127.0.0.1 这一行的注释。这将告诉您的系统在启动时从本地名称服务器读取。

要进行这一更改,我们只需在下面的脚本中向 _non_tor 变量添加额外的变量,以包含您的本地 IP 范围。下面的脚本包括 3 个最常见的 IP 范围。这些是匹配 192.168.0.X 192.168.1.X 和 10.0.0.X 的 IP。如果需要,您可以添加其他 IP。

#!/bin/sh

### set variables

#destinations you don’t want routed through Tor

_non_tor="192.168.1.0/24 192.168.0.0/24 10.0.0.0/24"

#the UID that Tor runs as (varies from system to system)

_tor_uid=id –u tor``

#Tor’s TransPort

_trans_port="9040"

### flush iptables

iptables -F

iptables -t nat -F

### set iptables *nat

iptables -t nat -A OUTPUT -m owner ˗˗uid-owner $_tor_uid -j RETURN

iptables -t nat -A OUTPUT -p udp ˗˗dport 53 -j REDIRECT ˗˗to-ports 53

#allow clearnet access for hosts in $_non_tor

for _clearnet in $_non_tor 127.0.0.0/9 127.128.0.0/10; do

iptables -t nat -A OUTPUT -d $_clearnet -j RETURN

done

#redirect all other output to Tor’s TransPort

iptables -t nat -A OUTPUT -p tcp ˗˗syn -j REDIRECT ˗˗to-ports $_trans_port

### set iptables *filter

iptables -A OUTPUT -m state ˗˗state ESTABLISHED,RELATED -j ACCEPT

#allow clearnet access for hosts in $_non_tor

for _clearnet in $_non_tor 127.0.0.0/8; do

iptables -A OUTPUT -d $_clearnet -j ACCEPT

done

#allow only Tor output

iptables -A OUTPUT -m owner ˗˗uid-owner $_tor_uid -j ACCEPT

iptables -A OUTPUT -j REJECT

一旦您确认所有需要排除的地址都在 _non_tor 变量中,我们就可以继续运行脚本来设置 tor。因此,继续将该脚本写到 tor.sh 文件中,然后用以下命令执行该脚本

sudo sh tor.sh

现在 TOR 已经设置好了,我们应该继续检查我们是否正确地使用了 TOR(图 13-3 )。TOR 项目再次伸出了援手,他们提供了一个很棒的网站,你可以访问这个网站来确认你是否正确地连接到了 TOR。因此,请将您的浏览器指向 https://check.torproject.org/的并确认您的输出与图 13-3 相匹配。

A978-1-4842-1162-5_13_Fig3_HTML.jpg

图 13-3。

TOR Browser Check

至此,您应该已经启动并运行了支持隐私的 TOR。恭喜你!

禁用 TOR

禁用 TOR 是一件非常简单的事情。您只需要重置 iptables 来删除我们在设置之前运行的所有脚本。为此,我们只需运行以下命令,该命令将刷新 iptables 中的所有内容:

sudo iptables -F

这将禁用所做的大部分更改,但仍会让 tor 守护进程在后台运行,并且还会保留名称服务器的更改。您应该运行下面的命令来停止 tor 守护进程。

sudo /etc/init.d/tor stop

您还需要通过恢复我们之前进行的备份来撤销对 resolv.conf 文件所做的更改。下面的命令实现了这一点:

sudo cp /etc/resolv.conf.bkp /etc/resolv.conf

错误和故障排除

在这个安装过程中,您可能会遇到一些问题。以下是您可能会遇到的一些常见问题以及解决方法。第一个问题可能是:

libkmod: ERROR ../libkmod/libkmod.c:554 kmod_search_moddep: could not open moddep file ’/lib/modules/3.18.7-v7+/modules.dep.bin’

这个问题与您的系统与 iptables 相比有点过时有关。这里的修复非常简单,您需要用下面的命令更新您的 Pi 的内部系统,然后重新启动:

rpi-update

您可能会遇到的另一个错误如下:

iptables v1.4.14: can’t initialize iptables table filter’: Table does not exist (do you need to insmod?)`

这是因为 iptables 命令无法与您的 Pi 的 Linux 内核正确交互。这里有两个解决方案,第一个是运行下面的命令来为 iptables 安装内核模块。

sudo modprobe ip_tables

sudo -i

echo ’ip_tables’ >> /etc/modules

在较新版本的 raspbian 下,这可能不起作用,因此您应该运行 raspberry pi 更新和升级命令:

sudo apt-get update

sudo apt-get upgrade

sudo rpi-update

摘要

在本章的学习过程中,您将了解什么是 TOR,以及在您可能不完全信任您通过其连接的设备的情况下,它是如何保护隐私的。您将学习如何设置 TOR,以及如何配置您的 raspberry Pi 来使用它。最后,您将学会如何从您的 Pi 中禁用 TOR 系统。有了这些技能和 Pi 的便携性,无论你在哪里,你都应该能够安全地浏览。

十四、手动操作——写入 SD 卡映像

在本书的第一章中,我们强调了为什么今天不再需要将操作映像直接写入 SD 卡,因为 NOOBS 会为您处理这些。事实上,NOOBS 让它变得如此简单,你可能会奇怪为什么我们仍然包括这些信息。

好吧,事实是,当 NOOBS 运作并做你想做的事情时,它一切都很好。具体来说,如果你是一个新用户,想安装 Raspbian 或轻松尝试不同的操作系统,那么 NOOBS 可以满足你。但是如果你想做其他事情,比如多次安装不同的操作系统,而不必重新下载镜像 10 次,或者你想把 Raspbian 放在 100 个 SD 卡上(谁知道呢,你可能会这么做),那么你自己直接写 SD 卡,完全绕过 NOOBS,这样会快得多,而且更具有讽刺意味。你可能还记得第一章中的内容,我们的私人侦探拒绝和 NOOBS 友好相处,并且在没有大量劝说的情况下不会上线——在这种情况下,手动下载图像可能是你最好的选择。

获取一些图像

首先,在我们将图像写入 SD 卡之前,我们需要获取图像。幸运的是,Pi 选择的最流行的操作系统(当然包括 Raspbian)在主下载页面上都有图片:

http://raspberrypi.org/downloads/

这是你之前下载 NOOBS 的同一个地方,你会在 NOOBS 提供的图片下面找到原始图片。在这个例子中,我们将再次覆盖 Raspbian,但是当然你可以使用图 A-1 中显示的页面上的任何选项来这样做。

A978-1-4842-1162-5_14_Fig1_HTML.jpg

图 A-1。

Plenty to choose from!

对于 Raspbian(上一张截图中没有显示)你可以选择直接下载或者通过 Bit Torrent 下载。Bit Torrent 是下载 Raspbian 的首选方式,因为它减轻了项目服务器和镜像的负载。然而,你需要一个 Bit Torrent 客户端,有些地方你可能不应该启动它(例如在工作中),有些连接由于 BitTorrent 的工作方式而表现很差(例如移动 3G)。同样,至少在香港,下载性能远不如本地镜像。如果可以的话,试着使用 Bit Torrent,否则,使用直接链接是完全可以接受的。

请记住,我们下载的图像是卡片上应该有的图像的直接表示。如果你只是将图像复制到卡片上,它仍然只是一张上面有 Raspbian 图像副本的卡片。我们需要做的是把图像直接写到卡片上,为此我们需要一些我们之前简单提到过的便利工具。

Note

您下载的图像文件是一个压缩的 ZIP 文件。在 Windows 8.1 上,双击该文件将打开一个压缩文件夹。您需要将图像文件本身复制到另一个位置,如“我的文档”或您的桌面。在 Mac 上,只需双击文件就可以提取图像并将其放入下载文件夹。

在 Windows 上使用图像编写器

推荐用于在 Windows 上编写图像的工具是一个名副其实的图像编写器。您可以在 Raspberry Pi 下载页面上找到该链接,或者访问该链接并选择“外部下载”,这将使其自动下载(参见图 A-2 ):

A978-1-4842-1162-5_14_Fig2_HTML.jpg

图 A-2。

Downloading Image Writer

https://launchpad.net/win32-image-writer

在撰写本文时,Image Writer 已知无法与 Windows 10 一起工作,尽管这可能在您阅读本文时得到解决。如果需要使用 Windows 10,也可以看看树莓 Pi 2 的 Windows IoT(物联网)版本。该工具包包含一个替代的图像写入工具,应该能够毫无困难地将这些图像写入 SD 卡,因为它来自微软,所以它应该可以在 Windows 10 上正常工作。

一旦你下载了 Image Writer,你会发现它是一个可以运行的可执行文件。以前它是以 zip 文件的形式提供的,需要先解压缩,但是看起来他们已经为你编写了一个很好的安装程序。所以首先要做的是——运行安装程序来安装 Image Writer。你首先会从 Windows 得到一个有用的警告(见图 A-3 )。

A978-1-4842-1162-5_14_Fig3_HTML.jpg

图 A-3。

The usual Windows warning

我们没有注意到安装和使用该软件的任何问题,但一如既往,请确保您在使用该工具安装未签名的第三方软件时感到舒适。

到目前为止一切顺利——我们已经准备好了成像工具。现在我们只需要提取图像文件。因为它是一个 zip 文件,只要双击它,你就会看到里面的图像文件。您可以看到压缩率(至少在我们看到的版本上)为 69%,这非常令人印象深刻。重要的是在写入之前提取这个文件,否则你将会在你的 SD 卡上简单地写出一个 zip 文件,这根本不能很好地工作。您可以按“提取”按钮,也可以将图像拖到桌面上。两种解决方案都一样有效。

好了,现在你只需要找到图像作者。最简单的方法是按下开始按钮,开始输入“win32DiskImager”,Windows 会自动为你完成(见图 A-4 )。

A978-1-4842-1162-5_14_Fig4_HTML.jpg

图 A-4。

Finding image writer in the start menu

一旦你让它运行起来,它将看起来像图 A-5 。

A978-1-4842-1162-5_14_Fig5_HTML.jpg

图 A-5。

Image Writer reader to go

在图 A-5 中可以看到,已经有相关的细节填写了。您可以看到图像的路径(实际上我已经将它提取到了桌面),并且可以看到它将被写入的设备(在本例中是 E)。这个版本的 Disk Imager 似乎能够检测到应用程序启动后添加的设备。一旦你填写了细节,你只需要按“写”按钮。这应该会给你一个警告提示,如图 A-6 所示。

A978-1-4842-1162-5_14_Fig6_HTML.jpg

图 A-6。

Last chance to change your mind

在这里检查设备名称绝对是值得的,并且最好确保您没有插入任何其他外部设备。例如,你真的不想不小心把图像写到相机的 SD 卡上。我们以前见过这种情况,所以它肯定会发生!

一旦你开始写,你将得到如图 A-7 所示的屏幕。

A978-1-4842-1162-5_14_Fig7_HTML.jpg

图 A-7。

Writing in progress

并且最终是图 A-8 中所示的那个。

A978-1-4842-1162-5_14_Fig8_HTML.jpg

图 A-8。

Just what it says on the tin

一旦你得到上面的弹出窗口,你就知道取出 SD 卡并在 Pi 中使用它是安全的。通常,当写入这类介质时,您需要弹出设备以确保应该写入的所有内容都已写入(因此,当您“不正确地”移除设备时,Windows 会抱怨是有原因的)。当你写一个磁盘映像的时候,你可以绕过文件系统直接写到设备上。

对,就这样,你完了!如果你选择了 Raspbian 并且正在寻找一些帮助来设置它(也许 NOOBS 因为某些原因不适合你),你可以回到第一章并且从第一次启动开始继续。

在 Mac 上使用 dd

如果您使用的是 Mac,我们希望向您展示将图像写入 SD 卡是多么简单。唉,我们做不到这一点,因为没有一个简单、容易的方法来做到这一点(尽管在您阅读本文时可能有一些,所以如果您不想使用 dd,请务必与 Google 核实)。擅长许多其他事情的磁盘工具,只是不知道如何处理我们的标准图像文件。我们试着把它转换成一个.dmg文件(Mac 的原生图像格式),也不行。我们还查看了您可能已经下载的帮助解决问题的在线工具,但我们没有发现任何比首先手动完成任务更容易的东西。

因此,我们将比原计划提前一点接触命令行。我们不会深入讨论我们实际在做什么,因为这些命令中的大部分稍后会在它们的 Linux 版本中看到。现在,你只需要相信我们。

寻找终点站

首先,我们需要打开终端。可以在Applications下的Utilities目录中找到。为了将下面的内容放入上下文中,我们用我们使用的所有命令的完整副本来结束这一部分。这个过程相当简单;它只是有相当数量的活动部件。

我们打开了终端,现在我们需要使用sudo成为根用户,相当于 Windows 机器上的管理员。

现在,出于安全原因,修补低级设备是危险的(例如,你不希望病毒能够直接写入硬盘),所以普通用户不允许发出该级别的命令。因为我们需要将 Raspbian 映像直接写入 SD 卡,所以我们别无选择:我们需要直接访问 sd 卡。幸运的是,root 可以不受限制地访问机器,所以作为 root,我们可以将映像写入卡中。我们需要使用的命令是:

sudo –i

该命令以 root 用户身份打开一个交互式提示符,并授予“超级用户”权限。您可以使用sudo来直接执行命令,但是因为我们将要执行其中的一些命令,所以这样做更方便。sudo然后会提示您输入密码(通常用于您的用户帐户的密码)。一旦sudo能够确认坐在键盘前的真的是你,你将会在根提示符下结束。

Caution

我们现在有权限在系统上做任何我们想做的事情,虽然这意味着我们现在可以制作我们的图像,但这也意味着如果我们不小心,我们真的会把事情搞砸。在 Unix 下,假设 root 知道自己在做什么,并且几乎没有安全防护。以 root 用户身份运行任何命令时都要非常小心,仔细检查(然后再次检查),只有在完全确定的情况下才应该按回车键。完成后,您还应该关闭终端窗口,以防万一。

好吧,现在怎么办?向 SD 卡写入数据的挑战之一是知道 sd 卡实际上是系统上的哪个设备。你不会想不小心把你的主硬盘误认为它,因为那会有一些不愉快的后果。您通常可以做出一些假设(例如,我们知道/dev/disk0 几乎总是会成为系统盘,所以您永远也不会想要写入这个磁盘),但是为了限制风险,我们将按数字来做这件事。

首先,确保您的 SD 卡没有连接到 Mac,然后像这样运行 mount 命令:

mbp:∼ root# mount

/dev/disk0s2 on / (hfs, local, journaled)

devfs on /dev (devfs, local, nobrowse)

map -hosts on /net (autofs, nosuid, automounted, nobrowse)

map auto_home on /home (autofs, automounted, nobrowse)

mbp:∼ root#

现在,你可能会看到类似的东西,但可能会有一点不同。我们可以忽略 devfs 和地图线,因为它们实际上只是操作系统的一部分。我们感兴趣的是/上标识/dev/disk0s2 的第一行。这是系统盘,我们要确保不碰这个。如果您映射了任何网络驱动器或附加了磁盘映像,列表中可能会有其他条目。没关系,因为在这个阶段我们并不真的在寻找什么特别的东西,我们只是想为你的系统建立一个基准。

好了,现在是插入 SD 卡的时候了。SD 卡是预先格式化的,可以在相机中使用(尽管现在很多相机都会重新格式化它们),所以你应该可以在 Finder 的 Devices 下看到它。对于我们的特殊卡片,它看起来像图 A-9 。

A978-1-4842-1162-5_14_Fig9_HTML.jpg

图 A-9。

What you’ll see in Finder after inserting your SD Card

由于卡已经自动挂载,我们现在可以返回并重新运行 mount 命令,看看发生了什么变化。这是我们重新运行时得到的结果:

mbp:∼ root# mount

/dev/disk0s2 on / (hfs, local, journaled)

devfs on /dev (devfs, local, nobrowse)

map -hosts on /net (autofs, nosuid, automounted, nobrowse)

map auto_home on /home (autofs, automounted, nobrowse)

/dev/disk2s2 on /Volumes/UNTITLED (msdos, local, nodev, nosuid, noowners)

mbp:∼ root#

这里我们关心的是添加一个新磁盘,在本例中是 disk2。我们可以从它的挂载位置(/Volumes/UNTITLED)看出这是我们感兴趣的磁盘。所以现在我们知道我们想在哪里写我们的形象。

Info

BSD 系统将磁盘分割成片。在我们的示例中,挂载的文件系统位于 disk2s2 上。这相当于磁盘 2,片 2。这允许您直接引用一个片,但出于我们的目的,我们希望写入设备本身。因此,在我们的例子中,我们将写入/dev/disk2。

不过有一个小问题。当我们安装并使用 SD 卡时,我们不能直接写入 sd 卡。如果我们从 Finder 中弹出它,它不仅会卸载文件系统,还会弹出设备。这对我们没有帮助,因为我们仍然需要设备存在才能写入数据。为了解决这个问题,我们将使用名为“diskutil”的 Mac 专用命令手动卸载文件系统。Mac 确实有通用的 Unix umount 命令(我们将在后面的章节中介绍),但是如果您的 Mac 上的任何东西碰巧在查看 SD 卡,umount 将失败,并声称设备正忙。另一方面,Diskutil 知道这一点,并且通常可以卸载设备而不会有任何问题。对于我们,我们运行以下命令:

mbp:∼ root# diskutil unmount /dev/disk2s2

Volume UNTITLED on disk2s2 unmounted

mbp:∼ root#

在这一切之后,我们获得了超级用户权限,隔离了要写入的设备,卸载了文件系统,这样我们就可以直接写入卡本身。我们现在要做的就是开始写作了!

这项任务选择的工具称为“dd”。这个工具有点老派,因为它只关心从设备读取和向设备写入。它对文件系统不感兴趣,也不知道硬盘和 SD 卡之间的细微差别。它只是读取和写入,而不关心它从哪里读取或写入。这是一个基本的 Unix 原则,我们将在后面的章节中再次讨论。现在,我们将利用这一点在您的 SD 卡上制作一份图像文件的精确副本。

dd 只需要知道两件事,从哪里读取(if=参数)和向哪里写入(of=参数)。我们已经搞清楚了写入位(它将是/dev/disk2 ),但是源代码呢?如果您按照前面的说明进行了操作,那么您应该将图像文件放在您的主区域的下载目录中。将我们需要的信息输入终端的最简单方法是键入:

dd if=

然后,转到 Finder 中的下载目录(或您提取图像文件的位置),单击并按住图像文件,然后将其拖到您的终端窗口。这将为您粘贴完整的路径,而无需您键入任何内容。这意味着您将得到与此非常相似的结果:

dd if=/Users/myuser/Downloads/2012-08-16-wheezy-raspbian.img

现在我们已经指定了输入文件,我们需要做的就是指定我们希望 dd 将它写入的确切位置。由于我们之前的实验,我们知道这将是/dev/disk2。我们还将添加“bs=1M ”,让 dd 以更大的块写入映像(这意味着您不必等待四个小时才能完成)。因此,dd 所需的完整命令如下所示:

dd if=/Users/miggyx/Downloads/2012-08-16-wheezy-raspbian.img of=/dev/disk2 bs=1M

运行此命令可能需要一些时间(即几小时而不是几秒钟)。图像本身的大小约为 2GB,您的普通智能卡阅读器并不是特别快。使用我们的 USB 适配器,我们最近的 MacBook Pro 花了整整 25 分钟。稍后回来后,您应该会发现 dd 已经完成了它的任务,并且您又回到了命令提示符下。

好吧,不可否认,这并不像在 Windows 上写图像那样简单或直接,但是如果你看看我们必须做的一切,使用命令行允许我们以一种非常紧凑和精确的方式表达我们想要的。这是我们在第四章中回顾的内容,在那里我们看到了学习使用命令行的各种好处。

这是我们为了将映像写入磁盘而输入的命令的完整副本。如果我们上面的解释不太符合,或者你不完全确定最终结果应该是什么样的,你可以使用下面的文字记录作为参考,将你的版本与我们的进行比较:

Last login: Wed Sep 19 13:48:40 on ttys000

mbp:∼ pmembrey$ sudo -i

Password:

mbp:∼ root# mount

/dev/disk0s2 on / (hfs, local, journaled)

devfs on /dev (devfs, local, nobrowse)

map -hosts on /net (autofs, nosuid, automounted, nobrowse)

map auto_home on /home (autofs, automounted, nobrowse)

<<SD Card inserted>>

mbp:∼ root# mount

/dev/disk0s2 on / (hfs, local, journaled)

devfs on /dev (devfs, local, nobrowse)

map -hosts on /net (autofs, nosuid, automounted, nobrowse)

map auto_home on /home (autofs, automounted, nobrowse)

/dev/disk2s1 on /Volumes/UNTITLED (msdos, local, nodev, nosuid, noowners)

mbp:∼ root# diskutil unmount /dev/disk2s1

Volume UNTITLED on disk2s1 unmounted

mbp:∼ root# dd if=/Users/pmembrey/Downloads/2012-08-16-wheezy-raspbian.img of=/dev/disk2 bs=1M

mbp:∼ root#

对,有了我们(辛辛苦苦)准备的 SD 卡,终于可以启动 Pi 了!如果你已经安装了 Raspbian 并且你想按照初始配置进行操作,你可以跳回第一章并按照第一次启动时的说明进行操作。祝你好运!

posted @ 2024-08-02 19:35  绝不原创的飞龙  阅读(1)  评论(0编辑  收藏  举报