Linux 有问必答：如何解决 Linux 上的 Wireshark 界面僵死

Summary: 问题: 当我试图在 Ubuntu 上的 Wireshark 中打开一个 pre-recorded 数据包转储时，它的界面突然死机，在我运行 Wireshark 的终端出现了下面的错误和警告。我该如何解决这个问题？  (wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GObject' (wireshark:3480): GLib-GObject-CRITICAL **: g_object_set_qdata_full: assertion 'G_IS_OBJECT (object)' failed (wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GtkRange' (wireshark:3480): Gtk-CRITICAL **: gtk_ran

>
> **问题**: 当我试图在 Ubuntu 上的 Wireshark 中打开一个 pre-recorded 数据包转储时，它的界面突然死机，在我运行 Wireshark 的终端出现了下面的错误和警告。我该如何解决这个问题？
>
>
>

```
(wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GObject'
(wireshark:3480): GLib-GObject-CRITICAL **: g_object_set_qdata_full: assertion 'G_IS_OBJECT (object)' failed
(wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GtkRange'
(wireshark:3480): Gtk-CRITICAL **: gtk_range_get_adjustment: assertion 'GTK_IS_RANGE (range)' failed
(wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GtkOrientable'
(wireshark:3480): Gtk-CRITICAL **: gtk_orientable_get_orientation: assertion 'GTK_IS_ORIENTABLE (orientable)' failed
(wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GtkScrollbar'
(wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GtkWidget'
(wireshark:3480): GLib-GObject-WARNING **: invalid unclassed pointer in cast to 'GObject'
(wireshark:3480): GLib-GObject-CRITICAL **: g_object_get_qdata: assertion 'G_IS_OBJECT (object)' failed
(wireshark:3480): Gtk-CRITICAL **: gtk_widget_set_name: assertion 'GTK_IS_WIDGET (widget)' failed

```

Wireshark 是一个基于 GUI 的数据包捕获和嗅探工具。该工具被网络管理员普遍使用，网络安全工程师或开发人员对于各种任务的数据包级的网络分析是必需的，例如在网络故障，漏洞测试，应用程序调试，或逆向协议工程是必需的。 Wireshark 允许实时记录数据包，并通过便捷的图形用户界面浏览他们的协议首部和有效负荷。

![](/data/attachment/album/201509/10/202003k22ffoi2envzik3v.jpg)

这是 Wireshark 的 UI，尤其是在 Ubuntu 桌面下运行时，当你向上或向下滚动分组列表视图时，或开始加载一个 pre-recorded 包转储文件时，有时会挂起或冻结，并出现以下错误。

![](/data/attachment/album/201509/10/202009fgo9vryyiiw6r163.jpg)

显然，这个错误是由 Wireshark 和叠加滚动条之间的一些不兼容造成的，在最新的 Ubuntu 桌面还没有被解决（例如，Ubuntu 15.04 的桌面）。

一种避免 Wireshark 的 UI 卡死的办法就是 **暂时禁用叠加滚动条**。在 Wireshark 上有两种方法来禁用叠加滚动条，这取决于你在桌面上如何启动 Wireshark 的。

### 命令行解决方法

叠加滚动条可以通过设置"**LIBOVERLAY\_SCROLLBAR**"环境变量为“0”来被禁止。

所以，如果你是在终端使用命令行启动 Wireshark 的，你可以在 Wireshark 中禁用叠加滚动条，如下所示。

打开你的 .bashrc 文件，并定义以下 alias。

```
alias wireshark="LIBOVERLAY_SCROLLBAR=0 /usr/bin/wireshark"

```

### 桌面启动解决方法

如果你是使用桌面启动器启动的 Wireshark，你可以编辑它的桌面启动器文件。

```
$ sudo vi /usr/share/applications/wireshark.desktop

```

查找以"Exec"开头的行，并如下更改。

```
Exec=env LIBOVERLAY_SCROLLBAR=0 wireshark %f

```

虽然这种解决方法可以在系统级帮助到所有桌面用户，但升级 Wireshark 后被覆盖就没用了。如果你想保留修改的 .desktop 文件，如下所示将它复制到你的主目录。

```
$ cp /usr/share/applications/wireshark.desktop ~/.local/share/applications/

```

---

via: <http://ask.xmodulo.com/fix-wireshark-gui-freeze-linux-desktop.html>

作者：[Dan Nanni](http://ask.xmodulo.com/author/nanni) 译者：[strugglingyouth](https://github.com/strugglingyouth) 校对：[wxy](https://github.com/wxy)

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


LinuxCon: 服务器操作系统的转型

Summary: 西雅图报道。容器迟早要改变世界，以及改变操作系统的角色。这是 Wim Coekaerts 带来的 LinuxCon 演讲主题，Coekaerts 是 Oracle 公司 Linux 与虚拟化工程的高级副总裁。  Coekaerts 在开始演讲的时候拿出一张关于桌面之年的幻灯片，引发了现场观众的一片笑声。之后他说 2015 年很明显是容器之年，更是应用之年，应用才是容器的关键。 你需要操作系统做什么事情？，Coekaerts 回答现场观众：只需一件事：运行一个应用。操作系统负责管理硬件和资源，来让你的应用运行起来。 Coakaerts 补充说，在 Docker 容器的帮助下，我们的注意力再次集

西雅图报道。容器迟早要改变世界，以及改变操作系统的角色。这是 Wim Coekaerts 带来的 LinuxCon 演讲主题，Coekaerts 是 Oracle 公司 Linux 与虚拟化工程的高级副总裁。

![](/data/attachment/album/201509/10/203541nl1qzrrjq9ft98q9.jpg)

Coekaerts 在开始演讲的时候拿出一张关于“桌面之年”的幻灯片，引发了现场观众的一片笑声。之后他说 2015 年很明显是容器之年，更是应用之年，应用才是容器的关键。

“你需要操作系统做什么事情？”，Coekaerts 回答现场观众：“只需一件事：运行一个应用。操作系统负责管理硬件和资源，来让你的应用运行起来。”

Coakaerts 补充说，在 Docker 容器的帮助下，我们的注意力再次集中在应用上，而在 Oracle，我们将注意力放在如何让应用更好地运行在操作系统上。

“许多人过去常常需要繁琐地安装应用，而现在的年轻人只需要按一个按钮就能让应用在他们的移动设备上运行起来”。

人们对安装企业版的软件需要这么复杂的步骤而感到惊讶，而 Docker 帮助他们脱离了这片苦海。

“操作系统的角色已经变了。” Coekaerts 说。

Docker 的出现不代表虚拟机的淘汰，容器化过程需要经过很长时间才能变得成熟，然后才能在世界范围内得到应用。

在这段时间内，容器会与虚拟机共存，并且我们需要一些工具，将应用在容器和虚拟机之间进行转换迁移。Coekaerts 举例说 Oracle 的 VirtualBox 就可以用来帮助用户运行 Docker，而它原来是被广泛用在桌面系统上的一项开源技术。现在 Docker 的 Kitematic 项目将在 Mac 上使用 VirtualBox 运行 Docker。

### 容器的开放计算计划和一次写随处部署

一个能让容器成功的关键是“一次写，随处部署”的概念。而在容器之间的互操作领域，Linux 基金会的开放计算计划（OCI）扮演一个非常关键的角色。

“使用 OCI，应用编译一次后就可以很方便地在多地运行，所以你可以将你的应用部署在任何地方”。

Coekaerts 总结说虽然在迁移到容器模型过程中会发生很多好玩的事情，但容器还没真正做好准备，他强调 Oracle 现在正在验证将产品运行在容器内的可行性，但这是一个非常艰难的过程。

“运行数据库很简单，难的是要搞定数据库所需的环境”，Coekaerts 说：“容器与虚拟机不一样，一些需要依赖底层系统配置的应用无法从主机迁移到容器中。”

另外，Coekaerts 指出在容器内调试问题与在虚拟机内调试问题也是不一样的，现在还没有成熟的工具来进行容器应用的调试。

Coekaerts 强调当容器足够成熟时，有一点很重要：不要抛弃现有的技术。组织和企业不能抛弃现有的部署好的应用，而完全投入新技术的怀抱。

“部署新技术是很困难的事情，你需要缓慢地迁移过去，能让你顺利迁移的技术才是成功的技术。”Coekaerts 说。

---

via: <http://www.serverwatch.com/server-news/linuxcon-the-changing-role-of-the-server-os.html>

作者：[Sean Michael Kerner](http://www.serverwatch.com/author/Sean-Michael-Kerner-101580.htm) 译者：[bazz2](https://github.com/bazz2) 校对：[wxy](https://github.com/wxy)

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


Linux 上将出现一个新的文件系统：bcachefs

Summary: 这个有 5 年历史，由 Kent Oberstreet 创建，过去属于谷歌的文件系统，最近完成了全部关键组件。Bcachefs 文件系统自称其性能和稳定性与 ext4 和 xfs 相同，而其他方面的功能又可以与 btrfs 和 zfs 相媲美。主要特性包括校验、压缩、多设备支持、缓存、快照与其他漂亮的特性。  Bcachefs 来自 bcache，这是一个块级缓存层。从 bcaceh 到一个功能完整的写时复制文件系统，堪称是一项质的转变。 对自己的问题为什么要出一个新的文件系统中，Kent Oberstreet 自问自答道：当我还在谷歌的时候，我与其他在 bcache 上工作的同事在偶然的情况下

从 bcaceh 到一个功能完整<br />
应该是bcache吧

谢谢，笔误~~马上修改。

这个有 5 年历史，由 Kent Oberstreet 创建，过去属于谷歌的文件系统，最近完成了全部关键组件。Bcachefs 文件系统自称其性能和稳定性与 ext4 和 xfs 相同，而其他方面的功能又可以与 btrfs 和 zfs 相媲美。主要特性包括校验、压缩、多设备支持、缓存、快照与其他“漂亮”的特性。

![](/data/attachment/album/201509/10/204300kxsnyhzsqqqyoxer.png)

Bcachefs 来自 **bcache**，这是一个块级缓存层。从 bcache 到一个功能完整的[写时复制](https://en.wikipedia.org/wiki/Copy-on-write)文件系统，堪称是一项质的转变。

对自己的问题“为什么要出一个新的文件系统”中，Kent Oberstreet 自问自答道：当我还在谷歌的时候，我与其他在 bcache 上工作的同事在偶然的情况下意识到我们正在使用的东西可以成为一个成熟文件系统的功能块，我们可以用 bcache 创建一个拥有干净而优雅设计的文件系统，而最重要的一点是，bcachefs 的主要目的就是在性能和稳定性上能与 ext4 和 xfs 匹敌，同时拥有 btrfs 和 zfs 的特性。

Overstreet 邀请人们在自己的系统上测试 bcachefs，可以通过邮件列表[通告]获取 bcachefs 的操作指南。

Linux 生态系统中文件系统几乎处于一家独大状态，Fedora 在第 16 版的时候就想用 btrfs 换掉 ext4 作为其默认文件系统，但是到现在（LCTT：都出到 Fedora 22 了）还在使用 ext4。而几乎所有 Debian 系的发行版（Ubuntu、Mint、elementary OS 等）也使用 ext4 作为默认文件系统，并且这些主流的发行版都没有替换默认文件系统的意思。

---

via: <http://www.linuxveda.com/2015/08/22/linux-gain-new-file-system-bcachefs/>

作者：[Paul Hill](http://www.linuxveda.com/author/paul_hill/) 译者：[bazz2](https://github.com/bazz2) 校对：[wxy](https://github.com/wxy)

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


你知道 Linux 内核是如何构建的吗？

Summary: 介绍 我不会告诉你怎么在自己的电脑上去构建、安装一个定制化的 Linux 内核，这样的资料太多了，它们会对你有帮助。本文会告诉你当你在内核源码路径里敲下make 时会发生什么。 当我刚刚开始学习内核代码时，Makefile 是我打开的第一个文件，这个文件看起来真令人害怕 :)。那时候这个 Makefile 还只包含了1591 行代码，当我开始写本文时，内核已经是4.2.0的第三个候选版本 了。 这个 makefile 是 Linux 内核代码的根 makefile ，内核构建就始于此处。是的，它的内容很多，但是如果你已经读过内核源代码，你就会发现每个包含代码的目录都有

### 介绍

我不会告诉你怎么在自己的电脑上去构建、安装一个定制化的 Linux 内核，这样的[资料](https://encrypted.google.com/search?q=building+linux+kernel#q=building+linux+kernel+from+source+code)太多了，它们会对你有帮助。本文会告诉你当你在内核源码路径里敲下`make` 时会发生什么。

当我刚刚开始学习内核代码时，[Makefile](https://github.com/torvalds/linux/blob/master/Makefile) 是我打开的第一个文件，这个文件看起来真令人害怕 :)。那时候这个 [Makefile](https://en.wikipedia.org/wiki/Make_%28software%29) 还只包含了`1591` 行代码，当我开始写本文时，内核已经是[4.2.0的第三个候选版本](https://github.com/torvalds/linux/commit/52721d9d3334c1cb1f76219a161084094ec634dc) 了。

这个 makefile 是 Linux 内核代码的根 makefile ，内核构建就始于此处。是的，它的内容很多，但是如果你已经读过内核源代码，你就会发现每个包含代码的目录都有一个自己的 makefile。当然了，我们不会去描述每个代码文件是怎么编译链接的，所以我们将只会挑选一些通用的例子来说明问题。而你不会在这里找到构建内核的文档、如何整洁内核代码、[tags](https://en.wikipedia.org/wiki/Ctags) 的生成和[交叉编译](https://en.wikipedia.org/wiki/Cross_compiler) 相关的说明，等等。我们将从`make` 开始，使用标准的内核配置文件，到生成了内核镜像 [bzImage](https://en.wikipedia.org/wiki/Vmlinux#bzImage) 结束。

如果你已经很了解 [make](https://en.wikipedia.org/wiki/Make_%28software%29) 工具那是最好，但是我也会描述本文出现的相关代码。

让我们开始吧！

![](/data/attachment/album/201509/11/092508gz45l78glkmkgzp2.png)

（题图来自：adafruit.com）

### 编译内核前的准备

在开始编译前要进行很多准备工作。最主要的就是找到并配置好配置文件，`make` 命令要使用到的参数都需要从这些配置文件获取。现在就让我们深入内核的根 `makefile` 吧

内核的根 `Makefile` 负责构建两个主要的文件：[vmlinux](https://en.wikipedia.org/wiki/Vmlinux) （内核镜像可执行文件）和模块文件。内核的 [Makefile](https://github.com/torvalds/linux/blob/master/Makefile) 从定义如下变量开始：

```
VERSION = 4
PATCHLEVEL = 2
SUBLEVEL = 0
EXTRAVERSION = -rc3
NAME = Hurr durr I'ma sheep

```

这些变量决定了当前内核的版本，并且被使用在很多不同的地方，比如同一个 `Makefile` 中的 `KERNELVERSION` ：

```
KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)

```

接下来我们会看到很多`ifeq` 条件判断语句，它们负责检查传递给 `make` 的参数。内核的 `Makefile` 提供了一个特殊的编译选项 `make help` ，这个选项可以生成所有的可用目标和一些能传给 `make` 的有效的命令行参数。举个例子，`make V=1` 会在构建过程中输出详细的编译信息，第一个 `ifeq` 就是检查传递给 make 的 `V=n` 选项。

```
ifeq ("$(origin V)", "command line")
  KBUILD_VERBOSE = $(V)
endif
ifndef KBUILD_VERBOSE
  KBUILD_VERBOSE = 0
endif

ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q = @
endif

export quiet Q KBUILD_VERBOSE

```

如果 `V=n` 这个选项传给了 `make` ，系统就会给变量 `KBUILD_VERBOSE` 选项附上 `V` 的值，否则的话`KBUILD_VERBOSE` 就会为 `0`。然后系统会检查 `KBUILD_VERBOSE` 的值，以此来决定 `quiet` 和`Q` 的值。符号 `@` 控制命令的输出，如果它被放在一个命令之前，这条命令的输出将会是 `CC scripts/mod/empty.o`，而不是`Compiling .... scripts/mod/empty.o`（LCTT 译注：CC 在 makefile 中一般都是编译命令）。在这段最后，系统导出了所有的变量。

下一个 `ifeq` 语句检查的是传递给 `make` 的选项 `O=/dir`，这个选项允许在指定的目录 `dir` 输出所有的结果文件：

```
ifeq ($(KBUILD_SRC),)

ifeq ("$(origin O)", "command line")
  KBUILD_OUTPUT := $(O)
endif

ifneq ($(KBUILD_OUTPUT),)
saved-output := $(KBUILD_OUTPUT)
KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \
                                && /bin/pwd)
$(if $(KBUILD_OUTPUT),, \
     $(error failed to create output directory "$(saved-output)"))

sub-make: FORCE
    $(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \
    -f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS))

skip-makefile := 1
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)

```

系统会检查变量 `KBUILD_SRC`，它代表内核代码的顶层目录，如果它是空的（第一次执行 makefile 时总是空的），我们会设置变量 `KBUILD_OUTPUT` 为传递给选项 `O` 的值（如果这个选项被传进来了）。下一步会检查变量 `KBUILD_OUTPUT` ，如果已经设置好，那么接下来会做以下几件事：

* 将变量 `KBUILD_OUTPUT` 的值保存到临时变量 `saved-output`；
* 尝试创建给定的输出目录；
* 检查创建的输出目录，如果失败了就打印错误；
* 如果成功创建了输出目录，那么就在新目录重新执行 `make` 命令（参见选项`-C`）。

下一个 `ifeq` 语句会检查传递给 make 的选项 `C` 和 `M`：

```
ifeq ("$(origin C)", "command line")
  KBUILD_CHECKSRC = $(C)
endif
ifndef KBUILD_CHECKSRC
  KBUILD_CHECKSRC = 0
endif

ifeq ("$(origin M)", "command line")
  KBUILD_EXTMOD := $(M)
endif

```

第一个选项 `C` 会告诉 `makefile` 需要使用环境变量 `$CHECK` 提供的工具来检查全部 `c` 代码，默认情况下会使用[sparse](https://en.wikipedia.org/wiki/Sparse)。第二个选项 `M` 会用来编译外部模块（本文不做讨论）。

系统还会检查变量 `KBUILD_SRC`，如果 `KBUILD_SRC` 没有被设置，系统会设置变量 `srctree` 为`.`：

```
ifeq ($(KBUILD_SRC),)
        srctree := .
endif

objtree := .
src     := $(srctree)
obj     := $(objtree)

export srctree objtree VPATH

```

这将会告诉 `Makefile` 内核的源码树就在执行 `make` 命令的目录，然后要设置 `objtree` 和其他变量为这个目录，并且将这些变量导出。接着就是要获取 `SUBARCH` 的值，这个变量代表了当前的系统架构（LCTT 译注：一般都指CPU 架构）：

```
SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
                  -e s/sun4u/sparc64/ \
                  -e s/arm.*/arm/ -e s/sa110/arm/ \
                  -e s/s390x/s390/ -e s/parisc64/parisc/ \
                  -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
                  -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ )

```

如你所见，系统执行 [uname](https://en.wikipedia.org/wiki/Uname) 得到机器、操作系统和架构的信息。因为我们得到的是 `uname` 的输出，所以我们需要做一些处理再赋给变量 `SUBARCH` 。获得 `SUBARCH` 之后就要设置`SRCARCH` 和 `hfr-arch`，`SRCARCH` 提供了硬件架构相关代码的目录，`hfr-arch` 提供了相关头文件的目录：

```
ifeq ($(ARCH),i386)
        SRCARCH := x86
endif
ifeq ($(ARCH),x86_64)
        SRCARCH := x86
endif

hdr-arch  := $(SRCARCH)

```

注意：`ARCH` 是 `SUBARCH` 的别名。如果没有设置过代表内核配置文件路径的变量 `KCONFIG_CONFIG`，下一步系统会设置它，默认情况下就是 `.config` ：

```
KCONFIG_CONFIG  ?= .config
export KCONFIG_CONFIG

```

以及编译内核过程中要用到的 [shell](https://en.wikipedia.org/wiki/Shell_%28computing%29)

```
CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
      else if [ -x /bin/bash ]; then echo /bin/bash; \
      else echo sh; fi ; fi)

```

接下来就要设置一组和编译内核的编译器相关的变量。我们会设置主机的 `C` 和 `C++` 的编译器及相关配置项：

```
HOSTCC       = gcc
HOSTCXX      = g++
HOSTCFLAGS   = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89
HOSTCXXFLAGS = -O2

```

接下来会去适配代表编译器的变量 `CC`，那为什么还要 `HOST*` 这些变量呢？这是因为 `CC` 是编译内核过程中要使用的目标架构的编译器，但是 `HOSTCC` 是要被用来编译一组 `host` 程序的（下面我们就会看到）。

然后我们就看到变量 `KBUILD_MODULES` 和 `KBUILD_BUILTIN` 的定义，这两个变量决定了我们要编译什么东西（内核、模块或者两者）：

```
KBUILD_MODULES :=
KBUILD_BUILTIN := 1

ifeq ($(MAKECMDGOALS),modules)
  KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1)
endif

```

在这我们可以看到这些变量的定义，并且，如果们仅仅传递了 `modules` 给 `make`，变量 `KBUILD_BUILTIN` 会依赖于内核配置选项 `CONFIG_MODVERSIONS`。

下一步操作是引入下面的文件：

```
include scripts/Kbuild.include

```

文件 [Kbuild](https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kbuild.txt) 或者又叫做 `Kernel Build System` 是一个用来管理构建内核及其模块的特殊框架。`kbuild` 文件的语法与 makefile 一样。文件[scripts/Kbuild.include](https://github.com/torvalds/linux/blob/master/scripts/Kbuild.include) 为 `kbuild` 系统提供了一些常规的定义。因为我们包含了这个 `kbuild` 文件，我们可以看到和不同工具关联的这些变量的定义，这些工具会在内核和模块编译过程中被使用（比如链接器、编译器、来自 [binutils](http://www.gnu.org/software/binutils/) 的二进制工具包 ，等等）：

```
AS      = $(CROSS_COMPILE)as
LD      = $(CROSS_COMPILE)ld
CC      = $(CROSS_COMPILE)gcc
CPP     = $(CC) -E
AR      = $(CROSS_COMPILE)ar
NM      = $(CROSS_COMPILE)nm
STRIP       = $(CROSS_COMPILE)strip
OBJCOPY     = $(CROSS_COMPILE)objcopy
OBJDUMP     = $(CROSS_COMPILE)objdump
AWK     = awk
...
...
...

```

在这些定义好的变量后面，我们又定义了两个变量：`USERINCLUDE` 和 `LINUXINCLUDE`。他们包含了头文件的路径（第一个是给用户用的，第二个是给内核用的）：

```
USERINCLUDE    := \
        -I$(srctree)/arch/$(hdr-arch)/include/uapi \
        -Iarch/$(hdr-arch)/include/generated/uapi \
        -I$(srctree)/include/uapi \
        -Iinclude/generated/uapi \
        -include $(srctree)/include/linux/kconfig.h

LINUXINCLUDE    := \
        -I$(srctree)/arch/$(hdr-arch)/include \
        ...

```

以及给 C 编译器的标准标志：

```
KBUILD_CFLAGS   := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
           -fno-strict-aliasing -fno-common \
           -Werror-implicit-function-declaration \
           -Wno-format-security \
           -std=gnu89

```

这并不是最终确定的编译器标志，它们还可以在其他 makefile 里面更新（比如 `arch/` 里面的 kbuild）。变量定义完之后，全部会被导出供其他 makefile 使用。

下面的两个变量 `RCS_FIND_IGNORE` 和 `RCS_TAR_IGNORE` 包含了被版本控制系统忽略的文件：

```
export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o    \
              -name CVS -o -name .pc -o -name .hg -o -name .git \) \
              -prune -o
export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
             --exclude CVS --exclude .pc --exclude .hg --exclude .git

```

这就是全部了，我们已经完成了所有的准备工作，下一个点就是如果构建`vmlinux`。

### 直面内核构建

现在我们已经完成了所有的准备工作，根 makefile（注：内核根目录下的 makefile）的下一步工作就是和编译内核相关的了。在这之前，我们不会在终端看到 `make` 命令输出的任何东西。但是现在编译的第一步开始了，这里我们需要从内核根 makefile 的 [598](https://github.com/torvalds/linux/blob/master/Makefile#L598) 行开始，这里可以看到目标`vmlinux`：

```
all: vmlinux
    include arch/$(SRCARCH)/Makefile

```

不要操心我们略过的从 `export RCS_FIND_IGNORE.....` 到 `all: vmlinux.....` 这一部分 makefile 代码，他们只是负责根据各种配置文件（`make *.config`）生成不同目标内核的，因为之前我就说了这一部分我们只讨论构建内核的通用途径。

目标 `all:` 是在命令行如果不指定具体目标时默认使用的目标。你可以看到这里包含了架构相关的 makefile（在这里就指的是 [arch/x86/Makefile](https://github.com/torvalds/linux/blob/master/arch/x86/Makefile)）。从这一时刻起，我们会从这个 makefile 继续进行下去。如我们所见，目标 `all` 依赖于根 makefile 后面声明的 `vmlinux`：

```
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE

```

`vmlinux` 是 linux 内核的静态链接可执行文件格式。脚本 [scripts/link-vmlinux.sh](https://github.com/torvalds/linux/blob/master/scripts/link-vmlinux.sh) 把不同的编译好的子模块链接到一起形成了 vmlinux。

第二个目标是 `vmlinux-deps`，它的定义如下：

```
vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN)

```

它是由内核代码下的每个顶级目录的 `built-in.o` 组成的。之后我们还会检查内核所有的目录，`kbuild` 会编译各个目录下所有的对应 `$(obj-y)` 的源文件。接着调用 `$(LD) -r` 把这些文件合并到一个 `build-in.o` 文件里。此时我们还没有`vmlinux-deps`，所以目标 `vmlinux` 现在还不会被构建。对我而言 `vmlinux-deps` 包含下面的文件：

```
arch/x86/kernel/vmlinux.lds arch/x86/kernel/head_64.o
arch/x86/kernel/head64.o    arch/x86/kernel/head.o
init/built-in.o             usr/built-in.o
arch/x86/built-in.o         kernel/built-in.o
mm/built-in.o               fs/built-in.o
ipc/built-in.o              security/built-in.o
crypto/built-in.o           block/built-in.o
lib/lib.a                   arch/x86/lib/lib.a
lib/built-in.o              arch/x86/lib/built-in.o
drivers/built-in.o          sound/built-in.o
firmware/built-in.o         arch/x86/pci/built-in.o
arch/x86/power/built-in.o   arch/x86/video/built-in.o
net/built-in.o

```

下一个可以被执行的目标如下：

```
$(sort $(vmlinux-deps)): $(vmlinux-dirs) ;
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@

```

就像我们看到的，`vmlinux-dir` 依赖于两部分：`prepare` 和 `scripts`。第一个 `prepare` 定义在内核的根 `makefile` 中，准备工作分成三个阶段：

```
prepare: prepare0
prepare0: archprepare FORCE
    $(Q)$(MAKE) $(build)=.
archprepare: archheaders archscripts prepare1 scripts_basic

prepare1: prepare2 $(version_h) include/generated/utsrelease.h \
                   include/config/auto.conf
    $(cmd_crmodverdir)
prepare2: prepare3 outputmakefile asm-generic

```

第一个 `prepare0` 展开到 `archprepare` ，后者又展开到 `archheader` 和 `archscripts`，这两个变量定义在 `x86_64` 相关的 [Makefile](https://github.com/torvalds/linux/blob/master/arch/x86/Makefile)。让我们看看这个文件。`x86_64` 特定的 makefile 从变量定义开始，这些变量都是和特定架构的配置文件 ([defconfig](https://github.com/torvalds/linux/tree/master/arch/x86/configs)，等等)有关联。在定义了编译 [16-bit](https://en.wikipedia.org/wiki/Real_mode) 代码的编译选项之后，根据变量 `BITS` 的值，如果是 `32`， 汇编代码、链接器、以及其它很多东西（全部的定义都可以在[arch/x86/Makefile](https://github.com/torvalds/linux/blob/master/arch/x86/Makefile)找到）对应的参数就是 `i386`，而 `64` 就对应的是 `x86_84`。

第一个目标是 makefile 生成的系统调用列表（syscall table）中的 `archheaders` ：

```
archheaders:
    $(Q)$(MAKE) $(build)=arch/x86/entry/syscalls all

```

第二个目标是 makefile 里的 `archscripts`：

```
archscripts: scripts_basic
    $(Q)$(MAKE) $(build)=arch/x86/tools relocs

```

我们可以看到 `archscripts` 是依赖于根 [Makefile](https://github.com/torvalds/linux/blob/master/Makefile)里的`scripts_basic` 。首先我们可以看出 `scripts_basic` 是按照 [scripts/basic](https://github.com/torvalds/linux/blob/master/scripts/basic/Makefile) 的 makefile 执行 make 的：

```
scripts_basic:
    $(Q)$(MAKE) $(build)=scripts/basic

```

`scripts/basic/Makefile` 包含了编译两个主机程序 `fixdep` 和 `bin2` 的目标：

```
hostprogs-y := fixdep
hostprogs-$(CONFIG_BUILD_BIN2C)     += bin2c
always      := $(hostprogs-y)

$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep

```

第一个工具是 `fixdep`：用来优化 [gcc](https://gcc.gnu.org/) 生成的依赖列表，然后在重新编译源文件的时候告诉make。第二个工具是 `bin2c`，它依赖于内核配置选项 `CONFIG_BUILD_BIN2C`，并且它是一个用来将标准输入接口（LCTT 译注：即 stdin）收到的二进制流通过标准输出接口（即：stdout）转换成 C 头文件的非常小的 C 程序。你可能注意到这里有些奇怪的标志，如 `hostprogs-y` 等。这个标志用于所有的 `kbuild` 文件，更多的信息你可以从[documentation](https://github.com/torvalds/linux/blob/master/Documentation/kbuild/makefiles.txt) 获得。在我们这里， `hostprogs-y` 告诉 `kbuild` 这里有个名为 `fixed` 的程序，这个程序会通过和 `Makefile` 相同目录的 `fixdep.c` 编译而来。

执行 make 之后，终端的第一个输出就是 `kbuild` 的结果：

```
$ make
  HOSTCC  scripts/basic/fixdep

```

当目标 `script_basic` 被执行，目标 `archscripts` 就会 make [arch/x86/tools](https://github.com/torvalds/linux/blob/master/arch/x86/tools/Makefile) 下的 makefile 和目标 `relocs`:

```
$(Q)$(MAKE) $(build)=arch/x86/tools relocs

```

包含了[重定位](https://en.wikipedia.org/wiki/Relocation_%28computing%29) 的信息的代码 `relocs_32.c` 和 `relocs_64.c` 将会被编译，这可以在`make` 的输出中看到：

```
  HOSTCC  arch/x86/tools/relocs_32.o
  HOSTCC  arch/x86/tools/relocs_64.o
  HOSTCC  arch/x86/tools/relocs_common.o
  HOSTLD  arch/x86/tools/relocs

```

在编译完 `relocs.c` 之后会检查 `version.h`:

```
$(version_h): $(srctree)/Makefile FORCE
    $(call filechk,version.h)
    $(Q)rm -f $(old_version_h)

```

我们可以在输出看到它：

```
CHK     include/config/kernel.release

```

以及在内核的根 Makefiel 使用 `arch/x86/include/generated/asm` 的目标 `asm-generic` 来构建 `generic` 汇编头文件。在目标 `asm-generic` 之后，`archprepare` 就完成了，所以目标 `prepare0` 会接着被执行，如我上面所写：

```
prepare0: archprepare FORCE
    $(Q)$(MAKE) $(build)=.

```

注意 `build`，它是定义在文件 [scripts/Kbuild.include](https://github.com/torvalds/linux/blob/master/scripts/Kbuild.include)，内容是这样的：

```
build := -f $(srctree)/scripts/Makefile.build obj

```

或者在我们的例子中，它就是当前源码目录路径：`.`：

```
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.build obj=.

```

脚本 [scripts/Makefile.build](https://github.com/torvalds/linux/blob/master/scripts/Makefile.build) 通过参数 `obj` 给定的目录找到 `Kbuild` 文件，然后引入 `kbuild` 文件：

```
include $(kbuild-file)

```

并根据这个构建目标。我们这里 `.` 包含了生成 `kernel/bounds.s` 和 `arch/x86/kernel/asm-offsets.s` 的 [Kbuild](https://github.com/torvalds/linux/blob/master/Kbuild) 文件。在此之后，目标 `prepare` 就完成了它的工作。 `vmlinux-dirs` 也依赖于第二个目标 `scripts` ，它会编译接下来的几个程序：`filealias`，`mk_elfconfig`，`modpost` 等等。之后，`scripts/host-programs` 就可以开始编译我们的目标 `vmlinux-dirs` 了。

首先，我们先来理解一下 `vmlinux-dirs` 都包含了那些东西。在我们的例子中它包含了下列内核目录的路径：

```
init usr arch/x86 kernel mm fs ipc security crypto block
drivers sound firmware arch/x86/pci arch/x86/power
arch/x86/video net lib arch/x86/lib

```

我们可以在内核的根 [Makefile](https://github.com/torvalds/linux/blob/master/Makefile) 里找到 `vmlinux-dirs` 的定义：

```
vmlinux-dirs    := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
             $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
             $(net-y) $(net-m) $(libs-y) $(libs-m)))

init-y      := init/
drivers-y   := drivers/ sound/ firmware/
net-y       := net/
libs-y      := lib/
...
...
...

```

这里我们借助函数 `patsubst` 和 `filter`去掉了每个目录路径里的符号 `/`，并且把结果放到 `vmlinux-dirs` 里。所以我们就有了 `vmlinux-dirs` 里的目录列表，以及下面的代码：

```
$(vmlinux-dirs): prepare scripts
    $(Q)$(MAKE) $(build)=$@

```

符号 `$@` 在这里代表了 `vmlinux-dirs`，这就表明程序会递归遍历从 `vmlinux-dirs` 以及它内部的全部目录（依赖于配置），并且在对应的目录下执行 `make` 命令。我们可以在输出看到结果：

```
  CC      init/main.o
  CHK     include/generated/compile.h
  CC      init/version.o
  CC      init/do_mounts.o
  ...
  CC      arch/x86/crypto/glue_helper.o
  AS      arch/x86/crypto/aes-x86_64-asm_64.o
  CC      arch/x86/crypto/aes_glue.o
  ...
  AS      arch/x86/entry/entry_64.o
  AS      arch/x86/entry/thunk_64.o
  CC      arch/x86/entry/syscall_64.o

```

每个目录下的源代码将会被编译并且链接到 `built-io.o` 里：

```
$ find . -name built-in.o
./arch/x86/crypto/built-in.o
./arch/x86/crypto/sha-mb/built-in.o
./arch/x86/net/built-in.o
./init/built-in.o
./usr/built-in.o
...
...

```

好了，所有的 `built-in.o` 都构建完了，现在我们回到目标 `vmlinux` 上。你应该还记得，目标 `vmlinux` 是在内核的根makefile 里。在链接 `vmlinux` 之前，系统会构建 [samples](https://github.com/torvalds/linux/tree/master/samples), [Documentation](https://github.com/torvalds/linux/tree/master/Documentation) 等等，但是如上文所述，我不会在本文描述这些。

```
vmlinux: scripts/link-vmlinux.sh $(vmlinux-deps) FORCE
    ...
    ...
    +$(call if_changed,link-vmlinux)

```

你可以看到，调用脚本 [scripts/link-vmlinux.sh](https://github.com/torvalds/linux/blob/master/scripts/link-vmlinux.sh) 的主要目的是把所有的 `built-in.o` 链接成一个静态可执行文件，和生成 [System.map](https://en.wikipedia.org/wiki/System.map)。 最后我们来看看下面的输出：

```
  LINK    vmlinux
  LD      vmlinux.o
  MODPOST vmlinux.o
  GEN     .version
  CHK     include/generated/compile.h
  UPD     include/generated/compile.h
  CC      init/version.o
  LD      init/built-in.o
  KSYM    .tmp_kallsyms1.o
  KSYM    .tmp_kallsyms2.o
  LD      vmlinux
  SORTEX  vmlinux
  SYSMAP  System.map

```

`vmlinux` 和`System.map` 生成在内核源码树根目录下。

```
$ ls vmlinux System.map
System.map  vmlinux

```

这就是全部了，`vmlinux` 构建好了，下一步就是创建 [bzImage](https://en.wikipedia.org/wiki/Vmlinux#bzImage).

### 制作bzImage

`bzImage` 就是压缩了的 linux 内核镜像。我们可以在构建了 `vmlinux` 之后通过执行 `make bzImage` 获得`bzImage`。同时我们可以仅仅执行 `make` 而不带任何参数也可以生成 `bzImage` ，因为它是在 [arch/x86/kernel/Makefile](https://github.com/torvalds/linux/blob/master/arch/x86/Makefile) 里预定义的、默认生成的镜像：

```
all: bzImage

```

让我们看看这个目标，它能帮助我们理解这个镜像是怎么构建的。我已经说过了 `bzImage` 是被定义在 [arch/x86/kernel/Makefile](https://github.com/torvalds/linux/blob/master/arch/x86/Makefile)，定义如下：

```
bzImage: vmlinux
    $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
    $(Q)mkdir -p $(objtree)/arch/$(UTS_MACHINE)/boot
    $(Q)ln -fsn ../../x86/boot/bzImage $(objtree)/arch/$(UTS_MACHINE)/boot/$@

```

在这里我们可以看到第一次为 boot 目录执行 `make`，在我们的例子里是这样的：

```
boot := arch/x86/boot

```

现在的主要目标是编译目录 `arch/x86/boot` 和 `arch/x86/boot/compressed` 的代码，构建 `setup.bin` 和 `vmlinux.bin`，最后用这两个文件生成 `bzImage`。第一个目标是定义在 [arch/x86/boot/Makefile](https://github.com/torvalds/linux/blob/master/arch/x86/boot/Makefile) 的 `$(obj)/setup.elf`:

```
$(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
    $(call if_changed,ld)

```

我们已经在目录 `arch/x86/boot` 有了链接脚本 `setup.ld`，和扩展到 `boot` 目录下全部源代码的变量 `SETUP_OBJS` 。我们可以看看第一个输出：

```
  AS      arch/x86/boot/bioscall.o
  CC      arch/x86/boot/cmdline.o
  AS      arch/x86/boot/copy.o
  HOSTCC  arch/x86/boot/mkcpustr
  CPUSTR  arch/x86/boot/cpustr.h
  CC      arch/x86/boot/cpu.o
  CC      arch/x86/boot/cpuflags.o
  CC      arch/x86/boot/cpucheck.o
  CC      arch/x86/boot/early_serial_console.o
  CC      arch/x86/boot/edd.o

```

下一个源码文件是 [arch/x86/boot/header.S](https://github.com/torvalds/linux/blob/master/arch/x86/boot/header.S)，但是我们不能现在就编译它，因为这个目标依赖于下面两个头文件：

```
$(obj)/header.o: $(obj)/voffset.h $(obj)/zoffset.h

```

第一个头文件 `voffset.h` 是使用 `sed` 脚本生成的，包含用 `nm` 工具从 `vmlinux` 获取的两个地址：

```
#define VO__end 0xffffffff82ab0000
#define VO__text 0xffffffff81000000

```

这两个地址是内核的起始和结束地址。第二个头文件 `zoffset.h` 在 [arch/x86/boot/compressed/Makefile](https://github.com/torvalds/linux/blob/master/arch/x86/boot/compressed/Makefile) 可以看出是依赖于目标 `vmlinux`的：

```
$(obj)/zoffset.h: $(obj)/compressed/vmlinux FORCE
    $(call if_changed,zoffset)

```

目标 `$(obj)/compressed/vmlinux` 依赖于 `vmlinux-objs-y` —— 说明需要编译目录 [arch/x86/boot/compressed](https://github.com/torvalds/linux/tree/master/arch/x86/boot/compressed) 下的源代码，然后生成 `vmlinux.bin`、`vmlinux.bin.bz2`，和编译工具 `mkpiggy`。我们可以在下面的输出看出来：

```
  LDS     arch/x86/boot/compressed/vmlinux.lds
  AS      arch/x86/boot/compressed/head_64.o
  CC      arch/x86/boot/compressed/misc.o
  CC      arch/x86/boot/compressed/string.o
  CC      arch/x86/boot/compressed/cmdline.o
  OBJCOPY arch/x86/boot/compressed/vmlinux.bin
  BZIP2   arch/x86/boot/compressed/vmlinux.bin.bz2
  HOSTCC  arch/x86/boot/compressed/mkpiggy

```

`vmlinux.bin` 是去掉了调试信息和注释的 `vmlinux` 二进制文件，加上了占用了 `u32` （LCTT 译注：即4-Byte）的长度信息的 `vmlinux.bin.all` 压缩后就是 `vmlinux.bin.bz2`。其中 `vmlinux.bin.all` 包含了 `vmlinux.bin` 和`vmlinux.relocs`（LCTT 译注：vmlinux 的重定位信息），其中 `vmlinux.relocs` 是 `vmlinux` 经过程序 `relocs` 处理之后的 `vmlinux` 镜像（见上文所述）。我们现在已经获取到了这些文件，汇编文件 `piggy.S` 将会被 `mkpiggy` 生成、然后编译：

```
  MKPIGGY arch/x86/boot/compressed/piggy.S
  AS      arch/x86/boot/compressed/piggy.o

```

这个汇编文件会包含经过计算得来的、压缩内核的偏移信息。处理完这个汇编文件，我们就可以看到 `zoffset` 生成了：

```
  ZOFFSET arch/x86/boot/zoffset.h

```

现在 `zoffset.h` 和 `voffset.h` 已经生成了，[arch/x86/boot](https://github.com/torvalds/linux/tree/master/arch/x86/boot/) 里的源文件可以继续编译：

```
  AS      arch/x86/boot/header.o
  CC      arch/x86/boot/main.o
  CC      arch/x86/boot/mca.o
  CC      arch/x86/boot/memory.o
  CC      arch/x86/boot/pm.o
  AS      arch/x86/boot/pmjump.o
  CC      arch/x86/boot/printf.o
  CC      arch/x86/boot/regs.o
  CC      arch/x86/boot/string.o
  CC      arch/x86/boot/tty.o
  CC      arch/x86/boot/video.o
  CC      arch/x86/boot/video-mode.o
  CC      arch/x86/boot/video-vga.o
  CC      arch/x86/boot/video-vesa.o
  CC      arch/x86/boot/video-bios.o

```

所有的源代码会被编译，他们最终会被链接到 `setup.elf` ：

```
  LD      arch/x86/boot/setup.elf

```

或者：

```
ld -m elf_x86_64   -T arch/x86/boot/setup.ld arch/x86/boot/a20.o arch/x86/boot/bioscall.o arch/x86/boot/cmdline.o arch/x86/boot/copy.o arch/x86/boot/cpu.o arch/x86/boot/cpuflags.o arch/x86/boot/cpucheck.o arch/x86/boot/early_serial_console.o arch/x86/boot/edd.o arch/x86/boot/header.o arch/x86/boot/main.o arch/x86/boot/mca.o arch/x86/boot/memory.o arch/x86/boot/pm.o arch/x86/boot/pmjump.o arch/x86/boot/printf.o arch/x86/boot/regs.o arch/x86/boot/string.o arch/x86/boot/tty.o arch/x86/boot/video.o arch/x86/boot/video-mode.o arch/x86/boot/version.o arch/x86/boot/video-vga.o arch/x86/boot/video-vesa.o arch/x86/boot/video-bios.o -o arch/x86/boot/setup.elf

```

最后的两件事是创建包含目录 `arch/x86/boot/*` 下的编译过的代码的 `setup.bin`：

```
objcopy  -O binary arch/x86/boot/setup.elf arch/x86/boot/setup.bin

```

以及从 `vmlinux` 生成 `vmlinux.bin` :

```
objcopy  -O binary -R .note -R .comment -S arch/x86/boot/compressed/vmlinux arch/x86/boot/vmlinux.bin

```

最最后，我们编译主机程序 [arch/x86/boot/tools/build.c](https://github.com/torvalds/linux/blob/master/arch/x86/boot/tools/build.c)，它将会用来把 `setup.bin` 和 `vmlinux.bin` 打包成 `bzImage`:

```
arch/x86/boot/tools/build arch/x86/boot/setup.bin arch/x86/boot/vmlinux.bin arch/x86/boot/zoffset.h arch/x86/boot/bzImage

```

实际上 `bzImage` 就是把 `setup.bin` 和 `vmlinux.bin` 连接到一起。最终我们会看到输出结果，就和那些用源码编译过内核的同行的结果一样：

```
Setup is 16268 bytes (padded to 16384 bytes).
System is 4704 kB
CRC 94a88f9a
Kernel: arch/x86/boot/bzImage is ready  (#5)

```

全部结束。

### 结论

这就是本文的结尾部分。本文我们了解了编译内核的全部步骤：从执行 `make` 命令开始，到最后生成 `bzImage`。我知道，linux 内核的 makefile 和构建 linux 的过程第一眼看起来可能比较迷惑，但是这并不是很难。希望本文可以帮助你理解构建 linux 内核的整个流程。

### 链接

* [GNU make util](https://en.wikipedia.org/wiki/Make_%28software%29)
* [Linux kernel top Makefile](https://github.com/torvalds/linux/blob/master/Makefile)
* [cross-compilation](https://en.wikipedia.org/wiki/Cross_compiler)
* [Ctags](https://en.wikipedia.org/wiki/Ctags)
* [sparse](https://en.wikipedia.org/wiki/Sparse)
* [bzImage](https://en.wikipedia.org/wiki/Vmlinux#bzImage)
* [uname](https://en.wikipedia.org/wiki/Uname)
* [shell](https://en.wikipedia.org/wiki/Shell_%28computing%29)
* [Kbuild](https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kbuild.txt)
* [binutils](http://www.gnu.org/software/binutils/)
* [gcc](https://gcc.gnu.org/)
* [Documentation](https://github.com/torvalds/linux/blob/master/Documentation/kbuild/makefiles.txt)
* [System.map](https://en.wikipedia.org/wiki/System.map)
* [Relocation](https://en.wikipedia.org/wiki/Relocation_%28computing%29)

---

via: <https://github.com/0xAX/linux-insides/blob/master/Misc/how_kernel_compiled.md>

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

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


Shilpa Nair 分享的 RedHat Linux 包管理方面的面试经验

Summary: Shilpa Nair 刚于2015年毕业。她之后去了一家位于 Noida，Delhi 的国家新闻电视台，应聘实习生的岗位。在她去年毕业季的时候，常逛 Tecmint 寻求作业上的帮助。从那时开始，她就常去 Tecmint。  有关 RPM 方面的 Linux 面试题 所有的问题和回答都是 Shilpa Nair 根据回忆重写的。  大家好！我是来自 Delhi 的Shilpa Nair。我不久前才顺利毕业，正寻找一个实习的机会。在大学早期的时候，我就对 UNIX 十分喜爱，所以我也希望这个机会能适合我，满足我的兴趣。我被提问了很多问题，大部分都是关于 RedHat 包管理的基础问题。  下面就是我被

**Shilpa Nair 刚于2015年毕业。她之后去了一家位于 Noida，Delhi 的国家新闻电视台，应聘实习生的岗位。在她去年毕业季的时候，常逛 Tecmint 寻求作业上的帮助。从那时开始，她就常去 Tecmint。**

![Linux Interview Questions on RPM](/data/attachment/album/201509/13/201307tx8vpzv28w0ca6z2.jpg)

*有关 RPM 方面的 Linux 面试题*

所有的问题和回答都是 Shilpa Nair 根据回忆重写的。

>
> “大家好！我是来自 Delhi 的Shilpa Nair。我不久前才顺利毕业，正寻找一个实习的机会。在大学早期的时候，我就对 UNIX 十分喜爱，所以我也希望这个机会能适合我，满足我的兴趣。我被提问了很多问题，大部分都是关于 RedHat 包管理的基础问题。”
>
>
>

下面就是我被问到的问题，和对应的回答。我仅贴出了与 RedHat GNU/Linux 包管理相关的，也是主要被提问的。

### 1，Linux 里如何查找一个包安装与否？假设你需要确认 ‘nano’ 有没有安装，你怎么做？

**回答**：为了确认 nano 软件包有没有安装，我们可以使用 rpm 命令，配合 -q 和 -a 选项来查询所有已安装的包

```
# rpm -qa nano
或
# rpm -qa | grep -i nano

nano-2.3.1-10.el7.x86_64

```

同时包的名字必须是完整的，不完整的包名会返回到提示符，不打印任何东西，就是说这包（包名字不全）未安装。下面的例子会更好理解些：

我们通常使用 vim 替代 vi 命令。当时如果我们查找安装包 vi/vim 的时候，我们就会看到标准输出上没有任何结果。

```
# vi
# vim

```

尽管如此，我们仍然可以像上面一样运行 vi/vim 命令来清楚地知道包有没有安装。只是因为我们不知道它的完整包名才不能找到的。如果我们不确切知道完整的文件名，我们可以使用通配符：

```
# rpm -qa vim*

vim-minimal-7.4.160-1.el7.x86_64

```

通过这种方式，我们可以获得任何软件包的信息，安装与否。

### 2. 你如何使用 rpm 命令安装 XYZ 软件包？

**回答**：我们可以使用 rpm 命令安装任何的软件包（\*.rpm），像下面这样，选项 -i（安装），-v（冗余或者显示额外的信息）和 -h（在安装过程中，打印#号显示进度）。

```
# rpm -ivh peazip-1.11-1.el6.rf.x86_64.rpm

Preparing...                          ################################# [100%]
Updating / installing...
   1:peazip-1.11-1.el6.rf             ################################# [100%]

```

如果要升级一个早期版本的包，应加上 -U 选项，选项 -v 和 -h 可以确保我们得到用 # 号表示的冗余输出，这增加了可读性。

### 3. 你已经安装了一个软件包（假设是 httpd），现在你想看看软件包创建并安装的所有文件和目录，你会怎么做？

**回答**：使用选项 -l（列出所有文件）和 -q（查询）列出 httpd 软件包安装的所有文件（Linux 哲学：所有的都是文件，包括目录）。

```
# rpm -ql httpd

/etc/httpd
/etc/httpd/conf
/etc/httpd/conf.d
...

```

### 4. 假如你要移除一个软件包，叫 postfix。你会怎么做？

**回答**：首先我们需要知道什么包安装了 postfix。查找安装 postfix 的包名后，使用 -e（擦除/卸载软件包）和 -v（冗余输出）两个选项来实现。

```
# rpm -qa postfix*

postfix-2.10.1-6.el7.x86_64

```

然后移除 postfix，如下:

```
# rpm -ev postfix-2.10.1-6.el7.x86_64

Preparing packages...
postfix-2:3.0.1-2.fc22.x86_64

```

### 5. 获得一个已安装包的具体信息，如版本，发行号，安装日期，大小，总结和一个简短的描述。

**回答**：我们通过使用 rpm 的选项 -qi，后面接包名，可以获得关于一个已安装包的具体信息。

举个例子，为了获得 openssh 包的具体信息，我需要做的就是：

```
# rpm -qi openssh

[root@tecmint tecmint]# rpm -qi openssh
Name        : openssh
Version     : 6.8p1
Release     : 5.fc22
Architecture: x86_64
Install Date: Thursday 28 May 2015 12:34:50 PM IST
Group       : Applications/Internet
Size        : 1542057
License     : BSD
....

```

### 6. 假如你不确定一个指定包的配置文件在哪，比如 httpd。你如何找到所有 httpd 提供的配置文件列表和位置。

**回答**： 我们需要用选项 -c 接包名，这会列出所有配置文件的名字和他们的位置。

```
# rpm -qc httpd

/etc/httpd/conf.d/autoindex.conf
/etc/httpd/conf.d/userdir.conf
/etc/httpd/conf.d/welcome.conf
/etc/httpd/conf.modules.d/00-base.conf
/etc/httpd/conf/httpd.conf
/etc/sysconfig/httpd

```

相似地，我们可以列出所有相关的文档文件，如下：

```
# rpm -qd httpd

/usr/share/doc/httpd/ABOUT_APACHE
/usr/share/doc/httpd/CHANGES
/usr/share/doc/httpd/LICENSE
...

```

我们也可以列出所有相关的证书文件，如下：

```
# rpm -qL openssh

/usr/share/licenses/openssh/LICENCE

```

忘了说明上面的选项 -d 和 -L 分别表示 “文档” 和 “证书”，抱歉。

### 7. 你找到了一个配置文件，位于‘/usr/share/alsa/cards/AACI.conf’，现在你不确定该文件属于哪个包。你如何查找出包的名字？

**回答**：当一个包被安装后，相关的信息就存储在了数据库里。所以使用选项 -qf（-f 查询包拥有的文件）很容易追踪谁提供了上述的包。

```
# rpm -qf /usr/share/alsa/cards/AACI.conf
alsa-lib-1.0.28-2.el7.x86_64

```

类似地，我们可以查找（谁提供的）关于任何子包，文档和证书文件的信息。

### 8. 你如何使用 rpm 查找最近安装的软件列表？

**回答**：如刚刚说的，每一样被安装的文件都记录在了数据库里。所以这并不难，通过查询 rpm 的数据库，找到最近安装软件的列表。

我们通过运行下面的命令，使用选项 -last（打印出最近安装的软件）达到目的。

```
# rpm -qa --last

```

上面的命令会打印出所有安装的软件，最近安装的软件在列表的顶部。

如果我们关心的是找出特定的包，我们可以使用 grep 命令从列表中匹配包（假设是 sqlite ），简单如下：

```
# rpm -qa --last | grep -i sqlite

sqlite-3.8.10.2-1.fc22.x86_64                 Thursday 18 June 2015 05:05:43 PM IST

```

我们也可以获得10个最近安装的软件列表，简单如下：

```
# rpm -qa --last | head

```

我们可以重定义一下，输出想要的结果，简单如下：

```
# rpm -qa --last | head -n 2

```

上面的命令中，-n 代表数目，后面接一个常数值。该命令是打印2个最近安装的软件的列表。

### 9. 安装一个包之前，你如果要检查其依赖。你会怎么做？

**回答**：检查一个 rpm 包（XYZ.rpm）的依赖，我们可以使用选项 -q（查询包），-p（指定包名）和 -R（查询/列出该包依赖的包，嗯，就是依赖）。

```
# rpm -qpR gedit-3.16.1-1.fc22.i686.rpm

/bin/sh
/usr/bin/env
glib2(x86-32) >= 2.40.0
gsettings-desktop-schemas
gtk3(x86-32) >= 3.16
gtksourceview3(x86-32) >= 3.16
gvfs
libX11.so.6
...

```

### 10. rpm 是不是一个前端的包管理工具呢？

**回答**：**不是！**rpm 是一个后端管理工具，适用于基于 Linux 发行版的 RPM （此处指 Redhat Package Management）。

[YUM](http://www.tecmint.com/20-linux-yum-yellowdog-updater-modified-commands-for-package-mangement/)，全称 Yellowdog Updater Modified，是一个 RPM 的前端工具。YUM 命令自动完成所有工作，包括解决依赖和其他一切事务。

最近，[DNF](/article-5718-1.html)（YUM命令升级版）在Fedora 22发行版中取代了 YUM。尽管 YUM 仍然可以在 RHEL 和 CentOS 平台使用，我们也可以安装 dnf，与 YUM 命令共存使用。据说 DNF 较于 YUM 有很多提高。

知道更多总是好的，保持自我更新。现在我们移步到前端部分来谈谈。

### 11. 你如何列出一个系统上面所有可用的仓库列表。

**回答**：简单地使用下面的命令，我们就可以列出一个系统上所有可用的仓库列表。

```
# yum repolist
或
# dnf repolist

Last metadata expiration check performed 0:30:03 ago on Mon Jun 22 16:50:00 2015.
repo id       repo name                      status
*fedora       Fedora 22 - x86_64             44,762
ozonos        Repository for Ozon OS         61
*updates      Fedora 22 - x86_64 - Updates

```

上面的命令仅会列出可用的仓库。如果你需要列出所有的仓库，不管可用与否，可以这样做。

```
# yum repolist all
或
# dnf repolist all

Last metadata expiration check performed 0:29:45 ago on Mon Jun 22 16:50:00 2015.
repo id           repo name                       status
*fedora           Fedora 22 - x86_64              enabled: 44,762
fedora-debuginfo  Fedora 22 - x86_64 - Debug      disabled
fedora-source     Fedora 22 - Source              disabled
ozonos            Repository for Ozon OS          enabled:     61
*updates          Fedora 22 - x86_64 - Updates    enabled:  5,018
updates-debuginfo Fedora 22 - x86_64 - Updates - Debug

```

### 12. 你如何列出一个系统上所有可用并且安装了的包？

**回答**：列出一个系统上所有可用的包，我们可以这样做：

```
# yum list available
或
# dnf list available

ast metadata expiration check performed 0:34:09 ago on Mon Jun 22 16:50:00 2015.
Available Packages
0ad.x86_64                 0.0.18-1.fc22                   fedora
0ad-data.noarch            0.0.18-1.fc22                   fedora
0install.x86_64            2.6.1-2.fc21                    fedora
0xFFFF.x86_64              0.3.9-11.fc22                   fedora
2048-cli.x86_64            0.9-4.git20141214.723738c.fc22  fedora
2048-cli-nocurses.x86_64   0.9-4.git20141214.723738c.fc22  fedora
....

```

而列出一个系统上所有已安装的包，我们可以这样做。

```
# yum list installed
或
# dnf list installed

Last metadata expiration check performed 0:34:30 ago on Mon Jun 22 16:50:00 2015.
Installed Packages
GeoIP.x86_64                    1.6.5-1.fc22       @System
GeoIP-GeoLite-data.noarch       2015.05-1.fc22     @System
NetworkManager.x86_64           1:1.0.2-1.fc22     @System
NetworkManager-libnm.x86_64     1:1.0.2-1.fc22     @System
aajohan-comfortaa-fonts.noarch  2.004-4.fc22       @System
....

```

而要同时满足两个要求的时候，我们可以这样做。

```
# yum list
或
# dnf list

Last metadata expiration check performed 0:32:56 ago on Mon Jun 22 16:50:00 2015.
Installed Packages
GeoIP.x86_64                    1.6.5-1.fc22       @System
GeoIP-GeoLite-data.noarch       2015.05-1.fc22     @System
NetworkManager.x86_64           1:1.0.2-1.fc22     @System
NetworkManager-libnm.x86_64     1:1.0.2-1.fc22     @System
aajohan-comfortaa-fonts.noarch  2.004-4.fc22       @System
acl.x86_64                      2.2.52-7.fc22      @System
....

```

### 13. 你会怎么在一个系统上面使用 YUM 或 DNF 分别安装和升级一个包与一组包？

**回答**：安装一个包（假设是 nano），我们可以这样做，

```
  # yum install nano

```

而安装一组包（假设是 Haskell），我们可以这样做，

```
  # yum groupinstall 'haskell'

```

升级一个包（还是 nano），我们可以这样做，

```
  # yum update nano

```

而为了升级一组包（还是 haskell），我们可以这样做，

```
# yum groupupdate 'haskell'
```

### 14. 你会如何同步一个系统上面的所有安装软件到稳定发行版？

**回答**：我们可以一个系统上（假设是 CentOS 或者 Fedora）的所有包到稳定发行版，如下，

```
 # yum distro-sync      [在 CentOS/ RHEL]
 或
 # dnf distro-sync      [在 Fedora 20之后版本]

```

似乎来面试之前你做了相当不多的功课，很好！在进一步交谈前，我还想问一两个问题。

### 15. 你对 YUM 本地仓库熟悉吗？你尝试过建立一个本地 YUM 仓库吗？让我们简单看看你会怎么建立一个本地 YUM 仓库。

**回答**：首先，感谢你的夸奖。回到问题，我必须承认我对本地 YUM 仓库十分熟悉，并且在我的本地主机上也部署过，作为测试用。

1、 为了建立本地 YUM 仓库，我们需要安装下面三个包：

```
# yum install deltarpm  python-deltarpm  createrepo

```

2、 新建一个目录(假设 /home/$USER/rpm)，然后复制 RedHat/CentOS DVD 上的 RPM 包到这个文件夹下

```
# mkdir /home/$USER/rpm
# cp /path/to/rpm/on/DVD/*.rpm /home/$USER/rpm

```

3、 新建基本的库头文件如下。

```
# createrepo -v /home/$USER/rpm

```

4、 在路径 /etc/yum.repo.d 下创建一个 .repo 文件（如 abc.repo):

```
cd /etc/yum.repos.d && cat << EOF abc.repo
[local-installation]name=yum-local
baseurl=file:///home/$USER/rpm
enabled=1
gpgcheck=0
EOF

```

**重要**：用你的用户名替换掉 $USER。

以上就是创建一个本地 YUM 仓库所要做的全部工作。我们现在可以从这里安装软件了，相对快一些，安全一些，并且最重要的是不需要 Internet 连接。

好了！面试过程很愉快。我已经问完了。我会将你推荐给 HR。你是一个年轻且十分聪明的候选者，我们很愿意你加入进来。如果你有任何问题，你可以问我。

**我**：谢谢，这确实是一次愉快的面试，我感到今天非常幸运，可以搞定这次面试...

显然，不会在这里结束。我问了很多问题，比如他们正在做的项目。我会担任什么角色，负责什么，，，balabalabala

小伙伴们，这之后的 3 天会经过 HR 轮，到时候所有问题到时候也会被写成文档。希望我当时表现不错。感谢你们所有的祝福。

谢谢伙伴们和 Tecmint，花时间来编辑我的面试经历。我相信 Tecmint 好伙伴们做了很大的努力，必要要赞一个。当我们与他人分享我们的经历的时候，其他人从我们这里知道了更多，而我们自己则发现了自己的不足。

这增加了我们的信心。如果你最近也有任何类似的面试经历，别自己蔵着。分享出来！让我们所有人都知道。你可以使用如下的表单来与我们分享你的经历。

---

via: <http://www.tecmint.com/linux-rpm-package-management-interview-questions/>

作者：[Avishek Kumar](http://www.tecmint.com/author/avishek/) 译者：[wi-cuckoo](https://github.com/wi-cuckoo) 校对：[wxy](https://github.com/wxy)

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


Xtreme 下载管理器升级带来全新用户界面

Summary: Xtreme 下载管理器, 毫无疑问是Linux界最好的下载管理器之一 , 它的新版本名叫 XDM 2015 ，这次的新版本给我们带来了全新的外观体验！ Xtreme 下载管理器，也被称作 XDM 或 XDMAN，它是一个跨平台的下载管理器，可以用于 Linux、Windows 和 Mac OS X 系统之上。同时它兼容于主流的浏览器，如 Chrome, Firefox, Safari 等，因此当你从浏览器下载东西的时候可以直接使用 XDM 下载。 当你的网络连接超慢并且需要管理下载文件的时候，像 XDM 这种软件可以帮到你大忙。例如说你在一个慢的要死的网络速度下下载一个超大文件，或者你想要暂停和恢

依赖java，看到这一句我就醉了，感觉桌面软件依赖java的，注定很慢

越改越丑

昨天装了，今天就删掉了……

今天我想用这玩意下载ed2k连接的，结果等了半天没有任何进度，看了一下详情发现这下载器蠢萌蠢萌的，直接把ed2k前缀前面再加一个http前缀就开始试图下载了……

最后滚回百度云……

顺便，ed2k的内容是VC6安装盘，试图用以证明VC6是世界上最好的编译器，用起来崩溃出错的人都是因为没有配套用Win98，国内VC6可以用半个世纪！

然而事实上快的一笔

![](/data/attachment/album/201509/13/203022chn72mjk7tren6b7.jpg)

[Xtreme 下载管理器](http://xdman.sourceforge.net/), 毫无疑问是[Linux界最好的下载管理器](http://itsfoss.com/4-best-download-managers-for-linux/)之一 , 它的新版本名叫 XDM 2015 ，这次的新版本给我们带来了全新的外观体验！

Xtreme 下载管理器，也被称作 XDM 或 XDMAN，它是一个跨平台的下载管理器，可以用于 Linux、Windows 和 Mac OS X 系统之上。同时它兼容于主流的浏览器，如 Chrome, Firefox, Safari 等，因此当你从浏览器下载东西的时候可以直接使用 XDM 下载。

当你的网络连接超慢并且需要管理下载文件的时候，像 XDM 这种软件可以帮到你大忙。例如说你在一个慢的要死的网络速度下下载一个超大文件，或者你想要暂停和恢复下载的话， XDM 可以帮助你。

XDM 的主要功能：

* 暂停和恢复下载
* [从 YouTube 下载视频](http://itsfoss.com/download-youtube-videos-ubuntu/)，其他视频网站同样适用
* 强制聚合
* 下载加速
* 计划下载
* 下载限速
* 与浏览器整合
* 支持代理服务器

下面你可以看到 XDM 新旧版本之间的差别。

![Old XDM](/data/attachment/album/201509/13/203023mpzwon433npodfqg.jpg)

*老版本XDM*

![New XDM](/data/attachment/album/201509/13/203023oevcg1qzp30vcvcq.png)

*新版本XDM*

### 在基于 Ubuntu 的 Linux 发行版上安装 Xtreme下载管理器

感谢 Noobslab 提供的 PPA，你可以使用以下命令来安装 Xtreme 下载管理器。虽然 XDM 依赖 Java，但是托 PPA 的福，你不需要对其进行单独的安装。

```
sudo add-apt-repository ppa:noobslab/apps
sudo apt-get update
sudo apt-get install xdman

```

以上的 PPA 可以在 Ubuntu 或者其他基于 Ubuntu 的发行版上使用，如 Linux Mint, elementary OS, Linux Lite 等。

#### 删除 XDM

如果你是使用 PPA 安装的 XDM ，可以通过以下命令将其删除：

```
sudo apt-get remove xdman
sudo add-apt-repository --remove ppa:noobslab/apps

```

对于其他Linux发行版，可以通过以下连接下载：

* [下载 Xtreme 下载管理器](http://xdman.sourceforge.net/download.html)

---

via: <http://itsfoss.com/xtreme-download-manager-install/>

作者：[Abhishek](http://itsfoss.com/author/abhishek/) 译者：[mr-ping](https://github.com/mr-ping) 校对：[wxy](https://github.com/wxy)

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


在 Linux 中怎样将 MySQL 迁移到 MariaDB 上

Summary: 自从甲骨文收购 MySQL 后，由于甲骨文对 MySQL 的开发和维护更多倾向于闭门的立场，很多 MySQL 的开发者和用户放弃了 MySQL。在社区驱动下，促使更多人移到 MySQL 的另一个叫 MariaDB 的分支。在原有 MySQL 开发人员的带领下，MariaDB 的开发遵循开源的理念，并确保它的二进制格式与 MySQL 兼容。Linux 发行版如 Red Hat 家族（Fedora，CentOS，RHEL），Ubuntu 和 Mint，openSUSE 和 Debian 已经开始使用，并支持 MariaDB 作为 MySQL 的直接替换品。  如果你想要将 MySQL 中的数据库迁移到 MariaDB 中，这篇文章就是你所期待的。幸运的是

如果是海量数据迁移呢？ 这个方式不太方便啊。

用MyDumper并行导出、恢复

这文章本来就没有存在的价值，mysql mariadb本质都是一样的东西，只是叫的名字不一样

这情况，以后应该是mariaDB成主流，mysql成分支了

非常佩服MariaDB的开发者

迁移到mariadb后，中文全是？改了各种地方还是问号

那是你的字符集在转换过程中没处理好。

自从甲骨文收购 MySQL 后，由于甲骨文对 MySQL 的开发和维护更多倾向于闭门的立场，很多 MySQL 的开发者和用户放弃了 MySQL。在社区驱动下，促使更多人移到 MySQL 的另一个叫 MariaDB 的分支。在原有 MySQL 开发人员的带领下，MariaDB 的开发遵循开源的理念，并确保[它的二进制格式与 MySQL 兼容](https://mariadb.com/kb/en/mariadb/mariadb-vs-mysql-compatibility/)。Linux 发行版如 Red Hat 家族（Fedora，CentOS，RHEL），Ubuntu 和 Mint，openSUSE 和 Debian 已经开始使用，并支持 MariaDB 作为 MySQL 的直接替换品。

![](/data/attachment/album/201509/13/212003cfteafjxezxxfefs.jpg)

如果你想要将 MySQL 中的数据库迁移到 MariaDB 中，这篇文章就是你所期待的。幸运的是，由于他们的二进制兼容性，MySQL-to-MariaDB 迁移过程是非常简单的。如果你按照下面的步骤，将 MySQL 迁移到 MariaDB 会是无痛的。

### 准备 MySQL 数据库和表

出于演示的目的，我们在做迁移之前在数据库中创建一个测试的 MySQL 数据库和表。如果你在 MySQL 中已经有了要迁移到 MariaDB 的数据库，跳过此步骤。否则，按以下步骤操作。

在终端输入 root 密码登录到 MySQL 。

```
$ mysql -u root -p

```

创建一个数据库和表。

```
mysql> create database test01;
mysql> use test01;
mysql> create table pet(name varchar(30), owner varchar(30), species varchar(20), sex char(1));

```

在表中添加一些数据。

```
mysql> insert into pet values('brandon','Jack','puddle','m'),('dixie','Danny','chihuahua','f');

```

退出 MySQL 数据库.

### 备份 MySQL 数据库

下一步是备份现有的 MySQL 数据库。使用下面的 mysqldump 命令导出现有的数据库到文件中。运行此命令之前，请确保你的 MySQL 服务器上启用了二进制日志。如果你不知道如何启用二进制日志，请参阅结尾的教程说明。

```
$ mysqldump --all-databases --user=root --password --master-data > backupdb.sql

```

![](/data/attachment/album/201509/13/212006qh7hw8bnfkhnuhng.jpg)

现在，在卸载 MySQL 之前先在系统上备份 my.cnf 文件。此步是可选的。

```
$ sudo cp /etc/mysql/my.cnf /opt/my.cnf.bak

```

### 卸载 MySQL

首先，停止 MySQL 服务。

```
$ sudo service mysql stop

```

或者:

```
$ sudo systemctl stop mysql

```

或:

```
$ sudo /etc/init.d/mysql stop

```

然后继续下一步，使用以下命令移除 MySQL 和配置文件。

在基于 RPM 的系统上 (例如, CentOS, Fedora 或 RHEL):

```
$ sudo yum remove mysql* mysql-server mysql-devel mysql-libs
$ sudo rm -rf /var/lib/mysql

```

在基于 Debian 的系统上(例如, Debian, Ubuntu 或 Mint):

```
$ sudo apt-get remove mysql-server mysql-client mysql-common
$ sudo apt-get autoremove
$ sudo apt-get autoclean
$ sudo deluser mysql
$ sudo rm -rf /var/lib/mysql

```

### 安装 MariaDB

在 CentOS/RHEL 7和Ubuntu（14.04或更高版本）上，最新的 MariaDB 已经包含在其官方源。在 Fedora 上，自19 版本后 MariaDB 已经替代了 MySQL。如果你使用的是旧版本或 LTS 类型如 Ubuntu 13.10 或更早的，你仍然可以通过添加其官方仓库来安装 MariaDB。

[MariaDB 网站](https://downloads.mariadb.org/mariadb/repositories/#mirror=aasaam) 提供了一个在线工具帮助你依据你的 Linux 发行版中来添加 MariaDB 的官方仓库。此工具为 openSUSE, Arch Linux, Mageia, Fedora, CentOS, RedHat, Mint, Ubuntu, 和 Debian 提供了 MariaDB 的官方仓库.

![](/data/attachment/album/201509/13/212009l3liivqs1in0i77i.jpg)

下面例子中，我们使用 Ubuntu 14.04 发行版和 CentOS 7 配置 MariaDB 库。

**Ubuntu 14.04**

```
$ sudo apt-get install software-properties-common
$ sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xcbcb082a1bb943db
$ sudo add-apt-repository 'deb http://mirror.mephi.ru/mariadb/repo/5.5/ubuntu trusty main'
$ sudo apt-get update
$ sudo apt-get install mariadb-server

```

**CentOS 7**

以下为 MariaDB 创建一个自定义的 yum 仓库文件。

```
$ sudo vi /etc/yum.repos.d/MariaDB.repo

```

---

```
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/5.5/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

```

---

```
$ sudo yum install MariaDB-server MariaDB-client

```

安装了所有必要的软件包后，你可能会被要求为 MariaDB 的 root 用户创建一个新密码。设置 root 的密码后，别忘了恢复备份的 my.cnf 文件。

```
$ sudo cp /opt/my.cnf /etc/mysql/

```

现在启动 MariaDB 服务。

```
$ sudo service mariadb start

```

或:

```
$ sudo systemctl start mariadb

```

或:

```
$ sudo /etc/init.d/mariadb start

```

### 导入 MySQL 的数据库

最后，我们将以前导出的数据库导入到 MariaDB 服务器中。

```
$ mysql -u root -p < backupdb.sql

```

输入你 MariaDB 的 root 密码，数据库导入过程将开始。导入过程完成后，将返回到命令提示符下。

要检查导入过程是否完全成功，请登录到 MariaDB 服务器，并查看一些样本来检查。

```
$ mysql -u root -p

```

---

```
MariaDB [(none)]> show databases;
MariaDB [(none)]> use test01;
MariaDB [test01]> select * from pet;

```

![](/data/attachment/album/201509/13/212018xcndeiyhn077fidr.jpg)

### 结论

如你在本教程中看到的，MySQL-to-MariaDB 的迁移并不难。你应该知道，MariaDB 相比 MySQL 有很多新的功能。至于配置方面，在我的测试情况下，我只是将我旧的 MySQL 配置文件（my.cnf）作为 MariaDB 的配置文件，导入过程完全没有出现任何问题。对于配置文件，我建议你在迁移之前请仔细阅读 MariaDB 配置选项的文件，特别是如果你正在使用 MySQL 的特定配置。

如果你正在运行有海量的表、包括群集或主从复制的数据库的复杂配置，看一看 Mozilla IT 和 Operations 团队的 [更详细的指南](https://blog.mozilla.org/it/2013/12/16/upgrading-from-mysql-5-1-to-mariadb-5-5/) ，或者 [官方的 MariaDB 文档](https://mariadb.com/kb/en/mariadb/documentation/)。

### 故障排除

1、 在运行 mysqldump 命令备份数据库时出现以下错误。

```
$ mysqldump --all-databases --user=root --password --master-data > backupdb.sql

```

---

```
mysqldump: Error: Binlogging on server not active

```

通过使用 "--master-data"，你可以在导出的输出中包含二进制日志信息，这对于数据库的复制和恢复是有用的。但是，二进制日志未在 MySQL 服务器启用。要解决这个错误，修改 my.cnf 文件，并在 [mysqld] 部分添加下面的选项。（LCTT 译注：事实上，如果你并没有启用二进制日志，那取消"--master-data"即可。）

```
log-bin=mysql-bin

```

保存 my.cnf 文件，并重新启动 MySQL 服务：

```
$ sudo service mysql restart

```

或者:

```
$ sudo systemctl restart mysql

```

或:

```
$ sudo /etc/init.d/mysql restart

```

---

via: <http://xmodulo.com/migrate-mysql-to-mariadb-linux.html>

作者：[Kristophorus Hadiono](http://xmodulo.com/author/kristophorus) 译者：[strugglingyouth](https://github.com/strugglingyouth) 校对：[wxy](https://github.com/wxy)

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


守卫自由的 Linux 世界

Summary: 合作是开源的一部分。OIN 的 CEO Keith Bergelt 解释说，开放创新网络（Open Invention Network）模式允许众多企业和公司决定它们该在哪较量，在哪合作。随着开源的演变，我们需要为合作创造渠道，否则我们将会有几百个团体把数十亿美元花费到同样的技术上。 开放创新网络（Open Invention Network），即 OIN，正在全球范围内开展让 Linux 远离专利诉讼的伤害的活动。它的努力得到了一千多个公司的热烈回应，它们的加入让这股力量成为了历史上最大的反专利管理组织。 开放创新网络以白帽子组织的身份创建于2005年，目的是保护 Linux 免受

很看好Linux的情怀。

![](/data/attachment/album/201509/13/224536dw7ot7jjt4ldic7h.jpg)

**合作是开源的一部分。OIN 的 CEO Keith Bergelt 解释说，开放创新网络（Open Invention Network）模式允许众多企业和公司决定它们该在哪较量，在哪合作。随着开源的演变，“我们需要为合作创造渠道，否则我们将会有几百个团体把数十亿美元花费到同样的技术上。”**

[开放创新网络（Open Invention Network）](http://www.openinventionnetwork.com/)，即 OIN，正在全球范围内开展让 Linux 远离专利诉讼的伤害的活动。它的努力得到了一千多个公司的热烈回应，它们的加入让这股力量成为了历史上最大的反专利管理组织。

开放创新网络以白帽子组织的身份创建于2005年，目的是保护 Linux 免受来自许可证方面的困扰。包括 Google、 IBM、 NEC、 Novell、 Philips、 [Red Hat](http://www.redhat.com/) 和 Sony 这些成员的董事会给予了它可观的经济支持。世界范围内的多个组织通过签署自由 OIN 协议加入了这个社区。

创立开放创新网络的组织成员把它当作利用知识产权保护 Linux 的大胆尝试。它的商业模式非常的难以理解。它要求它的成员采用免版权许可证，并永远放弃由于 Linux 相关知识产权起诉其他成员的机会。

然而，从 Linux 收购风波——想想服务器和云平台——那时起，保护 Linux 知识产权的策略就变得越加的迫切。

在过去的几年里，Linux 的版图曾经历了一场变革。OIN 不必再向人们解释这个组织的定义，也不必再解释为什么 Linux 需要保护。据 OIN 的 CEO Keith Bergelt 说，现在 Linux 的重要性得到了全世界的关注。

“我们已经见到了一场人们了解到 OIN 如何让合作受益的文化变革，”他对 LinuxInsider 说。

### 如何运作

开放创新网络使用专利权的方式创建了一个协作环境。这种方法有助于确保创新的延续。这已经使很多软件厂商、顾客、新型市场和投资者受益。

开放创新网络的专利证可以让任何公司、公共机构或个人免版权使用。这些权利的获得建立在签署者同意不会专为了维护专利而攻击 Linux 系统的基础上。

OIN 确保 Linux 的源代码保持开放的状态。这让编程人员、设备厂商、独立软件开发者和公共机构在投资和使用 Linux 时不用过多的担心知识产权的问题。这让对 Linux 进行重新打包、嵌入和使用的公司省了不少钱。

“随着版权许可证越来越广泛的使用，对 OIN 许可证的需求也变得更加的迫切。现在，人们正在寻找更加简单或更实用的解决方法”，Bergelt 说。

OIN 法律防御援助对成员是免费的。成员必须承诺不对 OIN 名单上的软件发起专利诉讼。为了保护他们的软件，他们也同意提供他们自己的专利。最终，这些保证将让几十万的交叉许可通过该网络相互连接起来，Bergelt 如此解释道。

### 填补法律漏洞

“OIN 正在做的事情是非常必要的。它提供另一层 IP （知识产权）保护，”[休斯顿法律中心大学](http://www.law.uh.edu/)的副教授 Greg R. Vetter 这样说道。

他回答 LinuxInsider 说，第二版 GPL 许可证被某些人认为提供了隐含的专利许可，但是律师们更喜欢明确的许可。

OIN 所提供的许可填补了这个空白。它还明确的覆盖了 Linux 内核。据 Vetter 说，明确的专利许可并不是 GPLv2 中的必要部分，但是这个部分被加入到了 GPLv3 中。（LCTT 译注：Linux 内核采用的是 GPLv2 的许可）

拿一个在 GPLv3 中写了10000行代码的代码编写者来说。随着时间推移，其他的代码编写者会贡献更多行的代码，也加入到了知识产权中。GPLv3 中的软件专利许可条款将基于所有参与的贡献者的专利，保护全部代码的使用，Vetter 如此说道。

### 并不完全一样

专利权和许可证在法律结构上层层叠叠互相覆盖。弄清两者对开源软件的作用就像是穿越雷区。

Vetter 说“通常，许可证是授予建立在专利和版权法律上的额外权利的法律结构。许可证被认为是给予了人们做一些的可能会侵犯到其他人的知识产权权利的事的许可。”

Vetter 指出，很多自由开源许可证（例如 Mozilla 公共许可、GNU GPLv3 以及 Apache 软件许可）融合了某些互惠专利权的形式。Vetter 指出，像 BSD 和 MIT 这样旧的许可证不会提到专利。

一个软件的许可证让其他人可以在某种程度上使用这个编程人员创造的代码。版权对所属权的建立是自动的，只要某个人写或者画了某个原创的东西。然而，版权只覆盖了个别的表达方式和衍生的作品。他并没有涵盖代码的功能性或可用的想法。

专利涵盖了功能性。专利权还可以被许可。版权可能无法保护某人如何独立地开发对另一个人的代码的实现，但是专利填补了这个小瑕疵，Vetter 解释道。

### 寻找安全通道

许可证和专利混合的法律性质可能会对开源开发者产生威胁。据 [Chaotic Moon Studios](http://www.chaoticmoon.com/) 的创办者之一、 [IEEE](http://www.ieee.org/) 计算机协会成员 William Hurley 说，对于某些人来说，即使是 GPL 也会成为威胁。

“在很久以前，开源是个完全不同的世界。被彼此间的尊重和把代码视为艺术而非资产的观点所驱动，那时的程序和代码比现在更加的开放。我相信很多为最好的愿景所做的努力几乎最后总是背负着意外的结果，”Hurley 这样告诉 LinuxInsider。

他暗示说，成员人数超越了1000人（的组织）可能会在知识产权保护重要性方面意见不一。这可能会继续搅混开源生态系统这滩浑水。

“最终，这些显现出了围绕着知识产权的常见的一些错误概念。拥有几千个开发者并不会减少风险——而是增加。给出了专利许可的开发者越多，它们看起来就越值钱，”Hurley 说。“它们看起来越值钱，有着类似专利的或者其他知识产权的人就越可能试图利用并从中榨取他们自己的经济利益。”

### 共享与竞争共存

竞合策略是开源的一部分。OIN 模型让各个公司能够决定他们将在哪竞争以及在哪合作，Bergelt 解释道。

“开源演化中的许多改变已经把我们移到了另一个方向上。我们必须为合作创造渠道。否则我们将会有几百个团体把数十亿美元花费到同样的技术上，”他说。

手机产业的革新就是个很好的例子。各个公司放出了不同的标准。没有共享，没有合作，Bergelt 解释道。

他说：“这让我们在美国接触技术的能力落后了七到十年。我们接触设备的经验远远落后于世界其他地方的人。在我们用不上 CDMA (Code Division Multiple Access 码分多址访问通信技术)时对 GSM (Global System for Mobile Communications 全球移动通信系统) 还沾沾自喜。”

### 改变格局

OIN 在去年经历了激增400个新许可的增长。这意味着着开源有了新趋势。

Bergelt 说：“市场到达了一个临界点，组织内的人们终于意识到直白地合作和竞争的需要。结果是两件事同时进行。这可能会变得复杂、费力。”

然而，这个由人们开始考虑合作和竞争的文化革新所驱动的转换过程是可以接受的。他解释说，这也是一个人们怎样拥抱开源的转变——尤其是在 Linux 这个开源社区的领导者项目。

还有一个迹象是，最具意义的新项目都没有在 GPLv3 许可下开发。

### 二个总比一个好

“GPL 极为重要，但是事实是有一堆的许可模型正被使用着。在 Eclipse、Apache 和 Berkeley 许可中，专利问题的相对可解决性通常远远低于在 GPLv3 中的。”Bergelt 说。

GPLv3 对于解决专利问题是个自然的补充——但是 GPL 自身不足以独自解决围绕专利使用的潜在冲突。所以 OIN 的设计是以能够补充版权许可为目的的，他补充道。

然而，层层叠叠的专利和许可也许并没有带来多少好处。到最后，专利在几乎所有的案例中都被用于攻击目的——而不是防御目的，Bergelt 暗示说。

“如果你不准备对其他人采取法律行动，那么对于你的知识产权来说专利可能并不是最佳的法律保护方式”，他说。“我们现在生活在一个对软件——开放的和专有的——误会重重的世界里。这些软件还被错误而过时的专利系统所捆绑。我们每天在工业化和被扼杀的创新中挣扎”，他说。

### 法院是最后的手段

想到 OIN 的出现抑制了诉讼的泛滥就感到十分欣慰，Bergelt 说，或者至少可以说 OIN 的出现扼制了特定的某些威胁。

“可以说我们让人们放下他们的武器。同时我们正在创建一种新的文化规范。一旦你入股这个模型中的非侵略专利，所产生的相关影响就是对合作的鼓励”，他说。

如果你愿意承诺合作，你的第一反应就会趋向于不急着起诉。相反的，你会想如何让我们允许你使用我们所拥有的东西并让它为你赚钱，而同时我们也能使用你所拥有的东西，Bergelt 解释道。

“OIN 是个多面的解决方式。它鼓励签署者创造双赢协议”，他说，“这让起诉成为最逼不得已的行为。那才是它的位置。”

### 底线

Bergelt 坚信，OIN 的运作是为了阻止 Linux 受到专利伤害。在这个需要 Linux 的世界里没有诉讼的地方。

唯一临近的是与微软的移动之争，这关系到行业的发展前景（原文： The only thing that comes close are the mobile wars with Microsoft, which focus on elements high in the stack. 不太理解，请指正。）。那些来自法律的挑战可能是为了提高包括使用 Linux 产品的所属权的成本，Bergelt 说。

尽管如此“这些并不是有关 Linux 诉讼”，他说。“他们的重点并不在于 Linux 的核心。他们关注的是 Linux 系统里都有些什么。”

---

via: <http://www.linuxinsider.com/story/Defending-the-Free-Linux-World-81512.html>

作者：Jack M. Germain 译者：[H-mudcup](https://github.com/H-mudcup) 校对：[wxy](https://github.com/wxy)

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


Node.js 4.0 中的 ES 6 特性介绍

Summary: Node.js 4.0.0 已经发布了。这是和 io.js 合并之后的首个稳定版本，它带来了一系列的新特性，支持 ES 6的大部分特性。已经有很多 ES 6 的特性介绍了，这里我们介绍一下该怎么使用它们。  1. 模板字符串 如果你要在 JavaScript 中创建多行字符串，你可能会使用如下的语法： var message = .join('\n'); 对于少量字符串这还算合适，但是如果比较多就会显得混乱。不过，有个聪明的开发者提出了一个叫multiline的技巧： var multiline = require('multiline'); var message = multiline(function () {/* The quick brown fox jumps over the l

nodejs会越来越好的吧

Nodejs，虽然我用的不是它，但仍然觉得很牛x！

不复杂、好用，它在一条正确的路上。

[Node.js 4.0.0 已经发布了](/article-6181-1.html)。这是和 io.js 合并之后的首个稳定版本，它带来了一系列的新特性，支持 ES 6的大部分特性。已经有很多 [ES 6 的特性](https://nodejs.org/en/docs/es6/)介绍了，这里我们介绍一下该怎么使用它们。

![](/data/attachment/album/201509/14/150337fbb1xe1b53z770n3.jpg)

### 1. 模板字符串

如果你要在 JavaScript 中创建多行字符串，你可能会使用如下的语法：

```
var message = [
    'The quick brown fox',
    'jumps over',
    'the lazy dog'
].join('\n');
```

对于少量字符串这还算合适，但是如果比较多就会显得混乱。不过，有个聪明的开发者提出了一个叫 [multiline](https://github.com/sindresorhus/multiline) 的技巧：

```
var multiline = require('multiline');
var message = multiline(function () {/*
    The quick brown fox
    jumps over
    the lazy dog
*/});
```

幸运的是，ES 6 为我们带来了[模板字符串](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings):

```
var message = `
    The quick brown fox
        jumps over
        the lazy dog
`;
```

此外，它还给我们带来了字符串内插：

```
var name = 'Schroedinger';

// 不要这样做 ...
var message = 'Hello ' + name + ', how is your cat?';
var message = ['Hello ', name, ', how is your cat?'].join('');
var message = require('util').format('Hello %s, how is your cat?', name);

// 应该这样做 ...
var message = `Hello ${name}, how is your cat?`;
```

[在 MDN 上查看模板字符串的细节](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/template_strings).

### 2. 类

在 ES5 中定义类看起来有点奇怪，也比较麻烦：

```
var Pet = function (name) {
    this._name = name;
};

Pet.prototype.sayHello = function () {
    console.log('*scratch*');
};

Object.defineProperty(Pet.prototype, 'name', {
  get: function () {
    return this._name;
  }
});

var Cat = function (name) {
    Pet.call(this, name);
};

require('util').inherits(Cat, Pet);

Cat.prototype.sayHello = function () {
    Pet.prototype.sayHello.call(this);
    console.log('miaaaauw');
};
```

幸运的是，在 Node.js 中可以使用新的 ES6 格式：

```
class Pet {
    constructor(name) {
        this._name = name;
    }
    sayHello() {
        console.log('*scratch*');
    }
    get name() {
        return this._name;
    }
}

class Cat extends Pet {
    constructor(name) {
        super(name);
    }
    sayHello() {
        super.sayHello();
        console.log('miaaaauw');
    }
}
```

有 extends 关键字、构造子、调用超类及属性，是不是很棒？还不止这些，[看看 MDN 上的更详细的介绍。](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)

### 3. 箭头函数

在函数里面对 `this` 的动态绑定总是会导致一些混乱，人们一般是这样用的：

```
Cat.prototype.notifyListeners = function () {
    var self = this;
    this._listeners.forEach(function (listener) {
        self.notifyListener(listener);
    });
};
```

```
Cat.prototype.notifyListeners = function () {
    this._listeners.forEach(function (listener) {
        this.notifyListener(listener);
    }.bind(this));
};
```

现在你可以使用胖箭头函数了：

```
Cat.prototype.notifyListeners = function () {
    this._listeners.forEach((listener) => {
        this.notifyListener(listener);
    });
};
```

[了解箭头函数的更多细节。](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions).

### 4. 对象字面量

使用对象字面量，你现在有了很漂亮的快捷方式：

```
var age = 10, name = 'Petsy', size = 32;

// 不要这样做 ...
var cat = {
    age: age,
    name: name,
    size: size
};

// ... 而是这样做 ...
var cat = {
    age,
    name,
    size
};
```

此外，你现在可以很容易地 [给你的对象字面量添加函数](https://github.com/lukehoban/es6features#enhanced-object-literals)。

### 5. Promise

不用再依赖像 `bluebird` 或 `Q`这样的第三方库了，你现在可以使用 [原生的 promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). 它们公开了如下 API：

```
var p1 = new Promise(function (resolve, reject) {});
var p2 = Promise.resolve(20);
var p3 = Promise.reject(new Error());
var p4 = Promise.all(p1, p2);
var p5 = Promise.race(p1, p2);

// 显然
p1.then(() => {}).catch(() => {});
```

### 6. 字符串方法

我们也有了一系列新的字符串功能：

```
// 在几种情况下可以替代 `indexOf()`
name.startsWith('a')
name.endsWith('c');
name.includes('b');

// 重复字符串三次
name.repeat(3);
```

去告诉那些使用 Ruby 的家伙吧！字符串现在也 [对 unicode 支持更好了](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla#Additions_to_the_String_object)。

### 7. let 和 const

猜猜下列函数调用的返回值：

```
var x = 20;
(function () {
    if (x === 20) {
        var x = 30;
    }
    return x;
}()); // -> undefined
```

是的， `undefined`。使用 `let` 替代 `var` ，你会得到预期的行为：

```
let x = 20;
(function () {
    if (x === 20) {
        let x = 30;
    }
    return x;
}()); // -> 20
```

原因是什么呢？ `var` 是函数作用域，而 `let` 是块级作用域（如大部分人所预期的）。因此，可以说 `let` 是一个新`var`。 你可以[在 MDN 上了解更多细节](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let)。

此外，Node.js 也[支持 const 关键字](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)了，它可以防止你为同一个引用赋予不同的值：

```
var MY_CONST = 42; // no, no
const MY_CONST = 42; // yes, yes

MY_CONST = 10 // 使用了 const ，这就不行了
```

### 结语

Node.js 4.0.0 带来了更多的 ES6 特性，我希望这七个例子可以吸引你升级到最新版本。

还有更多的语言特性呢（例如，maps/sets, 符号和生成器，这里只提到了一点）。你可以看看 [Node.js 4.0.0 的 ES6 概览](https://nodejs.org/en/docs/es6/)。 赶快升级吧！


使用脚本便捷地在 Ubuntu 中安装最新 Linux 内核

Summary: 想要安装最新的Linux内核吗？一个简单的脚本就可以在Ubuntu系统中方便的完成这项工作。 Michael Murphy 写了一个脚本用来将最新的候选版、标准版、或者低延时版的内核安装到 Ubuntu 系统中。这个脚本会在询问一些问题后从 Ubuntu 内核主线页面 下载安装最新的 Linux 内核包。 通过脚本来安装、升级Linux内核:   点击这个 github 页面 右上角的 Download Zip 来下载该脚本。   鼠标右键单击用户下载目录下的 Zip 文件，选择 在此展开 将其解压。   右键点击解压后的文件夹，选择 在终端中打开 到此文件夹下。    此时将会打开一个终端，并

方便是很方面但是。。。新手求助。。。下载脚本的链接，没找脚本。。。

链接访问不了

终于能省点劲了，其实内核更新本就不复杂

呃，这个脚本是被万恶的墙给挡了。。我来想想办法。

已经搬运回来啦。

![](/data/attachment/album/201509/14/233726upxtb524hpwbza2p.png)

想要安装最新的Linux内核吗？一个简单的脚本就可以在Ubuntu系统中方便的完成这项工作。

Michael Murphy 写了一个脚本用来将最新的候选版、标准版、或者低延时版的内核安装到 Ubuntu 系统中。这个脚本会在询问一些问题后从 [Ubuntu 内核主线页面](http://kernel.ubuntu.com/%7Ekernel-ppa/mainline/) 下载安装最新的 Linux 内核包。

### 通过脚本来安装、升级Linux内核:

1、 点击这个 [github 页面](https://gist.github.com/mmstick/8493727) 右上角的 “Download Zip” 来下载该脚本（注：此脚本在墙外，我已经搬运回来了，请参见下面。）。

2、鼠标右键单击用户下载目录下的 Zip 文件，选择 “在此展开” 将其解压。

3、右键点击解压后的文件夹，选择 “在终端中打开” 到此文件夹下。

![](/data/attachment/album/201509/14/233727wx63yw3ze8403y0j.jpg)

此时将会打开一个终端，并且自动导航到目标文件夹下。如果你找不到 “在终端中打开” 选项的话，在 Ubuntu 软件中心搜索安装 `nautilus-open-terminal` ，然后重新登录系统即可（也可以再终端中运行 `nautilus -q` 来取代重新登录系统的操作）。

备注：此脚本如下，你可以将它保存为一个可执行的 shell 脚本：

```
#!/bin/bash
cd /tmp

if ! which lynx > /dev/null; then sudo apt-get install lynx -y; fi

if [ "$(getconf LONG_BIT)" == "64" ]; then arch=amd64; else arch=i386; fi

function download() {
   wget $(lynx -dump -listonly -dont-wrap-pre $kernelURL | grep "$1" | grep "$2" | grep "$arch" | cut -d ' ' -f 4)
}

# Kernel URL
read -p "Do you want the latest RC?" rc
case "$rc" in
   y* | Y*) kernelURL=$(lynx -dump -nonumbers http://kernel.ubuntu.com/~kernel-ppa/mainline/ | tail -1) ;;
   n* | N*) kernelURL=$(lynx -dump -nonumbers http://kernel.ubuntu.com/~kernel-ppa/mainline/ | grep -v rc | tail -1) ;;
   *) exit ;;
esac

read -p "Do you want the lowlatency kernel?" lowlatency
case "$lowlatency" in
   y* | Y*) lowlatency=1 ;;
   n* | n*) lowlatency=0 ;;
   *) exit ;;
esac

# Download Kernel
if [ "$lowlatency" == "0" ]; then
   echo "Downloading the latest generic kernel."
   download generic header
   download generic image
elif [ "$lowlatency" == "1" ]; then
   echo "Downloading the latest lowlatency kernel."
   download lowlatency header
   download lowlatency image
fi

# Shared Kernel Header
wget $(lynx -dump -listonly -dont-wrap-pre $kernelURL | grep all | cut -d ' ' -f 4)

# Install Kernel
echo "Installing Linux Kernel"
sudo dpkg -i linux*.deb
echo "Done. You may now reboot."
```

 4. 当进入终端后，运行以下命令来赋予脚本执行本次操作的权限。

```
chmod +x *

```

最后，每当你想要安装或升级 Ubuntu 的 linux 内核时都可以运行此脚本。

```
./*

```

![](/data/attachment/album/201509/14/233729a1gi948vf1naaux4.jpg)

这里之所以使用 \* 替代脚本名称是因为文件夹中只有它一个文件。

如果脚本运行成功，重启电脑即可。

### 恢复并且卸载新版内核

如果因为某些原因要恢复并且移除新版内核的话，请重启电脑，在 Grub 启动器的 **高级选项** 菜单下选择旧版内核来启动系统。

当系统启动后，参照下边章节继续执行。

### 如何移除旧的（或新的）内核:

1. 从 Ubuntu 软件中心安装 Synaptic Package Manager。
2. 打开 Synaptic Package Manager 然后如下操作:

* 点击 **Reload** 按钮，让想要被删除的新内核显示出来.
* 在左侧面板中选择 **Status -> Installed** ，让查找列表更清晰一些。
* 在 Quick filter 输入框中输入 **linux-image-** 用于查询。
* 选择一个内核镜像 “linux-image-x.xx.xx-generic” 然后将其标记为removal（或者Complete Removal）
* 最后，应用变更

![](/data/attachment/album/201509/14/233733apkb1dwbp77bbb5e.jpg)

重复以上操作直到移除所有你不需要的内核。注意，不要随意移除此刻正在运行的内核，你可以通过 `uname -r` 命令来查看运行的内核。

对于 Ubuntu 服务器来说，你可以一步步运行下面的命令：

```
uname -r

dpkg -l | grep linux-image-

sudo apt-get autoremove KERNEL_IMAGE_NAME

```

![](/data/attachment/album/201509/14/233736wb7ldfgsf73dekmi.jpg)

---

via: <http://ubuntuhandbook.org/index.php/2015/08/install-latest-kernel-script/>

作者：[Ji m](http://ubuntuhandbook.org/index.php/about/) 译者：[mr-ping](https://github.com/mr-ping) 校对：[wxy](https://github.com/wxy)

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


修复安装完 Ubuntu 后无可引导设备的错误

Summary: 通常情况下，我会安装启动 Ubuntu 和 Windows 的双系统，但是这次我决定完全消除 Windows 纯净安装 Ubuntu。纯净安装 Ubuntu 完成后，结束时屏幕输出无可引导设备 (no bootable device found) 而不是进入 GRUB 界面。显然，安装搞砸了 UEFI 引导设置。  我会告诉你我是如何修复在宏碁笔记本上安装 Ubuntu 后出现无可引导设备错误的。我声明了我使用的是宏碁灵越 R13，这很重要，因为我们需要更改固件设置，而这些设置可能因制造商和设备有所不同。 因此在你开始这里介绍的步骤之前，先看一下发生这个错误时我计算机的状态：  我的宏碁灵越

但是相对也要考虑那些不能这样的bios的解决办法啊，记得以前有efi写入主板引导的教程，但是忘记了

我一直都搞不懂EFI是个什么鬼东西

你超棒！！！！！！！！

谢谢

通常情况下，我会安装启动 Ubuntu 和 Windows 的双系统，但是这次我决定完全消除 Windows 纯净安装 Ubuntu。纯净安装 Ubuntu 完成后，结束时屏幕输出<ruby> 无可引导设备 <rp>  ( </rp> <rt>  no bootable device found </rt> <rp>  ) </rp></ruby>而不是进入 GRUB 界面。显然，安装搞砸了 UEFI 引导设置。

![安装完 Ubuntu 后无可引导设备](/data/attachment/album/201509/15/133347nvljblvol3v692lz.jpg)

我会告诉你我是如何修复**在宏碁笔记本上安装 Ubuntu 后出现<ruby> 无可引导设备 <rp>  （ </rp> <rt>  no bootable device found </rt> <rp>  ） </rp></ruby>错误**的。我声明了我使用的是宏碁灵越 R13，这很重要，因为我们需要更改固件设置，而这些设置可能因制造商和设备有所不同。

因此在你开始这里介绍的步骤之前，先看一下发生这个错误时我计算机的状态：

* 我的宏碁灵越 R13 预装了 Windows 8.1 和 UEFI 引导管理器
* <ruby> 安全引导 <rp>  ( </rp> <rt>  Secure boot </rt> <rp>  ) </rp></ruby>没有关闭，（我的笔记本刚维修过，维修人员又启用了它，直到出现了问题我才发现）。你可以阅读这篇博文了解[如何在宏碁笔记本中关闭<ruby> 安全引导 <rp>  ( </rp> <rt>  secure boot </rt> <rp>  ) </rp></ruby>](http://itsfoss.com/disable-secure-boot-in-acer/)
* 我选择了清除所有东西安装 Ubuntu，例如现有的 Windows 8.1，各种分区等
* 安装完 Ubuntu 之后，从硬盘启动时我看到无可引导设备错误。但能从 USB 设备正常启动

在我看来，没有禁用<ruby> 安全引导 <rp>  ( </rp> <rt>  secure boot </rt> <rp>  ) </rp></ruby>可能是这个错误的原因。但是，我没有数据支撑我的观点。这仅仅是预感。有趣的是，双系统启动 Windows 和 Linux 经常会出现这两个 Grub 问题：

* [错误：没有 grub 救援分区](http://itsfoss.com/solve-error-partition-grub-rescue-ubuntu-linux/)
* [支持最小化 BASH 式的行编辑](http://itsfoss.com/fix-minimal-bash-line-editing-supported-grub-error-linux/)

如果你遇到类似的情况，你可以试试我的修复方法。

### 修复安装完 Ubuntu 后无可引导设备错误

请原谅我的图片质量很差。我的一加相机不能很好地拍摄笔记本屏幕。

#### 第一步

关闭电源并进入引导设置。我需要在宏碁灵越 R13 上快速地按下 Fn+F2。如果你使用固态硬盘的话要按的非常快，因为固态硬盘启动速度很快。这取决于你的制造商，你可能要用 Del 或 F10 或者 F12。

#### 第二步

在引导设置中，确保启用了<ruby> 安全引导 <rp>  ( </rp> <rt>  Secure Boot </rt> <rp>  ) </rp></ruby>。它在 Boot 标签里。

#### 第三步

进入到 Security 标签，找到 “<ruby> 选择一个用于执行的可信任 UEFI 文件 <rp>  ( </rp> <rt>  Select an UEFI file as trusted for executing </rt> <rp>  ) </rp></ruby>” 并敲击回车。

![修复无可引导设备错误](/data/attachment/album/201509/15/133348yqlwaoo5lzhhxlto.jpg)

特意说明，我们这一步是要在你的设备中添加 UEFI 设置文件（安装 Ubuntu 的时候生成）到可信 UEFI 启动中。如果你记得的话，UEFI 启动的主要目的是提供安全性，由于（可能）没有禁用<ruby> 安全引导 <rp>  ( </rp> <rt>  Secure Boot </rt> <rp>  ) </rp></ruby>，设备不会试图从新安装的操作系统中启动。添加它到类似白名单的可信列表，会使设备从 Ubuntu UEFI 文件启动。

#### 第四步

在这里你可以看到你的硬盘，例如 HDD0。如果你有多块硬盘，我希望你记住你安装 Ubuntu 的那块。同样敲击回车。

![在 Boot 设置中修复无可引导设备错误](/data/attachment/album/201509/15/133350ym2bmwabbbaw8sv7.jpg)

#### 第五步

你应该可以看到<EFI>了，敲击回车。

![在 UEFI 中修复设置](/data/attachment/album/201509/15/133351vtg47ssk1tv74kj4.jpg)

#### 第六步

在下一个屏幕中你会看到<ubuntu> 。耐心点，马上就好了。

![安装完 Ubuntu 后修复启动错误](/data/attachment/album/201509/15/133355sxcul5ffatckc2it.jpg)

#### 第七步

你可以看到 shimx64.efi，grubx64.efi 和 MokManager.efi 文件。重要的是 shimx64.efi。选中它并敲击回车。

![修复无可引导设备](/data/attachment/album/201509/15/133402h00u3ac331l23wao.jpg)

在下一个屏幕中，输入 Yes 并敲击回车。

![无可引导设备_7](/data/attachment/album/201509/15/133405gguu3ncwwbxb4l8e.jpg)

#### 第八步

当我们添加它到可信 EFI 文件并执行后，按 F10 保存并退出。

![保存并退出固件设置](/data/attachment/album/201509/15/133409hc1e17u69fce4x37.jpg)

重启你的系统，这时你就可以看到熟悉的 GRUB 界面了。就算你没有看到 Grub 界面，起码也再也不会看到“<ruby> 无可引导设备 <rp>  ( </rp> <rt>  no bootable device found </rt> <rp>  ) </rp></ruby>”。你应该可以进入 Ubuntu 了。

如果修复后搞乱了你的 Grub 界面，但你确实能登录系统，你可以重装 Grub 并进入到 Ubuntu 熟悉的紫色 Grub 界面。

我希望这篇指南能帮助你修复无可引导设备错误。欢迎提出任何疑问、建议或者感谢。

---

via: <http://itsfoss.com/no-bootable-device-found-ubuntu/>

作者：[Abhishek](http://itsfoss.com/author/abhishek/) 译者：[ictlyh](http://www.mutouxiaogui.cn/blog/) 校对：[wxy](https://github.com/wxy)

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


RHCSA 系列（四）: 编辑文本文件及分析文本

圣战、、、、

我会经常用到设置行号 复制和取代的功能，没看到复制取代某个关键字的用法

yutou83 [Internet Explorer 11.0|Windows 7]

作为系统管理员的日常职责的一部分，每个系统管理员都必须处理文本文件，这包括编辑已有文件（大多可能是配置文件），或创建新的文件。有这样一个说法，假如你想在 Linux 世界中挑起一场圣战，你可以询问系统管理员们，什么是他们最喜爱的编辑器以及为什么。在这篇文章中，我们并不打算那样做，但我们将向你呈现一些技巧，这些技巧对使用两款在 RHEL 7 中最为常用的文本编辑器: nano（由于其简单和易用，特别是对于新手来说）和 vi/m（由于其自身的几个特色使得它不仅仅是一个简单的编辑器）来说都大有裨益。我确信你可以找到更多的理由来使用其中的一个或另一个，或许其他的一些编辑器如 emacs 或 pico。这完全取决于你自己。

![学习 Nano 和 vi 编辑器](/data/attachment/album/201509/15/231442zmaexaxjqn7exmzn.png)

*RHCSA: 使用 Nano 和 Vim 编辑文本文件 – Part 4*

### 使用 Nano 编辑器来编辑文件

要启动 nano，你可以在命令提示符下输入 `nano`，或可选地跟上一个文件名（在这种情况下，若文件存在，它将在编辑模式中被打开）。若文件不存在，或我们省略了文件名， nano 也将在编辑模式下开启，但将为我们开启一个空白屏以便开始输入：

![Nano 编辑器](/data/attachment/album/201509/15/231442f8q5dqolq6jqwmye.png)

*Nano 编辑器*

正如你在上一张图片中所见的那样， nano 在屏幕的底部呈现出一些可以通过指定的快捷键来触发的功能（^，即插入记号，代指 Ctrl 键)。它们中的一些是：

* Ctrl + G: 触发一个帮助菜单，带有一个关于功能和相应的描述的完整列表；

![Nano 编辑器帮助菜单](/data/attachment/album/201509/15/231443h7sqt9ddauamimmj.png)

*Nano 编辑器帮助菜单*

* Ctrl + O: 保存更改到一个文件。它可以让你用一个与源文件相同或不同的名称来保存该文件，然后按 Enter 键来确认。

![Nano 编辑器保存更改模式](/data/attachment/album/201509/15/231444dgk4qf4074vb9q6b.png)

*Nano 编辑器的保存更改模式*

* Ctrl + X: 离开当前文件，假如更改没有被保存，则它们将被丢弃；
* Ctrl + R: 通过指定一个完整的文件路径，让你选择一个文件来将该文件的内容插入到当前文件中；

![Nano: 插入文件内容到主文件中](/data/attachment/album/201509/15/231444mfuldufe2pzyyxe8.png)

*Nano: 插入文件内容到主文件中*

上图的操作将把 `/etc/passwd` 的内容插入到当前文件中。

* Ctrl + K: 剪切当前行；
* Ctrl + U: 粘贴；
* Ctrl + C: 取消当前的操作并返回先前的屏幕；

为了轻松地在打开的文件中浏览， nano 提供了下面的功能：

* Ctrl + F 和 Ctrl + B 分别先前或向后移动光标；而 Ctrl + P 和 Ctrl + N 则分别向上或向下移动一行，功能与箭头键相同；
* Ctrl + space 和 Alt + space 分别向前或向后移动一个单词；

最后，

* 假如你想将光标移动到文档中的特定位置，使用 Ctrl + \_ (下划线) 并接着输入 X,Y 将准确地带你到 第 X 行，第 Y 列。

![在 nano 中定位到具体的行，列](/data/attachment/album/201509/15/231444tch3efiuwpifxez2.png)

*在 nano 中定位到具体的行和列*

上面的例子将带你到当前文档的第 15 行，第 14 列。

假如你可以回忆起你早期的 Linux 岁月，特别是当你刚从 Windows 迁移到 Linux 中，你就可能会同意：对于一个新手来说，使用 nano 来开始学习是最好的方式。

### 使用 Vim 编辑器来编辑文件

Vim 是 vi 的加强版本，它是 Linux 中一个著名的文本编辑器，可在所有兼容 POSIX 的 \*nix 系统中获取到，例如在 RHEL 7 中。假如你有机会并可以安装 Vim，请继续；假如不能，这篇文章中的大多数（若不是全部）的提示也应该可以正常工作。

Vim 的一个出众的特点是可以在多个不同的模式中进行操作：

* <ruby> 命令模式 <rp>  （ </rp> <rt>  Command Mode </rt> <rp>  ） </rp></ruby>将允许你在文件中跳转和输入命令，这些命令是由一个或多个字母组成的简洁且大小写敏感的组合。假如你想重复执行某个命令特定次数，你可以在这个命令前加上需要重复的次数（这个规则只有极少数例外）。例如， `yy`（或 `Y`，yank 的缩写）可以复制整个当前行，而 `4yy`（或 `4Y`）则复制整个从当前行到接下来的 3 行(总共 4 行)。
* 我们总是可以通过敲击 `Esc` 键来进入命令模式（无论我们正工作在哪个模式下）。
* 在<ruby> 末行模式 <rp>  （ </rp> <rt>  Ex Mode </rt> <rp>  ） </rp></ruby>中，你可以操作文件（包括保存当前文件和运行外部的程序或命令）。要进入末行模式，你必须从命令模式中（换言之，输入 `Esc` + `:`)输入一个冒号(`:`)，再直接跟上你想使用的末行模式命令的名称。
* 对于<ruby> 插入模式 <rp>  （ </rp> <rt>  Insert Mode </rt> <rp>  ） </rp></ruby>，可以输入字母 `i` 进入，然后只需要输入文字即可。大多数的击键结果都将出现在屏幕中的文本中。

现在，让我们看看如何在 vim 中执行在上一节列举的针对 nano 的相同的操作。不要忘记敲击 Enter 键来确认 vim 命令。

为了从命令行中获取 vim 的完整手册，在命令模式下键入 `:help` 并敲击 Enter 键：

![vim 编辑器帮助菜单](/data/attachment/album/201509/15/231445svvzzavunbvav5kv.png)

*vim 编辑器帮助菜单*

上面的部分呈现出一个内容列表，这些定义的小节则描述了 Vim 的特定话题。要浏览某一个小节，可以将光标放到它的上面，然后按 `Ctrl + ]` （闭方括号）。注意，底部的小节展示的是当前文件的内容。

1、 要保存更改到文件，在命令模式中运行下面命令中的任意一个，就可以达到这个目的：

```
:wq!
:x!
ZZ (是的，两个 ZZ,前面无需添加冒号)

```

2、 要离开并丢弃更改，使用 `:q!`。这个命令也将允许你离开上面描述过的帮助菜单，并返回到命令模式中的当前文件。

3、 剪切 N 行：在命令模式中键入 `Ndd`。

4、 复制 M 行：在命令模式中键入 `Myy`。

5、 粘贴先前剪贴或复制过的行：在命令模式中按 `P`键。

6、 要插入另一个文件的内容到当前文件：

```
:r filename

```

例如，插入 `/etc/fstab` 的内容，可以这样做：

[在 vi 编辑器中插入文件的内容](http://www.tecmint.com/wp-content/uploads/2015/03/Insert-Content-vi-Editor.png)

*在 vi 编辑器中插入文件的内容*

7、 插入一个命令的输出到当前文档：

```
:r! command

```

例如，要在光标所在的当前位置后面插入日期和时间：

![在 vi 编辑器中插入时间和日期](/data/attachment/album/201509/15/231446qns4zsysfv77tssf.png)

*在 vi 编辑器中插入时间和日期*

在另一篇我写的文章中，([LFCS 系列（二）](http://www.tecmint.com/vi-editor-usage/))，我更加详细地解释了在 vim 中可用的键盘快捷键和功能。或许你可以参考那个教程来查看如何使用这个强大的文本编辑器的更深入的例子。

### 使用 grep 和正则表达式来分析文本

到现在为止，你已经学习了如何使用 nano 或 vim 创建和编辑文件。打个比方说，假如你成为了一个文本编辑器忍者 – 那又怎样呢？ 在其他事情上，你也需要知道如何在文本中搜索正则表达式。

正则表达式（也称为 "regex" 或 "regexp"） 是一种识别一个特定文本字符串或模式的方式，使得一个程序可以将这个模式和任意的文本字符串相比较。尽管利用 grep 来使用正则表达式值得用一整篇文章来描述，这里就让我们复习一些基本的知识：

**1、 最简单的正则表达式是一个由数字和字母构成的字符串（例如，单词 "svm"） ，或者两个（在使用两个字符串时，你可以使用 `|`(或) 操作符）：**

```
# grep -Ei 'svm|vmx' /proc/cpuinfo

```

上面命令的输出结果中若有这两个字符串之一的出现，则标志着你的处理器支持虚拟化:

![正则表达式示例](/data/attachment/album/201509/15/231447xf5wkowee5ecwsew.png)

*正则表达式示例*

**2、 第二种正则表达式是一个范围列表，由方括号包裹。**

例如， `c[aeiou]t` 匹配字符串 cat、cet、cit、cot 和 cut，而 `[a-z]` 和 `[0-9]` 则相应地匹配小写字母或十进制数字。假如你想重复正则表达式 X 次，在正则表达式的后面立即输入 `{X}`即可。

例如，让我们从 `/etc/fstab` 中析出存储设备的 UUID：

```
# grep -Ei '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}' -o /etc/fstab

```

![在 Linux 中从一个文件中析出字符串](/data/attachment/album/201509/15/231448zutw1oqegs11u6uw.png)

*从一个文件中析出字符串*

方括号中的第一个表达式 `[0-9a-f]` 被用来表示小写的十六进制字符，`{8}`是一个量词，暗示前面匹配的字符串应该重复的次数（在一个 UUID 中的开头序列是一个 8 个字符长的十六进制字符串）。

在圆括号中，量词 `{4}`和连字符暗示下一个序列是一个 4 个字符长的十六进制字符串，接着的量词 `({3})`表示前面的表达式要重复 3 次。

最后，在 UUID 中的最后一个 12 个字符长的十六进制字符串可以由 `[0-9a-f]{12}` 取得， `-o` 选项表示只打印出在 `/etc/fstab`中匹配行中的匹配的(非空)部分。

**3、 POSIX 字符类**

| 字符类 | 匹配 … |
| --- | --- |
| `[:alnum:]` | 任意字母或数字 [a-zA-Z0-9] |
| `[:alpha:]` | 任意字母 [a-zA-Z] |
| `[:blank:]` | 空格或制表符 |
| `[:cntrl:]` | 任意控制字符 (ASCII 码的 0 至 32) |
| `[:digit:]` | 任意数字 [0-9] |
| `[:graph:]` | 任意可见字符 |
| `[:lower:]` | 任意小写字母 [a-z] |
| `[:print:]` | 任意非控制字符 |
| `[:space:]` | 任意空格 |
| `[:punct:]` | 任意标点字符 |
| `[:upper:]` | 任意大写字母 [A-Z] |
| `[:xdigit:]` | 任意十六进制数字 [0-9a-fA-F] |
| `[:word:]` | 任意字母，数字和下划线 [a-zA-Z0-9\_] |

例如，我们可能会对查找已添加到我们系统中给真实用户的 UID 和 GID（参考“[RHCSA 系列（二）: 如何进行文件和目录管理](/article-6155-1.html)”来回忆起这些知识）感兴趣。那么，我们将在 `/etc/passwd` 文件中查找 4 个字符长的序列：

```
# grep -Ei [[:digit:]]{4} /etc/passwd

```

![在文件中查找一个字符串](/data/attachment/album/201509/15/231449tvx4ixv54xtw17g7.png)

*在文件中查找一个字符串*

上面的示例可能不是真实世界中使用正则表达式的最好案例，但它清晰地启发了我们如何使用 POSIX 字符类来使用 grep 分析文本。

### 总结

在这篇文章中，我们已经提供了一些技巧来最大地利用针对命令行用户的两个文本编辑器 nano 和 vim，这两个工具都有相关的扩展文档可供阅读，你可以分别查询它们的官方网站(链接在下面给出)以及使用“[RHCSA 系列（一）: 回顾基础命令及系统文档](/article-6133-1-rel.html)”中给出的建议。

#### 参考文件链接

* <http://www.nano-editor.org/>
* <http://www.vim.org/>

---

via: <http://www.tecmint.com/rhcsa-exam-how-to-use-nano-vi-editors/>

作者：[Gabriel Cánepa](http://www.tecmint.com/author/gacanepa/) 译者：[FSSlc](https://github.com/FSSlc) 校对：[wxy](https://github.com/wxy)

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


在 Ubuntu 上安装类 Winamp 的音频播放器 Qmmp 0.9.0

Summary: Qmmp，一个基于 Qt 的音频播放器，与 Winamp 或 xmms 的用户界面类似，现在最新版本是0.9.0。PPA 已经在 Ubuntu 15.10，Ubuntu 15.04，Ubuntu 14.04，Ubuntu 12.04 和其衍生版本中已经更新了。 Qmmp 0.9.0 是一个较大的版本，有许多新的功能，有许多改进和新的转变。它添加了如下功能：  音频-信道序列转换器; 9通道支持均衡器; 支持艺术家专辑标签; 异步排序; 不用修改 qmmp.pri 来禁用插件（仅在 qmake 中）功能 记住播放列表滚动位置功能; 排除 cue 数据文件功能; 更改用户代理功能; 改变窗口标题功能; 禁用 gme 插件淡出的功能; 简单

习惯DeadbeeF了，暂时不动。

![](/data/attachment/album/201509/15/233319na4486zp284asunm.png)

Qmmp，一个基于 Qt 的音频播放器，与 Winamp 或 xmms 的用户界面类似，现在最新版本是0.9.0。PPA 已经在 Ubuntu 15.10，Ubuntu 15.04，Ubuntu 14.04，Ubuntu 12.04 和其衍生版本中已经更新了。

Qmmp 0.9.0 是一个较大的版本，有许多新的功能，有许多改进和新的转变。它添加了如下功能：

* 音频-信道序列转换器;
* 9通道支持均衡器;
* 支持艺术家专辑标签;
* 异步排序;
* 不用修改 qmmp.pri 来禁用插件（仅在 qmake 中）功能
* 记住播放列表滚动位置功能;
* 排除 cue 数据文件功能;
* 更改用户代理功能;
* 改变窗口标题功能;
* 禁用 gme 插件淡出的功能;
* 简单用户界面（QSUI）有以下变化：
	+ 增加了多列的支持;
	+ 增加了按艺术家专辑排序;
	+ 增加了按文件的修改日期进行排序;
	+ 增加了隐藏歌曲长度功能;
	+ 增加了“Rename List”的默认热键;
	+ 增加了“Save List”功能到标签菜单;
	+ 增加了复位字体功能;
	+ 增加了复位快捷键功能;
	+ 改进了状态栏;

它还改进了播放列表的改变通知，播放列表容器，采样率转换器，cmake 构建脚本，标题格式化，在 mpeg 插件中支持 ape 标签，fileops 插件，降低了 cpu 占用率，改变默认的皮肤（炫光）和分离的播放列表。

![qmmp-090](/data/attachment/album/201509/15/233320unxt4sqzn0quqa8a.jpg)

### 在 Ubuntu 中安装 Qmmp 0.9.0 :

新版本已经制做了 PPA，适用于目前所有 Ubuntu 发行版和衍生版。

1、添加 [Qmmp PPA](https://launchpad.net/%7Eforkotov02/+archive/ubuntu/ppa).

从 Dash 中打开终端并启动应用，通过按 Ctrl+Alt+T 快捷键。当它打开时，运行命令：

```
sudo add-apt-repository ppa:forkotov02/ppa

```

![qmmp-ppa](/data/attachment/album/201509/15/233321vt607c50k5oo450x.jpg)

2、在添加 PPA 后，通过更新软件来升级 Qmmp 播放器。刷新系统缓存，并通过以下命令安装软件：

```
sudo apt-get update
sudo apt-get install qmmp qmmp-plugin-pack
```

就是这样。尽情享受吧！

---

via: <http://ubuntuhandbook.org/index.php/2015/09/qmmp-0-9-0-in-ubuntu/>

作者：[Ji m](http://ubuntuhandbook.org/index.php/about/) 译者：[strugglingyouth](https://github.com/strugglingyouth) 校对：[wxy](https://github.com/wxy)

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


Debian 项目不再提供 CD 格式的 ISO 镜像

Summary: debian-cd 项目负责人 Stephen McIntyre今天在Debian邮件列表中对近日召开的 DebConf15 大会上的 Debian CD BoF会议进行了摘要总结。 该消息说，自即将发布的 Debian GNU/Linux 9.0 (Stretch) 版本开始，今后 Debian GNU/Linux 系统不再生成 CD 套装的 ISO 镜像，但是会依旧生成 DVD 和蓝光镜像。  当前 debian-cd 项目会生成大量的各种镜像，包括：  CD DVD 非自由的网络安装镜像（包括非自由的固件包） 非自由的固件打包  debian-live 团队使用 live-build 创建的在线镜像（Live image）  包括非自由的固件的镜像  openstack-debian-ima

9还很遥远呢

哦

debian-cd 项目负责人 Stephen McIntyre [今天在Debian邮件列表中](https://lists.debian.org/debian-devel-announce/2015/09/msg00004.html)对近日召开的 DebConf15 大会上的 Debian CD BoF会议进行了摘要总结。

该消息说，自即将发布的 Debian GNU/Linux 9.0 (Stretch) 版本开始，今后 Debian GNU/Linux 系统不再生成 CD 套装的 ISO 镜像，但是会依旧生成 DVD 和蓝光镜像。

![](/data/attachment/album/201509/16/220934y7hh0u15wupm22g1.jpg "cdr.jpg")

当前 debian-cd 项目会生成大量的各种镜像，包括：

* CD
* DVD
* 非自由的网络安装镜像（包括非自由的固件包）
* 非自由的固件打包

debian-live 团队使用 live-build 创建的在线镜像（Live image）

* 包括非自由的固件的镜像

openstack-debian-images 生成的 Openstack 镜像

所有这些都是在 pettersson 上构建的，这是一台托管在 umu.se 的大型中央化的 CD 构建机。

对于新的发行版和测试版本，会停止构建它的完整 CD 套装（针对 90% 以上的系统架构）。同时，也会停止构建针对不同桌面的可选的 CD1 。不过，会继续构建 DVD 和蓝光镜像，DVD#1 也可以继续用于 4GB 的 USB 存储棒。

网络安装镜像会继续构建，这个又小又方便的镜像还有很多人用。对于旧的发行版，会继续构建 CD 套装和可选的 CD1 （Wheezy 和 Jessie），这个不会半途而废。


Linux 有问必答：如何在 Linux 中统计一个进程的线程数

Summary: 问题: 我正在运行一个程序，它在运行时会派生出多个线程。我想知道程序在运行时会有多少线程。在 Linux 中检查进程的线程数最简单的方法是什么？  如果你想看到 Linux 中每个进程的线程数，有以下几种方法可以做到这一点。 方法一: /proc proc 伪文件系统，它驻留在 /proc 目录，这是最简单的方法来查看任何活动进程的线程数。 /proc 目录以可读文本文件形式输出，提供现有进程和系统硬件相关的信息如 CPU、中断、内存、磁盘等等. $ cat /proc/pid/status  上面的命令将显示进程 pid 的详细信息，包括过程状态（例如, sleeping, running)

>
> **问题**: 我正在运行一个程序，它在运行时会派生出多个线程。我想知道程序在运行时会有多少线程。在 Linux 中检查进程的线程数最简单的方法是什么？
>
>
>

如果你想看到 Linux 中每个进程的线程数，有以下几种方法可以做到这一点。

### 方法一: /proc

proc 伪文件系统，它驻留在 /proc 目录，这是最简单的方法来查看任何活动进程的线程数。 /proc 目录以可读文本文件形式输出，提供现有进程和系统硬件相关的信息如 CPU、中断、内存、磁盘等等.

```
$ cat /proc/<pid>/status

```

上面的命令将显示进程 <pid> 的详细信息，包括过程状态（例如, sleeping, running)，父进程 PID，UID，GID，使用的文件描述符的数量，以及上下文切换的数量。输出也包括**进程创建的总线程数**如下所示。

```
Threads: <N>

```

例如，检查 PID 20571进程的线程数：

```
$ cat /proc/20571/status

```

![](/data/attachment/album/201509/17/102919l37w6x2y2gcss686.jpg)

输出表明该进程有28个线程。

或者，你可以在 /proc//task 中简单的统计子目录的数量，如下所示。

```
$ ls /proc/<pid>/task | wc

```

这是因为，对于一个进程中创建的每个线程，在 `/proc/<pid>/task` 中会创建一个相应的目录，命名为其线程 ID。由此在 `/proc/<pid>/task` 中目录的总数表示在进程中线程的数目。

### 方法二: ps

如果你是功能强大的 ps 命令的忠实用户，这个命令也可以告诉你一个进程（用“H”选项）的线程数。下面的命令将输出进程的线程数。“h”选项需要放在前面。

```
$ ps hH p <pid> | wc -l

```

如果你想监视一个进程的不同线程消耗的硬件资源（CPU & memory），请参阅[此教程](/article-5633-1.html)。

---

via: <http://ask.xmodulo.com/number-of-threads-process-linux.html>

作者：[Dan Nanni](http://ask.xmodulo.com/author/nanni) 译者：[strugglingyouth](https://github.com/strugglingyouth) 校对：[wxy](https://github.com/wxy)

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


Nmcli 网络管理命令行工具基础

Summary: 介绍 在本教程中，我们会在CentOS / RHEL 7中讨论网络管理工具（NetworkManager command line tool），也叫nmcli。那些使用ifconfig的用户应该在CentOS 7中避免使用ifconfig 了。 让我们用nmcli工具配置一些网络设置。 要得到系统中所有接口的地址信息 # ip addr show  示例输出： 1: lo: LOOPBACK,UP,LOWER_UP mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever prefe

# 看 IP

nmcli dev show eno????

# 设 DNS

nmcli connection modify "static" ipv4.dns "1.2.3.4, 5.6.7.8"

老实说我觉得nmcli和firewall-cmd都是灾难。

没觉得，nmcli 可以一站式完成几乎所有网络配置。而 firewall-cmd 也很方便。不是所有人都精通 iptables。

我是觉得，这么冗长的命令和参数，其实对于英语国家来说，毫无感觉，而对于非英语国家，总是不太友好。

现在 GNU 包的很多软件都同时支持短参数和长参数格式，甚至部分参数只有长的没有短的。长参数格式有一个好处是，具有一定的自解释功能，方便用户了解命令具体执行什么操作。而且像 nmcli 这些较新的命令，也支持参数缩写。比如 nmcli connection 可以缩写为 nmcli co。

![](/data/attachment/album/201509/17/105759s9i4i9wpkyw8ip09.jpg)

### 介绍

在本教程中，我们会在CentOS / RHEL 7中讨论<ruby> 网络管理命令行工具 <rp>  （ </rp> <rt>  NetworkManager command line tool </rt> <rp>  ） </rp></ruby>，也叫**nmcli**。那些使用**ifconfig**的用户应该在CentOS 7中避免使用**ifconfig** 了。

让我们用nmcli工具配置一些网络设置。

#### 要得到系统中所有接口的地址信息

```
[root@localhost ~]# ip addr show

```

**示例输出：**

```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
 inet 127.0.0.1/8 scope host lo
 valid_lft forever preferred_lft forever
 inet6 ::1/128 scope host
 valid_lft forever preferred_lft forever
2: eno16777736: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
 link/ether 00:0c:29:67:2f:4c brd ff:ff:ff:ff:ff:ff
 inet 192.168.1.51/24 brd 192.168.1.255 scope global eno16777736
 valid_lft forever preferred_lft forever
 inet6 fe80::20c:29ff:fe67:2f4c/64 scope link
 valid_lft forever preferred_lft forever

```

#### 检索与已连接的接口相关的数据包统计

```
[root@localhost ~]# ip -s link show eno16777736

```

**示例输出：**

![](/data/attachment/album/201509/17/105801w5ppjse4gpp8q2wp.png)

#### 得到路由配置

```
[root@localhost ~]# ip route

```

示例输出：

```
default via 192.168.1.1 dev eno16777736 proto static metric 100
192.168.1.0/24 dev eno16777736 proto kernel scope link src 192.168.1.51 metric 100

```

#### 分析主机/网站路径

```
[root@localhost ~]# tracepath unixmen.com

```

输出像traceroute，但是更加完整。

![](/data/attachment/album/201509/17/105802rls9dmr97ggqm3qm.png)

### nmcli 工具

**nmcli** 是一个非常丰富和灵活的命令行工具。nmcli使用的情况有：

* **设备** – 正在使用的网络接口
* **连接** – 一组配置设置，对于一个单一的设备可以有多个连接，可以在连接之间切换。

#### 找出有多少连接服务于多少设备

```
[root@localhost ~]# nmcli connection show

```

![](/data/attachment/album/201509/17/105802yfaass94qukuqkk4.png)

#### 得到特定连接的详情

```
[root@localhost ~]# nmcli connection show eno1

```

**示例输出：**

![](/data/attachment/album/201509/17/105802upxvxpfxepvl0psl.png)

#### 得到网络设备状态

```
[root@localhost ~]# nmcli device status

```

---

```
 DEVICE               TYPE              STATE          CONNECTION
eno16777736            ethernet      connected              eno1
lo                     loopback      unmanaged               --

```

#### 使用“dhcp”创建新的连接

```
[root@localhost ~]# nmcli connection add con-name "dhcp" type ethernet ifname eno16777736

```

这里，

* **connection add** – 添加新的连接
* **con-name** – 连接名
* **type** – 设备类型
* **ifname** – 接口名

这个命令会使用dhcp协议添加连接

**示例输出：**

```
Connection 'dhcp' (163a6822-cd50-4d23-bb42-8b774aeab9cb) successfully added.

```

#### 不通过dhcp分配IP，使用“static”添加地址

```
[root@localhost ~]# nmcli connection add con-name "static" ifname eno16777736 autoconnect no type ethernet ip4 192.168.1.240 gw4 192.168.1.1

```

**示例输出：**

```
Connection 'static' (8e69d847-03d7-47c7-8623-bb112f5cc842) successfully added.

```

**更新连接：**

```
[root@localhost ~]# nmcli connection up eno1

```

再检查一遍，ip地址是否已经改变

```
[root@localhost ~]# ip addr show

```

![](/data/attachment/album/201509/17/105803yg4zwfi70m7fgi00.png)

#### 添加DNS设置到静态连接中

```
[root@localhost ~]# nmcli connection modify "static" ipv4.dns 202.131.124.4

```

#### 添加更多的DNS

```
[root@localhost ~]# nmcli connection modify "static" +ipv4.dns 8.8.8.8
```

**注意**：要使用额外的**+**符号，并且要是**+ipv4.dns**，而不是**ip4.dns**。

#### 添加一个额外的ip地址

```
[root@localhost ~]# nmcli connection modify "static" +ipv4.addresses 192.168.200.1/24

```

使用命令刷新设置：

```
[root@localhost ~]# nmcli connection up eno1

```

![](/data/attachment/album/201509/17/105804p999fmwnlddk6dsn.png)

你会看见，设置生效了。

完结。

---

via: <http://www.unixmen.com/basics-networkmanager-command-line-tool-nmcli/>

作者：Rajneesh Upadhyay 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


Linux 有问必答：如何删除 Ubuntu 上不再使用的旧内核

Summary: 提问：过去我已经在我的Ubuntu上升级了几次内核。现在我想要删除这些旧的内核镜像来节省我的磁盘空间。如何用最简单的方法删除Ubuntu上先前版本的内核？  在Ubuntu上，有几个方法来升级内核。在Ubuntu桌面中，软件更新允许你每天检查并更新到最新的内核上。在Ubuntu服务器上，最为重要的安全更新项目之一就是 unattended-upgrades 软件包会自动更新内核。然而，你也可以手动用apt-get或者aptitude命令来更新。 随着时间的流逝，持续的内核更新会在系统中积聚大量的不再使用的内核，浪费你的磁盘空间。每个内核镜像和其相关联的模块/头文件

这是我自己总结的清理 Linux 内核包的代码

但是有些问题，不能识别内核的子版本，需要手动修改一下。比如没有识别内核版本中的 6-201

系统是 dnf 需要自行替换 yum

如下命令使用长参数格式

# 列出较早版本的 Linux 內核包, For Fedora

rpm --query --all | grep --ignore-case '^kernel-' | grep --invert-match $(uname --kernel-release | cut --delimiter='-' --fields=1)

# 刪除之前列出的较早前的 Linux 內核包

sudo yum --assumeno remove "$(rpm --query --all | grep --ignore-case '^kernel-' | grep --invert-match $(uname --

sudo yum --assumeno remove "$(rpm --query --all | grep --ignore-case '^kernel-' | grep --invert-match $(uname --kernel-release | cut --delimiter='-' --fields=1))"

这是刚刚修改后的命令，因为不长清理内核，所以一直没有怎么改。

这次是直接用 uname 返回的内核版本，没有做任何截取。

不过考虑到发行版的差异，所以还有如下的一个版本

此外没有用 autoremove，是因为之前发现如果用 autoremove 会带出其他包

这个问题可能与 dnf 版本有关。

用 --assumeno 是防止意外删除，仅展示命令要执行什么。

# 版本1

rpm --query --all | grep --ignore-case '^kernel-' | grep --invert-match $(uname --kernel-release)

sudo dnf --assumeno remove $(rpm --query --all | grep --ignore-case '^kernel-' | grep --invert-match $(uname --kernel-release))

# 版本 2

os_ver=$(uname --kernel-release | awk --assign FS='.' '{print $(NF-1)"."$(NF)}')

knlver=$(uname --kernel-release | sed $'s#.'"$os_ver"'##')

# rpm --query --all | grep --ignore-case '^kernel-' | grep --invert-match "$knlver"

sudo dnf --assumeno remove $(rpm --query --all | grep --ignore-case '^kernel-' | grep --invert-match "$knlver")

兄台，注册个用户吧，这样回帖长度会长很多。

所以还是fedora好，dnf update自动删除旧内核

dnf 确实可以自动删除，不过默认条件下是在删除最早的一个。暂不清楚能不能改成在一定时间后删除所有老的内核。

如果新内核导致系统崩溃，会需要使用久内核来启动系统。虽然这些版本不太可能会发生这么严重的错误，但是可能还是存在的。起码得留一个能够稳定的久内核

兄台，注册个账号吧！欢迎入驻！   :>

汗！自己都忘了登陆了！

原来是你~~

是我 :>

>
> **提问**：过去我已经在我的Ubuntu上升级了几次内核。现在我想要删除这些旧的内核镜像来节省我的磁盘空间。如何用最简单的方法删除Ubuntu上先前版本的内核？
>
>
>

在Ubuntu上，有几个方法来升级内核。在Ubuntu桌面中，软件更新允许你每天检查并更新到最新的内核上。在Ubuntu服务器上，最为重要的安全更新项目之一就是 unattended-upgrades 软件包会自动更新内核。然而，你也可以手动用apt-get或者aptitude命令来更新。

随着时间的流逝，持续的内核更新会在系统中积聚大量的不再使用的内核，浪费你的磁盘空间。每个内核镜像和其相关联的模块/头文件会占用200-400MB的磁盘空间，因此由不再使用的内核而浪费的磁盘空间会快速地增加。

![](/data/attachment/album/201509/18/091447jtx4rf8o2f5y4o96.jpg)

GRUB管理器为每个旧内核都维护了一个GRUB入口，以备你想要使用它们。

![](/data/attachment/album/201509/18/091455qvnp7gyjf14lwojw.jpg)

作为磁盘清理的一部分，如果你不再使用这些，你可以考虑清理掉这些镜像。

### 如何清理旧内核镜像

在删除旧内核之前，记住最好留有2个最近的内核（最新的和上一个版本），以防主要的版本出错。现在就让我们看看如何在Ubuntu上清理旧内核。

在Ubuntu内核镜像包含了以下的包。

* **linux-image-**: 内核镜像
* **linux-image-extra-**: 额外的内核模块
* **linux-headers-**: 内核头文件

首先检查系统中安装的内核镜像。

```
$ dpkg --list | grep linux-image
$ dpkg --list | grep linux-headers

```

在列出的内核镜像中，你可以移除一个特定的版本（比如3.19.0-15）。

```
$ sudo apt-get purge linux-image-3.19.0-15
$ sudo apt-get purge linux-headers-3.19.0-15

```

上面的命令会删除内核镜像和它相关联的内核模块和头文件。

注意如果你还没有升级内核那么删除旧内核会自动触发安装新内核。这样在删除旧内核之后，GRUB配置会自动升级来移除GRUB菜单中相关GRUB入口。

如果你有很多没用的内核，你可以用shell表达式来一次性地删除多个内核。注意这个括号表达式只在bash或者兼容的shell中才有效。

```
$ sudo apt-get purge linux-image-3.19.0-{18,20,21,25}
$ sudo apt-get purge linux-headers-3.19.0-{18,20,21,25}

```

![](/data/attachment/album/201509/18/091544qutw3pzp1ww9whtt.jpg)

上面的命令会删除4个内核镜像：3.19.0-18、3.19.0-20、3.19.0-21 和 3.19.0-25。

如果GRUB配置由于任何原因在删除旧内核后没有正确升级，你可以尝试手动用update-grub2命令来更新配置。

```
$ sudo update-grub2

```

现在就重启来验证GRUB菜单是否已经正确清理了。

![](/data/attachment/album/201509/18/091544jbjwrewfbhlbdhaf.jpg)

---

via: <http://ask.xmodulo.com/remove-kernel-images-ubuntu.html>

作者：[Dan Nanni](http://ask.xmodulo.com/author/nanni) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


在 Ubuntu 和 Elementary OS 上使用 NaSC 进行简单数学运算

Summary: NaSC，Not a Soulver Clone 的缩写，是为 elementary 操作系统开发的第三方应用程序。正如名字暗示的那样，NaSC 的灵感来源于 Soulver，后者是像普通人一样进行数学计算的 OS X 应用。 Elementary OS 它自己本身借鉴了 OS X，也就不奇怪它的很多第三方应用灵感都来自于 OS X 应用。 回到 NaSC，像普通人一样进行数学计算到底是什么意思呢？事实上，它意味着正如你想的那样去书写。按照该应用程序的介绍：  它能使你像平常那样进行计算。它允许你输入任何你想输入的，智能识别其中的数学部分并在右边面板打印出结果。然后你可以在后面的等

![](/data/attachment/album/201509/18/092344txr8v82r18u8vjde.jpg)

[NaSC](http://parnold-x.github.io/nasc/)，Not a Soulver Clone 的缩写，是为 elementary 操作系统开发的第三方应用程序。正如名字暗示的那样，NaSC 的灵感来源于 [Soulver](http://www.acqualia.com/soulver/)，后者是像普通人一样进行数学计算的 OS X 应用。

Elementary OS 它自己本身借鉴了 OS X，也就不奇怪它的很多第三方应用灵感都来自于 OS X 应用。

回到 NaSC，“像普通人一样进行数学计算”到底是什么意思呢？事实上，它意味着正如你想的那样去书写。按照该应用程序的介绍：

>
> “它能使你像平常那样进行计算。它允许你输入任何你想输入的，智能识别其中的数学部分并在右边面板打印出结果。然后你可以在后面的等式中使用这些结果，如果结果发生了改变，等式中使用的也会同样变化。”
>
>
>

还不相信？让我们来看一个截图。

![](/data/attachment/album/201509/18/092344ghrypleljt6eallz.png)

现在，你明白什么是 “像普通人一样做数学” 了吗？坦白地说，我并不是这类应用程序的粉丝，但对你们中的某些人可能会有用。让我们来看看怎么在 Elementary OS、Ubuntu 和 Linux Mint 上安装 NaSC。

### 在 Ubuntu、Elementary OS 和 Mint 上安装 NaSC

安装 NaSC 有一个可用的 PPA。PPA 是 ‘每日’，意味着每日构建（意即，不稳定），但作为我的快速测试，并没什么影响。

打开一个终端并运行下面的命令：

```
sudo apt-add-repository ppa:nasc-team/daily
sudo apt-get update
sudo apt-get install nasc

```

这是 Ubuntu 15.04 中使用 NaSC 的一个截图：

![](/data/attachment/album/201509/18/092345pad5592gn14zydig.png)

如果你想卸载它，可以使用下面的命令：

```
sudo apt-get remove nasc
sudo apt-add-repository --remove ppa:nasc-team/daily

```

如果你试用了这个软件，要分享你的经验哦。除此之外，你也可以在第三方 Elementary OS 应用中体验 [Vocal podcast app for Linux](http://itsfoss.com/podcast-app-vocal-linux/)。

---

via: <http://itsfoss.com/math-ubuntu-nasc/>

作者：[Abhishek](http://itsfoss.com/author/abhishek/) 译者：[ictlyh](http://www.mutouxiaogui.cn/blog/) 校对：[wxy](https://github.com/wxy)

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


RHCSA 系列（五）: RHEL7 中的进程管理：开机，关机

Summary: 我们将概括和简要地复习从你按开机按钮来打开你的 RHEL 7 服务器到呈现出命令行界面的登录屏幕之间所发生的所有事情，以此来作为这篇文章的开始。  Linux 开机过程 请注意：  相同的基本原则也可以应用到其他的 Linux 发行版本中，但可能需要较小的更改，并且 下面的描述并不是旨在给出开机过程的一个详尽的解释，而只是介绍一些基础的东西  Linux 开机过程   初始化 POST（加电自检）并执行硬件检查；   当 POST 完成后，系统的控制权将移交给启动管理器的第一阶段（first stage），它存储在一个硬盘的引导扇区（对于使用 BIOS 和 MBR 的

又一个专题栏目了！ ：>

开机过程不是很详细, 比如stage1,stage2, 我在其他资料上看到还有个stage1.5

我们将概括和简要地复习从你按开机按钮来打开你的 RHEL 7 服务器到呈现出命令行界面的登录屏幕之间所发生的所有事情，以此来作为这篇文章的开始。

![RHEL 7 开机过程](/data/attachment/album/201509/18/143619mi1uzcqi9cu9eqqw.png)

*Linux 开机过程*

**请注意：**

1. 相同的基本原则也可以应用到其他的 Linux 发行版本中，但可能需要较小的更改，并且
2. 下面的描述并不是旨在给出开机过程的一个详尽的解释，而只是介绍一些基础的东西

### Linux 开机过程

1. 初始化 POST（加电自检）并执行硬件检查；
2. 当 POST 完成后，系统的控制权将移交给启动管理器的<ruby> 第一阶段 <rp>  （ </rp> <rt>  first stage </rt> <rp>  ） </rp></ruby>，它存储在一个硬盘的引导扇区（对于使用 BIOS 和 MBR 的旧式的系统而言）或存储在一个专门的 (U)EFI 分区上。
3. 启动管理器的第一阶段完成后，接着进入启动管理器的<ruby> 第二阶段 <rp>  （ </rp> <rt>  second stage </rt> <rp>  ） </rp></ruby>，通常大多数使用的是 GRUB（GRand Unified Boot Loader 的简称），它驻留在 `/boot` 中，然后开始加载内核和驻留在 RAM 中的初始化文件系统（被称为 initramfs，它包含执行必要操作所需要的程序和二进制文件，以此来最终挂载真实的根文件系统）。
4. 接着展示了<ruby> 闪屏 <rp>  （ </rp> <rt>  splash </rt> <rp>  ） </rp></ruby>过后，呈现在我们眼前的是类似下图的画面，它允许我们选择一个操作系统和内核来启动：

![RHEL 7 开机屏幕](/data/attachment/album/201509/18/143621j7j777cfubofttcc.png)

*启动菜单屏幕*
5. 内核会对接入到系统的硬件进行设置，当根文件系统被挂载后，接着便启动 PID 为 1 的进程，这个进程将开始初始化其他的进程并最终呈现给我们一个登录提示符界面。

注意：假如我们想在启动后查看这些信息，我们可以使用 [dmesg 命令](/article-3587-1.html)，并使用这个系列里的上一篇文章中介绍过的工具（注：即 grep）来过滤它的输出。

![登录屏幕和进程的 PID](/data/attachment/album/201509/18/143622uus38ekomtotke2o.png)

*登录屏幕和进程的 PID*

在上面的例子中，我们使用了大家熟知的 `ps` 命令来显示在系统启动过程中的一系列当前进程的信息，它们的父进程（或者换句话说，就是那个开启这些进程的进程）为 systemd（大多数现代的 Linux 发行版本已经切换到的系统和服务管理器）：

```
# ps -o ppid,pid,uname,comm --ppid=1

```

记住 `-o`（为 -format 的简写）选项允许你以一个自定义的格式来显示 ps 的输出，以此来满足你的需求；这个自定义格式使用 `man ps` 里 STANDARD FORMAT SPECIFIERS 一节中的特定关键词。

另一个你想自定义 ps 的输出而不是使用其默认输出的情形是：当你需要找到引起 CPU 或内存消耗过多的那些进程，并按照下列方式来对它们进行排序时：

```
# ps aux --sort=+pcpu              # 以 %CPU 来排序(增序)
# ps aux --sort=-pcpu              # 以 %CPU 来排序(降序)
# ps aux --sort=+pmem              # 以 %MEM 来排序(增序)
# ps aux --sort=-pmem              # 以 %MEM 来排序(降序)
# ps aux --sort=+pcpu,-pmem        # 结合 %CPU (增序) 和 %MEM (降序)来排列

```

![https://img.linux.net.cn/data/attachment/album/201509/18/143623k9xzqohboobbbhbv.png](/data/attachment/album/201509/18/143623k9xzqohboobbbhbv.png)

*自定义 ps 命令的输出*

### systemd 的一个介绍

在 Linux 世界中，很少有能比在主流的 Linux 发行版本中采用 systemd 引起更多的争论的决定。systemd 的倡导者根据以下事实来表明其主要的优势：

1. 在系统启动期间，systemd 允许并发地启动更多的进程（相比于先前的 SysVinit，SysVinit 似乎总是表现得更慢，因为它一个接一个地启动进程，检查一个进程是否依赖于另一个进程，然后等待守护进程启动才可以启动的更多的服务)，并且
2. 在一个运行着的系统中，它用作一个动态的资源管理器。这样在启动期间，当一个服务被需要时，才启动它（以此来避免消耗系统资源）而不是在没有一个合理的原因的情况下启动额外的服务。
3. 向后兼容 sysvinit 的脚本。

另外请阅读: ['init' 和 'systemd' 背后的故事](http://www.tecmint.com/systemd-replaces-init-in-linux/)

systemd 由 systemctl 工具控制，假如你了解 SysVinit，你将会对以下的内容感到熟悉：

* service 工具，在旧一点的系统中，它被用来管理 SysVinit 脚本，以及
* chkconfig 工具，为系统服务升级和查询运行级别信息
* shutdown 你一定使用过几次来重启或关闭一个运行的系统。

下面的表格展示了使用传统的工具和 systemctl 之间的相似之处：

| 旧式工具 | Systemctl 等价命令 | 描述 |
| --- | --- | --- |
| service name start | systemctl start name | 启动 name （这里 name 是一个服务） |
| service name stop | systemctl stop name | 停止 name |
| service name condrestart | systemctl try-restart name | 重启 name （如果它已经运行了） |
| service name restart | systemctl restart name | 重启 name |
| service name reload | systemctl reload name | 重载 name 的配置 |
| service name status | systemctl status name | 显示 name 的当前状态 |
| service - status-all | systemctl | 显示当前所有服务的状态 |
| chkconfig name on | systemctl enable name | 通过一个特定的单元文件，让 name 可以在系统启动时运行（这个文件是一个符号链接）。启用或禁用一个启动时的进程，实际上是增加或移除一个到 /etc/systemd/system 目录中的符号链接。 |
| chkconfig name off | systemctl disable name | 通过一个特定的单元文件，让 name 可以在系统启动时禁止运行（这个文件是一个符号链接）。 |
| chkconfig -list name | systemctl is-enabled name | 确定 name （一个特定的服务）当前是否启用。 |
| chkconfig - list | systemctl - type=service | 显示所有的服务及其是否启用或禁用。 |
| shutdown -h now | systemctl poweroff | 关机 |
| shutdown -r now | systemctl reboot | 重启系统 |

systemd 也引进了单元（unit）（它可能是一个服务，一个挂载点，一个设备或者一个网络套接字）和目标（target）（它们定义了 systemd 如何去管理和同时开启几个相关的进程，可以认为它们与在基于 SysVinit 的系统中的运行级别等价，尽管事实上它们并不等价）的概念。

### 总结归纳

其他与进程管理相关，但并不仅限于下面所列的功能的任务有：

**1. 在考虑到系统资源的使用上，调整一个进程的执行优先级：**

这是通过 `renice` 工具来完成的，它可以改变一个或多个正在运行着的进程的调度优先级。简单来说，调度优先级是一个允许内核（当前只支持 >= 2.6 的版本）根据某个给定进程被分配的执行优先级（即友善度（niceness），从 -20 到 19）来为其分配系统资源的功能。

`renice` 的基本语法如下：

```
# renice [-n] priority [-gpu] identifier

```

在上面的通用命令中，第一个参数是将要使用的优先级数值，而另一个参数可以是进程 ID（这是默认的设定），进程组 ID，用户 ID 或者用户名。一个常规的用户（即除 root 以外的用户）只可以更改他或她所拥有的进程的调度优先级，并且只能增加友善度的层次（这意味着占用更少的系统资源）。

![在 Linux 中调整进程的优先级](/data/attachment/album/201509/18/143625qrcjyyrp99p5oifo.png)

*进程调度优先级*

**2. 按照需要杀死一个进程（或终止其正常执行）：**

更精确地说，杀死一个进程指的是通过 [kill 或 pkill](/article-2116-1.html) 命令给该进程发送一个信号，让它优雅地（SIGTERM=15）或立即（SIGKILL=9）结束它的执行。

这两个工具的不同之处在于前一个被用来终止一个特定的进程或一个进程组，而后一个则允许你通过进程的名称和其他属性，执行相同的动作。

另外， pkill 与 pgrep 相捆绑，pgrep 提供将受符合的进程的 PID 给 pkill 来使用。例如，在运行下面的命令之前：

```
# pkill -u gacanepa

```

查看一眼由 gacanepa 所拥有的 PID 或许会带来点帮助：

```
# pgrep -l -u gacanepa

```

![找到用户拥有的 PID](/data/attachment/album/201509/18/143625aliip0luf3jsuisw.png)

*找到用户拥有的 PID*

默认情况下，kill 和 pkiill 都发送 SIGTERM 信号给进程，如我们上面提到的那样，这个信号可以被忽略（即该进程可能会终止其自身的执行，也可能不终止），所以当你因一个合理的理由要真正地停止一个运行着的进程，则你将需要在命令行中带上特定的 SIGKILL 信号：

```
# kill -9 identifier               # 杀死一个进程或一个进程组
# kill -s SIGNAL identifier        # 同上
# pkill -s SIGNAL identifier       # 通过名称或其他属性来杀死一个进程

```

### 结论

在这篇文章中，我们解释了在 RHEL 7 系统中，有关开机启动过程的基本知识，并分析了一些可用的工具来帮助你通过使用一般的程序和 systemd 特有的命令来管理进程。

请注意，这个列表并不旨在涵盖有关这个话题的所有花哨的工具，请随意使用下面的评论栏来添加你自已钟爱的工具和命令。同时欢迎你的提问和其他的评论。

---

via: <http://www.tecmint.com/rhcsa-exam-boot-process-and-process-management/>

作者：[Gabriel Cánepa](http://www.tecmint.com/author/gacanepa/) 译者：[FSSlc](https://github.com/FSSlc) 校对：[wxy](https://github.com/wxy)

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


也许你需要在 Antergos 与 Arch Linux 中查看印度语和梵文？

Summary: 你们到目前或许知道，我最近一直在尝试体验 Antergos Linux。在安装完Antergos后我所首先注意到的一些事情是在默认的 Chromium 浏览器中没法正确显示印度语脚本。 这是一件奇怪的事情，在我之前桌面Linux的体验中是从未遇到过的。起初，我认为是浏览器的问题，所以我安装了Firefox，然而问题依旧，Firefox也不能正确显示印度语。和Chromium不显示任何东西不同的是，Firefox确实显示了一些东西，但是毫无可读性。  Chromium中的印度语显示  Firefox中的印度语显示 奇怪吧？那么，默认情况下基于Arch的Antergos Linux中没有印度语的支持吗？

然并卵

![](/data/attachment/album/201509/20/194150xovjxooxoxoeoqob.jpg)

你们到目前或许知道，我最近一直在尝试体验 [Antergos Linux](http://antergos.com/)。在安装完[Antergos](http://itsfoss.com/tag/antergos/)后我所首先注意到的一些事情是在默认的 Chromium 浏览器中**没法正确显示印度语脚本**。

这是一件奇怪的事情，在我之前桌面Linux的体验中是从未遇到过的。起初，我认为是浏览器的问题，所以我安装了Firefox，然而问题依旧，Firefox也不能正确显示印度语。和Chromium不显示任何东西不同的是，Firefox确实显示了一些东西，但是毫无可读性。

![No hindi support in Arch Linux based Antergos](/data/attachment/album/201509/20/194150sff3owb6ob9yf3e7.jpg)

*Chromium中的印度语显示*

![No hindi support in Arch Linux based Antergos](/data/attachment/album/201509/20/194152jrdz1cju1jqzdcpw.jpg)

*Firefox中的印度语显示*

奇怪吧？那么，默认情况下基于Arch的Antergos Linux中没有印度语的支持吗？我没有去验证，但是我假设其它基于梵语脚本的印地语之类会产生同样的问题。

在这个快速指南中，我打算为大家演示如何来添加梵语支持，以便让印度语和其它印地语都能正确显示。

### 在Antergos和Arch Linux中添加印地语支持

打开终端，使用以下命令：

```
sudo yaourt -S ttf-indic-otf

```

键入密码，它会提供给你对于印地语的译文支持。

重启Firefox，会马上正确显示印度语了，但是它需要一次重启来显示印度语。因此，我建议你在安装了印地语字体后**重启你的系统**。

![Adding Hindi display support in Arch based Antergos Linux](/data/attachment/album/201509/20/194154okov6m03wdxxk31x.jpg)

我希望这篇快速指南能够帮助你，让你可以在Antergos和其它基于Arch的Linux发行版中，如Manjaro Linux，阅读印度语、梵文、泰米尔语、泰卢固语、马拉雅拉姆语、孟加拉语，以及其它印地语。

---

via: <http://itsfoss.com/display-hindi-arch-antergos/>

作者：[Abhishek](http://itsfoss.com/author/abhishek/) 译者：[GOLinux](https://github.com/GOLinux) 校对：[wxy](https://github.com/wxy)

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


如何在 Docker 容器中运行支持 OData 的 JBoss 数据虚拟化 GA

Summary: 大家好，我们今天来学习如何在一个 Docker 容器中运行支持 OData（译者注：Open Data Protocol，开放数据协议） 的 JBoss 数据虚拟化 6.0.0 GA（译者注：GA，General Availability，具体定义可以查看WIKI）。JBoss 数据虚拟化是数据提供和集成解决方案平台，将多种分散的数据源转换为一种数据源统一对待，在正确的时间将所需数据传递给任意的应用或者用户。JBoss 数据虚拟化可以帮助我们将数据快速组合和转换为可重用的商业友好的数据模型，通过开放标准接口简单可用。它提供全面的数据抽取、联合、集成、转换，以及传输功能，将来自一个

大家好，我们今天来学习如何在一个 Docker 容器中运行支持 OData（译者注：Open Data Protocol，开放数据协议） 的 JBoss 数据虚拟化 6.0.0 GA（译者注：GA，General Availability，具体定义可以查看[WIKI](https://en.wikipedia.org/wiki/Software_release_life_cycle#General_availability_.28GA.29)）。JBoss 数据虚拟化是数据提供和集成解决方案平台，将多种分散的数据源转换为一种数据源统一对待，在正确的时间将所需数据传递给任意的应用或者用户。JBoss 数据虚拟化可以帮助我们将数据快速组合和转换为可重用的商业友好的数据模型，通过开放标准接口简单可用。它提供全面的数据抽取、联合、集成、转换，以及传输功能，将来自一个或多个源的数据组合为可重复使用和共享的灵活数据。要了解更多关于 JBoss 数据虚拟化的信息，可以查看它的[官方文档](http://www.redhat.com/en/technologies/jboss-middleware/data-virtualization)。Docker 是一个提供开放平台用于打包，装载和以轻量级容器运行任何应用的开源平台。使用 Docker 容器我们可以轻松处理和启用支持 OData 的 JBoss 数据虚拟化。

![](/data/attachment/album/201509/20/195208f747orti44lu4q7n.png)

下面是该指南中在 Docker 容器中运行支持 OData 的 JBoss 数据虚拟化的简单步骤。

### 1. 克隆仓库

首先，我们要用 git 命令从 <https://github.com/jbossdemocentral/dv-odata-docker-integration-demo> 克隆带数据虚拟化的 OData 仓库。假设我们的机器上运行着 Ubuntu 15.04 linux 发行版。我们要使用 apt-get 命令安装 git。

```
# apt-get install git

```

安装完 git 之后，我们运行下面的命令克隆仓库。

```
# git clone https://github.com/jbossdemocentral/dv-odata-docker-integration-demo

Cloning into 'dv-odata-docker-integration-demo'...
remote: Counting objects: 96, done.
remote: Total 96 (delta 0), reused 0 (delta 0), pack-reused 96
Unpacking objects: 100% (96/96), done.
Checking connectivity... done.

```

### 2. 下载 JBoss 数据虚拟化安装器

现在，我们需要从下载页 <http://www.jboss.org/products/datavirt/download/> 下载 JBoss 数据虚拟化安装器。下载了 **jboss-dv-installer-6.0.0.GA-redhat-4.jar** 后，我们把它保存在名为 **software** 的目录下。

### 3. 创建 Docker 镜像

下一步，下载了 JBoss 数据虚拟化安装器之后，我们打算使用 Dockerfile 和刚从仓库中克隆的资源创建 docker 镜像。

```
# cd dv-odata-docker-integration-demo/
# docker build -t jbossdv600 .

...
Step 22 : USER jboss
---> Running in 129f701febd0
---> 342941381e37
Removing intermediate container 129f701febd0
Step 23 : EXPOSE 8080 9990 31000
---> Running in 61e6d2c26081
---> 351159bb6280
Removing intermediate container 61e6d2c26081
Step 24 : CMD $JBOSS_HOME/bin/standalone.sh -c standalone.xml -b 0.0.0.0 -bmanagement 0.0.0.0
---> Running in a9fed69b3000
---> 407053dc470e
Removing intermediate container a9fed69b3000
Successfully built 407053dc470e

```

注意：在这里我们假设你已经安装了 docker 并正在运行。

### 4. 启动 Docker 容器

创建了支持 oData 的 JBoss 数据虚拟化 Docker 镜像之后，我们打算运行 docker 容器并用 -P 标签指定端口。我们运行下面的命令来实现。

```
# docker run -p 8080:8080 -d -t jbossdv600

7765dee9cd59c49ca26850e88f97c21f46859d2dc1d74166353d898773214c9c

```

### 5. 获取容器 IP

启动了 Docker 容器之后，我们想要获取正在运行的 docker 容器的 IP 地址。要做到这点，我们运行后面添加了正在运行容器 id 号的 docker inspect 命令。

```
# docker inspect <$containerID>

...
"NetworkSettings": {
"Bridge": "",
"EndpointID": "3e94c5900ac5954354a89591a8740ce2c653efde9232876bc94878e891564b39",
"Gateway": "172.17.42.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"HairpinMode": false,
"IPAddress": "172.17.0.8",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,

```

### 6. Web 界面

现在，如果一切如期望的那样进行，当我们用浏览器打开 http://container-ip:8080/ 和 http://container-ip:9990 时会看到支持 oData 的 JBoss 数据虚拟化登录界面和 JBoss 管理界面。管理验证的用户名和密码分别是 admin 和 redhat1！数据虚拟化验证的用户名和密码都是 user。之后，我们可以通过 web 界面在内容间导航。

**注意**： 强烈建议在第一次登录后尽快修改密码。

### 总结

终于我们成功地运行了跑着支持 OData 多源虚拟数据库的 JBoss 数据虚拟化 的 Docker 容器。JBoss 数据虚拟化真的是一个很棒的平台，它为多种不同来源的数据进行虚拟化，并将它们转换为商业友好的数据模型，产生通过开放标准接口简单可用的数据。使用 Docker 技术可以简单、安全、快速地部署支持 OData 多源虚拟数据库的 JBoss 数据虚拟化。如果你有任何疑问、建议或者反馈，请在下面的评论框中写下来，以便我们可以改进和更新内容。非常感谢！Enjoy:-)

---

via: <http://linoxide.com/linux-how-to/run-jboss-data-virtualization-ga-odata-docker-container/>

作者：[Arun Pyasi](http://linoxide.com/author/arunp/) 译者：[ictlyh](http://www.mutouxiaogui.cn/blog) 校对：[wxy](https://github.com/wxy)

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