如何在 Linux 中检查密码的复杂性/强度和评分？

# 如何在 Linux 中检查密码的复杂性/强度和评分？

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

我们都知道密码的重要性。最好的密码就是使用难以猜测密码。另外，我建议你为每个服务使用不同的密码，如电子邮件、ftp、ssh 等。最重要的是，我建议你们经常更改密码，以避免不必要的黑客攻击。

默认情况下，RHEL 和它的衍生版使用 cracklib 模块来检查密码强度。我们将教你如何使用 cracklib 模块检查密码强度。

如果你想检查你创建的密码评分，请使用 pwscore 包。

如果你想创建一个好密码，最起码它应该至少有 12-15 个字符长度。它应该按以下组合创建，如字母（小写和大写）、数字和特殊字符。Linux 中有许多程序可用于检查密码复杂性，我们今天将讨论有关 cracklib 模块和 pwscore 评分。

### 如何在 Linux 中安装 cracklib 模块？

cracklib 模块在大多数发行版仓库中都有，因此，请使用发行版官方软件包管理器来安装它。

对于 Fedora 系统，使用 [DNF 命令](https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/)来安装 cracklib。

```
$ sudo dnf install cracklib
```

对于 Debian/Ubuntu 系统，使用 [APT-GET 命令](https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/) 或 [APT 命令](https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/)来安装 libcrack2。

```
$ sudo apt install libcrack2
```

对于基于 Arch Linux 的系统，使用 [Pacman 命令](https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/)来安装 cracklib。

```
$ sudo pacman -S cracklib
```

对于 RHEL/CentOS 系统，使用 [YUM 命令](https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/)来安装 cracklib。

```
$ sudo yum install cracklib
```

对于 openSUSE Leap 系统，使用 [Zypper 命令](https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/)来安装 cracklib。

```
$ sudo zypper install cracklib
```

### 如何在 Linux 中使用 cracklib 模块检查密码复杂性？

我在本文中添加了一些示例来助你更好地了解此模块。

如果你提供了任何如人名或地名或常用字，那么你将看到一条消息“它存在于字典的单词中”。

```
$ echo "password" | cracklib-check
password: it is based on a dictionary word
```

Linux 中的默认密码长度为 7 个字符。如果你提供的密码少于 7 个字符，那么你将看到一条消息“它太短了”。

```
$ echo "123" | cracklib-check
123: it is WAY too short
```

当你提供像我们这样的好密码时，你会看到 “OK”。

```
$ echo "ME$2w!@fgty6723" | cracklib-check
ME!@fgty6723: OK
```

### 如何在 Linux 中安装 pwscore？

pwscore 包在大多数发行版仓库中都有，因此，请使用发行版官方软件包管理器来安装它。

对于 Fedora 系统，使用 [DNF 命令](https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/)来安装 libpwquality。

```
$ sudo dnf install libpwquality
```

对于 Debian/Ubuntu 系统，使用 [APT-GET 命令](https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/) 或 [APT 命令](https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/)来安装 libpwquality。

```
$ sudo apt install libpwquality
```

对于基于 Arch Linux 的系统，使用 [Pacman 命令](https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/)来安装 libpwquality。

```
$ sudo pacman -S libpwquality
```

对于 RHEL/CentOS 系统，使用 [YUM 命令](https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/)来安装 libpwquality。

```
$ sudo yum install libpwquality
```

对于 openSUSE Leap 系统，使用 [Zypper 命令](https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/)来安装 libpwquality。

```
$ sudo zypper install libpwquality
```

如果你提供了任何如人名或地名或常用字，那么你将看到一条消息“它存在于字典的单词中”。

```
$ echo "password" | pwscore
Password quality check failed:
 The password fails the dictionary check - it is based on a dictionary word
```

Linux 中的默认密码长度为 7 个字符。如果你提供的密码少于 7 个字符，那么你将看到一条消息“密码短于 8 个字符”。

```
$ echo "123" | pwscore
Password quality check failed:
 The password is shorter than 8 characters
```

当你像我们这样提供了一个好的密码时，你将会看到“密码评分”。

```
$ echo "ME!@fgty6723" | pwscore
90
```

---

via: <https://www.2daygeek.com/how-to-check-password-complexity-strength-and-score-in-linux/>

