安卓编年史（22）：周期外更新——谁需要一个新系统？

Summary: 在安卓 4.2 和安卓 4.3 之间，谷歌进行了一次周期外更新，显示了有多少安卓可以不用经过费力的 OTA 更新而得到改进。得益于谷歌 Play 商店和 Play 服务，这些更新可以在不更新任何系统核心组件的前提下送达。

# 安卓编年史（22）：周期外更新——谁需要一个新系统？

*Play 商店又一次重新设计！这一版非常接近现在的设计，卡片结构让改变布局变得易如反掌。 [Ron Amadeo 供图]*

### 周期外更新——谁需要一个新系统？

在安卓 4.2 和安卓 4.3 之间，谷歌进行了一次周期外更新，显示了有多少安卓可以不用经过费力的 OTA 更新而得到改进。得益于[谷歌 Play 商店和 Play 服务](http://arstechnica.com/gadgets/2013/09/balky-carriers-and-slow-oems-step-aside-google-is-defragging-android/)，这些更新可以在不更新任何系统核心组件的前提下送达。

2013 年 4 月，谷歌发布了谷歌 Play 商店的一个主要设计改动。就如同在这之后的大多数重新设计，新的 Play 商店完全接受了 Google Now 审美，即在灰色背景上的白色卡片。操作栏基于当前页面内容部分更改颜色，由于首屏内容以商店的各部分为主，操作栏颜色是中性的灰色。导航至内容部分的按钮指向热门付费，在那下面通常是一块促销内容或一组推荐应用。

*独立的内容部分有漂亮的颜色。 [Ron Amadeo 供图]*

新的 Play 商店展现了谷歌卡片设计语言的真正力量，在所有的屏幕尺寸上能够拥有响应式布局。一张大的卡片能够和若干小卡片组合，大屏幕设备能够显示更多的卡片，而且相对于拉伸来适应横屏模式，可以通过在一行显示更多卡片来适应。Play 商店的内容编辑们也可以自由地使用卡片布局；需要关注的大更新可以获得更大的卡片。这个设计最终会慢慢渗透向其它谷歌 Play 内容应用，最后拥有一个统一的设计。

*Hangouts 取代了 Google Talk，现在仍由 Google+ 团队继续开发。 [Ron Amadeo 供图]*

Google I/O，谷歌的年度开发者会议，通常会宣布一个新的安卓版本。但是 2013 年的会议，谷歌只是发布了一些改进而没有系统更新。

谷歌宣布的大事件之一是 Google Talk 的更新，谷歌的即时消息平台。在很长一段时间里，谷歌随安卓附带四个文本交流应用：Google Talk，Google+ Messenger，信息（短信应用），Google Voice。拥有四个应用来完成相同的任务——给某人发送文本消息——对用户来说很混乱。在 I/O 上，谷歌结束了 Google Talk 并且从头开始创建全新的消息产品 [Google Hangouts](http://arstechnica.com/information-technology/2013/05/hands-on-with-hangouts-googles-new-text-and-video-chat-architecture/)。虽然最初只是想替代 Google Talk，Hangouts 的计划是统一所有谷歌的不同的消息应用到统一的界面下。

Hangouts 的用户界面布局真的和 Google Talk 没什么大的差别。主页面包含你的聊天会话，点击某一项就能进入聊天页面。界面设计上有所更新，聊天页面现在使用了卡片风格来显示每个段落，并且聊天列表是个“抽屉”风格的界面，这意味着你可以通过水平滑动打开它。Hangouts 有已读回执和输入状态指示，并且群聊现在是个主要特性。

Google+ 是 Hangouts 的中心，所以产品的全名实际上是“Google+ Hangouts”。Hangouts 完全整合到了 Google+ 桌面站点。身份和头像直接从 Google+ 拉取，点击头像会打开用户的 Google+ 资料。和将浏览器换为 Google Chrome 类似，核心安卓功能交给了一个单独的团队——Google+ 团队，这是变得越发繁忙的安卓工程师的抗议的结果。随着 Google+ 团队的接手，安卓的主要即时通讯客户端现在成为一个持续开发的应用。它被放进了 Play 商店并且有稳定的更新频率。

*新导航抽屉界面。 图片来自 [developer.android.com](https://developer.android.com/design/patterns/navigation-drawer.html)*

谷歌还给操作栏引入了新的设计元素：导航抽屉。这个抽屉显示为在左上角应用图标旁的三道横线。点击或从屏幕左边缘向右滑动，会出现一个侧边菜单目录。就像名字所指明的，这个是用来在应用内导航的，它会显示若干应用内的顶层位置。这使得应用首屏可以用来显示内容，也给了用户一致的、易于访问的导航元素。导航抽屉基本上就是个大号的菜单，可以滚动并且固定在左侧。

---

[Ron Amadeo](http://arstechnica.com/author/ronamadeo) / Ron是Ars Technica的评论编缉，专注于安卓系统和谷歌产品。他总是在追寻新鲜事物，还喜欢拆解事物看看它们到底是怎么运作的。[@RonAmadeo](https://twitter.com/RonAmadeo)

---

via: <http://arstechnica.com/gadgets/2016/10/building-android-a-40000-word-history-of-googles-mobile-os/23/>

译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](http://linux.cn/) 荣誉推出


掌握 Git 之美

Summary: 使用 7 条简单的 Git 命令开始你的软件开发之旅

可以

使用 7 条简单的 Git 命令开始你的软件开发之旅

# 掌握 Git 之美

>
> 使用 7 条简单的 Git 命令开始你的软件开发之旅
>
>
>

你是否曾经想知道如何学好 Git？你长期以来都是跌跌撞撞地在使用 Git。最终，你总需要掌握它的窍门。这就是我写这篇文章的原因，我将带你去启蒙之旅。这儿是我关于如何加快 Git 学习过程的基本指南。我将介绍 Git 的实际情况以及我使用最多的 7 条 Git 命令。本文主要针对有兴趣的开发人员和大学新生，他们需要关于 Git 的介绍以及如何掌握基础知识。

---

>
> 你可以往前继续阅读整篇文章，或者只读 TLDR; 部分，尽管这将使我很受伤。
>
>
>

### TLDR;

在学习 Git 的过程中，请养成下面这些步骤的习惯：

1. 随时使用 `git status`！
2. 只更改那些你真正想更改的文件。
3. `git add -A` 会是你的朋友。
4. 随时使用命令 `git commit -m "meaningful messages"`。
5. 做任何推送（push）之前先使用命令 `git pull`，但是这需要在你提交过一些更改之后。
6. 最后，`git push`推送提交的更改。

---

### 良宵莫辜负

对任何开发人员来说，通常第一步都是选择一个广泛使用的地方托管他或她的代码库。那就是，[GitHub](https://github.com/)。它是一切有关代码的聚集地。要理解 GitHub 的概念，你先需要知道什么是 Git。

Git 是一款基于命令行的版本控制软件，在 Windows 和 Mac 系统上也有几款可用的桌面应用。 Git 由 Linux 之父 Linus Torvalds 开发，Linus Torvalds 还是是计算机科学中最有影响力的人物之一。因为这一优势，Git 已经成为绝大多数软件开发人员关于共享和维护代码的标准。这一大段话，让我们将其细细道来。正如它的名字所说，版本控制软件 Git 让你可以预览你写过的代码的所有版本。从字面上来说， 开发人员的每个代码库都将永远存储在其各自的仓库中，仓库可以叫做任何名字，从 *pineapple* 到 *express* 都行。在此仓库开发代码的过程中，你将进行出无数次的更改，直到第一次正式发布。这就是版本控制软件如此重要的核心原因所在。它让作为开发人员的你可以清楚地了解对代码库进行的所有更改、修订和改进。从另外一个方面说，它使协同合作更容易，下载代码进行编辑，然后将更改上传到仓库。然而，尽管有了这么多好处，然而还有一件事可以锦上添花。你可以下载并使用这些文件，即使你在整个开发过程中什么事也没有做。

让我们回到文章的 GitHub 部分。它只是所有仓库的枢纽（hub），这些仓库可以存储在其中并在线浏览。它是一个让有着共同兴趣的人相聚的地方。

### 千里之行始于足下

OK，记住，Git 是一款软件，像任何其他软件一样，你首先需要安装它：

[Git - 安装 Git，如果你希望从源代码安装 Git，你需要安装这些 Git 的依赖库： autotools —— 来自 git-scm.com](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)

*Tips：请点击上面的链接，然后按照说明开始。*

完成了安装过程，很好。现在你需要在你的浏览器地址栏输入 [github.com](https://github.com/) 访问该网站。如果你还没有帐号的话需要新创建一个帐号，这就是你的起舞之处。登录并创建一个新仓库，命名为 Steve ，没有什么理由，只是想要一个名为史蒂夫的仓库好玩而已。选中 “Initialize this repository with a README” 复选框并点击创建按钮。现在你有了一个叫做 Steve 的仓库。我相信你会为你自己感到自豪。

### 现在开始在使用 Git

现在是比较有趣的部分。你将把 Steve 克隆到你本地的机器上。可以把这个过程看作从 Github 上复制仓库到你的电脑上。点击 “clone or download” 按钮，你将看到一个类似下面这样的 URL:

```
https://github.com/yourGithubAccountName/Steve.git

```

复制这个 URL 并打开命令提示符窗口。现在输入并运行条命令：

```
git clone https://github.com/yourGithubAccountName/Steve.git

```

Abrakadabra！Steve 仓库已经被自动克隆到了你的电脑上。查看你克隆这个仓库的目录，你会看到一个叫做 Steve 的文件夹。这个本地的文件夹现在已经链接到了它的 “origin” ，也就是 GitHub 上的远程仓库。

记住这个过程，在你的软件开发工程人员的职业生涯中你一定会重复这个过程很多次的。完成所有这些准备工作之后，你就可以开始使用最普通且常用的 Git 命令了。

### 你现在已经开始在真实场景使用 Git 了

找到 Steve 目录并在该目录中打开命令提示符窗口，运行下面的命令：

```
git status

```

这会输出你的工作目录的状态，让你知道所有你编辑过的文件。这意味着它显示了远程库中和本地工作目录中之间的文件差异。`status` 命令被用来作为 `commit` 的模版，我将在这篇教程后面进一步谈论 `commit` 。简单的说，`[git status][1]` 告诉你你编辑过哪些文件，以给你一个你想要上传到远程库的概述。

但是，在你做任何上传之前，你首先需要做的是选择你需要发送回远程库的文件。使用下面命令完成：

```
git add

```

接着在 Steve 目录新建一个文本文件，可以取一个好玩的名字 `pineapple.txt`。在这个文件里面随便写些你想写的内容，返回命令提示符，然后再次输入 `git status`。现在，你将看到这个文件以红色出现在标记 “untracked files” 下面。

```
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be commited)

pineapple.txt

```

下一步就是将它添加到暂存区（staging）。暂存区可以看作是这样的一个环境：你做过的所有更改在提交时都将捆绑为一个更改而被提交。现在，你可以将这个文件加入暂存区：

```
git add -A

```

`-A` 选项意味着所有你更改过的文件都会被加到暂存区等待提交。然而， `git add` 非常灵活，它也可以像这样一个文件一个文件的添加：

```
git add pineapple.txt

```

这种方法让你有能力选择你想要暂存的每一个文件，而不用担心加入那些你不想改变的东西。

再次运行 `git status`，你会看到如下输出：

```
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

new file:   pineapple.txt

```

准备好提交更改了吗？开始吧。

```
git commit -m "Write your message here"

```

[Git commit](https://git-scm.com/docs/git-commit) 命令会将存储在暂存区中的文件和来自用户的用于描述更改的日志信息一起存储在一个新的地方。`-m`选项加入了写在双引号内的信息。

再次检查状态，你会看到：

```
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean

```

所有的更改现在都被加入到一次提交当中了，同时会有一条与你所做相关的信息。现在你可以用 `git push` 将这次提交推送到远程库 “origin”了。这条命令就像字面意义所说，它会把你提交的更改从本地机器上传到 GitHub 的远程仓库中。返回到命令提示符，然后运行：

```
git push

```

你会被要求输入你的 GitHub 帐号和密码，之后你会看到类似下面的这些内容：

```
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 280 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/yourGithubUserName/Steve.git
   c77a97c..08bb95a  master -> master

```

就是这样。你已经成功上传了你本地的更改。看看你在 GitHub 上的仓库，你会看到它现在包含了一叫做 `pineapple.txt` 的文件。

如果你是一个开发小组的一员呢？如果他们都推送提交到 “origin”，将会发生什么？这就是 Git 真正开始发挥它的魔力的时候。你可以使用一条简单的命令轻松地将最新版本的代码库 [pull](https://git-scm.com/docs/git-pull) 到你本地的机器上：

```
git pull

```

但是 Git 也有限制：你需要有相匹配的版本才能推送到 “origin”。这意味着你本地的版本需要和 origin 的版本大致一样。当你从 “origin” 拉取（pull）文件时，在你的工作目录中不能有文件，因为它们将会在这个过程中被覆盖。因此我给出了这条简单的建议。在学习 Git 的过程中，请养成下面这些步骤的习惯：

1. 随时使用 `git status`！
2. 只更改那些你真正想更改的文件。
3. `git add -A` 会是你的朋友。
4. 随时使用命令 `git commit -m "meaningful messages"`。
5. 做任何推送（push）之前先使用命令 `git pull`，但是这需要在你提交过一些更改之后。
6. 最后，`git push`推送提交的更改。

---

嘿！你还在看这篇文章吗？你已经看了很久了，休息一下吧！

休息好了吗？好的！让我们来处理一些错误。如果你不小心更改了一些你本不应该更改的文件后怎么办呢？不需要担心，只需要使用 [git checkout](https://git-scm.com/docs/git-checkout)。让我们在文件 `pineapple.txt` 里更改一些内容：在文件中加入一行，比方说，“Steve is mega-awesome!” 。然后保存更改并用 `git status` 检查一下：

```
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

modified:   pineapple.txt

no changes added to commit (use "git add" and/or "git commit -a")

```

正如预料的那样，它已经被记录为一次更改了。但是，假如 Steve 实际上并不是很优秀呢？假如 Steve 很差劲呢？不用担心！最简单的还原更改的方式是运行命令：

```
git checkout -- pineapple.txt

```

现在你会看到文件已经恢复到了先前的状态。

但是假如你玩砸了呢？我是说，事情已经变得混乱，并且需要把所有东西重置到与 “origin” 一样的状态。也不需要担心，在这种紧急情况下我们可以享受 Git 的美妙之处：

```
git reset --hard

```

[git reset](https://git-scm.com/docs/git-reset) 命令和 `--hard` 选项一起可以抛弃自上次提交以来的所有更改，有些时候真的很好用。

---

最后，我想鼓励你尽可能多地使用 Git。这是能够熟练使用它的最好学习方式。除此之外，养成阅读 Git 文档的习惯。一开始可能会有些云里雾里，但是过段时间后你就会明白它的窍门了。

*希望你们（小伙子和姑娘们）读这篇文章的时候会和我写它时一样的开心。如果你认为这篇文章对别人有用，你尽可以与别人分享它。或者，如果你喜欢这篇文章，你可以在下面点下赞以便让更多的人看到这篇文章。*

---

via: <https://hackernoon.com/how-to-master-the-art-of-git-68e1050f3147>

作者：[Adnan Rahić](https://hackernoon.com/@adnanrahic) 译者：[zhousiyu325](https://github.com/zhousiyu325) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Linux 内核文章特辑

Summary: 备受关注的 LinuxCon 2017（北京）即将在一周后在北京首秀，而国内已经连续举办了 11 届的中国 Linux 内核开发者大会（CLK）也将在金秋十月的北京举办第 12 届。值此 Linux 界两大盛会举办之际，我特意收集了一些 Linux 内核方面的文章分享给大家。

# Linux 内核文章特辑

备受关注的 [LinuxCon 2017（北京）](http://www.bagevent.com/event/561769)即将在一周后在北京首秀，而国内已经连续举办了 11 届的[中国 Linux 内核开发者大会（CLK）](http://www.ckernel.org/)也将在金秋十月的北京举办第 12 届。值此 Linux 界两大盛会举办之际，我特意收集了一些 Linux 内核方面的文章分享给大家。

让我们先以一篇漫画开端：《[漫画赏析：Linux 内核到底长啥样](/article-8290-1.html)》，这篇并不算严谨的漫画，来自极客漫画站 TurnOff.us，由 [LCTT 翻译组](https://linux.cn/lctt/)进行汉化和点评，以有趣的方式向大众展示了内核里面都发生了些什么：

当然， 作为非专业陈述，就不必深究细节了，但是这篇漫画成功地引起了诸多（伪）Linux 内核爱好者的兴趣。

如果你对 Linux 内核发生了兴趣，想要知道 [Linux 内核是如何构建的](/article-6197-1.html)，那这里也有[一篇文章](/article-6197-1.html)可以指导你，这是一篇由 GitHub 上 [0xAX](https://github.com/0xAX) 写的[一系列 Linux 内核文章](https://github.com/0xAX/linux-insides)中的一篇， LCTT 成员 [@mudongliang](https://github.com/mudongliang) 参与了组织翻译。

此系列我们还翻译了数篇数据结构方面的文章，如：[双向链表](/article-7321-1.html)、[基数树](/article-7353-1.html)、[位数组](/article-7707-1.html)，这些在你做内核开发和研究时肯定会用到。当然，Linus Torvalds 大神向来以对进入内核的代码审核严苛而著称，比如说，他曾经就如何[写出具有 “good taste” 的代码](/article-8498-1.html)而发表过演讲。

说起来，现在内核的变化太快了，简直是日新月异，比如说，我们就注意到 [BPF 进入了 4.9 内核](/article-8038-1.html)，它相当于 BSD 中的 DTrace 一样。另外，据闻 Linux 内核将[新增一种异构内存管理](/article-8593-1.html)，将会加快 Linux 上的机器学习处理能力。

这么多的新特性的涌现，背后代表着大量的代码和贡献人员的辛勤付出。据 [2016 年度《Linux 内核开发》报告](/article-7720-1.html)，自版本 3.18 于 2014 年 12 月 7 日发布以来，已合并了近 115000 个变更，这些贡献来自近 500 家公司的 5062 名开发人员。

当然，Linux 内核发展这么迅速，随着影响力的提升，也越来越引起各界的注意，比如说，华盛顿邮报就曾经批评 Linux “没有一个系统性的机制以在骇客之前发现和解决安全问题，或引入更新的防御技术”，“Linux 内核开发社区没有一个首席安全官”等等。针对这篇文章，LWN 上也有人对此进行了一些[回应](/article-7404-1.html)，并就一些问题进行了辨析和反思。

所以，现在 Linux 内核不仅仅需要更好的安全机制的出现和贡献者的努力，也需要[解决 Linux 内核代码审查人员短缺问题](/article-7905-1.html)。

前面说了很多 Linux 内核开发人员更关注的话题， 对于普通的 Linux 用户来说，可能更关注的是如何在 [CentOS](/article-8310-1.html) 和 [Ubuntu](/article-8284-1.html) 上升级内核。不过，现在的内核已经支持[升级后不重启](/article-4656-1.html)了，对于某些内核补丁，可以[热应用](/article-8005-1.html)而不用重启。这对于生产环境中的 Linux 服务器很重要，比如 [Ubuntu](/article-7888-1.html)、[Oracle Linux](/article-6874-1.html) 等发行版已经支持了。

作为 Linux 的使用者，尤其是 Linux 服务器的运维人员，密切监控 Linux 的各项性能指标也是必需的工作，无论是[传统工具](/article-5898-1.html)： top、ps、pstree、[vmstat](/article-8157-1.html)、[iostat](/article-4024-1.html)，还是 [htop](/article-7004-1.html)、 [nmon](/article-6886-1.html)、[ntopng](/article-5664-1.html) 这样的新工具；而且不但有 [cpustat](/article-8466-1.html)、[CoreFreq](/article-8241-1.html) 这样专门监控 CPU 的工具，也有各种大而全的全面监控系统，如 [Glances](/article-6882-1.html)、[netdata](/article-7576-1.html)、 [Munin](/article-6920-1.html)。总之，[用于监控的工具和系统不要太多了](/article-6987-1.html)。

那么，你喜欢 Linux ，喜欢研究下 Linux 内核么？如果是，那么这两场大会你一定要关注：

* [LinuxCon + ContainerCon + CloudOpen China 2017](http://www.bagevent.com/event/561769)
* [中国 Linux 内核开发者大会（CLK）](http://www.ckernel.org/)


Linux GRUB2 配置简介

Summary: 学习 GRUB 引导加载程序是如何预备你的系统并启动操作系统内核的。

不应该是 grub2-mkconfig --output=/boot/grub2/grub.cfg ?

把2去掉

不, 就是 /boot/grub2

各个平台的不一样，有的带有2有的没有. 和版本也有关系

学习 GRUB 引导加载程序是如何预备你的系统并启动操作系统内核的。

# Linux GRUB2 配置简介

>
> 学习 GRUB 引导加载程序是如何预备你的系统并启动操作系统内核的。
>
>
>

<img src="content_image/album_201706_13_061338lskppuy2khsjop12.png" alt="Linux GRUB2 配置简介" title="Linux GRUB2 配置简介">

自从上个月为我的文章《[Linux 引导和启动过程简介](https://opensource.com/article/17/2/linux-boot-and-startup)》做研究开始，我对更深入了解 GRUB2 产生了兴趣。这篇文章提供了配置 GRUB2 的简要介绍。为了简便起见，我大多数情况下会使用 GRUB 指代 GRUB2。

### GRUB

GRUB 来自 GRand Unified Bootloader 的缩写。它的功能是在启动时从 BIOS 接管掌控、加载自身、加载 Linux 内核到内存，然后再把执行权交给内核。一旦内核开始掌控，GRUB 就完成了它的任务，也就不再需要了。

GRUB 支持多种 Linux 内核，并允许用户在启动时通过菜单在其中选择。我发现这是一种非常有用的工具，因为我有很多次遇到一个应用程序或者系统服务在特定内核版本下失败的问题。有好几次，引导到一个较旧的内核时就可以避免类似的问题。默认情况下，使用 `yum` 或 `dnf` 进行更新时会保存三个内核 - 最新的以及两个比较旧的。在被包管理器删除之前所保留的内核数目可以在 `/etc/dnf/dnf.conf` 或 `/etc/yum.conf` 文件中配置。我通常把 `installonly_limit` 的值修改为 9 以便保留 9 个内核。当我不得不恢复到低几个版本的内核时这非常有用。

### GRUB 菜单

GRUB 菜单的功能是当默认的内核不是想要的时，允许用户从已经安装的内核中选择一个进行引导。通过上下箭头键允许你选中想要的内核，敲击回车键会使用选中的内核继续引导进程。

GRUB 菜单也提供了超时机制，因此如果用户没有做任何选择，GRUB 就会在没有用户干预的情况下使用默认内核继续引导。敲击键盘上除了回车键之外的任何键会停止终端上显示的倒数计时器。立即敲击回车键会使用默认内核或者选中的内核继续引导进程。

GRUB 菜单提供了一个 “<ruby> 救援 <rt>  rescue </rt></ruby>” 内核，用于故障排除或者由于某些原因导致的常规内核不能完成启动过程。不幸的是，这个救援内核不会引导到救援模式。文章后面会更详细介绍这方面的东西。

### grub.cfg 文件

`grub.cfg` 文件是 GRUB 配置文件。它由 `grub2-mkconfig` 程序根据用户的配置使用一组主配置文件以及 grub 默认文件而生成。`/boot/grub2/grub.cfg` 文件在 Linux 安装时会初次生成，安装新内核时又会重新生成。

`grub.cfg` 文件包括了类似 Bash 脚本的代码以及一个按照安装顺序排序的已安装内核列表。例如，如果你有 4 个已安装内核，最新的内核索引是 0，前一个内核索引是 1，最旧的内核索引是 3。如果你能访问 `grub.cfg` 文件，你应该去看看感受一下它看起来是什么样。`grub.cfg` 太大也就没有包含在这篇文章中。

### GRUB 配置文件

`grub.cfg` 的主要配置文件都在 `/etc/grub.d` 目录。该目录中的每个文件都包含了最终会整合到 `grub.cfg` 文件中的 GRUB 代码。这些配置文件的命名模式以排序方式设计，这使得最终的 `grub.cfg` 文件可以按正确的顺序整合而成。每个文件都有注释表明该部分的开始和结束，这些注释也是最终的 `grub.cfg` 文件的一部分，从而可以看出每个部分是由哪个文件生成。分隔注释看起来像这样：

```
### BEGIN /etc/grub.d/10_linux ###

### END /etc/grub.d/10_linux ###

```

不要修改这些文件，除非你是一个 GRUB 专家并明白更改会发生什么。无论如何，修改 `grub.cfg` 文件时你也总应该保留一个原始文件的备份。 `40_custom` 和 `41_custom` 这两个特别的文件用于生成用户对 GRUB 配置的修改。你仍然要注意对这些文件的更改的后果，并保存一份原始 `grub.cfg` 文件的备份。

你也可以把你自己的文件添加到 `/etc/grub.d` 目录。这样做的一个可能的原因是为非 Linux 操作系统添加菜单行。要注意遵循命名规则，确保配置文件中额外的菜单选项刚好在 `10_linux` 条目之前或之后。

### GRUB 默认文件

老版本 GRUB 的配置非常简单而明了，我只需要修改 `/boot/grub/grub.conf` 就可以了。对于新版本的 GRUB2，我虽然还可以通过更改 `/boot/grub2/grub.cfg` 来修改，但和老版本的 GRUB 相比，新版本相对更加复杂。另外，安装一个新内核时 `grub.cfg` 可能会被重写，因此任何修改都可能消失。当然，GNU.org 的 GRUB 手册确实有过直接创建和修改 `/boot/grub2/grub.cfg` 的讨论。

一旦你明白了如何做，更改 GRUB2 配置就会变得非常简单。我为之前的文章研究 GRUB2 的时候才明白这个。秘方就在 `/etc/default` 目录里面，一个自然而然称为 `grub` 的文件，它可以通过简单的终端命令操作。`/etc/default` 目录包括了一些类似 Google Chrome、 useradd、 和 grub 程序的配置文件。

`/etc/default/grub` 文件非常简单。这个 `grub` 默认文件已经列出了一些有效的键值对。你可以简单地更改现有键值或者添加其它文件中还没有的键。下面的列表 1 显示了一个没有更改过的 `/etc/default/grub` 文件。

```
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g'
   /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="rd.lvm.lv=fedora_fedora25vm/root
   rd.lvm.lv=fedora_fedora25vm/swap
   rd.lvm.lv=fedora_fedora25vm/usr rhgb quiet"
GRUB_DISABLE_RECOVERY="true"

```

*列表 1：Fedora 25 一个原始 grub 默认文件。*

[GRUB 手册 5.1 章节](https://www.gnu.org/software/grub/manual/grub.html#Simple-configuration)包括了所有可以添加到该 `grub` 文件的键的信息。我只需要修改 `grub` 默认文件已经有的一些键值就够了。让我们看看这些键值以及一些在 grub 默认文件中没有出现的每个键的意义。

* `GRUB_TIMEOUT` 这个键的值决定了显示 GRUB 选择菜单的时间长度。GRUB 提供了同时保存多个安装内核并在启动时使用 GRUB 菜单在其中选择的功能。这个键的默认值是 5 秒，但我通常修改为 10 秒使得有更多时间查看选项并作出选择。
* `GRUB_DISTRIBUTOR` 这个键定义了一个从 `/etc/system-release` 文件中提取发行版本的 [sed](https://en.wikipedia.org/wiki/Sed) 表达式。这个信息用于生成出现在 GRUB 菜单中的每个内核发布版的文本名称，例如 “Fedora” 等。由于不同发行版之间 `system-release` 文件结构的差异，在你的系统中这个 sed 表达式可能有些不同。
* `GRUB_DEFAULT` 决定默认引导哪个内核。如果是 `saved`，这代表最新内核。这里的其它选项如果是数字则代表了 `grub.cfg` 中列表的索引。使用索引号 3，就会总是加载列表中的第四个内核，即使安装了一个新内核之后也是。因此使用索引数字的话，在安装一个新内核后会加载不同的内核。要确保引导特定内核版本的唯一方法是设置 `GRUB_DEFAULT` 的值为想要内核的名称，例如 `4.8.13-300.fc25.x86_64`。
* `GRUB_SAVEDEFAULT` 通常，grub 默认文件中不会指定这个选项。当选择不同内核进行引导时，正常操作下该内核只会启动一次。默认内核不会改变。当其设置为 `true` 并和 `GRUB_DEFAULT=saved` 一起使用时，这个选项会保存一个不同内核作为默认值。当选择不同内核进行引导时会发生这种情况。
* `GRUB_DISABLE_SUBMENU` 一些人可能会希望为 GRUB 菜单创建一个内核的层级菜单结构。这个键和 `grub.cfg` 中一些额外内核配置允许创建这样的层级结构。例如，主菜单中可能有 `production` 和 `test` 子菜单，每个子菜单中包括了一些合适的内核。设置它为 `false` 可以启用子菜单。
* `GRUB_TERMINAL_OUTPUT` 一些环境下可能需要或者必要将输出重定向到一个不同的显示控制台或者终端。默认情况下是把输出发送到默认终端，通常 `console` 等价于 Intel 系列个人电脑的标准输出。另一个有用的选择是在使用串行终端或者 Integrated Lights Out (ILO) 终端连接的数据中心或者实验室环境中指定 `serial`。
* `GRUB_TERMINAL_INPUT` 和 `GRUB_TERMINAL_OUTPUT` 类似，可能需要或者必要重定向输入为串行终端或者 ILO 设备、而不是标准键盘输入。
* `GRUB_CMDLINE_LINUX` 这个键包括了在启动时会传递给内核的命令行参数。注意这些参数会被添加到 `grub.cfg` 所有已安装内核的内核行。这意味着所有已安装的内核在启动时都会有相同的参数。我通常删除 `rhgb` 和 `quiet` 参数以便我可以看到引导和启动时内核和 systemd 输出的所有内核信息消息。
* `GRUB_DISABLE_RECOVERY` 当这个键的值被设置为 `false`，GRUB 菜单中就会为每个已安装的内核创建一个恢复条目。当设置为 `true` 时就不会创建任何恢复条目。但不管这个设置怎样，最后的内核条目总是一个 `rescue` 选项。不过在 rescue 选项中我遇到了一个问题，下面我会详细介绍。

还有一些你可能觉得有用但我没有在这里介绍的键。它们的描述可以在 [GRUB 手册 2](https://www.gnu.org/software/grub/manual/grub.html#Simple-configuration) 的 5.1 章节找到。

### 生成 grub.cfg

完成所需的配置之后，就需要生成 `/boot/grub2/grub.cfg` 文件。这通过下面的命令完成。

```
grub2-mkconfig > /boot/grub2/grub.cfg

```

这个命令按照顺序使用位于 `/etc/grub.d` 的配置文件构建 `grub.cfg` 文件，然后使用 grub 默认文件的内容修改输出以便获得最终所需的配置。`grub2-mkconfig` 命令会尝试定位所有已安装的内核并在 `grub.cfg` 文件的 `10_Linux` 部分新建条目。它还创建一个 `rescue` 条目提供一个用于从 Linux 不能启动的严重问题中恢复的方法。

强烈建议你不要手动编辑 `grub.cfg` 文件，因为任何对该文件的直接修改都会在下一次安装新内核或者手动运行 `grub2-mkconfig` 时被重写。

### 问题

我遇到一个如果没有意识到就可能导致严重后果的 GRUB2 问题。这个救援内核没有启动，反而启动了另外一个内核。我发现那是列表中索引为 1 的内核，也就是列表中的第二个内核。额外的测试发现不管使用原始的还是我生成的 `grub.cfg` 配置文件都会发生这个问题。我在虚拟机和真实硬件上都尝试过而且都发生了这个问题。我只测试了 Fedora 25，因此其它 Fedora 发行版本可能没有这个问题。

注意，从救援内核生成的 “recovery” 内核条目不能引导到维护模式。

我推荐将 grub 默认文件中 `GRUB_DISABLE_RECOVERY` 的值更改为 “false”，然后生成你自己的 `grub.cfg`。这会在 GRUB 菜单中为每个已安装的内核生成可用的恢复条目。这些恢复配置能像期望那样工作，从而从那些需要输入密码登录的内核条目中引导到运行级别 1，也就是进入（不需要密码的）单用户维护模式。你也可以按 `Ctrl-D` 继续正常的引导进入默认运行级别。

### 总结

GRUB 是引导 Linux 计算机到可用状态过程的一系列事件中，发生在 BIOS 之后的第一步。理解如何配置 GRUB 对于恢复或者处理多种类型的问题非常重要。

这么多年来我多次不得不引导到恢复或者救援模式以便解决多种类型的问题。其中的一些问题确实是类似 `/etc/fstab` 或其它配置文件中不恰当条目导致的引导问题，也有一些是由于应用程序或者系统软件和最新的内核不兼容的问题。硬件兼容性问题也可能妨碍特定的内核启动。

我希望这些信息能对你开启 GRUB 配置之旅有所帮助。

（ 题图 ： Internet Archive [Book](https://www.flickr.com/photos/internetarchivebookimages/14746482994/in/photolist-ot6zCN-odgbDq-orm48o-otifuv-otdyWa-ouDjnZ-otGT2L-odYVqY-otmff7-otGamG-otnmSg-rxnhoq-orTmKf-otUn6k-otBg1e-Gm6FEf-x4Fh64-otUcGR-wcXsxg-tLTN9R-otrWYV-otnyUE-iaaBKz-ovcPPi-ovokCg-ov4pwM-x8Tdf1-hT5mYr-otb75b-8Zk6XR-vtefQ7-vtehjQ-xhhN9r-vdXhWm-xFBgtQ-vdXdJU-vvTH6R-uyG5rH-vuZChC-xhhGii-vvU5Uv-vvTNpB-vvxqsV-xyN2Ai-vdXcFw-vdXuNC-wBMhes-xxYmxu-vdXxwS-vvU8Zt) [Images](https://www.flickr.com/photos/internetarchivebookimages/14774719031/in/photolist-ovAie2-otPK99-xtDX7p-tmxqWf-ow3i43-odd68o-xUPaxW-yHCtWi-wZVsrD-DExW5g-BrzB7b-CmMpC9-oy4hyF-x3UDWA-ow1m4A-x1ij7w-tBdz9a-tQMoRm-wn3tdw-oegTJz-owgrs2-rtpeX1-vNN6g9-owemNT-x3o3pX-wiJyEs-CGCC4W-owg22q-oeT71w-w6PRMn-Ds8gyR-x2Aodm-owoJQm-owtGp9-qVxppC-xM3Gw7-owgV5J-ou9WEs-wihHtF-CRmosE-uk9vB3-wiKdW6-oeGKq3-oeFS4f-x5AZtd-w6PNuv-xgkofr-wZx1gJ-EaYPED-oxCbFP). Opensource.com 修改。 CC BY-SA 4.0）

---

作者简介：

David Both - David Both 是一个居住在 Raleigh，北卡罗来纳州的 Linux 和开源倡导者。他在 IT 界已经有超过 40 年，并在他工作的 IBM 执教 OS/2 20 多年。在 IBM 的时候，他在 1981 年开设了第一个最初 IBM 个人电脑的培训课程。他在红帽教授过 RHCE 课程并在 MCI Worldcom、 Cisco、 和北卡罗来纳州工作过。他已经在 Linux 和开源软件方面工作将近 20 年。

---

via: <https://opensource.com/article/17/3/introduction-grub2-configuration-linux>

作者：[David Both](https://opensource.com/users/dboth) 译者：[ictlyh](https://github.com/ictlyh) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


机器学习的新捷径：通过 SYCL 在 GPU 上加速 C++

Summary: 不幸的是，对于日常程序员，OpenCL 的学习曲线陡峭；一个简单的 Hello World 程序可能就需要上百行晦涩难懂的代码。因此，为了减轻这种痛苦，Khronos 组织已经开发了一个称为 SYCL 的新标准，这是一个在 OpenCL 之上的 C++ 抽象层。

# 机器学习的新捷径：通过 SYCL 在 GPU 上加速 C++

在机器学习、计算机视觉以及高性能计算领域，充分利用显卡计算应用程序的能力已成为当前的热门。类似 OpenCL 的技术通过硬件无关的编程模型展现了这种能力，使得你可以编写抽象于不同体系架构的代码。它的目标是“一次编写，到处运行”，不管它是 Intel CPU、AMD 独立显卡还是 DSP 等等。不幸的是，对于日常程序员，OpenCL 的学习曲线陡峭；一个简单的 Hello World 程序可能就需要上百行晦涩难懂的代码。因此，为了减轻这种痛苦，Khronos 组织已经开发了一个称为 [SYCL](https://www.khronos.org/sycl) 的新标准，这是一个在 OpenCL 之上的 C++ 抽象层。通过 SYCL，你可以使用干净、现代的 C++ 开发出这些通用 GPU（GPGPU）应用程序，而无需拘泥于 OpenCL。下面是一个使用 SYCL 开发，通过并行 STL 实现的向量乘法事例：

```
#include <vector>
#include <iostream>

#include <sycl/execution_policy>
#include <experimental/algorithm>
#include <sycl/helpers/sycl_buffers.hpp>

using namespace std::experimental::parallel;
using namespace sycl::helpers;

int main() {
  constexpr size_t array_size = 1024*512;
  std::array<cl::sycl::cl_int, array_size> a;
  std::iota(begin(a),end(a),0);

  {
    cl::sycl::buffer<int> b(a.data(), cl::sycl::range<1>(a.size()));
    cl::sycl::queue q;
    sycl::sycl_execution_policy<class Mul> sycl_policy(q);
    transform(sycl_policy, begin(b), end(b), begin(b),
              [](int x) { return x*2; });
  }
}

```

为了作为对比，下面是一个通过 C++ API 使用 OpenCL 编写的大概对应版本（无需花过多时间阅读，只需注意到它看起来难看而且冗长）。

```
#include <iostream>
#include <array>
#include <numeric>
#include <CL/cl.hpp>

int main(){
    std::vector<cl::Platform> all_platforms;
    cl::Platform::get(&all_platforms);
    if(all_platforms.size()==0){
        std::cout<<" No platforms found. Check OpenCL installation!\n";
        exit(1);
    }
    cl::Platform default_platform=all_platforms[0];

    std::vector<cl::Device> all_devices;
    default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);
    if(all_devices.size()==0){
        std::cout<<" No devices found. Check OpenCL installation!\n";
        exit(1);
    }

    cl::Device default_device=all_devices[0];
    cl::Context context({default_device});

    cl::Program::Sources sources;
    std::string kernel_code=
        "   void kernel mul2(global int* A){"
        "       A[get_global_id(0)]=A[get_global_id(0)]*2;"
        "   }";
    sources.push_back({kernel_code.c_str(),kernel_code.length()});

    cl::Program program(context,sources);
    if(program.build({default_device})!=CL_SUCCESS){
        std::cout<<" Error building: "<<program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device)<<"\n";
        exit(1);
    }

    constexpr size_t array_size = 1024*512;
    std::array<cl_int, array_size> a;
    std::iota(begin(a),end(a),0);

    cl::Buffer buffer_A(context,CL_MEM_READ_WRITE,sizeof(int)*a.size());
    cl::CommandQueue queue(context,default_device);

    if (queue.enqueueWriteBuffer(buffer_A,CL_TRUE,0,sizeof(int)*a.size(),a.data()) != CL_SUCCESS) {
        std::cout << "Failed to write memory;n";
        exit(1);
    }

    cl::Kernel kernel_add = cl::Kernel(program,"mul2");
    kernel_add.setArg(0,buffer_A);

    if (queue.enqueueNDRangeKernel(kernel_add,cl::NullRange,cl::NDRange(a.size()),cl::NullRange) != CL_SUCCESS) {
        std::cout << "Failed to enqueue kernel\n";
        exit(1);
    }

    if (queue.finish() != CL_SUCCESS) {
        std::cout << "Failed to finish kernel\n";
        exit(1);
    }

    if (queue.enqueueReadBuffer(buffer_A,CL_TRUE,0,sizeof(int)*a.size(),a.data()) != CL_SUCCESS) {
        std::cout << "Failed to read result\n";
        exit(1);
    }
}

```

在这篇博文中我会介绍使用 SYCL 加速你 GPU 上的 C++ 代码。

### GPGPU 简介

在我开始介绍如何使用 SYCL 之前，我首先给那些不熟悉这方面的人简要介绍一下为什么你可能想要在 GPU 上运行计算任务。如果已经使用过 OpenCL、CUDA 或类似的库，可以跳过这一节。

GPU 和 CPU 的一个关键不同就是 GPU 有大量小的、简单的处理单元，而不是少量（对于普通消费者桌面硬件通常是 1-8 个）复杂而强大的核。

上面是一个 4 核 CPU 的简单漫画示意图。每个核都有一组寄存器以及不同等级的缓存（有些是共享缓存、有些不是），然后是主内存。

在 GPU 上，多个小处理单元被组成一个执行单元。每个小处理单元都附有少量内存，每个执行单元都有一些共享内存用于它的处理单元。除此之外，还有一些 GPU 范围的内存，然后是 CPU 使用的主内存。执行单元内部的单元是 *lockstep* ，每个单元都在不同的数据片上执行相同的指令。

这可以使 GPU 同时处理大量的数据。如果是在 CPU 上，也许你可以使用多线程和向量指令在给定时间内完成大量的工作，但是 GPU 所能处理的远多于此。在 GPU 上一次性能够处理的数据规模使得它非常适合于类似图形（duh）、数学处理、神经网络等等。

GPGPU 编程的很多方面使得它和日常的 CPU 编程完全不同。例如，从主内存传输数据到 GPU 是*很慢的*。*真的*很慢。会完全干掉你的性能使你慢下来。因此，GPU 编程的权衡是尽可能多地利用加速器的高吞吐量来掩盖数据来往的延迟。

这里还有一些不那么明显的问题，例如分支的开销。由于执行单元内的处理单元按照 lockstep 工作，使它们执行不同路径（不同的控制流）的嵌套分支就是个真正的问题。这通常通过在所有单元上执行所有分支并标记出无用结果来解决。这是一个基于嵌套级别的指数级的复杂度，这当然是坏事情。当然，有一些优化方法可以拯救该问题，但需要注意：你从 CPU 领域带来的简单假设和知识在 GPU 领域可能导致大问题。

在我们回到 SYCL 之前，需要介绍一些术语。<ruby> 主机 <rp>  （ </rp> <rt>  host </rt> <rp>  ） </rp></ruby>是主 CPU 运行的机器，<ruby> 设备 <rp>  （ </rp> <rt>  device </rt> <rp>  ） </rp></ruby>是会运行你 OpenCL 代码的地方。设备可能就是主机，但也可能是你机器上的一些加速器、模拟器等。<ruby> 内核 <rp>  （ </rp> <rt>  kernel </rt> <rp>  ） </rp></ruby>是一个特殊函数，它是在你设备上运行代码的入口点。通常还会提供一些主机设置好的缓存给它用于输入和输出数据。

### 回到 SYCL

这里有两个可用的 SYCL 实现：[triSYCL](https://github.com/Xilinx/triSYCL)，由 Xilinx 开发的实验性开源版本（通常作为标准的试验台使用），以及 [ComputeCpp](https://www.codeplay.com/products/computesuite/computecpp)，由 Codeplay（我在 Codeplay 工作，但这篇文章是在没有我雇主建议的情况下使用我自己时间编写的） 开发的工业级实现（当前处于开发测试版）。只有 ComputeCpp 支持在 GPU 上执行内核，因此在这篇文章中我们会使用它。

第一步是在你的机器上配置以及运行 ComputeCpp。主要组件是一个实现了 SYCL API 的运行时库，以及一个基于 Clang 的编译器，它负责编译你的主机代码和设备代码。在本文写作时，已经在 Ubuntu 和 CentOS 上官方支持 Intel CPU 以及某些 AMD GPU。在其它 Linux 发行版上让它工作也非常简单（例如，我让它在我的 Arch 系统上运行）。对更多的硬件和操作系统的支持正在进行中，查看[支持平台文档](https://www.codeplay.com/products/computesuite/computecpp/reference/platform-support-notes)获取最新列表。[这里](https://www.codeplay.com/products/computesuite/computecpp/reference/release-notes/)列出了依赖和组件。你也可能想要下载 [SDK](https://github.com/codeplaysoftware/computecpp-sdk)，其中包括了示例、文档、构建系统集成文件，以及其它。在这篇文章中我会使用 [SYCL 并行 STL](https://github.com/KhronosGroup/SyclParallelSTL)，如果你想要自己在家学习的话也要下载它。

一旦你设置好了一切，我们就可以开始通用 GPU 编程了！正如简介中提到的，我的第一个示例使用 SYCL 并行 STL 实现。我们现在来看看如何使用纯 SYCL 编写代码。

```
#include <CL/sycl.hpp>

#include <array>
#include <numeric>
#include <iostream>

int main() {
      const size_t array_size = 1024*512;
      std::array<cl::sycl::cl_int, array_size> in,out;
      std::iota(begin(in),end(in),0);

      {
          cl::sycl::queue device_queue;
          cl::sycl::range<1> n_items{array_size};
          cl::sycl::buffer<cl::sycl::cl_int, 1> in_buffer(in.data(), n_items);
          cl::sycl::buffer<cl::sycl::cl_int, 1> out_buffer(out.data(), n_items);

          device_queue.submit([&](cl::sycl::handler &cgh) {
              constexpr auto sycl_read = cl::sycl::access::mode::read;
              constexpr auto sycl_write = cl::sycl::access::mode::write;

              auto in_accessor = in_buffer.get_access<sycl_read>(cgh);
              auto out_accessor = out_buffer.get_access<sycl_write>(cgh);

              cgh.parallel_for<class VecScalMul>(n_items,
                  [=](cl::sycl::id<1> wiID) {
                      out_accessor[wiID] = in_accessor[wiID]*2;
                  });
         });
     }
}

```

我会把它划分为一个个片段。

```
#include <CL/sycl.hpp>

```

我们做的第一件事就是包含 SYCL 头文件，它会在我们的命令中添加 SYCL 运行时库。

```
const size_t array_size = 1024*512;
std::array<cl::sycl::cl_int, array_size> in,out;
std::iota(begin(in),end(in),0);

```

这里我们构造了一个很大的整型数组并用数字 `0` 到 `array_size-1` 初始化（这就是 `std::iota` 所做的）。注意我们使用 `cl::sycl::cl_int` 确保兼容性。

```
{
    //...
}

```

接着我们打开一个新的作用域，其目的为二：

1. `device_queue` 将在该作用域结束时解构，它将阻塞，直到内核完成。
2. `in_buffer` 和 `out_buffer` 也将解构，这将强制数据传输回主机并允许我们从 `in` 和 `out` 中访问数据。 `cl::sycl::queue device_queue;`

现在我们创建我们的命令队列。命令队列是所有工作（内核）在分发到设备之前需要入队的地方。有很多方法可以定制队列，例如说提供设备用于入队或者设置异步错误处理器，但对于这个例子默认构造器就可以了；它会查找兼容的 GPU，如果失败的话会回退到主机 CPU。

```
cl::sycl::range<1> n_items{array_size};

```

接下来我们创建一个范围，它描述了内核在上面执行的数据的形状。在我们简单的例子中，它是一个一维数组，因此我们使用 `cl::sycl::range<1>`。如果数据是二维的，我们就会使用 `cl::sycl::range<2>`，以此类推。除了 `cl::sycl::range`，还有 `cl::sycl::ndrange`，它允许你指定工作组大小以及越界范围，但在我们的例子中我们不需要使用它。

```
cl::sycl::buffer<cl::sycl::cl_int, 1> in_buffer(in.data(), n_items);
cl::sycl::buffer<cl::sycl::cl_int, 1> out_buffer(out.data(), n_items);

```

为了控制主机和设备之间的数据共享和传输，SYCL 提供了一个 `buffer` 类。我们创建了两个 SYCL 缓存用于管理我们的输入和输出数组。

```
      device_queue.submit([&](cl::sycl::handler &cgh) {/*...*/});

```

设置好了我们所有数据之后，我们就可以入队真正的工作。有多种方法可以做到，但设置并行执行的一个简单方法是在我们的队列中调用 `.submit` 函数。对于这个函数我们传递了一个运行时调度该任务时会被执行的“命令组伪函数”（伪函数是规范，不是我创造的）。命令组处理器设置任何内核需要的余下资源并分发它。

```
constexpr auto sycl_read = cl::sycl::access::mode::read_write;
constexpr auto sycl_write = cl::sycl::access::mode::write;

auto in_accessor = in_buffer.get_access<sycl_read>(cgh);
auto out_accessor = out_buffer.get_access<sycl_write>(cgh);

```

为了控制到我们缓存的访问并告诉该运行时环境我们会如何使用数据，我们需要创建访问器。很显然，我们创建了一个访问器用于从 `in_buffer` 读入，一个访问器用于写到 `out_buffer`。

```
cgh.parallel_for<class VecScalMul>(n_items,
    [=](cl::sycl::id<1> wiID) {
         out_accessor[wiID] = in_accessor[wiID]*2;
    });

```

现在我们已经完成了所有设置，我们可以真正的在我们的设备上做一些计算了。这里我们根据范围 `n_items` 在命令组处理器 `cgh` 之上分发一个内核。实际内核自身是一个使用 work-item 标识符作为输入、输出我们计算结果的 lamda 表达式。在这种情况下，我们从 `in_accessor` 使用 work-item 标识符作为索引读入，将其乘以 `2`，然后将结果保存到 `out_accessor` 相应的位置。`<class VecScalMul>` 是一个为了在标准 C++ 范围内工作的不幸的副产品，因此我们需要给内核一个唯一的类名以便编译器能完成它的工作。

```
}

```

在此之后，我们现在可以访问 `out` 并期望看到正确的结果。

这里有相当多的新概念在起作用，但使用这些技术你可以看到这些能力和所展现出来的东西。当然，如果你只是想在你的 GPU 上执行一些代码而不关心定制化，那么你就可以使用 SYCL 并行 STL 实现。

### SYCL 并行 STL

SYCL 并行 STL 是一个 TS 的并行化实现，它分发你的算法函数对象作为 SYCL 内核。在这个页面前面我们已经看过这样的例子，让我们来快速过一遍。

```
#include <vector>
#include <iostream>

#include <sycl/execution_policy>
#include <experimental/algorithm>
#include <sycl/helpers/sycl_buffers.hpp>

using namespace std::experimental::parallel;
using namespace sycl::helpers;

int main() {
  constexpr size_t array_size = 1024*512;
  std::array<cl::sycl::cl_int, array_size> in,out;
  std::iota(begin(in),end(in),0);

  {
    cl::sycl::buffer<int> in_buffer(in.data(), cl::sycl::range<1>(in.size()));
    cl::sycl::buffer<int> out_buffer(out.data(), cl::sycl::range<1>(out.size()));
    cl::sycl::queue q;
    sycl::sycl_execution_policy<class Mul> sycl_policy(q);
    transform(sycl_policy, begin(in_buffer), end(in_buffer), begin(out_buffer),
              [](int x) { return x*2; });
  }
}

```

```
  constexpr size_t array_size = 1024*512;
  std::array<cl::sycl::cl_int, array_size> in, out;
  std::iota(begin(in),end(in),0);

```

到现在为止一切如此相似。我们再一次创建一组数组用于保存我们的输入输出数据。

```
cl::sycl::buffer<int> in_buffer(in.data(), cl::sycl::range<1>(in.size()));
cl::sycl::buffer<int> out_buffer(out.data(), cl::sycl::range<1>(out.size()));
cl::sycl::queue q;

```

这里我们创建类似上个例子的缓存和队列。

```
sycl::sycl_execution_policy<class Mul> sycl_policy(q);

```

这就是有趣的部分。我们从我们的队列中创建 `sycl_execution_policy`，给它一个名称让内核使用。这个执行策略然后可以像 `std::execution::par` 或 `std::execution::seq` 那样使用。

```
transform(sycl_policy, begin(in_buffer), end(in_buffer), begin(out_buffer),
          [](int x) { return x*2; });

```

现在我们的内核分发看起来像提供了一个执行策略的 `std::transform` 调用。我们传递的闭包会被编译并在设备上执行，而不需要我们做其它更加复杂的设置。

当然，除了 `transform` 你可以做更多。开发的时候，SYCL 并行 STL 支持以下算法：

* `sort`
* `transform`
* `for_each`
* `for_each_n`
* `count_if`
* `reduce`
* `inner_product`
* `transform_reduce`

这就是这篇短文需要介绍的东西。如果你想和 SYCL 的开发保持同步，那就要看 [sycl.tech](http://sycl.tech/)。最近重要的开发就是移植 [Eigen](https://github.com/ville-k/sycl_starter) 和 [Tensorflow](http://deep-beta.co.uk/setting-up-tensorflow-with-opencl-using-sycl/) 到 SYCL ，为 OpenCL 设备带来引入关注的人工智能编程。对我个人而言，我很高兴看到高级编程模型可以用于异构程序自动优化，以及它们是怎样支持类似 [HPX](https://github.com/STEllAR-GROUP/hpx) 或 [SkelCL](https://github.com/skelcl/skelcl) 等更高级的技术。

---

via: <https://blog.tartanllama.xyz/c++/2017/05/19/sycl/>

作者：[TartanLlama](https://www.twitter.com/TartanLlama) 译者：[ictlyh](https://github.com/ictlyh) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何用树莓派控制 GPIO 引脚并操作继电器

Summary: 学习如何用 PHP 和温度传感器实现树莓派控制 GPIO 并操作继电器

树梅派最好玩的就是你可以自由的构建自己的玩具。任何其他硬件没有这种优势

什么叫任何硬件？类似树莓派的硬件就有不好。加上那些爱破解手机，游戏机的。还有自己设计电路板，好像有个俄罗斯人自己用晶体管，还是电子管，体积有几个机柜，但可以玩俄罗斯方块的计算机。P.S. 树莓派的“莓”字错了。

17岁的阿三能写出这样的文章让中国的高中生感到惭愧。另外，我感觉树莓派只适合搭建 demo，稳定性、散热等方面均有不少问题，你不会想因为树莓派放家里电器短路烧了吧。

印度软件就是强啊。

那是你没见识过中国现在的小学生,初中生和高中生.<br />
据我所知, 有个初中生自己设计电路, 自己规划软硬件成本, 在论坛内发起小规模众筹, 做出了一款基于Linux的图形计算器

学习如何用 PHP 和温度传感器实现树莓派控制 GPIO 并操作继电器

# 如何用树莓派控制 GPIO 引脚并操作继电器

>
> 学习如何用 PHP 和温度传感器实现树莓派控制 GPIO 并操作继电器
>
>
>

你是否曾经想知道怎样使用手机或者电脑在任何地方控制你的风扇和灯等一些家用电器？

我现在想控制我的圣诞彩灯，是使用手机呢，还是使用平板电脑呢，或者是使用笔记本电脑呢？都不是，而是仅仅使用一个树莓派。让我来告诉你如何使用 PHP 和温度传感器实现树莓派控制 GPIO 引脚并操作继电器。我使用 AJAX 把它们整合在了一起。

### 硬件要求：

* 树莓派
* 安装有 Raspbian 系统的 SD 卡（任何一张 SD 卡都可以，但是我更偏向使用大小为 32GB 等级为 class 10 的 SD 卡）
* 电源适配器
* 跳线（母对母跳线和公转母跳线）
* 继电器板（我使用一个用于 12V 继电器的继电器板）
* DS18B20 温度传感器
* 树莓派的 Wi-Fi 适配器
* 路由器（为了访问互联网，你需要有一个拥有端口转发的路由器）
* 10KΩ 的电阻

### 软件要求：

* 下载并安装 Raspbian 系统到你的 SD 卡
* 有效的互联网连接
* Apache web 服务器
* PHP
* WiringPi
* 基于 Mac 或者 Windows 的 SSH 客户端

### 一般的配置和设置

1、 插入 SD 卡到树莓派，然后使用以太网网线将它连接到路由器；

2、 连接 WiFi 适配器；

3、 使用 SSH 方式登录到树莓派，然后使用下面的命令编辑 `interfaces` 文件：

```
sudo nano /etc/network/interfaces

```

这个命令会用一个叫做 `nano` 的编辑器打开这个文件。它是一个非常简单又易于使用的文本编辑器。如果你不熟悉基 Linux 的操作系统，可以使用键盘上的方向键来操作。

用 `nano` 打开这个文件后，你会看到这样一个界面：

4、要配置你的无线网络，按照下面所示修改这个文件：

```
iface lo inet loopback
iface eth0 inet dhcp
allow-hotplug wlan0
auto wlan0
iface wlan0 inet dhcp
   wpa-ssid "Your Network SSID"
   wpa-psk "Your Password"

```

5、 按 `CTRL+O` 保存，然后按 `CTRL+X` 退出编辑器。

到目前为止，一切都已经配置完成，接下来你需要做的就是使用命令重新加载网络：

```
sudo service networking reload

```

（警告：如果你是使用远程连接的方式连接的树莓派，连接将会中断。)

### 软件配置

#### 安装 Apache web 服务器

Apache 是一个受欢迎的服务器应用，你可以在树莓派安装这个程序让它提供网页服务。Apache 原本就可以通过 HTTP 方式提供 HTML 文件服务，添加其他模块后，Apache 还可以使用像 PHP 这样的脚本语言来提供动态网页的服务。

可以在命令行输入下面命令安装 Apache：

```
sudo apt-get install apache2 -y

```

安装完成后，可以在浏览器地址栏输入树莓派的 IP 地址来测试 web 服务器。如果你可以获得下面图片的内容，说明你已经成功地安装并设置好了你的服务器。

要改变这个默认的页面和添加你自己的 html 文件，进入 `var/www/html` 目录：

```
cd /var/www/html

```

添加一些文件来测试是否成功。

#### 安装 PHP

PHP 是一个预处理器，这意味着它是当服务器收到网页请求时才会运行的一段代码。它开始运行，处理网页上需要被显示的内容，然后把网页发送给浏览器。不像静态的 HTML，PHP 在不同的环境下可以显示不同的内容。其他的语言也可以做到这一点，但是由于 WordPress 是用 PHP 编写的，有些时候你需要使用它。PHP 是 web 上一种非常受欢迎的语言，像 Facebok 和 Wikipeadia 这样的大型项目都是用 PHP 编写的。

使用下面的命令安装 PHP 和 Apache 软件包：

```
sudo apt-get install php5 libapache2-mod-php5 -y

```

#### 测试 PHP

创建文件 `index.php`：

```
sudo nano index.php

```

在里面写入一些 PHP 内容：

```
<?php echo "hello world"; ?>

```

保存文件，接下来删除 `index.html`，因为它比 `index.php` 的优先级更高：

```
sudo rm index.html

```

刷新你的浏览器，你会看到 “hello world”。这并不是动态的，但是它仍然由 PHP 提供服务。如果你在上面看到提原始的 PHP 文件而不是“hello world”，重新加载和重启 Apahce（LCTT 译注，重启即可）：

```
sudo /etc/init.d/apache2 reload
sudo /etc/init.d/apache2 restart

```

#### 安装 WiringPi

为了可以对代码的更改进行跟踪，WiringPi 的维护采用 git。但假如你因为某些原因而没法使用 git，还有一种可以替代的方案。（通常你的防火墙会把你隔离开来，所以请先检查一下你的防火墙的设置情况！）

如果你还没有安装 git，那么在 Debian 及其衍生版本中（比如 Raspbian），你可以这样安装它：

```
sudo apt-get install git-core

```

若是你遇到了一些错误，请确保你的树莓派是最新版本的 Raspbian 系统：

```
sudo apt-get update sudo apt-get upgrade

```

使用 git 获取最 WiringPi：

```
sudo git clone git://git.drogon.net/wiringPi

```

如果你之前已经使用过 clone 操作，那么可以使用下面命令：

```
cd wiringPi && git pull origin

```

这个命令会将会获取更新的版本，你然后可以重新运行下面的构建脚本。

有一个新的简化的脚本来构建和安装:

```
cd wiringPi && ./build

```

这个新的构建脚本将会为你完成编译和安装 WiringPi。它曾一度需要使用 `sudo` 命令，所以在运行这它之前你可能需要检查一下这个脚本。

#### 测试 WiringPi

运行 `gpio` 命令来检查安装成功与否:

```
gpio -v gpio readall

```

这将给你一些信心，软件运行良好。

#### 连接 DS18B20 传感器到树莓派

* 传感器上的黑线用于 GND。
* 红线用于 VCC。
* 黄线是 GPIO 线。

连线：

* VCC 连接 3V 的 1 号引脚。
* GPIO 线连接 7 号引脚（GPIO4）。
* 地线连接 GND 的 9 号引脚。

#### 软件配置

为了用 PHP 使用 DS18B20 温度传感器模块，你需要执行下面的命令来激活用于树莓派上 GPIO 引脚和 DS18B20 的内核模块：

```
sudo modprobe w1-gpio
sudo modprobe w1-therm

```

你不想每次 Raspberry 重启后都手动执行上述命令，所以你想每次开机能自动启动这些模块。可以在文件 `/etc/modules` 中添加下面的命令行来做到：

```
sudo nano /etc/modules/

```

添加下面的命令行到它里面:

```
w1-gpio
w1-therm

```

为了测试，输入:

```
cd /sys/bus/w1/devices/

```

现在输入 `ls`。

你会看到你的设备信息。在设备驱动程序中，你的 DS18B20 传感器应该作为一串字母和数字被列出。在本例中，设备被记录为 `28-000005e2fdc3`。然后你需要使用 `cd` 命令来访问传感器，用你自己的序列号替代我的： `cd 28-000005e2fdc3`。

DS18B20 会周期性的将数据写入文件 `w1_slave`，所以你只需要使用命令 `cat`来读出数据： `cat w1_slave`。

这会生成下面的两行文本，输出中 `t=` 表示摄氏单位的温度。在前两位数后面加上一个小数点(例如，我收到的温度读数是 30.125 摄氏度)。

### 连接继电器

1、 取两根跳线，把其中一根连接到树莓派上的 GPIO24（18 号引脚），另一根连接 GND 引脚。你可以参考下面这张图。

2、 现在将跳线的另一端连接到继电器板。GND 连接到继电器上的 GND，GPIO 输出线连接到继电器的通道引脚号，这取决于你正使用的继电器型号。记住，将树莓派上的 GND 与继电器上的 GND 连接连接起来，树莓派上的 GPIO 输出连接继电器上的输入引脚。

注意！将继电器连接树莓派的时候小心一些，因为它可能会导致电流回流，这会造成短路。

3、 现在将电源连接继电器，可以使用 12V 的电源适配器，也可以将 VCC 引脚连接到什么破上的 3.3V 或 5.5V 引脚。

### 使用 PHP 控制继电器

让我们先写一个借助于 WiringPi 软件用来控制 Paspberry Pi 上 GPIO 引脚的 PHP 脚本。

1、在 Apache 服务器的网站根目录下创建一个文件，使用下面命令切换到该目录：

```
cd /var/www/html

```

2、 新建一个叫 `Home` 的文件夹：

```
sudo mkdir Home

```

3、 新建一个叫 `on.php`的脚本

```
sudo nano on.php

```

4、 在脚本中加入下面的代码：

```
<?php
        system("gpio-g mode 24 out");
        system("gpio-g write 24 1");
?>

```

5、 使用 `CTRL+O` 保存文件，`CTRL+X` 退出。

上面的代码中，你在第一行使用命令将 24 号 GPIO引脚设置为 output 模式：

```
system("gpio-g mode 24 out");

```

在第二行，你使用 `1` 将 24 号引脚 GPIO 打开，在二进制中"1"表示打开，"0"表示关闭。

6、 为了关闭继电器，可以创建另外一个 `off.php` 文件，并用 `0` 替换 `1`。

```
<?php
        system(" gpio-g mode 24 out ");
        system(" gpio-g write 24 1 ");
?>

```

7、 如果你已经将继电器连接了树莓派，可以在浏览器中输入你的树莓派的 IP 地址，并在后面加上目录名和文件名来进行访问：

```
http://{IPADDRESS}/home/on.php

```

这将会打开继电器。

8、 要关闭它，可以访问叫 `off.php` 的文件：

```
http://{IPADDRESS}/home/off.php

```

现在你需要能够在一个单独的页面来控制这两样事情，而不用单独的刷新或者访问这两个页面。你可以使用 AJAX 来完成。

9、 新建一个 HTML 文件，并在其中加入下面代码：

```
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">// <![CDATA[
$(document).ready(function() {
  $('#on').click(function(){
  var a= new XMLHttpRequest();
  a.open("GET", "on.php"); a.onreadystatechange=function(){
    if (a.readyState==4){
      if(a.status ==200){
      } else alert ("http error");
      }
    }
    a.send();
  });
});
$(document).ready(function()
  {
    $('#Off').click(function(){
      var a= new XMLHttpRequest();
      a.open("GET", "off.php");
      a.onreadystatechange=function(){
        if(a.readyState==4){
          if(a.status ==200){
          } else alert ("http error");
          }
        }
      a.send();
    });
  });
</script>
<button id="on" type="button"``Switch Lights On </button>
<button id="off" type="button"``Switch Lights Off </button>

```

10、 保存文件，进入你的 web 浏览器目录，然后打开那个网页。你会看到两个按钮，它们可以打开和关闭灯泡。基于同样的想法，你还可以使用 bootstrap 和 CSS 来创建一个更加漂亮的 web 界面。

### 在这个网页上观察温度

1、 新建一个 `temperature.php` 的文件：

```
sudo nano temperature.php

```

2、 在文件中加入下面的代码，用你自己的设备 ID 替换 `10-000802292522`：

```
<?php
//File to read
$file = '/sys/devices/w1_bus_master1/10-000802292522/w1_slave';
//Read the file line by line
$lines = file($file);
//Get the temp from second line
$temp = explode('=', $lines[1]);
//Setup some nice formatting (i.e., 21,3)
$temp = number_format($temp[1] / 1000, 1, ',', '');
//And echo that temp
echo $temp . " °C";
?>

```

3、 打开你刚刚创建的 HTML 文件，并创建一个新的带有 `id` 为 “screen” 的 `<div>`标签

```
<div id="screen"></div>

```

4、 在这个标签后或者这个文档的尾部下面的代码：

```
<script>
$(document).ready(function(){
  setInterval(function(){
    $("#screen").load('temperature.php')
  }, 1000);
});
</script>

```

其中，`#screen` 是标签 `<div>` 的 `id` ，你想在它里面显示温度。它会每隔 1000 毫秒加载一次 `temperature.php` 文件。

我使用了 bootstrap 框架来制作一个漂亮的面板来显示温度，你还可以加入多个图标和图形让网页更有吸引力。

这只是一个控制继电器板并显示温度的基础的系统，你可以通过创建基于定时和从恒温器读数等基于事件触发来进一步地对系统进行开发。

（ 题图：opensource.com）

---

作者简介：

Abdul Hannan Mustajab: 我 17 岁，生活在印度。我正在追求科学，数学和计算机科学方面的教育。我在 spunkytechnology.com 上发表关于我的项目的博客。我一直在对使用不同的微控制器和电路板的基于物联网的 AI 进行研究。

---

via: <https://opensource.com/article/17/3/operate-relays-control-gpio-pins-raspberry-pi>

作者：[Abdul Hannan Mustajab](https://opensource.com/users/mustajabhannan) 译者：[zhousiyu325](https://github.com/zhousiyu325) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


10 个使用 Cinnamon 作为 Linux 桌面环境的理由

kubuntu17.04倒还挺稳定的，只是少数几个软件偶尔会卡住

不喜欢的理由，一个就足够了。

为什么现在还有人喜欢这种类似 Windows 95 那种窄窄的任务栏，不觉得小吗？

因为我需要更多的工作空间，而不是一条大大的任务栏～

对于现在很多宽屏显示器来说，可以选择竖放任务栏。

说得好！我选择KDE

之前用过linux Mint 17, Cinnamon 确实易用，专有驱动安装很方便。操作跟 Windows 很接近。

但是有个问题就是中文输入法一直没有解决好，最后就放弃了。

现在版本号到18了，不知道中文输入有没有解决。

表示从来没遇到过这个问题，我用的是fcitx～

Cinnamon确实是很不错的界面，美观、适用

优麒麟安装这个，锁屏失效怎么回事

来自河南郑州的 Chrome Mobile 73.0|Android 10 用户

# 10 个使用 Cinnamon 作为 Linux 桌面环境的理由

>
> Cinnamon 是一个让人怀旧 GNOME 2 的 Linux 桌面环境，它灵活、快速，并提供了种种的功能。
>
>
>

最近我安装了 Fedora 25，我觉得当前的 [KDE](https://opensource.com/life/15/4/9-reasons-to-use-kde) Plasma 版本并不稳定。在我决定尝试其它的桌面之前一天崩溃了好几次。在我安装了几个其它的桌面，并每个尝试了几个小时后，我最终决定在 Plasma 打上补丁并且稳定之前就使用 Cinnamon 了。以下是我所发现的。

### Cinnamon 简介

在 2011，带有新的 GNOME Shell 的 GNOME 3 发布了，新的界面马上引来了或正或反的反馈。许多用户以及开发者非常喜欢原先的 GNOME 界面，因此有多个组织复刻了它，其中一个结果就是 Cinnamon。

开发 GNOME 3 的 GNOME shell 背后的原因之一是许多原先的 GNOME 用户界面组件不再活跃开发了。这同样也是 Cinnamon 以及其他 GNOME 复刻项目的问题。 Linux Mint 项目是 Cinnamon 的一个首要推动者，因为 GNOME 是 Mint 的官方桌面环境。Mint 开发者已经将 Cinnamon 推进到了不需要 GNOME 本身的地步，Cinnamon 已经是一个完全独立的桌面环境，它保留了许多用户喜欢的 GNOME 界面的功能。

*图 1：打开系统设置工具的默认 Cinnamon 桌面。*

Cinnamon 3.2 是当前发布版本。除了 Mint，Cinnamon 还在许多发行版中可用，包括 Fedora、Arch、Gentoo、Debian 和 OpenSUSE 等。

### 使用 Cinnamon 的理由

这是我的使用 Cinnamon 的 10 个重要理由：

1. **集成。** 桌面的选择并不取决于在较长时间内是否有为它写的应用。我使用过的所有应用程序，不管它是在哪个桌面下写的，它都可以在任何其它桌面上运行正常，Cinnamon 也不例外。要运行那些为 KDE、GNOME 或其他桌面编写的程序所需要的库都有，可以在 Cinnamon 上面顺滑地使用这些程序。
2. **外观。** 让我们面对它，外观是很重要的。Cinnamon 有一个明快的、干净的外观，它使用了易于阅读的字体以及颜色的组合。桌面没有不必要的阻碍，你可以使用“系统设置” => “桌面” 菜单配置显示在桌面上的的图标。这个菜单还允许你指定是否在主监视器、次监视器或者所有监视器上显示桌面图标。
3. **桌面组件。** 桌面组件是一些小型的、可以添加到桌面的单一用途的程序。只有一些是可用的，但是你可以从 CPU 或者磁盘监视器、天气应用、便利贴、桌面相簿、时间和日期等之中选择。我喜欢时间和日期桌面组件，因为它比 Cinnamon 面板中的小程序易于阅读。
4. **速度。** Cinnamon 快速又敏捷。程序加载和显示很快。桌面自身在登录时加载也很快，虽然这只是我的主观体验，并没有基于时间测试。
5. **配置。**  Cinnamon 不如 KDE Plasma 那样可配置，但是也要比我第一次尝试它的时候有更多的配置。Cinnamon 控制中心提供了许多桌面配置选项的集中访问。它有一个主窗口，可以从它启动特定功能的配置窗口。可以很容易地在 “系统设置” 的 “主题” 的可用外观中选择新的外观。你可以选择窗口边框、图标、控件、鼠标指针和桌面基本方案。其它选择还包括字体和背景。我发现这些配置工具中有许多是我遇到的最好的。它有适量的桌面主题，从而能够显著改变桌面的外观，而不会像 KDE 那样面临选择困难。
6. **Cinnamon 面板。** Cinnamon 面板，即工具栏，最初的配置非常简单。它包含用于启动程序的菜单、基本的系统托盘和应用程序选择器。这个面板易于配置，并且添加新的程序启动器只需要定位你想要添加到主菜单的程序，右键单击程序图标，然后选择“添加到面板”。你还可以将启动器图标添加到桌面本身，以及 Cinnamon 的 “收藏” 的启动栏中。你还可以进入面板的**编辑**模式并重新排列图标。
7. **灵活性。** 有时可能很难找到最小化或者隐藏的正在运行的程序，如果有许多正在运行的应用程序，则在工具栏的程序选择器上查找它可能会有挑战性。 在某种程度上，这是因为程序并不总是有序地排在选择器中使其易于查找，所以我最喜欢的功能之一就是可以拖动正在运行的程序的按钮并将其重新排列在选择器上。这可以使查找和显示属于程序的窗口更容易，因为现在它们现在在我放的位置上。

Cinnamon 桌面还有一个非常好的弹出菜单，你可以右键单击访问。此菜单有一些常用任务，例如访问桌面设置、添加桌面组件以及其他与桌面相关的任务。

其它菜单项之一是 “创建新文档”，它使用位于 `~/Templates` 目录中的文档模板，并列出它们中的每一个。只需点击要使用的模板，使用这个模板的文档就会使用默认的 Office 程序创建。在我的情况下，那就是 LibreOffice。
8. **多工作空间。** Cinnamon 像其他桌面环境一样提供了多个桌面。Cinnamon 称它为“工作区”。工作区选择器位于 Cinnamon 面板中并展示每个工作区的窗口概览。窗口可以在工作区之间移动或指定到所有工作区。我确实发现工作区选择器有时候会比窗口位置的显示慢一些，所以我将工作区选择器切换为显示工作区编号，而不是在工作区中显示窗口概览。
9. **Nemo。** 大部分桌面因种种目而使用它们自己偏好的默认程序，Cinnamon 也不例外。我偏好的桌面文件管理器是 Krusader，但是 Cinnamon 默认使用 Nemo，因此在测试中我就用它了。我发现我很喜欢 Nemo。它有一个美丽干净的界面，我喜欢大部分功能并经常使用。它易于使用，同时对我的需求也足够灵活。虽然 Nemo 是 Nautilus 的复刻，但是我发现 Nemo 更好地被集成进了 Cinnamon 环境。Nautilus 界面看上去没有与 Cinnamon 很好集成，与 Cinnamon 不太和谐。
10. **稳定性。** Cinnamon 非常稳定且可用。

### 总结

Cinnamon 是 GNOME 3 桌面的复刻，它看上去像一个前所未有的 GNOME 桌面。它的发展看起来是符合逻辑的改进， Cinnamon 开发者认为需要在提升和扩展 GNOME 的同时保留它的独特性以及被大家非常喜欢的特性。它不再是 GNOME 3 - 它是不同的并且是更好的。Cinnamon 看上去很棒，并且对我而言也工作得很好，并且从 KDE 这个我仍旧非常喜欢的环境切换过来也很顺畅。我花费了几天时间学习 Cinnamon 的差异如何使我的桌面体验更好，并且我非常高兴了解这个很棒的桌面。

虽然我喜欢 Cinnamon，但我仍然喜欢体验其它的环境，我目前正切换到 LXDE 桌面，并已经用了几个星期。在我使用一段时间时候，我会分享我的 LXDE 体验。

（题图： [Sam Mugraby](https://commons.wikimedia.org/wiki/File:Cinnamon-other.jpg)，Photos8.com. [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/deed.en)）

---

作者简介：

David Both 是一个 Linux 和开源倡导者，他居住在北卡罗莱纳州的 Raleigh。他在 IT 行业已经超过 40 年，在他工作的 IBM 公司教授 OS/2 超过 20 年，他在 1981 年为最早的 IBM PC 写了第一个培训课程。他教过 Red Hat 的 RHCE 课程，在 MCI Worldcom、 Cisco 和北卡罗莱纳州 工作过。他一直在使用 Linux 和开源软件近 20 年。

---

via: <https://opensource.com/article/17/1/cinnamon-desktop-environment>

作者：[David Both](https://opensource.com/users/dboth) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


许多 SQL 性能问题来自于“不必要的强制性工作”

Summary: 在编写高效 SQL 时，你可能遇到的最有影响的事情就是索引。但是，一个很重要的事实就是很多 SQL 客户端要求数据库做很多“不必要的强制性工作”。

可惜程序猿大佬不会理你，人家orm用的欢乐自在，性能？不关心

# 许多 SQL 性能问题来自于“不必要的强制性工作”

在编写高效 SQL 时，你可能遇到的最有影响的事情就是[索引](http://use-the-index-luke.com/)。但是，一个很重要的事实就是很多 SQL 客户端要求数据库做很多**“不必要的强制性工作”**。

跟我再重复一遍：

>
> 不必要的强制性工作
>
>
>

什么是**“不必要的强制性工作”**？这个意思包括两个方面：

### 不必要的

假设你的客户端应用程序需要这些信息：

这没什么特别的。我们运行着一个电影数据库（[例如 Sakila 数据库](https://github.com/jOOQ/jOOQ/tree/master/jOOQ-examples/Sakila)），我们想要给用户显示每部电影的名称和评分。

这是能产生上面结果的查询：

```
SELECT title, rating
FROM film

```

然而，我们的应用程序（或者我们的 ORM（LCTT 译注：<ruby> 对象关系映射 <rp>  （ </rp> <rt>  Object-Relational Mapping </rt> <rp>  ） </rp></ruby>））运行的查询却是：

```
SELECT *
FROM film

```

我们得到什么？猜一下。我们得到很多无用的信息：

甚至一些复杂的 JSON 数据全程在下列环节中加载：

* 从磁盘
* 加载到缓存
* 通过总线
* 进入客户端内存
* 然后被丢弃

是的，我们丢弃了其中大部分的信息。检索它所做的工作完全就是不必要的。对吧？没错。

### 强制性

这是最糟糕的部分。现今随着优化器变得越来越聪明，这些工作对于数据库来说都是强制执行的。数据库没有办法*知道*客户端应用程序实际上不需要其中 95% 的数据。这只是一个简单的例子。想象一下如果我们连接更多的表...

你想想那会怎样呢？数据库还快吗？让我们来看看一些之前你可能没有想到的地方：

### 内存消耗

当然，单次执行时间不会变化很大。可能是慢 1.5 倍，但我们可以忍受，是吧？为方便起见，有时候确实如此。但是如果你*每次*都为了方便而牺牲性能，这事情就大了。我们不说性能问题（单个查询的速度），而是关注在吞吐量上时（系统响应时间），事情就变得困难而难以解决。你就会受阻于规模的扩大。

让我们来看看执行计划，这是 Oracle 的：

```
--------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes |
--------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1000 |   166K|
|   1 |  TABLE ACCESS FULL| FILM |  1000 |   166K|
--------------------------------------------------

```

对比一下：

```
--------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes |
--------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1000 | 20000 |
|   1 |  TABLE ACCESS FULL| FILM |  1000 | 20000 |
--------------------------------------------------

```

当执行 `SELECT *` 而不是 `SELECT film, rating` 的时候，我们在数据库中使用了 8 倍之多的内存。这并不奇怪，对吧？我们早就知道了。在很多我们并不需要其中全部数据的查询中我们都是这样做的。我们为数据库产生了**不必要的强制性工作**，其后果累加了起来，就是我们使用了多达 8 倍的内存（当然，数值可能有些不同）。

而现在，所有其它的步骤（比如，磁盘 I/O、总线传输、客户端内存消耗）也受到相同的影响，我这里就跳过了。另外，我还想看看...

### 索引使用

如今大部分数据库都有[涵盖索引](https://blog.jooq.org/2015/04/28/do-not-think-that-one-second-is-fast-for-query-execution/)（LCTT 译注：covering index，包括了你查询所需列、甚至更多列的索引，可以直接从索引中获取所有需要的数据，而无需访问物理表）的概念。涵盖索引并不是特殊的索引。但对于一个特定的查询，它可以“意外地”或人为地转变为一个“特殊索引”。

看看这个查询：

```
SELECT *
FROM actor
WHERE last_name LIKE 'A%'

```

执行计划中没有什么特别之处。它只是个简单的查询。索引范围扫描、表访问，就结束了：

```
-------------------------------------------------------------------
| Id  | Operation                   | Name                | Rows  |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                     |     8 |
|   1 |  TABLE ACCESS BY INDEX ROWID| ACTOR               |     8 |
|*  2 |   INDEX RANGE SCAN          | IDX_ACTOR_LAST_NAME |     8 |
-------------------------------------------------------------------

```

这是个好计划吗？如果我们只是想要这些，那么它就不是：

当然，我们浪费了内存之类的。再来看看这个查询：

```
SELECT first_name, last_name
FROM actor
WHERE last_name LIKE 'A%'

```

它的计划是：

```
----------------------------------------------------
| Id  | Operation        | Name            | Rows  |
----------------------------------------------------
|   0 | SELECT STATEMENT |                 |     8 |
|*  1 |  INDEX RANGE SCAN| IDX_ACTOR_NAMES |     8 |
----------------------------------------------------

```

现在我们可以完全消除表访问，因为有一个索引涵盖了我们查询需要的所有东西……一个涵盖索引。这很重要吗？当然！这种方法可以将你的某些查询加速一个数量级（如果在某个更改后你的索引不再涵盖，可能会降低一个数量级）。

你不能总是从涵盖索引中获利。索引也有它们自己的成本，你不应该添加太多索引，例如像这种情况就是不明智的。让我们来做个测试：

```
SET SERVEROUTPUT ON
DECLARE
  v_ts TIMESTAMP;
  v_repeat CONSTANT NUMBER := 100000;
BEGIN
  v_ts := SYSTIMESTAMP;

  FOR i IN 1..v_repeat LOOP
    FOR rec IN (
      -- Worst query: Memory overhead AND table access
      SELECT *
      FROM actor
      WHERE last_name LIKE 'A%'
    ) LOOP
      NULL;
    END LOOP;
  END LOOP;

  dbms_output.put_line('Statement 1 : ' || (SYSTIMESTAMP - v_ts));
  v_ts := SYSTIMESTAMP;

  FOR i IN 1..v_repeat LOOP
    FOR rec IN (
      -- Better query: Still table access
      SELECT /*+INDEX(actor(last_name))*/
        first_name, last_name
      FROM actor
      WHERE last_name LIKE 'A%'
    ) LOOP
      NULL;
    END LOOP;
  END LOOP;

  dbms_output.put_line('Statement 2 : ' || (SYSTIMESTAMP - v_ts));
  v_ts := SYSTIMESTAMP;

  FOR i IN 1..v_repeat LOOP
    FOR rec IN (
      -- Best query: Covering index
      SELECT /*+INDEX(actor(last_name, first_name))*/
        first_name, last_name
      FROM actor
      WHERE last_name LIKE 'A%'
    ) LOOP
      NULL;
    END LOOP;
  END LOOP;

  dbms_output.put_line('Statement 3 : ' || (SYSTIMESTAMP - v_ts));
END;
/

```

结果是：

```
Statement 1 : +000000000 00:00:02.479000000
Statement 2 : +000000000 00:00:02.261000000
Statement 3 : +000000000 00:00:01.857000000

```

注意，表 actor 只有 4 列，因此语句 1 和 2 的差别并不是太令人印象深刻，但仍然很重要。还要注意我使用了 Oracle 的提示来强制优化器为查询选择一个或其它索引。在这种情况下语句 3 明显胜利。这是一个好*很多*的查询，也是一个十分简单的查询。

当我们写 `SELECT *` 语句时，我们为数据库带来了**不必要的强制性工作**，这是无法优化的。它不会使用涵盖索引，因为比起它所使用的 `LAST_NAME` 索引，涵盖索引开销更多一点，不管怎样，它都要访问表以获取无用的 `LAST_UPDATE` 列。

使用 `SELECT *` 会变得更糟。考虑一下……

### SQL 转换

优化器工作的很好，因为它们转换了你的 SQL 查询（[看我最近在 Voxxed Days Zurich 关于这方面的演讲](https://www.youtube.com/watch?v=wTPGW1PNy_Y)）。例如，其中有一个称为“表连接消除”的转换，它真的很强大。看看这个辅助视图，我们写了这个视图是因为我们非常讨厌总是连接所有这些表：

```
CREATE VIEW v_customer AS
SELECT
  c.first_name, c.last_name,
  a.address, ci.city, co.country
FROM customer c
JOIN address a USING (address_id)
JOIN city ci USING (city_id)
JOIN country co USING (country_id)

```

这个视图仅仅是把 `CUSTOMER` 和他们不同的 `ADDRESS` 部分所有“对一”关系连接起来。谢天谢地，它很工整。

现在，使用这个视图一段时间之后，想象我们非常习惯这个视图，我们都忘了所有它底层的表。然后，我们运行了这个查询：

```
SELECT *
FROM v_customer

```

我们得到了一个相当令人印象深刻的计划：

```
----------------------------------------------------------------
| Id  | Operation            | Name     | Rows  | Bytes | Cost |
----------------------------------------------------------------
|   0 | SELECT STATEMENT     |          |   599 | 47920 |   14 |
|*  1 |  HASH JOIN           |          |   599 | 47920 |   14 |
|   2 |   TABLE ACCESS FULL  | COUNTRY  |   109 |  1526 |    2 |
|*  3 |   HASH JOIN          |          |   599 | 39534 |   11 |
|   4 |    TABLE ACCESS FULL | CITY     |   600 | 10800 |    3 |
|*  5 |    HASH JOIN         |          |   599 | 28752 |    8 |
|   6 |     TABLE ACCESS FULL| CUSTOMER |   599 | 11381 |    4 |
|   7 |     TABLE ACCESS FULL| ADDRESS  |   603 | 17487 |    3 |
----------------------------------------------------------------

```

当然是这样。我们运行了所有这些表连接以及全表扫描，因为这就是我们让数据库去做的：获取所有的数据。

现在，再一次想一下，对于一个特定场景，我们真正想要的是：

是啊，对吧？现在你应该知道我的意图了。但想像一下，我们确实从前面的错误中学到了东西，现在我们实际上运行下面一个比较好的查询：

```
SELECT first_name, last_name
FROM v_customer

```

再来看看结果！

```
------------------------------------------------------------------
| Id  | Operation          | Name        | Rows  | Bytes | Cost  |
------------------------------------------------------------------
|   0 | SELECT STATEMENT   |             |   599 | 16173 |     4 |
|   1 |  NESTED LOOPS      |             |   599 | 16173 |     4 |
|   2 |   TABLE ACCESS FULL| CUSTOMER    |   599 | 11381 |     4 |
|*  3 |   INDEX UNIQUE SCAN| SYS_C007120 |     1 |     8 |     0 |
------------------------------------------------------------------

```

这是执行计划一个*极大的*进步。我们的表连接被消除了，因为优化器可以证明它们是**不必要的**，因此一旦它可以证明这点（而且你不会因使用 `select *` 而使其成为**强制性**工作），它就可以移除这些工作并不执行它。为什么会发生这种情况？

每个 `CUSTOMER.ADDRESS_ID` 外键保证了*有且只有一个* `ADDRESS.ADDRESS_ID` 主键值，因此可以保证 `JOIN` 操作是对一连接，它不会产生或者删除行。如果我们甚至不选择行或查询行，当然我们就不需要真正地去加载行。可以证实地移除 `JOIN` 并不会改变查询的结果。

数据库总是会做这些事情。你可以在大部分数据库上尝试它：

```
-- Oracle
SELECT CASE WHEN EXISTS (
  SELECT 1 / 0 FROM dual
) THEN 1 ELSE 0 END
FROM dual

-- 更合理的 SQL 语句，例如 PostgreSQL
SELECT EXISTS (SELECT 1 / 0)

```

在这种情况下，当你运行这个查询时你可能预料到会抛出算术异常：

```
SELECT 1 / 0 FROM dual

```

产生了：

```
ORA-01476: divisor is equal to zero

```

但它并没有发生。优化器（甚至解析器）可以证明 `EXISTS (SELECT ..)` 谓词内的任何 `SELECT` 列表达式不会改变查询的结果，因此也就没有必要计算它的值。呵！

### 同时……

大部分 ORM 最不幸问题就是事实上他们很随意就写出了 `SELECT *` 查询。事实上，例如 HQL / JPQL，就设置默认使用它。你甚至可以完全抛弃 `SELECT` 从句，因为毕竟你想要获取所有实体，正如声明的那样，对吧？

例如：

`FROM` `v_customer`

例如 [Vlad Mihalcea](https://vladmihalcea.com/2016/09/13/the-best-way-to-handle-the-lazyinitializationexception/)（一个 Hibernate 专家和 Hibernate 开发倡导者）建议你每次确定不想要在获取后进行任何更改时再使用查询。ORM 使解决对象图持久化问题变得简单。注意：持久化。真正修改对象图并持久化修改的想法是固有的。

但如果你不想那样做，为什么要抓取实体呢？为什么不写一个查询？让我们清楚一点：从性能角度，针对你正在解决的用例写一个查询*总是*会胜过其它选项。你可以不会在意，因为你的数据集很小，没关系。可以。但最终，你需要扩展并重新设计你的应用程序以便在强制实体图遍历之上支持查询语言，就会变得很困难。你也需要做其它事情。

### 计算出现次数

资源浪费最严重的情况是在只是想要检验存在性时运行 `COUNT(*)` 查询。例如：

>
> 这个用户有没有订单？
>
>
>

我们会运行：

```
SELECT count(*)
FROM orders
WHERE user_id = :user_id

```

很简单。如果 `COUNT = 0`：没有订单。否则：是的，有订单。

性能可能不会很差，因为我们可能有一个 `ORDERS.USER_ID` 列上的索引。但是和下面的这个相比你认为上面的性能是怎样呢：

```
-- Oracle
SELECT CASE WHEN EXISTS (
  SELECT *
  FROM orders
  WHERE user_id = :user_id
) THEN 1 ELSE 0 END
FROM dual

-- 更合理的 SQL 语句，例如 PostgreSQL
SELECT EXISTS (
  SELECT *
  FROM orders
  WHERE user_id = :user_id
)

```

它不需要火箭科学家来确定，一旦它找到一个，实际存在谓词就可以马上停止寻找额外的行。因此，如果答案是“没有订单”，速度将会是差不多。但如果结果是“是的，有订单”，那么结果在我们不计算具体次数的情况下就会*大幅*加快。

因为我们*不在乎*具体的次数。我们告诉数据库去计算它（**不必要的**），而数据库也不知道我们会丢弃所有大于 1 的结果（**强制性**）。

当然，如果你在 JPA 支持的集合上调用 `list.size()` 做同样的事情，情况会变得更糟！

[近期我有关于该情况的博客以及在不同数据库上的测试。去看看吧。](https://blog.jooq.org/2016/09/14/avoid-using-count-in-sql-when-you-could-use-exists/)

### 总结

这篇文章的立场很“明显”。别让数据库做**不必要的强制性工作**。

它**不必要**，因为对于你给定的需求，你*知道*一些特定的工作不需要完成。但是，你告诉数据库去做。

它**强制性**，因为数据库无法证明它是**不必要的**。这些信息只包含在客户端中，对于服务器来说无法访问。因此，数据库需要去做。

这篇文章大部分在介绍 `SELECT *`，因为这是一个很简单的目标。但是这并不仅限于数据库。这关系到客户端要求服务器完成**不必要的强制性工作**的任何分布式算法。你的 AngularJS 应用程序平均有多少个 N+1 问题，UI 在服务结果 A 上循环，多次调用服务 B，而不是把所有对 B 的调用打包为一个调用？这是一个复发的模式。

解决方法总是相同。你给执行你命令的实体越多信息，（理论上）它能更快执行这样的命令。每次都写一个好的查询。你的整个系统都会为此感谢你的。

### 如果你喜欢这篇文章...

再看看近期我在 Voxxed Days Zurich 的演讲，其中我展示了一些在数据处理算法上为什么 SQL 总是会胜过 Java 的双曲线例子。

（题图：Pixabay， CC0）

---

via: <https://blog.jooq.org/2017/03/08/many-sql-performance-problems-stem-from-unnecessary-mandatory-work>

作者：[jooq](https://blog.jooq.org/) 译者：[ictlyh](https://github.com/ictlyh) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


D 编程语言是用于开发的绝佳语言的 5 个理由

D语言基本是已经死透的玩意，十几年前就诞生的语言，到现在没有一个Killer级别的应用，官网Packages总计只有1000来个，简直不要太可怜。。。

# D 编程语言是用于开发的绝佳语言的 5 个理由

>
> D 语言的模块化、开发效率、可读性以及其它一些特性使其非常适合用于协同软件的开发。
>
>
>

<img src="content_image/album_201706_15_061109teln46d93d8e33n2.png" alt="Why the D programming language is great for open source development" title="Why the D programming language is great for open source development">

[D 编程语言](https://dlang.org/)是一种静态类型的通用编程语言，它具有和 C 语言类似的语法，能够编译为本地代码。许多理由使得它很适合用于开源软件开发，下面讲到的是其中一些理由。

### 模块化能力

在大多数情况下，当你有一个好的想法，你可以完全按照你的内心所想的方式通过代码来实现它。然而，有的时候，你不得让你的想法向代码妥协，而不是通过模块化代码来适应想法。D 语言支持多种[编程范式](https://en.wikipedia.org/wiki/Programming_paradigm)，包括函数式风格、命令式、面向对象、元编程、并发（演员模式），这些全都和谐共存。你可以选择任何一种方便的编程范式来将你的想法转换为代码。

通过使用[模板](http://ddili.org/ders/d.en/templates.html)，可以生成额外的 D 代码并在编译的过程中把它编排进去，你可以把这些代码描述成编译器生成代码的一种模式。这是一种非常有用的设计算法，无需把它们绑定到任何特定的类型。由于模版的通用性，就很容易生成平台无关的代码。通过将模板与[条件编译](https://dlang.org/spec/version.html)结合，跨平台的应用变得更加容易实现，也更容易接受来自使用不同操作系统的开发者的贡献。有了这一点，一个程序员可以通过很少的代码，利用有限的时间实现很多东西。

[range](http://ddili.org/ders/d.en/ranges.html) 已经深度集成到了 D 语言中，相对于具体实现，它抽象出容器元素（比如数组、关联数组和链表等）是如何访问的。这个抽象使得可以在许多容器类型中设计和使用大量的算法，而无需绑定到特定的数据结构。D 的[数组切片](https://dlang.org/spec/arrays.html#slicing)是 range 的一个实现。最终，你可以用很少的时间写很少的代码，并且只需要很低的维护成本。

### 开发效率

大多数开源软件的代码贡献者都是基于有限的时间志愿工作的。 D 语言能够极大的提高开发效率，因为你可以用更少的时间完成更多的事情。D 的模板和 range 使得程序员在开发通用代码和可复用代码时效率更高，但这些仅仅是 D 开发效率高的其中几个优势。另外一个主要的吸引力是， D 的编译速度看起来感觉就像解释型语言一样，比如 Python、JavaScript、Ruby 和 PHP，它使得 D 能够快速成型。

D 可以很容易的与旧的代码进行对接，减少了移植的需要。它的设计目的是[与 C 代码进行自然地对接](https://dlang.org/spec/interfaceToC.html)，毕竟， C 语言大量用在遗留代码、精心编写而测试过的代码、库以及低级系统调用（特别是 Linux 系统）上。C++ 代码在 [D 中也是可调用的](https://dlang.org/spec/cpp_interface.html)，从而进行更大的扩展。事实上，[Python](https://code.dlang.org/packages/pyd)、[Objective-C](https://dlang.org/spec/objc_interface.html)、[Lua](http://beza1e1.tuxen.de/into_luad.html) 和 [Fortran](http://www.active-analytics.com/blog/interface-d-with-c-fortran/) 这些语言在技术层面上都是可以在 D 中使用的，有许多第三方正在努力在把 D 语言推向这些领域。这使得大量的开源库在 D 中均可使用，这符合开源软件开发的惯例。

### 可读性和可维护性

```
import std.stdio; // 导入标准输入/输出模块
void main()
{
    writeln("Hello, World!");
}

```

*D 语言的 Hello, World 演示*

对于熟悉 C 语言的人来说， D 代码很容易理解。另外， D 代码的可读性很强，即使是复杂的代码。这使得很容易发现错误。可读性对于吸引贡献者来说也是很重要的，这是开源软件成长的关键。

在 D 中一个非常简单但很有用的[语法糖](https://en.wikipedia.org/wiki/Syntactic_sugar)是支持使用下滑线分隔数字，这使得数字的可读性更高。这在数学上很有用：

```
int count = 100_000_000;
double price = 20_220.00 + 10.00;
int number = 0x7FFF_FFFF; // 16 进制系统

```

[ddoc](https://dlang.org/spec/ddoc.html) 是一个内建的工具，它能够很容易的自动根据代码注释生成文档，而不需要使用额外的工具。文档写作、改进和更新变得更加简单，不具挑战性，因为它伴随代码同时生成。

[Contract](http://ddili.org/ders/d.en/contracts.html) 能够检查代码的实现，从而确保 D 代码的行为能够像期望的那样。就像法律契约的签订是为了确保每一方在协议中做自己该做的事情，在 D 语言中的契约式编程，能够确保实现的每一个函数、类等如期望的那样产生预期的结果和行为。这样一个特性对于错误检查非常实用，特别是在开源软件中，当多个人合作一个项目的时候。契约是大项目的救星。D 语言强大的契约式编程特性是内建的，而不是后期添加的。契约不仅使得使用 D 语言更加方便，也减少了正确写作和维护困难的头痛。

### 方便

协同开发是具有挑战性的，因为代码经常发生变化，并且有许多移动部分。D 语言通过支持在本地范围内导入模块，从而缓解了那些问题：

```
// 返回偶数
int[] evenNumbers(int[] numbers)
{
    // "filter" and "array" are only accessible locally
    import std.algorithm: filter;
    import std.array: array;
    return numbers.filter!(n => n%2 == 0).array;
}

```

*对 filter 使用 `!` 运算符是[模板参数](http://ddili.org/ders/d.en/templates.html)的一个语法*

上面的函数可以在不破坏代码的情况下调用，因为它不依赖任何全局导入模块。像这样实现的函数都可以在后期无需破坏代码的情况下增强，这是协同开发的好东西。

[通用函数调用语法（UFCS）](http://ddili.org/ders/d.en/ufcs.html)是 D 语言中的一个语法糖，它允许像调用一个对象的成员函数那样调用常规函数。一个函数的定义如下：

```
void cook(string food, int quantity)
{
    import std.stdio: writeln;
    writeln(food, " in quantity of ", quantity);
}

```

它能够以通常的方式调用：

```
string food = "rice";
int quantity = 3;

cook(food, quantity);

```

通过 UFCS，这个函数也可以像下面这样调用，看起来好像 `cook` 是一个成员函数：

```
string food = "rice";
int quantity = 3;

food.cook(quantity);

```

在编译过程中，编译器会自动把 `food` 作为 `cook` 函数的第一个参数。UFCS 使得它能够链起来常规函数，给你的代码产生一种函数风格编程的自然感觉。UFCS 在 D 语言中被大量使用，就像在上面的 `evenNumbers` 函数中使用的 `filter` 和 `array` 函数那样。结合模板、range、条件编译和 UFCS 能够在不牺牲方便性的前提下给予你强大的力量。

`auto` 关键词可以用来代替任何类型。编译器在编译过程中会静态推断类型。这样可以省去输入很长的类型名字，让你感觉写 D 代码就像是在写动态类型语言。

```
// Nope. Do you?
VeryLongTypeHere variable = new VeryLongTypeHere();

// 使用 auto 关键词
auto variable =  new VeryLongTypeHere();
auto name = "John Doe";
auto age = 12;
auto letter  = 'e';
auto anArray = [1, 2.0, 3, 0, 1.5]; // type of double[]
auto dictionary = ["one": 1, "two": 2, "three": 3]; // type of int[string]
auto cook(string food) {...} // auto for a function return type

```

D 的[foreach](http://ddili.org/ders/d.en/foreach.html) 循环允许遍历各种不同的底层数据类型的集合和 range：

```
foreach(name; ["John", "Yaw", "Paul", "Kofi", "Ama"])
{
    writeln(name);
}

foreach(number; [1, 2, 3, 4, 4, 6]) {...}

foreach(number; 0..10) {...} // 0..10 is the syntax for number range

class Student {...}
Student[] students = [new Student(), new Student()];
foreach(student; students) {...}

```

D 语言中内建的[单元测试](https://dlang.org/spec/unittest.html)不仅免除了使用外部工具的需要，也方便了程序员在自己的代码中执行测试。所有的测试用例都位于可定制的 `unittest{}` 块中：

```
int[] evenNumbers(int[] numbers)
{
    import std.algorithm: filter;
    import std.array: array;
    return numbers.filter!(n => n%2 == 0).array;
}

unittest
{
    assert( evenNumbers([1, 2, 3, 4]) == [2, 4] );
}

```

使用 D 语言的标准编译器 DMD，你可以通过增加 `-unittest` 编译器标志把所有的测试编译进可执行结果中。

[Dub](http://code.dlang.org/getting_started) 是 D 语言的一个内建包管理器和构建工具，使用它可以很容易的添加来自 [Dub package registry](https://code.dlang.org/) 的第三方库。Dub 可以在编译过程中下载、编译和链接这些包，同时也会升级到新版本。

### 选择

除了提供多种编程范例和功能特性外，D 还提供其他的选择。它目前有三个可用的开源编译器。官方编译器 DMD 使用它自己的后端，另外两个编译器 GDC 和 LDC，分别使用 GCC 和 LLVM 后端。DMD 以编译速度块而著称，而 LDC 和 GDC 则以在很短的编译时间内生成快速生成机器代码而著称。你可以自由选择其中一个以适应你的使用情况。

默认情况下，D 语言是采用[垃圾收集](https://dlang.org/spec/garbage.html)的内存分配方式的。你也可以选择手动进行内存管理，如果你想的话，甚至可以进行引用计数。一切选择都是你的。

### 更多

在这个简要的讨论中，还有许多 D 语言好的特性没有涉及到。我强烈推荐阅读 [D 语言的特性概述](https://dlang.org/comparison.html)，这是隐藏在[标准库](https://dlang.org/phobos/index.html)中的宝藏，以及 [D 语言的使用区域](https://dlang.org/areas-of-d-usage.html)，从而进一步了解人们用它来干什么。许多组织已经[使用 D 语言来进行开发](https://dlang.org/orgs-using-d.html)。最后，如果你打算开始学习 D 语言，那么请看这本书 *[D 语言编程](http://ddili.org/ders/d.en/index.html)*。

（题图：opensource.com）

---

via: <https://opensource.com/article/17/5/d-open-source-software-development>

作者：[Lawrence Aberba](https://opensource.com/users/aberba) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


极客漫画：一篇关于 PHP 的优点的漫画

Summary:
PHP 有什么优点吗？
有，请看这幅漫画：

看不懂

问你有啥优点，漫画一片空白，说明啥也没有

为何还要有4个方框。。直接留白不就行了

来自辽宁本溪的 Chrome Mobile 58.0|Android 5.1 用户

PHP有很多优点，长篇大论也不为过，当纸买来时，我却不知道该写些什么

哈哈哈！

这个方框是是四格漫画的常用样式。

哈哈哈

哈哈哈

来比比看谁开发快，谁省钱

我还以为是模块化的意思

这也不失一解

...phper表示有被冒犯到(｡•ˇ‸ˇ•｡)

PHP 有什么优点吗？
有，请看这幅漫画：

# 极客漫画：一篇关于 PHP 的优点的漫画

PHP 有什么优点吗？

有，请看这幅漫画：

<img src="content_image/album_201706_15_073050rd4ydtdtp5ncsy4i.png" alt="A Comic About PHP Good Parts" title="A Comic About PHP Good Parts">

……

（这是 PHP 被黑的最惨的一次。）

---

via: <http://turnoff.us/geek/php-good-parts/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


极客漫画：敏捷餐馆

哈哈，没有最烂只有更烂

# 极客漫画：敏捷餐馆

过于殷勤（敏捷）的侍者会让你美好的一餐糟糕无比。

然而，离开“敏捷”的“持续交付”餐馆，旁边还有“瀑布”餐吧。

嗷，这个快节奏的年代！

<img src="content_image/album_201706_15_081956yzagl3zv4i1gke38.png" alt="The Agile Restaurant" title="The Agile Restaurant">

注：<ruby> “敏捷” <rp>  （ </rp> <rt>  agile </rt> <rp>  ） </rp></ruby>开发、<ruby> “持续交付” <rp>  （ </rp> <rt>  Continuous Delivery </rt> <rp>  ） </rp></ruby>（CD）和<ruby> “瀑布” <rp>  （ </rp> <rt>  waterfall </rt> <rp>  ） </rp></ruby>式开发都是软件开发术语。瀑布式开发/瀑布模型是一种传统的、过时的开发模式，其得名于开发阶段按顺序衔接，如瀑布般进行。敏捷和持续交付是近年来流行的开发模式，能够比较好的适应现代的软件开发需求，但是，显然，如果餐馆也采用这种模式，似乎不太对劲。

---

via: <http://turnoff.us/geek/agile-restaurant/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


微软正在成为一个 Linux 供应商

Microsoft 曾经推出过一款类 UNIX 的操作系统 Xenix，我还在其他网站看到过某个版本 Internet Explorer For UNIX 的截图，不是后来给 Apple 开发的在 OS X 系统运行的 Internet Explorer，就是运行在 UNIX 上的版本。

微软的 Linux 子系统只要能够很好解决兼容和能耗问题，比起对电量消耗大的虚拟机方案，还是一个不错的方案。

对于 Linux 子系统存储在 NTFS 可能因为文件或目录的大小写导致一些问题。我想到的，但是没有实践的方案是。找到当前用户 %USERPROFILE%，或者 %APPDATA%, %LOCALAPPDATA%（系统环境变量）. 下专门存放 Linux 子系统的目录， 在最初阶段， 将其 robocopy . VHDX -copyall -s -e 到一个由 VHD 或 VHDX 的虚拟硬盘文件里，FS 还是 ntfs，最后把这个虚拟硬盘挂载到原来那个目录，挂载前确保其是空目录。自动挂载虚拟硬盘文件可用 diskpart 实现。

哈哈，居然还有人记得——我曾经有过一本 Microsoft Press 出版的 《RUNNING UNIX》 的书

用了很久了，确实方便了许多。

来自四川成都的 Chrome Mobile 40.0|Android 6.0 用户

# 微软正在成为一个 Linux 供应商

>
> 微软通过将 Linux 融入自己的产品中来弥合与 Linux 的裂隙。
>
>
>

<img src="content_image/album_201706_16_020219gcts2dzb22wvk816.jpg" alt="" title="">

Linux 以及开源技术在数据中心、云以及 IoT 中变得如此主流，以至于微软无法忽视他们。

在微软自己的云中，三分之一的机器运行着 Linux。这些是运行 Linux 的微软客户。微软需要支持他们使用的平台，否则他们将到别处去了。

以下就是微软如何将 Linux 战略落实到它的开发者平台 （Windows 10）、云 （Azure） 以及数据中心 （Windows Server） 上的。

**Windows 中的 Linux：** IT 专家管理公共或者私有 Linux 机器需要原生的 UNIX 工具。Linux 以及 macOS 是仅有的二个提供原生能力的平台。这也难怪你在各种会议如 DockerCon、OpenStack Summit 或者 CoreOS Fest 看到的都是 MacBook 或者少量的 Linux 桌面。

为了弥补这之间的裂隙，微软与 Canonical 协作在 Windows 内部构建了一个 Linux 子系统，它提供了原生的 Linux 工具。这是一个很棒的妥协，这样 IT 专家可以在继续使用 Windows 10 桌面的同时能够使用大多数 Linux 工具来管理他们的 Linux 机器。

**Azure 中的 Linux：** 不能完整支持 Linux 的云有什么好的呢？微软一直以来与 Linux 供应商合作来使客户能够在 Azure 中运行 Linux 程序以及任务。

微软不仅与三家主要的 Linux 供应商 Red Hat、SUSE 和 Canonical 签署了协议，还与无数的其他公司合作，为 Debian 这样的基于社区的发行版提供了支持。

**Windows Server 中的 Linux：** 这是剩下的最后一块拼图。客户使用的 Linux 容器是一个巨大的生态系统。Docker Hub 上有超过 90 万个 Docker 容器，它们只能在 Linux 机器上运行。微软希望把这些容器带到自己的平台上。

在 DockerCon 中，微软宣布在 Windows Server 中支持 Linux 容器，将这些容器都带到 Windows 中。

事情正变得更加有趣，在 Windows 10 上的 Bash on Ubuntu 成功之后，微软正将 Ubuntu bash 带到 Windows Server 中。是的，你听的没错。Windows Server 也将会有一个 Linux 子系统。

微软的高级项目经理 Rich Turne 告诉我：“服务器上的 WSL 为管理员提供了偏好的 \*NIX 管理脚本和工具，以便让他们可以在更熟悉的工作环境工作。”

微软在一个通告中称它将允许 IT 专家 “可以在 Windows Server 容器主机上使用在 Linux 容器上所用的相同的脚本、工具、流程和容器镜像。这些容器使用我们的 Hyper-V 隔离技术结合你选择的 Linux 内核来托管负载，而主机上的管理脚本以及工具使用 WSL。”

在覆盖了上面三个情况后，微软已经成功地创建了一个客户不必选择任何 Linux 供应商的环境。

### 它对微软意味着什么？

通过将 Linux 融入它自己的产品，微软已经成为了一个 Linux 供应商。它是 Linux 基金会的一份子，它是众多 Linux 贡献者之一，并且它现在在自己的商店中分发 Linux。

只有一个小问题。微软没有拥有任何 Linux 技术。它完全依赖于外部的厂家，目前 Canonical 为其提供了完全的 Linux 层。如果 Canonical 被强力的竞争对手收购，那会是一个很大的风险。

或许对微软而言尝试收购 Canonical 是有意义的，并且会将核心技术收入囊中。这是有道理的。

### 这对 Linux 供应商意味着什么

表面上，很显然这对微软是个胜利，因为它的客户可以留存在 Windows 世界中。它还将包含 Linux 在数据中心中的发展势头。它或许还会影响 Linux 桌面，由于现在 IT 专家不必为了寻找 \*NIX 工具使用 Linux 桌面了，它们可以在 Windows 中做任何事。

微软的成功是传统 Linux 厂家的失败么？某种程度上来说，是的，微软已经成为了一个直接竞争者。但是这里明显的赢家是 Linux。

---

via: <http://www.cio.com/article/3197016/linux/how-microsoft-is-becoming-a-linux-vendor.html>

作者：[Swapnil Bhartiya](http://www.cio.com/author/Swapnil-Bhartiya/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


下周一，微软约你在 LinuxCon 见？！

我变故我在，开源赢未来！

# 下周一，微软约你在 LinuxCon 见？！

你们都知道了吧，[LinuxCon 第一次走进中国了](https://www.lfasiallc.com/linuxcon-containercon-cloudopen-china)，就在下周一，Linux 基金会将携豪华阵容隆重降临北京国家会议中心，而且，Linus Torvalds 大神也将第一次出现在中国。

好吧，我知道你们知道了，可是你们知道，就是那个微软公司，它又*又***又**来了！你或许知道微软参加 LinuxCon 已经不是第一次了，从 2015 年开始，微软就频频[出现在 LinuxCon 上](/article-6076-1.html)了，而且，就在去年11月，还进一步宣布[成为了 Linux 基金会的最顶级的白金会员](/article-7966-1.html)！

可能还有人不太习惯将微软和开源视作一个阵营，也有一些社区意见领袖一直对此持谨慎的态度。好吧，无论是不是还担心微软的居心，但是我们这几年可以看到，微软在开源领域的举措之多，已经不亚于其在商业软件方面的动作了。

那么，这次微软来 LinuxCon 会做什么演讲呢？老王专门找了 Linux 基金会的 Maggie 去联系上了微软，想要提前挖掘一些内幕出来。

### 《我变故我在——微软与开源共舞》

根据日程安排，这次微软安排了若干重量级代表出席 LinuxCon，其中就包括微软中国云计算与企业事业部的资深合伙人及高级总监梁戈碧女士，而她除了会 LinuxCon 大会上的技术女性午餐会之外，还会做题为《我变故我在——微软与开源共舞》的演讲，这真是一个意料之外又在情理之中的演讲啊。

*梁戈碧女士*

梁戈碧女士拥有威廉玛丽学院的计算机科学硕士学位。在加盟微软前就职于英特尔15年，先后在美国和中国的英特尔公司担任多个技术和领导职务。她在云计算领域拥有卓越的成就，领导设计了 Windows Azure 存储等面向全球客户的云计算产品和服务。更重要的是，她对开源和技术有独特的认知，在微软内部积极推动和布道开源的技术和解决方案。更是在微软内部积极参与女性平权活动，为倡导女性在 IT 领域的地位和发展做出了卓越的贡献。

让我们猜猜梁女士将会谈到什么？

**✿ 根据我们侧面了解到的信息，她会回顾微软的开源历史，总结微软已经在开源上取得的进展。**

>
> 2014 年 10 月 20 日，出任微软公司首席执行官不久的萨提亚 ∙ 纳德拉第一次公开宣示了微软对 Linux 和开源世界的新感情。过去两年，从微软智能云 Azure 到 Windows 10，从开发工具到数据库平台，“把 Linux 放在重中之重”，已经成为微软内部人人皆知的准则。
>
>
> —— 《[拥抱开源，微软是认真的](https://news.microsoft.com/zh-cn/拥抱开源，微软是认真的/ ) 》
>
>
>

*微软开源简史*

现在，微软逐渐加大了对开源和 Linux 方面的关注和投入，诸如 [PowerShell](/article-7699-1.html)、[Visual Studio Code](/article-6604-1.html) 以及 [Edge JavaScript 引擎](/article-6698-1.html)这样的项目，已经逐个开源化，将微软推近这个它曾经憎恨过的开源世界。而且，通过 Windows 10，[微软开始走进 Linux](/article-7177-1.html)，因为该操作系统内置了 Ubuntu。 在收购了 Xamarin 之后，还[开源了其软件开发工具包](/article-7181-1.html)。此外，微软还和 [Red Hat](/article-7020-1.html) 和 [SUSE](/article-1593-1.html) 合作在Azure 云上推出了有官方支持的 Linux 镜像。而今年初，微软还发布了 [Linux 上的 SQL Server](/article-7082-1.html)，甚至得到了[鲍尔默的赞誉](/article-7095-1.html)。

*开源在整个微软公司，已经蔚然成风*

**✿ 她还会解释微软是如何和****Linux** **社区及其它社区合作的。**

据我们所知，Linux 基金会并不是微软加入的第一个行业领袖级的 Linux 团体，微软已经参与了几个 Linux 基金会项目的贡献，包括 Node.js 基金会、 OpenDaylight、开放容器促进联盟、R 社团、开放 API 促进联盟等。

**✿ 然后会通过对微软的开源战略的分享，用一系列真实的例子来例证微软不仅仅是拥抱开源，而且还对开源技术进行创新，并将这些创新回馈给社区。**

根据去年的章鱼猫报告，GitHub上开源贡献者最多的组织是微软，超过了 Facebook、docker，以及谷歌。

*GitHub 的 2016 章鱼猫报告中，微软以贡献者数量最多而排名第一*

这充分证明了微软的开源策略的实行情况。据微软内部资料，其开源策略分为四个方面：支持、整合、发布和贡献。

*微软的开源策略*

**✿ 通过与社区密切合作，让核心创新给客户带来更具敏捷性、创造性的产品和服务之选。**

随着微软在开源开放方面的举措，其核心产品，无论是 SQL Server 这样的重量级数据库，还是 Windows 10 中内置 Linux 子系统，也包括 .NET Core 、TypeScript 这样的开发环境和工具语言，纷纷开源或支持 Linux 。

*微软核心产品开源或支持 Linux*

而作为微软近年来重中之重的 Azure 云业务，也在各个层面上全面支持开源。包括从底层的基础设施、容器、数据库和中间件，乃至于平台框架、应用程序。均采用和支持了大量的开源组件。

*Azure 在各个层次全面支持开源*

梁女士的演讲时间并不长，按照日程安排只有短短的15分钟，但其所表达出来微软对开源的信心和坚决的态度，令人瞩目，我想，开源社区是该正视微软这个软件巨人闯入开源世界的所带来的新格局了。

### LinuxCon 技术女性午餐会

当然，除了这段演讲之外，其实，我也非常关注由微软主持的 LinuxCon 技术女性午餐会。虽然作为中年大叔，但是我觉得我还是坚决支持女性在技术和开源领域的发展的（我不是为了混进午餐会才这么说的！）。据说，有人引荐的话，像我这样的进步分子是可以参加技术女性午餐会的，我正在考虑要不要推掉下周一中午的其它（机油）邀约……

国内技术圈对技术女性的处境和发展并没有像硅谷那样形成一种潮流，但是我们也听到和看到了一些这样的活动和观点。事实上，在国内技术女性的发展还处于较早的阶段，因此，关怀女性，尤其是关怀技术女性的发展，是技术界应该重视的一件事。这也是为什么 LinuxCon 上有专门的技术女性午餐会的安排的原因。

具体，在这个午餐会上有什么见闻，请大家等我的第一时间火线报道吧！:-D

那么，LinuxCon 见！

（本文中所采用的部分图片来自微软公司，得到了梁戈碧女士、微软公司的许可。文中提及的名称和商标均属于其商标许可人所有。）


极客漫画：最后一个问题

Summary: ps aux 以及 ps -elf 都是查看进程的方式，这个漫画就是说使用这两种方式的人就像 vim 党和 Emacs 党一样，随时都可能爆发圣战（大误 。

附录第一句话“ps aux 是最常用的 UNIX 风格选项组合”这句话笔误了，应该是BSD风格

我用的是ps ex，这个x指的是X Window，用Window必须得有X。虽然X其实没什么用处。

哈哈，谢谢~

# 极客漫画：最后一个问题

<img src="content_image/album_201706_17_105335d1u74qf117mylpu3.png" alt="One Last Question" title="One Last Question">

`ps aux` 以及 `ps -elf` 都是查看进程的方式，分别来自于 BSD 风格（必须不带 `-`）和 UNIX 风格（必须带 `-`），这两种方式都有不少人用，此外除了这种可组合的单字母选项方式之外，还有以 `--` 开头的 GNU 选项方式。

这个漫画就是说使用这两种方式的人就像 vim 党和 Emacs 党一样，随时都可能爆发圣战（大误 。

**附录：**

`ps aux` 是最常用的 BSD 风格选项组合，其中的 `a` 简单的说，表示所有关联到终端的进程，如果同时使用 `x` 则代表所有进程；`u` 表示列出进程的用户。

另外，可能是由于错用 `ps -aux` 的人太多，一些新的 `ps` 版本会在输入 `ps -aux` 时显示 `ps aux` 的结果，而不是 `ps -aux` 原本的意义：列出用户 `x` 所有的进程，如果没有则报错。

`ps -elf` 的 `-e` 代表列出所有进程，`-l` 代表长格式，`-f` 代表完整的格式，有时候也用 `-F` 代表超完整的格式，具体大家试试便知。 不过，不同操作系统（如 Linux、BSD）的 `ps` 的版本和参数有很大差异，具体还是要以自己的手册而定。

另外一句题外话，之所以 `aux` 和 `-elf` 这两种选项组合常用，是由于这个组合正好是易记、易读的英文单词（辅助、精灵），其组合后的用途也很有用。这种情况也出现在其它的常见命令中。

注：本漫画中原来用的是 `ps -eLF`，在某些版本上这个参数是成立的，但是，大部分情况下都使用的是 `ps -elf`，因此我们做了修改。

---

via: <http://turnoff.us/geek/one-last-question/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者：[name1e5s](https://github.com/name1e5s) 校对：[wxy](https://github.com/wxy) 合成：[name1e5s](https://github.com/name1e5s) 点评：[name1e5s](https://github.com/name1e5s)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


安卓编年史（23）：Android 4.3，果冻豆——早早支持可穿戴设备

# 安卓编年史（23）：Android 4.3，果冻豆——早早支持可穿戴设备

*漂亮的新 Google Play Music 应用，从电子风格转向完美契合 Play 商店的风格。 [Ron Amadeo 供图]*

在 I/O 大会推出的另一个应用更新是 Google Music 应用。音乐应用经过了完全的重新设计，最终摆脱了蜂巢中引入的蓝底蓝色调的设计。Play Music 的设计和几个月前发布的 Play 商店一致，有着响应式的白色卡片布局。Music 同时还是最早采用新抽屉导航样式的主要应用之一。谷歌还随新应用发布了 Google Play Music All Access，每月 10 美元的包月音乐订阅服务。Google Music 现在拥有订阅计划，音乐购买，以及云端音乐存储空间。这个版本还引入了“Instant Mix”，谷歌会在云端给相似的歌曲计算出一份歌单。

*一个展示对 Google Play Games 支持的游戏。上面是 Play 商店游戏特性描述，登陆游戏触发的权限对话框，Play Games 通知，以及成就界面。 [Ron Amadeo 供图]*

谷歌还引入了 “Google Play Games”，一个后端服务，开发者可以将其附加到游戏中。这项服务简单说就是安卓版的 Xbox Live 或苹果的 Game Center。开发者可以给游戏添加 Play Games 支持，这样就能通过使用谷歌的后端服务，更简单地将成就、多人游戏、游戏配对、用户账户以及云端存档集成到游戏中。

Play Games 是谷歌在游戏方面推进的开始。就像单独的 GPS 设备，翻盖手机，以及 MP3 播放器，智能手机的生产者希望游戏设备能够变成智能手机的一个功能点。当你有部智能手机的时候你为什么还有买个任天堂 DS 或 PS Vita 呢？一个易于使用的多人游戏服务是这项计划的重要部分，我们仍能看到这个决定最后的成果。在今天，坊间都在传言谷歌和苹果有关于客厅游戏设备的计划。

*Google Keep，谷歌自 Google Notebook 以来第一个笔记服务。 [Ron Amadeo 供图]*

毫无疑问一些产品为了赶上 Google I/O 大会的发布准时开发完成了，[但是三个半小时内的主题](http://live.arstechnica.com/liveblog-google-io-2013-keynote/)已经够多了，一些产品在大会的发布上忽略了。Google I/O 大会的三天后一切都清楚了，谷歌带来了 Google Keep，一个用于安卓和在线的笔记应用。Keep 看起来很简单，就是一个用上了响应式 Google-Now 风格设计的笔记应用。用户可以改变卡片的尺寸，从多栏布局改为单列视图。笔记可以由文本，清单，自动转文本的语音或者图片组成。笔记卡片可以拖动并在主界面重新组织，你甚至可以给笔记换个颜色。

*Gmail 4.5，换上了新的导航抽屉设计，去掉了几个按钮并将操作栏合并到了抽屉里。 [Ron Amadeo 供图]*

在 I/O 大会之后，没有哪些应用没出现在谷歌的周期外更新里。2013 年 6 月，谷歌发布了新版设计的 Gmail。最显眼的变化就是一个月前 Google I/O 大会引入的新导航抽屉界面。最吸引眼球的变化是用上了 Google+ 资料图片来取代复选框。虽然复选框看起来被去掉了，它们其实还在那，点击邮件左边的图片就是了。

*新谷歌地图，换上了全白的 Google-Now 风格主题。 [Ron Amadeo 供图]*

一个月后，谷歌在 Play 商店发布了全新的谷歌地图。这是谷歌地图自冰淇淋三明治以来第一个经过细致地重新设计的版本。新版本完全适配了 Google Now 白色卡片审美，还大大减少了屏幕上显示的元素。新版谷歌地图似乎设计时有意使地图总是显示在屏幕上，你很难找到除了设置页面之外还能完全覆盖地图显示的选项。

这个版本的谷歌地图看起来活在它自己的小小设计世界中。白色的搜索栏“浮动”在地图之上，地图显示部分在它旁边和上面都有。这和传统的操作栏设计有所不同。一般在应用左上角的导航抽屉，在这里是在左下角。这里的主界面没有向上按钮、应用图标，也没有浮动按钮。

*新谷歌地图轻量化了许多，在一屏内能够显示更多的信息。 [Ron Amadeo 供图]*

左边的图片显示的是点击了搜索栏后的效果（带键盘，这里关闭了）。过去谷歌在空搜索栏下面显示一个空页面，但在地图中，谷歌利用这些空间链接到新的“本地”页面。搜索结果页显示一般信息的结果，比如餐馆、加油站，以及景点。在结果页的底部是个列表，显示你的搜索历史和手动缓存部分地图的选项。

右侧图片显示的是地点页面。上面地图 7.0 的截图里显示的地图不是略缩图，它是完整的地图视图。在新版的谷歌地图中，地点作为卡片浮动显示在主地图之上，地图重新居中显示该地点。向上滑动可以让卡片覆盖地图，向下滑动可以显示带有底部一小条结果的完整地图。如果该地点是搜索结果列表中的一个，左右滑动可以在结果之间切换。

地点页面重新设计以显示更有用的信息概览。在第一页，新版添加了重要信息，比如地图上的位置，点评得分，以及点评数目。因为这是个手机，所以软件内可以直接拨打电话，电话号码的显示被认为是毫无意义的，被去掉了。旧版地点显示到那里的距离，新版谷歌地图显示到那里的时间，基于交通状况和偏好的交通方式——一个更加实用的衡量方式。新版还在中间放了个分享按钮，这使得通过即时通讯或短信协调的时候更加方便。

### Android 4.3，果冻豆——早早支持可穿戴设备

如果谷歌没有在安卓 4.3 和安卓 4.2 之间通过 Play 商店发布更新的话，安卓 4.3 会是个不可思议的更新。如果新版 Play 商店、Gmail、地图、书籍、音乐、Hangouts 环聊，以及 Play Games 打包作为新版安卓的一部分，它将会作为有史以来最大的发布受到欢呼。虽然谷歌没必要延后新功能的发布。有了 Play 服务框架，只剩很少的部分需要系统更新，2013 年 7 月底谷歌发布了看似无关紧要的“安卓 4.3”。

*安卓 4.3 通知访问权限界面的可穿戴设备选项。 [Ron Amadeo 供图]*

谷歌也毫无疑问地认为 4.3 的重要性不高，将新版也叫做“果冻豆”（第三个叫果冻豆的版本了）。安卓 4.3 的新功能列表像是谷歌无法通过 Play 商店或谷歌 Play 服务更新的部分的细目清单，大部分包含了为开发者作出的底层架构改动。

但许多新增功能似乎只为了一个目的——安卓 4.3 是谷歌对可穿戴计算支持的特洛伊木马。4.3 加入了低功耗蓝牙支持，使用很少的能耗将安卓和其它设备连接到一起并传输数据——可穿戴设备的必要特性。安卓 4.3 还添加了“通知访问权限”API，允许应用完全复制和控制通知面板。应用可以显示通知文本以及和用户操作一样地和通知交互——也就是点击操作按钮和消除通知。当你有个通知面板时从本机应用做这个操作没什么意义，但是在一个独立于你手机的设备上，复制通知面板的消息就显得很有用了。为数不多的接入的应用是 “Android Wear Preview（安卓可穿戴预览）”，使用了通知 API 驱动大部分的 Android Wear 界面。

“4.3 是给可穿戴设备准备的”这个理论解释了 4.3 相对较少的新特性：它的推出是为了给 OEM 厂商时间去升级设备，为 [Android Wear](http://arstechnica.com/gadgets/2014/03/in-depth-with-android-wear-googles-quantum-leap-of-a-smartwatch-os/) 的发布做准备。这个计划看起来起作用了。Android Wear 要求 安卓 4.3 及以上版本，安卓 4.3 已经发布很长时间了，大部分主要的旗舰设备都已经升级了。

安卓并没有那么激动人心，但安卓从现在起的新版也不需要那么激动人心了。一切都变得那么模块化了，谷歌可以通过 Google Play 在它们完成时随时推送更新，不用再作为一个大系统更新来更新这么多组件。

---

[Ron Amadeo](http://arstechnica.com/author/ronamadeo) / Ron是Ars Technica的评论编缉，专注于安卓系统和谷歌产品。他总是在追寻新鲜事物，还喜欢拆解事物看看它们到底是怎么运作的。[@RonAmadeo](https://twitter.com/RonAmadeo)

---

via: <http://arstechnica.com/gadgets/2016/10/building-android-a-40000-word-history-of-googles-mobile-os/24/>

译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](http://linux.cn/) 荣誉推出


安卓编年史（24）：Android 4.4，奇巧——更完美，更少的内存占用

# 安卓编年史（24）：Android 4.4，奇巧——更完美，更少的内存占用

*LG 制造的 Nexus 5，奇巧（KitKat）的首发设备。*

### Android 4.4，奇巧——更完美，更少的内存占用

谷歌安卓 4.4 的发布确实很讨巧。谷歌和[雀巢公司合作](http://arstechnica.com/gadgets/2013/09/official-the-next-edition-of-android-is-kitkat-version-4-4/)，新版系统的代号是“奇巧（KitKat）”，并且它是在 2013 年 10 月 31 日发布的，也就是万圣节。雀巢公司推出了限量版带安卓机器人的奇巧巧克力，它的包装也帮助新版系统推广，消费者有机会赢取一台 Nexus 7。

一部新的 Nexus 设备也随奇巧一同发布，就是 Nexus 5。新旗舰拥有迄今最大的显示屏：一块五英寸、1920x1080 分辨率的 LCD 显示屏。除了更大尺寸的屏幕，Nexus 5 的制造商 LG 还将 Nexus 5 的机器大小控制得和 Galaxy Nexus 或 Nexus 4 差不多。

Nexus 5 相对同时期的高端手机配置算是标准了，拥有 2.3Ghz 骁龙 800 处理器和 2GB 内存。手机再次在 Play 商店销售无锁版，相同配置的大多数手机价格都在 600 到 700 美元之间，但 Nexus 5 的售价仅为 350 美元。

奇巧最重要的改进之一你并不能看到：显著减少的内存占用。对奇巧而言，谷歌齐心协力开始了降低系统和预装应用内存占用的努力，称作“Project Svelte”。经过了无数的优化工作和通过一个“低内存模式”（禁用图形开销大的特效），安卓现在可以在 340MB 内存下运行。低内存需求是件了不起的事，因为在发展中国家的设备——智能手机增长最快的市场——许多设备的内存仅有 512MB。冰淇淋三明治更高级的 UI 显著提高了对安卓设备的系统配置要求，这使得很多低端设备——甚至是新发布的低端设备——的安卓版本停留在姜饼。奇巧更低的配置需求意味着这些廉价设备能够跟上脚步。有了奇巧，谷歌希望完全消灭姜饼（写下本文时姜饼的市场占有率还在 20% 左右）。只是降低系统需求还不够，甚至有报道称谷歌将[不再授权](http://www.androidpolice.com/2014/02/10/rumor-google-to-begin-forcing-oems-to-certify-android-devices-with-a-recent-os-version-if-they-want-google-apps/)谷歌应用给姜饼设备。

除了给低端设备带来更现代版本的系统，Project Svelte 更低的内存需求同样对可穿戴设备也是个好消息。Google Glass [宣布](http://www.androidpolice.com/2014/03/01/glass-xe14-delayed-until-its-ready-promises-big-changes-and-a-move-to-kitkat/)它会切换到这个更精简的系统，[Android Wear](http://arstechnica.com/gadgets/2014/03/in-depth-with-android-wear-googles-quantum-leap-of-a-smartwatch-os/) 同样也运行在奇巧之上。安卓 4.4 带来的更低的内存需求以及 4.3 中的通知消息 API 和低功耗蓝牙支持给了可穿戴计算漂亮的支持。

奇巧的亮点还有无数精心打磨过的核心系统界面，它们无法通过 Play 商店升级。系统界面，拨号盘，时钟还有设置都能看到升级。

*奇巧在 Google Now 启动器下的透明系统栏。 [Ron Amadeo 供图]*

奇巧不仅去掉了讨人厌的锁屏左右屏的线框——它还默认完全禁用了锁屏小部件！谷歌明显感觉到了多屏锁屏和锁屏主屏对新用户来说有点复杂，所以锁屏小部件现在需要从设置里启用。锁屏和时钟里不平衡的时间字体换成了一个对称的字重，看起来好看多了。

在奇巧中，应用拥有将系统栏和状态栏透明的能力，显著地改变了系统的外观。系统栏和状态栏现在混合到壁纸和启用透明栏的应用中去了。这些栏还能通过新功能“沉浸”模式完全被应用隐藏。

奇巧是“电子”科幻风格的棺材上的最后一颗钉子，几乎完全移除了系统的蓝色痕迹。状态栏图标由蓝色变成中性的白色。主屏的状态栏和系统栏并不是完全透明的；它们有深色的渐变，这样在使用浅色壁纸的时候白色的图标还能轻易地识别出来。

*Google Now 和文件夹的调整。 [Ron Amadeo 供图]*

在 Nexus 5 上随奇巧到来的主屏实际上由 Nexus 5 独占了几个月，但现在任何 Nexus 设备都能拥有它了。新的主屏叫做“Google Now Launcher”，它实际上是[谷歌搜索应用](http://arstechnica.com/gadgets/2013/11/google-just-pulled-a-facebook-home-kitkats-primary-interface-is-google-search/)。是的，谷歌搜索从一个简单的搜索框成长到了整个主屏幕，并且在奇巧中，它涉及了壁纸、图标、应用抽屉、小部件、主屏设置、Google Now，当然，还有搜索框。由于搜索现在运行在整个主屏幕，任何时候只要打开了主屏并且屏幕是点亮的，就可以通过说“OK Google”激活语音命令。在搜索栏有引导用户说出“OK Google”的文本，在几次使用后这个介绍会隐去。

Google Now 的集成度现在更高了。除了通常的系统栏上滑激活，Google Now 还占据了最左侧的主屏。新版还引入了一些设计上的调整。谷歌的 logo 移到了搜索栏内，整个顶部区域更紧凑了。显示更多卡片的设计被去除了，新添加的一组底部按钮指向备忘录、自定义选项，以及一个更多操作按钮，里面有设置、反馈，以及帮助。因为 Google Now 是主屏幕的一部分，所以它也拥有透明 的系统栏和状态栏。

透明以及让系统的特定部分“更明亮”是奇巧的设计主题。黑色调通过透明化从状态栏和系统栏移除了，文件夹的黑色背景也换为了白色。

*新的，更加清爽的应用列表，以及完整的应用阵容。 [Ron Amadeo 供图]*

奇巧的图标阵容相对 4.3 有显著的变化。更戏剧化地说，这是一场大屠杀，谷歌从 4.3 的配置中移除了七个图标。谷歌 Hangouts 现在能够处理短信，所以“信息”应用被去除了。Hangouts 同时还接手了 Google Messenger 的职责，所以它的图标也不见了。Google Currents 不再作为默认应用预装，因为它不久后就会被终结——和它一起的还有 Google Play Magazines（Play 杂志），取代它们的是 Google Play Newsstand（Play 报刊亭）。谷歌地图被打回一个图标，这意味着本地和导航的快捷方式被去掉了。难以理解的 Movie Studio 也被去除了——谷歌肯定已经意识到了没人想在手机上剪辑电影。有了主屏的“OK Google”关键词检测，语音搜索图标的呈现就显得多余了，因而将其移除。令人沮丧的是，没人用的新闻和天气应用还在。

有个新应用“Photos（相片）”——实际上是 Google+ 的一部分——接手了图片管理的工作。在 Nexus 5 上，相册和 Google+ 相片十分相似，但在 Google Play 版设备上更新版的奇巧中，相册已经完全被 Google+ 相片所取代。Play Games 是谷歌的后端多用户游戏服务——谷歌版的 Xbox Live 或苹果的 Game Center。Google Drive，已经在 Play 商店存在数年的应用，终于成为了内置应用。谷歌 2012 年 6 月收购的 Quickoffice 也进入了内置应用阵容。Drive 可以打开 Google 文档，Quickoffice 可以打开微软 Office 文档。如果细细追究起来，在大多数奇巧中包含了两个文档编辑应用和两个相片编辑应用。

---

[Ron Amadeo](http://arstechnica.com/author/ronamadeo) / Ron是Ars Technica的评论编缉，专注于安卓系统和谷歌产品。他总是在追寻新鲜事物，还喜欢拆解事物看看它们到底是怎么运作的。[@RonAmadeo](https://twitter.com/RonAmadeo)

---

via: <http://arstechnica.com/gadgets/2016/10/building-android-a-40000-word-history-of-googles-mobile-os/25/>

译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](http://linux.cn/) 荣誉推出


我是如何开始踏上 bash 脚本编程之路的？

失业了，失业了。作家都开始写脚本了。<br />
这次真要从入门到入土了。

作家都开始写脚本了，程序员果真要失业了。。。。

我想点个赞

# 我是如何开始踏上 bash 脚本编程之路的？

>
> 通过一些简单的 Google 搜索，即使是编程入门者也可以尝试编写代码将以往枯燥和冗长的任务自动化。
>
>
>

<img src="content_image/album_201706_17_145617k8n6a5kz0k65akkz.png" alt="How Google helped me learn bash scripting" title="How Google helped me learn bash scripting">

我前几天写了一个脚本。对于一些人来说，这句话听起来没什么了不起的。而对于另一些人来说，这句话意义重大。要知道，我不是一个程序员，而是一个作家。

### 我需要解决什么？

我的问题相当简单：我需要将工程文件进行分类。这些文件可以从一个网站 URL 以 .zip 的格式下载。当我正手工将它们拷贝到我的电脑桌面，并移动到一个已按照我文件分类的需要进行了结构化的目录时，一位作家同事给我提了建议：*“不就是写个脚本的事吗？”*

我心想：*“就写个脚本？”*——说得好像这是世界上最容易做的事情一样。

### Google 是如何解救我的？

同事的问题促使我思考，并且经过思考后，我进行了 Google 搜索。

**Linux 上使用的是什么脚本编程语言？**

这是我第一个 Google 搜索的准则。也许很多人心里会想：“她太笨了！”是的，我很笨。不过，这的确使我走上了一条解决问题的道路。最常见的搜索结果是 Bash 。嗯，我听说过 Bash 。呃，我要分类的文件中有一个里面就有 Bash，那无处不在的 `#!/bin/bash` 。我重新看了下那个文件，我知道它的用途，因为我需要将它分类。

这引导我进行了下一个 Google 搜索。

**如何从一个 URL 下载 zip 文件？**

那确实是我的基本任务。我有一个带有 .zip 文件的 URL ，它包含有所有我需要分类的文件，所以我寻求万能的 Google 的帮助。搜索到的精华内容和其它一些结果引导我使用 Curl 。但最重要的是：我不仅找到了 Curl ，其中一条置顶的搜索结果还展示了一个使用 Curl 去下载并解压 .zip 文件的 Bash 脚本。这超出了我本来想寻求的答案，但那也使我意识到在 Google 搜索具体的请求可以得到我写这个脚本需要的信息。所以，在这个收获的推动下，我写了最简单的脚本：

```
#!/bin/sh

curl http://rather.long.url | tar -xz -C my_directory --strip-components=1

```

我迫不及待地运行看看。但我发现一个问题： URL 是会变的，根据我要访问的文件的分组不同而不同。我有新的问题需要解决，这使我进行了下一轮搜索。

**参数如何传递给 Bash 脚本？**

我需要以不同的 URL 和不同的最终目录来运行此脚本。 Google 向我展示了如何使用 `$1`、`$2` 等等来替换我在命令行中运行脚本时输入的内容。比如：

```
bash myscript.sh http://rather.long.url my_directory

```

这就好多了。一切如我所愿，灵活，实用。最重要的是我只要输入一条简短的命令就可以节省 30 分钟无聊的复制、粘贴工作。这个早上的时间花得值得。

然后我发现还有一个问题：我很健忘，并且我知道我几个月才运行一次这个脚本。这留给我两个疑问：

* 我要如何记得运行脚本时输入什么（URL 先，还是目录先）？
* 如果我被货车撞了，其它作家如何知道该怎样运行我的脚本？

我需要一个使用说明 —— 如果我使用不正确，则脚本会提示。比如：

```
usage: bash yaml-fetch.sh <'snapshot_url'> <directory>

```

否则，则直接运行脚本。我的下一个搜索是：

**如何在 Bash 脚本里使用 “if/then/else”?**

幸运的是，我已经知道编程中 `if/then/else` 的存在。我只要找出如何使用它的方法。在这个过程中，我也学到了如何在 Bash 脚本里使用 `echo` 打印。我的最终成果如下：

```
#!/bin/sh

URL=$1
DIRECTORY=$2

if [ $# -eq 0 ];
 then
 echo "usage: bash yaml-fetch.sh <'snapshot_url'> <directory>".
 else

# 如果目录不存在则创建它
 echo 'create directory'

 mkdir $DIRECTORY

 # 下载并解压 yaml 文件
 echo 'fetch and untar the yaml files'

 curl $URL | tar -xz -C $DIRECTORY --strip-components=1
fi

```

### Google 和脚本编程如何颠覆我的世界？

好吧，这稍微有点夸大，不过现在是 21 世纪，学习新东西（特别是稍微简单的东西）比以前简单多了。我所学到的（除了如何写一个简短的、自动分类的 Bash 脚本之外）是如果我有疑问，那么有很大可能性是其它人在之前也有过相同的疑问。当我困惑时，我可以问下一个问题，再下一个问题。最后，我不仅拥有了脚本，还拥有了可以一直拥有并可以简化其它任务的新技能，这是我之前所没有的。

别止步于第一个脚本（或者编程的第一步）。这是一个技能，和其它的技能并无不同，有大量的信息可以在这一路上帮助你。你无需阅读大量的书或参加一个月的课程。你可以像婴儿学步那样简单地开始写脚本，然后掌握技能并建立自信。人们总有写成千上万行代码的需求，并对它进行分支、合并、修复错误。但是，通过简单的脚本或其它方式来自动化、简单化任务的需求也一样强烈。这样的一个小脚本和小小的自信就能够让你启程脚本编程之路。

（题图： opensource.com）

---

作者简介：

Sandra McCann 是一位 Linux 和开源技术的倡导者。她是一位软件开发者、学习资源内容架构师、内容创作者。桑德拉目前是位于韦斯特福德马萨诸塞州的红帽公司的内容创作者，专注于 OpenStack 和 NFV 技术。

---

via: <https://opensource.com/article/17/5/how-i-learned-bash-scripting>

作者：[Sandra McCann](https://opensource.com/users/sandra-mccann) 译者：[xllc](https://github.com/xllc) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Linux 中高效编写 Bash 脚本的 10 个技巧

Summary: Shell 脚本编程 是你在 Linux 下学习或练习编程的最简单的方式。尤其对 系统管理员要处理着自动化任务，且要开发新的简单的实用程序或工具等（这里只是仅举几例）更是必备技能。

很好的文章，学习了！

纠正了我不少坏毛病诶。。。

我倾向于用“==”来比较字符串。

习惯也是这个，作者给出第6个建议时并没告知原因？

# Linux 中高效编写 Bash 脚本的 10 个技巧

Shell 脚本编程 是你在 Linux 下学习或练习编程的最简单的方式。尤其对 [系统管理员要处理着自动化任务](https://www.tecmint.com/using-shell-script-to-automate-linux-system-maintenance-tasks/)，且要开发新的简单的实用程序或工具等（这里只是仅举几例）更是必备技能。

本文中，我们将分享 10 个写出高效可靠的 bash 脚本的实用技巧，它们包括：

### 1、 脚本中多写注释

这是不仅可应用于 shell 脚本程序中，也可用在其他所有类型的编程中的一种推荐做法。在脚本中作注释能帮你或别人翻阅你的脚本时了解脚本的不同部分所做的工作。

对于刚入门的人来说，注释用 `#` 号来定义。

```
# TecMint 是浏览各类 Linux 文章的最佳站点

```

### 2、 当运行失败时使脚本退出

有时即使某些命令运行失败，bash 可能继续去执行脚本，这样就影响到脚本的其余部分（会最终导致逻辑错误）。用下面的行的方式在遇到命令失败时来退出脚本执行：

```
# 如果命令运行失败让脚本退出执行
set -o errexit
# 或
set -e

```

### 3、 当 Bash 用未声明变量时使脚本退出

Bash 也可能会使用能导致起逻辑错误的未声明的变量。因此用下面行的方式去通知 bash 当它尝试去用一个未声明变量时就退出脚本执行：

```
# 若有用未设置的变量即让脚本退出执行
set -o nounset
# 或
set -u

```

### 4、 使用双引号来引用变量

当引用时（使用一个变量的值）用双引号有助于防止由于空格导致单词分割开和由于识别和扩展了通配符而导致的不必要匹配。

看看下面的例子：

```
#!/bin/bash
# 若命令失败让脚本退出
set -o errexit
# 若未设置的变量被使用让脚本退出
set -o nounset
echo "Names without double quotes"
echo

names="Tecmint FOSSMint Linusay"

for name in $names; do
  echo "$name"
done

echo
echo "Names with double quotes"
echo

for name in "$names"; do
  echo "$name"
done

exit 0

```

保存文件并退出，接着如下运行一下：

```
$ ./names.sh

```

*在脚本中用双引号*

### 5、 在脚本中使用函数

除了非常小的脚本（只有几行代码），总是记得用函数来使代码模块化且使得脚本更可读和可重用。

写函数的语法如下所示：

```
function check_root(){
  command1;
  command2;
}
# 或
check_root(){
  command1;
  command2;
}

```

写成单行代码时，每个命令后要用终止符号：

```
check_root(){ command1; command2; }

```

### 6、 字符串比较时用 `=` 而不是 `==`

注意 `==` 是 `=` 的同义词，因此仅用个单 `=` 来做字符串比较，例如：

```
value1=”tecmint.com”
value2=”fossmint.com”
if [ "$value1" = "$value2" ]

```

### 7、 用 `$(command)` 而不是老旧的 ``command`` 来做代换

[命令代换](https://www.tecmint.com/assign-linux-command-output-to-variable/) 是用这个命令的输出结果取代命令本身。用 `$(command)` 而不是引号 ``command`` 来做命令代换。

这种做法也是 [shellcheck tool](https://www.tecmint.com/shellcheck-shell-script-code-analyzer-for-linux/) （可针对 shell 脚本显示警告和建议）所建议的。例如：

```
user=`echo “$UID”`
user=$(echo “$UID”)

```

### 8、 用 `readonly` 来声明静态变量

静态变量不会改变；它的值一旦在脚本中定义后不能被修改：

```
readonly passwd_file=”/etc/passwd”
readonly group_file=”/etc/group”

```

### 9、 环境变量用大写字母命名，而自定义变量用小写

所有的 bash 环境变量用大写字母去命名，因此用小写字母来命名你的自定义变量以避免变量名冲突：

```
# 定义自定义变量用小写，而环境变量用大写
nikto_file=”$HOME/Downloads/nikto-master/program/nikto.pl”
perl “$nikto_file” -h  “$1”

```

### 10、 总是对长脚本进行调试

如果你在写有数千行代码的 bash 脚本，排错可能变成噩梦。为了在脚本执行前易于修正一些错误，要进行一些调试。通过阅读下面给出的指南来掌握此技巧：

1. [如何在 Linux 中启用 Shell 脚本调试模式](/article-8028-1.html)
2. [如何在 Shell 脚本中执行语法检查调试模式](/article-8045-1.html)
3. [如何在 Shell 脚本中跟踪调试命令的执行](/article-8120-1.html)

本文到这就结束了，你是否有一些其他更好的 bash 脚本编程经验想要分享？若是的话，在下面评论框分享出来吧。

---

作者简介：

Aaron Kili 是一个 Linux 和 F.O.S.S（Free and Open-Source Software，自由及开放源代码软件）爱好者，未来的 Linux 系统管理员、Web 开发人员，目前是 TecMint 的内容创作者，他喜欢用电脑工作，且崇尚分享知识。

---

via: <https://www.tecmint.com/useful-tips-for-writing-bash-scripts-in-linux/>

作者：[Aaron Kili](https://www.tecmint.com/author/aaronkili/) 译者：[ch-cn](https://github.com/ch-cn) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


给非英语母语的人从事开源项目的若干建议

说的是呢

# 给非英语母语的人从事开源项目的若干建议

<img src="content_image/album_201706_18_070757mziaiil4l45g5a0i.png" alt="Tips for non-native English speakers working on open source projects" title="Tips for non-native English speakers working on open source projects">

大多数的开源项目的主要语言都是英语，但是开源项目的用户和贡献者却遍布全球。非英语母语的人在参与这个生态系统时会面临许多沟通和文化上的挑战。

在这篇文章中，作为不以英语为母语的 OpenStack 的贡献者的我们将会分享一些所面临挑战——如何去克服它们，还有一些好的方案，它们能够减轻不以英语为母语且刚开始从事的人的焦虑。我们的总部在日本、巴西和中国，每天都会与世界各地的大型 OpenStack 社区合作。

OpenStack 的官方语言是英语，这意味着我们是作为非英语为母语的人士来进行交流。

### 挑战

非英语为母语的人士在开源社区工作时会面临具体沟通挑战：它们与有限的语言技能和文化差异有关。

#### 语言技能

让我们来关注在阅读、写作、听力和口语背后的具体语言技能。

**阅读**：这是最简单也是最重要的技能。最简单是因为：如果你不明白写了什么，你有机会再次阅读它，或者需要的话可以多次阅读。如果你遇到了一个不常见的短语、表达式或者缩写，你可以使用一个词典或者翻译器。在另一方面，它是最重要的技能是因为：对大多数开源项目而言，主要的交流方式都是邮件列表和 IRC。

**写作**：英语语法是一个问题，尤其是对句子结构不同的语言而言。这可能会在用电子邮件进行通信和通过 IRC 频道进行通信时产生问题。对一些人来说，写出又长又漂亮的句子比较困难，而普遍依赖于简单句子，这是因为这些易于书写和理解。

**听力**：这对非英语为母语的人来说比阅读和写作更加困难。通常，英语为母语的人之间的对话在非常快的，这就使得那些仍然处于刚从事阶段的人很难理解他们的讨论，同时也限制了他们参与到讨论当中。此外，试图理解一个遍布全球的社区的各种口音也增加了复杂性。有意思的是，美国人的发音往往比其他的容易理解。

**口语**：口语比听力更加的困难，因为参与者的词汇量可能会比较有限。而且，英语的音素和语法通常与那些母语不是英语的人的母语相差很大，这就使得互动更加的难以理解。

#### 文化差异

在开源社区与其他人交流时，每种文化都有它自己不同的规范。例如，日本人通常不会明确的说好的或者不，他们认为这是尊重别人的一种方式，可以避免彼此间的争论。这通常与其他的文化大不一样，可能会对所表达的内容造成误解。

在中国文化中，人们倾向于只是说好的，而不是说不，或者试图商讨。在一个像 OpenStack 这样的分布于全球的社区里，这通常会导致在表达意见时缺乏自信。另外，中国人喜欢首先列出事实，然后在后面给出结论，而这会对来自其他文化中的人造成困惑，因为这不是他们所期望的。

例如，巴西人可能会认为讨论是以类似的方式进行的；然而，其他文化的反应会很直接和简短，这听起来可能会有点粗鲁。

### 克服障碍

语言技能方面的挑战要比文化差异方面的挑战容易克服。文化差异需要被受到尊重，然而英语技能却总是可以被改善的。

为了刷新你的语言技能，你应该尽可能多地接触该语言。不要担心你的局限，只管尽自己所能，你终将会得到改善。

尽可能多的阅读，因为这有助于你积累词汇。通过日常的聊天和邮件列表进行交流也很有帮助。一些工具，如实时字典和翻译器，对这些平台非常有用。

与别人或者你自己交谈可以帮助你更自如地频繁地说话。进行一对一的对话来表达你的想法比在更大的群体中讨论更容易。

### 新手的融入

来自新手和母语者的一些举措可能会对学习过程产生积极的影响。

#### 新手

说出和写下你的意见，并且提出你的问题；参与其中总是一个练习你的英语的很好的机会。不要害怕。

对于会议，确保你提前准备过，这样你将会对会议主题比较熟悉，而且会对自己要表达的意见更加的自信。

与英语为母语的人结交朋友，多和他们讨论来提高你的英语技能。

用英语写博客和技术文章也是不错的主意。

#### 给英语为母语的人士的建议

请说话慢一点儿，同时使用一些简单的单词和句子。如果你发现了非英语为母语的人使用英语中的一些错误请不要嘲笑他们，尝试鼓励新来的人表达自己的意见，让他们非常舒适地表达意见。

*这篇文章由 Masayuki Igawa、Dong Ma 和 Samuel de Medeiros Queiroz 共同协作完成，可以在 Hobart 的 linux.conf.au 2017([#lca2017](https://twitter.com/search?q=%23lca2017&src=typd))：[开源社区中的非英语母语者：一个真实的故事](https://linux.conf.au/schedule/presentation/70/)中了解更多*

（ 题图：opensource.com）

---

作者简介：

Masayuki Igawa 是一名拥有 15 年大量软件项目经验的软件工程师，目前正在开发与 Linux 内核和虚拟化相关开源软件。自 2013 年起，他就一直是一名活跃的 OpenStack 项目贡献者。他是像 Tempest 和 subunit2sql 这样一些 OpenStack QA 项目的核心成员。他目前就职于 HPE 的 Upstream OpenStack 团队，该团队目的是使 OpenStack 更适合所有人。他以前曾在 OpenStack 峰会上发表演讲。

---

via: <https://opensource.com/article/17/1/non-native-speakers-take-open-source-communities>

作者：[Masayuki Igawa](https://opensource.com/users/masayukig) 译者：[zhousiyu325](https://github.com/zhousiyu325) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


在 LXD 2.3 及以上版本中管理网络

Summary: 当 LXD 2.0 随着 Ubuntu 16.04 一起发布时，LXD 联网就简单了。直到 LXD 2.3，LXD 终于发展了自己的网络管理 API ，并有相应的命令行工具。

# 在 LXD 2.3 及以上版本中管理网络

<img src="content_image/album_201706_18_074013zftpxooxnyh3h1yc.jpg" alt="" title="">

### 介绍

当 LXD 2.0 随着 Ubuntu 16.04 一起发布时，LXD 联网就简单了。要么你可以使用 `lxd init` 来配置，为你的容器自己提供一个 “lxdbr0” 网桥，要么使用一个已存在的物理接口。

虽然这确实有效，但是有点混乱，因为大部分的桥接配置发生在 Ubuntu 打包的 LXD 之外。那些脚本只能支持一个桥接，并且没有通过 API 暴露，这使得远程配置有点痛苦。

直到 LXD 2.3，LXD 终于发展了自己的网络管理 API ，并有相应的命令行工具。这篇文章试图来简述这些新的功能。

### 基础联网

在初始情况下，LXD 2.3 没有定义任何网络。`lxd init` 会为你设置一个，并且默认情况下将所有新的容器连接到它，但是让我们亲手尝试看下究竟发生了些什么。

要创建一个新的带有随机 IPv4 和 IP6 子网，并启用 NAT 的网络，只需要运行：

```
stgraber@castiana:~$ lxc network create testbr0
Network testbr0 created

```

你可以如下查看它的配置：

```
stgraber@castiana:~$ lxc network show testbr0
name: testbr0
config:
 ipv4.address: 10.150.19.1/24
 ipv4.nat: "true"
 ipv6.address: fd42:474b:622d:259d::1/64
 ipv6.nat: "true"
managed: true
type: bridge
usedby: []

```

如果你不想要那些自动配置的子网，你可以这么做：

```
stgraber@castiana:~$ lxc network create testbr0 ipv6.address=none ipv4.address=10.0.3.1/24 ipv4.nat=true
Network testbr0 created

```

那就会这样：

```
stgraber@castiana:~$ lxc network show testbr0
name: testbr0
config:
 ipv4.address: 10.0.3.1/24
 ipv4.nat: "true"
 ipv6.address: none
managed: true
type: bridge
usedby: []

```

如果你的容器没有使用它，那么创建的网络对你也没什么用。要将你新创建的网络连接到所有容器，你可以这么做：

```
stgraber@castiana:~$ lxc network attach-profile testbr0 default eth0

```

要将一个网络连接到一个已存在的容器中，你可以这么做：

```
stgraber@castiana:~$ lxc network attach my-container default eth0

```

现在，假设你已经在机器中安装了 openvswitch，并且要将这个网桥转换成 OVS 网桥，只需更改为正确的驱动：

```
stgraber@castiana:~$ lxc network set testbr0 bridge.driver openvswitch

```

如果你想要一次性做一系列修改。`lxc network edit` 可以让你在编辑器中交互编辑网络配置。

### 静态租约及端口安全

使用 LXD 管理 DHCP 服务器的一个好处是可以使得管理 DHCP 租约很简单。你所需要的是一个容器特定的网卡设备以及正确的属性设置。

```
root@yak:~# lxc init ubuntu:16.04 c1
Creating c1
root@yak:~# lxc network attach testbr0 c1 eth0
root@yak:~# lxc config device set c1 eth0 ipv4.address 10.0.3.123
root@yak:~# lxc start c1
root@yak:~# lxc list c1
+------+---------+-------------------+------+------------+-----------+
| NAME |  STATE  |        IPV4       | IPV6 |    TYPE    | SNAPSHOTS |
+------+---------+-------------------+------+------------+-----------+
|  c1  | RUNNING | 10.0.3.123 (eth0) |      | PERSISTENT | 0         |
+------+---------+-------------------+------+------------+-----------+

```

IPv6 也是相同的方法，但是换成 `ipv6.address` 属性。

相似地，如果你想要阻止你的容器更改它的 MAC 地址或者为其他 MAC 地址转发流量（比如嵌套），你可以用下面的命令启用端口安全：

```
root@yak:~# lxc config device set c1 eth0 security.mac_filtering true

```

### DNS

LXD 在网桥上运行 DNS 服务器。除了设置网桥的 DNS 域（ `dns.domain` 网络属性）之外，还支持 3 种不同的操作模式（`dns.mode`）：

* `managed` ：每个容器都会有一条 DNS 记录，匹配它的名字以及已知的 IP 地址。容器无法通过 DHCP 改变这条记录。
* `dynamic` ：允许容器通过 DHCP 在 DNS 中自行注册。因此，在 DHCP 协商期间容器发送的任何主机名最终都出现在 DNS 中。
* `none` ： 针对那些没有任何本地 DNS 记录的递归 DNS 服务器。

默认的模式是 `managed`，并且典型的是最安全以及最方便的，因为它为容器提供了 DNS 记录，但是不允许它们通过 DHCP 发送虚假主机名嗅探其他的记录。

### 使用隧道

除了这些，LXD 还支持使用 GRE 或者 VXLAN 隧道连接到其他主机。

LXD 网络可以连接任何数量的隧道，从而轻松地创建跨多个主机的网络。这对于开发、测试和演示非常有用，生产环境通常更喜欢使用 VLAN 进行分割。

所以说，你想在主机 “edfu” 上有一个运行 IPv4 和 IPv6 的基础 “testbr0” 网络，并希望在主机 “djanet” 上使用它来生成容器。最简单的方法是使用组播 VXLAN 隧道。这种类型的隧道仅在两个主机位于同一物理段上时才起作用。

```
root@edfu:~# lxc network create testbr0 tunnel.lan.protocol=vxlan
Network testbr0 created
root@edfu:~# lxc network attach-profile testbr0 default eth0

```

它在主机 “edfu” 上定义了一个 “testbr0” 桥接，并为其他主机能加入它设置了一个组播 VXLAN。在这个设置中，“edfu” 为这个网络扮演了一个路由器角色，提供 DHCP、DNS 等等，其他主机只是通过隧道转发流量。

```
root@djanet:~# lxc network create testbr0 ipv4.address=none ipv6.address=none tunnel.lan.protocol=vxlan
Network testbr0 created
root@djanet:~# lxc network attach-profile testbr0 default eth0

```

现在你可以在任何一台主机上启动容器，并看到它们从同一个地址池中获取 IP，通过隧道直接互相通讯。

如先前所述，这个使用了组播，它通常在跨越路由器时无法很好工作。在这些情况下，你可以用单播模式使用 VXLAN 或者 GRE 隧道。

要使用 GRE 加入另一台主机，首先配置服务主机：

```
root@edfu:~# lxc network set testbr0 tunnel.nuturo.protocol gre
root@edfu:~# lxc network set testbr0 tunnel.nuturo.local 172.17.16.2
root@edfu:~# lxc network set testbr0 tunnel.nuturo.remote 172.17.16.9

```

接着是“客户端”主机：

```
root@nuturo:~# lxc network create testbr0 ipv4.address=none ipv6.address=none tunnel.edfu.protocol=gre tunnel.edfu.local=172.17.16.9 tunnel.edfu.remote=172.17.16.2
Network testbr0 created
root@nuturo:~# lxc network attach-profile testbr0 default eth0

```

如果你像使用 VXLAN，只要这么做：

```
root@edfu:~# lxc network set testbr0 tunnel.edfu.id 10
root@edfu:~# lxc network set testbr0 tunnel.edfu.protocol vxlan

```

还有：

```
root@nuturo:~# lxc network set testbr0 tunnel.edfu.id 10
root@nuturo:~# lxc network set testbr0 tunnel.edfu.protocol vxlan

```

这里需要隧道 id 以防与已经配置的多播 VXLAN 隧道冲突。

这就是如何使用最近的 LXD 简化跨主机联网了！

### 总结

LXD 使得从简单的单主机网络到数千个容器的非常复杂的跨主机网络的定义变得更加容易。它也使为一些容器定义一个新网络或者给容器添加第二个设备，并连接到隔离的私有网络变得很简单。

虽然这篇文章介绍了支持的大部分功能，但仍有一些可以微调 LXD 网络体验的窍门。可以在这里找到完整的列表：[https://github.com/lxc/lxd/blob/master/doc/configuration.md](https://github.com/lxc/lxd/blob/master/doc/configuration.md#network-configuration) 。

### 额外信息

* LXD 主站：<https://linuxcontainers.org/lxd>
* Github 地址： <https://github.com/lxc/lxd>
* 邮件列表支持：[https://lists.linuxcontainers.org](https://lists.linuxcontainers.org/)
* IRC 频道：#lxcontainers on irc.freenode.net
* 在线尝试 LXD：<https://linuxcontainers.org/lxd/try-it>

---

via: <https://www.stgraber.org/2016/10/27/network-management-with-lxd-2-3/>

作者：[Stéphane Graber](https://www.stgraber.org/author/stgraber/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Debian GNU/Linux 9 “Stretch” 正式发布

Debian大法好~！

升级悲剧中，之前划的磁盘空间不足～～～<br />
现在只得把/opt，/var/cache等目录挪走，再链接过去。

昨天在虚拟机里安装使用了一下，感觉确实更好用了，有空再在笔记本里安装。<br />
Debian 大法好。

我在老的惠普2540p上，安装使用基本都正常，但是在终端操作时，会时不时突然黑屏关机，重装后还是如此，不晓得咋弄了

翻译有问题哎

来自辽宁沈阳的 Chrome Mobile 37.0|Android 6.0 用户

哪里有问题，请您指正哈。

# Debian GNU/Linux 9 “Stretch” 正式发布

<img src="content_image/album_201706_19_050039zztd47ede4611bjt.jpg" alt="" title="">

已经使用了两年之久的代号为 “Jessie” 的 Debian GNU/Linux 8，终于被标记为 “oldstable”了。就在 18 日，Debian 项目宣布 Debian GNU/Linux 9，代号为 “Stretch” 的新版本正式发布！

这个 2017 年最重要的 GNU/Linux 发行版，Debian 9 进入了稳定状态，已经可以部署到生产环境中——接下来将会有一大批基于 Debian 的下游衍生版本正在赶来。

Debian 9 是一个主要发布版本，其对现代的硬件和 CPU 架构支持更好，使用了更新的核心组件和应用，此外还有一大堆其它的新功能，当然，稳定性和安全的改进更是重中之重，以及不可尽数的 bug 修复。

在[发布公告](https://www.debian.org/News/2017/20170617)中称：“在经过 26 个月的开发之后，Debian 项目很自豪地推出了新的稳定版本 Debian 9（代号 ‘Stretch’），并在接下来的 5 年内由 Debian 安全团队和 Debian 长期支持团队进行支持。”

### Debian GNU/Linux 9 “Stretch” 亮点

Debian 9 的亮点有：支持 64 位小端 MIPS 硬件架构（mips64el），而停止了对 PowerPC（powerpc）架构的支持；新的 [deb.debian.org](http://deb.debian.org/) 镜像；可以以普通用户运行 X.Org 显示服务器，而不是以 root 用户。

此外，对 APT 和 aptitude 命令行软件包管理器做了重大改进，现在更容易获取和使用调试软件包， APT 源列表中增加了新的 “dbg-sym” 软件仓库，为许多软件包自动地提供了调试符号。Debian 9 中还带有首次发布的 Debian Astro Pure Blend。

Debian 9 中的大量软件包和核心组件进行了更新：

* Linux 4.9 LTS 内核
* GNOME 3.22
* KDE Frameworks 5.28、KDE Plasma 5.8 和 KDE Applications 16.08
* MATE 1.16
* Xfce 4.12
* Chromium 59.0.3071.86
* Firefox 45.9
* GIMP 2.8.18
* Thunderbird 45.8
* LibreOffice 5.2
* Apache 2.4.25
* Tomcat 8.5
* GnuPG 2.1
* MariaDB 10.1
* PostgreSQL 9.6
* GNU Compiler Collection 6.3
* Perl 5.24
* PHP 7.0
* Golang 1.7
* OpenJDK 8
* Python 2.7.13 and 3.5.3
* Ruby 2.3
* Samba 4.5
* systemd 232
* Xen Hypervisor

Debian 9 官方支持 32 位（i386）、64 位（amd64）、64 位 ARM（arm64）等等硬件架构。

那些还在运行 Debian 8 “Jessie” 的计算机现在可以升级到 Debian 9 了。而要全新安装则可以从 debian.org [下载安装介质](https://www.debian.org/distrib/netinst.en.html)，当然，你也可以下载支持各种桌面环境的“[现场版](https://www.debian.org/CD/live/)”。


2017 年的八大系统运维和工程发展趋势

DBA是什么鬼....前几年就有啊...

数据库管理员

# 2017 年的八大系统运维和工程发展趋势

预测趋势是棘手的，尤其是在快速发展的系统运维和工程领域。2016 年，在我们的 Velocity 大会上，我们讨论了分布式系统、SRE、容器化、无服务架构，人员倦怠以及与提供软件相关的人力与技术挑战等诸多问题。以下是我们认为的下一年的趋势：

### 1、 分布式系统

我们认为这个很重要，我们[在整个 Velocity 会议上再次关注了它](https://www.oreilly.com/ideas/velocity-a-new-direction)。

### 2、 站点可靠性工程（SRE）

<ruby>   站点可靠性工程  <rp>  （ </rp> <rt>  Site Reliability Engineering </rt> <rp>  ） </rp></ruby>（SRE）-它只是运维么？[或者它是 DevOps 的另外一个名称吗](http://conferences.oreilly.com/velocity/devops-web-performance-ny/public/content/devops-sre-ama-video)？这是 Google 对那些需要做大量系统及软件工程的运维专业人士的称呼。它由在像 Dropbox 公司的前 Google 人向业内推广，[招聘 SRE 的职位](https://www.glassdoor.com/Salaries/site-reliability-engineer-salary-SRCH_KO0,25.htm)正不断增加，特别是有大型数据中心的面向网络的公司。在某些情况下，SRE 的作用更多地是帮助开发人员运营自己的服务。

### 3、 容器化

公司将继续容器化它们的软件交付。Docker 公司本身已经将 Docker 定位为“[增量革命](http://blog.scottlowe.org/2016/06/21/dockercon-2016-day-2-keynote/)”的工具，对遗留应用进行容器化已成为企业的常见案例。Docker 的未来是什么？随着工程师继续采用诸如 Kubernetes 和 Mesos 之类的编排工具，更高层次的抽象可能为其他容器（如 rkt、Garden 等）提供更多空间。

### 4、 Unikernels

unikernels 是容器化之后的下一步么？它们不合适产品环境么？有些人吹捧 unikernels 的安全和性能好处。关注一下 unikernels 在 2017 是如何进化的，[特别要关注下 Dokcer 公司在这个领域做的](http://www.infoworld.com/article/3024410/application-virtualization/docker-kicks-off-unikernel-revolution.html)。（今年它已经收购了 Unikernel Systems）

### 5、 <ruby> 无服务架构 <rp>  （ </rp> <rt>  Serverless </rt> <rp>  ） </rp></ruby>

无服务架构视功能为基础的计算单元。有些人认为这个术语是误导性的（让人想起 “noops”），并且更倾向于把这个趋势称为“<ruby> 功能即服务 <rp>  （ </rp> <rt>  Functions-as-a-Service </rt> <rp>  ） </rp></ruby>”（FaaS）。开发人员和架构师正在越来越多地尝试这个技术，并期望看到有越来越多的程序用这个范式编写。更多关于 serverless/FaaS 对运维的意义，请查看 Michael Hausenblas 的 [Serverless 运维](http://www.oreilly.com/webops-perf/free/serverless-ops.csp?intcmp=il-webops-free-lp-na_new_site_top_8_systems_operations_and_engineering_trends_for_2017_body_text_cta)免费电子书。

### 6、 原生云程序开发

就像 DevOps，这个术语已经被市场人员使用并滥用很久了，但是<ruby> 云计算基金会 <rp>  （ </rp> <rt>  Cloud Native Computing Foundation </rt> <rp>  ） </rp></ruby>（CNCF）为这些新工具（通常是谷歌发起的）做了一个很好的例子，这些工具不仅利用了云，而且特别还在于分布式系统（即微服务，容器化和动态编排）所提供的优势和机会。

### 7、 监控

随着行业从 Nagios 风格的监控发展到流化指标和可视化，我们在生产越来越多的系统数据，而如何理解它们则是下一个挑战，因此，我们看到供应商开始提供具有机器学习功能的监控服务，以及更普遍的是 IT 运营人员开始去研究让机器学习分析系统数据的技术。同样，随着我们的基础设施变得更加动态和分布式，监控越来越少地检查某个资源的健康状况，更多的是在服务之间追踪流量。因此，分布式跟踪已经出现。

### 8、 DevOps 安全

随着 DevOps 安全的普及，[安全性正在迅速成为团队范围的关注](https://www.oreilly.com/learning/devopssec-securing-software-through-continuous-delivery)。当重视安全和合规方面的公司在速度的竞争上感到了压力时，要同时满足速度和可靠性的 DevOps 所面对的经典挑战尤其明显。

### 告诉我们关于你的工作

作为一名 IT 运维专业人员 - 你是否使用系统管理的术语如 DevOps、SRE、DBA 等等。- [欢迎你来分享你的见解](http://www.oreilly.com/webops-perf/2016-ops-survey.html)。

---

作者简介：

Courtney Nash 主持 O'Reilly Media 的多个会议，是专注于现代网络运维、高性能程序和安全性的战略内容总监。一位前学术神经科学家，她仍然对大脑着迷，以及它如何告诉我们与技术互动和对技术的期望。自从移居西雅图，在一家蓬勃发展的在线书店工作之后，她花了 17 年的时间从事技术行业的各种工作。在外面，你可以看到 Courtney 在骑自行车、徒步旅行、滑雪。。。

O'Reilly Media 的基础架构和运维编辑 Brian Anderson 介绍了从传统系统管理到云计算、Web 性能、Docker 和 DevOps 等软件交付的重要内容。他一直从事在线教育，服务于学习者的需求超过十多年。

---

via: <https://www.oreilly.com/ideas/top-8-systems-operations-and-engineering-trends-for-2017>

作者：[Courtney Nash](https://www.oreilly.com/people/3f5d7-courtneyw-nash), [Brian Anderson](https://www.oreilly.com/people/brian_anderson) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


嘿！获得新成就！论一次与 LinuxCon 的近距离邂逅！

Summary: 没错，这就是一篇炫耀贴。

羡慕中。。。

我就差个签名，签名，签名！！！

可以炫耀几年了

羡慕中

哈哈，一张有纪念意义的照片！

Linuz来中国了。不知道他们是咋来的。也不知道他们知不知道很多技术网站我们根本没机会看看。

知道或不知道都没啥意义

羡慕呀

人在广州，默默的羡慕

妹子报错!

羡慕

WOW

我朋友圈里面有两个人，拿出了他们十年前和 linus 的合影炫耀 ……

右下角的妹砸真好看！

够吹一年

羡慕啊！！！！

羡慕

有没有视频啊!

老太太都不扶就服你

妥妥的跟大神勾搭上了阿

妥妥的跟大神勾搭上了阿

好羡慕啊，大神啊。(¯﹃¯)

那得多激动啊，快打110，不对120

会有的

国内IT人员形象太差，没有气质。

那是我环环妹子~

视频在哪？

请不要以偏概全，谢谢。

这气质。。。。。。

一张合影可以炫耀好多年了

NB

没错，这就是一篇炫耀贴。

# 嘿！获得新成就！论一次与 LinuxCon 的近距离邂逅！

没错，这就是一篇炫耀贴。老王的朋友都知道老王最近一直在念叨着 LinuxCon 大会，这不，就在今天，我等了几个月之久的 LinuxCon 终于在北京国家会议中心召开了！

一大早，嗯，严格来说是早上 4 点，我就起床了，由于要出去参加整整一天的 LinuxCon，所以我得提前将今天要编发的内容准备好。忙完 Linux 中国网站要发的内容之后，我又经过了一个小时的车程，终于赶在签到时间前到达了本次 LinuxCon 大会的现场——北京国家会议中心。

*来早了的国家会议中心*

想着等会就能见到心目中的大神： Linus Torvalds —— Linux 之父，还真有点小激动。

这次大会，虽然门票是真贵，但是——它居然提供早餐，而且不仅如此，会场的茶歇、午餐，也都提供！甚至，就在会议结束，大家准备各回各家时，它居然还提供了晚餐！晚餐！！这简直是一场太酷的技术大会了——要我说，这种大会多来几场，我肯定次次都要来啊！

好了，不能这么没出息，我不是为吃的来的。

*会议早餐*

### 场外喜逢格雷

汇合了 Linux 中国的小伙伴们之后，我们换上了 LinuxCon 大会专属 T 恤，围在小桌前开始吃自助早餐时，突然，远处出现一位“高人”，真的是“高”人啊。在那些端着盘子、站着吃饭的观众们中间，有一位个子很高、顶部闪闪发亮的“高”人在移动，简直不要太醒目！

他是谁？

对 LinuxCon 仔细做过功课的我，一下就认出了，原来是格雷啊，就是那个经常出现在内核邮件列表中的 Greg Kroah-Hartman 啊！好吧，我知道你也不会念他的名字，所以，你就知道他就是那位负责维护所有的稳定版的 Linux内核分支的人就好了。

*格雷就负责那些绿色的稳定版系列维护*

本着机会难得，我和小伙伴们匆匆丢下嘴边的食物，马上围上前去，通过简单的比划，表达了我们美好的愿望。格雷一路“呵呵”地和我们大伙合影、和我单独合影。别说，这快活的“呵呵”笑声，让我觉得格雷老兄特忠厚。

好了，无图无真相，扯这么多都不上图，你们可要砸键盘了！

*老王与格雷的合影*

看见没，老王身高有 170 公分，可我才到格雷老兄的肩膀！！！觉不觉得我们两个的光头熠熠生辉？！（划重点，光头）

### 遭遇一个笑容满面的吉姆

对比了一下身高之后略感挫败的我，接着就准备进入主会场了。

由于进场时间比较早，我们就坐到了最中间的前排，然后，我们就又发现一位“熟”人——我已经在各种资料中很多次见过他的面容啦——Linux 基金会执行总监，Jim Zemlin，让我们就叫他吉姆吧。

由于受刚才和格雷老哥合影成功的鼓舞，我就壮起胆子，大家组队去（打 BOSS，删掉）找吉姆合影啦。吉姆果然如人家说的，是个很热情的人，不但满足了我们组队的要求，还允许我们换着人来单打。而且，可能是受他真诚的笑容感染，我们居然很自然的勾肩搭背地照了好几张。逮着眼镜的吉姆，一看就是那种真心开心的笑容，我觉得他肯定为大会终于在中国召开了而高兴！别人的合影我就不放了，我就放我与吉姆的一张吧：

*老王和吉姆的合影*

后来，我发现我们的小伙伴netb2c和吉姆有一张神奇的照片，我觉得我得分享给大家，希望不要被他看到，哈哈哈哈。（划重点，眼镜）

*好诡异的蓝色眼镜！*

不知道你看到这里什么感受，是不是很羡慕啊。都说了，这是一个炫耀贴嘛——所有的技术干货这里都不会提及，我会以后专门写一篇干货分享的——如果有时间 :D

### 真正的炫耀，在这里

你以为这就够了？错！

事实上，在之前，老王真心没有任何预料到会和心目中的大神有近距离接触。因为有朋友给我说，Linus Torvalds 不喜和人合影——这也可以理解嘛，Linus 是一个率真而低调的人，要是一个个粉丝们合影过来，估计就没写代码的时间了。

因此，下午老王受邀参加 Linux 基金会的新闻发布会时，虽然知道Linus 会出席，但是真心没想着能近距离接触到他。

为了怕参加新闻发布会人太多，我一样是早早抵达会场，在很前面的第二排找了个位置，因为第一排据说是预留座位。

过了一会儿，吉姆来了，嗯，看来快开始了——突然，旁边走过去一个胖子，额，说胖子也不对，其实就像老王一样，中年发福有肚腩而已。只见他身着灰黑 T恤，穿着牛仔裤，踩着轻快的脚步，一路走了进来！

啊啊啊啊，Linus Torvalds 就这样一不留神进来了！

然后，他就坐在我前面一排了。紧张，由于担心失礼，老王没敢拿出相机来，就掏出手机来偷偷拍两张。

*拍个侧影，应该不会被发现*

这侧面还是挺有型的吧！

嘿，照了几张之后，好像不会被发现哎，但是我还是不敢冲到前面去对着他拍照，万一生气把我赶出去呢。

接下来的新闻发布会上，到了问答环节，老王在得到提问机会后，马上就抛出了早已准备好的问题：

>
> 老王：看来每个人面对偶像时都会紧张啊。现在 Linux 已经取得很大的成功，那么我想请问 Linus Torvalds 先生，您认为 Linux 和您个人所取得的成功是一种偶然还是必然？谢谢。
>
>
> Linus Torvalds 表示，这份成功的背后既有必然性，也有偶然性。如果 Linux 出现再早几年就可能赶不上互联网的发展，也就不会有社区协作、网络传播的支持，就很难取得这样的成功；而要是再晚几年，可能成功的就是另外的操作系统，或许不是 Linux 和他了，但是必然会有一种适应需求而出现的操作系统。
>
>
>

新闻发布会结束时，大家马上一拥而上，我旁边的美女一个箭步，顺利拉住了 Linus 的注意力，成功拿到了 Linus Torvalds 在 LinuxCon 上的第一个签名！让旁边的我们羡慕嫉妒恨啊！！！Linus 在被围观之后，发现根本走不开，居然同意和大家来一张大合影！老王马上开始考虑站位问题，既要有礼貌风度，又不能在合影里面只露出半个脑袋。

然而，经过一番站位博弈之后，老王发现，还是只有蹲在 Linus 身前才比较合适。不过这张照片抓拍时间不够好，Linus 在看啥呐？

*老王背后是不专心合影的 Linus Torvalds 和陆首群先生*

原本以为有个合影就是奢望的我，当然还是希望得到人更少一些的合影了。在鄙视了那些拿出手机，蹭到 Linus 身前强行自拍的人之后（其实是老王比较腼腆）；终于捞到了一个和 LinuxStory 社区创始人闻其详一同与 Linus Torvalds 合影的机会。

*从左到右：Linux 中国的王兴宇、Linus Torvalds、LinuxStory 的闻其详*

等等，Linus 左肩上的那个手是谁的？！你这让我们怎么把你 P 掉啊！忍不住炫耀之心给朋友们看了之后，大家纷纷表示，请把右边那个人 P 掉，哈哈。

### 惊喜之外

LinuxCon 议程有两天，20日上午，Linus Torvalds 会有一个公开访谈环节。因此，第二天一早，我们的 Linux 小伙伴 Bestony 就早早就位最佳直播位。

非常幸运的是，老王在 Linus 上台预备前，又一次遇到了他。这次，老王可是有备而来，专门拿出 Linux 唯一的一本自传：《<ruby> 只是为了好玩 <rp>  （ </rp> <rt>  Just for Fun </rt> <rp>  ） </rp></ruby>》，请他帮我签了名——虽然旁边工作人员极力阻挠，但是 Linus Torvalds 还是非常通情达理地为我签了名，哈哈哈！

*Linus Torvalds 的签字*

这本书我可得收藏好了！

---

 对了，之后就是 Linus Torvalds 的访谈了，我们的小伙伴 Bestony 已经做了直播，没赶上直播的同学，可以稍后观看我们剪辑和配置字幕的视频，敬请期待！