理解 Linux 链接（一）

Summary: 链接是可以将文件和目录放在你希望它们放在的位置的另一种方式。

链接是可以将文件和目录放在你希望它们放在的位置的另一种方式。

# 理解 Linux 链接（一）

>
> 链接是可以将文件和目录放在你希望它们放在的位置的另一种方式。
>
>
>

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

除了 `cp` 和 `mv` 这两个我们在[本系列的前一部分](https://www.linux.com/blog/2018/8/linux-beginners-moving-things-around)中详细讨论过的，链接是可以将文件和目录放在你希望它们放在的位置的另一种方式。它的优点是可以让你同时在多个位置显示一个文件或目录。

如前所述，在物理磁盘这个级别上，文件和目录之类的东西并不真正存在。文件系统是为了方便人类使用，将它们虚构出来。但在磁盘级别上，有一个名为<ruby> 分区表 <rt>  partition table </rt></ruby>的东西，它位于每个分区的开头，然后数据分散在磁盘的其余部分。

虽然有不同类型的分区表，但是在分区开头的那个表包含的数据将映射每个目录和文件的开始和结束位置。分区表的就像一个索引：当从磁盘加载文件时，操作系统会查找表中的条目，分区表会告诉文件在磁盘上的起始位置和结束位置。然后磁盘头移动到起点，读取数据，直到它到达终点，您看：这就是你的文件。

### 硬链接

硬链接只是分区表中的一个条目，它指向磁盘上的某个区域，表示该区域**已经被分配给文件**。换句话说，硬链接指向已经被另一个条目索引的数据。让我们看看它是如何工作的。

打开终端，创建一个实验目录并进入：

```
mkdir test_dir
cd test_dir
```

使用 [touch](https://www.linux.com/blog/2018/8/linux-beginners-moving-things-around) 创建一个文件：

```
touch test.txt
```

为了获得更多的体验（？），在文本编辑器中打开 `test.txt` 并添加一些单词。

现在通过执行以下命令来建立硬链接：

```
ln test.txt hardlink_test.txt
```

运行 `ls`，你会看到你的目录现在包含两个文件，或者看起来如此。正如你之前读到的那样，你真正看到的是完全相同的文件的两个名称： `hardlink_test.txt` 包含相同的内容，没有填充磁盘中的任何更多空间（可以尝试使用大文件来测试），并与 `test.txt` 使用相同的 inode：

```
$ ls -li *test*
16515846 -rw-r--r-- 2 paul paul 14 oct 12 09:50 hardlink_test.txt
16515846 -rw-r--r-- 2 paul paul 14 oct 12 09:50 test.txt
```

`ls` 的 `-i` 选项显示一个文件的 “inode 数值”。“inode” 是分区表中的信息块，它包含磁盘上文件或目录的位置、上次修改的时间以及其它数据。如果两个文件使用相同的 inode，那么无论它们在目录树中的位置如何，它们在实际上都是相同的文件。

### 软链接

软链接，也称为<ruby> 符号链接 <rt>  symlink </rt></ruby>，它与硬链接是不同的：软链接实际上是一个独立的文件，它有自己的 inode 和它自己在磁盘上的小块地方。但它只包含一小段数据，将操作系统指向另一个文件或目录。

你可以使用 `ln` 的 `-s` 选项来创建一个软链接：

```
ln -s test.txt softlink_test.txt
```

这将在当前目录中创建软链接 `softlink_test.txt`，它指向 `test.txt`。

再次执行 `ls -li`，你可以看到两种链接的不同之处：

```
$ ls -li
total 8
16515846 -rw-r--r-- 2 paul paul 14 oct 12 09:50 hardlink_test.txt
16515855 lrwxrwxrwx 1 paul paul 8 oct 12 09:50 softlink_test.txt -> test.txt
16515846 -rw-r--r-- 2 paul paul 14 oct 12 09:50 test.txt
```

`hardlink_test.txt` 和 `test.txt` 包含一些文本并且*字面上*占据相同的空间。它们使用相同的 inode 数值。与此同时，`softlink_test.txt` 占用少得多，并且具有不同的 inode 数值，将其标记为完全不同的文件。使用 `ls` 的 `-l` 选项还会显示软链接指向的文件或目录。

### 为什么要用链接？

它们适用于**带有自己环境的应用程序**。你的 Linux 发行版通常不会附带你需要应用程序的最新版本。以优秀的 [Blender 3D](https://www.blender.org/) 设计软件为例，Blender 允许你创建 3D 静态图像以及动画电影，人人都想在自己的机器上拥有它。问题是，当前版本的 Blender 至少比任何发行版中的自带的高一个版本。

幸运的是，[Blender 提供可以开箱即用的下载](https://www.blender.org/download/)。除了程序本身之外，这些软件包还包含了 Blender 需要运行的复杂的库和依赖框架。所有这些数据和块都在它们自己的目录层次中。

每次你想运行 Blender，你都可以 `cd` 到你下载它的文件夹并运行：

```
./blender
```

但这很不方便。如果你可以从文件系统的任何地方，比如桌面命令启动器中运行 `blender` 命令会更好。

这样做的方法是将 `blender` 可执行文件链接到 `bin/` 目录。在许多系统上，你可以通过将其链接到文件系统中的任何位置来使 `blender` 命令可用，就像这样。

```
ln -s /path/to/blender_directory/blender /home/<username>/bin
```

你需要链接的另一个情况是**软件需要过时的库**。如果你用 `ls -l` 列出你的 `/usr/lib` 目录，你会看到许多软链接文件一闪而过。仔细看看，你会看到软链接通常与它们链接到的原始文件具有相似的名称。你可能会看到 `libblah` 链接到 `libblah.so.2`，你甚至可能会注意到 `libblah.so.2` 相应链接到原始文件 `libblah.so.2.1.0`。

这是因为应用程序通常需要安装比已安装版本更老的库。问题是，即使新版本仍然与旧版本（通常是）兼容，如果程序找不到它正在寻找的版本，程序将会出现问题。为了解决这个问题，发行版通常会创建链接，以便挑剔的应用程序**相信**它找到了旧版本，实际上它只找到了一个链接并最终使用了更新的库版本。

有些是和**你自己从源代码编译的程序**相关。你自己编译的程序通常最终安装在 `/usr/local` 下，程序本身最终在 `/usr/local/bin` 中，它在 `/usr/local/bin` 目录中查找它需要的库。但假设你的新程序需要 `libblah`，但 `libblah` 在 `/usr/lib` 中，这就是所有其它程序都会寻找到它的地方。你可以通过执行以下操作将其链接到 `/usr/local/lib`：

```
ln -s /usr/lib/libblah /usr/local/lib
```

或者如果你愿意，可以 `cd` 到 `/usr/local/lib`：

```
cd /usr/local/lib
```

然后使用链接：

```
ln -s ../lib/libblah
```

还有几十个案例证明软链接是有用的，当你使用 Linux 更熟练时，你肯定会发现它们，但这些是最常见的。下一次，我们将看一些你需要注意的链接怪异。

通过 Linux 基金会和 edX 的免费 [“Linux 简介”](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)课程了解有关 Linux 的更多信息。

---

via: <https://www.linux.com/blog/intro-to-linux/2018/10/linux-links-part-1>

作者：[Paul Brown](https://www.linux.com/users/bro66) 选题：[lujun9972](https://github.com/lujun9972) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

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


如何在 Linux 中一次重命名多个文件

Summary: 在本教程中，我们将学习使用 Linux 中的 mmv 命令一次重命名多个文件。 此命令用于在类 Unix 操作系统中使用标准通配符批量移动、复制、追加和重命名文件。

# 如何在 Linux 中一次重命名多个文件

你可能已经知道，我们使用 `mv` 命令在类 Unix 操作系统中重命名或者移动文件和目录。 但是，`mv` 命令不支持一次重命名多个文件。 不用担心。 在本教程中，我们将学习使用 Linux 中的 `mmv` 命令一次重命名多个文件。 此命令用于在类 Unix 操作系统中使用标准通配符批量移动、复制、追加和重命名文件。

### 在 Linux 中一次重命名多个文件

`mmv` 程序可在基于 Debian 的系统的默认仓库中使用。 要想在 Debian、Ubuntu、Linux Mint 上安装它，请运行以下命令：

```
$ sudo apt-get install mmv
```

我们假设你在当前目录中有以下文件。

```
$ ls
a1.txt a2.txt a3.txt
```

现在，你想要将所有以字母 “a” 开头的文件重命名为以 “b” 开头的。 当然，你可以在几秒钟内手动执行此操作。 但是想想你是否有数百个文件想要重命名？ 这是一个非常耗时的过程。 这时候 `mmv` 命令就很有帮助了。

要将所有以字母 “a” 开头的文件重命名为以字母 “b” 开头的，只需要运行：

```
$ mmv a\* b\#1
```

让我们检查一下文件是否都已经重命名了。

```
$ ls
b1.txt b2.txt b3.txt
```

如你所见，所有以字母 “a” 开头的文件（即 `a1.txt`、`a2.txt`、`a3.txt`）都重命名为 `b1.txt`、`b2.txt`、`b3.txt`。

**解释**

在上面的例子中，第一个参数（`a\*`）是 “from” 模式，第二个参数是 “to” 模式（`b\#1`）。根据上面的例子，`mmv` 将查找任何以字母 “a” 开头的文件名，并根据第二个参数重命名匹配的文件，即 “to” 模式。我们可以使用通配符，例如用 `*`、`?` 和 `[]` 来匹配一个或多个任意字符。请注意，你必须转义使用通配符，否则它们将被 shell 扩展，`mmv` 将无法理解。

“to” 模式中的 `#1` 是通配符索引。它匹配 “from” 模式中的第一个通配符。 “to” 模式中的 `#2` 将匹配第二个通配符（如果有的话），依此类推。在我们的例子中，我们只有一个通配符（星号），所以我们写了一个 `#1`。并且，`#` 符号也应该被转义。此外，你也可以用引号括起模式。

你甚至可以将具有特定扩展名的所有文件重命名为其他扩展名。例如，要将当前目录中的所有 `.txt` 文件重命名为 `.doc` 文件格式，只需运行：

```
$ mmv \*.txt \#1.doc
```

这是另一个例子。 我们假设你有以下文件。

```
$ ls
abcd1.txt abcd2.txt abcd3.txt
```

你希望在当前目录下的所有文件中将第一次出现的 “abc” 替换为 “xyz”。 你会怎么做呢？

很简单。

```
$ mmv '*abc*' '#1xyz#2'
```

请注意，在上面的示例中，模式被单引号括起来了。

让我们检查下 “abc” 是否实际上被替换为 “xyz”。

```
$ ls
xyzd1.txt xyzd2.txt xyzd3.txt
```

看到没？ 文件 `abcd1.txt`、`abcd2.txt` 和 `abcd3.txt` 已经重命名为 `xyzd1.txt`、`xyzd2.txt` 和 `xyzd3.txt`。

`mmv` 命令的另一个值得注意的功能是你可以使用 `-n` 选项打印输出而不是重命名文件，如下所示。

```
$ mmv -n a\* b\#1
a1.txt -> b1.txt
a2.txt -> b2.txt
a3.txt -> b3.txt
```

这样，你可以在重命名文件之前简单地验证 `mmv` 命令实际执行的操作。

有关更多详细信息，请参阅 man 页面。

```
$ man mmv
```

### 更新：Thunar 文件管理器

**Thunar 文件管理器**默认具有内置**批量重命名**选项。 如果你正在使用 Thunar，那么重命名文件要比使用 `mmv` 命令容易得多。

Thunar 在大多数 Linux 发行版的默认仓库库中都可用。

要在基于 Arch 的系统上安装它，请运行：

```
$ sudo pacman -S thunar
```

在 RHEL、CentOS 上:

```
$ sudo yum install thunar
```

在 Fedora 上:

```
$ sudo dnf install thunar
```

在 openSUSE 上:

```
$ sudo zypper install thunar
```

在 Debian、Ubuntu、Linux Mint 上:

```
$ sudo apt-get install thunar
```

安装后，你可以从菜单或应用程序启动器中启动批量重命名程序。 要从终端启动它，请使用以下命令：

```
$ thunar -B
```

批量重命名方式如下。

单击“+”，然后选择要重命名的文件列表。 批量重命名可以重命名文件的名称、文件的后缀或者同时重命名文件的名称和后缀。 Thunar 目前支持以下批量重命名：

* 插入日期或时间
* 插入或覆盖
* 编号
* 删除字符
* 搜索和替换
* 大写或小写

当你从选项列表中选择其中一个条件时，你将在“新名称”列中看到更改的预览，如下面的屏幕截图所示。

选择条件后，单击“重命名文件”选项来重命名文件。

你还可以通过选择两个或更多文件从 Thunar 中打开批量重命名器。 选择文件后，按 F2 或右键单击并选择“重命名”。

嗯，这就是本次的所有内容了。希望有所帮助。更多干货即将到来。敬请关注！

祝快乐！

---

via: <https://www.ostechnix.com/how-to-rename-multiple-files-at-once-in-linux/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[Flowsnow](https://github.com/Flowsnow) 校对：[wxy](https://github.com/wxy)

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


MidnightBSD 发布 1.0！

# MidnightBSD 发布 1.0！

几天前，Lucas Holt 宣布发布 MidnightBSD 1.0。让我们快速看一下这个新版本中包含的内容。

### 什么是 MidnightBSD？

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

[MidnightBSD](https://www.midnightbsd.org/) 是 FreeBSD 的一个分支。Lucas 创建了 MightnightBSD，这成为桌面用户和 BSD 新手的一个选择。他想创造一个能让人们快速体验 BSD 桌面的东西。他认为其他发行版过于关注服务器市场。

### MidnightBSD 1.0 中有什么？

根据[发布说明](https://www.midnightbsd.org/notes/)（[视频](https://www.youtube.com/embed/-rlk2wFsjJ4)），1.0 中的大部分工作都是更新基础系统，改进包管理器和更新工具。新版本与 FreeBSD 10-Stable 兼容。

Mports（MidnightBSD 的包管理系统）已经升级支持使用一个命令安装多个包。`mport upgrade` 命令已经修复。Mports 现在会跟踪已弃用和过期的包。它还引入了新的包格式。

其他变化包括：

* 现在支持 [ZFS](https://itsfoss.com/what-is-zfs/) 作为启动文件系统。以前，ZFS 只能用于附加存储。 \* 支持 NVME SSD。 \* AMD Ryzen 和 Radeon 的支持得到了改善。 \* Intel、Broadcom 和其他驱动程序已更新。 \* 已从 FreeBSD 移植 bhyve 支持。 \* 传感器框架已被删除，因为它导致锁定问题。 \* 删除了 Sudo 并用 OpenBSD 中的 [doas](https://man.openbsd.org/doas) 替换。 \* 增加了对 Microsoft hyper-v 的支持。

### 升级之前

如果你当前是 MidnightBSD 的用户或正在考虑尝试新版本，那么还是再等一会。Lucas 目前正在重建软件包以支持新的软件包格式和工具。他还计划在未来几个月内升级软件包和移植桌面环境。他目前正致力于移植 Firefox 52 ESR，因为它是最后一个不需要 Rust 的版本。他还希望将更新版本的 Chromium 移植到 MidnightBSD。我建议关注 MidnightBSD 的 [Twitter](https://twitter.com/midnightbsd)。

### 0.9 怎么回事？

你可能注意到 MidnightBSD 的先前版本是 0.8.6。你现在可能想知道“为什么跳到 1.0”？根据 Lucas 的说法，他在开发 0.9 时遇到了几个问题。事实上，他重试好几次。他最终采用与 0.9 分支不同的方式，并变成了 1.0。有些软件包在 0.\* 系列也有问题。

### 需要帮助

目前，MidnightBSD 项目几乎是 Lucas Holt 一个人的作品。这是其发展缓慢的主要原因。如果你有兴趣帮忙，可以通过 [Twitter](https://twitter.com/midnightbsd) 与他联系。

在[发布公告视频](https://www.youtube.com/watch?v=-rlk2wFsjJ4)中。Lucas 说他遇到了上游项目接受补丁的问题。他们似乎认为 MidnightBSD 太小了。这通常意味着他必须从头开始移植应用。

### 想法

我对劣势者有一个想法。在我接触的所有 BSD 中，这个外号最适合 MidnightBSD。一个人想要创建一个轻松的桌面体验。当前只有一个其他的 BSD 在尝试做相似的事情：Project Trident。我想这是 BSD 成功的真正的阻碍。Linux 成功是因为人们可以快速容易地安装它。希望 MidnightBSD 为 BSD 做到这一点，但是还有很长的路要走。

你有没有用过 MidnightBSD？如果没有，你最喜欢的 BSD 是什么？我们应该涵盖哪些其他 BSD 主题？请在下面的评论中告诉我们。

如果你觉得这篇文章有趣，请花一点时间在社交媒体，Hacker News 或 [Reddit](http://reddit.com/r/linuxusersgroup) 上分享它。

---

via: <https://itsfoss.com/midnightbsd-1-0-release/>

作者：[John Paul](https://itsfoss.com/author/john/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


用 350 行代码从零开始，将 Lisp 编译成 JavaScript

# 用 350 行代码从零开始，将 Lisp 编译成 JavaScript

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

我们将会在本篇文章中看到从零开始实现的编译器，将简单的类 LISP 计算语言编译成 JavaScript。完整的源代码在 [这里](https://gist.github.com/soupi/d4ff0727ccb739045fad6cdf533ca7dd)。

我们将会：

1. 自定义语言，并用它编写一个简单的程序
2. 实现一个简单的解析器组合器
3. 为该语言实现一个解析器
4. 为该语言实现一个美观的打印器
5. 为我们的用途定义 JavaScript 的一个子集
6. 实现代码转译器，将代码转译成我们定义的 JavaScript 子集
7. 把所有东西整合在一起

开始吧！

### 1、定义语言

Lisp 族语言最迷人的地方在于，它们的语法就是树状表示的，这就是这门语言很容易解析的原因。我们很快就能接触到它。但首先让我们把自己的语言定义好。关于我们语言的语法的范式（BNF）描述如下：

```
program ::= expr
expr ::= <integer> | <name> | ([<expr>])
```

基本上，我们可以在该语言的最顶层定义表达式并对其进行运算。表达式由一个整数（比如 `5`）、一个变量（比如 `x`）或者一个表达式列表（比如 `(add x 1)`）组成。

整数对应它本身的值，变量对应它在当前环境中绑定的值，表达式列表对应一个函数调用，该列表的第一个参数是相应的函数，剩下的表达式是传递给这个函数的参数。

该语言中，我们保留一些内建的特殊形式，这样我们就能做一些更有意思的事情：

* `let` 表达式使我们可以在它的 `body` 环境中引入新的变量。语法如下：

```
let ::= (let ([<letarg>]) <body>)
letargs ::= (<name> <expr>)
body ::= <expr>
```
* `lambda` 表达式：也就是匿名函数定义。语法如下：

```
lambda ::= (lambda ([<name>]) <body>)
```

还有一些内建函数： `add`、`mul`、`sub`、`div` 和 `print`。

让我们看看用我们这门语言编写的入门示例程序：

```
(let
  ((compose
    (lambda (f g)
      (lambda (x) (f (g x)))))
  (square
    (lambda (x) (mul x x)))
  (add1
    (lambda (x) (add x 1))))
  (print ((compose square add1) 5)))
```

这个程序定义了 3 个函数：`compose`、`square` 和 `add1`。然后将计算结果的值 `((compose square add1) 5)` 输出出来。

我相信了解这门语言，这些信息就足够了。开始实现它吧。

在 Haskell 中，我们可以这样定义语言：

```
type Name = String

data Expr
  = ATOM Atom
  | LIST [Expr]
    deriving (Eq, Read, Show)

data Atom
  = Int Int
  | Symbol Name
    deriving (Eq, Read, Show)
```

我们可以解析用该语言用 `Expr` 定义的程序。而且，这里我们添加了新数据类型 `Eq`、`Read` 和 `Show` 等实例用于测试和调试。你能够在 REPL 中使用这些数据类型，验证它们确实有用。

我们不在语法中定义 `lambda`、`let` 或其它的内建函数，原因在于，当前情况下我们没必要用到这些东西。这些函数仅仅是 `LIST` （表达式列表）的更加特殊的用例。所以我决定将它放到后面的部分。

一般来说你想要在抽象语法中定义这些特殊用例 —— 用于改进错误信息、禁用静态分析和优化等等，但在这里我们不会这样做，对我们来说这些已经足够了。

另一件你想做的事情可能是在语法中添加一些注释信息。比如定位：`Expr` 是来自哪个文件的，具体到这个文件的哪一行哪一列。你可以在后面的阶段中使用这一特性，打印出错误定位，即使它们不是处于解析阶段。

* 练习 1：添加一个 `Program` 数据类型，可以按顺序包含多个 `Expr`
* 练习 2：向语法树中添加一个定位注解。

### 2、实现一个简单的解析器组合库

我们要做的第一件事情是定义一个<ruby> 嵌入式领域专用语言 <rt>  Embedded Domain Specific Language </rt></ruby>（EDSL），我们会用它来定义我们的语言解析器。这常常被称为解析器组合库。我们做这件事完全是出于学习的目的，Haskell 里有很好的解析库，在实际构建软件或者进行实验时，你应该使用它们。[megaparsec](https://mrkkrp.github.io/megaparsec/) 就是这样的一个库。

首先我们来谈谈解析库的实现的思路。本质上，我们的解析器就是一个函数，接受一些输入，可能会读取输入的一些或全部内容，然后返回解析出来的值和无法解析的输入部分，或者在解析失败时抛出异常。我们把它写出来。

```
newtype Parser a
  = Parser (ParseString -> Either ParseError (a, ParseString))

data ParseString
  = ParseString Name (Int, Int) String

data ParseError
  = ParseError ParseString Error

type Error = String
```

这里我们定义了三个主要的新类型。

第一个，`Parser a` 是之前讨论的解析函数。

第二个，`ParseString` 是我们的输入或携带的状态。它有三个重要的部分：

* `Name`: 这是源的名字
* `(Int, Int)`: 这是源的当前位置
* `String`: 这是等待解析的字符串

第三个，`ParseError` 包含了解析器的当前状态和一个错误信息。

现在我们想让这个解析器更灵活，我们将会定义一些常用类型的实例。这些实例让我们能够将小巧的解析器和复杂的解析器结合在一起（因此它的名字叫做 “解析器组合器”）。

第一个是 `Functor` 实例。我们需要 `Functor` 实例，因为我们要能够对解析值应用函数从而使用不同的解析器。当我们定义自己语言的解析器时，我们将会看到关于它的示例。

```
instance Functor Parser where
  fmap f (Parser parser) =
    Parser (\str -> first f <$> parser str)
```

第二个是 `Applicative` 实例。该实例的常见用例是在多个解析器中实现一个纯函数。

```
instance Applicative Parser where
  pure x = Parser (\str -> Right (x, str))
  (Parser p1) <*> (Parser p2) =
    Parser $
      \str -> do
        (f, rest)  <- p1 str
        (x, rest') <- p2 rest
        pure (f x, rest')

```

（注意：我们还会实现一个 Monad 实例，这样我们才能使用符号）

第三个是 `Alternative` 实例。万一前面的解析器解析失败了，我们要能够提供一个备用的解析器。

```
instance Alternative Parser where
  empty = Parser (`throwErr` "Failed consuming input")
  (Parser p1) <|> (Parser p2) =
    Parser $
      \pstr -> case p1 pstr of
        Right result -> Right result
        Left  _      -> p2 pstr
```

第四个是 `Monad` 实例。这样我们就能链接解析器。

```
instance Monad Parser where
  (Parser p1) >>= f =
    Parser $
     \str -> case p1 str of
       Left err -> Left err
       Right (rs, rest) ->
         case f rs of
           Parser parser -> parser rest
```

接下来，让我们定义一种的方式，用于运行解析器和防止失败的助手函数：

```
runParser :: String -> String -> Parser a -> Either ParseError (a, ParseString)
runParser name str (Parser parser) = parser $ ParseString name (0,0) str

throwErr :: ParseString -> String -> Either ParseError a
throwErr ps@(ParseString name (row,col) _) errMsg =
  Left $ ParseError ps $ unlines
    [ "*** " ++ name ++ ": " ++ errMsg
    , "* On row " ++ show row ++ ", column " ++ show col ++ "."
    ]

```

现在我们将会开始实现组合器，这是 EDSL 的 API，也是它的核心。

首先，我们会定义 `oneOf`。如果输入列表中的字符后面还有字符的话，`oneOf` 将会成功，否则就会失败。

```
oneOf :: [Char] -> Parser Char
oneOf chars =
  Parser $ \case
    ps@(ParseString name (row, col) str) ->
      case str of
        []     -> throwErr ps "Cannot read character of empty string"
        (c:cs) ->
          if c `elem` chars
          then Right (c, ParseString name (row, col+1) cs)
          else throwErr ps $ unlines ["Unexpected character " ++ [c], "Expecting one of: " ++ show chars]
```

`optional` 将会抛出异常，停止解析器。失败时它仅仅会返回 `Nothing`。

```
optional :: Parser a -> Parser (Maybe a)
optional (Parser parser) =
  Parser $
    \pstr -> case parser pstr of
      Left _ -> Right (Nothing, pstr)
      Right (x, rest) -> Right (Just x, rest)
```

`many` 将会试着重复运行解析器，直到失败。当它完成的时候，会返回成功运行的解析器列表。`many1` 做的事情是一样的，但解析失败时它至少会抛出一次异常。

```
many :: Parser a -> Parser [a]
many parser = go []
  where go cs = (parser >>= \c -> go (c:cs)) <|> pure (reverse cs)

many1 :: Parser a -> Parser [a]
many1 parser =
  (:) <$> parser <*> many parser
```

下面的这些解析器通过我们定义的组合器来实现一些特殊的解析器：

```
char :: Char -> Parser Char
char c = oneOf [c]

string :: String -> Parser String
string = traverse char

space :: Parser Char
space = oneOf " \n"

spaces :: Parser String
spaces = many space

spaces1 :: Parser String
spaces1 = many1 space

withSpaces :: Parser a -> Parser a
withSpaces parser =
  spaces *> parser <* spaces

parens :: Parser a -> Parser a
parens parser =
     (withSpaces $ char '(')
  *> withSpaces parser
  <* (spaces *> char ')')

sepBy :: Parser a -> Parser b -> Parser [b]
sepBy sep parser = do
  frst <- optional parser
  rest <- many (sep *> parser)
  pure $ maybe rest (:rest) frst
```

现在为该门语言定义解析器所需要的所有东西都有了。

* 练习 ：实现一个 EOF（end of file/input，即文件或输入终止符）解析器组合器。

### 3、为我们的语言实现解析器

我们会用自顶而下的方法定义解析器。

```
parseExpr :: Parser Expr
parseExpr = fmap ATOM parseAtom <|> fmap LIST parseList

parseList :: Parser [Expr]
parseList = parens $ sepBy spaces1 parseExpr

parseAtom :: Parser Atom
parseAtom = parseSymbol <|> parseInt

parseSymbol :: Parser Atom
parseSymbol = fmap Symbol parseName
```

注意到这四个函数是在我们这门语言中属于高阶描述。这解释了为什么 Haskell 执行解析工作这么棒。在定义完高级部分后，我们还需要定义低级别的 `parseName` 和 `parseInt`。

我们能在这门语言中用什么字符作为名字呢？用小写的字母、数字和下划线吧，而且名字的第一个字符必须是字母。

```
parseName :: Parser Name
parseName = do
  c  <- oneOf ['a'..'z']
  cs <- many $ oneOf $ ['a'..'z'] ++ "0123456789" ++ "_"
  pure (c:cs)
```

整数是一系列数字，数字前面可能有负号 `-`：

```
parseInt :: Parser Atom
parseInt = do
  sign <- optional $ char '-'
  num  <- many1 $ oneOf "0123456789"
  let result = read $ maybe num (:num) sign of
  pure $ Int result
```

最后，我们会定义用来运行解析器的函数，返回值可能是一个 `Expr` 或者是一条错误信息。

```
runExprParser :: Name -> String -> Either String Expr
runExprParser name str =
  case runParser name str (withSpaces parseExpr) of
    Left (ParseError _ errMsg) -> Left errMsg
    Right (result, _) -> Right result
```

* 练习 1 ：为第一节中定义的 `Program` 类型编写一个解析器
* 练习 2 ：用 Applicative 的形式重写 `parseName`
* 练习 3 ：`parseInt` 可能出现溢出情况，找到处理它的方法，不要用 `read`。

### 4、为这门语言实现一个更好看的输出器

我们还想做一件事，将我们的程序以源代码的形式打印出来。这对完善错误信息很有用。

```
printExpr :: Expr -> String
printExpr = printExpr' False 0

printAtom :: Atom -> String
printAtom = \case
  Symbol s -> s
  Int i -> show i

printExpr' :: Bool -> Int -> Expr -> String
printExpr' doindent level = \case
  ATOM a -> indent (bool 0 level doindent) (printAtom a)
  LIST (e:es) ->
    indent (bool 0 level doindent) $
      concat
        [ "("
        , printExpr' False (level + 1) e
        , bool "\n" "" (null es)
        , intercalate "\n" $ map (printExpr' True (level + 1)) es
        , ")"
        ]

indent :: Int -> String -> String
indent tabs e = concat (replicate tabs "  ") ++ e
```

* 练习 ：为第一节中定义的 `Program` 类型编写一个美观的输出器

好，目前为止我们写了近 200 行代码，这些代码一般叫做编译器的前端。我们还要写大概 150 行代码，用来执行三个额外的任务：我们需要根据需求定义一个 JS 的子集，定义一个将我们的语言转译成这个子集的转译器，最后把所有东西整合在一起。开始吧。

### 5、根据需求定义 JavaScript 的子集

首先，我们要定义将要使用的 JavaScript 的子集：

```
data JSExpr
  = JSInt Int
  | JSSymbol Name
  | JSBinOp JSBinOp JSExpr JSExpr
  | JSLambda [Name] JSExpr
  | JSFunCall JSExpr [JSExpr]
  | JSReturn JSExpr
    deriving (Eq, Show, Read)

type JSBinOp = String
```

这个数据类型表示 JavaScript 表达式。我们有两个原子类型 `JSInt` 和 `JSSymbol`，它们是由我们这个语言中的 `Atom` 转译来的，我们用 `JSBinOp` 来表示二元操作，比如 `+` 或 `*`，用 `JSLambda` 来表示匿名函数，和我们语言中的 `lambda expression（lambda 表达式）` 一样，我们将会用 `JSFunCall` 来调用函数，用 `let` 来引入新名字，用 `JSReturn` 从函数中返回值，在 JavaScript 中是需要返回值的。

`JSExpr` 类型是对 JavaScript 表达式的 **抽象表示**。我们会把自己语言中表达式的抽象表示 `Expr` 转译成 JavaScript 表达式的抽象表示 `JSExpr`。但为了实现这个功能，我们需要实现 `JSExpr` ，并从这个抽象表示中生成 JavaScript 代码。我们将通过递归匹配 `JSExpr` 实现，将 JS 代码当作 `String` 来输出。这和我们在 `printExpr` 中做的基本上是一样的。我们还会追踪元素的作用域，这样我们才可以用合适的方式缩进生成的代码。

```
printJSOp :: JSBinOp -> String
printJSOp op = op

printJSExpr :: Bool -> Int -> JSExpr -> String
printJSExpr doindent tabs = \case
  JSInt    i     -> show i
  JSSymbol name  -> name
  JSLambda vars expr -> (if doindent then indent tabs else id) $ unlines
    ["function(" ++ intercalate ", " vars ++ ") {"
    ,indent (tabs+1) $ printJSExpr False (tabs+1) expr
    ] ++ indent tabs "}"
  JSBinOp  op e1 e2  -> "(" ++ printJSExpr False tabs e1 ++ " " ++ printJSOp op ++ " " ++ printJSExpr False tabs e2 ++ ")"
  JSFunCall f exprs  -> "(" ++ printJSExpr False tabs f ++ ")(" ++ intercalate ", " (fmap (printJSExpr False tabs) exprs) ++ ")"
  JSReturn expr      -> (if doindent then indent tabs else id) $ "return " ++ printJSExpr False tabs expr ++ ";"
```

* 练习 1 ：添加 `JSProgram` 类型，它可以包含多个 `JSExpr` ，然后创建一个叫做 `printJSExprProgram` 的函数来生成代码。
* 练习 2 ：添加 `JSExpr` 的新类型：`JSIf`，并为其生成代码。

### 6、实现到我们定义的 JavaScript 子集的代码转译器

我们快做完了。这一节将会创建函数，将 `Expr` 转译成 `JSExpr`。

基本思想很简单，我们会将 `ATOM` 转译成 `JSSymbol` 或者 `JSInt`，然后会将 `LIST` 转译成一个函数调用或者转译的特例。

```
type TransError = String

translateToJS :: Expr -> Either TransError JSExpr
translateToJS = \case
  ATOM (Symbol s) -> pure $ JSSymbol s
  ATOM (Int i)    -> pure $ JSInt i
  LIST xs -> translateList xs

translateList :: [Expr] -> Either TransError JSExpr
translateList = \case
  []     -> Left "translating empty list"
  ATOM (Symbol s):xs
    | Just f <- lookup s builtins ->
      f xs
  f:xs ->
    JSFunCall <$> translateToJS f <*> traverse translateToJS xs
```

`builtins` 是一系列要转译的特例，就像 `lambada` 和 `let`。每一种情况都可以获得一系列参数，验证它是否合乎语法规范，然后将其转译成等效的 `JSExpr`。

```
type Builtin  = [Expr] -> Either TransError JSExpr
type Builtins = [(Name, Builtin)]

builtins :: Builtins
builtins =
  [("lambda", transLambda)
  ,("let", transLet)
  ,("add", transBinOp "add" "+")
  ,("mul", transBinOp "mul" "*")
  ,("sub", transBinOp "sub" "-")
  ,("div", transBinOp "div" "/")
  ,("print", transPrint)
  ]
```

我们这种情况，会将内建的特殊形式当作特殊的、非第一类的进行对待，因此不可能将它们当作第一类函数。

我们会把 Lambda 表达式转译成一个匿名函数：

```
transLambda :: [Expr] -> Either TransError JSExpr
transLambda = \case
  [LIST vars, body] -> do
    vars' <- traverse fromSymbol vars
    JSLambda vars' <$> (JSReturn <$> translateToJS body)

  vars ->
    Left $ unlines
      ["Syntax error: unexpected arguments for lambda."
      ,"expecting 2 arguments, the first is the list of vars and the second is the body of the lambda."
      ,"In expression: " ++ show (LIST $ ATOM (Symbol "lambda") : vars)
      ]

fromSymbol :: Expr -> Either String Name
fromSymbol (ATOM (Symbol s)) = Right s
fromSymbol e = Left $ "cannot bind value to non symbol type: " ++ show e
```

我们会将 `let` 转译成带有相关名字参数的函数定义，然后带上参数调用函数，因此会在这一作用域中引入变量：

```
transLet :: [Expr] -> Either TransError JSExpr
transLet = \case
  [LIST binds, body] -> do
    (vars, vals) <- letParams binds
    vars' <- traverse fromSymbol vars
    JSFunCall . JSLambda vars' <$> (JSReturn <$> translateToJS body) <*> traverse translateToJS vals
   where
    letParams :: [Expr] -> Either Error ([Expr],[Expr])
    letParams = \case
      [] -> pure ([],[])
      LIST [x,y] : rest -> ((x:) *** (y:)) <$> letParams rest
      x : _ -> Left ("Unexpected argument in let list in expression:\n" ++ printExpr x)

  vars ->
    Left $ unlines
      ["Syntax error: unexpected arguments for let."
      ,"expecting 2 arguments, the first is the list of var/val pairs and the second is the let body."
      ,"In expression:\n" ++ printExpr (LIST $ ATOM (Symbol "let") : vars)
      ]
```

我们会将可以在多个参数之间执行的操作符转译成一系列二元操作符。比如：`(add 1 2 3)` 将会变成 `1 + (2 + 3)`。

```
transBinOp :: Name -> Name -> [Expr] -> Either TransError JSExpr
transBinOp f _ []   = Left $ "Syntax error: '" ++ f ++ "' expected at least 1 argument, got: 0"
transBinOp _ _ [x]  = translateToJS x
transBinOp _ f list = foldl1 (JSBinOp f) <$> traverse translateToJS list
```

然后我们会将 `print` 转换成对 `console.log` 的调用。

```
transPrint :: [Expr] -> Either TransError JSExpr
transPrint [expr] = JSFunCall (JSSymbol "console.log") . (:[]) <$> translateToJS expr
transPrint xs     = Left $ "Syntax error. print expected 1 arguments, got: " ++ show (length xs)
```

注意，如果我们将这些代码当作 `Expr` 的特例进行解析，那我们就可能会跳过语法验证。

* 练习 1 ：将 `Program` 转译成 `JSProgram`
* 练习 2 ：为 `if Expr Expr Expr` 添加一个特例，并将它转译成你在上一次练习中实现的 `JSIf` 条件语句。

### 7、把所有东西整合到一起

最终，我们将会把所有东西整合到一起。我们会：

1. 读取文件
2. 将文件解析成 `Expr`
3. 将文件转译成 `JSExpr`
4. 将 JavaScript 代码发送到标准输出流

我们还会启用一些用于测试的标志位：

* `--e` 将进行解析并打印出表达式的抽象表示（`Expr`）
* `--pp` 将进行解析，美化输出
* `--jse` 将进行解析、转译、并打印出生成的 JS 表达式（`JSExpr`）的抽象表示
* `--ppc` 将进行解析，美化输出并进行编译

```
main :: IO ()
main = getArgs >>= \case
  [file] ->
    printCompile =<< readFile file
  ["--e",file] ->
    either putStrLn print . runExprParser "--e" =<< readFile file
  ["--pp",file] ->
    either putStrLn (putStrLn . printExpr) . runExprParser "--pp" =<< readFile file
  ["--jse",file] ->
    either print (either putStrLn print . translateToJS) . runExprParser "--jse" =<< readFile file
  ["--ppc",file] ->
    either putStrLn (either putStrLn putStrLn) . fmap (compile . printExpr) . runExprParser "--ppc" =<< readFile file
  _ ->
    putStrLn $ unlines
      ["Usage: runghc Main.hs [ --e, --pp, --jse, --ppc ] <filename>"
      ,"--e     print the Expr"
      ,"--pp    pretty print Expr"
      ,"--jse   print the JSExpr"
      ,"--ppc   pretty print Expr and then compile"
      ]

printCompile :: String -> IO ()
printCompile = either putStrLn putStrLn . compile

compile :: String -> Either Error String
compile str = printJSExpr False 0 <$> (translateToJS =<< runExprParser "compile" str)

```

大功告成。将自己的语言编译到 JS 子集的编译器已经完成了。再说一次，你可以在 [这里](https://gist.github.com/soupi/d4ff0727ccb739045fad6cdf533ca7dd) 看到完整的源文件。

用我们的编译器运行第一节的示例，产生的 JavaScript 代码如下：

```
$ runhaskell Lisp.hs example.lsp
(function(compose, square, add1) {
  return (console.log)(((compose)(square, add1))(5));
})(function(f, g) {
  return function(x) {
    return (f)((g)(x));
  };
}, function(x) {
  return (x * x);
}, function(x) {
  return (x + 1);
})
```

如果你在自己电脑上安装了 node.js，你可以用以下命令运行这段代码：

```
$ runhaskell Lisp.hs example.lsp | node -p
36
undefined
```

* 最终练习 : 编译有多个表达式的程序而非仅编译一个表达式。

---

via: <https://gilmi.me/blog/post/2016/10/14/lisp-to-js>

作者：[Gil Mizrahi](https://gilmi.me/home) 选题：[oska874](https://github.com/oska874) 译者：[BriFuture](https://github.com/BriFuture) 校对：[wxy](https://github.com/wxy)

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


重启和关闭 Linux 系统的 6 个终端命令

# 重启和关闭 Linux 系统的 6 个终端命令

<img src="content_image/album_201810_31_205455k6w9oawuwpbifku9.png" alt="" title="">

在 Linux 管理员的日程当中，有很多需要执行的任务，其中就有系统的重启和关闭。

对于 Linux 管理员来说，重启和关闭系统是其诸多风险操作中的一例，有时候，由于某些原因，这些操作可能无法挽回，他们需要更多的时间来排查问题。

在 Linux 命令行模式下我们可以执行这些任务。很多时候，由于熟悉命令行，Linux 管理员更倾向于在命令行下完成这些任务。

重启和关闭系统的 Linux 命令并不多，用户需要根据需要，选择合适的命令来完成任务。

以下所有命令都有其自身特点，并允许被 Linux 管理员使用.

**建议阅读：**

* [查看系统/服务器正常运行时间的 11 个方法](https://www.2daygeek.com/11-methods-to-find-check-system-server-uptime-in-linux/)
* [Tuptime 一款为 Linux 系统保存历史记录、统计运行时间工具](https://www.2daygeek.com/tuptime-a-tool-to-report-the-historical-and-statistical-running-time-of-linux-system/)

系统重启和关闭之始，会通知所有已登录的用户和进程。当然，如果使用了时间参数，系统将拒绝新的用户登入。

执行此类操作之前，我建议您坚持复查，因为您只能得到很少的提示来确保这一切顺利。

下面陈列了一些步骤：

* 确保您拥有一个可以处理故障的控制台，以防之后可能会发生的问题。 VMWare 可以访问虚拟机，而 IPMI、iLO 和 iDRAC 可以访问物理服务器。
* 您需要通过公司的流程，申请修改或故障的执行权直到得到许可。
* 为安全着想，备份重要的配置文件，并保存到其他服务器上.
* 验证日志文件（提前检查）
* 和相关团队交流，比如数据库管理团队，应用团队等。
* 通知数据库和应用服务人员关闭服务，并得到确定答复。
* 使用适当的命令复盘操作，验证工作。
* 最后，重启系统。
* 验证日志文件，如果一切顺利，执行下一步操作，如果发现任何问题，对症排查。
* 无论是回退版本还是运行程序，通知相关团队提出申请。
* 对操作做适当守候，并将预期的一切正常的反馈给团队

使用下列命令执行这项任务。

* `shutdown`、`halt`、`poweroff`、`reboot` 命令：用来停机、重启或切断电源
* `init` 命令：是 “initialization” 的简称，是系统启动的第一个进程。
* `systemctl` 命令：systemd 是 Linux 系统和服务器的管理程序。

### 方案 1：如何使用 shutdown 命令关闭和重启 Linux 系统

`shutdown` 命令用于断电或重启本地和远程的 Linux 机器。它为高效完成作业提供多个选项。如果使用了时间参数，系统关闭的 5 分钟之前，会创建 `/run/nologin` 文件，以确保后续的登录会被拒绝。

通用语法如下：

```
# shutdown [OPTION] [TIME] [MESSAGE]
```

运行下面的命令来立即关闭 Linux 机器。它会立刻杀死所有进程，并关闭系统。

```
# shutdown -h now
```

* `-h`：如果不特指 `-halt` 选项，这等价于 `-poweroff` 选项。

另外我们可以使用带有 `-halt` 选项的 `shutdown` 命令来立即关闭设备。

```
# shutdown --halt now
或者
# shutdown -H now
```

* `-H, --halt`：停止设备运行

另外我们可以使用带有 `poweroff` 选项的 `shutdown` 命令来立即关闭设备。

```
# shutdown --poweroff now
或者
# shutdown -P now
```

* `-P, --poweroff`：切断电源（默认）。

如果您没有使用时间选项运行下面的命令，它将会在一分钟后执行给出的命令。

```
# shutdown -h
Shutdown scheduled for Mon 2018-10-08 06:42:31 EDT, use 'shutdown -c' to cancel.

root@2daygeek.com#
Broadcast message from root@vps.2daygeek.com (Mon 2018-10-08 06:41:31 EDT):

The system is going down for power-off at Mon 2018-10-08 06:42:31 EDT!
```

其他的登录用户都能在中断中看到如下的广播消息：

```
[daygeek@2daygeek.com ~]$
Broadcast message from root@2daygeek.com (Mon 2018-10-08 06:41:31 EDT):

The system is going down for power-off at Mon 2018-10-08 06:42:31 EDT!
```

对于使用了 `-halt` 选项：

```
# shutdown -H
Shutdown scheduled for Mon 2018-10-08 06:37:53 EDT, use 'shutdown -c' to cancel.

root@2daygeek.com#
Broadcast message from root@vps.2daygeek.com (Mon 2018-10-08 06:36:53 EDT):

The system is going down for system halt at Mon 2018-10-08 06:37:53 EDT!
```

对于使用了 `-poweroff` 选项：

```
# shutdown -P
Shutdown scheduled for Mon 2018-10-08 06:40:07 EDT, use 'shutdown -c' to cancel.

root@2daygeek.com#
Broadcast message from root@vps.2daygeek.com (Mon 2018-10-08 06:39:07 EDT):

The system is going down for power-off at Mon 2018-10-08 06:40:07 EDT!
```

可以在您的终端上敲击 `shutdown -c` 选项取消操作。

```
# shutdown -c

Broadcast message from root@vps.2daygeek.com (Mon 2018-10-08 06:39:09 EDT):

The system shutdown has been cancelled at Mon 2018-10-08 06:40:09 EDT!
```

其他的登录用户都能在中断中看到如下的广播消息：

```
[daygeek@2daygeek.com ~]$
Broadcast message from root@vps.2daygeek.com (Mon 2018-10-08 06:41:35 EDT):

The system shutdown has been cancelled at Mon 2018-10-08 06:42:35 EDT!
```

添加时间参数，如果你想在 `N` 秒之后执行关闭或重启操作。这里，您可以为所有登录用户添加自定义广播消息。例如，我们将在五分钟后重启设备。

```
# shutdown -r +5 "To activate the latest Kernel"
Shutdown scheduled for Mon 2018-10-08 07:13:16 EDT, use 'shutdown -c' to cancel.

[root@vps138235 ~]#
Broadcast message from root@vps.2daygeek.com (Mon 2018-10-08 07:08:16 EDT):

To activate the latest Kernel
The system is going down for reboot at Mon 2018-10-08 07:13:16 EDT!
```

运行下面的命令立即重启 Linux 机器。它会立即杀死所有进程并且重新启动系统。

```
# shutdown -r now
```

* `-r, --reboot`： 重启设备。

### 方案 2：如何通过 reboot 命令关闭和重启 Linux 系统

`reboot` 命令用于关闭和重启本地或远程设备。`reboot` 命令拥有两个实用的选项。

它能够优雅的关闭和重启设备（就好像在系统菜单中惦记重启选项一样简单）。

执行不带任何参数的 `reboot` 命令来重启 Linux 机器。

```
# reboot
```

执行带 `-p` 参数的 `reboot` 命令来关闭 Linux 机器电源。

```
# reboot -p
```

* `-p, --poweroff`：调用 `halt` 或 `poweroff` 命令，切断设备电源。

执行带 `-f` 参数的 `reboot` 命令来强制重启 Linux 设备（这类似按压机器上的电源键）。

```
# reboot -f
```

* `-f, --force`：立刻强制中断，切断电源或重启。

### 方案 3：如何通过 init 命令关闭和重启 Linux 系统

`init`（“initialization” 的简写）是系统启动的第一个进程。

它将会检查 `/etc/inittab` 文件并决定 linux 运行级别。同时，允许用户在 Linux 设备上执行关机或重启操作. 这里存在从 `0` 到 `6` 的七个运行等级。

**建议阅读：**

* [如何检查 Linux 上所有运行的服务](https://www.2daygeek.com/how-to-check-all-running-services-in-linux/)

执行以下 `init` 命令关闭系统。

```
# init 0
```

* `0`： 停机 – 关闭系统。

运行下面的 `init` 命令重启设备：

```
# init 6
```

* `6`：重启 – 重启设备。

### 方案 4：如何通过 halt 命令关闭和重启 Linux 系统

`halt` 命令用来切断电源或关闭远程 Linux 机器或本地主机。 中断所有进程并关闭 cpu。

```
# halt
```

### 方案 5：如何通过 poweroff 命令关闭和重启 Linux 系统

`poweroff` 命令用来切断电源或关闭远程 Linux 机器或本地主机。 `poweroff` 很像 `halt`，但是它可以关闭设备硬件（灯和其他 PC 上的其它东西）。它会给主板发送 ACPI 指令，然后信号发送到电源，切断电源。

```
# poweroff
```

### 方案 6：如何通过 systemctl 命令关闭和重启 Linux 系统

systemd 是一款适用于所有主流 Linux 发型版的全新 init 系统和系统管理器，而不是传统的 SysV init 系统。

systemd 兼容与 SysV 和 LSB 初始化脚本。它能够替代 SysV init 系统。systemd 是内核启动的第一个进程，并持有序号为 1 的进程 PID。

**建议阅读：**

* [chkservice – 一款终端下系统单元管理工具](https://www.2daygeek.com/chkservice-a-tool-for-managing-systemd-units-from-linux-terminal/)

它是一切进程的父进程，Fedora 15 是第一个适配安装 systemd （替代了 upstart）的发行版。

`systemctl` 是命令行下管理 systemd 守护进程和服务的主要工具（如 `start`、`restart`、`stop`、`enable`、`disable`、`reload` & `status`）。

systemd 使用 .service 文件而不是 SysV init 使用的 bash 脚本。 systemd 将所有守护进程归与自身的 Linux cgroups 用户组下，您可以浏览 `/cgroup/systemd` 文件查看该系统层次等级。

```
# systemctl halt
# systemctl poweroff
# systemctl reboot
# systemctl suspend
# systemctl hibernate
```

---

via: <https://www.2daygeek.com/6-commands-to-shutdown-halt-poweroff-reboot-the-linux-system/>

作者：[Prakash Subramanian](https://www.2daygeek.com/author/prakash/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[cyleft](https://github.com/cyleft) 校对：[wxy](https://github.com/wxy)

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


Linux 中国通证商城发布

Summary: 这次上线的“Linux 中国通证商城”—— https://shop.linux.cn ，是基于 WooCommerce 所构建的，并专门自行开发了支持 ERC20 通证的插件，以支持我们的 LCCN 通证的链上支付。

# Linux 中国通证商城发布

在我们发布了 Linux 中国的[社区通证 LCCN](/article-9886-1.html) 之后，我们又在通证经济建设方向迈出了一步。通证作为一个经济体系中流转的价值凭证，其不但可以根据社区成员的行为进行精细的通证分发，而且还需要建立通证的流通渠道。

按照我们之前的设计，我们流通 LCCN 的通道有二：

1. 社区提供通证的 B2C 消费渠道
2. 通证持有者个人的通证消费渠道

作为社区，我们可以将社区所拥有的大部分资源，比如媒体资源、客户置换资源、定制礼品等以 LCCN 兑换的方式提供给社区成员。比如这次，我们就将官方网站的广告位、认证微信的文章推送、认证微博的转发等资源开放给社区来兑换。我们也同时将从合作伙伴中置换和赞助来的资源（如兑换券、书籍等）。

此外，我们也小规模组织了二手物品的交换群，可供大家用 LCCN 交换其他人手中的闲置物品。目前已经发生了多笔交易，交易了包括手机、树莓派、书籍等物品，最高交易额高达 Ⓛ28800。

这次上线的“Linux 中国通证商城”—— <https://shop.linux.cn> ，是基于 WooCommerce 所构建的，并专门自行开发了支持 ERC20 通证的插件，以支持我们的 LCCN 通证的链上支付。当然，作为开源社区，我们的插件同样遵循开源精神，开源到了 [GitHub](https://github.com/inKerk/woocommerce-erc20-payment-gateway) 上。

我们的通证商城的上线，得到了人民邮电出版社、UCloud、刘遄老师等的大力支持。其中刘遄老师捐献了其畅销书《Linux 就该这么学》 多达 30 册。由衷感谢各位伙伴的支持！

欢迎大家体验和参与贡献，也欢迎各位合作伙伴参与我们的生态建设。


用 Pandoc 生成一篇调研论文

Summary: 学习如何用 Markdown 管理章节引用、图像、表格以及更多。

学习如何用 Markdown 管理章节引用、图像、表格以及更多。

# 用 Pandoc 生成一篇调研论文

>
> 学习如何用 Markdown 管理章节引用、图像、表格以及更多。
>
>
>

这篇文章对于使用 [Markdown](https://en.wikipedia.org/wiki/Markdown) 语法做一篇调研论文进行了一个深度体验。覆盖了如何创建和引用章节、图像（用 Markdown 和 [LaTeX](https://www.latex-project.org/)）和参考书目。我们也讨论了一些棘手的案例和为什么使用 LaTex 是一个正确的做法。

### 调研

调研论文一般包括对章节、图像、表格和参考书目的引用。[Pandoc](https://pandoc.org/) 本身并不能交叉引用这些，但是它能够利用 [pandoc-crossref](http://lierdakil.github.io/pandoc-crossref/) 过滤器来完成自动编号和章节、图像、表格的交叉引用。

让我们从重写原本以 LaTax 撰写的 [一个教育调研报告的例子](https://dl.acm.org/citation.cfm?id=3270118) 开始，然后用 Markdown（和一些 LaTax）、Pandoc 和 Pandoc-crossref 重写。

#### 添加并引用章节

要想章节被自动编号，必须使用 Markdown H1 标题编写。子章节使用 H2-H4 子标题编写（通常不需要更多级别了）。例如一个章节的标题是 “Implementation”，写作 `# Implementation {#sec: implementation}`，然后 Pandoc 会把它转化为 `3. Implementation`（或者转换为相应的章节编号）。`Implementation` 这个标题使用了 H1 并且声明了一个 `{#sec: implementation}` 的标签，这是作者用于引用该章节的标签。要想引用一个章节，输入 `@` 符号并跟上对应章节标签，使用方括号括起来即可： `[@ sec:implementation]`

[在这篇论文中](https://dl.acm.org/citation.cfm?id=3270118), 我们发现了下面这个例子：

```
we lack experience (consistency between TAs, [@sec:implementation]).
```

Pandoc 转换：

```
we lack experience (consistency between TAs, Section 4).
```

章节被自动编号（这在本文最后的 `Makefile` 当中说明）。要创建无编号的章节，输入章节的标题并在最后添加 `{-}`。例如：`### Designing a game for maintainability {-}` 就以标题 “Designing a game for maintainability”，创建了一个无标号的章节。

#### 添加并引用图像

添加并引用一个图像，跟添加并引用一个章节和添加一个 Markdown 图片很相似：

```
{#fig:scatter-matrix}
```

上面这一行是告诉 Pandoc，有一个标有 Scatterplot matrix 的图像以及这张图片路径是 `data/scatterplots/RScatterplotMatrix2.png`。`{#fig:scatter-matrix}` 表明了用于引用该图像的名字。

这里是从一篇论文中进行图像引用的例子：

```
The boxes "Enjoy", "Grade" and "Motivation" ([@fig:scatter-matrix]) ...
```

Pandoc 产生如下输出：

```
The boxes "Enjoy", "Grade" and "Motivation" (Fig. 1) ...
```

#### 添加及引用参考书目

大多数调研报告都把引用放在一个 BibTeX 的数据库文件中。在这个例子中，该文件被命名为 [biblio.bib](https://github.com/kikofernandez/pandoc-examples/blob/master/research-paper/biblio.bib)，它包含了论文中所有的引用。下面是这个文件的样子：

```
@inproceedings{wrigstad2017mastery,
    Author =       {Wrigstad, Tobias and Castegren, Elias},
    Booktitle =    {SPLASH-E},
    Title =        {Mastery Learning-Like Teaching with Achievements},
    Year =         2017
}

@inproceedings{review-gamification-framework,
  Author =       {A. Mora and D. Riera and C. Gonzalez and J. Arnedo-Moreno},
  Publisher =    {IEEE},
  Booktitle =    {2015 7th International Conference on Games and Virtual Worlds
                  for Serious Applications (VS-Games)},
  Doi =          {10.1109/VS-GAMES.2015.7295760},
  Keywords =     {formal specification;serious games (computing);design
                  framework;formal design process;game components;game design
                  elements;gamification design frameworks;gamification-based
                  solutions;Bibliographies;Context;Design
                  methodology;Ethics;Games;Proposals},
  Month =        {Sept},
  Pages =        {1-8},
  Title =        {A Literature Review of Gamification Design Frameworks},
  Year =         2015,
  Bdsk-Url-1 =   {http://dx.doi.org/10.1109/VS-GAMES.2015.7295760}
}

...
```

第一行的 `@inproceedings{wrigstad2017mastery,` 表明了出版物 的类型（`inproceedings`），以及用来指向那篇论文的标签（`wrigstad2017mastery`）。

引用这篇题为 “Mastery Learning-Like Teaching with Achievements” 的论文, 输入：

```
the achievement-driven learning methodology [@wrigstad2017mastery]
```

Pandoc 将会输出：

```
the achievement- driven learning methodology [30]
```

这篇论文将会产生像下面这样被标号的参考书目：

引用文章的集合也很容易：只要引用使用分号 `;` 分隔开被标记的参考文献就可以了。如果一个引用有两个标签 —— 例如： `SEABORN201514` 和 `gamification-leaderboard-benefits`—— 像下面这样把它们放在一起引用：

```
Thus, the most important benefit is its potential to increase students' motivation
and engagement [@SEABORN201514;@gamification-leaderboard-benefits].
```

Pandoc 将会产生：

```
Thus, the most important benefit is its potential to increase students’ motivation
and engagement [26, 28]
```

### 问题案例

一个常见的问题是所需项目与页面不匹配。不匹配的部分会自动移动到它们认为合适的地方，即便这些位置并不是读者期望看到的位置。因此在图像或者表格接近于它们被提及的地方时，我们需要调节一下那些元素放置的位置，使得它们更加易于阅读。为了达到这个效果，我建议使用 `figure` 这个 LaTeX 环境参数，它可以让用户控制图像的位置。

我们看一个上面提到的图像的例子：

```
{#fig:scatter-matrix}
```

然后使用 LaTeX 重写：

```
\begin{figure}[t]
\includegraphics{data/scatterplots/RScatterplotMatrix2.png}
\caption{\label{fig:matrix}Scatterplot matrix}
\end{figure}
```

在 LaTeX 中，`figure` 环境参数中的 `[t]` 选项表示这张图用该位于该页的最顶部。有关更多选项，参阅 [LaTex/Floats, Figures, and Captions](https://en.wikibooks.org/wiki/LaTeX/Floats,_Figures_and_Captions#Figures) 这篇 Wikibooks 的文章。

### 产生一篇论文

到目前为止，我们讲了如何添加和引用（子）章节、图像和参考书目，现在让我们重温一下如何生成一篇 PDF 格式的论文。要生成 PDF，我们将使用 Pandoc 生成一篇可以被构建成最终 PDF 的 LaTeX 文件。我们还会讨论如何以 LaTeX，使用一套自定义的模板和元信息文件生成一篇调研论文，以及如何将 LaTeX 文档编译为最终的 PDF 格式。

很多会议都提供了一个 .cls 文件或者一套论文应有样式的模板；例如，它们是否应该使用两列的格式以及其它的设计风格。在我们的例子中，会议提供了一个名为 `acmart.cls` 的文件。

作者通常想要在他们的论文中包含他们所属的机构，然而，这个选项并没有包含在默认的 Pandoc 的 LaTeX 模板（注意，可以通过输入 `pandoc -D latex` 来查看 Pandoc 模板）当中。要包含这个内容，找一个 Pandoc 默认的 LaTeX 模板，并添加一些新的内容。将这个模板像下面这样复制进一个名为 `mytemplate.tex` 的文件中：

```
pandoc -D latex > mytemplate.tex
```

默认的模板包含以下代码：

```
$if(author)$
\author{$for(author)$$author$$sep$ \and $endfor$}
$endif$
$if(institute)$
\providecommand{\institute}[1]{}
\institute{$for(institute)$$institute$$sep$ \and $endfor$}
$endif$
```

因为这个模板应该包含作者的联系方式和电子邮件地址，在其他一些选项之间，我们更新这个模板以添加以下内容（我们还做了一些其他的更改，但是因为文件的长度，就没有包含在此处）：

```
latex
$for(author)$
    $if(author.name)$
        \author{$author.name$}
        $if(author.affiliation)$
            \affiliation{\institution{$author.affiliation$}}
        $endif$
        $if(author.email)$
            \email{$author.email$}
        $endif$
    $else$
        $author$
    $endif$
$endfor$
```

要让这些更改起作用，我们还应该有下面的文件：

* `main.md` 包含调研论文
* `biblio.bib` 包含参考书目数据库
* `acmart.cls` 我们使用的文档的集合
* `mytemplate.tex` 是我们使用的模板文件（代替默认的）

让我们添加论文的元信息到一个 `meta.yaml` 文件：

```
---
template: 'mytemplate.tex'
documentclass: acmart
classoption: sigconf
title: The impact of opt-in gamification on `\\`{=latex} students' grades in a software design course
author:
- name: Kiko Fernandez-Reyes
  affiliation: Uppsala University
  email: kiko.fernandez@it.uu.se
- name: Dave Clarke
  affiliation: Uppsala University
  email: dave.clarke@it.uu.se
- name: Janina Hornbach
  affiliation: Uppsala University
  email: janina.hornbach@fek.uu.se
bibliography: biblio.bib
abstract: |
  An achievement-driven methodology strives to give students more control over their learning with enough flexibility to engage them in deeper learning. (more stuff continues)

include-before: |
      \` ``{=latex}
      \copyrightyear{2018}
      \acmYear{2018}
      \setcopyright{acmlicensed}
      \acmConference[MODELS '18 Companion]{ACM/IEEE 21th International Conference on Model Driven Engineering Languages and Systems}{October 14--19, 2018}{Copenhagen, Denmark}
      \acmBooktitle{ACM/IEEE 21th International Conference on Model Driven Engineering Languages and Systems (MODELS '18 Companion), October 14--19, 2018, Copenhagen, Denmark}
      \acmPrice{XX.XX}
      \acmDOI{10.1145/3270112.3270118}
      \acmISBN{978-1-4503-5965-8/18/10}

      \begin{CCSXML}
      <ccs2012>
      <concept>
      <concept_id>10010405.10010489</concept_id>
      <concept_desc>Applied computing~Education</concept_desc>
      <concept_significance>500</concept_significance>
      </concept>
      </ccs2012>
      \end{CCSXML}

      \ccsdesc[500]{Applied computing~Education}

      \keywords{gamification, education, software design, UML}
      \` ``
figPrefix:
  - "Fig."
  - "Figs."
secPrefix:
  - "Section"
  - "Sections"
...
```

这个元信息文件使用 LaTeX 设置下列参数：

* `template` 指向使用的模板（`mytemplate.tex`）
* `documentclass` 指向使用的 LaTeX 文档集合（`acmart`）
* `classoption` 是在 `sigconf` 的案例中，指向这个类的选项
* `title` 指定论文的标题
* `author` 是一个包含例如 `name`、`affiliation` 和 `email` 的地方
* `bibliography` 指向包含参考书目的文件（`biblio.bib`）
* `abstract` 包含论文的摘要
* `include-before` 是这篇论文的具体内容之前应该被包含的信息；在 LaTeX 中被称为 [前言](https://www.sharelatex.com/learn/latex/Creating_a_document_in_LaTeX#The_preamble_of_a_document)。我在这里包含它去展示如何产生一篇计算机科学的论文，但是你可以选择跳过
* `figPrefix` 指向如何引用文档中的图像，例如：当引用图像的 `[@fig:scatter-matrix]` 时应该显示什么。例如，当前的 `figPrefix` 在这个例子 `The boxes "Enjoy", "Grade" and "Motivation" ([@fig:scatter-matrix])`中，产生了这样的输出：`The boxes "Enjoy", "Grade" and "Motivation" (Fig. 3)`。如果这里有很多图像，目前的设置表明它应该在图像号码旁边显示 `Figs.`
* `secPrefix` 指定如何引用文档中其他地方提到的部分（类似之前的图像和概览）

现在已经设置好了元信息，让我们来创建一个 `Makefile`，它会产生你想要的输出。`Makefile` 使用 Pandoc 产生 LaTeX 文件，`pandoc-crossref` 产生交叉引用，`pdflatex` 构建 LaTeX 为 PDF，`bibtex` 处理引用。

`Makefile` 已经展示如下：

```
all: paper

paper:
        @pandoc -s -F pandoc-crossref --natbib meta.yaml --template=mytemplate.tex -N \
         -f markdown -t latex+raw_tex+tex_math_dollars+citations -o main.tex main.md
        @pdflatex main.tex &> /dev/null
        @bibtex main &> /dev/null
        @pdflatex main.tex &> /dev/null
        @pdflatex main.tex &> /dev/null

clean:
        rm main.aux main.tex main.log main.bbl main.blg main.out

.PHONY: all clean paper
```

Pandoc 使用下面的标记：

* `-s` 创建一个独立的 LaTeX 文档
* `-F pandoc-crossref` 利用 `pandoc-crossref` 进行过滤
* `--natbib` 用 `natbib` （你也可以选择 `--biblatex`）对参考书目进行渲染
* `--template` 设置使用的模板文件
* `-N` 为章节的标题编号
* `-f` 和 `-t` 指定从哪个格式转换到哪个格式。`-t` 通常包含格式和 Pandoc 使用的扩展。在这个例子中，我们标明的 `raw_tex+tex_math_dollars+citations` 允许在 Markdown 中使用 `raw_tex` LaTeX。 `tex_math_dollars` 让我们能够像在 LaTeX 中一样输入数学符号，`citations` 让我们可以使用 [这个扩展](http://pandoc.org/MANUAL.html#citations)。

要从 LaTeX 产生 PDF，按 [来自bibtex](http://www.bibtex.org/Using/) 的指导处理参考书目：

```
@pdflatex main.tex &> /dev/null
@bibtex main &> /dev/null
@pdflatex main.tex &> /dev/null
@pdflatex main.tex &> /dev/null
```

脚本用 `@` 忽略输出，并且重定向标准输出和错误到 `/dev/null` ，因此我们在使用这些命令的可执行文件时不会看到任何的输出。

最终的结果展示如下。这篇文章的库可以在 [GitHub](https://github.com/kikofernandez/pandoc-examples/tree/master/research-paper) 找到：

### 结论

在我看来，研究的重点是协作、思想的传播，以及在任何一个恰好存在的领域中改进现有的技术。许多计算机科学家和工程师使用 LaTeX 文档系统来写论文，它对数学提供了完美的支持。来自社会科学的研究人员似乎更喜欢 DOCX 文档。

当身处不同社区的研究人员一同写一篇论文时，他们首先应该讨论一下他们将要使用哪种格式。然而如果包含太多的数学符号，DOCX 对于工程师来说不会是最简便的选择，LaTeX 对于缺乏编程经验的研究人员来说也有一些问题。就像这篇文章中展示的，Markdown 是一门工程师和社会科学家都很轻易能够使用的语言。

---

via: <https://opensource.com/article/18/9/pandoc-research-paper>

作者：[Kiko Fernandez-Reyes](https://opensource.com/users/kikofernandez) 选题：[lujun9972](https://github.com/lujun9972) 译者：[dianbanjiu](https://github.com/dianbanjiu) 校对：[wxy](https://github.com/wxy)

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


Flameshot：一个简洁但功能丰富的截图工具

Summary: 在本教程中，我们将看到如何安装 Flameshot 以及如何使用它来截图。

在本教程中，我们将看到如何安装 Flameshot 以及如何使用它来截图。

# Flameshot：一个简洁但功能丰富的截图工具

<img src="content_image/album_201811_01_131936ytmy79zy9fvf69vl.png" alt="" title="">

截图是我工作的一部分，我先前使用深度截图工具来截图，深度截图是一个简单、轻量级且非常简洁的截图工具。它自带许多功能例如窗口识别、快捷键支持、图片编辑、延时截图、社交分享、智能存储以及图片清晰度调整等功能。今天我碰巧发现了另一个具备多种功能的截图工具，它就是 **Flameshot** ，一个简单但功能丰富的针对类 Unix 系统的截图工具。它简单易用，可定制并且有选项可以支持上传截图到在线图片分享网站 **imgur** 上。同时 Flameshot 有一个 CLI 版本，所以你也可以从命令行来进行截图。Flameshot 是一个完全免费且开源的工具。在本教程中，我们将看到如何安装 Flameshot 以及如何使用它来截图。

### 安装 Flameshot

**在 Arch Linux 上：**

Flameshot 可以从 Arch LInux 的 [community] 仓库中获取。确保你已经启用了 community 仓库，然后就可以像下面展示的那样使用 pacman 来安装 Flameshot ：

```
$ sudo pacman -S flameshot
```

它也可以从 [**AUR**](https://aur.archlinux.org/packages/flameshot-git) 中获取，所以你还可以使用任意一个 AUR 帮助程序（例如 [**Yay**](https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/)）来在基于 Arch 的系统中安装它：

```
$ yay -S flameshot-git
```

**在 Fedora 中：**

```
$ sudo dnf install flameshot
```

在 **Debian 10+** 和 **Ubuntu 18.04+** 中，可以使用 APT 包管理器来安装它：

```
$ sudo apt install flameshot
```

**在 openSUSE 上：**

```
$ sudo zypper install flameshot
```

在其他的 Linux 发行版中，可以从源代码编译并安装它。编译过程中需要 **Qt version 5.3** 以及 **GCC 4.9.2** 或者它们的更高版本。

### 使用

可以从菜单或者应用启动器中启动 Flameshot。在 MATE 桌面环境，它通常可以在 “Applications -> Graphics” 下找到。

一旦打开了它，你就可以在系统面板中看到 Flameshot 的托盘图标。

**注意：**

假如你使用 Gnome 桌面环境，为了能够看到系统托盘图标，你需要安装 [TopIcons](https://extensions.gnome.org/extension/1031/topicons/) 扩展。

在 Flameshot 托盘图标上右击，你便会看到几个菜单项，例如打开配置窗口、信息窗口以及退出该应用。

要进行截图，只需要点击托盘图标就可以了。接着你将看到如何使用 Flameshot 的帮助窗口。选择一个截图区域，然后敲回车键便可以截屏了，点击右键便可以看到颜色拾取器，再敲空格键便可以查看屏幕侧边的面板。你可以使用鼠标的滚轮来增加或者减少指针的宽度。

Flameshot 自带一系列非常好的功能，例如：

* 可以进行手写
* 可以划直线
* 可以画长方形或者圆形框
* 可以进行长方形区域选择
* 可以画箭头
* 可以对要点进行标注
* 可以添加文本
* 可以对图片或者文字进行模糊处理
* 可以展示图片的尺寸大小
* 在编辑图片是可以进行撤销和重做操作
* 可以将选择的东西复制到剪贴板
* 可以保存选区
* 可以离开截屏
* 可以选择另一个 app 来打开图片
* 可以上传图片到 imgur 网站
* 可以将图片固定到桌面上

下面是一个示例的视频：

<http://www.ostechnix.com/wp-content/uploads/2018/09/Flameshot-demo.mp4>

### 快捷键

Frameshot 也支持快捷键。在 Flameshot 的托盘图标上右击并点击 “Information” 窗口便可以看到在 GUI 模式下所有可用的快捷键。下面是在 GUI 模式下可用的快捷键清单：

| 快捷键 | 描述 |
| --- | --- |
| `←`、`↓`、`↑`、`→` | 移动选择区域 1px |
| `Shift` + `←`、`↓`、`↑`、`→` | 将选择区域大小更改 1px |
| `Esc` | 退出截图 |
| `Ctrl` + `C` | 复制到粘贴板 |
| `Ctrl` + `S` | 将选择区域保存为文件 |
| `Ctrl` + `Z` | 撤销最近的一次操作 |
| 鼠标右键 | 展示颜色拾取器 |
| 鼠标滚轮 | 改变工具的宽度 |

边按住 `Shift` 键并拖动选择区域的其中一个控制点将会对它相反方向的控制点做类似的拖放操作。

### 命令行选项

Flameshot 也支持一系列的命令行选项来延时截图和保存图片到自定义的路径。

要使用 Flameshot GUI 模式，运行：

```
$ flameshot gui
```

要使用 GUI 模式截屏并将你选取的区域保存到一个自定义的路径，运行：

```
$ flameshot gui -p ~/myStuff/captures
```

要延时 2 秒后打开 GUI 模式可以使用：

```
$ flameshot gui -d 2000
```

要延时 2 秒并将截图保存到一个自定义的路径（无 GUI）可以使用：

```
$ flameshot full -p ~/myStuff/captures -d 2000
```

要截图全屏并保存到自定义的路径和粘贴板中使用：

```
$ flameshot full -c -p ~/myStuff/captures
```

要在截屏中包含鼠标并将图片保存为 PNG 格式可以使用：

```
$ flameshot screen -r
```

要对屏幕 1 进行截屏并将截屏复制到粘贴板中可以运行：

```
$ flameshot screen -n 1 -c
```

你还需要什么功能呢？Flameshot 拥有几乎截屏的所有功能：添加注释、编辑图片、模糊处理或者对要点做高亮等等功能。我想：在我找到它的最佳替代品之前，我将一直使用 Flameshot 来作为我当前的截图工具。请尝试一下它，你不会失望的。

好了，这就是今天的全部内容了。后续将有更多精彩内容，请保持关注！

Cheers!

---

via: <https://www.ostechnix.com/flameshot-a-simple-yet-powerful-feature-rich-screenshot-tool/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[FSSlc](https://github.com/FSSlc) 校对：[wxy](https://github.com/wxy)

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


模拟 Altair 8800 计算机

Summary: Altair 8800 是 1975 年发布的自建家用电脑套件。Altair 基本上是第一台个人电脑（PC），虽然 PC 这个名词好几年前就出现了。对 Dell、HP 或者 Macbook 而言它是亚当（或者夏娃）。

# 模拟 Altair 8800 计算机

[Altair 8800](https://en.wikipedia.org/wiki/Altair_8800) 是 1975 年发布的自建家用电脑套件。Altair 基本上是第一台个人电脑（PC），虽然 PC 这个名词好几年前就出现了。对 Dell、HP 或者 Macbook 而言它是亚当（或者夏娃）。

有些人认为为 Z80（与 Altair 的 Intel 8080 密切相关的处理器）编写仿真器真是太棒了，并认为它需要一个模拟 Altair 的控制面板。所以如果你想知道 1975 年使用电脑是什么感觉，你可以在你的 Macbook 上运行 Altair：

### 安装它

你可以从[这里](http://www.autometer.de/unix4fun/z80pack/ftp/)的 FTP 服务器下载 Z80 包。你要查找最新的 Z80 包版本，例如 `z80pack-1.26.tgz`。

首先解压文件：

```
$ tar -xvf z80pack-1.26.tgz
```

进入解压目录：

```
$ cd z80pack-1.26
```

控制面板模拟基于名为 `frontpanel` 的库。你必须先编译该库。如果你进入 `frontpanel` 目录，你会发现 `README` 文件列出了这个库自己的依赖项。你在这里的体会几乎肯定会与我的不同，但也许我的痛苦可以作为例子。我安装了依赖项，但是是通过 [Homebrew](http://brew.sh/) 安装的。为了让库能够编译，我必须确保在 `Makefile.osx` 中将 `/usr/local/include`添加到 Clang 的 include 路径中。

如果你觉得依赖没有问题，那么你应该就能编译这个库（我们现在位于 `z80pack-1.26/frontpanel`）：

```
$ make -f Makefile.osx ...
$ make -f Makefile.osx clean
```

你应该会得到 `libfrontpanel.so`。我把它拷贝到 `libfrontpanel.so`。

Altair 模拟器位于 `z80pack-1.26/altairsim` 下。你现在需要编译模拟器本身。进入 `z80pack-1.26/altairsim/srcsim` 并再次运行 `make`：

```
$ make -f Makefile.osx ...
$ make -f Makefile.osx clean
```

该过程将在 `z80pack-1.26/altairsim` 中创建一个名为 `altairsim` 的可执行文件。运行该可执行文件，你应该会看到标志性的 Altair 控制面板！

如果你想要探究，请阅读原始的 [Altair 手册](http://www.classiccmp.org/dunfield/altair/d/88opman.pdf)

如果你喜欢这篇文章，我们每两周更新一次！在 Twitter 上关注 [@TwoBitHistory][6](https://twitter.com/TwoBitHistory) 或订阅 [RSS 源](https://twobithistory.org/feed.xml)了解什么时候有新文章。

---

via: <https://twobithistory.org/2017/12/02/simulating-the-altair.html>

作者：[Two-Bit History](https://twobithistory.org) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


在 Linux 上使用 systemd 设置定时器

Summary: 学习使用 systemd 创建启动你的游戏服务器的定时器。

学习使用 systemd 创建启动你的游戏服务器的定时器。

# 在 Linux 上使用 systemd 设置定时器

>
> 学习使用 systemd 创建启动你的游戏服务器的定时器。
>
>
>

之前，我们看到了如何[手动的](/article-9700-1.html)、[在开机与关机时](/article-9703-1.html)、[在启用某个设备时](https://www.linux.com/blog/intro-to-linux/2018/6/systemd-services-reacting-change)、[在文件系统发生改变时](https://www.linux.com/blog/learn/intro-to-linux/2018/6/systemd-services-monitoring-files-and-directories) 启用与禁用 systemd 服务。

定时器增加了另一种启动服务的方式，基于……时间。尽管与定时任务很相似，但 systemd 定时器稍微地灵活一些。让我们看看它是怎么工作的。

### “定时运行”

让我们展开[本系列前两篇文章](/article-9703-1.html)中[你所设置的](/article-9700-1.html) [Minetest](https://www.minetest.net/) 服务器作为如何使用定时器单元的第一个例子。如果你还没有读过那几篇文章，可以现在去看看。

你将通过创建一个定时器来“改进” Minetest 服务器，使得在服务器启动 1 分钟后运行游戏服务器而不是立即运行。这样做的原因可能是，在启动之前可能会用到其他的服务，例如发邮件给其他玩家告诉他们游戏已经准备就绪，你要确保其他的服务（例如网络）在开始前完全启动并运行。

最终，你的 `minetest.timer` 单元看起来就像这样：

```
# minetest.timer
[Unit]
Description=Runs the minetest.service 1 minute after boot up

[Timer]
OnBootSec=1 m
Unit=minetest.service

[Install]
WantedBy=basic.target
```

一点也不难吧。

如以往一般，开头是 `[Unit]` 和一段描述单元作用的信息，这儿没什么新东西。`[Timer]` 这一节是新出现的，但它的作用不言自明：它包含了何时启动服务，启动哪个服务的信息。在这个例子当中，`OnBootSec` 是告诉 systemd 在系统启动后运行服务的指令。

其他的指令有：

* `OnActiveSec=`，告诉 systemd 在定时器启动后多长时间运行服务。
* `OnStartupSec=`，同样的，它告诉 systemd 在 systemd 进程启动后多长时间运行服务。
* `OnUnitActiveSec=`，告诉 systemd 在上次由定时器激活的服务启动后多长时间运行服务。
* `OnUnitInactiveSec=`，告诉 systemd 在上次由定时器激活的服务停用后多长时间运行服务。

继续 `minetest.timer` 单元，`basic.target` 通常用作<ruby> 后期引导服务 <rt>  late boot services </rt></ruby>的<ruby> 同步点 <rt>  synchronization point </rt></ruby>。这就意味着它可以让 `minetest.timer` 单元运行在安装完<ruby> 本地挂载点 <rt>  local mount points </rt></ruby>或交换设备，套接字、定时器、路径单元和其他基本的初始化进程之后。就像在[第二篇文章中 systemd 单元](/article-9703-1.html)里解释的那样，`targets` 就像<ruby> 旧的运行等级 <rt>  old run levels </rt></ruby>一样，可以将你的计算机置于某个状态，或像这样告诉你的服务在达到某个状态后开始运行。

在前两篇文章中你配置的 `minetest.service` 文件[最终](/article-9703-1.html)看起来就像这样：

```
# minetest.service
[Unit]
Description= Minetest server
Documentation= https://wiki.minetest.net/Main_Page

[Service]
Type= simple
User=

ExecStart= /usr/games/minetest --server
ExecStartPost= /home//bin/mtsendmail.sh "Ready to rumble?" "Minetest Starting up"

TimeoutStopSec= 180
ExecStop= /home//bin/mtsendmail.sh "Off to bed. Nightie night!" "Minetest Stopping in 2 minutes"
ExecStop= /bin/sleep 120
ExecStop= /bin/kill -2 $MAINPID

[Install]
WantedBy= multi-user.target
```

这儿没什么需要修改的。但是你需要将 `mtsendmail.sh`（发送你的 email 的脚本）从：

```
#!/bin/bash
# mtsendmail
sleep 20
echo $1 | mutt -F /home/<username>/.muttrc -s "$2" my_minetest@mailing_list.com
sleep 10
```

改成：

```
#!/bin/bash
# mtsendmail.sh
echo $1 | mutt -F /home/paul/.muttrc -s "$2" pbrown@mykolab.com
```

你做的事是去除掉 Bash 脚本中那些蹩脚的停顿。Systemd 现在来做等待。

### 让它运行起来

确保一切运作正常，禁用 `minetest.service`：

```
sudo systemctl disable minetest
```

这使得系统启动时它不会一同启动；然后，相反地，启用 `minetest.timer`：

```
sudo systemctl enable minetest.timer
```

现在你就可以重启服务器了，当运行 `sudo journalctl -u minetest.*` 后，你就会看到 `minetest.timer` 单元执行后大约一分钟，`minetest.service` 单元开始运行。

*图 1：minetest.timer 运行大约 1 分钟后 minetest.service 开始运行*

### 时间的问题

`minetest.timer` 在 systemd 的日志里显示的启动时间为 09:08:33 而 `minetest.service` 启动时间是 09:09:18，它们之间少于 1 分钟，关于这件事有几点需要说明一下：首先，请记住我们说过 `OnBootSec=` 指令是从引导完成后开始计算服务启动的时间。当 `minetest.timer` 的时间到来时，引导已经在几秒之前完成了。

另一件事情是 systemd 给自己设置了一个<ruby> 误差幅度 <rt>  margin of error </rt></ruby>（默认是 1 分钟）来运行东西。这有助于在多个<ruby> 资源密集型进程 <rt>  resource-intensive processes </rt></ruby>同时运行时分配负载：通过分配 1 分钟的时间，systemd 可以等待某些进程关闭。这也意味着 `minetest.service` 会在引导完成后的 1~2 分钟之间启动。但精确的时间谁也不知道。

顺便一提，你可以用 `AccuracySec=` 指令[修改误差幅度](https://www.freedesktop.org/software/systemd/man/systemd.timer.html#AccuracySec=)。

你也可以检查系统上所有的定时器何时运行或是上次运行的时间：

```
systemctl list-timers --all
```

*图 2：检查定时器何时运行或上次运行的时间*

最后一件值得思考的事就是你应该用怎样的格式去表示一段时间。Systemd 在这方面非常灵活：`2 h`，`2 hours` 或 `2hr` 都可以用来表示 2 个小时。对于“秒”，你可以用 `seconds`，`second`，`sec` 和 `s`。“分”也是同样的方式：`minutes`，`minute`，`min` 和 `m`。你可以检查 `man systemd.time` 来查看 systemd 能够理解的所有时间单元。

### 下一次

下次你会看到如何使用日历中的日期和时间来定期运行服务，以及如何通过组合定时器与设备单元在插入某些硬件时运行服务。

回头见！

在 Linux 基金会和 edx 上通过免费课程 [“Introduction to Linux”](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux) 学习更多关于 Linux 的知识。

---

via: <https://www.linux.com/blog/learn/intro-to-linux/2018/7/setting-timer-systemd-linux>

作者：[Paul Brown](https://www.linux.com/users/bro66) 选题：[lujun9972](https://github.com/lujun9972) 译者：[LuuMing](https://github.com/LuuMing) 校对：[wxy](https://github.com/wxy)

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


正确选择开源数据库的 5 个技巧

Summary: 对关键应用的选择不容许丝毫错误。

对关键应用的选择不容许丝毫错误。

# 正确选择开源数据库的 5 个技巧

>
> 对关键应用的选择不容许丝毫错误。
>
>
>

你或许会遇到需要选择合适的开源数据库的情况。但这无论对于开源方面的老手或是新手，都是一项艰巨的任务。

在过去的几年中，采用开源技术的企业越来越多。面对这样的趋势，众多开源应用公司都纷纷承诺自己提供的解决方案能够各种问题、适应各种负载。但这些承诺不能轻信，在开源应用上的选择是重要而艰难的，尤其是数据库这种关键的应用。

凭借我在 [Percona](https://www.percona.com/) 和其它公司担任 IT 专家的经验，我很幸运能够指导其他人在开源技术的选择上做出正确的决策，因为需要考虑的重要因素太多了。希望通过这篇文章能够向大家分享这方面的一些技巧。

### 有一个明确的目标

这一点看似简单，但在和很多人聊过 MySQL、MongoDB、PostgreSQL 之后，我觉得这一点才是最重要的。

面对繁杂的开源数据库，更需要明确自己的目标。无论这个数据库是作为开发用的标准化数据库后端，抑或是用于替换遗留代码中的原有数据库，这都是一个明确的目标。

目标一旦确定，就可以集中精力与开源软件的提供方商讨更多细节了。

### 了解你的工作负载

尽管开源数据库技术的功能越来越丰富，但这些新加入的功能都不太具有普适性。譬如 MongoDB 新增了事务的支持、MySQL 新增了 JSON 存储的功能等等。目前开源数据库的普遍趋势是不断加入新的功能，但很多人的误区却在于没有选择最适合的工具来完成自己的工作 —— 这样的人或许是一个自大的开发者，又或许是一个视野狭窄的主管 —— 最终导致公司业务上的损失。最致命的是，在业务初期，使用了不适合的工具往往也可以顺利地完成任务，但随着业务的增长，很快就会到达瓶颈，尽管这个时候还可以替换更合适的工具，但成本就比较高了。

例如，如果你需要的是数据分析仓库，关系数据库可能不是一个适合的选择；如果你处理事务的应用要求严格的数据完整性和一致性，就不要考虑 NoSQL 了。

### 不要重新发明轮子

在过去的数十年，开源数据库技术迅速发展壮大。开源数据库从新生，到受到质疑，再到受到认可，现在已经成为很多企业生产环境的数据库。企业不再需要担心选择开源数据库技术会产生风险，因为开源数据库通常都有活跃的社区，可以为越来越多的初创公司、中型企业甚至 500 强公司提供开源数据库领域的支持和第三方工具。

Battery Ventures 是一家专注于技术的投资公司，最近推出了一个用于跟踪最受欢迎开源项目的 [BOSS 指数](https://techcrunch.com/2017/04/07/tracking-the-explosive-growth-of-open-source-software/) 。它提供了对一些被广泛采用的开源项目和活跃的开源项目的详细情况。其中，数据库技术毫无悬念地占据了榜单的主导地位，在前十位之中占了一半。这个 BOSS 指数对于刚接触开源数据库领域的人来说，这是一个很好的切入点。当然，开源技术的提供者也会针对很多常见的典型问题给出对应的解决方案。

我认为，你想要做的事情很可能已经有人解决过了。即使这些先行者的解决方案不一定完全契合你的需求，但也可以从他们成功或失败的案例中根据你自己的需求修改得出合适的解决方案。

如果你采用了一个最前沿的技术，这就是你探索的好机会了。如果你的工作负载刚好适合新的开源数据库技术，放胆去尝试吧。第一个吃螃蟹的人总是会得到意外的挑战和收获。

### 先从简单开始

你的数据库实际上需要达到多少个 [9](https://en.wikipedia.org/wiki/Five_nines) 的可用性？对许多公司来说，“实现高可用性”仅仅只是一个模糊的目标。当然，最常见的答案都会是“它是关键应用，我们无论多短的停机时间都是无法忍受的”。

数据库环境越复杂，管理的难度就越大，成本也会越高。理论上你总可以将数据库的可用性提得更高，但代价将会是大大增加的管理难度和性能下降。所以，先从简单开始，直到有需要时再逐步扩展。

例如，Booking.com 是一个有名的旅游预订网站。但少有人知的是，它使用 MySQL 作为数据库后端。 Booking.com 高级系统架构师 Nicolai Plum 曾经发表过一次[演讲](https://www.percona.com/live/mysql-conference-2015/sessions/bookingcom-evolution-mysql-system-design)，讲述了他们公司使用 MySQL 数据库的历程。其中一个重点就是，在初始阶段数据库可以被配置得很简单，然后逐渐变得复杂。对于早期的数据库需求，一个简单的主从架构就足够了，但随着工作负载和数据量的增加，数据库引入了负载均衡、多个读取副本，还使用 Hadoop 进行分析。尽管如此，早期的架构仍然是非常简单的。

### 有疑问，找专家

如果你仍然不确定数据库选择的是否合适，可以在论坛、网站或者与软件的提供者处商讨。研究各种开源数据库是否满足自己的需求是一件很有意义的事，因为总会发现你从不知道的技术。而开源社区就是分享这些信息的地方。

当你接触到开源软件和软件提供者时，有一件重要的事情需要注意。很多公司都有开放的核心业务模式，鼓励采用他们的数据库软件。你可以只接受他们的部分建议和指导，然后用你自己的能力去研究和探索替代方案。

### 总结

选择正确的开源数据库是一个重要的过程。很多时候，人们都会在真正理解需求之前就做出决定，这是本末倒置的。

---

via: <https://opensource.com/article/18/10/tips-choosing-right-open-source-database>

作者：[Barrett Chambers](https://opensource.com/users/barrettc) 选题：[lujun9972](https://github.com/lujun9972) 译者：[HankChow](https://github.com/HankChow) 校对：[wxy](https://github.com/wxy)

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


四个开源的 Android 邮件客户端

Summary: Email 现在还没有绝迹，而且现在大部分邮件都来自于移动设备。

Email 现在还没有绝迹，而且现在大部分邮件都来自于移动设备。

# 四个开源的 Android 邮件客户端

>
> Email 现在还没有绝迹，而且现在大部分邮件都来自于移动设备。
>
>
>

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

现在一些年轻人正将邮件称之为“老年人的交流方式”，然而事实却是邮件绝对还没有消亡。虽然[协作工具](https://opensource.com/alternatives/trello)、社交媒体，和短信很常用，但是它们还没做好取代邮件这种必要的商业（和社交）通信工具的准备。

考虑到邮件还没有消失，并且（很多研究表明）人们都是在移动设备上阅读邮件，拥有一个好的移动邮件客户端就变得很关键。如果你是一个想使用开源的邮件客户端的 Android 用户，事情就变得有点棘手了。

我们提供了四个开源的 Andorid 邮件客户端供选择。其中两个可以通过 Andorid 官方应用商店 [Google Play](https://play.google.com/store) 下载。你也可以在 [Fossdroid](https://fossdroid.com/) 或者 [F-Droid](https://f-droid.org/) 这些开源 Android 应用库中找到他们。（下方有每个应用的具体下载方式。）

### K-9 Mail

[K-9 Mail](https://k9mail.github.io/) 拥有几乎和 Android 一样长的历史——它起源于 Android 1.0 邮件客户端的一个补丁。它支持 IMAP 和 WebDAV、多用户、附件、emoji 和其它经典的邮件客户端功能。它的[用户文档](https://k9mail.github.io/documentation.html)提供了关于安装、启动、安全、阅读和发送邮件等等的帮助。

K-9 基于 [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) 协议开源，[源码](https://github.com/k9mail/k-9)可以从 GitHub 上获得. 应用可以从 [Google Play](https://play.google.com/store/apps/details?id=com.fsck.k9)、[Amazon](https://www.amazon.com/K-9-Dog-Walkers-Mail/dp/B004JK61K0/) 和 [F-Droid](https://f-droid.org/packages/com.fsck.k9/) 上下载。

### p≡p

正如它的全称，”Pretty Easy Privacy”说的那样，[p≡p](https://www.pep.security/android.html.en) 主要关注于隐私和安全通信。它提供自动的、端到端的邮件和附件加密（但要求你的收件人也要能够加密邮件——否则，p≡p 会警告你的邮件将不加密发出）。

你可以从 GitLab 获得[源码](https://pep-security.lu/gitlab/android/pep)（基于 [GPLv3](https://pep-security.lu/gitlab/android/pep/blob/feature/material/LICENSE) 协议），并且可以从应用的官网上找到相应的[文档](https://www.pep.security/docs/)。应用可以在 [Fossdroid](https://fossdroid.com/a/p%E2%89%A1p.html) 上免费下载或者在 [Google Play](https://play.google.com/store/apps/details?id=security.pEp) 上支付一点儿象征性的费用下载。

### InboxPager

[InboxPager](https://github.com/itprojects/InboxPager) 允许你通过 SSL/TLS 协议收发邮件信息，这也表明如果你的邮件提供商（比如 Gmail ）没有默认开启这个功能的话，你可能要做一些设置。（幸运的是， InboxPager 提供了 Gmail 的[设置教程](https://github.com/itprojects/InboxPager/blob/HEAD/README.md#gmail-configuration)。）它同时也支持通过 OpenKeychain 应用进行 OpenPGP 加密。

InboxPager 基于 [GPLv3](https://github.com/itprojects/InboxPager/blob/c5641a6d644d001bd4cec520b5a96d7e588cb6ad/LICENSE) 协议，其源码可从 GitHub 获得，并且应用可以从 [F-Droid](https://f-droid.org/en/packages/net.inbox.pager/) 下载。

### FairEmail

[FairEmail](https://email.faircode.eu/) 是一个极简的邮件客户端，它的功能集中于读写信息，没有任何多余的可能拖慢客户端的功能。它支持多个帐号和用户、消息线索、加密等等。

它基于 [GPLv3](https://github.com/M66B/open-source-email/blob/master/LICENSE) 协议开源，[源码](https://github.com/M66B/open-source-email)可以从 GitHub 上获得。你可以在 [Fossdroid](https://fossdroid.com/a/fairemail.html) 上下载 FairEamil；对 Google Play 版本感兴趣的人可以从 [testing the software](https://play.google.com/apps/testing/eu.faircode.email) 获得应用。

肯定还有更多的开源 Android 客户端（或者上述软件的加强版本）——活跃的开发者们可以关注一下。如果你知道还有哪些优秀的应用，可以在评论里和我们分享。

---

via: <https://opensource.com/article/18/10/open-source-android-email-clients>

作者：[Opensource.com](https://opensource.com) 选题：[lujun9972](https://github.com/lujun9972) 译者：[zianglei](https://github.com/zianglei) 校对：[wxy](https://github.com/wxy)

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


Linux 上最好的 9 个免费视频编辑软件（2018）

# Linux 上最好的 9 个免费视频编辑软件（2018）

>
> 概要：这里介绍 Linux 上几个最好的视频编辑器，介绍它们的特性、利与弊，以及如何在你的 Linux 发行版上安装它们。
>
>
>

我们曾经在一篇短文中讨论过 [Linux 上最好的照片管理应用](https://itsfoss.com/linux-photo-management-software/)，[Linux 上最好的代码编辑器](https://itsfoss.com/best-modern-open-source-code-editors-for-linux/)。今天我们将讨论 **Linux 上最好的视频编辑软件**。

当谈到免费视频编辑软件，Windows Movie Maker 和 iMovie 是大部分人经常推荐的。

很不幸，上述两者在 GNU/Linux 上都不可用。但是不必担心，我们为你汇集了一个**最好的视频编辑器**清单。

### Linux 上最好的视频编辑器

接下来让我们一起看看这些最好的视频编辑软件。如果你觉得文章读起来太长，这里有一个快速摘要。

| 视频编辑器 | 主要用途 | 类型 |
| --- | --- | --- |
| Kdenlive | 通用视频编辑 | 自由开源 |
| OpenShot | 通用视频编辑 | 自由开源 |
| Shotcut | 通用视频编辑 | 自由开源 |
| Flowblade | 通用视频编辑 | 自由开源 |
| Lightworks | 专业级视频编辑 | 免费增值 |
| Blender | 专业级三维编辑 | 自由开源 |
| Cinelerra | 通用视频编辑 | 自由开源 |
| DaVinci | 专业级视频处理编辑 | 免费增值 |
| VidCutter | 简单视频拆分合并 | 自由开源 |

### 1、 Kdenlive

[Kdenlive](https://kdenlive.org/) 是 [KDE](https://www.kde.org/) 上的一个自由且[开源](https://itsfoss.com/tag/open-source/)的视频编辑软件，支持双视频监控、多轨时间线、剪辑列表、自定义布局、基本效果，以及基本过渡效果。

它支持多种文件格式和多种摄像机、相机，包括低分辨率摄像机（Raw 和 AVI DV 编辑）、mpeg2、mpeg4 和 h264 AVCHD（小型相机和便携式摄像机）、高分辨率摄像机文件（包括 HDV 和 AVCHD 摄像机）、专业摄像机（包括 XDCAM-HD™ 流、IMX™ (D10) 流、DVCAM (D10)、DVCAM、DVCPRO™、DVCPRO50™ 流以及 DNxHD™ 流）。

如果你正寻找 Linux 上 iMovie 的替代品，Kdenlive 会是你最好的选择。

Kdenlive 特性：

* 多轨视频编辑
* 多种音视频格式支持
* 可配置的界面和快捷方式
* 使用文本或图像轻松创建切片
* 丰富的效果和过渡
* 音频和视频示波器可确保镜头绝对平衡
* 代理编辑
* 自动保存
* 广泛的硬件支持
* 关键帧效果

优点：

* 通用视频编辑器
* 对于那些熟悉视频编辑的人来说并不太复杂

缺点：

* 如果你想找的是极致简单的编辑软件，它可能还是令你有些困惑
* KDE 应用程序以臃肿而臭名昭著

#### 安装 Kdenlive

Kdenlive 适用于所有主要的 Linux 发行版。你只需在软件中心搜索即可。[Kdenlive 网站的下载部分](https://kdenlive.org/download/)提供了各种软件包。

命令行爱好者可以通过在 Debian 和基于 Ubuntu 的 Linux 发行版中运行以下命令从终端安装它：

```
sudo apt install kdenlive
```

### 2、 OpenShot

[OpenShot](http://www.openshot.org/) 是 Linux 上的另一个多用途视频编辑器。OpenShot 可以帮助你创建具有过渡和效果的视频。你还可以调整声音大小。当然，它支持大多数格式和编解码器。

你还可以将视频导出至 DVD，上传至 YouTube、Vimeo、Xbox 360 以及许多常见的视频格式。OpenShot 比 Kdenlive 要简单一些。因此，如果你需要界面简单的视频编辑器，OpenShot 是一个不错的选择。

它还有个简洁的[开始使用 Openshot](http://www.openshot.org/user-guide/) 文档。

OpenShot 特性：

* 跨平台，可在 Linux、macOS 和 Windows 上使用
* 支持多种视频，音频和图像格式
* 强大的基于曲线的关键帧动画
* 桌面集成与拖放支持
* 不受限制的音视频轨道或图层
* 可剪辑调整大小、缩放、修剪、捕捉、旋转和剪切
* 视频转换可实时预览
* 合成，图像层叠和水印
* 标题模板，标题创建，子标题
* 利用图像序列支持2D动画
* 3D 动画标题和效果
* 支持保存为 SVG 格式以及矢量标题和可信证
* 滚动动态图片
* 帧精度（逐步浏览每一帧视频）
* 剪辑的时间映射和速度更改
* 音频混合和编辑
* 数字视频效果，包括亮度，伽玛，色调，灰度，色度键等

优点：

* 用于一般视频编辑需求的通用视频编辑器
* 可在 Windows 和 macOS 以及 Linux 上使用

缺点：

* 软件用起来可能很简单，但如果你对视频编辑非常陌生，那么肯定需要一个曲折学习的过程
* 你可能仍然没有达到专业级电影制作编辑软件的水准

#### 安装 OpenShot

OpenShot 也可以在所有主流 Linux 发行版的软件仓库中使用。你只需在软件中心搜索即可。你也可以从[官方页面](http://www.openshot.org/download/)中获取它。

在 Debian 和基于 Ubuntu 的 Linux 发行版中，我最喜欢运行以下命令来安装它：

```
sudo apt install openshot
```

### 3、 Shotcut

[Shotcut](https://www.shotcut.org/) 是 Linux 上的另一个编辑器，可以和 Kdenlive 与 OpenShot 归为同一联盟。虽然它确实与上面讨论的其他两个软件有类似的功能，但 Shotcut 更先进的地方是支持 4K 视频。

支持许多音频、视频格式，过渡和效果是 Shotcut 的众多功能中的一部分。它也支持外部监视器。

这里有一系列视频教程让你[轻松上手 Shotcut](https://www.shotcut.org/tutorials/)。它也可在 Windows 和 macOS 上使用，因此你也可以在其他操作系统上学习。

Shotcut 特性：

* 跨平台，可在 Linux、macOS 和 Windows 上使用
* 支持各种视频，音频和图像格式
* 原生时间线编辑
* 混合并匹配项目中的分辨率和帧速率
* 音频滤波、混音和效果
* 视频转换和过滤
* 具有缩略图和波形的多轨时间轴
* 无限制撤消和重做播放列表编辑，包括历史记录视图
* 剪辑调整大小、缩放、修剪、捕捉、旋转和剪切
* 使用纹波选项修剪源剪辑播放器或时间轴
* 在额外系统显示/监视器上的外部监察
* 硬件支持

你可以在[这里](https://www.shotcut.org/features/)阅它的更多特性。

优点：

* 用于常见视频编辑需求的通用视频编辑器
* 支持 4K 视频
* 可在 Windows，macOS 以及 Linux 上使用

缺点：

* 功能太多降低了软件的易用性

#### 安装 Shotcut

Shotcut 以 [Snap](https://itsfoss.com/use-snap-packages-ubuntu-16-04/) 格式提供。你可以在 Ubuntu 软件中心找到它。对于其他发行版，你可以从此[下载页面](https://www.shotcut.org/download/)获取可执行文件来安装。

### 4、 Flowblade

[Flowblade](http://jliljebl.github.io/flowblade/) 是 Linux 上的一个多轨非线性视频编辑器。与上面讨论的一样，这也是一个自由开源的软件。它具有时尚和现代化的用户界面。

用 Python 编写，它的设计初衷是快速且准确。Flowblade 专注于在 Linux 和其他自由平台上提供最佳体验。所以它没有在 Windows 和 OS X 上运行的版本。Linux 用户专享其实感觉也不错的。

你也可以查看这个不错的[文档](https://jliljebl.github.io/flowblade/webhelp/help.html)来帮助你使用它的所有功能。

Flowblade 特性：

* 轻量级应用
* 为简单的任务提供简单的界面，如拆分、合并、覆盖等
* 大量的音视频效果和过滤器
* 支持[代理编辑](https://jliljebl.github.io/flowblade/webhelp/proxy.html)
* 支持拖拽
* 支持多种视频、音频和图像格式
* 批量渲染
* 水印
* 视频转换和过滤器
* 具有缩略图和波形的多轨时间轴

你可以在 [Flowblade 特性](https://jliljebl.github.io/flowblade/features.html)里阅读关于它的更多信息。

优点：

* 轻量
* 适用于通用视频编辑

缺点：

* 不支持其他平台

#### 安装 Flowblade

Flowblade 应当在所有主流 Linux 发行版的软件仓库中都可以找到。你可以从软件中心安装它。也可以在[下载页面](https://jliljebl.github.io/flowblade/download.html)查看更多信息。

另外，你可以在 Ubuntu 和基于 Ubuntu 的系统中使用一下命令安装 Flowblade：

```
sudo apt install flowblade
```

### 5、 Lightworks

如果你在寻找一个具有更多特性的视频编辑器，这就是你想要的。[Lightworks](https://www.lwks.com/) 是一个跨平台的专业视频编辑器，可以在 Linux、Mac OS X 以及 Windows上使用。

它是一款屡获殊荣的专业[非线性编辑](https://en.wikipedia.org/wiki/Non-linear_editing_system)（NLE）软件，支持高达 4K 的分辨率以及 SD 和 HD 格式的视频。

Lightworks 可以在 Linux 上使用，然而它不开源。

Lightwokrs 有两个版本：

* Lightworks 免费版
* Lightworks 专业版

专业版有更多功能，比如支持更高的分辨率，支持 4K 和蓝光视频等。

这个[页面](https://www.lwks.com/index.php?option=com_lwks&view=download&Itemid=206&tab=4)有广泛的可用文档。你也可以参考 [Lightworks 视频向导页](https://www.lwks.com/videotutorials)的视频。

Lightworks 特性：

* 跨平台
* 简单直观的用户界面
* 简明的时间线编辑和修剪
* 实时可用的音频和视频FX
* 可用精彩的免版税音频和视频内容
* 适用于 4K 的 Lo-Res 代理工作流程
* 支持导出 YouTube/Vimeo，SD/HD视频，最高可达4K
* 支持拖拽
* 各种音频和视频效果和滤镜

优点：

* 专业，功能丰富的视频编辑器

缺点：

* 免费版有使用限制

#### 安装 Lightworks

Lightworks 为 Debian 和基于 Ubuntu 的 Linux 提供了 DEB 安装包，为基于 Fedora 的 Linux 发行版提供了RPM 安装包。你可以在[下载页面](https://www.lwks.com/index.php?option=com_lwks&view=download&Itemid=206&tab=1)找到安装包。

### 6、 Blender

[Blender](https://www.blender.org/) 是一个专业的，工业级的开源跨平台视频编辑器。它在制作 3D 作品的工具当中较为流行。Blender 已被用于制作多部好莱坞电影，包括蜘蛛侠系列。

虽然最初设计用于制作 3D 模型，但它也具有多种格式视频的编辑功能。

Blender 特性：

* 实时预览、亮度波形、色度矢量显示和直方图显示
* 音频混合、同步、擦洗和波形可视化
* 最多32个轨道，用于添加视频、图像、音频、场景、面具和效果
* 速度控制、调整图层、过渡、关键帧、过滤器等

你可以在[这里](https://www.blender.org/features/)阅读更多相关特性。

优点：

* 跨平台
* 专业级视频编辑

缺点：

* 复杂
* 主要用于制作 3D 动画，不专门用于常规视频编辑

#### 安装 Blender

Blender 的最新版本可以从[下载页面](https://www.blender.org/download/)下载。

### 7、 Cinelerra

[Cinelerra](http://cinelerra.org/) 从 1998 年发布以来，已被下载超过 500 万次。它是 2003 年第一个在 64 位系统上提供非线性编辑的视频编辑器。当时它是 Linux 用户的首选视频编辑器，但随后一些开发人员丢弃了此项目，它也随之失去了光彩。

好消息是它正回到正轨并且良好地再次发展。

如果你想了解关于 Cinelerra 项目是如何开始的，这里有些[有趣的背景故事](http://cinelerra.org/our-story)。

Cinelerra 特性：

* 非线性编辑
* 支持 HD 视频
* 内置框架渲染器
* 各种视频效果
* 不受限制的图层数量
* 拆分窗格编辑

优点：

* 通用视频编辑器

缺点：

* 不适用于新手
* 没有可用的安装包

#### 安装 Cinelerra

你可以从 [SourceForge](https://sourceforge.net/projects/heroines/files/cinelerra-6-src.tar.xz/download) 下载源码。更多相关信息请看[下载页面](http://cinelerra.org/download)。

### 8、 DaVinci Resolve

如果你想要好莱坞级别的视频编辑器，那就用好莱坞正在使用的专业工具。来自 Blackmagic 公司的 [DaVinci Resolve](https://www.blackmagicdesign.com/products/davinciresolve/) 就是专业人士用于编辑电影和电视节目的专业工具。

DaVinci Resolve 不是常规的视频编辑器。它是一个成熟的编辑工具，在这一个应用程序中提供编辑，色彩校正和专业音频后期制作功能。

DaVinci Resolve 不开源。类似于 LightWorks，它也为 Linux 提供一个免费版本。专业版售价是 $300。

DaVinci Resolve 特性：

* 高性能播放引擎
* 支持所有类型的编辑类型，如覆盖、插入、波纹覆盖、替换、适合填充、末尾追加
* 高级修剪
* 音频叠加
* Multicam Editing 可实现实时编辑来自多个摄像机的镜头
* 过渡和过滤效果
* 速度效果
* 时间轴曲线编辑器
* VFX 的非线性编辑

优点：

* 跨平台
* 专业级视频编辑器

缺点：

* 不适用于通用视频编辑
* 不开源
* 免费版本中有些功能无法使用

#### 安装 DaVinci Resolve

你可以从[这个页面](https://www.blackmagicdesign.com/products/davinciresolve/)下载 DaVinci Resolve。你需要注册，哪怕仅仅下载免费版。

### 9、 VidCutter

不像这篇文章讨论的其他视频编辑器，[VidCutter](https://itsfoss.com/vidcutter-video-editor-linux/) 非常简单。除了分割和合并视频之外，它没有其他太多功能。但有时你正好需要 VidCutter 提供的这些功能。

VidCutter 特性：

* 适用于Linux、Windows 和 MacOS 的跨平台应用程序
* 支持绝大多数常见视频格式，例如：AVI、MP4、MPEG 1/2、WMV、MP3、MOV、3GP、FLV 等等
* 界面简单
* 修剪和合并视频，仅此而已

优点：

* 跨平台
* 很适合做简单的视频分割和合并

缺点：

* 不适合用于通用视频编辑
* 经常崩溃

#### 安装 VidCutter

如果你使用的是基于 Ubuntu 的 Linux 发行版，你可以使用这个官方 PPA（LCTT 译注：PPA，个人软件包档案，PersonalPackageArchives）：

```
sudo add-apt-repository ppa:ozmartian/apps
sudo apt-get update
sudo apt-get install vidcutter
```

Arch Linux 用户可以轻松的使用 AUR 安装它。对于其他 Linux 发行版的用户，你可以从这个 [Github 页面](https://github.com/ozmartian/vidcutter/releases)上查找安装文件。

### 哪个是 Linux 上最好的视频编辑软件？

文章里提到的一些视频编辑器使用 [FFmpeg](https://www.ffmpeg.org/)。你也可以自己使用 FFmpeg。它只是一个命令行工具，所以我没有在上文的列表中提到，但一句也不提又不公平。

如果你需要一个视频编辑器来简单的剪切和拼接视频，请使用 VidCutter。

如果你需要的不止这些，**OpenShot** 或者 **Kdenlive** 是不错的选择。他们有规格标准的系统，适用于初学者。

如果你拥有一台高端计算机并且需要高级功能，可以使用 **Lightworks** 或者 **DaVinci Resolve**。如果你在寻找更高级的工具用于制作 3D 作品，你肯定会支持选择 **Blender**。

这就是在 Ubuntu、Linux Mint、Elementary，以及其它发行版等 **Linux 上最好的视频编辑软件**的全部内容。向我们分享你最喜欢的视频编辑器。

---

via: <https://itsfoss.com/best-video-editing-software-linux/>

作者：[itsfoss](https://itsfoss.com/author/itsfoss/) 译者：[fuowang](https://github.com/fuowang) 校对：[wxy](https://github.com/wxy)

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


Gifski：一个跨平台的高质量 GIF 编码器

Summary: 今天，我将向你展示如何从一段视频或者一些图片来制作高质量的 gif 动图。

今天，我将向你展示如何从一段视频或者一些图片来制作高质量的 gif 动图。

# Gifski：一个跨平台的高质量 GIF 编码器

<img src="content_image/album_201811_02_211831hq0ygxiu9k9y0zdo.png" alt="" title="">

作为一名文字工作者，我需要在我的文章中添加图片。有时为了更容易讲清楚某个概念，我还会添加视频或者 gif 动图，相比于文字，通过视频或者 gif 格式的输出，读者可以更容易地理解我的指导。前些天，我已经写了篇文章来介绍针对 Linux 的功能丰富的强大截屏工具 [Flameshot](/article-10180-1.html)。今天，我将向你展示如何从一段视频或者一些图片来制作高质量的 gif 动图。这个工具就是 **Gifski**，一个跨平台、开源、基于 **Pngquant** 的高质量命令行 GIF 编码器。

对于那些好奇 pngquant 是什么的读者，简单来说 pngquant 是一个针对 PNG 图片的无损压缩命令行工具。相信我，pngquant 是我使用过的最好的 PNG 无损压缩工具。它可以将 PNG 图片最高压缩 **70%** 而不会损失图片的原有质量并保存了所有的阿尔法透明度。经过压缩的图片可以在所有的网络浏览器和系统中使用。而 Gifski 是基于 Pngquant 的，它使用 pngquant 的功能来创建高质量的 GIF 动图。Gifski 能够创建每帧包含上千种颜色的 GIF 动图。Gifski 也需要 **ffmpeg** 来将视频转换为 PNG 图片。

### 安装 Gifski

首先需要确保你安装了 FFMpeg 和 Pngquant。

FFmpeg 在大多数的 Linux 发行版的默认软件仓库中都可以获取到，所以你可以使用默认的包管理器来安装它。具体的安装过程，请参考下面链接中的指导。

* [在 Linux 中如何安装 FFmpeg](https://www.ostechnix.com/install-ffmpeg-linux/)

Pngquant 可以从 [AUR](https://aur.archlinux.org/packages/pngquant/) 中获取到。要在基于 Arch 的系统安装它，使用任意一个 AUR 帮助程序即可，例如下面示例中的 [Yay](https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/)：

```
$ yay -S pngquant
```

在基于 Debian 的系统中，运行：

```
$ sudo apt install pngquant
```

假如在你使用的发行版中没有 pngquant，你可以从源码编译并安装它。为此你还需要安装 `libpng-dev` 包。

```
$ git clone --recursive https://github.com/kornelski/pngquant.git
$ make
$ sudo make install
```

安装完上述依赖后，再安装 Gifski。假如你已经安装了 [Rust](https://www.ostechnix.com/install-rust-programming-language-in-linux/) 编程语言，你可以使用 **cargo** 来安装它：

```
$ cargo install gifski
```

另外，你还可以使用 [Linuxbrew](https://www.ostechnix.com/linuxbrew-common-package-manager-linux-mac-os-x/) 包管理器来安装它：

```
$ brew install gifski
```

假如你不想安装 cargo 或 Linuxbrew，可以从它的 [发布页面](https://github.com/ImageOptim/gifski/releases) 下载最新的二进制程序，或者手动从源码编译并安装 gifski 。

### 使用 Gifski 来创建高质量的 GIF 动图

进入你保存 PNG 图片的目录，然后运行下面的命令来从这些图片创建 GIF 动图：

```
$ gifski -o file.gif *.png
```

上面的 `file.gif` 为最后输出的 gif 动图。

Gifski 还有其他的特性，例如：

* 创建特定大小的 GIF 动图
* 在每秒钟展示特定数目的动图
* 以特定的质量编码
* 更快速度的编码
* 以给定顺序来编码图片，而不是以排序的结果来编码

为了创建特定大小的 GIF 动图，例如宽为 800，高为 400，可以使用下面的命令：

```
$ gifski -o file.gif -W 800 -H 400 *.png
```

你可以设定 GIF 动图在每秒钟展示多少帧，默认值是 **20**。为此，可以运行下面的命令：

```
$ gifski -o file.gif --fps 1 *.png
```

在上面的例子中，我指定每秒钟展示 1 帧。

我们还能够以特定质量（1-100 范围内）来编码。显然，更低的质量将生成更小的文件，更高的质量将生成更大的 GIF 动图文件。

```
$ gifski -o file.gif --quality 50 *.png
```

当需要编码大量图片时，Gifski 将会花费更多时间。如果想要编码过程加快到通常速度的 3 倍左右，可以运行：

```
$ gifski -o file.gif --fast *.png
```

请注意上面的命令产生的 GIF 动图文件将减少 10% 的质量，并且文件大小也会更大。

如果想让图片以某个给定的顺序（而不是通过排序）精确地被编码，可以使用 `--nosort` 选项。

```
$ gifski -o file.gif --nosort *.png
```

假如你不想让 GIF 循环播放，只需要使用 `--once` 选项即可：

```
$ gifski -o file.gif --once *.png
```

### 从视频创建 GIF 动图

有时或许你想从一个视频创建 GIF 动图。这也是可以做到的，这时候 FFmpeg 便能提供帮助。首先像下面这样，将视频转换成一系列的 PNG 图片：

```
$ ffmpeg -i video.mp4 frame%04d.png
```

上面的命令将会从 `video.mp4` 这个视频文件创建名为 “frame0001.png”、“frame0002.png”、“frame0003.png” 等等形式的图片（其中的 `%04d` 代表帧数），然后将这些图片保存在当前的工作目录。

转换好图片后，只需要运行下面的命令便可以制作 GIF 动图了：

```
$ gifski -o file.gif *.png
```

想知晓更多的细节，请参考它的帮助部分：

```
$ gifski -h
```

[这是](https://gif.ski/jazz-chromecast-ultra.gif)使用 Gifski 创建的示例 GIF 动图文件。

正如你看到的那样，GIF 动图的质量看起来是非常好的。

好了，这就是全部内容了。希望这篇指南对你有所帮助。更多精彩内容即将呈现，请保持关注！

干杯吧！

---

```
via: https://www.ostechnix.com/gifski-a-cross-platform-high-quality-gif-encoder/
```

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[FSSlc](https://github.com/FSSlc) 校对：[wxy](https://github.com/wxy)

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


6 个用于写书的开源工具

Summary: 这些多能、免费的工具可以满足你撰写、编辑和生成你自己的书籍的全部需求。

这些多能、免费的工具可以满足你撰写、编辑和生成你自己的书籍的全部需求。

# 6 个用于写书的开源工具

>
> 这些多能、免费的工具可以满足你撰写、编辑和生成你自己的书籍的全部需求。
>
>
>

<img src="content_image/album_201811_02_214546jj828j99tt88d08d.png" alt="" title="">

我在 1993 年首次使用并贡献了免费和开源软件，从那时起我一直是一名开源软件的开发人员和布道者。尽管我被记住的一个项目是 [FreeDOS 项目](http://www.freedos.org/)，这是一个 DOS 操作系统的开源实现，但我已经编写或者贡献了数十个开源软件项目。

我最近写了一本关于 FreeDOS 的书。《[使用 FreeDOS](http://www.freedos.org/ebook/)》是我庆祝 FreeDOS 出现 24 周年而撰写的。它是关于安装和使用 FreeDOS、关于我最喜欢的 DOS 程序，以及 DOS 命令行和 DOS 批处理编程的快速参考指南的集合。在一位出色的专业编辑的帮助下，我在过去的几个月里一直在编写这本书。

《使用 FreeDOS》 可在知识共享署名（cc-by）国际公共许可证下获得。你可以从 [FreeDOS 电子书](http://www.freedos.org/ebook/)网站免费下载 EPUB 和 PDF 版本。（我也计划为那些喜欢纸质的人提供印刷版本。）

这本书几乎完全是用开源软件制作的。我想分享一下对用来创建、编辑和生成《使用 FreeDOS》的工具的看法。

### Google 文档

[Google 文档](https://www.google.com/docs/about/)是我使用的唯一不是开源软件的工具。我将我的第一份草稿上传到 Google 文档，这样我就能与编辑器进行协作。我确信有开源协作工具，但 Google 文档能够让两个人同时编辑同一个文档、发表评论、编辑建议和更改跟踪 —— 更不用说它使用段落样式和能够下载完成的文档 —— 这使其成为编辑过程中有价值的一部分。

### LibreOffice

我开始使用的是 [LibreOffice](https://www.libreoffice.org/) 6.0，但我最终使用 LibreOffice 6.1 完成了这本书。我喜欢 LibreOffice 对样式的丰富支持。段落样式可以轻松地为标题、页眉、正文、示例代码和其他文本应用样式。字符样式允许我修改段落中文本的外观，例如内联示例代码或用不同的样式代表文件名。图形样式让我可以将某些样式应用于截图和其他图像。页面样式允许我轻松修改页面的布局和外观。

### GIMP

我的书包括很多 DOS 程序截图、网站截图和 FreeDOS 的 logo。我用 [GIMP](https://www.gimp.org/) 修改这本书的图像。通常，只是裁剪或调整图像大小，但在我准备本书的印刷版时，我使用 GIMP 创建了一些更适于打印布局的图像。

### Inkscape

大多数 FreeDOS 的 logo 和小鱼吉祥物都是 SVG 格式，我使用 [Inkscape](https://inkscape.org/) 来调整它们。在准备电子书的 PDF 版本时，我想在页面顶部放置一个简单的蓝色横幅，角落里有 FreeDOS 的 logo。实验后，我发现在 Inkscape 中创建一个我想要的横幅 SVG 图案更容易，然后我将其粘贴到页眉中。

### ImageMagick

虽然使用 GIMP 来完成这项工作也很好，但有时在一组图像上运行 [ImageMagick](https://www.imagemagick.org/) 命令会更快，例如转换为 PNG 格式或调整图像大小。

### Sigil

LibreOffice 可以直接导出到 EPUB 格式，但它不是个好的转换器。我没有尝试使用 LibreOffice 6.1 创建 EPUB，但在 LibreOffice 6.0 中没有包含我的图像。它还以奇怪的方式添加了样式。我使用 [Sigil](https://sigil-ebook.com/) 来调整 EPUB 并使一切看起来正常。Sigil 甚至还有预览功能，因此你可以看到 EPUB 的样子。

### QEMU

因为本书是关于安装和运行 FreeDOS 的，所以我需要实际运行 FreeDOS。你可以在任何 PC 模拟器中启动 FreeDOS，包括 VirtualBox、QEMU、GNOME Boxes、PCem 和 Bochs。但我喜欢 [QEMU](https://www.qemu.org/) 的简单性。QEMU 控制台允许你以 PPM 格式转储屏幕，这非常适合抓取截图来包含在书中。

当然，我不得不提到在 [Linux](https://www.kernel.org/) 上运行 [GNOME](https://www.gnome.org/)。我使用 Linux 的 [Fedora](https://getfedora.org/) 发行版。

---

via: <https://opensource.com/article/18/9/writing-book-open-source-tools>

作者：[Jim Hall](https://opensource.com/users/jim-hall) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


10 个最值得关注的树莓派博客

Summary: 如果你正在计划你的下一个树莓派项目，那么这些博客或许有帮助。

如果你正在计划你的下一个树莓派项目，那么这些博客或许有帮助。

# 10 个最值得关注的树莓派博客

>
> 如果你正在计划你的下一个树莓派项目，那么这些博客或许有帮助。
>
>
>

<img src="content_image/album_201811_02_231408nnq8es4n8c8cc3zy.png" alt="" title="">

网上有很多很棒的树莓派爱好者网站、教程、代码仓库、YouTube 频道和其他资源。以下是我最喜欢的十大树莓派博客，排名不分先后。

### 1、Raspberry Pi Spy

树莓派粉丝 Matt Hawkins 从很早开始就在他的网站 [Raspberry Pi Spy](https://www.raspberrypi-spy.co.uk/) 上撰写了大量全面且信息丰富的教程。我从这个网站上直接学到了很多东西，而且 Matt 似乎也总是涵盖到众多主题的第一个人。在我学习使用树莓派的前三年里，多次在这个网站得到帮助。

值得庆幸的是，这个不断采用新技术的网站仍然很强大。我希望看到它继续存在下去，让新社区成员在需要时得到帮助。

### 2、Adafruit

[Adafruit](https://blog.adafruit.com/category/raspberry-pi/) 是硬件黑客中知名品牌之一。该公司制作和销售漂亮的硬件，并提供由员工、社区成员，甚至 Lady Ada 女士自己编写的优秀教程。

除了网上商店，Adafruit 还经营一个博客，这个博客充满了来自世界各地的精彩内容。在博客上可以查看树莓派的类别，特别是在工作日的最后一天，会在 Adafruit Towers 举办名为 [Friday is Pi Day](https://blog.adafruit.com/category/raspberry-pi/) 的活动。

### 3、Recantha 的 Raspberry Pi Pod

Mike Horne（Recantha）是英国一位重要的树莓派社区成员，负责 [CamJam 和 Potton Pi＆Pint](https://camjam.me/?page_id=753)（剑桥的两个树莓派社团）以及 [Pi Wars](https://piwars.org/) （一年一度的树莓派机器人竞赛）。他为其他人建立树莓派社团提供建议，并且总是有时间帮助初学者。Horne 和他的共同组织者 Tim Richardson 一起开发了 CamJam Edu Kit （一系列小巧且价格合理的套件，适合初学者使用 Python 学习物理计算）。

除此之外，他还运营着 [Pi Pod](https://www.recantha.co.uk/blog/)，这是一个包含了世界各地树莓派相关内容的博客。它可能是这个列表中更新最频繁的树莓派博客，所以这是一个把握树莓派社区动向的极好方式。

### 4. Raspberry Pi 官方博客

必须提一下[树莓派基金会](https://www.raspberrypi.org/blog/)的官方博客，这个博客涵盖了基金会的硬件、软件、教育、社区、慈善和青年编码俱乐部的一系列内容。博客上的大型主题是家庭数字化、教育授权，以及硬件版本和软件更新的官方新闻。

该博客自 [2011 年](https://www.raspberrypi.org/blog/first-post/) 运行至今，并提供了自那时以来所有 1800 多个帖子的 [存档](https://www.raspberrypi.org/blog/archive/) 。你也可以在 Twitter 上关注[@raspberrypi\_otd](https://twitter.com/raspberrypi_otd)，这是我用 [Python](https://github.com/bennuttall/rpi-otd-bot/blob/master/src/bot.py) 创建的机器人（教程在这里：[Opensource.com](https://opensource.com/article/17/8/raspberry-pi-twitter-bot)）。Twitter 机器人推送来自博客存档的过去几年同一天的树莓派帖子。

### 5、RasPi.tv

另一位开创性的树莓派社区成员是 Alex Eames，通过他的博客和 YouTube 频道 [RasPi.tv](https://rasp.tv/)，他很早就加入了树莓派社区。他的网站为很多创客项目提供高质量、精心制作的视频教程和书面指南。

Alex 的网站 [RasP.iO](https://rasp.io/) 制作了一系列树莓派附加板和配件，包括方便的 GPIO 端口引脚、电路板测量尺等等。他的博客也拓展到了 [Arduino](https://www.arduino.cc/)、[WEMO](http://community.wemo.com/) 以及其他小网站。

### 6、pyimagesearch

虽然不是严格的树莓派博客（名称中的“py”是“Python”，而不是“树莓派”），但该网站的 [树莓派栏目](https://www.pyimagesearch.com/category/raspberry-pi/) 有着大量内容。 Adrian Rosebrock 获得了计算机视觉和机器学习领域的博士学位，他的博客旨在分享他在学习和制作自己的计算机视觉项目时所学到的机器学习技巧。

如果你想使用树莓派的相机模块学习面部或物体识别，来这个网站就对了。Adrian 在图像识别领域的深度学习和人工智能知识和实际应用是首屈一指的，而且他编写了自己的项目，这样任何人都可以进行尝试。

### 7、Raspberry Pi Roundup

这个[博客](https://thepihut.com/blogs/raspberry-pi-roundup)由英国官方树莓派经销商之一 The Pi Hut 进行维护，会有每周的树莓派新闻。这是另一个很好的资源，可以紧跟树莓派社区的最新资讯，而且之前的文章也值得回顾。

### 8、Dave Akerman

[Dave Akerman](http://www.daveakerman.com/) 是研究高空热气球的一流专家，他分享使用树莓派以最低的成本进行热气球发射方面的知识和经验。他会在一张由热气球拍摄的平流层照片下面对本次发射进行评论，也会对个人发射树莓派热气球给出自己的建议。

查看 Dave 的[博客](http://www.daveakerman.com/)，了解精彩的临近空间摄影作品。

### 9、Pimoroni

[Pimoroni](https://blog.pimoroni.com/) 是一家世界知名的树莓派经销商，其总部位于英国谢菲尔德。这家经销商制作了著名的 [树莓派彩虹保护壳](https://shop.pimoroni.com/products/pibow-for-raspberry-pi-3-b-plus)，并推出了许多极好的定制附加板和配件。

Pimoroni 的博客布局与其硬件设计和品牌推广一样精美，博文内容非常适合创客和业余爱好者在家进行创作，并且可以在有趣的 YouTube 频道 [Bilge Tank](https://www.youtube.com/channel/UCuiDNTaTdPTGZZzHm0iriGQ) 上找到。

### 10、Stuff About Code

Martin O'Hanlon 以树莓派社区成员的身份转为了树莓派基金会的员工，他起初出于乐趣在树莓派上开发“我的世界”作弊器，最近作为内容编辑加入了树莓派基金会。幸运的是，马丁的新工作并没有阻止他更新[博客](https://www.stuffaboutcode.com/)并与世界分享有益的趣闻。

除了“我的世界”的很多内容，你还可以在 Python 库、[Blue Dot](https://bluedot.readthedocs.io/en/latest/#) 和 [guizero](https://lawsie.github.io/guizero/) 上找到 Martin O'Hanlon 的贡献，以及一些总结性的树莓派技巧。

---

via: <https://opensource.com/article/18/8/top-10-raspberry-pi-blogs-follow>

作者：[Ben Nuttall](https://opensource.com/users/bennuttall) 选题：[lujun9972](https://github.com/lujun9972) 译者：[jlztan](https://github.com/jlztan) 校对：[wxy](https://github.com/wxy)

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


9 个提升开发者与设计师协作的方法

# 9 个提升开发者与设计师协作的方法

>
> 抛开成见，设计师和开发者的命运永远交织在一起。 以下是如何让每个人都在同一页面上。
>
>
>

<img src="content_image/album_201811_03_231741r8atzzk0k1jtja8t.png" alt="" title="">

在任何软件项目中，设计至关重要。设计师不像开发团队那样熟悉其内部工作，但迟早都要知道开发人员写代码的意图。

两边都有自己的成见。工程师经常认为设计师们古怪不理性，而设计师也认为工程师们死板要求高。在一天的工作快要结束时，情况会变得更加微妙。设计师和开发者们的命运永远交织在一起。

做到以下九件事，便可以改进他们之间的合作。

### 1. 首先，说实在的，打破壁垒

几乎每一个行业都有“<ruby> 迷墙 <rt>  wall of confusion </rt></ruby>”的因子。无论你干什么工作，拆除这堵墙的第一步就是要双方都认同它需要拆除。一旦所有的人都认为现有的流程效率低下，你就可以从其它想法中获得灵感，然后解决问题。

### 2. 学会共情

在开始干之前，先等一下。这是团队建设的重要的交汇点，也是建立共同认知的时机：我们都是成人，我们都有自己的优点与缺点，更重要的是，我们是一个团队。围绕工作流程与工作效率的讨论会经常发生，因此在开始之前，建立一个信任与协作的基础至关重要。

### 3. 认识差异

设计师和开发者从不同的角度攻克问题。对于相同的问题，设计师会追求更好的效果，而开发者会寻求更高的效率。这两种观点不必互相排斥。谈判和妥协的余地很大，并且在二者之间必然存在一个用户满意度最佳的中点。

### 4. 拥抱共性

这一切都是与工作流程相关的。<ruby> 持续集成 <rt>  Continuous Integration </rt></ruby>/<ruby> 持续交付 <rt>  Continuous Delivery </rt></ruby>，scrum，agile 等等，都基本上说了一件事：构思，迭代，考察，重复。迭代和重复是两种工作的相同点。因此，不再让开发周期紧跟设计周期，而是同时并行地运行它们，这样会更有意义。<ruby> 同步周期 <rt>  Syncing cycles </rt></ruby>允许团队在每个环节交流、协作、互相影响。

### 5. 管理期望

一切冲突的起因一言以蔽之：期望不符。因此，防止系统性分裂的简单办法就是通过确保团队成员在说之前先想、在做之前先说来管理期望。设定的期望往往会通过日常对话不断演变。强迫团队通过开会以达到其效果可能会适得其反。

### 6. 按需开会

只在工作开始和工作结束开一次会远远不够。但也不意味着每天或每周都要开会。定期开会也可能会适得其反。试着按需开会吧。即兴会议，即使是员工闲聊，也可能会发生很棒的事情。如果你的团队是分散式的或者甚至有一名远程员工，视频会议，文本聊天或者打电话都是开会的好方法。团队中的每人都有多种方式互相沟通，这一点非常重要。

### 7. 建立词库

设计师和开发者有时候对相似的想法有着不同的术语，就像把猫叫成喵。毕竟，比起术语的准确度和合适度来，大家统一说法才更重要。

### 8. 学会沟通

无论什么时候，团队中的每个人都有责任去维持一个有效的沟通。每个人都应该努力做到一字一板。

### 9. 不断改善

仅一名团队成员就能破坏整个进度。全力以赴。如果每个人都不关心产品或目标，继续项目或者做出改变的动机就会出现问题。

---

via: <https://opensource.com/article/18/5/9-ways-improve-collaboration-developers-designers>

作者：[Jason Brock](https://opensource.com/users/jkbrock), [Jason Porter](https://opensource.com/users/lightguardjp) 选题：[lujun9972](https://github.com/lujun9972) 译者：[LuuMing](https://github.com/LuuMing) 校对：[pityonline](https://github.com/pityonline)

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


如何分析并探索 Docker 容器镜像的内容

Summary: 我们将学会使用一个名为 Dive 的工具来分析和探索 Docker 镜像每层的内容。

# 如何分析并探索 Docker 容器镜像的内容

或许你已经了解到 Docker 容器镜像是一个轻量、独立、含有运行某个应用所需全部软件的可执行包，这也是为什么容器镜像会经常被开发者用于构建和分发应用。假如你很好奇一个 Docker 镜像里面包含了什么东西，那么这篇简要的指南或许会帮助到你。今天，我们将学会使用一个名为 **Dive** 的工具来分析和探索 Docker 镜像每层的内容。

通过分析 Docker 镜像，我们可以发现在各个层之间可能重复的文件并通过移除它们来减小 Docker 镜像的大小。Dive 工具不仅仅是一个 Docker 镜像分析工具，它还可以帮助我们来构建镜像。Dive 是一个用 Go 编程语言编写的自由开源工具。

### 安装 Dive

首先从该项目的 [发布页](https://github.com/wagoodman/dive/releases) 下载最新版本，然后像下面展示的那样根据你所使用的发行版来安装它。

假如你正在使用 **Debian** 或者 **Ubuntu**，那么可以运行下面的命令来下载并安装它。

```
$ wget https://github.com/wagoodman/dive/releases/download/v0.0.8/dive_0.0.8_linux_amd64.deb
```

```
$ sudo apt install ./dive_0.0.8_linux_amd64.deb
```

**在 RHEL 或 CentOS 系统中**

```
$ wget https://github.com/wagoodman/dive/releases/download/v0.0.8/dive_0.0.8_linux_amd64.rpm
```

```
$ sudo rpm -i dive_0.0.8_linux_amd64.rpm
```

Dive 也可以使用 [Linuxbrew](https://www.ostechnix.com/linuxbrew-common-package-manager-linux-mac-os-x/) 包管理器来安装。

```
$ brew tap wagoodman/dive
```

```
$ brew install dive
```

至于其他的安装方法，请参考 [Dive 项目的 GitHub 网页](https://github.com/wagoodman/dive)。

### 分析并探索 Docker 镜像的内容

要分析一个 Docker 镜像，只需要运行加上 Docker 镜像 ID 的 `dive` 命令就可以了。你可以使用 `sudo docker images` 来得到 Docker 镜像的 ID。

```
$ sudo dive ea4c82dcd15a
```

上面命令中的 `ea4c82dcd15a` 是某个镜像的 ID。

然后 `dive` 命令将快速地分析给定 Docker 镜像的内容并将它在终端中展示出来。

正如你在上面的截图中看到的那样，在终端的左边一栏列出了给定 Docker 镜像的各个层及其详细内容，浪费的空间大小等信息。右边一栏则给出了给定 Docker 镜像每一层的内容。你可以使用 `Ctrl+空格` 来在左右栏之间切换，使用 `UP`/`DOWN` 光标键来在目录树中进行浏览。

下面是 `dive` 的快捷键列表：

* `Ctrl+空格` —— 在左右栏之间切换
* `空格` —— 展开或收起目录树
* `Ctrl+A` —— 文件树视图：展示或隐藏增加的文件
* `Ctrl+R` —— 文件树视图：展示或隐藏被移除的文件
* `Ctrl+M` —— 文件树视图：展示或隐藏被修改的文件
* `Ctrl+U` —— 文件树视图：展示或隐藏未修改的文件
* `Ctrl+L` —— 层视图：展示当前层的变化
* `Ctrl+A` —— 层视图：展示总的变化
* `Ctrl+/` —— 筛选文件
* `Ctrl+C` —— 退出

在上面的例子中，我使用了 `sudo` 权限，这是因为我的 Docker 镜像存储在 `/var/lib/docker/` 目录中。假如你的镜像保存在你的家目录 （`$HOME`）或者在其他不属于 `root` 用户的目录，你就没有必要使用 `sudo` 命令。

你还可以使用下面的单个命令来构建一个 Docker 镜像并立刻分析该镜像：

```
$ dive build -t <some-tag>
```

Dive 工具仍处于 beta 阶段，所以可能会存在 bug。假如你遇到了 bug，请在该项目的 GitHub 主页上进行报告。

好了，这就是今天的全部内容。现在你知道如何使用 Dive 工具来探索和分析 Docker 容器镜像的内容以及利用它构建镜像。希望本文对你有所帮助。

更多精彩内容即将呈现，请保持关注！

干杯！

---

via: <https://www.ostechnix.com/how-to-analyze-and-explore-the-contents-of-docker-images/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[FSSlc](https://github.com/FSSlc) 校对：[wxy](https://github.com/wxy)

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