作者：[Magesh Maruthamuthu](https://www.2daygeek.com/author/magesh/) 选题：[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/) 荣誉推出


浅析 Bash 中的 {花括号}

好文章！mark

# 浅析 Bash 中的 {花括号}

>
> 让我们继续我们的 Bash 基础之旅，来近距离观察一下花括号，了解一下如何和何时使用它们。
>
>
>

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

在前面的 Bash 基础系列文章中，我们或多或少地使用了一些还没有讲到的符号。在之前文章的很多例子中，我们都使用到了括号，但并没有重点讲解关于括号的内容。

这个系列接下来的文章中，我们会研究括号们的用法：如何使用这些括号？将它们放在不同的位置会有什么不同的效果？除了圆括号、方括号、花括号以外，我们还会接触另外的将一些内容“包裹”起来的符号，例如单引号、双引号和反引号。

在这周，我们先来看看花括号 `{}`。

### 构造序列

花括号在之前的《[点的含义](/article-10465-1.html)》这篇文章中已经出现过了，当时我们只对点号 `.` 的用法作了介绍。但在构建一个序列的过程中，同样不可以缺少花括号。

我们使用

```
echo {0..10}
```

来顺序输出 0 到 10 这 11 个数。使用

```
echo {10..0}
```

可以将这 11 个数倒序输出。更进一步，可以使用

```
echo {10..0..2}
```

来跳过其中的奇数。

而

```
echo {z..a..2}
```

则从倒序输出字母表，并跳过其中的第奇数个字母。

以此类推。

还可以将两个序列进行组合：

```
echo {a..z}{a..z}
```

这个命令会将从 aa 到 zz 的所有双字母组合依次输出。

这是很有用的。在 Bash 中，定义一个数组的方法是在圆括号 `()` 中放置各个元素并使用空格隔开，就像这样：

```
month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
```

如果需要获取数组中的元素，就要使用方括号 `[]` 并在其中填入元素的索引：

```
$ echo ${month[3]} # 数组索引从 0 开始，因此 [3] 对应第 4 个元素
Apr
```

先不要过分关注这里用到的三种括号，我们等下会讲到。

注意，像上面这样，我们可以定义这样一个数组：

```
letter_combos=({a..z}{a..z})
```

其中 `letter_combos` 变量指向的数组依次包含了从 aa 到 zz 的所有双字母组合。

因此，还可以这样定义一个数组：

```
dec2bin=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
```

在这里，`dec2bin` 变量指向的数组按照升序依次包含了所有 8 位的二进制数，也就是 00000000、00000001、00000010，……，11111111。这个数组可以作为一个十进制数到 8 位二进制数的转换器。例如将十进制数 25 转换为二进制数，可以这样执行：

```
$ echo ${dec2bin[25]}
00011001
```

对于进制转换，确实还有更好的方法，但这不失为一个有趣的方法。

### 参数展开

再看回前面的

```
echo ${month[3]}
```

在这里，花括号的作用就不是构造序列了，而是用于<ruby> 参数展开 <rt>  parameter expansion </rt></ruby>。顾名思义，参数展开就是将花括号中的变量展开为这个变量实际的内容。

我们继续使用上面的 `month` 数组来举例：

```
month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
```

注意，Bash 中的数组索引从 0 开始，因此 3 代表第 4 个元素 `"Apr"`。因此 `echo ${month[3]}` 在经过参数展开之后，相当于 `echo "Apr"`。

像上面这样将一个数组展开成它所有的元素，只是参数展开的其中一种用法。另外，还可以通过参数展开的方式读取一个字符串变量，并对其进行处理。

例如对于以下这个变量：

```
a="Too longgg"
```

如果执行：

```
echo ${a%gg}
```

可以输出 “too long”，也就是去掉了最后的两个 g。

在这里，

* `${...}` 告诉 shell 展开花括号里的内容
* `a` 就是需要操作的变量
* `%` 告诉 shell 需要在展开字符串之后从字符串的末尾去掉某些内容
* `gg` 是被去掉的内容

这个特性在转换文件格式的时候会比较有用，我来举个例子：

[ImageMagick](http://www.imagemagick.org/) 是一套可以用于操作图像文件的命令行工具，它有一个 `convert` 命令。这个 `convert` 命令的作用是可以为某个格式的图像文件制作一个另一格式的副本。

下面这个命令就是使用 `convert` 为 JPEG 格式图像 `image.jpg` 制作一个 PNG 格式的图像副本 `image.png`：

```
convert image.jpg image.png
```

在很多 Linux 发行版中都预装了 ImageMagick，如果没有预装，一般可以在发行版对应的软件管理器中找到。

继续来看，在对变量进行展开之后，就可以批量执行相类似的操作了：

```
i=image.jpg
convert $i ${i%jpg}png
```

这实际上是将变量 `i` 末尾的 `"jpg"` 去掉，然后加上 `"png"`，最终将整个命令拼接成 `convert image.jpg image.png`。

如果你觉得并不怎么样，可以想象一下有成百上千个图像文件需要进行这个操作，而仅仅运行：

```
for i in *.jpg; do convert $i ${i%jpg}png; done
```

就瞬间完成任务了。

如果需要去掉字符串开头的部分，就要将上面的 `%` 改成 `#` 了：

```
$ a="Hello World!"
$ echo Goodbye${a#Hello}
Goodbye World!
```

参数展开还有很多用法，但一般在写脚本的时候才会需要用到。在这个系列以后的文章中就继续提到。

### 合并输出

最后介绍一个花括号的用法，这个用法很简单，就是可以将多个命令的输出合并在一起。首先看下面这个命令：

```
echo "I found all these PNGs:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls > PNGs.txt
```

以分号分隔开的几条命令都会执行，但只有最后的 `ls` 命令的结果输出会被重定向到 `PNGs.txt` 文件中。如果将这几条命令用花括号包裹起来，就像这样：

```
{ echo "I found all these PNGs:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls; } > PNGs.txt
```

执行完毕后，可以看到 `PNGs.txt` 文件中会包含两次 `echo` 的内容、`find` 命令查找到的 PNG 文件以及最后的 `ls` 命令结果。

需要注意的是，花括号与命令之间需要有空格隔开。因为这里的花括号 `{` 和 `}` 是作为 shell 中的保留字，shell 会将这两个符号之间的输出内容组合到一起。

另外，各个命令之间要用分号 `;` 分隔，否则命令无法正常运行。

### 下期预告

在后续的文章中，我会介绍其它“包裹”类符号的用法，敬请关注。

---

via: <https://www.linux.com/blog/learn/2019/2/all-about-curly-braces-bash>

作者：[Paul Brown](https://www.linux.com/users/bro66) 选题：[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/) 荣誉推出


降低 Emacs 启动时间的高级技术

Summary: 《Emacs Start Up Profiler》 的作者教你六项减少 Emacs 启动时间的技术。

减少 Emacs 启动时间的技术，讲的不错。我还有个方法

换VIM或者换电脑。23333

# 降低 Emacs 启动时间的高级技术

>
> 《[Emacs Start Up Profiler](https://github.com/jschaf/esup)》 的作者教你六项减少 Emacs 启动时间的技术。
>
>
>

简而言之：做下面几个步骤：

1. 使用 Esup 进行性能检测。
2. 调整垃圾回收的阀值。
3. 使用 use-package 来自动（延迟）加载所有东西。
4. 不要使用会引起立即加载的辅助函数。
5. 参考我的 [配置](https://github.com/jschaf/dotfiles/blob/master/emacs/start.el)。

### 从 .emacs.d 的失败到现在

我最近宣布了 .emacs.d 的第三次失败，并完成了第四次 Emacs 配置的迭代。演化过程为：

1. 拷贝并粘贴 elisp 片段到 `~/.emacs` 中，希望它能工作。
2. 借助 `el-get` 来以更结构化的方式来管理依赖关系。
3. 放弃自己从零配置，以 Spacemacs 为基础。
4. 厌倦了 Spacemacs 的复杂性，基于 `use-package` 重写配置。

本文汇聚了三次重写和创建 《[Emacs Start Up Profiler](https://github.com/jschaf/esup)》过程中的技巧。非常感谢 Spacemacs、use-package 等背后的团队。没有这些无私的志愿者，这项任务将会困难得多。

### 不过守护进程模式又如何呢

在我们开始之前，让我反驳一下优化 Emacs 时的常见观念：“Emacs 旨在作为守护进程来运行的，因此你只需要运行一次而已。”

这个观点很好，只不过：

* 速度总是越快越好。
* 配置 Emacs 时，可能会有不得不通过重启 Emacs 的情况。例如，你可能为 `post-command-hook` 添加了一个运行缓慢的 `lambda` 函数，很难删掉它。
* 重启 Emacs 能帮你验证不同会话之间是否还能保留配置。

### 1、估算当前以及最佳的启动时间

第一步是测量当前的启动时间。最简单的方法就是在启动时显示后续步骤进度的信息。

```
;; Use a hook so the message doesn't get clobbered by other messages.
(add-hook 'emacs-startup-hook
    (lambda ()
        (message "Emacs ready in %s with %d garbage collections."
            (format "%.2f seconds"
                (float-time
                    (time-subtract after-init-time before-init-time)))
        gcs-done)))
```

第二步、测量最佳的启动速度，以便了解可能的情况。我的是 0.3 秒。

```
# -q ignores personal Emacs files but loads the site files.
emacs -q --eval='(message "%s" (emacs-init-time))'

;; For macOS users:
open -n /Applications/Emacs.app --args -q --eval='(message "%s" (emacs-init-time))'
```

### 2、检测 Emacs 启动指标对你大有帮助

《[Emacs StartUp Profiler](https://github.com/jschaf/esup)》（ESUP）将会给你顶层语句执行的详细指标。

*图 1: Emacs Start Up Profiler 截图*

>
> 警告：Spacemacs 用户需要注意，ESUP 目前与 Spacemacs 的 init.el 文件有冲突。遵照 <https://github.com/jschaf/esup/issues/48> 上说的进行升级。
>
>
>

### 3、调高启动时垃圾回收的阀值

这为我节省了 **0.3 秒**。

Emacs 默认值是 760kB，这在现代机器看来极其保守。真正的诀窍在于初始化完成后再把它降到合理的水平。这为我节省了 0.3 秒。

```
;; Make startup faster by reducing the frequency of garbage
;; collection.  The default is 800 kilobytes.  Measured in bytes.
(setq gc-cons-threshold (* 50 1000 1000))

;; The rest of the init file.

;; Make gc pauses faster by decreasing the threshold.
(setq gc-cons-threshold (* 2 1000 1000))
```

*~/.emacs.d/init.el*

### 4、不要 require 任何东西，而是使用 use-package 来自动加载

让 Emacs 变坏的最好方法就是减少要做的事情。`require` 会立即加载源文件，但是很少会出现需要在启动阶段就立即需要这些功能的。

在 [use-package](https://github.com/jwiegley/use-package) 中你只需要声明好需要哪个包中的哪个功能，`use-package` 就会帮你完成正确的事情。它看起来是这样的：

```
(use-package evil-lisp-state ; the Melpa package name

  :defer t ; autoload this package

  :init ; Code to run immediately.
  (setq evil-lisp-state-global nil)

  :config ; Code to run after the package is loaded.
  (abn/define-leader-keys "k" evil-lisp-state-map))
```

可以通过查看 `features` 变量来查看 Emacs 现在加载了那些包。想要更好看的输出可以使用 [lpkg explorer](https://gist.github.com/RockyRoad29/bd4ca6fdb41196a71662986f809e2b1c) 或者我在 [abn-funcs-benchmark.el](https://github.com/jschaf/dotfiles/blob/master/emacs/funcs/abn-funcs-benchmark.el) 中的变体。输出看起来类似这样的：

```
479 features currently loaded
  - abn-funcs-benchmark: /Users/jschaf/.dotfiles/emacs/funcs/abn-funcs-benchmark.el
  - evil-surround: /Users/jschaf/.emacs.d/elpa/evil-surround-20170910.1952/evil-surround.elc
  - misearch: /Applications/Emacs.app/Contents/Resources/lisp/misearch.elc
  - multi-isearch: nil
  - <many more>
```

### 5、不要使用辅助函数来设置模式

通常，Emacs 包会建议通过运行一个辅助函数来设置键绑定。下面是一些例子：

* `(evil-escape-mode)`
* `(windmove-default-keybindings) ; 设置快捷键。`
* `(yas-global-mode 1) ; 复杂的片段配置。`

可以通过 `use-package` 来对此进行重构以提高启动速度。这些辅助函数只会让你立即加载那些尚用不到的包。

下面这个例子告诉你如何自动加载 `evil-escape-mode`。

```
;; The definition of evil-escape-mode.
(define-minor-mode evil-escape-mode
  (if evil-escape-mode
      (add-hook 'pre-command-hook 'evil-escape-pre-command-hook)
    (remove-hook 'pre-command-hook 'evil-escape-pre-command-hook)))

;; Before:
(evil-escape-mode)

;; After:
(use-package evil-escape
  :defer t
  ;; Only needed for functions without an autoload comment (;;;###autoload).
  :commands (evil-escape-pre-command-hook)

  ;; Adding to a hook won't load the function until we invoke it.
  ;; With pre-command-hook, that means the first command we run will
  ;; load evil-escape.
  :init (add-hook 'pre-command-hook 'evil-escape-pre-command-hook))
```

下面来看一个关于 `org-babel` 的例子，这个例子更为复杂。我们通常的配置时这样的：

```
(org-babel-do-load-languages
 'org-babel-load-languages
 '((shell . t)
   (emacs-lisp . nil)))
```

这不是个好的配置，因为 `org-babel-do-load-languages` 定义在 `org.el` 中，而该文件有超过 2 万 4 千行的代码，需要花 0.2 秒来加载。通过查看源代码可以看到 `org-babel-do-load-languages` 仅仅只是加载 `ob-<lang>` 包而已，像这样：

```
;; From org.el in the org-babel-do-load-languages function.
(require (intern (concat "ob-" lang)))
```

而在 `ob-<lang>.el` 文件中，我们只关心其中的两个方法 `org-babel-execute:<lang>` 和 `org-babel-expand-body:<lang>`。我们可以延时加载 org-babel 相关功能而无需调用 `org-babel-do-load-languages`，像这样：

```
;; Avoid `org-babel-do-load-languages' since it does an eager require.
(use-package ob-python
  :defer t
  :ensure org-plus-contrib
  :commands (org-babel-execute:python))

(use-package ob-shell
  :defer t
  :ensure org-plus-contrib
  :commands
  (org-babel-execute:sh
   org-babel-expand-body:sh

   org-babel-execute:bash
   org-babel-expand-body:bash))
```

### 6、使用惰性定时器来推迟加载非立即需要的包

我推迟加载了 9 个包，这帮我节省了 **0.4 秒**。

有些包特别有用，你希望可以很快就能使用它们，但是它们本身在 Emacs 启动过程中又不是必须的。这些软件包包括：

* `recentf`：保存最近的编辑过的那些文件。
* `saveplace`：保存访问过文件的光标位置。
* `server`：开启 Emacs 守护进程。
* `autorevert`：自动重载被修改过的文件。
* `paren`：高亮匹配的括号。
* `projectile`：项目管理工具。
* `whitespace`：高亮行尾的空格。

不要 `require` 这些软件包，**而是等到空闲 N 秒后再加载它们**。我在 1 秒后加载那些比较重要的包，在 2 秒后加载其他所有的包。

```
(use-package recentf
  ;; Loads after 1 second of idle time.
  :defer 1)

(use-package uniquify
  ;; Less important than recentf.
  :defer 2)
```

### 不值得的优化

不要费力把你的 Emacs 配置文件编译成字节码了。这只节省了大约 0.05 秒。把配置文件编译成字节码还可能导致源文件与编译后的文件不一致从而难以重现错误进行调试。

---

via: <https://blog.d46.us/advanced-emacs-startup/>

作者：[Joe Schafer](https://blog.d46.us/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


在 Linux 中如何删除文件中的空行

# 在 Linux 中如何删除文件中的空行

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

有时你可能需要在 Linux 中删除某个文件中的空行。如果是的，你可以使用下面方法中的其中一个。有很多方法可以做到，但我在这里只是列举一些简单的方法。

你可能已经知道 `grep`、`awk` 和 `sed` 命令是专门用来处理文本数据的工具。

如果你想了解更多关于这些命令的文章，请访问这几个 URL：[在 Linux 中创建指定大小的文件的几种方法](https://www.2daygeek.com/create-a-file-in-specific-certain-size-linux/)，[在 Linux 中创建一个文件的几种方法](https://www.2daygeek.com/linux-command-to-create-a-file/) 以及 [在 Linux 中删除一个文件中的匹配的字符串](https://www.2daygeek.com/empty-a-file-delete-contents-lines-from-a-file-remove-matching-string-from-a-file-remove-empty-blank-lines-from-a-file/)。

这些属于高级命令，它们可用在大多数 shell 脚本中执行所需的操作。

下列 5 种方法可以做到。

* `sed`：过滤和替换文本的流编辑器。
* `grep`：输出匹配到的行。
* `cat`：合并文件并打印内容到标准输出。
* `tr`：替换或删除字符。
* `awk`：awk 工具用于执行 awk 语言编写的程序，专门用于文本处理。
* `perl`：Perl 是一种用于处理文本的编程语言。

我创建了一个 `2daygeek.txt` 文件来测试这些命令。下面是文件的内容。

```
$ cat 2daygeek.txt
2daygeek.com is a best Linux blog to learn Linux.

It's FIVE years old blog.

This website is maintained by Magesh M, it's licensed under CC BY-NC 4.0.

He got two GIRL babys.

Her names are Tanisha & Renusha.
```

现在一切就绪，我们准备开始用多种方法来验证。

### 使用 sed 命令

`sed` 是一个<ruby> 流编辑器 <rt>  stream editor </rt></ruby>。流编辑器是用来编辑输入流（文件或管道）中的文本的。

```
$ sed '/^$/d' 2daygeek.txt
2daygeek.com is a best Linux blog to learn Linux.
It's FIVE years old blog.
This website is maintained by Magesh M, it's licensed under CC BY-NC 4.0.
He got two GIRL babes.
Her names are Tanisha & Renusha.
```

以下是命令展开的细节：

* `sed`： 该命令本身。
* `//`： 标记匹配范围。
* `^`： 匹配字符串开头。
* `$`： 匹配字符串结尾。
* `d`： 删除匹配的字符串。
* `2daygeek.txt`： 源文件名。

### 使用 grep 命令

`grep` 可以通过正则表达式在文件中搜索。该表达式可以是一行或多行空行分割的字符，`grep` 会打印所有匹配的内容。

```
$ grep . 2daygeek.txt
or
$ grep -Ev "^$" 2daygeek.txt
or
$ grep -v -e '^$' 2daygeek.txt
2daygeek.com is a best Linux blog to learn Linux.
It's FIVE years old blog.
This website is maintained by Magesh M, it's licensed under CC BY-NC 4.0.
He got two GIRL babes.
Her names are Tanisha & Renusha.
```

以下是命令展开的细节：

* `grep`： 该命令本身。
* `.`： 替换任意字符。
* `^`： 匹配字符串开头。
* `$`： 匹配字符串结尾。
* `E`： 使用扩展正则匹配模式。
* `e`： 使用常规正则匹配模式。
* `v`： 反向匹配。
* `2daygeek.txt`： 源文件名。

### 使用 awk 命令

`awk` 可以执行使用 awk 语言写的脚本，大多是专用于处理文本的。awk 脚本是一系列 `awk` 命令和正则的组合。

```
$ awk NF 2daygeek.txt
or
$ awk '!/^$/' 2daygeek.txt
or
$ awk '/./' 2daygeek.txt
2daygeek.com is a best Linux blog to learn Linux.
It's FIVE years old blog.
This website is maintained by Magesh M, it's licensed under CC BY-NC 4.0.
He got two GIRL babes.
Her names are Tanisha & Renusha.
```

以下是命令展开的细节：

* `awk`： 该命令本身。
* `//`： 标记匹配范围。
* `^`： 匹配字符串开头。
* `$`： 匹配字符串结尾。
* `.`： 匹配任意字符。
* `!`： 删除匹配的字符串。
* `2daygeek.txt`： 源文件名。

### 使用 cat 和 tr 命令 组合

`cat` 是<ruby> 串联（拼接） <rt>  concatenate </rt></ruby>的简写。经常用于在 Linux 中读取一个文件的内容。

`cat` 是在类 Unix 系统中使用频率最高的命令之一。它提供了常用的三个处理文本文件的功能：显示文件内容、将多个文件拼接成一个，以及创建一个新文件。

`tr` 可以将标准输入中的字符转换，压缩或删除，然后重定向到标准输出。

```
$ cat 2daygeek.txt | tr -s '\n'
2daygeek.com is a best Linux blog to learn Linux.
It's FIVE years old blog.
This website is maintained by Magesh M, it's licensed under CC BY-NC 4.0.
He got two GIRL babes.
Her names are Tanisha & Renusha.
```

以下是命令展开的细节：

* `cat`： cat 命令本身。
* `tr`： tr 命令本身。
* `|`： 管道符号。它可以将前面的命令的标准输出作为下一个命令的标准输入。
* `s`： 替换标数据集中任意多个重复字符为一个。
* `\n`： 添加一个新的换行。
* `2daygeek.txt`： 源文件名。

### 使用 perl 命令

Perl 表示<ruby> 实用的提取和报告语言 <rt>  Practical Extraction and Reporting Language </rt></ruby>。Perl 在初期被设计为一个专用于文本处理的编程语言，现在已扩展应用到 Linux 系统管理，网络编程和网站开发等多个领域。

```
$ perl -ne 'print if /\S/' 2daygeek.txt
2daygeek.com is a best Linux blog to learn Linux.
It's FIVE years old blog.
This website is maintained by Magesh M, it's licensed under CC BY-NC 4.0.
He got two GIRL babes.
Her names are Tanisha & Renusha.
```

以下是命令展开的细节：

* `perl`： perl 命令。
* `n`： 逐行读入数据。
* `e`： 执行某个命令。
* `print`： 打印信息。
* `if`： if 条件分支。
* `//`： 标记匹配范围。
* `\S`： 匹配任意非空白字符。
* `2daygeek.txt`： 源文件名。

---

via: <https://www.2daygeek.com/remove-delete-empty-lines-in-a-file-in-linux/>

作者：[Magesh Maruthamuthu](https://www.2daygeek.com/author/magesh/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[pityonline](https://github.com/pityonline) 校对：[wxy](https://github.com/wxy)

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


Emoji-Log：编写 Git 提交信息的新方法

Summary: 使用 Emoji-Log 为你的提交添加上下文。

使用 Emoji-Log 为你的提交添加上下文。

# Emoji-Log：编写 Git 提交信息的新方法

>
> 使用 Emoji-Log 为你的提交添加上下文。
>
>
>

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

我是一名全职的开源开发人员，我喜欢称自己为“开源者”。我从事开源软件工作已经超过十年，并[构建了数以百计的](https://github.com/ahmadawais)开源软件应用程序。

同时我也是“<ruby> 避免重复工作 <rt>  Don’t Repeat Yourself </rt></ruby>”（DRY）哲学的忠实粉丝，并且我相信编写更好的 Git 提交消息是 DRY 的一个重要组成部分。它们具有足够的上下文关联，可以作为你开源软件的变更日志。我编写的众多工作流之一是 [Emoji-Log](https://github.com/ahmadawais/Emoji-Log/)，它是一个简单易用的开源 Git 提交日志标准。它通过使用表情符号来创建更好的 Git 提交消息，从而改善了开发人员的体验（DX）。

我使用 Emoji-Log 构建了 [VSCode Tips & Tricks 仓库](https://github.com/ahmadawais/VSCode-Tips-Tricks) 和我的 ? [紫色 VSCode 主题仓库](https://github.com/ahmadawais/shades-of-purple-vscode/commits/master)，以及一个看起来很漂亮的[自动变更日志](https://github.com/ahmadawais/shades-of-purple-vscode/blob/master/CHANGELOG.md)。

### Emoji-Log 的哲学

我喜欢（很多）表情符号，我很喜欢它们。编程、代码、极客/书呆子、开源……所有这一切本质上都很枯燥，有时甚至很无聊。表情符号帮助我添加颜色和情感。想要将感受添加到这个 2D 的、平板的、基于文本的代码世界并没有错。

相比于[数百个表情符号](https://gitmoji.carloscuesta.me/)，我学会的更好办法是让类别较小和普遍性。以下是指导使用 Emoji-Log 编写提交信息的原则：

* **必要的**
	+ Git 提交信息是必要的。
	+ 像下订单一样编写提交信息。
		- 例如，使用 ✅ **Add** 而不是 ❌ **Added**
		- 例如，使用 ✅ **Create** 而不是 ❌ **Creating**
* **规则**
	+ 少数类别易于记忆。
	+ 不多也不少
		- 例如 **? NEW** 、 **? IMPROVE** 、 **? FIX** 、 **? DOC** 、 **? RELEASE** 、 **✅ TEST**
* **行为**
	+ 让 Git 的提交基于你所采取的操作
	+ 使用像 [VSCode](https://VSCode.pro) 这样的编辑器来提交带有提交信息的正确文件。

### 编写提交信息

仅使用以下 Git 提交信息。简单而小巧的占地面积是 Emoji-Log 的核心。

* **? NEW: 必要的信息**
	+ 当你添加一些全新的东西时使用。
		- 例如 **? NEW: 添加 Git 忽略的文件**
* **? IMPROVE: 必要的信息**
	+ 用于改进/增强代码段，如重构等。
		- 例如 **? IMPROVE: 远程 IP API 函数**
* **? FIX: 必要的信息**
	+ 修复 bug 时使用，不用解释了吧？
		- 例如 **? FIX: Case converter**
* **? DOC: 必要的信息**
	+ 添加文档时使用，比如 README.md 甚至是内联文档。
		- 例如 **? DOC: API 接口教程**
* **? RELEASE: 必要的信息**
	+ 发布新版本时使用。例如， **? RELEASE: Version 2.0.0**
* **✅ TEST: 必要的信息**
	+ 发布新版本时使用。
		- 例如 **✅ TEST: 模拟用户登录/注销**

就这些了，不多不少。

### Emoji-Log 函数

为了快速构建原型，我写了以下函数，你可以将它们添加到 `.bashrc` 或者 `.zshrc` 文件中以快速使用 Emoji-Log。

```
#.# Better Git Logs.

### Using EMOJI-LOG (https://github.com/ahmadawais/Emoji-Log).

# Git Commit, Add all and Push — in one step.

function gcap() {
    git add . && git commit -m "$*" && git push
}

# NEW.
function gnew() {
    gcap "? NEW: $@"
}

# IMPROVE.
function gimp() {
    gcap "? IMPROVE: $@"
}

# FIX.
function gfix() {
    gcap "? FIX: $@"
}

# RELEASE.
function grlz() {
    gcap "? RELEASE: $@"
}

# DOC.
function gdoc() {
    gcap "? DOC: $@"
}

# TEST.
function gtst() {
    gcap "✅ TEST: $@"
}
```

要为 [fish shell](https://en.wikipedia.org/wiki/Friendly_interactive_shell) 安装这些函数，运行以下命令：

```
function gcap; git add .; and git commit -m "$argv"; and git push; end;
function gnew; gcap "? NEW: $argv"; end
function gimp; gcap "? IMPROVE: $argv"; end;
function gfix; gcap "? FIX: $argv"; end;
function grlz; gcap "? RELEASE: $argv"; end;
function gdoc; gcap "? DOC: $argv"; end;
function gtst; gcap "✅ TEST: $argv"; end;
funcsave gcap
funcsave gnew
funcsave gimp
funcsave gfix
funcsave grlz
funcsave gdoc
funcsave gtst
```

如果你愿意，可以将这些别名直接粘贴到 `~/.gitconfig` 文件：

```
# Git Commit, Add all and Push — in one step.
cap = "!f() { git add .; git commit -m \"$@\"; git push; }; f"

# NEW.
new = "!f() { git cap \"? NEW: $@\"; }; f"
# IMPROVE.
imp = "!f() { git cap \"? IMPROVE: $@\"; }; f"
# FIX.
fix = "!f() { git cap \"? FIX: $@\"; }; f"
# RELEASE.
rlz = "!f() { git cap \"? RELEASE: $@\"; }; f"
# DOC.
doc = "!f() { git cap \"? DOC: $@\"; }; f"
# TEST.
tst = "!f() { git cap \"✅ TEST: $@\"; }; f"
```

### Emoji-Log 例子

这里列出了一些使用 Emoji-Log 的仓库：

* [Create-guten-block toolkit](https://github.com/ahmadawais/create-guten-block/commits/)
* [VSCode Shades of Purple theme](https://github.com/ahmadawais/shades-of-purple-vscode/commits/)
* [Ahmad Awais' GitHub repos](https://github.com/ahmadawais) （我的最新的仓库）
* [CaptainCore CLI](https://github.com/CaptainCore/captaincore-cli/commits/) （WordPress 管理工具）
* [CaptainCore GUI](https://github.com/CaptainCore/captaincore-gui/commits/) （WordPress 插件）

你呢？如果你的仓库使用 Emoji-Log，请将这个 [Emoji-Log 徽章](https://on.ahmda.ws/rOMZ/c)放到你的 README 中，并给我发送一个[拉取请求](https://github.com/ahmadawais/Emoji-Log/pulls)，以让我可以将你的仓库列在这里。

---

via: <https://opensource.com/article/19/2/emoji-log-git-commit-messages>

作者：[Ahmad Awais](https://opensource.com/users/mrahmadawais) 选题：[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/) 荣誉推出


给大家安利一下 PowerShell

# 给大家安利一下 PowerShell

>
> 代码更简洁、脚本更清晰、跨平台一致性等好处是让 Linux 和 OS X 用户喜爱 PowerShell 的原因。
>
>
>

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

今年（2018）早些时候，[Powershell Core](https://github.com/PowerShell/PowerShell/blob/master/README.md) 以 [MIT](https://spdx.org/licenses/MIT) 开源协议发布了[正式可用版（GA）](https://blogs.msdn.microsoft.com/powershell/2018/01/10/powershell-core-6-0-generally-available-ga-and-supported/)。PowerShell 算不上是新技术。自 2006 年为 Windows 发布了第一版 PowerShell 以来，PowerShell 的创建者在[结合了](http://www.jsnover.com/Docs/MonadManifesto.pdf) Unⅸ shell 的强大和灵活的同时也在弥补他们所意识到的缺点，特别是从组合命令中获取值时所要进行的文本操作。

在发布了 5 个主要版本之后，PowerShell 已经可以在所有主流操作系统上（包括 OS X 和 Linux）本地运行同样创新的 shell 和命令行环境。一些人（应该说是大多数人）可能依旧在嘲弄这位诞生于 Windows 的闯入者的大胆和冒失：为那些远古以来（从千禧年开始算不算？）便存在着强大的 shell 环境的平台引荐自己。在本帖中，我希望可以将 PowerShell 的优势介绍给大家，甚至是那些经验老道的用户。

### 跨平台一致性

如果你计划将脚本从一个执行环境迁移到另一个平台时，你需要确保只使用了那些在两个平台下都起作用的命令和语法。比如在 GNU 系统中，你可以通过以下方式获取昨天的日期：

```
date --date="1 day ago"
```

在 BSD 系统中（比如 OS X），上述语法将没办法工作，因为 BSD 的 date 工具需要以下语法：

```
date -v -1d
```

因为 PowerShell 具有宽松的许可证，并且在所有的平台都有构建，所以你可以把 PowerShell 和你的应用一起打包。因此，当你的脚本运行在目标系统中时，它们会运行在一样的 shell 环境中，使用与你的测试环境中同样的命令实现。

### 对象和结构化数据

\*nix 命令和工具依赖于你使用和操控非结构化数据的能力。对于那些长期活在 `sed`、 `grep` 和 `awk` 环境下的人们来说，这可能是小菜一碟，但现在有更好的选择。

让我们使用 PowerShell 重写那个获取昨天日期的实例。为了获取当前日期，使用 `Get-Date` cmdlet（读作 “commandlet”）：

```
> Get-Date

Sunday, January 21, 2018 8:12:41 PM
```

你所看到的输出实际上并不是一个文本字符串。不如说，这是 .Net Core 对象的一个字符串表现形式。就像任何 OOP 环境中的对象一样，它具有类型以及你可以调用的方法。

让我们来证明这一点：

```
> $(Get-Date).GetType().FullName
System.DateTime
```

`$(...)` 语法就像你所期望的 POSIX shell 中那样，计算括弧中的命令然后替换整个表达式。但是在 PowerShell 中，这种表达式中的 `$` 是可选的。并且，最重要的是，结果是一个 .Net 对象，而不是文本。因此我们可以调用该对象中的 `GetType()` 方法来获取该对象类型（类似于 Java 中的 `Class` 对象），`FullName` [属性](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties) 则用来获取该类型的全称。

那么，这种对象导向的 shell 是如何让你的工作变得更加简单呢？

首先，你可将任何对象排进 `Get-Member` cmdlet 来查看它提供的所有方法和属性。

```
> (Get-Date) | Get-Member
PS /home/yevster/Documents/ArticlesInProgress> $(Get-Date) | Get-Member

   TypeName: System.DateTime

Name                 MemberType     Definition
----                 ----------     ----------
Add                  Method         datetime Add(timespan value)
AddDays              Method         datetime AddDays(double value)
AddHours             Method         datetime AddHours(double value)
AddMilliseconds      Method         datetime AddMilliseconds(double value)
AddMinutes           Method         datetime AddMinutes(double value)
AddMonths            Method         datetime AddMonths(int months)
AddSeconds           Method         datetime AddSeconds(double value)
AddTicks             Method         datetime AddTicks(long value)
AddYears             Method         datetime AddYears(int value)
CompareTo            Method         int CompareTo(System.Object value), int ...
```

你可以很快的看到 DateTime 对象具有一个 `AddDays` 方法，从而可以使用它来快速的获取昨天的日期：

```
> (Get-Date).AddDays(-1)

Saturday, January 20, 2018 8:24:42 PM
```

为了做一些更刺激的事，让我们调用 Yahoo 的天气服务（因为它不需要 API 令牌）然后获取你的本地天气。

```
$city="Boston"
$state="MA"
$url="https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22${city}%2C%20${state}%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
```

现在，我们可以使用老派的方法然后直接运行 `curl $url` 来获取 JSON 二进制对象，或者……

```
$weather=(Invoke-RestMethod $url)
```

如果你查看了 `$weather` 类型（运行 `echo $weather.GetType().FullName`），你将会发现它是一个 `PSCustomObject`。这是一个用来反射 JSON 结构的动态对象。

然后 PowerShell 可以通过 tab 补齐来帮助你完成命令输入。只需要输入 `$weather.`（确报包含了 `.`）然后按下 `Tab` 键。你将看到所有根级别的 JSON 键。输入其中的一个，然后跟上 `.` ，再一次按下 `Tab` 键，你将看到它所有的子键（如果有的话）。

因此，你可以轻易的导航到你所想要的数据：

```
> echo $weather.query.results.channel.atmosphere.pressure
1019.0

> echo $weather.query.results.channel.wind.chill                                 41
```

并且如果你有非结构化的 JSON 或 CSV 数据（通过外部命令返回的），只需要将它相应的排进 `ConverFrom-Json` 或 `ConvertFrom-CSV` cmdlet，然后你可以得到一个漂亮干净的对象。

### 计算 vs. 自动化

我们使用 shell 用于两种目的。一个是用于计算，运行独立的命令然后手动响应它们的输出。另一个是自动化，通过写脚本执行多个命令，然后以编程的方式相应它们的输出。

我们大多数人都能发现这两种目的在 shell 上的不同且互相冲突的要求。计算任务要求 shell 简洁明了。用户输入的越少越好。但如果用户输入对其他用户来说几乎难以理解，那这一点就不重要了。脚本，从另一个角度来讲是代码。可读性和可维护性是关键。这一方面，POSIX 工具通常是失败的。虽然一些命令通常会为它们的参数提供简洁明了的语法（如：`-f` 和 `--force`），但是命令名字本身就不简洁明了。

PowerShell 提供了几个机制来消除这种浮士德式的平衡。

首先，tab 补齐可以消除键入参数名的需要。比如：键入 `Get-Random -Mi`，按下 `Tab` 然后 PowerShell 将会为你完成参数：`Get-Random -Minimum`。但是如果你想更简洁一些，你甚至不需要按下 `Tab`。如下所示，PowerShell 可以理解：

```
Get-Random -Mi 1 -Ma 10
```

因为 `Mi` 和 `Ma` 每一个都具有独立不同的补齐。

你可能已经留意到所有的 PowerShell cmdlet 名称具有动名词结构。这有助于脚本的可读性，但是你可能不想一而再、再而三的键入 `Get-`。所以并不需要！如果你之间键入了一个名词而没有动词的话，PowerShell 将查找带有该名词的 `Get-` 命令。

>
> 小心：尽管 PowerShell 不区分大小写，但在使用 PowerShell 命令是时，名词首字母大写是一个好习惯。比如，键入 `date` 将会调用系统中的 `date` 工具。键入 `Date` 将会调用 PowerShell 的 `Get-Date` cmdlet。
>
>
>

如果这还不够，PowerShell 还提供了别名，用来创建简单的名字。比如，如果键入 `alias -name cd`，你将会发现 `cd` 在 PowerShell 实际上时 `Set-Location` 命令的别名。

所以回顾以下 —— 你可以使用强大的 tab 补全、别名，和名词补全来保持命令名词简洁、自动化和一致性参数名截断，与此同时还可以享受丰富、可读的语法格式。

### 那么……你看呢？

这些只是 PowerShell 的一部分优势。还有更多特性和 cmdlet，我还没讨论（如果你想弄哭 `grep` 的话，可以查看 [Where-Object](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/where-object?view=powershell-6) 或其别称 `?`）。如果你有点怀旧的话，PowerShell 可以为你加载原来的本地工具。但是给自己足够的时间来适应 PowerShell 面向对象 cmdlet 的世界，然后你将发现自己会选择忘记回去的路。

---

via: <https://opensource.com/article/18/2/powershell-people>

作者：[Yev Bronshteyn](https://opensource.com/users/yevster) 译者：[sanfusu](https://github.com/sanfusu) 校对：[wxy](https://github.com/wxy)

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


Summary: 今天，我在使用 Firefox 时遇到了一个奇怪的错误。

今天，我在使用 Firefox 时遇到了一个奇怪的错误。

# 如何修复 Mozilla Firefox 中出现的 “Network Protocol Error”

Mozilla Firefox 多年来一直是我的默认 Web 浏览器，我每天用它来进行日常网络活动，例如访问邮件，浏览喜欢的网站等。今天，我在使用 Firefox 时遇到了一个奇怪的错误。我试图在 Reddit 平台上分享我们的一个指南时，在 Firefox 上出现了以下错误消息：

>
> Network Protocol Error
>
>
> Firefox has experienced a network protocol violation that cannot be repaired.
>
>
> The page you are trying to view cannot be shown because an error in the network protocol was detected.
>
>
> Please contact the website owners to inform them of this problem.
>
>
>

老实说，我有点慌，我以为可能是我的系统受到了某种恶意软件的影响。哈哈！但是我发现我错了。我在 Arch Linux 桌面上使用的是最新的 Firefox 版本，我在 Chromium 浏览器中打开了相同的链接，它正确显示了，我猜这是 Firefox 相关的错误。在谷歌上搜索后，我解决了这个问题，如下所述。

出现这种问题主要是因为“浏览器缓存”，如果你遇到此类错误，例如 “Network Protocol Error” 或 “Corrupted Content Error”，遵循以下任何一种方法。

**方法 1：**

要修复 “Network Protocol Error” 或 “Corrupted Content Error”，你需要在重新加载网页时绕过缓存。为此，按下 `Ctrl + F5` 或 `Ctrl + Shift + R` 快捷键，它将从服务器重新加载页面，而不是从 Firefox 缓存加载。这样网页就应该可以正常工作了。

**方法 2：**

如果方法 1 不起作用，尝试以下方法。

打开 “Edit - > Preferences”，在 “Preferences” 窗口中，打开左窗格中的 “Privacy & Security” 选项卡，单击 “Clear Data” 选项清除 Firefox 缓存。

确保你选中了 “Cookies and Site Data” 和 “Cached Web Content” 选项，然后单击 “Clear”。

完成！现在 Cookie 和离线内容将被删除。注意，Firefox 可能会将你从登录的网站中注销，稍后你可以重新登录这些网站。最后，关闭 Firefox 浏览器并重新启动系统。现在网页加载没有任何问题。

希望这对你有帮助。更多好东西要来了，敬请关注！

干杯！

---

via: <https://www.ostechnix.com/how-to-fix-network-protocol-error-on-mozilla-firefox/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[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 安全：Cmd 提供可视化控制用户活动

Summary: Cmd 可以帮助机构监控、验证和阻止那些超出系统预期使用范围的活动。

Cmd 可以帮助机构监控、验证和阻止那些超出系统预期使用范围的活动。

# Linux 安全：Cmd 提供可视化控制用户活动

>
> Cmd 可以帮助机构监控、验证和阻止那些超出系统预期使用范围的活动。
>
>
>

有一个新的 Linux 安全工具你值得了解一下：Cmd（读作 “see em dee”），它极大地改变了可以对 Linux 用户进行控制的类型。它远远超出了传统的用户权限配置，并在监视和控制用户能够在 Linux 系统上运行的命令方面发挥了积极作用。

Cmd 由同名公司开发，专注于云应用。鉴于越来越多的应用迁移到依赖于 Linux 的云环境中，而可用工具的缺口使得难以充分实施所需的安全性。除此以外，Cmd 还可用于管理和保护本地系统。

### Cmd 与传统 Linux 安全控件的区别

Cmd 公司的领导 Milun Tesovic 和 Jake King 表示，除非了解了用户日常如何工作以及什么被视是“正常”，机构无法自信地预测或控制用户行为。他们寻求提供一种能够精细控制、监控和验证用户活动的工具。

Cmd 通过形成用户活动配置文件（描绘这些用户通常进行的活动）来监视用户活动，注意其在线行为的异常（登录时间、使用的命令、用户位置等），以及预防和报告某些意味着系统攻击的活动（例如，下载或修改文件和运行特权命令）。产品的行为是可配置的，可以快速进行更改。

如今大多数人用来检测威胁、识别漏洞和控制用户权限的工具，我们已经使用了很久了，但我们仍在努力抗争保持系统和数据的安全。Cmd 让我们更能够确定恶意用户的意图，无论这些用户是设法侵入帐户还是代表内部威胁。

*查看实时 Linux 会话*

### Cmd 如何工作？

在监视和管理用户活动时，Cmd 可以：

* 收集描述用户活动的信息
* 使用基线来确定什么是正常的
* 使用特定指标检测并主动防止威胁
* 向负责人发送警报

*在 Cmd 中构建自定义策略*

Cmd 扩展了系统管理员通过传统方法可以控制的内容，例如配置 `sudo` 权限，提供更精细和特定情境的控制。

管理员可以选择可以与 Linux 系统管理员所管理的用户权限控制分开管理的升级策略。

Cmd 客户端提供实时可视化（而不是事后日志分析），并且可以阻止操作、要求额外的身份验证或根据需要进行协商授权。

此外，如果有用户位置信息，Cmd 支持基于地理定位的自定义规则。并且可以在几分钟内将新策略推送到部署在主机上的客户端。

*在 Cmd 中构建触发器查询*

### Cmd 的融资新闻

[Cmd](https://cmd.com) 最近完成了由 [GV](https://www.gv.com/) （前身为 Google Ventures）领投，Expa、Amplify Partners 和其他战略投资者跟投的 [1500 万美元的融资](https://www.linkedin.com/pulse/changing-cybersecurity-announcing-cmds-15-million-funding-jake-king/)。这使该公司的融资金额达到了 2160 万美元，这将帮助其继续为该产品增加新的防御能力并发展其工程师团队。

此外，该公司还任命 GV 的普通合伙人 Karim Faris 为董事会成员。

---

via: <https://www.networkworld.com/article/3342454/linux-security-cmd-provides-visibility-control-over-user-activity.html>

作者：[Sandra Henry-Stocker](https://www.networkworld.com/author/Sandra-Henry_Stocker/) 选题：[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/) 荣誉推出


toplip：一款十分强大的文件加密解密 CLI 工具

Summary: 它是一款使用一种叫做 AES256 的强大加密方法的自由开源的加密工具。它同时也使用了 XTS-AES 设计以保护你的隐私数据。它还使用了 Scrypt，一种基于密码的密钥生成函数来保护你的密码免于暴力破解。

# toplip：一款十分强大的文件加密解密 CLI 工具

在市场上能找到许多用来保护文件的文档加密工具。我们已经介绍过其中一些例如 [Cryptomater](https://www.ostechnix.com/cryptomator-open-source-client-side-encryption-tool-cloud/)、[Cryptkeeper](https://www.ostechnix.com/how-to-encrypt-your-personal-foldersdirectories-in-linux-mint-ubuntu-distros/)、[CryptGo](https://www.ostechnix.com/cryptogo-easy-way-encrypt-password-protect-files/)、[Cryptr](https://www.ostechnix.com/cryptr-simple-cli-utility-encrypt-decrypt-files/)、[Tomb](https://www.ostechnix.com/tomb-file-encryption-tool-protect-secret-files-linux/)，以及 [GnuPG](https://www.ostechnix.com/an-easy-way-to-encrypt-and-decrypt-files-from-commandline-in-linux/) 等加密工具。今天我们将讨论另一款叫做 “toplip” 的命令行文件加密解密工具。它是一款使用一种叫做 [AES256](http://en.wikipedia.org/wiki/Advanced_Encryption_Standard) 的强大加密方法的自由开源的加密工具。它同时也使用了 XTS-AES 设计以保护你的隐私数据。它还使用了 [Scrypt](http://en.wikipedia.org/wiki/Scrypt)，一种基于密码的密钥生成函数来保护你的密码免于暴力破解。

### 优秀的特性

相比于其它文件加密工具，toplip 自带以下独特且杰出的特性。

* 非常强大的基于 XTS-AES256 的加密方法。
* <ruby> 合理的推诿 <rt>  Plausible deniability </rt></ruby>。
* 加密并嵌入文件到图片（PNG/JPG）中。
* 多重密码保护。
* 可防护直接暴力破解。
* 无可辨识的输出标记。
* 开源（GPLv3）。

### 安装 toplip

没有什么需要安装的。`toplip` 是独立的可执行二进制文件。你所要做的仅是从 [产品官方页面](https://2ton.com.au/Products/) 下载最新版的 `toplip` 并赋予它可执行权限。为此你只要运行：

```
chmod +x toplip
```

### 使用

如果你不带任何参数运行 `toplip`，你将看到帮助页面。

```
./toplip
```

请允许我给你展示一些例子。

为了达到指导目的，我建了两个文件 `file1` 和 `file2`。我同时也有 `toplip` 可执行二进制文件。我把它们全都保存进一个叫做 `test` 的目录。

#### 加密/解密单个文件

现在让我们加密 `file1`。为此，运行：

```
./toplip file1 > file1.encrypted
```

这行命令将让你输入密码。一旦你输入完密码，它就会加密 `file1` 的内容并将它们保存进你当前工作目录下一个叫做 `file1.encrypted` 的文件。

上述命令行的示例输出将会是这样：

```
This is toplip v1.20 (C) 2015, 2016 2 Ton Digital. Author: Jeff Marrison A showcase piece for the HeavyThing library. Commercial support available Proudly made in Cooroy, Australia. More info: https://2ton.com.au/toplip file1 Passphrase #1: generating keys...Done
Encrypting...Done
```

为了验证文件是否的确经过加密，试着打开它你会发现一些随机的字符。

为了解密加密过的文件，像以下这样使用 `-d` 参数：

```
./toplip -d file1.encrypted
```

这行命令会解密提供的文档并在终端窗口显示内容。

为了保存文档而不是写入到标准输出，运行：

```
./toplip -d file1.encrypted > file1.decrypted
```

输入正确的密码解密文档。`file1.encrypted` 的所有内容将会存入一个叫做 `file1.decrypted` 的文档。

请不要用这种命名方法，我这样用仅仅是为了便于理解。使用其它难以预测的名字。

#### 加密/解密多个文件

现在我们将使用两个分别的密码加密每个文件。

```
./toplip -alt file1 file2 > file3.encrypted
```

你会被要求为每个文件输入一个密码，使用不同的密码。

上述命令行的示例输出将会是这样：

```
This is toplip v1.20 (C) 2015, 2016 2 Ton Digital. Author: Jeff Marrison A showcase piece for the HeavyThing library. Commercial support available Proudly made in Cooroy, Australia. More info: https://2ton.com.au/toplip
file2 Passphrase #1 : generating keys...Done
file1 Passphrase #1 : generating keys...Done
Encrypting...Done
```

上述命令所做的是加密两个文件的内容并将它们保存进一个单独的叫做 `file3.encrypted` 的文件。在保存中分别给予各自的密码。比如说如果你提供 `file1` 的密码，`toplip` 将复原 `file1`。如果你提供 `file2` 的密码，`toplip` 将复原 `file2`。

每个 `toplip` 加密输出都可能包含最多四个单独的文件，并且每个文件都建有各自独特的密码。由于加密输出放在一起的方式，一下判断出是否存在多个文档不是一件容易的事。默认情况下，甚至就算确实只有一个文件是由 `toplip` 加密，随机数据都会自动加上。如果指定了多于一个文件，每个都有自己的密码，那么你可以有选择性地独立解码每个文件，以此来否认其它文件存在的可能性。这能有效地使一个用户在可控的暴露风险下打开一个加密的捆绑文件包。并且对于敌人来说，在计算上没有一种低廉的办法来确认额外的秘密数据存在。这叫做“<ruby> 合理的推诿 <rt>  Plausible deniability </rt></ruby>”，是 toplip 著名的特性之一。

为了从 `file3.encrypted` 解码 `file1`，仅需输入：

```
./toplip -d file3.encrypted > file1.encrypted
```

你将会被要求输入 `file1` 的正确密码。

为了从 `file3.encrypted` 解码 `file2`，输入：

```
./toplip -d file3.encrypted > file2.encrypted
```

别忘了输入 `file2` 的正确密码。

#### 使用多重密码保护

这是我中意的另一个炫酷特性。在加密过程中我们可以为单个文件提供多重密码。这样可以保护密码免于暴力尝试。

```
./toplip -c 2 file1 > file1.encrypted
```

这里，`-c 2` 代表两个不同的密码。上述命令行的示例输出将会是这样：

```
This is toplip v1.20 (C) 2015, 2016 2 Ton Digital. Author: Jeff Marrison A showcase piece for the HeavyThing library. Commercial support available Proudly made in Cooroy, Australia. More info: https://2ton.com.au/toplip
file1 Passphrase #1: generating keys...Done
file1 Passphrase #2: generating keys...Done
Encrypting...Done
```

正如你在上述示例中所看到的，`toplip` 要求我输入两个密码。请注意你必须提供两个不同的密码，而不是提供两遍同一个密码。

为了解码这个文件，这样做：

```
$ ./toplip -c 2 -d file1.encrypted > file1.decrypted
This is toplip v1.20 (C) 2015, 2016 2 Ton Digital. Author: Jeff Marrison A showcase piece for the HeavyThing library. Commercial support available Proudly made in Cooroy, Australia. More info: https://2ton.com.au/toplip
file1.encrypted Passphrase #1: generating keys...Done
file1.encrypted Passphrase #2: generating keys...Done
Decrypting...Done
```

#### 将文件藏在图片中

将一个文件、消息、图片或视频藏在另一个文件里的方法叫做隐写术。幸运的是 `toplip` 默认包含这个特性。

为了将文件藏入图片中，像如下所示的样子使用 `-m` 参数。

```
$ ./toplip -m image.png file1 > image1.png
This is toplip v1.20 (C) 2015, 2016 2 Ton Digital. Author: Jeff Marrison A showcase piece for the HeavyThing library. Commercial support available Proudly made in Cooroy, Australia. More info: https://2ton.com.au/toplip
file1 Passphrase #1: generating keys...Done
Encrypting...Done
```

这行命令将 `file1` 的内容藏入一张叫做 `image1.png` 的图片中。

要解码，运行：

```
$ ./toplip -d image1.png > file1.decrypted This is toplip v1.20 (C) 2015, 2016 2 Ton Digital. Author: Jeff Marrison A showcase piece for the HeavyThing library. Commercial support available Proudly made in Cooroy, Australia. More info: https://2ton.com.au/toplip
image1.png Passphrase #1: generating keys...Done
Decrypting...Done
```

#### 增加密码复杂度

为了进一步使文件变得难以破译，我们可以像以下这样增加密码复杂度：

```
./toplip -c 5 -i 0x8000 -alt file1 -c 10 -i 10 file2 > file3.encrypted
```

上述命令将会要求你为 `file1` 输入十条密码，为 `file2` 输入五条密码，并将它们存入单个叫做 `file3.encrypted` 的文件。如你所注意到的，我们在这个例子中又用了另一个 `-i` 参数。这是用来指定密钥生成循环次数。这个选项覆盖了 `scrypt` 函数初始和最终 PBKDF2 阶段的默认循环次数 1。十六进制和十进制数值都是允许的。比如说 `0x8000`、`10` 等。请注意这会大大增加计算次数。

为了解码 `file1`，使用：

```
./toplip -c 5 -i 0x8000 -d file3.encrypted > file1.decrypted
```

为了解码 `file2`，使用：

```
./toplip -c 10 -i 10 -d file3.encrypted > file2.decrypted
```

参考 `toplip` [官网](https://2ton.com.au/toplip/)以了解更多关于其背后的技术信息和使用的加密方式。

我个人对所有想要保护自己数据的人的建议是，别依赖单一的方法。总是使用多种工具/方法来加密文件。不要在纸上写下密码也不要将密码存入本地或云。记住密码，阅后即焚。如果你记不住，考虑使用任何了信赖的密码管理器。

* [KeeWeb – An Open Source, Cross Platform Password Manager](https://www.ostechnix.com/keeweb-an-open-source-cross-platform-password-manager/)
* [Buttercup – A Free, Secure And Cross-platform Password Manager](https://www.ostechnix.com/buttercup-a-free-secure-and-cross-platform-password-manager/)
* [Titan – A Command line Password Manager For Linux](https://www.ostechnix.com/titan-command-line-password-manager-linux/)

今天就到此为止了，更多好东西后续推出，请保持关注。

顺祝时祺！

---

via: <https://www.ostechnix.com/toplip-strong-file-encryption-decryption-cli-utility/>

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

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


高效使用 Org 模式

Summary: 在我 前一篇关于 Emacs 的文章中 我提到了 Org 模式（Org-mode），这是一个笔记管理工具和组织工具。本文中，我将会描述一下我日常的 Org 模式使用案例。

受虐使我快乐。因为我会得到高手的称谓。

来自湖北武汉的 Chrome Mobile 57.0|Android 8.1 用户

# 高效使用 Org 模式

### 简介

在我 [前一篇关于 Emacs 的文章中](http://www.badykov.com/emacs/2018/07/31/why-emacs-is-a-great-editor/) 我提到了 <ruby>   Org 模式  <rt>  Org-mode </rt></ruby>，这是一个笔记管理工具和组织工具。本文中，我将会描述一下我日常的 Org 模式使用案例。

### 笔记和代办列表

首先而且最重要的是，Org 模式是一个管理笔记和待办列表的工具，Org 模式的所有工具都聚焦于使用纯文本文件记录笔记。我使用 Org 模式管理多种笔记。

#### 一般性笔记

Org 模式最基本的应用场景就是以笔记的形式记录下你想记住的事情。比如，下面是我正在学习的笔记内容：

```
* Learn
** Emacs LISP
*** Plan

   - [ ] Read best practices
   - [ ] Finish reading Emacs Manual
   - [ ] Finish Exercism Exercises
   - [ ] Write a couple of simple plugins
     - Notification plugin

*** Resources

   https://www.gnu.org/software/emacs/manual/html_node/elisp/index.html
   http://exercism.io/languages/elisp/about
   [[http://batsov.com/articles/2011/11/30/the-ultimate-collection-of-emacs-resources/][The Ultimate Collection of Emacs Resources]]

** Rust gamedev
*** Study [[https://github.com/SergiusIW/gate][gate]] 2d game engine with web assembly support
*** [[ggez][https://github.com/ggez/ggez]]
*** [[https://www.amethyst.rs/blog/release-0-8/][Amethyst 0.8 Relesed]]

** Upgrade Elixir/Erlang Skills
*** Read Erlang in Anger
```

借助 [org-bullets](https://github.com/sabof/org-bullets) 它看起来是这样的：

在这个简单的例子中，你能看到 Org 模式的一些功能：

* 笔记允许嵌套
* 链接
* 带复选框的列表

#### 项目待办

我在工作时时常会发现一些能够改进或修复的事情。我并不会在代码文件中留下 TODO 注释 (坏味道)，相反我使用 [org-projectile](https://github.com/IvanMalison/org-projectile) 来在另一个文件中记录一个 TODO 事项，并留下一个快捷方式。下面是一个该文件的例子：

```
* [[elisp:(org-projectile-open-project%20"mana")][mana]] [3/9]
  :PROPERTIES:
  :CATEGORY: mana
  :END:
** DONE [[file:~/Development/mana/apps/blockchain/lib/blockchain/contract/create_contract.ex::insufficient_gas_before_homestead%20=][fix this check using evm.configuration]]
   CLOSED: [2018-08-08 Ср 09:14]
  [[https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md][eip2]]:
  If contract creation does not have enough gas to pay for the final gas fee for
  adding the contract code to the state, the contract creation fails (i.e. goes out-of-gas)
  rather than leaving an empty contract.
** DONE Upgrade Elixir to 1.7.
   CLOSED: [2018-08-08 Ср 09:14]
** TODO [#A] Difficulty tests
** TODO [#C] Upgrage to OTP 21
** DONE [#A] EIP150
   CLOSED: [2018-08-14 Вт 21:25]
*** DONE operation cost changes
    CLOSED: [2018-08-08 Ср 20:31]
*** DONE 1/64th for a call and create
    CLOSED: [2018-08-14 Вт 21:25]
** TODO [#C] Refactor interfaces
** TODO [#B] Caching for storage during execution
** TODO [#B] Removing old merkle trees
** TODO do not calculate cost twice
* [[elisp:(org-projectile-open-project%20".emacs.d")][.emacs.d]] [1/3]
  :PROPERTIES:
  :CATEGORY: .emacs.d
  :END:
** TODO fix flycheck issues (emacs config)
** TODO use-package for fetching dependencies
** DONE clean configuration
   CLOSED: [2018-08-26 Вс 11:48]
```

它看起来是这样的：

本例中你能看到更多的 Org 模式的功能：

* 代办列表具有 `TODO`、`DONE` 两个状态。你还可以定义自己的状态 (`WAITING` 等)
* 关闭的事项有 `CLOSED` 时间戳
* 有些事项有优先级 - A、B、C
* 链接可以指向文件内部 (`[[file:~/。..]`)

#### 捕获模板

正如 Org 模式的文档中所描述的，捕获可以在不怎么干扰你工作流的情况下让你快速存储笔记。

我配置了许多捕获模板，可以帮我快速记录想要记住的事情。

```
  (setq org-capture-templates
        '(("t" "Todo" entry (file+headline "~/Dropbox/org/todo.org" "Todo soon")
           "* TODO %? \n  %^t")
          ("i" "Idea" entry (file+headline "~/Dropbox/org/ideas.org" "Ideas")
           "* %? \n %U")
          ("e" "Tweak" entry (file+headline "~/Dropbox/org/tweaks.org" "Tweaks")
           "* %? \n %U")
          ("l" "Learn" entry (file+headline "~/Dropbox/org/learn.org" "Learn")
           "* %? \n")
          ("w" "Work note" entry (file+headline "~/Dropbox/org/work.org" "Work")
           "* %? \n")
          ("m" "Check movie" entry (file+headline "~/Dropbox/org/check.org" "Movies")
           "* %? %^g")
          ("n" "Check book" entry (file+headline "~/Dropbox/org/check.org" "Books")
           "* %^{book name} by %^{author} %^g")))
```

做书本记录时我需要记下它的名字和作者，做电影记录时我需要记下标签，等等。

### 规划

Org 模式的另一个超棒的功能是你可以用它来作日常规划。让我们来看一个例子：

我没有挖空心思虚构一个例子，这就是我现在真实文件的样子。它看起来内容并不多，但它有助于你花时间在在重要的事情上并且帮你对抗拖延症。

#### 习惯

根据 Org 模式的文档，Org 能够跟踪一种特殊的代办事情，称为 “习惯”。当我想养成新的习惯时，我会将该功能与日常规划功能一起连用：

你可以看到，目前我在尝试每天早期并且每两天锻炼一次。另外，它也有助于让我每天阅读书籍。

#### 议事日程视图

最后，我还使用议事日程视图功能。待办事项可能分散在不同文件中(比如我就是日常规划和习惯分散在不同文件中)，议事日程视图可以提供所有待办事项的总览：

### 更多 Org 模式的功能

* 手机应用（[Android](https://play.google.com/store/apps/details%EF%BC%9Fid=com.orgzly&hl=en)、[ios](https://itunes.apple.com/app/id1238649962%5D)）
* [将 Org 模式文档导出为其他格式](https://orgmode.org/manual/Exporting.html)（html、markdown、pdf、latex 等）
* 使用 [ledger](https://github.com/ledger/ledger-mode) [追踪财务状况](https://orgmode.org/worg/org-tutorials/weaving-a-budget.html)

### 总结

本文我描述了 Org 模式广泛功能中的一小部分，我每天都用它来提高工作效率，把时间花在重要的事情上。

---

via: <https://www.badykov.com/emacs/2018/08/26/be-productive-with-org-mode/>

作者：[Ayrat Badykov](https://www.badykov.com) 选题：[lujun9972](https://github.com/lujun9972) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


如何在 Linux 中查看可用的网络接口

真好

# 如何在 Linux 中查看可用的网络接口

在我们安装完一个 Linux 系统后最为常见的任务便是网络配置了。当然，你可以在安装系统时进行网络接口的配置。但是，对于某些人来说，他们更偏爱在安装完系统后再进行网络的配置或者更改现存的设置。众所周知，为了在命令行中进行网络设定的配置，我们首先必须知道系统中有多少个可用的网络接口。本次这个简单的指南将列出所有可能的方式来在 Linux 和 Unix 操作系统中找到可用的网络接口。

### 在 Linux 中找到可用的网络接口

我们可以使用下面的这些方法来找到可用的网络接口。

#### 方法 1 使用 ifconfig 命令

使用 `ifconfig` 命令来查看网络接口仍然是最常使用的方法。我相信还有很多 Linux 用户仍然使用这个方法。

```
$ ifconfig -a
```

示例输出：

```
enp5s0: flags=4098<BROADCAST,MULTICAST> mtu 1500
    ether 24:b6:fd:37:8b:29 txqueuelen 1000 (Ethernet)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 171420 bytes 303980988 (289.8 MiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 171420 bytes 303980988 (289.8 MiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

wlp9s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.225.37 netmask 255.255.255.0 broadcast 192.168.225.255
    inet6 2409:4072:6183:c604:c218:85ff:fe50:474f prefixlen 64 scopeid 0x0<global>
    inet6 fe80::c218:85ff:fe50:474f prefixlen 64 scopeid 0x20<link>
    ether c0:18:85:50:47:4f txqueuelen 1000 (Ethernet)
    RX packets 564574 bytes 628671925 (599.5 MiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 299706 bytes 60535732 (57.7 MiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
```

如上面的输出所示，在我的 Linux 机器上有两个网络接口，它们分别叫做 `enp5s0`（主板上的有线网卡）和 `wlp9s0`（无线网卡）。其中的 `lo` 是环回网卡，被用来访问本地的网络的服务，通常它的 IP 地址为 `127.0.0.1`。

我们也可以在许多 UNIX 变种例如 FreeBSD 中使用相同的 `ifconfig` 来列出可用的网卡。

#### 方法 2 使用 ip 命令

在最新的 Linux 版本中， `ifconfig` 命令已经被弃用了。你可以使用 `ip` 命令来罗列出网络接口，正如下面这样：

```
$ ip link show
```

示例输出：

```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp5s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 24:b6:fd:37:8b:29 brd ff:ff:ff:ff:ff:ff
3: wlp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DORMANT group default qlen 1000
    link/ether c0:18:85:50:47:4f brd ff:ff:ff:ff:ff:ff
```

你也可以使用下面的命令来查看。

```
$ ip addr
```

```
$ ip -s link
```

你注意到了吗？这些命令同时还显示出了已经连接的网络接口的状态。假如你仔细查看上面的输出，你将注意到我的有线网卡并没有跟网络线缆连接（从上面输出中的 `DOWN` 可以看出）。另外，我的无线网卡已经连接了（从上面输出中的 `UP` 可以看出）。想知晓更多的细节，可以查看我们先前的指南 [在 Linux 中查看网络接口的已连接状态](https://www.ostechnix.com/how-to-find-out-the-connected-state-of-a-network-cable-in-linux/)。

这两个命令（`ifconfig` 和 `ip`）已经足够在你的 LInux 系统中查看可用的网卡了。

然而，仍然有其他方法来列出 Linux 中的网络接口，下面我们接着看。

#### 方法 3 使用 /sys/class/net 目录

Linux 内核将网络接口的详细信息保存在 `/sys/class/net` 目录中，你可以通过查看这个目录的内容来检验可用接口的列表是否和前面的结果相符。

```
$ ls /sys/class/net
```

示例输出：

```
enp5s0 lo wlp9s0
```

#### 方法 4 使用 /proc/net/dev 目录

在 Linux 操作系统中，文件 `/proc/net/dev` 中包含有关网络接口的信息。

要查看可用的网卡，只需使用下面的命令来查看上面文件的内容：

```
$ cat /proc/net/dev
```

示例输出：

```
Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
wlp9s0: 629189631 566078 0 0 0 0 0 0 60822472 300922 0 0 0 0 0 0
enp5s0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
lo: 303980988 171420 0 0 0 0 0 0 303980988 171420 0 0 0 0 0 0
```

#### 方法 5 使用 netstat 命令

`netstat` 命令可以列出各种不同的信息，例如网络连接、路由表、接口统计信息、伪装连接和多播成员等。

```
$ netstat -i
```

示例输出：

```
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
lo 65536 171420 0 0 0 171420 0 0 0 LRU
wlp9s0 1500 565625 0 0 0 300543 0 0 0 BMRU
```

请注意 `netstat` 被弃用了， `netstat -i` 的替代命令是 `ip -s link`。另外需要注意的是这个方法将只列出激活的接口，而不是所有可用的接口。

#### 方法 6 使用 nmcli 命令

`nmcli` 是一个用来控制 NetworkManager 和报告网络状态的命令行工具。它可以被用来创建、展示、编辑、删除、激活、停用网络连接和展示网络状态。

假如你的 Linux 系统中安装了 NetworkManager，你便可以使用下面的命令来使用 `nmcli` 列出可以的网络接口：

```
$ nmcli device status
```

或者

```
$ nmcli connection show
```

现在你知道了如何在 Linux 中找到可用网络接口的方法，接下来，请查看下面的指南来知晓如何在 Linux 中配置 IP 地址吧。

* [如何在 Linux 和 Unix 中配置静态 IP 地址](https://www.ostechnix.com/configure-static-ip-address-linux-unix/)
* [如何在 Ubuntu 18.04 LTS 中配置 IP 地址](https://www.ostechnix.com/how-to-configure-ip-address-in-ubuntu-18-04-lts/)
* [如何在 Arch Linux 中配置静态和动态 IP 地址](https://www.ostechnix.com/configure-static-dynamic-ip-address-arch-linux/)
* [如何在 Linux 中为单个网卡分配多个 IP 地址](https://www.ostechnix.com/how-to-assign-multiple-ip-addresses-to-single-network-card-in-linux/)

假如你知道其他快捷的方法来在 Linux 中找到可用的网络接口，请在下面的评论部分中分享出来，我将检查你们的评论并更新这篇指南。

这就是全部的内容了，更多精彩内容即将呈现，请保持关注！

干杯！

---

via: <https://www.ostechnix.com/how-to-find-available-network-interfaces-on-linux/>

作者：[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/) 荣誉推出


开始使用 CryptPad 吧，一个开源的协作文档编辑器

为啥推广不开，可能就是因为操作不友好的原因，看了下sourceforce的，2015年的。反正我还没找到安装手册，以及下载位置，

你好

这个软件的GitHub repository在这里：https://github.com/xwiki-labs/cryptpad

软件安装指南在这里：https://github.com/xwiki-labs/cryptpad/wiki/Installation-guide

Docker Image使用构建和使用方法在这里：https://github.com/xwiki-labs/cryptpad/blob/master/docs/cryptpad-docker.md

# 开始使用 CryptPad 吧，一个开源的协作文档编辑器

>
> 使用 CryptPad 安全地共享你的笔记、文档、看板等，这是我们在开源工具系列中的第 5 个工具，它将使你在 2019 年更高效。
>
>
>

每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心，渴望开启新的一年，当然，“抛弃旧的，拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件，但事实上并不用这样。

这是我挑选出的 19 个新的（或者对你而言新的）开源工具中的第 5 个工具来帮助你在 2019 年更有效率。

### CryptPad

我们已经介绍过 [Joplin](https://opensource.com/article/19/1/productivity-tool-joplin)，它能很好地保存自己的笔记，但是，你可能已经注意到，它没有任何共享或协作功能。

[CryptPad](https://cryptpad.fr/index.html) 是一个安全、可共享的笔记应用和文档编辑器，它能够安全地协作编辑。与 Joplin 不同，它是一个 NodeJS 应用，这意味着你可以在桌面或其他服务器上运行它，并使用任何现代 Web 浏览器访问。它开箱即用，它支持富文本、Markdown、投票、白板，看板和 PPT。

它支持不同的文档类型且功能齐全。它的富文本编辑器涵盖了你所期望的所有基础功能，并允许你将文件导出为 HTML。它的 Markdown 的编辑能与 Joplin 相提并论，它的看板虽然不像 [Wekan](https://opensource.com/article/19/1/productivity-tool-wekan) 那样功能齐全，但也做得不错。其他支持的文档类型和编辑器也很不错，并且有你希望在类似应用中看到的功能，尽管投票功能显得有些粗糙。

然而，CryptPad 的真正强大之处在于它的共享和协作功能。共享文档只需在“共享”选项中获取可共享 URL，CryptPad 支持使用 `<iframe>` 标签嵌入其他网站的文档。可以在“编辑”或“查看”模式下使用密码和会过期的链接共享文档。内置聊天能够让编辑者相互交谈（请注意，具有浏览权限的人也可以看到聊天但无法发表评论）。

所有文件都使用用户密码加密存储。服务器管理员无法读取文档，这也意味着如果你忘记或丢失了密码，文件将无法恢复。因此，请确保将密码保存在安全的地方，例如放在[密码保险箱](https://opensource.com/article/18/4/3-password-managers-linux-command-line)中。

当它在本地运行时，CryptPad 是一个用于创建和编辑文档的强大应用。当在服务器上运行时，它成为了用于多用户文档创建和编辑的出色协作平台。在我的笔记本电脑上安装它不到五分钟，并且开箱即用。开发者还加入了在 Docker 中运行 CryptPad 的说明，并且还有一个社区维护用于方便部署的 Ansible 角色。CryptPad 不支持任何第三方身份验证，因此用户必须创建自己的帐户。如果你不想运行自己的服务器，CryptPad 还有一个社区支持的托管版本。

---

via: <https://opensource.com/article/19/1/productivity-tool-cryptpad>

作者：[Kevin Sonney](https://opensource.com/users/ksonney "Kevin Sonney") 选题：[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/) 荣誉推出


ODrive：Linux 中的 Google 云端硬盘图形客户端

# ODrive：Linux 中的 Google 云端硬盘图形客户端

这个我们已经多次讨论过。但是，我还要简要介绍一下它。截至目前，还没有官方的 Google 云端硬盘的 Linux 客户端，我们需要使用非官方客户端。Linux 中有许多集成 Google 云端硬盘的应用。每个应用都提供了一组功能。

我们过去在网站上写过一些此类文章。

这些文章是 [DriveSync](https://www.2daygeek.com/drivesync-google-drive-sync-client-for-linux/) 、[Google Drive Ocamlfuse 客户端](/article-10517-1.html) 和 [在 Linux 中使用 Nautilus 文件管理器挂载 Google 云端硬盘](https://www.2daygeek.com/mount-access-setup-google-drive-in-linux/)。

今天我们也将讨论相同的主题，程序名字是 ODrive。

### ODrive 是什么？

ODrive 意即 Open Drive。它是 Google 云端硬盘的图形客户端，它用 electron 框架编写。

它简单的图形界面能让用户几步就能集成 Google 云端硬盘。

### 如何在 Linux 上安装和设置 ODrive？

由于开发者提供了 AppImage 包，因此在 Linux 上安装 ODrive 没有任何困难。

只需使用 `wget` 命令从开发者的 GitHub 页面下载最新的 ODrive AppImage 包。

```
$ wget https://github.com/liberodark/ODrive/releases/download/0.1.3/odrive-0.1.3-x86_64.AppImage
```

你必须为 ODrive AppImage 文件设置可执行文件权限。

```
$ chmod +x odrive-0.1.3-x86_64.AppImage
```

只需运行 ODrive AppImage 文件以启动 ODrive GUI 以进行进一步设置。

```
$ ./odrive-0.1.3-x86_64.AppImage
```

运行上述命令时，可能会看到下面的窗口。只需按下“下一步”按钮即可进行进一步设置。

点击“连接”链接添加 Google 云端硬盘帐户。

输入你要设置 Google 云端硬盘帐户的电子邮箱。

输入邮箱密码。

允许 ODrive 访问你的 Google 帐户。

默认情况下，它将选择文件夹位置。如果你要选择特定文件夹，则可以更改。

最后点击“同步”按钮开始将文件从 Google 下载到本地系统。

同步正在进行中。

同步完成后。它会显示所有已下载的文件。

我看到所有文件都下载到上述目录中。

如果要将本地系统中的任何新文件同步到 Google 。只需从应用菜单启动 “ODrive”，但它不会实际启动应用。它将在后台运行，我们可以使用 `ps` 命令查看。

```
$ ps -df | grep odrive
```

将新文件添加到 Google文件夹后，它会自动开始同步。从通知菜单中也可以看到。是的，我看到一个文件已同步到 Google 中。

同步完成后图形界面没有加载，我不确定这个功能。我会向开发者反馈之后，根据他的反馈更新。

---

via: <https://www.2daygeek.com/odrive-open-drive-google-drive-gui-client-for-linux/>

作者：[Magesh Maruthamuthu](https://www.2daygeek.com/author/magesh/) 选题：[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/) 荣誉推出


时隔两年，PuTTY 发布了一个新的安全修复版本

Summary: 日前，得益于欧盟资助的 HackerOne 平台，PuTTY 发布了 0.71 版本，主要是修复了大量的安全缺陷。这个版本距其上个版本 0.70 的发布已近两年。

这个帮助很大

# 时隔两年，PuTTY 发布了一个新的安全修复版本

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

[PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) 是 Windows 上使用最广泛的 SSH 客户端之一，它也有 [Linux 版本](/article-10552-1.html)。日前，得益于欧盟资助的 [HackerOne 平台](https://hackerone.com/putty_h1c)，PuTTY [发布了 0.71 版本](https://www.chiark.greenend.org.uk/~sgtatham/putty/releases/0.71.html)，主要是修复了大量的安全缺陷。这个版本距其上个版本 0.70 的发布已近两年。

PuTTY 是一个自由开源且支持包括 SSH、Telnet 和 Rlogin 在内的多种协议的 GUI 客户端。

根据其[变更日志](https://www.chiark.greenend.org.uk/~sgtatham/putty/changes.html)，这个新版本的主要变更有：

* 由欧盟资助的漏洞赏金计划发现的漏洞的安全修复：
	+ 在 RSA 密钥交换过程中可由远程触发内容覆写，它发生在主机密钥校验之前
	+ 循环利用用于加密算法的随机数的潜在风险
	+ 在 Windows 上，通过与可执行文件位于同一目录中的恶意帮助文件进行劫持
	+ 在Unix上，任何类型的服务器到客户端转发过程中的可远程触发的缓冲区溢出
	+ 可以通过写入终端触发的多个拒绝服务攻击
* 其它安全增强：重写加密代码以消除缓存和定时侧信道
* 用户界面更改以防止来自恶意服务器的虚假身份验证提示
* 首次提供了基于 ARM 的 Windows 版的预构建二进制
* 最常见的加密算法的硬件加速版本：AES、SHA-256、SHA-1
* GTK PuTTY 现在支持非 X11 显示（如 Wayland）和高分辨率配置
* 现在，只要打开PuTTY窗口，就可以使用预先输入：在身份验证完成之前键入的键击将被缓冲而不是被删除
* 支持 GSSAPI 密钥交换：这是旧版 GSSAPI 身份验证系统的替代方案，可以在长时间会话期间更新转发的 Kerberos 凭据
* 用于剪贴板处理的更多用户界面选择
* 新的终端功能：支持 REP 转义序列（修复 ncurses 屏幕重绘失败）、真彩色和 SGR 2 暗淡文本
* 按 `Ctrl + Shift + PgUp` 或 `Ctrl + Shift + PgDn` 现在可以直接到达终端回滚的顶部或底部

如果要下载使用 PuTTY，请从其官网下载，以避免使用了被恶意篡改的版本：

* Windows 32 位：[putty-0.71-installer.msi](https://the.earth.li/~sgtatham/putty/latest/w32/putty-0.71-installer.msi)
* Windows 64 位：[putty-64bit-0.71-installer.msi](https://the.earth.li/~sgtatham/putty/latest/w64/putty-64bit-0.71-installer.msi)
* Unix 源代码：[putty-0.71.tar.gz](https://the.earth.li/~sgtatham/putty/latest/putty-0.71.tar.gz)

此外，也可以单独下载 putty 和 pscp 等的二进制执行文件：

* putty.exe（[32 位](https://the.earth.li/~sgtatham/putty/latest/w32/putty.exe)、[64 位](https://the.earth.li/~sgtatham/putty/latest/w64/putty.exe)）
* pscp.exe（[32 位](https://the.earth.li/~sgtatham/putty/latest/w32/pscp.exe)、[64 位](https://the.earth.li/~sgtatham/putty/latest/w64/pscp.exe)）


在 Emacs 的 dired 和 tramp 中异步运行 rsync

Summary: tmtxt-dired-async 可以扩展 dired（Emacs 内置的文件管理器），使之可以异步地运行 rsync 和其他命令（例如压缩、解压缩和下载）。

# 在 Emacs 的 dired 和 tramp 中异步运行 rsync

[Trần Xuân Trường](https://truongtx.me/about.html) 写的 [tmtxt-dired-async](https://truongtx.me/tmtxt-dired-async.html) 是一个不为人知的 Emacs 包，它可以扩展 dired（Emacs 内置的文件管理器），使之可以异步地运行 `rsync` 和其他命令 (例如压缩、解压缩和下载）。

这意味着你可以拷贝上 GB 的目录而不影响 Emacs 的其他任务。

它的一个功能时让你可以通过 `C-c C-a` 从不同位置添加任意多的文件到一个等待列表中，然后按下 `C-c C-v` 异步地使用 `rsync` 将整个等待列表中的文件同步到目标目录中。光这个功能就值得一试了。

例如这里将 arduino 1.9 的 beta 存档同步到另一个目录中：

整个进度完成后，底部的窗口会在 5 秒后自动退出。下面是异步解压上面的 arduino 存档后出现的另一个会话：

这个包进一步增加了我 dired 配置的实用性。

我刚刚贡献了 [一个拉取请求来允许 tmtxt-dired-async 同步到远程 tramp 目录中](https://github.com/tmtxt/tmtxt-dired-async/pull/6)，而且我立即使用该功能来将上 GB 的新照片传输到 Linux 服务器上。

若你想配置 tmtxt-dired-async，下载 [tmtxt-async-tasks.el](https://github.com/tmtxt/tmtxt-async-tasks)（被依赖的库）以及 [tmtxt-dired-async.el](https://github.com/tmtxt/tmtxt-dired-async)（若你想让它支持 tramp，请确保合并使用了我的拉取请求）到 `~/.emacs.d/` 目录中，然后添加下面配置：

```
;; no MELPA packages of this, so we have to do a simple check here
(setq dired-async-el (expand-file-name "~/.emacs.d/tmtxt-dired-async.el"))
(when (file-exists-p dired-async-el)
  (load (expand-file-name "~/.emacs.d/tmtxt-async-tasks.el"))
  (load dired-async-el)
  (define-key dired-mode-map (kbd "C-c C-r") 'tda/rsync)
  (define-key dired-mode-map (kbd "C-c C-z") 'tda/zip)
  (define-key dired-mode-map (kbd "C-c C-u") 'tda/unzip)

  (define-key dired-mode-map (kbd "C-c C-a") 'tda/rsync-multiple-mark-file)
  (define-key dired-mode-map (kbd "C-c C-e") 'tda/rsync-multiple-empty-list)
  (define-key dired-mode-map (kbd "C-c C-d") 'tda/rsync-multiple-remove-item)
  (define-key dired-mode-map (kbd "C-c C-v") 'tda/rsync-multiple)

  (define-key dired-mode-map (kbd "C-c C-s") 'tda/get-files-size)

  (define-key dired-mode-map (kbd "C-c C-q") 'tda/download-to-current-dir))
```

祝你开心！

---

via: <https://vxlabs.com/2018/03/30/asynchronous-rsync-with-emacs-dired-and-tramp/>

作者：[cpbotha](https://vxlabs.com/author/cpbotha/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


x86 和 ARM 的 Python 爬虫速度对比

# x86 和 ARM 的 Python 爬虫速度对比

假如说，如果你的老板给你的任务是一次又一次地访问竞争对手的网站，把对方商品的价格记录下来，而且要纯手工操作，恐怕你会想要把整个办公室都烧掉。

之所以现在网络爬虫的影响力如此巨大，就是因为网络爬虫可以被用于追踪客户的情绪和趋向、搜寻空缺的职位、监控房地产的交易，甚至是获取 UFC 的比赛结果。除此以外，还有很多意想不到的用途。

对于有这方面爱好的人来说，爬虫无疑是一个很好的工具。因此，我使用了 [Scrapy](https://scrapy.org/) 这个基于 Python 编写的开源网络爬虫框架。

鉴于我不太了解这个工具是否会对我的计算机造成伤害，我并没有将它搭建在我的主力机器上，而是搭建在了一台树莓派上面。

令人感到意外的是，Scrapy 在树莓派上面的性能并不差，或许这是 ARM 架构服务器的又一个成功例子？

我尝试 Google 了一下，但并没有得到令我满意的结果，仅仅找到了一篇相关的《[Drupal 建站对比](https://www.info2007.net/blog/2018/review-scaleway-arm-based-cloud-server.html)》。这篇文章的结论是，ARM 架构服务器性能比昂贵的 x86 架构服务器要更好。

从另一个角度来看，这种 web 服务可以看作是一个“被爬虫”服务，但和 Scrapy 对比起来，前者是基于 LAMP 技术栈，而后者则依赖于 Python，这就导致两者之间没有太多的可比性。

那我们该怎样做呢？只能在一些 VPS 上搭建服务来对比一下了。

### 什么是 ARM 架构处理器？

ARM 是目前世界上最流行的 CPU 架构。

但 ARM 架构处理器在很多人眼中的地位只是作为一个省钱又省电的选择，而不是跑在生产环境中的处理器的首选。

然而，诞生于英国剑桥的 ARM CPU，最初是用于极其昂贵的 [Acorn Archimedes](https://blog.dxmtechsupport.com.au/playing-badass-acorn-archimedes-games-on-a-raspberry-pi/) 计算机上的，这是当时世界上最强大的桌面计算机，甚至在很长一段时间内，它的运算速度甚至比最快的 386 还要快好几倍。

Acorn 公司和 Commodore、Atari 的理念类似，他们认为一家伟大的计算机公司就应该制造出伟大的计算机，让人感觉有点目光短浅。而比尔盖茨的想法则有所不同，他力图在更多不同种类和价格的 x86 机器上使用他的 DOS 系统。

拥有大量用户基数的平台会成为第三方开发者开发软件的平台，而软件资源丰富又会让你的计算机更受用户欢迎。

即使是苹果公司也几乎被打败。在 x86 芯片上投入大量的财力，最终，这些芯片被用于生产环境计算任务。

但 ARM 架构也并没有消失。基于 ARM 架构的芯片不仅运算速度快，同时也非常节能。因此诸如机顶盒、PDA、数码相机、MP3 播放器这些电子产品多数都会采用 ARM 架构的芯片，甚至在很多需要用电池或不配备大散热风扇的电子产品上，都可以见到 ARM 芯片的身影。

而 ARM 则脱离 Acorn 成为了一种特殊的商业模式，他们不生产实物芯片，仅仅是向芯片生产厂商出售相关的知识产权。

因此，这或多或少是 ARM 芯片被应用于如此之多的手机和平板电脑上的原因。当 Linux 被移植到这种架构的芯片上时，开源技术的大门就已经向它打开了，这才让我们今天得以在这些芯片上运行 web 爬虫程序。

#### 服务器端的 ARM

诸如[微软](https://www.computerworld.com/article/3178544/microsoft-windows/microsoft-and-arm-look-to-topple-intel-in-servers.html)和 [Cloudflare](https://www.datacenterknowledge.com/design/cloudflare-bets-arm-servers-it-expands-its-data-center-network) 这些大厂都在基础设施建设上花了重金，所以对于我们这些预算不高的用户来说，可以选择的余地并不多。

实际上，如果你的信用卡只够付每月数美元的 VPS 费用，一直以来只能考虑 [Scaleway](https://www.scaleway.com/) 这个高性价比的厂商。

但自从数个月前公有云巨头 [AWS](https://aws.amazon.com/) 推出了他们自研的 ARM 处理器 [AWS Graviton](https://www.theregister.co.uk/2018/11/27/amazon_aws_graviton_specs/) 之后，选择似乎就丰富了一些。

我决定在其中选择一款 VPS 厂商，将它提供的 ARM 处理器和 x86 处理器作出对比。

### 深入了解

所以我们要对比的是什么指标呢？

#### Scaleway

Scaleway 自身的定位是“专为开发者设计”。我觉得这个定位很准确，对于开发和原型设计来说，Scaleway 提供的产品确实可以作为一个很好的沙盒环境。

Scaleway 提供了一个简洁的仪表盘页面，让用户可以快速地从主页进入 bash shell 界面。对于很多小企业、自由职业者或者技术顾问，如果想要运行 web 爬虫，这个产品毫无疑问是一个物美价廉的选择。

ARM 方面我们选择 [ARM64-2GB](https://www.scaleway.com/virtual-cloud-servers/#anchor_arm) 这一款服务器，每月只需要 3 欧元。它带有 4 个 Cavium ThunderX 核心，这是在 2014 年推出的第一款服务器级的 ARMv8 处理器。但现在看来它已经显得有点落后了，并逐渐被更新的 ThunderX2 取代。

x86 方面我们选择 [1-S](https://www.scaleway.com/virtual-cloud-servers/#anchor_starter)，每月的费用是 4 欧元。它拥有 2 个英特尔 Atom C3995 核心。英特尔的 Atom 系列处理器的特点是低功耗、单线程，最初是用在笔记本电脑上的，后来也被服务器所采用。

两者在处理器以外的条件都大致相同，都使用 2 GB 的内存、50 GB 的 SSD 存储以及 200 Mbit/s 的带宽。磁盘驱动器可能会有所不同，但由于我们运行的是 web 爬虫，基本都是在内存中完成操作，因此这方面的差异可以忽略不计。

为了避免我不能熟练使用包管理器的尴尬局面，两方的操作系统我都会选择使用 Debian 9。

#### Amazon Web Services（AWS）

当你还在注册 AWS 账号的时候，使用 Scaleway 的用户可能已经把提交信用卡信息、启动 VPS 实例、添加 sudo 用户、安装依赖包这一系列流程都完成了。AWS 的操作相对来说比较繁琐，甚至需要详细阅读手册才能知道你正在做什么。

当然这也是合理的，对于一些需求复杂或者特殊的企业用户，确实需要通过详细的配置来定制合适的使用方案。

我们所采用的 AWS Graviton 处理器是 AWS EC2（<ruby> 弹性计算云 <rt>  Elastic Compute Cloud </rt></ruby>）的一部分，我会以按需实例的方式来运行，这也是最贵但最简捷的方式。AWS 同时也提供[竞价实例](https://aws.amazon.com/ec2/spot/pricing/)，这样可以用较低的价格运行实例，但实例的运行时间并不固定。如果实例需要长时间持续运行，还可以选择[预留实例](https://aws.amazon.com/ec2/pricing/reserved-instances/)。

看，AWS 就是这么复杂……

我们分别选择 [a1.medium](https://aws.amazon.com/ec2/instance-types/a1/) 和 [t2.small](https://aws.amazon.com/ec2/instance-types/t2/) 两种型号的实例进行对比，两者都带有 2GB 内存。这个时候问题来了，这里提到的 vCPU 又是什么？两种型号的不同之处就在于此。

对于 a1.medium 型号的实例，vCPU 是 AWS Graviton 芯片提供的单个计算核心。这个芯片由被亚马逊在 2015 收购的以色列厂商 Annapurna Labs 研发，是 AWS 独有的单线程 64 位 ARMv8 内核。它的按需价格为每小时 0.0255 美元。

而 t2.small 型号实例使用英特尔至强系列芯片，但我不确定具体是其中的哪一款。它每个核心有两个线程，但我们并不能用到整个核心，甚至整个线程。

我们能用到的只是“20% 的基准性能，可以使用 CPU 积分突破这个基准”。这可能有一定的原因，但我没有弄懂。它的按需价格是每小时 0.023 美元。

在镜像库中没有 Debian 发行版的镜像，因此我选择了 Ubuntu 18.04。

### 瘪四与大头蛋爬取 Moz 排行榜前 500 的网站

要测试这些 VPS 的 CPU 性能，就该使用爬虫了。一个方法是对几个网站在尽可能短的时间里发出尽可能多的请求，但这种操作不太礼貌，我的做法是只向大量网站发出少数几个请求。

为此，我编写了 `beavis.py`（瘪四）这个爬虫程序（致敬我最喜欢的物理学家和制片人 Mike Judge）。这个程序会将 Moz 上排行前 500 的网站都爬取 3 层的深度，并计算 “wood” 和 “ass” 这两个单词在 HTML 文件中出现的次数。（LCTT 译注：beavis（瘪四）和 butt-head（大头蛋） 都是 Mike Judge 的动画片《瘪四与大头蛋》中的角色）

但我实际爬取的网站可能不足 500 个，因为我需要遵循网站的 `robot.txt` 协定，另外还有些网站需要提交 javascript 请求，也不一定会计算在内。但这已经是一个足以让 CPU 保持繁忙的爬虫任务了。

Python 的[全局解释器锁](https://wiki.python.org/moin/GlobalInterpreterLock)机制会让我的程序只能用到一个 CPU 线程。为了测试多线程的性能，我需要启动多个独立的爬虫程序进程。

因此我还编写了 `butthead.py`，尽管大头蛋很粗鲁，它也总是比瘪四要略胜一筹。

我将整个爬虫任务拆分为多个部分，这可能会对爬取到的链接数量有一点轻微的影响。但无论如何，每次爬取都会有所不同，我们要关注的是爬取了多少个页面，以及耗时多长。

### 在 ARM 服务器上安装 Scrapy

安装 Scrapy 的过程与芯片的不同架构没有太大的关系，都是安装 `pip` 和相关的依赖包之后，再使用 `pip` 来安装 Scrapy。

据我观察，在使用 ARM 的机器上使用 `pip` 安装 Scrapy 确实耗时要长一点，我估计是由于需要从源码编译为二进制文件。

在 Scrapy 安装结束后，就可以通过 shell 来查看它的工作状态了。

在 Scaleway 的 ARM 机器上，Scrapy 安装完成后会无法正常运行，这似乎和 `service_identity` 模块有关。这个现象也会在树莓派上出现，但在 AWS Graviton 上不会出现。

对于这个问题，可以用这个命令来解决：

```
sudo pip3 install service_identity --force --upgrade
```

接下来就可以开始对比了。

### 单线程爬虫

Scrapy 的官方文档建议[将爬虫程序的 CPU 使用率控制在 80% 到 90% 之间](https://docs.scrapy.org/en/latest/topics/broad-crawls.html)，在真实操作中并不容易，尤其是对于我自己写的代码。根据我的观察，实际的 CPU 使用率变动情况是一开始非常繁忙，随后稍微下降，接着又再次升高。

在爬取任务的最后，也就是大部分目标网站都已经被爬取了的这个阶段，会持续数分钟的时间。这让人有点失望，因为在这个阶段当中，任务的运行时长只和网站的大小有比较直接的关系，并不能以之衡量 CPU 的性能。

所以这并不是一次严谨的基准测试，只是我通过自己写的爬虫程序来观察实际的现象。

下面我们来看看最终的结果。首先是 Scaleway 的机器：

| 机器种类 | 耗时 | 爬取页面数 | 每小时爬取页面数 | 每百万页面费用（欧元） |
| --- | --- | --- | --- | --- |
| Scaleway ARM64-2GB | 108m 59.27s | 38,205 | 21,032.623 | 0.28527 |
| Scaleway 1-S | 97m 44.067s | 39,476 | 24,324.648 | 0.33011 |

我使用了 [top](https://linux.die.net/man/1/top) 工具来查看爬虫程序运行期间的 CPU 使用率。在任务刚开始的时候，两者的 CPU 使用率都达到了 100%，但 ThunderX 大部分时间都达到了 CPU 的极限，无法看出来 Atom 的性能会比 ThunderX 超出多少。

通过 `top` 工具，我还观察了它们的内存使用情况。随着爬取任务的进行，ARM 机器的内存使用率最终达到了 14.7%，而 x86 则最终是 15%。

从运行日志还可以看出来，当 CPU 使用率到达极限时，会有大量的超时页面产生，最终导致页面丢失。这也是合理出现的现象，因为 CPU 过于繁忙会无法完整地记录所有爬取到的页面。

如果仅仅是为了对比爬虫的速度，页面丢失并不是什么大问题。但在实际中，业务成果和爬虫数据的质量是息息相关的，因此必须为 CPU 留出一些用量，以防出现这种现象。

再来看看 AWS 这边：

| 机器种类 | 耗时 | 爬取页面数 | 每小时爬取页面数 | 每百万页面费用（美元） |
| --- | --- | --- | --- | --- |
| a1.medium | 100m 39.900s | 41,294 | 24,612.725 | 1.03605 |
| t2.small | 78m 53.171s | 41,200 | 31,336.286 | 0.73397 |

为了方便比较，对于在 AWS 上跑的爬虫，我记录的指标和 Scaleway 上一致，但似乎没有达到预期的效果。这里我没有使用 `top`，而是使用了 AWS 提供的控制台来监控 CPU 的使用情况，从监控结果来看，我的爬虫程序并没有完全用到这两款服务器所提供的所有性能。

a1.medium 型号的机器尤为如此，在任务开始阶段，它的 CPU 使用率达到了峰值 45%，但随后一直在 20% 到 30% 之间。

让我有点感到意外的是，这个程序在 ARM 处理器上的运行速度相当慢，但却远未达到 Graviton CPU 能力的极限，而在 Intel Atom 处理器上则可以在某些时候达到 CPU 能力的极限。它们运行的代码是完全相同的，处理器的不同架构可能导致了对代码的不同处理方式。

个中原因无论是由于处理器本身的特性，还是二进制文件的编译，又或者是两者皆有，对我来说都是一个黑盒般的存在。我认为，既然在 AWS 机器上没有达到 CPU 处理能力的极限，那么只有在 Scaleway 机器上跑出来的性能数据是可以作为参考的。

t2.small 型号的机器性能让人费解。CPU 利用率大概 20%，最高才达到 35%，是因为手册中说的“20% 的基准性能，可以使用 CPU 积分突破这个基准”吗？但在控制台中可以看到 CPU 积分并没有被消耗。

为了确认这一点，我安装了 [stress](https://linux.die.net/man/1/stress) 这个软件，然后运行了一段时间，这个时候发现居然可以把 CPU 使用率提高到 100% 了。

显然，我需要调整一下它们的配置文件。我将 `CONCURRENT_REQUESTS` 参数设置为 5000，将 `REACTOR_THREADPOOL_MAXSIZE` 参数设置为 120，将爬虫任务的负载调得更大。

| 机器种类 | 耗时 | 爬取页面数 | 每小时爬取页面数 | 每万页面费用（美元） |
| --- | --- | --- | --- | --- |
| a1.medium | 46m 13.619s | 40,283 | 52,285.047 | 0.48771 |
| t2.small | 41m7.619s | 36,241 | 52,871.857 | 0.43501 |
| t2.small（无 CPU 积分） | 73m 8.133s | 34,298 | 28,137.8891 | 0.81740 |

a1.medium 型号机器的 CPU 使用率在爬虫任务开始后 5 分钟飙升到了 100%，随后下降到 80% 并持续了 20 分钟，然后再次攀升到 96%，直到任务接近结束时再次下降。这大概就是我想要的效果了。

而 t2.small 型号机器在爬虫任务的前期就达到了 50%，并一直保持在这个水平直到任务接近结束。如果每个核心都有两个线程，那么 50% 的 CPU 使用率确实是单个线程可以达到的极限了。

现在我们看到它们的性能都差不多了。但至强处理器的线程持续跑满了 CPU，Graviton 处理器则只是有一段时间如此。可以认为 Graviton 略胜一筹。

然而，如果 CPU 积分耗尽了呢？这种情况下的对比可能更为公平。为了测试这种情况，我使用 `stress` 把所有的 CPU 积分用完，然后再次启动了爬虫任务。

在没有 CPU 积分的情况下，CPU 使用率在 27% 就到达极限不再上升了，同时又出现了丢失页面的现象。这么看来，它的性能比负载较低的时候更差。

### 多线程爬虫

将爬虫任务分散到不同的进程中，可以有效利用机器所提供的多个核心。

一开始，我将爬虫任务分布在 10 个不同的进程中并同时启动，结果发现比每个核心仅使用 1 个进程的时候还要慢。

经过尝试，我得到了一个比较好的方案。把爬虫任务分布在 10 个进程中，但每个核心只启动 1 个进程，在每个进程接近结束的时候，再从剩余的进程中选出 1 个进程启动起来。

如果还需要优化，还可以让运行时间越长的爬虫进程在启动顺序中排得越靠前，我也在尝试实现这个方法。

想要预估某个域名的页面量，一定程度上可以参考这个域名主页的链接数量。我用另一个程序来对这个数量进行了统计，然后按照降序排序。经过这样的预处理之后，只会额外增加 1 分钟左右的时间。

结果，爬虫运行的总耗时超过了两个小时！毕竟把链接最多的域名都堆在同一个进程中也存在一定的弊端。

针对这个问题，也可以通过调整各个进程爬取的域名数量来进行优化，又或者在排序之后再作一定的修改。不过这种优化可能有点复杂了。

因此，我还是用回了最初的方法，它的效果还是相当不错的：

| 机器种类 | 耗时 | 爬取页面数 | 每小时爬取页面数 | 每万页面费用（欧元） |
| --- | --- | --- | --- | --- |
| Scaleway ARM64-2GB | 62m 10.078s | 36,158 | 34,897.0719 | 0.17193 |
| Scaleway 1-S | 60m 56.902s | 36,725 | 36,153.5529 | 0.22128 |

毕竟，使用多个核心能够大大加快爬虫的速度。

我认为，如果让一个经验丰富的程序员来优化的话，一定能够更好地利用所有的计算核心。但对于开箱即用的 Scrapy 来说，想要提高性能，使用更快的线程似乎比使用更多核心要简单得多。

从数量来看，Atom 处理器在更短的时间内爬取到了更多的页面。但如果从性价比角度来看，ThunderX 又是稍稍领先的。不过总的来说差距不大。

### 爬取结果分析

在爬取了 38205 个页面之后，我们可以统计到在这些页面中 “ass” 出现了 24170435 次，而 “wood” 出现了 54368 次。

“wood” 的出现次数不少，但和 “ass” 比起来简直微不足道。

### 结论

从上面的数据来看，对于性能而言，CPU 的架构并没有它们的问世时间重要，2018 年生产的 AWS Graviton 是单线程情况下性能最佳的。

你当然可以说按核心来比，Xeon 仍然赢了。但是，你不但需要计算美元的变化，甚至还要计算线程数。

另外在性能方面 2017 年生产的 Atom 轻松击败了 2014 年生产的 ThunderX，而 ThunderX 则在性价比方面占优。当然，如果你使用 AWS 的机器的话，还是使用 Graviton 吧。

总之，ARM 架构的硬件是可以用来运行爬虫程序的，而且在性能和费用方面也相当有竞争力。

而这种差异是否足以让你将整个技术架构迁移到 ARM 上？这就是另一回事了。当然，如果你已经是 AWS 用户，并且你的代码有很强的可移植性，那么不妨尝试一下 a1 型号的实例。

希望 ARM 设备在不久的将来能够在公有云上大放异彩。

### 源代码

这是我第一次使用 Python 和 Scrapy 来做一个项目，所以我的代码写得可能不是很好，例如代码中使用全局变量就有点力不从心。

不过我仍然会在下面开源我的代码。

要运行这些代码，需要预先安装 Scrapy，并且需要 [Moz 上排名前 500 的网站](https://moz.com/top500)的 csv 文件。如果要运行 `butthead.py`，还需要安装 [psutil](https://pypi.org/project/psutil/) 这个库。

```
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from scrapy.crawler import CrawlerProcess

ass = 0
wood = 0
totalpages = 0

def getdomains():

  moz500file = open('top500.domains.05.18.csv')

  domains = []
  moz500csv = moz500file.readlines()

  del moz500csv[0]

  for csvline in moz500csv:
    leftquote = csvline.find('"')
    rightquote = leftquote + csvline[leftquote + 1:].find('"')
    domains.append(csvline[leftquote + 1:rightquote])

  return domains

def getstartpages(domains):

  startpages = []

  for domain in domains:
    startpages.append('http://' + domain)

  return startpages

class AssWoodItem(scrapy.Item):
  ass = scrapy.Field()
  wood = scrapy.Field()
  url = scrapy.Field()

class AssWoodPipeline(object):
  def __init__(self):
    self.asswoodstats = []

  def process_item(self, item, spider):
    self.asswoodstats.append((item.get('url'), item.get('ass'), item.get('wood')))

  def close_spider(self, spider):
    asstally, woodtally = 0, 0

    for asswoodcount in self.asswoodstats:
      asstally += asswoodcount[1]
      woodtally += asswoodcount[2]

    global ass, wood, totalpages
    ass = asstally
    wood = woodtally
    totalpages = len(self.asswoodstats)

class BeavisSpider(CrawlSpider):
  name = "Beavis"
  allowed_domains = getdomains()
  start_urls = getstartpages(allowed_domains)
  #start_urls = [ 'http://medium.com' ]
  custom_settings = {
    'DEPTH_LIMIT': 3,
    'DOWNLOAD_DELAY': 3,
    'CONCURRENT_REQUESTS': 1500,
    'REACTOR_THREADPOOL_MAXSIZE': 60,
    'ITEM_PIPELINES': { '__main__.AssWoodPipeline': 10 },
    'LOG_LEVEL': 'INFO',
    'RETRY_ENABLED': False,
    'DOWNLOAD_TIMEOUT': 30,
    'COOKIES_ENABLED': False,
    'AJAXCRAWL_ENABLED': True
  }

  rules = ( Rule(LinkExtractor(), callback='parse_asswood'), )

  def parse_asswood(self, response):
    if isinstance(response, scrapy.http.TextResponse):
      item = AssWoodItem()
      item['ass'] = response.text.casefold().count('ass')
      item['wood'] = response.text.casefold().count('wood')
      item['url'] = response.url
      yield item

if __name__ == '__main__':

  process = CrawlerProcess({
      'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
  })

  process.crawl(BeavisSpider)
  process.start()

  print('Uhh, that was, like, ' + str(totalpages) + ' pages crawled.')
  print('Uh huhuhuhuh. It said ass ' + str(ass) + ' times.')
  print('Uh huhuhuhuh. It said wood ' + str(wood) + ' times.')
```

*beavis.py*

```
import scrapy, time, psutil
from scrapy.spiders import CrawlSpider, Rule, Spider
from scrapy.linkextractors import LinkExtractor
from scrapy.crawler import CrawlerProcess
from multiprocessing import Process, Queue, cpu_count

ass = 0
wood = 0
totalpages = 0
linkcounttuples =[]

def getdomains():

  moz500file = open('top500.domains.05.18.csv')

  domains = []
  moz500csv = moz500file.readlines()

  del moz500csv[0]

  for csvline in moz500csv:
    leftquote = csvline.find('"')
    rightquote = leftquote + csvline[leftquote + 1:].find('"')
    domains.append(csvline[leftquote + 1:rightquote])

  return domains

def getstartpages(domains):

  startpages = []

  for domain in domains:
    startpages.append('http://' + domain)

  return startpages

class AssWoodItem(scrapy.Item):
  ass = scrapy.Field()
  wood = scrapy.Field()
  url = scrapy.Field()

class AssWoodPipeline(object):
  def __init__(self):
    self.asswoodstats = []

  def process_item(self, item, spider):
    self.asswoodstats.append((item.get('url'), item.get('ass'), item.get('wood')))

  def close_spider(self, spider):
    asstally, woodtally = 0, 0

    for asswoodcount in self.asswoodstats:
      asstally += asswoodcount[1]
      woodtally += asswoodcount[2]

    global ass, wood, totalpages
    ass = asstally
    wood = woodtally
    totalpages = len(self.asswoodstats)

class ButtheadSpider(CrawlSpider):
  name = "Butthead"
  custom_settings = {
    'DEPTH_LIMIT': 3,
    'DOWNLOAD_DELAY': 3,
    'CONCURRENT_REQUESTS': 250,
    'REACTOR_THREADPOOL_MAXSIZE': 30,
    'ITEM_PIPELINES': { '__main__.AssWoodPipeline': 10 },
    'LOG_LEVEL': 'INFO',
    'RETRY_ENABLED': False,
    'DOWNLOAD_TIMEOUT': 30,
    'COOKIES_ENABLED': False,
    'AJAXCRAWL_ENABLED': True
  }

  rules = ( Rule(LinkExtractor(), callback='parse_asswood'), )

  def parse_asswood(self, response):
    if isinstance(response, scrapy.http.TextResponse):
      item = AssWoodItem()
      item['ass'] = response.text.casefold().count('ass')
      item['wood'] = response.text.casefold().count('wood')
      item['url'] = response.url
      yield item

def startButthead(domainslist, urlslist, asswoodqueue):
  crawlprocess = CrawlerProcess({
      'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
  })

  crawlprocess.crawl(ButtheadSpider, allowed_domains = domainslist, start_urls = urlslist)
  crawlprocess.start()
  asswoodqueue.put( (ass, wood, totalpages) )

if __name__ == '__main__':
  asswoodqueue = Queue()
  domains=getdomains()
  startpages=getstartpages(domains)
  processlist =[]
  cores = cpu_count()

  for i in range(10):
    domainsublist = domains[i * 50:(i + 1) * 50]
    pagesublist = startpages[i * 50:(i + 1) * 50]
    p = Process(target = startButthead, args = (domainsublist, pagesublist, asswoodqueue))
    processlist.append(p)

  for i in range(cores):
    processlist[i].start()

  time.sleep(180)

  i = cores

  while i != 10:
    time.sleep(60)
    if psutil.cpu_percent() < 66.7:
      processlist[i].start()
      i += 1

  for i in range(10):
    processlist[i].join()

  for i in range(10):
    asswoodtuple = asswoodqueue.get()
    ass += asswoodtuple[0]
    wood += asswoodtuple[1]
    totalpages += asswoodtuple[2]

  print('Uhh, that was, like, ' + str(totalpages) + ' pages crawled.')
  print('Uh huhuhuhuh. It said ass ' + str(ass) + ' times.')
  print('Uh huhuhuhuh. It said wood ' + str(wood) + ' times.')

```

*butthead.py*

---

via: <https://blog.dxmtechsupport.com.au/speed-test-x86-vs-arm-for-web-crawling-in-python/>

作者：[James Mawson](https://blog.dxmtechsupport.com.au/author/james-mawson/) 选题：[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/) 荣誉推出


在 Linux 中运行特定命令而无需 sudo 密码

就加一条语句的事，整了这么一大篇……

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

使用chmod +s /bin/mknod这类方法呢

# 在 Linux 中运行特定命令而无需 sudo 密码

我有一台部署在 AWS 上的 Ubuntu 系统，在它的里面有一个脚本，这个脚本的原有目的是以一定间隔（准确来说是每隔 1 分钟）去检查某个特定服务是否正在运行，如果这个服务因为某些原因停止了，就自动重启这个服务。但问题是我需要 sudo 权限来开启这个服务。正如你所知道的那样，当我们以 sudo 用户运行命令时，我们应该提供密码，但我并不想这么做，实际上我想做的是以 sudo 用户的身份运行这个服务但无需提供密码。假如你曾经经历过这样的情形，那么我知道一个简单的方法来做到这点。今天，在这个简短的指南中，我将教你如何在类 Unix 的操作系统中运行特定命令而无需 sudo 密码。

就让我们看看下面的例子吧。

```
$ sudo mkdir /ostechnix
[sudo] password for sk:
```

正如上面的截图中看到的那样，当我在根目录（`/`）中创建一个名为 `ostechnix` 的目录时，我需要提供 sudo 密码。每当我们尝试以 sudo 特权执行一个命令时，我们必须输入密码。而在我的预想中，我不想提供 sudo 密码。下面的内容便是我如何在我的 Linux 机子上运行一个 `sudo` 命令而无需输入密码的过程。

### 在 Linux 中运行特定命令而无需 sudo 密码

基于某些原因，假如你想允许一个用户运行特定命令而无需提供 sudo 密码，则你需要在 `sudoers` 文件中添加上这个命令。

假如我想让名为 `sk` 的用户去执行 `mkdir` 而无需提供 sudo 密码，下面就让我们看看该如何做到这点。

使用下面的命令来编辑 `sudoers` 文件：

```
$ sudo visudo
```

将下面的命令添加到这个文件的最后。

```
sk ALL=NOPASSWD:/bin/mkdir
```

其中 `sk` 是用户名。根据上面一行的内容，用户 `sk` 可以从任意终端执行 `mkdir` 命令而不必输入 sudo 密码。

你可以用逗号分隔的值来添加额外的命令（例如 `chmod`），正如下面展示的那样。

```
sk ALL=NOPASSWD:/bin/mkdir,/bin/chmod
```

保存并关闭这个文件，然后注销（或重启）你的系统。现在以普通用户 `sk` 登录，然后试试使用 `sudo` 来运行这些命令，看会发生什么。

```
$ sudo mkdir /dir1
```

看到了吗？即便我以 sudo 特权运行 `mkdir` 命令，也不会弹出提示让我输入密码。从现在开始，当用户 `sk` 运行 `mkdir` 时，就不必输入 sudo 密码了。

当运行除了添加到 `sudoers` 文件之外的命令时，你将被提示输入 sudo 密码。

让我们用 `sudo` 来运行另一个命令。

```
$ sudo apt update
```

看到了吗？这个命令将提示我输入 sudo 密码。

假如你不想让这个命令提示你输入 sudo 密码，请编辑 `sudoers` 文件：

```
$ sudo visudo
```

像下面这样将 `apt` 命令添加到 `sudoers` 文件中：

```
sk ALL=NOPASSWD:/bin/mkdir,/usr/bin/apt
```

你注意到了上面命令中 `apt` 二进制执行文件的路径与 `mkdir` 的有所不同吗？是的，你必须提供一个正确的可执行文件路径。要找到任意命令的可执行文件路径，例如这里的 `apt`，可以像下面这样使用 `whichis` 命令来查看：

```
$ whereis apt
apt: /usr/bin/apt /usr/lib/apt /etc/apt /usr/share/man/man8/apt.8.gz
```

如你所见，`apt` 命令的可执行文件路径为 `/usr/bin/apt`，所以我将这个路径添加到了 `sudoers` 文件中。

正如我前面提及的那样，你可以添加任意多个以逗号分隔的命令。一旦你做完添加的动作，保存并关闭你的 `sudoers` 文件，接着注销，然后重新登录进你的系统。

现在就检验你是否可以直接运行以 `sudo` 开头的命令而不必使用密码：

```
$ sudo apt update
```

看到了吗？`apt` 命令没有让我输入 sudo 密码，即便我用 `sudo` 来运行它。

下面展示另一个例子。假如你想运行一个特定服务，例如 `apache2`，那么就添加下面这条命令到 `sudoers` 文件中：

```
sk ALL=NOPASSWD:/bin/mkdir,/usr/bin/apt,/bin/systemctl restart apache2
```

现在用户 `sk` 就可以运行 `sudo systemctl restart apache` 命令而不必输入 sudo 密码了。

我可以再次让一个特别的命令提醒输入 sudo 密码吗？当然可以！只需要删除添加的命令，注销然后再次登录即可。

除了这种方法外，你还可以在命令的前面添加 `PASSWD:` 指令。让我们看看下面的例子：

在 `sudoers` 文件中添加或者修改下面的一行：

```
sk ALL=NOPASSWD:/bin/mkdir,/bin/chmod,PASSWD:/usr/bin/apt
```

在这种情况下，用户 `sk` 可以运行 `mkdir` 和 `chmod` 命令而不用输入 sudo 密码。然而，当他运行 `apt` 命令时，就必须提供 sudo 密码了。

免责声明：本篇指南仅具有教育意义。在使用这个方法的时候，你必须非常小心。这个命令既可能富有成效但也可能带来摧毁性效果。例如，假如你允许用户执行 `rm` 命令而不输入 sudo 密码，那么他们可能无意或有意地删除某些重要文件。我警告过你了！

那么这就是全部的内容了。希望这个能够给你带来帮助。更多精彩内容即将呈现，请保持关注！

干杯！

---

via: <https://www.ostechnix.com/run-particular-commands-without-sudo-password-linux/>

作者：[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/) 荣誉推出


开始使用 Cypht 吧，一个开源的电子邮件客户端

# 开始使用 Cypht 吧，一个开源的电子邮件客户端

>
> 使用 Cypht 将你的电子邮件和新闻源集成到一个界面中，这是我们 19 个开源工具系列中的第 4 个，它将使你在 2019 年更高效。
>
>
>

每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心，渴望开启新的一年，当然，“抛弃旧的，拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件，但事实上并不用这样。

这是我挑选出的 19 个新的（或者对你而言新的）开源工具中的第 4 个工具来帮助你在 2019 年更有效率。

### Cypht

我们花了很多时间来处理电子邮件，有效地[管理你的电子邮件](https://opensource.com/article/17/7/email-alternatives-thunderbird)可以对你的工作效率产生巨大影响。像 Thunderbird、Kontact/KMail 和 Evolution 这样的程序似乎都有一个共同点：它们试图复制 Microsoft Outlook 的功能，这在过去 10 年左右并没有真正改变。在过去十年中，甚至像 Mutt 和 Cone 这样的[著名控制台程序](https://opensource.com/life/15/8/top-4-open-source-command-line-email-clients)也没有太大变化。

[Cypht](https://cypht.org/) 是一个简单、轻量级和现代的 Webmail 客户端，它将多个帐户聚合到一个界面中。除了电子邮件帐户，它还包括 Atom/RSS 源。在 “Everything” 中，不仅可以显示收件箱中的邮件，还可以显示新闻源中的最新文章，从而使得阅读不同来源的内容变得简单。

它使用简化的 HTML 消息来显示邮件，或者你也可以将其设置为查看纯文本版本。由于 Cypht 不会加载远程图像（以帮助维护安全性），HTML 渲染可能有点粗糙，但它足以完成工作。你将看到包含大量富文本邮件的纯文本视图 —— 这意味着很多链接并且难以阅读。我不会说是 Cypht 的问题，因为这确实是发件人所做的，但它确实降低了阅读体验。阅读新闻源大致相同，但它们与你的电子邮件帐户集成，这意味着可以轻松获取最新的（我有时会遇到问题）。

用户可以使用预配置的邮件服务器并添加他们使用的任何其他服务器。Cypht 的自定义选项包括纯文本与 HTML 邮件显示，它支持多个配置文件以及更改主题（并自行创建）。你要记得单击左侧导航栏上的“保存”按钮，否则你的自定义设置将在该会话后消失。如果你在不保存的情况下注销并重新登录，那么所有更改都将丢失，你将获得开始时的设置。因此可以轻松地实验，如果你需要重置，只需在不保存的情况下注销，那么在再次登录时就会看到之前的配置。

本地[安装 Cypht](https://cypht.org/install.html) 非常容易。虽然它不使用容器或类似技术，但安装说明非常清晰且易于遵循，并且不需要我做任何更改。在我的笔记本上，从安装开始到首次登录大约需要 10 分钟。服务器上的共享安装使用相同的步骤，因此它应该大致相同。

最后，Cypht 是桌面和基于 Web 的电子邮件客户端的绝佳替代方案，它有简单的界面，可帮助你快速有效地处理电子邮件。

---

via: <https://opensource.com/article/19/1/productivity-tool-cypht-email>

作者：[Kevin Sonney](https://opensource.com/users/ksonney "Kevin Sonney") 选题：[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 操作系统。
>
>
>

如果你按顺序看我们本系列的文章，那么你已经 [选择](/article-10611-1.html) 和 [购买](/article-10615-1.html) 了你的树莓派和外围设备，现在，你将要去使用它。在第三篇文章中，我们来看一下你需要做些什么才能让它启动起来。

与你的笔记本、台式机、智能手机、或平板电脑不一样的是，树莓派上并没有内置存储。而是需要使用一个 Micro SD 卡去存储操作系统和文件。这么做的最大好处就是携带你的文件比较方便（甚至都不用带着树莓派）。不利之处是存储卡丢失和损坏的风险可能很高，这将导致你的文件丢失。因此，只要保护好你的 Micro SD 卡就没什么问题了。

你应该也知道，SD 卡的读写速度比起机械硬件或固态硬盘要慢很多，因此，你的树莓派的启动、读取、和写入的速度将不如其它设备。

### 如何安装 Raspbian

你拿到新树莓派的第一件事情就是将它的操作系统安装到一个 Micro SD 卡上。尽管树莓派上可用的操作系统很多（基于 Linux 的或非基于 Linux 的都有），但本系列课程将专注于 [Raspbian](https://www.raspbian.org/RaspbianFAQ)，它是树莓派的官方 Linux 版本。

安装 Raspbian 的最简单的方式是使用 [NOOBS](https://www.raspberrypi.org/downloads/noobs/)，它是 “New Out Of Box Software” 的缩写。树莓派官方提供了非常详细的 [NOOBS 文档](https://www.raspberrypi.org/documentation/installation/noobs.md)，因此，我就不在这里重复这些安装指令了。

NOOBS 可以让你选择安装以下的这些操作系统：

* [Raspbian](https://www.raspbian.org/RaspbianFAQ)
* [LibreELEC](https://libreelec.tv/)
* [OSMC](https://osmc.tv/)
* [Recalbox](https://www.recalbox.com/)
* [Lakka](http://www.lakka.tv/)
* [RISC OS](https://www.riscosopen.org/wiki/documentation/show/Welcome%20to%20RISC%20OS%20Pi)
* [Screenly OSE](https://www.screenly.io/ose/)
* [Windows 10 IoT Core](https://developer.microsoft.com/en-us/windows/iot)
* [TLXOS](https://thinlinx.com/)

再强调一次，我们在本系列的课程中使用的是 Raspbian，因此，拿起你的 Micro SD 卡，然后按照 NOOBS 文档去安装 Raspbian 吧。在本系列的第四篇文章中，我们将带你去看看，如何使用 Linux，包括你需要掌握的一些主要的命令。

---

via: <https://opensource.com/article/19/3/how-boot-new-raspberry-pi>

作者：[Anderson Silva](https://opensource.com/users/ansilva) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


树莓派使用入门：用树莓派学 Linux

Summary: 我们的《树莓派使用入门》的第四篇文章将进入到 Linux 命令行。

我们的《树莓派使用入门》的第四篇文章将进入到 Linux 命令行。

# 树莓派使用入门：用树莓派学 Linux

>
> 我们的《树莓派使用入门》的第四篇文章将进入到 Linux 命令行。
>
>
>

在本系列的 [第三篇文章](/article-10644-1.html) 中开始了我们的树莓派探索之旅，我分享了如何安装 Raspbian，它是树莓派的官方 Linux 版本。现在，你已经安装好了 Raspbian 并用它引导你的新树莓派，你已经具备学习 Linux 相关知识的条件了。

在这样简短的文章中去解决像“如何使用 Linux” 这样的宏大主题显然是不切实际的，因此，我只是给你提供一些如何使用树莓派来学习更多的 Linux 知识的一些创意而已。

我们花一些时间从命令行（又称“终端”）开始。自上世纪九十年代中期以来，Linux 的 [窗口管理器](https://opensource.com/article/18/8/window-manager) 和图形界面已经得到长足的发展。如今，你可以在 Linux 上通过鼠标点击来做一些事情了，就如同其它的操作系统一样容易。在我看来，只是“使用 Linux”和成为“一个 Linux 用户”是有区别的，后者至少能够在终端中“遨游“。

如果你想成为一个 Linux 用户，从终端中尝试以下的命令行开始：

* 使用像 `ls`、`cd` 和 `pwd` 这样的命令导航到你的 Home 目录。
* 使用 `mkdir`、`rm`、`mv` 和 `cp` 命令创建、删除、和重命名目录。
* 使用命令行编辑器（如 Vi、Vim、Emacs 或 Nano）去创建一个文本文件。
* 尝试一些其它命令，比如 `chmod`、`chown`、`w`、`cat`、`more`、`less`、`tail`、`free`、`df`、`ps`、`uname` 和 `kill`。
* 尝试一下 `/bin` 和 `/usr/bin` 目录中的其它命令。

学习命令行的最佳方式还是阅读它的 “man 手册”（简称手册）；在命令行中输入 `man <command>` 就可以像上面那样打开它。并且在互联网上搜索 Linux 命令速查表可以让你更清楚地了解命令的用法 —— 你应该会找到一大堆能帮你学习的资料。

Raspbian 就像主流的 Linux 发行版一样有非常多的命令，假以时日，你最终将比其他人会用更多的命令。我使用 Linux 命令行已经超过二十年了，即便这样仍然有一些命令我从来没有使用过，即便是那些我使用的过程中就一直存在的命令。

最后，你可以使用图形环境去更快地工作，但是只有深入到 Linux 命令行，你才能够获得操作系统真正的强大功能和知识。

---

via: <https://opensource.com/article/19/3/learn-linux-raspberry-pi>

作者：[Andersn Silva](https://opensource.com/users/ansilva) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


在 Fedora 上为 SSH 设置双因子验证

# 在 Fedora 上为 SSH 设置双因子验证

每天似乎都有一个安全漏洞的新闻报道，说我们的数据会因此而存在风险。尽管 SSH 是一种远程连接系统的安全方式，但你仍然可以使它更安全。本文将向你展示如何做到这一点。

此时<ruby> 双因子验证 <rt>  two-factor authentication </rt></ruby>（2FA）就有用武之地了。即使你禁用密码并只允许使用公钥和私钥进行 SSH 连接，但如果未经授权的用户偷窃了你的密钥，他仍然可以借此访问系统。

使用双因子验证，你不能仅仅使用 SSH 密钥连接到服务器，你还需要提供手机上的验证器应用程序随机生成的数字。

本文展示的方法是<ruby> 基于时间的一次性密码 <rt>  Time-based One-time Password </rt></ruby>（TOTP）算法。[Google Authenticator](https://en.wikipedia.org/wiki/Google_Authenticator) 用作服务器应用程序。默认情况下，Google Authenticator 在 Fedora 中是可用的。

至于手机，你可以使用与 TOTP 兼容的任何可以双路验证的应用程序。Andorid 或 iOS 有许多可以与 TOTP 和 Google Authenticator 配合使用的免费应用程序。本文与 [FreeOTP](https://freeotp.github.io/) 为例。

### 安装并设置 Google Authenticator

首先，在你的服务器上安装 Google Authenticator。 `$ sudo dnf install -y google-authenticator`

运行应用程序：

```
$ google-authenticator
```

该应用程序提供了一系列问题。下面的片段展示了如何进行合理的安全设置：

```
Do you want authentication tokens to be time-based (y/n) y
Do you want me to update your "/home/user/.google_authenticator" file (y/n)? y
```

这个应用程序为你提供一个密钥、验证码和恢复码。把它们放在安全的地方。如果你丢失了手机，恢复码是访问服务器的**唯一**方式。

### 设置手机验证

在你的手机上安装验证器应用程序（FreeOTP）。如果你有一台安卓手机，那么你可以在 Google Play 中找到它，也可以在苹果 iPhone 的 iTunes 商店中找到它。

Google Authenticator 会在屏幕上显示一个二维码。打开手机上的 FreeOTP 应用程序，选择添加新账户，在应用程序顶部选择二维码形状工具，然后扫描二维码即可。设置完成后，在每次远程连接服务器时，你必须提供验证器应用程序生成的随机数。

### 完成配置

应用程序会向你询问更多的问题。下面示例展示了如何设置合理的安全配置。

```
Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y
By default, tokens are good for 30 seconds. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of +-1min (window size of 3) to about +-4min (window size of 17 acceptable tokens).
Do you want to do so? (y/n) n
If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y
```

现在，你必须设置 SSH 来利用新的双路验证。

### 配置 SSH

在完成此步骤之前，**确保你已使用公钥建立了一个可用的 SSH 连接**，因为我们将禁用密码连接。如果出现问题或错误，一个已经建立的连接将允许你修复问题。

在你的服务器上，使用 [sudo](https://fedoramagazine.org/howto-use-sudo/) 编辑 `/etc/pam.d/sshd` 文件。

```
$ sudo vi /etc/pam.d/ssh
```

注释掉 `auth substack password-auth` 这一行：

```
#auth       substack     password-auth
```

将以下行添加到文件底部：

```
auth sufficient pam_google_authenticator.so
```

保存并关闭文件。然后编辑 `/etc/ssh/sshd_config` 文件：

```
$ sudo vi /etc/ssh/sshd_config
```

找到 `ChallengeResponseAuthentication` 这一行并将其更改为 `yes`：

```
ChallengeResponseAuthentication yes
```

找到 `PasswordAuthentication` 这一行并将其更改为 `no`：

```
PasswordAuthentication no
```

将以下行添加到文件底部：

```
AuthenticationMethods publickey,password publickey,keyboard-interactive
```

保存并关闭文件，然后重新启动 SSH：

```
$ sudo systemctl restart sshd
```

### 测试双因子验证

当你尝试连接到服务器时，系统会提示你输入验证码：

```
[user@client ~]$ ssh user@example.com
Verification code:
```

验证码由你手机上的验证器应用程序随机生成。由于这个数字每隔几秒就会发生变化，因此你需要在它变化之前输入它。

如果你不输入验证码，你将无法访问系统，你会收到一个权限被拒绝的错误：

```
[user@client ~]$ ssh user@example.com
Verification code:
Verification code:
Verification code:
Permission denied (keyboard-interactive).
[user@client ~]$
```

### 结论

通过添加这种简单的双路验证，现在未经授权的用户访问你的服务器将变得更加困难。

---

via: <https://fedoramagazine.org/two-factor-authentication-ssh-fedora/>

作者：[Curt Warfield](https://fedoramagazine.org/author/rcurtiswarfield/) 选题：[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/) 荣誉推出


Python 的 ChatOps 库：Opsdroid 和 Errbot

# Python 的 ChatOps 库：Opsdroid 和 Errbot

>
> 学习一下 Python 世界里最广泛使用的 ChatOps 库：每个都能做什么，如何使用。
>
>
>

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

ChatOps 是基于会话导向而进行的开发。其思路是你可以编写能够对聊天窗口中的某些输入进行回复的可执行代码。作为一个开发者，你能够用 ChatOps 从 Slack 合并拉取请求，自动从收到的 Facebook 消息中给某人分配支持工单，或者通过 IRC 检查开发状态。

在 Python 世界，最为广泛使用的 ChatOps 库是 Opsdroid 和 Errbot。在这个月的 Python 专栏，让我们一起聊聊使用它们是怎样的体验，它们各自适用于什么方面以及如何着手使用它们。

### Opsdroid

[Opsdroid](https://opsdroid.github.io/) 是一个相对年轻的（始于 2016）Python 开源聊天机器人库。它有着良好的开发文档，不错的教程，并且包含能够帮助你对接流行的聊天服务的插件。

#### 它内置了什么

库本身并没有自带所有你需要上手的东西，但这是故意的。轻量级的框架鼓励你去运用它现有的连接器（Opsdroid 所谓的帮你接入聊天服务的插件）或者去编写你自己的，但是它并不会因自带你所不需要的连接器而自贬身价。你可以轻松使用现有的 Opsdroid 连接器来接入：

* 命令行
* Cisco Spark
* Facebook
* GitHub
* Matrix
* Slack
* Telegram
* Twitter
* Websocket

Opsdroid 会调用使聊天机器人能够展现它们的“技能”的函数。这些技能其实是异步 Python 函数，并使用 Opsdroid 叫做“匹配器”的匹配装饰器。你可以设置你的 Opsdroid 项目，来使用同样从你设置文件所在的代码中的“技能”。你也可以从外面的公共或私人仓库调用这些“技能”。

你同样可以启用一些现存的 Opsdroid “技能”，包括 [seen](https://github.com/opsdroid/skill-seen) —— 它会告诉你聊天机器人上次是什么时候看到某个用户的，以及 [weather](https://github.com/opsdroid/skill-weather) —— 会将天气报告给用户。

最后，Opdroid 允许你使用现存的数据库模块设置数据库。现在 Opdroid 支持的数据库包括：

* Mongo
* Redis
* SQLite

你可以在你的 Opdroid 项目中的 `configuration.yaml` 文件设置数据库、技能和连接器。

#### Opsdroid 的优势

**Docker 支持：**从一开始 Opsdroid 就打算在 Docker 中良好运行。在 Docker 中的指导是它 [安装文档](https://opsdroid.readthedocs.io/en/stable/#docker) 中的一部分。使用 Opsdroid 和 Docker Compose 也很简单：将 Opsdroid 设置成一种服务，当你运行 `docker-compose up` 时，你的 Opsdroid 服务将会开启你的聊天机器人也将就绪。

```
version: "3"

services:
  opsdroid:
    container_name: opsdroid
    build:
      context: .
      dockerfile: Dockerfile
```

**丰富的连接器：** Opsdroid 支持九种像 Slack 和 Github 等从外部接入的服务连接器。你所要做的一切就是在你的设置文件中启用那些连接器，然后把必须的口令或者 API 密匙传过去。比如为了启用 Opsdroid 以在一个叫做 `#updates` 的 Slack 频道发帖，你需要将以下代码加入你设置文件的 `connectors` 部分：

```
 - name: slack
    api-token: "this-is-my-token"
    default-room: "#updates"
```

在设置 Opsdroid 以接入 Slack 之前你需要[添加一个机器人用户](https://api.slack.com/bot-users)。

如果你需要接入一个 Opsdroid 不支持的服务，在[文档](https://opsdroid.readthedocs.io/en/stable/extending/connectors/)里有有添加你自己的连接器的教程。

**相当不错的文档：** 特别是对于一个在积极开发中的新兴库来说，Opsdroid 的文档十分有帮助。这些文档包括一篇带你创建几个不同的基本技能的[教程](https://opsdroid.readthedocs.io/en/stable/tutorials/introduction/)。Opsdroid 在[技能](https://opsdroid.readthedocs.io/en/stable/extending/skills/)、[连接器](https://opsdroid.readthedocs.io/en/stable/extending/connectors/)、[数据库](https://opsdroid.readthedocs.io/en/stable/extending/databases/)，以及[匹配器](https://opsdroid.readthedocs.io/en/stable/matchers/overview/)方面的文档也十分清晰。

它所支持的技能和连接器的仓库为它的技能提供了富有帮助的示范代码。

**自然语言处理：** Opsdroid 的技能里面能使用正则表达式，但也同样提供了几个包括 [Dialogflow](https://opsdroid.readthedocs.io/en/stable/matchers/dialogflow/)，[luis.ai](https://opsdroid.readthedocs.io/en/stable/matchers/luis.ai/)，[Recast.AI](https://opsdroid.readthedocs.io/en/stable/matchers/recast.ai/) 以及 [wit.ai](https://opsdroid.readthedocs.io/en/stable/matchers/wit.ai/) 的 NLP API。

#### Opsdroid 可能的不足

Opsdroid 对它的一部分连接器还没有启用全部的特性。比如说，Slack API 允许你向你的消息添加颜色柱、图片以及其他的“附件”。Opsdroid Slack 连接器并没有启用“附件”特性，所以如果那些特性对你来说很重要的话，你需要编写一个自定义的 Slack 连接器。如果连接器缺少一个你需要的特性，Opsdroid 将欢迎你的[贡献](https://opsdroid.readthedocs.io/en/stable/contributing/)。文档中可以使用更多的例子，特别是对于预料到的使用场景。

#### 示例用法

```
from opsdroid.matchers import match_regex
import random

@match_regex(r'hi|hello|hey|hallo')
async def hello(opsdroid, config, message):
    text = random.choice(["Hi {}", "Hello {}", "Hey {}"]).format(message.user)
    await message.respond(text)
```

*hello/\_\_init\_\_.py*

```
connectors:
  - name: websocket

skills:
  - name: hello
    repo: "https://github.com/<user_id>/hello-skill"

```

*configuration.yaml*

### Errbot

[Errbot](http://errbot.io/en/latest/) 是一个功能齐全的开源聊天机器人。Errbot 发行于 2012 年，并且拥有人们从一个成熟的项目能期待的一切，包括良好的文档、优秀的教程以及许多帮你连入现有的流行聊天服务的插件。

#### 它内置了什么

不像采用了较轻量级方式的 Opsdroid，Errbot 自带了你需要可靠地创建一个自定义机器人的一切东西。

Errbot 包括了对于本地 XMPP、IRC、Slack、Hipchat 以及 Telegram 服务的支持。它通过社区支持的后端列出了另外十种服务。

#### Errbot 的优势

**良好的文档：** Errbot 的文档成熟易读。

**动态插件架构：** Errbot 允许你通过和聊天机器人交谈安全地安装、卸载、更新、启用以及禁用插件。这使得开发和添加特性十分简便。感谢 Errbot 的颗粒性授权系统，出于安全意识这所有的一切都可以被锁闭。

当某个人输入 `!help`，Errbot 使用你的插件的文档字符串来为可获取的命令生成文档，这使得了解每行命令的作用更加简便。

**内置的管理和安全特性：** Errbot 允许你限制拥有管理员权限的用户列表，甚至细粒度访问控制。比如说你可以限制特定用户或聊天房间访问特定命令。

**额外的插件框架：** Errbot 支持钩子、回调、子命令、webhook、轮询以及其它[更多特性](http://errbot.io/en/latest/features.html#extensive-plugin-framework)。如果那些还不够，你甚至可以编写[动态插件](http://errbot.io/en/latest/user_guide/plugin_development/dynaplugs.html)。当你需要基于在远程服务器上的可用命令来启用对应的聊天命令时，这个特性十分有用。

**自带测试框架：** Errbot 支持 [pytest](http://pytest.org/)，同时也自带一些能使你简便测试插件的有用功能。它的“[测试你的插件](http://errbot.io/en/latest/user_guide/plugin_development/testing.html)”的文档出于深思熟虑，并提供了足够的资料让你上手。

#### Errbot 可能的不足

**以 “!” 开头：** 默认情况下，Errbot 命令发出时以一个惊叹号打头（`!help` 以及 `!hello`）。一些人可能会喜欢这样，但是另一些人可能认为这让人烦恼。谢天谢地，这很容易关掉。

**插件元数据** 首先，Errbot 的 [Hello World](http://errbot.io/en/latest/index.html#simple-to-build-upon) 插件示例看上去易于使用。然而我无法加载我的插件，直到我进一步阅读了教程并发现我还需要一个 `.plug` 文档，这是一个 Errbot 用来加载插件的文档。这可能比较吹毛求疵了，但是在我深挖文档之前，这对我来说都不是显而易见的。

### 示例用法

```
import random
from errbot import BotPlugin, botcmd

class Hello(BotPlugin):

    @botcmd
    def hello(self, msg, args):
        text = random.choice(["Hi {}", "Hello {}", "Hey {}"]).format(message.user)
        return text
```

*hello.py*

```
[Core]
Name = Hello
Module = hello

[Python]
Version = 2+

[Documentation]
Description = Example "Hello" plugin
```

*hello.plug*

你用过 Errbot 或 Opsdroid 吗？如果用过请留下关于你对于这些工具印象的留言。

---

via: <https://opensource.com/article/18/3/python-chatops-libraries-opsdroid-and-errbot>

作者：[Jeff Triplett](https://opensource.com/users/laceynwilliams), [Lacey Williams Henschel](https://opensource.com/users/laceynwilliams) 译者：[tomjlw](https://github.com/tomjlw) 校对：[wxy](https://github.com/wxy)

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


开始使用 Freeplane 吧，一款开源思维导图

# 开始使用 Freeplane 吧，一款开源思维导图

>
> 使用 Freeplane 进行头脑风暴，这是我们开源工具系列中的第 13 个，它将使你在 2019 年更高效。
>
>
>

每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心，渴望开启新的一年，当然，“抛弃旧的，拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件，但事实上并不用这样。

这是我挑选出的 19 个新的（或者对你而言新的）开源工具中的第 13 个工具来帮助你在 2019 年更有效率。

### Freeplane

[思维导图](https://en.wikipedia.org/wiki/Mind_map)是我用于快速头脑风暴和捕捉数据的最有价值的工具之一。思维导图是一个灵活的过程，有助于显示事物的相关性，并可用于快速组织相互关联的信息。从规划角度来看，思维导图让你快速将大脑中的单个概念、想法或技术表达出来。

[Freeplane](https://www.freeplane.org/wiki/index.php/Home) 是一款桌面应用，可以轻松创建、查看、编辑和共享思维导图。它是 [FreeMind](https://sourceforge.net/projects/freemind/) 这款很长时间内都是思维导图首选应用的重新打造。

安装 Freeplane 非常简单。它是一个 [Java](https://java.com) 应用，并使用 ZIP 文件分发，可使用脚本在 Linux、Windows 和 MacOS 上启动。在第一次启动它时，主窗口会包含一个示例思维导图，其中包含指向你可以使用 Freeplane 执行的所有不同操作的文档的链接。

创建新思维导图时，你可以选择模板。标准模板（可能位于列表底部）适用于大多数情况。你只需开始输入开头的想法或短语，你的文本就会替换中心的文本。按“Insert”键将从中心添加一个分支（或节点），其中包含一个空白字段，你可以在其中填写与该想法相关的内容。再次按“Insert”将添加另一个节点到第一个上。在节点上按回车键将添加与该节点平行的节点。

在添加节点时，你可能会想到与主题相关的另一个想法。使用鼠标或箭头键，返回到导图的中心，然后按“Insert”键。这将在主题之外创建一个新节点。

如果你想使用 Freeplane 其他功能，请右键单击任何节点以显示该节点的“属性”菜单。工具窗口（在视图 ->控制菜单下激活）包含丰富的自定义选项，包括线条形状和粗细、边框形状、颜色等等。“日历”选项允许你在节点中插入日期，并为节点设置到期提醒。 （请注意，提醒仅在 Freeplane 运行时有效。）思维导图可以导出为多种格式，包括常见的图像、XML、Microsoft Project、Markdown 和 OPML。

Freeplane 为你提供了创建生动和实用的思维导图所需的所有工具，让你表达头脑中的想法，并可采取行动。

---

via: <https://opensource.com/article/19/1/productivity-tool-freeplane>

作者：[Kevin Sonney](https://opensource.com/users/ksonney "Kevin Sonney") 选题：[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/) 荣誉推出


龙井“上市”，阿里巴巴持续开源回馈社区

赞

# 龙井“上市”，阿里巴巴持续开源回馈社区

3 月 21 日在阿里云峰会·北京上，阿里巴巴旗下的阿里云当天即发布多款重磅产品，涵盖了超级计算、云原生数据库，以及SaaS 加速器，包括神龙异构超算集群、新版本 Polardb 可兼容 Oracle 数据库、轻量级 GPU 异构计算产品——VGN5i 实例等。阿里云总裁兼阿里巴巴 CTO 张建峰称，阿里云已经成为阿里巴巴经济体的技术基石，将继续加大投入，扩大核心技术的代际领先优势。

在本次峰会上，阿里巴巴还宣布开源 OpenJDK 长期支持版本 Alibaba Dragonwell，为全球 Java 界开发者提供了一个新的选择。该版本广泛应用于阿里巴巴旗下业务，在大规模 Java 应用部署下的稳定性、效率以及性能优化有突出的优势。

Java 是全球应用最广泛的语言技术栈。据统计，全球 Java 开发工程师超过 1000 万名。而 JDK 作为 Java 语言的软件开发工具包，是整个 Java 应用的核心。当前，在 JDK 全球市场份额中，Oracle JDK 占 70%、OpenJDK 约占 21%。但 2019 年 1 月之后，Oracle 不再提供 Oracle JDK 8 免费商业版本更新。

阿里巴巴一直不遗余力地推动全球 Java 技术进步。自 2010 年起，阿里就开始基于 OpenJDK 开源软件进行开发与定制。作为全集团 Java 应用的基石，Alibaba Dragonwell 支撑了阿里经济体内所有的 Java 业务，保证了多年来“双 11”的平稳运行，积累了大量业务场景下的实践经验。在大规模 Java 应用部署情况下，Alibaba Dragonwell 可以大幅度提高稳定性、效率及性能。

2018 年，阿里巴巴还作为首家且唯一的中国企业，获邀加入 Java 全球管理组织 Java Community Process（JCP）的最高执行委员会，为 Java 语言规范作出贡献。

“Dragonwell 中文译为龙井，象征着中国的茶文化，又恰好是杭州特色。well 一词通常被描述为水源汇聚在一起供大家分享，这也是我们开源的初衷，希望可以集合开发者的力量，不断完善该项目并最终贡献给所有用户。”阿里云智能资深技术专家李三红在采访中表示，阿里本身就是 Alibaba Dragonwell 的最大用户之一，未来一定会持续维护，这是毫无疑问的。同时也希望有更多的开发者参与贡献，让 Java 变得更好。

作为世界顶尖技术舞台上最活跃的力量之一，阿里巴巴始终积极拥抱开源，回馈社区。截止目前，阿里巴巴已经参与了 9 家全球开源基金会及组织，包括 Linux Foundation、Cloud Native Computing Foundation、Apache Software Foundation、Continuous Delivery Foundation 等，是 Linux、MySQL、JVM、Kubernetes、etcd、containerd、Flink、Envoy 等知名开源项目的核心贡献者和维护者，并主导开源 400 多个项目，涉及中间件、框架、组件、数据库、存储、工具领域等。

就此次 Dragonwell 开源的一些情况，记者采访了阿里巴巴相关负责人。

**Dragonwell，龙井？是寓意像龙井一样的品质吗？背后的想法是什么呢？**

Java 本身就是一种咖啡的名字，AWS 开源的 Corretto 也是一种咖啡名。

在取名字的时候，我们也考虑了很多。中国的 Java 开发者将是 Alibaba Dragonwell 重要的用户群体，所以想从一些有中国特色的饮品名中寻找灵感，既能代表中国的文化，同时也希望这个名字中能有非常宏大的意愿，能够诠释她包容一切。所以我们想到了杭州的绿茶——龙井。而它的英文名字 Dragonwell 也正好符合我们想要表达的意思。其中的 well 这个单词，就有着将很多水源汇聚在一起，一同享用的寓意，正好贴合开源的协作分享的精神理念，这也是阿里开源 JDK 的初衷，希望将许多开发者的贡献汇聚在一起，让大家能够一起免费使用 Java，一起推动 Java 的进步。

**为什么要去做 Dragonwell？是否可以分享一下相关背景？**

大家都知道 Java 一直是由 Oracle 主导的，早从 2017 年开始，Oracle 开始陆陆续续转变了一些 Java 的策略。去年也宣布了将从今年开始不再提供 OracleJDK 的免费更新。

阿里可以说是全球最大的 Java 用户之一，而 JDK 又是 Java 的一个基础设施。我们其实早从 2010 年开始，就已经基于 OpenJDK 开源软件进行开发与定制，9 年来，支撑了阿里经济体内所有的 Java 业务，历经多年的“双 11”考验，积累了大量业务场景下的实践经验。

阿里作为一家这么大体量的 Java 用户，我们有一份责任，就是把我们的 JDK 开放出去，给所有的 Java 用户一个新的选择。同时，对于阿里自身来说，Alibaba Dragonwell 会针对 LTS 的两个版本 Java8 和 Java11 随阿里云 VM 镜像发布，免费提供给阿里云客户使用。

**Alibaba Dragonwell 是基于哪个版本的 JDK？什么时候 GA，目前有没有各个阶段具体的发布时间表？**

此次发布的 Alibaba Dragonwell 8 预览版本对应于上游的 OpenJDK 8 的版本。Alibaba Dragonwell 作为 OpenJDK 下游，是一款免费的 JDK 发行版。它提供长期支持，包括关键修复和安全更新。

Alibaba Dragonwell 支持 x86-64/Linux 平台。Alibaba Dragonwell 的特点，或者说她所注重和强化的是：在数据中心大规模 Java 应用部署情况下，稳定性、效率以及性能的优化与提高。

目前发布的版本是预览版。 Alibaba Dragonwell 将每季度发布一个更新。目前计划是预览版的三个月后发布 GA。Alibaba Dragonwell 11 预计年底发布。

**以后会更注重 Java 新特性的跟进还是保证提供支持呢？对它今后的发展有什么设想或者目标？**

Alibaba Dragonwell 的前身是阿里巴巴内部使用的 AJDK。作为 AJDK 的开源版本， Alibaba Dragonwell 将沿袭 AJDK 的技术优势以及实践场景下的技术经验。AJDK 有众多的技术创新， 包括多租户、Wisp 协程技术、ZenGC 等。 我们希望逐步把阿里巴巴内部积累的技术创新开源出来贡献给 OpenJDK 社区, 并在 Dragonwell 沉淀下来。

**最近出现了一些开源软件变更开源协议问题，那目前/将来 Dragonwell 会不会加入一些支持限制条款呢？**

不会。Alibaba Dragonwell 是 OpenJDK 下游，我们会严格遵循 OpenJDK 社区相关原则及协议。

**前阵子 AWS 也推出了自己的 OpenJDK 发行版 Corretto，背后甚至有 Java 之父“站台”；再往前，其实 Azul、Red Hat 等厂商也有提供 OpenJDK 版本。那么阿里的 Dragonwell 有什么优势、特点呢？**

具体来说：

* 紧密与 OpenJDK 社区保持合作，保持对社区工作的跟踪，及时同步上游更。
* Alibaba Dragonwell 发行版与 Java SE 标准兼容。
* AJDK 上孵化的创新技术，会逐步贡献 OpenJDK，并在 Dragonwell 沉淀。比如这次版本包含的 JWarmUp 功能。 具体技术细节可以参考我们的用户手册。
* 基于阿里工程实践，Alibaba Dragonwell 会选择移植高版本Java的重要功能，这些移植功能已经在阿里内部被大规模部署，用户都可以免费使用，而不用等下一个 LTS 版本。比如这次版本移植了上游 Java 11 的 Java Flight Recorder （JFR）功能，Java 开发人员可以通过 JFR 收集 JVM 运行过程中的详细的 profiling 信息，配合 Java Mission Control（JMC），大幅提高 Java 应用的问题诊断及性能优化效率。这对于仍然停留在 Java8 的客户来说，还是非常有意义的。

**很多开发者使用的都是 Oracle 官方的 OracleJDK，大家什么情况下会去使用 OpenJDK 发行版，具体到 Dragonwell 是怎样呢？**

在 2018 年 CodeOne（原 JavaOne）大会上，来自 Java Platform Group 的首席架构师 Mark Reinhold 做了“The Future of Java is Today”的主题演讲，重点阐述了 Java 发布模式的变化，重点是：从 Java11 （包含）以及以后的版本，Oracle 将不再提供免费的长期支持。如果你需要长期支持，可以通过向 Oracle 付费的方式获得。而 Java8 的更新也将会在 2019 年 1 月份停止。

所以除非你是 Oracle 的付费客户，否则唯一的选择就是社区维护的 OpenJDK 版本。可以预见 Java 开发者从 Oracle JDK 切换到开源 OpenJDK 会越来越多。

阿里作为世界顶尖技术舞台上最活跃的力量之一，始终积极拥抱开源，回馈社区。我们本身就是世界上最大 Java 用户之一，未来会持续与 OpenJDK 社区的紧密合作，做好 Alibaba Dragonwell 的维护与开发工作。对于广大的 Java 开发者而言，Alibaba Dragonwell 是一个免费的新选择**。**同时我们也希望有更多的开发者能参与到社区里来、让 Java 变得更好！


区块链 2.0：介绍（一）

Summary: 区块链现在显然被认为是一种转型技术，它将为人们使用互联网的方式带来革新。本系列文章将探讨即将到来的基于区块链 2.0 的技术和应用浪潮。不同的涉众对它表现出的极大兴趣证明了区块链的存在。

# 区块链 2.0：介绍（一）

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

### 区块链 2.0：下一个计算范式

**区块链**现在显然被认为是一种转型技术，它将为人们使用互联网的方式带来革新。本系列文章将探讨即将到来的基于区块链 2.0 的技术和应用浪潮。不同的涉众对它表现出的极大兴趣证明了区块链的存在。

对于任何打算使用互联网做任何事情的人来说，了解它是什么以及它是如何工作的都是至关重要的。即使你所做的只是盯着 Instagram 上朋友们的早餐照片，或者寻找下一个最好的视频片段，你也需要知道这项技术能对这些提供什么样的帮助。

尽管区块链的基本概念早在上世纪 90 年代就被学术界提及，但它之所以成为网民热词，要归功于诸如**比特币**和**以太币**等支付平台的崛起。

比特币最初是一种去中心化的数字货币。它的出现意味着你基本上可以通过互联网进行完全匿名、安全可靠的支付。不过，在比特币这个简单的金融令牌系统背后，是区块链。您可以将比特币技术或任何加密货币看作是 3 层结构。区块链基础技术可以验证、记录和确认交易，在这个基础之上是协议，本质上来讲是一个规则或在线礼仪，用来兑现、记录和确认交易，当然，最重要的是通常被称作比特币的加密货币令牌。一旦记录了协议相关的事务，则由区块链生成令牌。

虽然大多数人只看到了最顶层，即代表比特币真正含义的硬币或代币，但很少有人知道，在区块链基础技术的帮助下，金融交易只是众多此类可能性中的一种。目前正在探讨这些可能性，以产生和开发所有去中心化交易方式的新标准。

在最基本的层面上，区块链可以被认为是一个包含所有记录和交易的账簿。这实际上意味着区块链理论上可以处理所有类型的记录。未来这方面的发展可能会导致各种硬资产（如房地产契约、实物钥匙等）和软无形资产（如身份记录、专利、商标、预约等）被编码为数字资产，通过区块链进行保护和转让。

对于不熟悉区块链的人来说，区块链上的事务本质上被认为是无偏见的永久记录。这是可能的，因为协议中内置了**共识系统**。所有交易均由系统参与者确认、审核和记录，在比特币加密货币平台中，该角色由**矿工**和交易所负责。这可能因不同的平台或区块链而异。构建该平台的协议栈是由开源代码所定义的，并且对任何具有技术能力的人都是免费的。与目前互联网上运行的许多其他平台不同，公开透明被内置进了该系统。

一旦事务被记录并编码到区块链中，它们就会被看到。参与者有义务按照它们最初的执行方式履行其交易和合约。除非原来的规则禁止了它，否则执行本身将由平台自动处理，因为它是硬编码的。区块链平台对于试图篡改记录、记录的持久性等方面的恢复能力，在因特网上是闻所未闻的。当这项技术的支持者们宣称其日益重要的意义时，这种能力是经常被提及的附加信任层。

这些特性并不是最近才被发现的隐藏的平台潜力，而是从一开始就被设想出来的。传说中的比特币创造者<ruby> 中本聪 <rt>  Satoshi Nakamoto </rt></ruby>在一份公报中说**“我花了数年的时间来构造一个用来支撑巨大的各种可能事务类型的设计……如果比特币能够流行起来，这些就是我们未来要探索的……但是它们在最初就设计，以确保它们将来能够实现。”**。这些特性被设计并融入到已经存在的协议中的事实印证了这些话。关键的想法是，去中心化的事务分类账就像区块链的功能一样，可以用于传输、部署和执行各种形式的合约。

领先的机构目前正在探索重新发明股票、养老金和衍生品等金融工具的可能性，而世界各国政府更关注区块链的防篡改和永久性保存记录的潜力。该平台的支持者声称，一旦开发达到一个关键的门槛，从你的酒店钥匙卡到版权和专利，那时起，一切都将通过区块链记录和实现。

**Ledra Capital**在[这个](http://ledracapital.com/blog/2014/3/11/bitcoin-series-24-the-mega-master-blockchain-list)页面上汇编并维护了几乎完整的项目和细节列表，这些项目和细节理论上可以通过区块链模型实现。想要真正意识到区块链对我们生活的影响有多大是一项艰巨的任务，但看看这个清单就会再次证明这么做的重要性。

现在，上面提到的所有官僚和商业用途可能会让你相信，这样的技术只会出现在政府和大型私营企业领域。然而，事实远非如此。鉴于该系统的巨大潜力使其对此类用途具有吸引力，而区块链还具有其它可能性和特性。还有一些与该技术相关的更复杂的概念，如 DApp、DAO、DAC、DAS 等，本系列文章将深入讨论这些概念。

基本上，开发正在如火如荼地进行，任何人对基于区块链的系统的定义、标准和功能进行指点以便进行更广泛的推广还为时尚早，但是这种可能性及其即将产生的影响无疑是存在的。甚至有人谈到基于区块链的智能手机和选举期间的民意调查。

这只是一个简短的对这个平台能力的鸟瞰。我们将通过一系列这样详细的帖子和文章来研究这些不同的可能性。关注[本系列的下一篇文章](https://www.ostechnix.com/blockchain-2-0-revolutionizing-the-financial-system/)，它将探索区块链是如何革新交易和契约的。

---

via: <https://www.ostechnix.com/blockchain-2-0-an-introduction/>

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

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