互联网的安全是如何保证的：TLS、SSL 和 CA

Summary: 你的浏览器里的锁的图标的后面是什么？

OSI七层模型啥时候蹦出了个安全层。。。

好文，基本概念解释的很到位

你的浏览器里的锁的图标的后面是什么？

# 互联网的安全是如何保证的：TLS、SSL 和 CA

>
> 你的浏览器里的锁的图标的后面是什么？
>
>
>

每天你都会重复这件事很多次，访问网站，网站需要你用你的用户名或者电子邮件地址和你的密码来进行登录。银行网站、社交网站、电子邮件服务、电子商务网站和新闻网站。这里只在使用了这种机制的网站中列举了其中一小部分。

每次你登录进一个这种类型的网站时，你实际上是在说：“是的，我信任这个网站，所以我愿意把我的个人信息共享给它。”这些数据可能包含你的姓名、性别、实际地址、电子邮箱地址，有时候甚至会包括你的信用卡信息。

但是你怎么知道你可以信任这个网站？换个方式问，为了让你可以信任它，网站应该如何保护你的交易？

本文旨在阐述使网站变得安全的机制。我会首先论述 web 协议 http 和 https，以及<ruby> 传输层安全 <rt>  Transport Layer Security </rt></ruby>（TLS）的概念，后者是<ruby> 互联网协议 <rt>  Internet Protocol </rt></ruby>（IP）层中的加密协议之一。然后，我会解释<ruby> 证书颁发机构 <rt>  certificate authority </rt></ruby>和自签名证书，以及它们如何帮助保护一个网站。最后，我会介绍一些开源的工具，你可以使用它们来创建和管理你的证书。

### 通过 https 保护路由

了解一个受保护的网站的最简单的方式就是在交互中观察它，幸运的是，在今天的互联网上，发现一个安全的网站远远比找到一个不安全的网站要简单。但是，因为你已经在 Opensource.com 这个网站上了，我会使用它来作为案例，无论你使用的是哪个浏览器，你应该在你的地址栏旁边看到一个像锁一样的图标。点击这个锁图标，你应该会看见一些和下面这个类似的东西。

默认情况下，如果一个网站使用的是 http 协议，那么它是不安全的。为通过网站主机的路由添加一个配置过的证书，可以把这个网站从一个不安全的 http 网站变为一个安全的 https 网站。那个锁图标通常表示这个网站是受 https 保护的。

点击证书来查看网站的 CA，根据你的浏览器，你可能需要下载证书来查看它。

在这里，你可以了解有关 Opensource.com 证书的信息。例如，你可以看到 CA 是 DigiCert，并以 Opensource.com 的名称提供给 Red Hat。

这个证书信息可以让终端用户检查该网站是否可以安全访问。

>
> 警告：如果你没有在网站上看到证书标志，或者如果你看见的标志显示这个网站不安全——请不要登录或者做任何需要你个人数据的操作。这种情况非常危险！
>
>
>

如果你看到的是警告标志，对于大多数面向公众开放的网站来说，这很少见，它通常意味着该证书已经过期或者是该证书是自签名的，而非通过一个受信任的第三方来颁发。在我们进入这些主题之前，我想解释一下 TLS 和 SSL。

### 带有 TLS 和 SSL 的互联网协议

TLS 是旧版<ruby> 安全套接字层协议 <rt>  Secure Socket Layer </rt></ruby>（SSL）的最新版本。理解这一点的最好方法就是仔细理解互联网协议的不同协议层。

我们知道当今的互联网是由 6 个层面组成的：物理层、数据链路层、网络层、传输层、安全层、应用层。物理层是基础，这一层是最接近实际的硬件设备的。应用层是最抽象的一层，是最接近终端用户的一层。安全层可以被认为是应用层的一部分，TLS 和 SSL，是被设计用来在一个计算机网络中提供通信安全的加密协议，它们位于安全层中。

这个过程可以确保终端用户使用网络服务时，通信的安全性和保密性。

### 证书颁发机构和自签名证书

<ruby> 证书颁发机构 <rt>  Certificate authority </rt></ruby>（CA）是受信任的组织，它可以颁发数字证书。

TLS 和 SSL 可以使连接更安全，但是这个加密机制需要一种方式来验证它；这就是 SSL/TLS 证书。TLS 使用了一种叫做非对称加密的加密机制，这个机制有一对称为私钥和公钥的安全密钥。（这是一个非常复杂的主题，超出了本文的讨论范围，但是如果你想去了解这方面的东西，你可以阅读“[密码学和公钥密码基础体系简介](https://opensource.com/article/18/5/cryptography-pki)”）你要知道的基础内容是，证书颁发机构们，比如 GlobalSign、DigiCert 和 GoDaddy，它们是受人们信任的可以颁发证书的供应商，它们颁发的证书可以用于验证网站使用的 TLS/SSL 证书。网站使用的证书是导入到主机服务器里的，用于保护网站。

然而，如果你只是要测试一下正在开发中的网站或服务，CA 证书可能对你而言太昂贵或者是太复杂了。你必须有一个用于生产目的的受信任的证书，但是开发者和网站管理员需要有一种更简单的方式来测试网站，然后他们才能将其部署到生产环境中；这就是自签名证书的来源。

自签名证书是一种 TLS/SSL 证书，是由创建它的人而非受信任的 CA 机构颁发的。用电脑生成一个自签名证书很简单，它可以让你在无需购买昂贵的 CA 颁发的证书的情况下测试一个安全网站。虽然自签名证书肯定不能拿到生产环境中去使用，但对于开发和测试阶段来说，这是一种简单灵活的方法。

### 生成证书的开源工具

有几种开源工具可以用来管理 TLS/SSL 证书。其中最著名的就是 openssl，这个工具包含在很多 Linux 发行版中和 MacOS 中。当然，你也可以使用其他开源工具。

| 工具名 | 描述 | 许可证 |
| --- | --- | --- |
| [OpenSSL](https://www.openssl.org/) | 实现 TLS 和加密库的最著名的开源工具 | Apache License 2.0 |
| [EasyRSA](https://github.com/OpenVPN/easy-rsa) | 用于构建 PKI CA 的命令行实用工具 | GPL v2 |
| [CFSSL](https://github.com/cloudflare/cfssl) | 来自 cloudflare 的 PKI/TLS 瑞士军刀 | BSD 2-Clause Simplified License |
| [Lemur](https://github.com/Netflix/lemur) | 来自<ruby> 网飞 <rt>  Netflix </rt></ruby>的 TLS 创建工具 | Apache License 2.0 |

如果你的目的是扩展和对用户友好，网飞的 Lemur 是一个很有趣的选择。你在[网飞的技术博客](https://medium.com/netflix-techblog/introducing-lemur-ceae8830f621)上可以查看更多有关它的信息。

### 如何创建一个 Openssl 证书

你可以靠自己来创建证书，下面这个案例就是使用 Openssl 生成一个自签名证书。

1、使用 `openssl` 命令行生成一个私钥：

```
openssl genrsa -out example.key 2048
```

2、使用在第一步中生成的私钥来创建一个<ruby> 证书签名请求 <rt>  certificate signing request </rt></ruby>（CSR）：

```
openssl req -new -key example.key -out example.csr -subj "/C=US/ST=TX/L=Dallas/O=Red Hat/OU=IT/CN=test.example.com"
```

3、使用你的 CSR 和私钥创建一个证书：

```
openssl x509 -req -days 366 -in example.csr -signkey example.key -out example.crt
```

### 了解更多关于互联网安全的知识

如果你想要了解更多关于互联网安全和网站安全的知识，请看我为这篇文章一起制作的 Youtube 视频。

你有什么问题？发在评论里让我们知道。

---

via: <https://opensource.com/article/19/11/internet-security-tls-ssl-certificate-authority>

作者：[Bryant Son](https://opensource.com/users/brson) 选题：[lujun9972](https://github.com/lujun9972) 译者：[hopefully2333](https://github.com/hopefully2333) 校对：[wxy](https://github.com/wxy)

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


如何使用 Flask 编写 Python Web API

# 如何使用 Flask 编写 Python Web API

>
> 这是一个快速教程，用来展示如何通过 Flask（目前发展最迅速的 Python 框架之一）来从服务器获取数据。
>
>
>

<img src="content_image/album_201912_21_112324fx6z8i11yyz7j8y8.png" alt="spiderweb diagram" title="spiderweb diagram">

[Python](https://www.python.org/) 是一个以语法简洁著称的高级的、面向对象的程序语言。它一直都是一个用来构建 RESTful API 的顶级编程语言。

[Flask](https://palletsprojects.com/p/flask/) 是一个高度可定制化的 Python 框架，可以为开发人员提供用户访问数据方式的完全控制。Flask 是一个基于 Werkzeug 的 [WSGI](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface) 工具包和 Jinja 2 模板引擎的”微框架“。它是一个被设计来开发 RESTful API 的 web 框架。

Flask 是 Python 发展最迅速的框架之一，很多知名网站如：Netflix、Pinterest 和 LinkedIn 都将 Flask 纳入了它们的开发技术栈。下面是一个简单的示例，展示了 Flask 是如何允许用户通过 HTTP GET 请求来从服务器获取数据的。

### 初始化一个 Flask 应用

首先，创建一个你的 Flask 项目的目录结构。你可以在你系统的任何地方来做这件事。

```
$ mkdir tutorial
$ cd tutorial
$ touch main.py
$ python3 -m venv env
$ source env/bin/activate
(env) $ pip3 install flask-restful
Collecting flask-restful
Downloading https://files.pythonhosted.org/packages/17/44/6e49...8da4/Flask_RESTful-0.3.7-py2.py3-none-any.whl
Collecting Flask>=0.8 (from flask-restful)
[...]
```

### 导入 Flask 模块

然后，在你的 `main.py` 代码中导入 `flask` 模块和它的 `flask_restful` 库：

```
from flask import Flask
from flask_restful import Resource, Api

app = Flask(__name__)
api = Api(app)

class Quotes(Resource):
    def get(self):
        return {
            'William Shakespeare': {
                'quote': ['Love all,trust a few,do wrong to none',
                'Some are born great, some achieve greatness, and some greatness thrust upon them.']
        },
        'Linus': {
            'quote': ['Talk is cheap. Show me the code.']
            }
        }

api.add_resource(Quotes, '/')

if __name__ == '__main__':
    app.run(debug=True)
```

### 运行 app

Flask 包含一个内建的用于测试的 HTTP 服务器。来测试一下这个你创建的简单的 API：

```
(env) $ python main.py
 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```

启动开发服务器时将启动 Flask 应用程序，该应用程序包含一个名为 `get` 的方法来响应简单的 HTTP GET 请求。你可以通过 `wget`、`curl` 命令或者任意的 web 浏览器来测试它。

```
$ curl http://localhost:5000
{
    "William Shakespeare": {
        "quote": [
            "Love all,trust a few,do wrong to none",
            "Some are born great, some achieve greatness, and some greatness thrust upon them."
        ]
    },
    "Linus": {
        "quote": [
            "Talk is cheap. Show me the code."
        ]
    }
}
```

要查看使用 Python 和 Flask 的类似 Web API 的更复杂版本，请导航至美国国会图书馆的 [Chronicling America](https://chroniclingamerica.loc.gov/about/api) 网站，该网站可提供有关这些信息的历史报纸和数字化报纸。

### 为什么使用 Flask?

Flask 有以下几个主要的优点：

1. Python 很流行并且广泛被应用，所以任何熟悉 Python 的人都可以使用 Flask 来开发。
2. 它轻巧而简约。
3. 考虑安全性而构建。
4. 出色的文档，其中包含大量清晰，有效的示例代码。

还有一些潜在的缺点:

1. 它轻巧而简约。但如果你正在寻找具有大量捆绑库和预制组件的框架，那么这可能不是最佳选择。
2. 如果必须围绕 Flask 构建自己的框架，则你可能会发现维护自定义项的成本可能会抵消使用 Flask 的好处。

如果你要构建 Web 程序或 API，可以考虑选择 Flask。它功能强大且健壮，并且其优秀的项目文档使入门变得容易。试用一下，评估一下，看看它是否适合你的项目。

在本课中了解更多信息关于 Python 异常处理以及如何以安全的方式进行操作。

---

via: <https://opensource.com/article/19/11/python-web-api-flask>

作者：[Rachel Waston](https://opensource.com/users/rachelwaston) 选题：[lujun9972](https://github.com/lujun9972) 译者：[hj24](https://github.com/hj24) 校对：[wxy](https://github.com/wxy)

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


如何在 Linux 系统中输入 emoji

Summary: 使用 GNOME 桌面可以让你在文字中轻松加入 emoji。

使用 GNOME 桌面可以让你在文字中轻松加入 emoji。

# 如何在 Linux 系统中输入 emoji

>
> 使用 GNOME 桌面可以让你在文字中轻松加入 emoji。
>
>
>

emoji 是潜藏在 Unicode 字符空间里的有趣表情图，它们已经风靡于整个互联网。emoji 可以用来在社交媒体上表示自己的心情状态，也可以作为重要文件名的视觉标签，总之它们的各种用法层出不穷。在 Linux 系统中有很多种方式可以输入 Unicode 字符，但 GNOME 桌面能让你更轻松地查找和输入 emoji。

### 准备工作

首先，你需要一个运行 [GNOME](https://www.gnome.org/) 桌面的 Linux 系统。

同时还需要安装一款支持 emoji 的字体。符合这个要求的字体有很多，使用你喜欢的软件包管理器直接搜索 `emoji` 并选择一款安装就可以了。

例如在 Fedora 上：

```
$ sudo dnf search emoji
emoji-picker.noarch : An emoji selection tool
unicode-emoji.noarch : Unicode Emoji Data Files
eosrei-emojione-fonts.noarch : A color emoji font
twitter-twemoji-fonts.noarch : Twitter Emoji for everyone
google-android-emoji-fonts.noarch : Android Emoji font released by Google
google-noto-emoji-fonts.noarch : Google “Noto Emoji” Black-and-White emoji font
google-noto-emoji-color-fonts.noarch : Google “Noto Color Emoji” colored emoji font
[...]
```

对于 Ubuntu 或者 Debian，需要使用 `apt search`。

在这篇文章中，我会使用 [Google Noto Color Emoji](https://www.google.com/get/noto/help/emoji/) 这款字体为例。

### 设置

要开始设置，首先打开 GNOME 的设置面板。

1、在左边侧栏中，选择“<ruby> 地区与语言 <rt>  Region & Language </rt></ruby>”类别。

2、点击“<ruby> 输入源 <rt>  Input Sources </rt></ruby>”选项下方的加号（+）打开“<ruby> 添加输入源 <rt>  Add an Input Source </rt></ruby>”面板。

3、在“<ruby> 添加输入源 <rt>  Add an Input Source </rt></ruby>”面板中，点击底部的菜单按钮。

4、滑动到列表底部并选择“<ruby> 其它 <rt>  Other </rt></ruby>”。

5、在“<ruby> 其它 <rt>  Other </rt></ruby>”列表中，找到“<ruby> 其它 <rt>  Other </rt></ruby>（<ruby> 快速输入 <rt>  Typing Booster </rt></ruby>）”。

6、点击右上角的“<ruby> 添加 <rt>  Add </rt></ruby>”按钮，将输入源添加到 GNOME 桌面。

以上操作完成之后，就可以关闭设置面板了。

#### 切换到快速输入

现在 GNOME 桌面的右上角会出现一个新的图标，一般情况下是当前语言的双字母缩写（例如英语是 en，世界语是 eo，西班牙语是 es，等等）。如果你按下了<ruby> 超级键 <rt>  Super key </rt></ruby>（也就是键盘上带有 Linux 企鹅/Windows 徽标/Mac Command 标志的键）+ 空格键的组合键，就会切换到输入列表中的下一个输入源。在这里，我们只有两个输入源，也就是默认语言和快速输入。

你可以尝试使用一下这个组合键，观察图标的变化。

#### 配置快速输入

在快速输入模式下，点击右上角的输入源图标，选择“<ruby> Unicode 符号和 emoji 联想 <rt>  Unicode symbols and emoji predictions </rt></ruby>”选项，设置为“<ruby> 开 <rt>  On </rt></ruby>”。

现在快速输入模式已经可以输入 emoji 了。这正是我们现在所需要的，当然快速输入模式的功能也并不止于此。

### 输入 emoji

在快速输入模式下，打开一个文本编辑器，或者网页浏览器，又或者是任意一种支持输入 Unicode 字符的软件，输入“thumbs up”，快速输入模式就会帮你迅速匹配的 emoji 了。

要退出 emoji 模式，只需要再次使用超级键+空格键的组合键，输入源就会切换回你的默认输入语言。

### 使用其它切换方式

如果你觉得“超级键+空格键”这个组合用起来不顺手，你也可以换成其它键的组合。在 GNOME 设置面板中选择“<ruby> 设备 <rt>  Device </rt></ruby>”→“<ruby> 键盘 <rt>  Keyboard </rt></ruby>”。

在“<ruby> 键盘 <rt>  Keyboard </rt></ruby>”页面中，将“<ruby> 切换到下一个输入源 <rt>  Switch to next input source </rt></ruby>”更改为你喜欢的组合键。

### 输入 Unicode

实际上，现代键盘的设计只是为了输入 26 个字母以及尽可能多的数字和符号。但 ASCII 字符的数量已经比键盘上能看到的字符多得多了，遑论上百万个 Unicode 字符。因此，如果你想要在 Linux 应用程序中输入 Unicode，但又不想使用快速输入，你可以尝试一下 Unicode 输入。

1. 打开任意一种支持输入 Unicode 字符的软件，但仍然使用你的默认输入语言
2. 使用 `Ctrl+Shift+U` 组合键进入 Unicode 输入模式
3. 在 Unicode 输入模式下，只需要输入某个 Unicode 字符的对应序号，就实现了对这个 Unicode 字符的输入。例如 `1F44D` 对应的是 ?，而 `2620` 则对应了 ☠。想要查看所有 Unicode 字符的对应序号，可以参考 [Unicode 规范](http://unicode.org/emoji/charts/full-emoji-list.html)。

### emoji 的实用性

emoji 可以让你的文本变得与众不同，这就是它们有趣和富有表现力的体现。同时 emoji 也有很强的实用性，因为它们本质上是 Unicode 字符，在很多支持自定义字体的地方都可以用到它们，而且跟使用其它常规字符没有什么太大的差别。因此，你可以使用 emoji 来对不同的文件做标记，在搜索的时候就可以使用 emoji 把这些文件快速筛选出来。

你可以在 Linux 中尽情地使用 emoji，因为 Linux 是一个对 Unicode 友好的环境，未来也会对 Unicode 有着越来越好的支持。

---

via: <https://opensource.com/article/19/10/how-type-emoji-linux>

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


GNOME 2 粉丝喜欢 Mate Linux 桌面的什么？

Mate也就适合对GNOME2有执念的人吧。

还是有点怀念的。GNOME 3 刚开始的时候，问题太多，我也用过一段时间 Mate。

KDE在是桌面未来。

KDE才是桌面未来。KDE才是桌面未来。KDE才是桌面未来。重要事情说3遍。

为什么这么说呢，基于哪些方面

还是很稳定的

# GNOME 2 粉丝喜欢 Mate Linux 桌面的什么？

>
> 本文是 24 天 Linux 桌面特别系列的一部分。如果你还在怀念 GNOME 2，那么 Mate Linux 桌面将满足你的怀旧情怀。
>
>
>

如果你以前听过这个传闻：当 GNOME3 第一次发布时，很多 GNOME 用户还没有准备好放弃 GNOME 2。[Mate](https://mate-desktop.org/)（以<ruby> 马黛茶 <rt>  yerba mate </rt></ruby>植物命名）项目的开始是为了延续 GNOME 2 桌面，刚开始时它使用 GTK 2（GNOME 2 所基于的工具包），然后又合并了 GTK 3。由于 Linux Mint 的简单易用，使得该桌面变得非常流行，并且从那时起，它已经普遍用于 Fedora、Ubuntu、Slackware、Arch 和许多其他 Linux 发行版上。今天，Mate 继续提供一个传统的桌面环境，它的外观和感觉与 GNOME 2 完全一样，使用 GTK 3 工具包。

你可以在你的 Linux 发行版的软件仓库中找到 Mate，也可以下载并[安装](https://mate-desktop.org/install/)一个把 Mate 作为默认桌面的发行版。不过，在你这样做之前，请注意为了提供完整的桌面体验，所以许多 Mate 应用程序都是随该桌面一起安装的。如果你运行的是不同的桌面，你可能会发现自己有多余的应用程序（两个 PDF 阅读器、两个媒体播放器、两个文件管理器，等等）。所以如果你只想尝试 Mate 桌面，可以在虚拟机（例如 [GNOME box](https://opensource.com/article/19/5/getting-started-gnome-boxes-virtualization)）中安装基于 Mate 的发行版。

### Mate 桌面之旅

Mate 项目不仅仅可以让你想起来 GNOME 2；它就是 GNOME 2。如果你是 00 年代中期 Linux 桌面的粉丝，至少，你会从中感受到 Mate 的怀旧情怀。我不是 GNOME 2 的粉丝，我更倾向于使用 KDE，但是有一个地方我无法想象没有 GNOME 2：[OpenSolaris](https://en.wikipedia.org/wiki/OpenSolaris)。OpenSolaris 项目并没有持续太久，在 Sun Microsystems 被并入 Oracle 之前，Ian Murdock 加入 Sun 时它就显得非常突出，我当时是一个初级的 Solaris 管理员，使用 OpenSolaris 来让自己更多学会那种 Unix 风格。这是我使用过 GNOME 2 的唯一平台（因为我一开始不知道如何更改桌面，后来习惯了它），而今天的 [OpenIndiana project](https://www.openindiana.org/documentation/faq/#what-is-openindiana) 是 OpenSolaris 的社区延续，它通过 Mate 桌面使用 GNOME 2。

Mate 的布局由左上角的三个菜单组成：应用程序、位置和系统。应用程序菜单提供对系统上安装的所有的应用程序启动器的快速访问。位置菜单提供对常用位置（如家目录、网络文件夹等）的快速访问。系统菜单包含全局选项，如关机和睡眠。右上角是一个系统托盘，屏幕底部有一个任务栏和一个虚拟桌面切换栏。

就桌面设计而言，这是一种稍微有点奇怪的配置。它从早期的 Linux 桌面、MacFinder 和 Windows 中借用了一些相同的部分，但是又创建了一个独特的配置，这种配置很直观而有些熟悉。Mate 执意保持这个模型，而这正是它的用户喜欢的地方。

### Mate 和开源

Mate 是一个最直接的例子，展示了开源如何使开发人员能够对抗项目生命的终结。从理论上讲，GNOME 2 会被 GNOME 3 所取代，但它依然存在，因为一个开发人员建立了该代码的一个分支并继续发展了下去。它的发展势头越来越庞大，更多的开发人员加入进来，并且这个让用户喜爱的桌面比以往任何时候都要更好。并不是所有的软件都有第二次机会，但是开源永远是一个机会，否则就永远没有机会。

使用和支持开源意味着支持用户和开发人员的自由。而且 Mate 桌面是他们的努力的有力证明。

---

via: <https://opensource.com/article/19/12/mate-linux-desktop>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[mayunmeiyouming](https://github.com/mayunmeiyouming) 校对：[wxy](https://github.com/wxy)

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


全球化思考:怎样克服交流中的文化差异

Summary: 这有一些建议帮助你的全球化开发团队能够更好地理解你们的讨论并能参与其中。

这有一些建议帮助你的全球化开发团队能够更好地理解你们的讨论并能参与其中。

# 全球化思考:怎样克服交流中的文化差异

>
> 这有一些建议帮助你的全球化开发团队能够更好地理解你们的讨论并能参与其中。
>
>
>

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

几周前，我见证了两位同事之间一次有趣的互动，他们分别是 Jason，我们的一位美国员工，和 Raj，一位来自印度的访问工作人员。

Raj 在印度时，他一般会通过电话参加美国中部时间上午 9 点的每日立会，现在他到美国工作了，就可以和组员们坐在同一间会议室里开会了。Jason 拦下了 Raj，说：“Raj 你要去哪？你不是一直和我们开电话会议吗？你突然出现在会议室里我还不太适应。” Raj 听了说，“是这样吗？没问题。”就回到自己工位前准备和以前一样参加电话会议了。

我去找 Raj，问他为什么不去参加每日立会，Raj 说 Jason 让自己给组员们打电话参会，而与此同时，Jason 也在会议室等着 Raj 来参加立会。

到底是哪里出的问题？Jason 明显只是调侃 Raj 终于能来一起开会了，为什么 Raj 没能听懂呢？

Jason 明显是在开玩笑，但 Raj 把它当真了。这就是在两人互相不了解对方文化语境时发生的一个典型误会。

我经常会遇到有人在电子邮件的末尾写“请复原”，最开始我很迷惑，“这有什么需要我复原的内容？”后来我才搞懂，“请复原”其实是“请回复”的意思。

在 Ricardo Fernandez 的TED 演讲“[如何管理跨文化团队](https://www.youtube.com/watch?v=QIoAkFpN8wQ)” 中，他提到了自己与一位南非同事发生的小故事。那位同事用一句“我一会给你打电话。”结束了两人的 IM 会话，Ricardo 回到办公室后就开始等这位同事的电话，十五分钟后他忍不住主动给这位同事打了电话，问他:“你不是说要给我打电话吗？”，这位同事答到:“是啊，我是说以后有机会给你打电话。”这时 Ricardo 才理解那位同事说的“一会”是“以后”的意思。

现在是全球化时代，我们的同事很可能不跟我们面对面接触，甚至不在同一座城市，来自不同的国家。越来越多的技术公司拥有全球化的工作场所，和来自世界各地的员工，他们有着不同的背景和经历。这种多样性使得技术公司能够在这个快速发展的科技大环境下拥有更强的竞争力。

但是这种地域的多样性也会给团队带来挑战。管理和维持高性能的团队发展对于同地协作的团队来说就有着很大难度，对于有着多样背景成员的全球化团队来说，无疑更加困难。成员之间的交流会发生延迟，误解时有发生，成员之间甚至会互相怀疑，这些都会影响着公司的成功。

到底是什么因素让全球化交流间发生误解呢？我们可以参照 Erin Meyer 的书《[文化地图](https://www.amazon.com/The-Culture-Map-Invisible-Boundaries/dp/1610392507)》，她在书中将全球文化分为八个类型，其中美国文化被分为低语境文化，与之相对的，日本为高语境文化。

看到这里你可能会问，高、低语境文化到底是什么意思？美国人从小就教育孩子们简洁表达，“直言不讳”是他们的表达准则；另一边，日本人从小学习在高效处理社交线索的同时进行交流，“察言观色”是他们的交流习惯。

大部分亚洲国家的文化都属于高语境文化。作为一个年轻的移民国家，美国毫不意外地拥有着低语境文化。移民来自于世界各地，拥有着不同的文化背景，他们不得不选择简洁而直接的交流方式，这或许就是其拥有低语境文化的原因。

### 从文化语境的角度与异国同事交流的三个步骤：

怎样面临跨文化交流中遇到的挑战？比如说一位美国人与他的日本同事交流，他更应该注重日本同事的非语言线索，同样的日本同事应当更关注美国人直接表达出的信息。如果你也面临类似的挑战，按照下面这三个步骤做，可以帮助你更有效地和异国同事交流，增进与他们的感情。

#### 认识到文化语境的差异

跨文化交流的第一步是认识到文化差异，跨文化交流从认识其他文化开始。

#### 尊重文化语境的差异

一旦你意识到了文化语境的差异会影响跨文化交流，你要做的就是尊重这些差异。在你遇到一种不同的交流方式时，学会接受差异，学会积极听取他人意见。

#### 调和文化语境的差异

只是认识和尊重差异还远远不够，你还需要学会如何调和这些差异。互相理解和换位思考可以增进差异的调和，你还要学着用它们去提高同事间的交流效率，推动生产力。

### 五种促进不同文化语境间交流的方法

为了加强组员们之间关系，这么多年来我一直在收集各种各样的方法和建议。这些方法帮助我解决了与外国组员间产生的很多交流问题，下面有其中一些例子：

#### 与外国组员交流时尽量使用视频会议的形式

研究表明，交流中约 55% 的内容不是靠语言传递的。肢体语言传达着一种十分微妙的信息，你可以根据它们理解对方的意思，而视频会议中处于异地的组员们能够看到对方的肢体语言。因此，组织远程会议时我一般都会采用视频会议的形式。

#### 确保每位成员都有机会分享他们的想法

我虽然喜欢开视频会议，但不是每次都能开的成。如果视频会议对你的团队来说并不常用，大家可能要一些时间去适应，你需要积极鼓励大家参与到其中，先从进行语音会议开始。

我们有一个外地的组员，每次都和我们进行语音会议，和我们提到她经常会有些想法想要分享，或者想做些贡献，但是我们互相看不到，她不知道该怎样开口。如果你一直在进行语音会议，注意要给组员们足够的时间和机会分享他们的想法。

#### 互相学习

通过你身边一两名外国朋友来学习他们的文化，你可以把从一位同事身上学到的应用于所有来自这个国家的同事。我有几位南亚和南美的同事，他们帮助我理解他们的文化，而这些也使得我更加专业。

对编程人员来说，我建议请你全世界的同行们检查你的代码，这个过程能让你观察到其他文化中人们怎样进行反馈、劝说他人，和最终进行技术决策。

#### 学会感同身受

同理心是一段牢固关系的核心。你越能换位思考，就越容易获得信任，来建立长久的关系。你可以在每次会议开始之前和大家闲聊几句，这样大家更容易处于一个放松的状态，如果团队中有很多外国人，要确保大家都能参与进来。

#### 和你的外国同事们单独见面

保持长久关系最好的方法是和你的组员们单独见面。如果你的公司可以报销这些费用，那么努力去和组员们见面吧。和一起工作了很长时间的组员们见面能够使你们的关系更加坚固。我所在的公司就有着周期性交换员工的传统，每隔一段时间，世界各地的员工就会来到美国工作，美国员工再到其他分部工作。

另一种聚齐组员们的机会是研讨会。研讨会创造的不仅是学习和培训的机会，你还可以挤出一些时间和组员们培养感情。

在如今，全球化经济不断发展，拥有来自不同国家和地区的员工对维持一个公司的竞争力来说越来越重要。即使组员们来自世界各地，团队中会出现一些交流问题，但拥有一支国际化的高绩效团队不是问题。如果你在工作中有什么促进团队交流的小窍门，请在评论中告诉我们吧。

---

via: <https://opensource.com/article/18/10/think-global-communication-challenges>

作者：[Avindra Fernando](https://opensource.com/users/avindrafernando) 选题：[lujun9972](https://github.com/lujun9972) 译者：[Valoniakim](https://github.com/Valoniakim) 校对：[wxy](https://github.com/wxy)

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


在 Linux 桌面中开始使用 Lumina

# 在 Linux 桌面中开始使用 Lumina

>
> 本文是 24 天 Linux 桌面特别系列的一部分。Lumina 桌面是让你使用快速、合理的基于 Fluxbox 桌面的捷径，它具有你无法缺少的所有功能。
>
>
>

多年来，有一个名为 PC-BSD 的基于 FreeBSD 的桌面操作系统（OS）。它旨在作为一个常规使用的系统，因此值得注意，因为 BSD 主要用于服务器。大多数时候，PC-BSD 默认带 KDE 桌面，但是 KDE 越来越依赖于 Linux 特定的技术，因此 PC-BSD 越来越从 KDE 迁离。PC-BSD 变成了 [Trident](https://project-trident.org/)，它的默认桌面是 [Lumina](https://lumina-desktop.org/)，它是一组小部件，它们使用与 KDE 相同的基于 Qt 的工具包，运行在 Fluxbox 窗口管理器上。

你可以在 Linux 发行版的软件仓库或 BSD 的 ports 树中找到 Lumina 桌面。如果你安装了 Lumina 并且已经在运行另一个桌面，那么你可能会发现有冗余的应用（两个 PDF 阅读器、两个文件管理器，等等），因为 Lumina 包含一些集成的应用。如果你只想尝试 Lumina 桌面，那么可以在虚拟机如 [GNOME Boxes](https://opensource.com/article/19/5/getting-started-gnome-boxes-virtualization) 中安装基于 Lumina 的 BSD 发行版。

如果在当前的操作系统上安装 Lumina，那么必须注销当前的桌面会话，才能登录到新的会话。默认情况下，会话管理器（SDDM、GDM、LightDM 或 XDM，取决于你的设置）将继续登录到以前的桌面，因此你必须在登录之前覆盖该桌面。

在 GDM 中：

在 SDDM 中：

### Lumina 桌面

Lumina 提供了一个简单而轻巧的桌面环境。屏幕底部有一个面板，它的左侧是应用菜单，中间是任务栏，右边是系统托盘。桌面上有图标，可以快速访问常见的应用和路径。

除了这个基本的桌面结构外，Lumina 还有自定义文件管理器、PDF 查看器，截图工具、媒体播放器、文本编辑器和存档工具。还有一个配置程序可以帮助你自定义 Lumina 桌面，并且右键单击桌面可以找到更多配置选项。

Lumina 与几个 Linux 轻量级桌面非常相似，尤其是 LXQT，不同之处在于 Lumina 完全不依赖于基于 Linux 的桌面框架（例如 ConsoleKit、PolicyKit、D-Bus 或 systemd）。对于你而言，这是否具有优势取决于所运行的操作系统。毕竟，如果你运行的是可以访问这些功能的 Linux，那么使用不使用这些特性的桌面可能就没有多大意义，还会减少功能。如果你运行的是 BSD，那么在 Fluxbox 中运行 Lumina 部件意味着你不必从 ports 安装 Linux 兼容库。

### 为什么要使用 Lumina

Lumina 设计简单，它没有很多功能，但是你可以安装 Fluxbox 你喜欢的组件（用于文件管理的 [PCManFM](https://wiki.lxde.org/en/PCManFM)、各种 [LXQt 应用](http://lxqt.org)、[Tint2](https://opensource.com/article/19/1/productivity-tool-tint2) 面板等）。在开源中，开源用户喜欢寻找不要重复发明轮子的方法（几乎与我们喜欢重新发明轮子一样多）。

Lumina 桌面是让你使用快速、合理的基于 Fluxbox 桌面的捷径，它具有你无法缺少的所有功能，并且你很少需要调整细节。试一试 Lumina 桌面，看看它是否适合你。

---

via: <https://opensource.com/article/19/12/linux-lumina-desktop>

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


网络启动一个 Fedora Live CD

Summary: 这个指南向你展示如何加载你的 Live CD 镜像到一个 ISCSI 服务器上，并使用 iPXE 启动加载程序来访问它们。

# 网络启动一个 Fedora Live CD

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

[Live CD](https://en.wikipedia.org/wiki/Live_CD) 对于很多任务是很有用的，例如:

* 将操作系统安装到一个硬盘驱动器
* 修复一个启动加载程序或执行其它救援模式操作
* 为 Web 浏览提供一个相适应的最小环境
* …以及[更多的东西](https://en.wikipedia.org/wiki/Live_CD#Uses)。

作为使用 DVD 和 USB 驱动器来存储你的 Live CD 镜像是一个替代方案，你可以上传它们到一个不太可能丢失或损坏的 [iSCSI](https://en.wikipedia.org/wiki/ISCSI) 服务器中。这个指南向你展示如何加载你的 Live CD 镜像到一个 ISCSI 服务器上，并使用 [iPXE](https://ipxe.org/) 启动加载程序来访问它们。

### 下载一个 Live CD 镜像

```
$ MY_RLSE=27
$ MY_LIVE=$(wget -q -O - https://dl.fedoraproject.org/pub/archive/fedora/linux/releases/$MY_RLSE/Workstation/x86_64/iso | perl -ne '/(Fedora[^ ]*?-Live-[^ ]*?\.iso)(?{print $^N})/;')
$ MY_NAME=fc$MY_RLSE
$ wget -O $MY_NAME.iso https://dl.fedoraproject.org/pub/archive/fedora/linux/releases/$MY_RLSE/Workstation/x86_64/iso/$MY_LIVE
```

上面的命令下载 `Fedora-Workstation-Live-x86_64-27-1.6.iso` Fedora Live 镜像，并保存为 `fc27.iso`。更改 `MY_RLSE` 的值来下载其它档案版本。或者，你可以浏览 <https://getfedora.org/> 来下载最新的 Fedora live 镜像。在 21 之前的版本使用不同的命名约定，必需[在这里手动下载](https://dl.fedoraproject.org/pub/archive/fedora/linux/releases/https://dl.fedoraproject.org/pub/archive/fedora/linux/releases/)。如果你手动下载一个 Live CD 镜像，设置 `MY_NAME` 变量为不带有扩展名的文件的基本名称。用此方法，下面部分中命令将引用正确的文件。

### 转换 Live CD 镜像

使用 `livecd-iso-to-disk` 工具来转换 ISO 文件为一个磁盘镜像，并添加 `netroot` 参数到嵌入的内核命令行：

```
$ sudo dnf install -y livecd-tools
$ MY_SIZE=$(du -ms $MY_NAME.iso | cut -f 1)
$ dd if=/dev/zero of=$MY_NAME.img bs=1MiB count=0 seek=$(($MY_SIZE+512))
$ MY_SRVR=server-01.example.edu
$ MY_RVRS=$(echo $MY_SRVR | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_SRVR})
$ MY_LOOP=$(sudo losetup --show --nooverlap --find $MY_NAME.img)
$ sudo livecd-iso-to-disk --format --extra-kernel-args netroot=iscsi:$MY_SRVR:::1:iqn.$MY_RVRS:$MY_NAME $MY_NAME.iso $MY_LOOP
$ sudo losetup -d $MY_LOOP
```

### 上传 Live 镜像到你的服务器

在你的 ISCSI 服务器上创建一个目录来存储你的 live 镜像，随后上传你修改的镜像到其中。

对于 21 及更高发布版本：

```
$ MY_FLDR=/images
$ scp $MY_NAME.img $MY_SRVR:$MY_FLDR/
```

对于 21 以前发布版本：

```
$ MY_FLDR=/images
$ MY_LOOP=$(sudo losetup --show --nooverlap --find --partscan $MY_NAME.img)
$ sudo tune2fs -O ^has_journal ${MY_LOOP}p1
$ sudo e2fsck ${MY_LOOP}p1
$ sudo dd status=none if=${MY_LOOP}p1 | ssh $MY_SRVR "dd of=$MY_FLDR/$MY_NAME.img"
$ sudo losetup -d $MY_LOOP
```

### 定义 iSCSI 目标

在你的 iSCSI 服务器上运行下面的命令：

```
$ sudo -i
# MY_NAME=fc27
# MY_FLDR=/images
# MY_SRVR=`hostname`
# MY_RVRS=$(echo $MY_SRVR | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_SRVR})
# cat << END > /etc/tgt/conf.d/$MY_NAME.conf
<target iqn.$MY_RVRS:$MY_NAME>
    backing-store $MY_FLDR/$MY_NAME.img
    readonly 1
    allow-in-use yes
</target>
END
# tgt-admin --update ALL
```

### 创建一个可启动 USB 驱动器

[iPXE](https://ipxe.org/) 启动加载程序有一个 [sanboot](http://ipxe.org/cmd/sanboot/) 命令，你可以使用它来连接并启动托管于你 ISCSI 服务器上运行的 live 镜像。它可以以很多不同的[格式](https://ipxe.org/appnote/buildtargets#boot_type)编译。最好的工作格式依赖于你正在运行的硬件。例如，下面的说明向你展示如何在一个 USB 驱动器上从 [syslinux](https://www.syslinux.org/wiki/index.php?title=SYSLINUX) 中 [链式加载](https://en.wikipedia.org/wiki/Chain_loading) iPXE。

首先，下载 iPXE，并以它的 lkrn 格式构建。这应该作为一个工作站上的普通用户完成：

```
$ sudo dnf install -y git
$ git clone http://git.ipxe.org/ipxe.git $HOME/ipxe
$ sudo dnf groupinstall -y "C Development Tools and Libraries"
$ cd $HOME/ipxe/src
$ make clean
$ make bin/ipxe.lkrn
$ cp bin/ipxe.lkrn /tmp
```

接下来，准备一个带有一个 MSDOS 分区表和一个 FAT32 文件系统的 USB 驱动器。下面的命令假设你已经连接将要格式化的 USB 驱动器。**注意：你要格式正确的驱动器！**

```
$ sudo -i
# dnf install -y parted util-linux dosfstools
# echo; find /dev/disk/by-id ! -regex '.*-part.*' -name 'usb-*' -exec readlink -f {} \; | xargs -i bash -c "parted -s {} unit MiB print | perl -0 -ne '/^Model: ([^(]*).*\n.*?([0-9]*MiB)/i && print \"Found: {} = \$2 \$1\n\"'"; echo; read -e -i "$(find /dev/disk/by-id ! -regex '.*-part.*' -name 'usb-*' -exec readlink -f {} \; -quit)" -p "Drive to format: " MY_USB
# umount $MY_USB?
# wipefs -a $MY_USB
# parted -s $MY_USB mklabel msdos mkpart primary fat32 1MiB 100% set 1 boot on
# mkfs -t vfat -F 32 ${MY_USB}1
```

最后，在 USB 驱动器上安装并配置 syslinux ，来链式加载 iPXE：

```
# dnf install -y syslinux-nonlinux
# syslinux -i ${MY_USB}1
# dd if=/usr/share/syslinux/mbr.bin of=${MY_USB}
# MY_MNT=$(mktemp -d)
# mount ${MY_USB}1 $MY_MNT
# MY_NAME=fc27
# MY_SRVR=server-01.example.edu
# MY_RVRS=$(echo $MY_SRVR | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_SRVR})
# cat << END > $MY_MNT/syslinux.cfg
ui menu.c32
default $MY_NAME
timeout 100
menu title SYSLINUX
label $MY_NAME
    menu label ${MY_NAME^^}
    kernel ipxe.lkrn
    append dhcp && sanboot iscsi:$MY_SRVR:::1:iqn.$MY_RVRS:$MY_NAME
END
# cp /usr/share/syslinux/menu.c32 $MY_MNT
# cp /usr/share/syslinux/libutil.c32 $MY_MNT
# cp /tmp/ipxe.lkrn $MY_MNT
# umount ${MY_USB}1
```

通过简单地编辑 `syslinux.cfg` 文件，并添加附加的菜单项，你应该能够使用这同一个 USB 驱动器来网络启动附加的 ISCSI 目标。

这仅是加载 IPXE 的一种方法。你可以直接在你的工作站上安装 syslinux 。再一种选项是编译 iPXE 为一个 EFI 可执行文件，并直接放置它到你的 [ESP](https://en.wikipedia.org/wiki/EFI_system_partition) 中。又一种选项是编译 iPXE 为一个 PXE 加载器，并放置它到你的能够被 DHCP 引用的 TFTP 服务器。最佳的选项依赖于的环境

### 最后说明

* 如果你以 IPXE 的 EFI 格式编译 IPXE ，你可能想添加 `–filename \EFI\BOOT\grubx64.efi` 参数到 `sanboot` 命令。
* 能够创建自定义 live 镜像。更多信息参考[创建和使用 live CD](https://docs.fedoraproject.org/en-US/quick-docs/creating-and-using-a-live-installation-image/#proc_creating-and-using-live-cd)。
* 可以添加 `–overlay-size-mb` 和 `–home-size-mb` 参数到 `livecd-iso-to-disk` 命令来创建永久存储的 live 镜像。然而，如果你有多个并发用户，你将需要设置你的 ISCSI 服务器来管理独立的每个用户的可写覆盖。这与 “[如何构建一个网络启动服务器，部分 4](https://fedoramagazine.org/how-to-build-a-netboot-server-part-4/)” 一文所示类似。
* Live 镜像在它们的内核命令行中支持一个 `persistenthome` 选项（例如， `persistenthome=LABEL=HOME`）。与经过 CHAP 身份验证的 iSCSI 目标一起使用，对于中心控制主目录，`persistenthome` 选项为 NFS 提供一个有趣的替代方案。

---

via: <https://fedoramagazine.org/netboot-a-fedora-live-cd/>

作者：[Gregory Bartholomew](https://fedoramagazine.org/author/glb/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[robsean](https://github.com/robsean) 校对：[wxy](https://github.com/wxys)

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


Linux 如何设置密码复杂度？

# Linux 如何设置密码复杂度？

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

对于 Linux 系统管理员来说，用户管理是最重要的事之一。这涉及到很多因素，实现强密码策略是用户管理的其中一个方面。移步后面的 URL 查看如何 [在 Linux 上生成一个强密码](https://www.2daygeek.com/5-ways-to-generate-a-random-strong-password-in-linux-terminal/)。它会限制系统未授权的用户的访问。

所有人都知道 Linux 的默认策略很安全，然而我们还是要做一些微调，这样才更安全。弱密码有安全隐患，因此，请特别注意。移步后面的 URL 查看生成的强密码的[密码长度和分值](https://www.2daygeek.com/how-to-check-password-complexity-strength-and-score-in-linux/)。本文将教你在 Linux 中如何实现最安全的策略。

在大多数 Linux 系统中，我们可以用 PAM（<ruby> 可插拔认证模块 <rt>  pluggable authentication module </rt></ruby>）来加强密码策略。在下面的路径可以找到这个文件。

* 在红帽系列的系统中，路径：`/etc/pam.d/system-auth`。
* Debian 系列的系统中，路径：`/etc/pam.d/common-password`。

关于默认的密码过期时间，可以在 `/etc/login.defs` 文件中查看详细信息。

为了更好理解，我摘取了文件的部分内容：

```
# vi /etc/login.defs

PASS_MAX_DAYS   99999
PASS_MIN_DAYS   0
PASS_MIN_LEN    5
PASS_WARN_AGE   7
```

详细解释:

* `PASS_MAX_DAYS`：一个密码可使用的最大天数。
* `PASS_MIN_DAYS`：两次密码修改之间最小的间隔天数。
* `PASS_MIN_LEN`：密码最小长度。
* `PASS_WARN_AGE`：密码过期前给出警告的天数。

我们将会展示在 Linux 中如何实现下面的 11 个密码策略。

* 一个密码可使用的最大天数
* 两次密码修改之间最小的间隔天数
* 密码过期前给出警告的天数
* 密码历史记录/拒绝重复使用密码
* 密码最小长度
* 最少的大写字母个数
* 最少的小写字母个数
* 最少的数字个数
* 最少的其他字符（符号）个数
* 账号锁定 — 重试
* 账号解锁时间

### 密码可使用的最大天数是什么？

这一参数限制一个密码可使用的最大天数。它强制用户在过期前修改他/她的密码。如果他们忘记修改，那么他们会登录不了系统。他们需要联系管理员才能正常登录。这个参数可以在 `/etc/login.defs` 文件中设置。我把这个参数设置为 90 天。

```
# vi /etc/login.defs

PASS_MAX_DAYS   90
```

### 密码最小天数是什么？

这个参数限制两次修改之间的最少天数。举例来说，如果这个参数被设置为 15 天，用户今天修改了密码，那么在 15 天之内他都不能修改密码。这个参数可以在 `/etc/login.defs` 文件中设置。我设置为 15 天。

```
# vi /etc/login.defs

PASS_MIN_DAYS   15
```

### 密码警告天数是什么？

这个参数控制密码警告的前置天数，在密码即将过期时会给用户警告提示。在警告天数结束前，用户会收到日常警告提示。这可以提醒用户在密码过期前修改他们的密码，否则我们就需要联系管理员来解锁密码。这个参数可以在 `/etc/login.defs` 文件中设置。我设置为 10 天。

```
# vi /etc/login.defs

PASS_WARN_AGE   10
```

**注意:** 上面的所有参数仅对新账号有效，对已存在的账号无效。

### 密码历史或拒绝重复使用密码是什么？

这个参数控制密码历史。它记录曾经使用过的密码（禁止使用的曾用密码的个数）。当用户设置新的密码时，它会检查密码历史，如果他们要设置的密码是一个曾经使用过的旧密码，将会发出警告提示。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。我设置密码历史为 5。

```
# vi /etc/pam.d/system-auth

password  sufficient  pam_unix.so md5 shadow nullok try_first_pass use_authtok remember=5
```

### 密码最小长度是什么？

这个参数表示密码的最小长度。当用户设置新密码时，系统会检查这个参数，如果新设的密码长度小于这个参数设置的值，会收到警告提示。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。我设置最小密码长度为 12。

```
# vi /etc/pam.d/system-auth

password  requisite   pam_cracklib.so try_first_pass retry=3 minlen=12
```

`try_first_pass retry=3`：在密码设置交互界面，用户有 3 次机会重设密码。

### 设置最少的大写字母个数？

这个参数表示密码中至少需要的大写字母的个数。这些是密码强度参数，可以让密码更健壮。当用户设置新密码时，系统会检查这个参数，如果密码中没有大写字母，会收到警告提示。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。我设置密码（中的大写字母）的最小长度为 1 个字母。

```
# vi /etc/pam.d/system-auth

password   requisite   pam_cracklib.so try_first_pass retry=3 minlen=12 ucredit=-1
```

### 设置最少的小写字母个数？

这个参数表示密码中至少需要的小写字母的个数。这些是密码强度参数，可以让密码更健壮。当用户设置新密码时，系统会检查这个参数，如果密码中没有小写字母，会收到警告提示。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。我设置为 1 个字母。

```
# vi /etc/pam.d/system-auth

password    requisite     pam_cracklib.so try_first_pass retry=3 minlen=12 lcredit=-1
```

### 设置密码中最少的数字个数？

这个参数表示密码中至少需要的数字的个数。这些是密码强度参数，可以让密码更健壮。当用户设置新密码时，系统会检查这个参数，如果密码中没有数字，会收到警告提示。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。我设置为 1 个数字。

```
# vi /etc/pam.d/system-auth

password    requisite     pam_cracklib.so try_first_pass retry=3 minlen=12 dcredit=-1
```

### 设置密码中最少的其他字符（符号）个数？

这个参数表示密码中至少需要的特殊符号的个数。这些是密码强度参数，可以让密码更健壮。当用户设置新密码时，系统会检查这个参数，如果密码中没有特殊符号，会收到警告提示。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。我设置为 1 个字符。

```
# vi /etc/pam.d/system-auth

password    requisite     pam_cracklib.so try_first_pass retry=3 minlen=12 ocredit=-1
```

### 设置账号锁定？

这个参数控制用户连续登录失败的最大次数。当达到设定的连续失败登录次数阈值时，锁定账号。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。

```
# vi /etc/pam.d/system-auth

auth        required      pam_tally2.so onerr=fail audit silent deny=5
account required pam_tally2.so
```

### 设定账号解锁时间？

这个参数表示用户解锁时间。如果一个用户账号在连续认证失败后被锁定了，当过了设定的解锁时间后，才会解锁。设置被锁定中的账号的解锁时间（900 秒 = 15分钟）。这个参数可以在 `/etc/pam.d/system-auth` 文件中设置。

```
# vi /etc/pam.d/system-auth

auth        required      pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900
account required pam_tally2.so
```

---

via: <https://www.2daygeek.com/how-to-set-password-complexity-policy-on-linux/>

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

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


在 Linux 上安装安卓 8.1 Oreo 来运行应用程序和游戏

Summary: android x86 是一个自由而开源的项目，将谷歌制作的安卓系统从 ARM 架构移植到了 x86 架构，可以让用户在他们的桌面电脑上运行安卓系统来享受所有的安卓功能和应用程序及游戏。

[root@WinJay ~]# sudo qemu-system-x86_64 -m 2048 -boot d -enable-kvm -smp 3 -net nic -net user -hda android.img -cdrom /home/WinJay/android-x86_64-9.0-rc1.iso

sudo: qemu-system-x86_64：找不到命令

我安装倒是一切顺利，但wifi连不上网，而且用着卡卡的，实体机i9的cpu32g内存ssd分配了64g空间给安卓 8.1 Oreo，总体感觉比xDroid差了很多

搞上了，卡卡的准备试试xDroid

# 在 Linux 上安装安卓 8.1 Oreo 来运行应用程序和游戏

[android x86](http://www.android-x86.org/) 是一个自由而开源的项目，将谷歌制作的安卓系统从 ARM 架构移植到了 x86 架构，可以让用户在他们的桌面电脑上运行安卓系统来享受所有的安卓功能和应用程序及游戏。

在前一段时间，android x86 项目完成了安卓 8.1 Oreo 系统的 x86 架构移植。在这篇文章中，我们将解释如何在你的 Linux 系统上安装它，以便你能够随时使用你的安卓 用程序和游戏。

### 在 Linux 上安装安卓 x86 8.1 Oreo

#### 准备环境

首先，让我们下载 android x86 8.1 Oreo 系统镜像。你可以从[这个页面](http://www.android-x86.org/download)下载它，只需单击 “android-x86\_64-8.1-r1.iso” 文件下的 “View” 按钮。

我们将在我们的 Linux 系统上使用 QEMU 来运行 android x86。QEMU 是一个非常好的模拟器软件，它也是自由而开源的，并且在所有主要的 Linux 发行版存储库中都是可用的。

在 Ubuntu/Linux Mint/Debian 上安装 QEMU：

```
sudo apt-get install qemu qemu-kvm libvirt-bin
```

在 Fedora 上安装 QEMU：

```
sudo dnf install qemu qemu-kvm
```

对于其它发行版，只需要搜索 “qemu” 和 “qemu-kvm” 软件包，并安装它们。

在你安装 QEMU 后，我们将需要运行下面的命令来创建 `android.img` 文件，它就像某种分配给安卓系统的磁盘空间。所有安卓文件和系统都将位于该镜像文件中：

```
qemu-img create -f qcow2 android.img 15G
```

我们在这里的意思是，我们想为该安卓系统分配一个最大 15GB 的磁盘空间，但是，你可以更改它到你想要的任意大小（确保它至少大于 5GB）。

现在，首次启动运行该安卓系统，运行：

```
sudo qemu-system-x86_64 -m 2048 -boot d -enable-kvm -smp 3 -net nic -net user -hda android.img -cdrom /home/mhsabbagh/android-x86_64-8.1-r1.iso
```

将 `/home/mhsabbagh/android-x86_64-8.1-r1.iso` 替换为你从 android x86 网站下载的文件的路径。关于我们在这里正在使用的其它选项的解释，你可以参考[这篇文章](https://fosspost.org/tutorials/use-qemu-test-operating-systems-distributions)。

在你运行上面的命令后，该安卓系统将启动：

#### 安装系统

从这个窗口中，选择 “Advanced options”, 它将引导到下面的菜单，你应如下在其中选择 “Auto\_installation” ：

在这以后，安装器将告知你是否想要继续，选择 “Yes”：

接下来，安装器将无需你的指示而继续进行：

最后，你将收到这个信息，它表示你已经成功安装安卓 8.1 ：

现在，关闭 QEMU 窗口即可。

#### 启动和使用 安卓 8.1 Oreo

现在，安卓系统已经完全安装在你的 `android.img` 文件中，你应该使用下面的 QEMU 命令来启动它，而不是前面的命令：

```
sudo qemu-system-x86_64 -m 2048 -boot d -enable-kvm -smp 3 -net nic -net user -hda android.img
```

注意，我们所做的只是移除 `-cdrom` 选项及其参数。这是告诉 QEMU，我们不再想从我们下载的 ISO 文件启动，相反，从这个安装的安卓系统启动。

你现在能够看到安卓的启动菜单：

然后，你将进入第一个准备向导，选择你的语言并继续：

从这里，选择 “Set up as new” 选项：

然后，安卓将询问你是否想登录到你当前的谷歌账号。这步骤是可选的，但是这很重要，以便你随后可以使用谷歌 Play 商店：

然后，你将需要接受条款：

现在，你可以选择你当前的时区：

系统将询问你是否想启动一些数据收集功能。如果我是你的话，我将简单地全部关闭它们，像这样：

最后，你将有两种启动类型可供选择，我建议你选择 Launcher3 选项，并使其成为默认项：

然后，你将看到完整工作的安卓系统主屏幕：

从现在起，你可以做你想做的任何事情；你可以使用内置的安卓应用程序，或者你可以浏览你的系统设置来根据你的喜好进行调整。你可以更改你的系统的外观和体验，或者你可以像示例一样运行 Chrome ：

你可以开始从谷歌 Play 商店安装一些应用程序程序，像 WhatsApp 和其它的应用程序，以供你自己使用：

你现在可以用你的系统做任何你想做的事。恭喜！

### 以后如何轻松地运行安卓 8.1 Oreo

我们不想总是不得不打开终端窗口，并写那些长长的 QEMU 命令来运行安卓系统，相反，我们想在我们需要时一次单击就运行它。

为此，我们将使用下面的命令在 `/usr/share/applications` 下创建一个名为 `android.desktop` 的新文件：

```
sudo nano /usr/share/applications/android.desktop
```

并在其中粘贴下面的内容（右键单击然后粘贴）：

```
[Desktop Entry]
Name=Android 8.1
Comment=Run Android 8.1 Oreo on Linux using QEMU
Icon=phone
Exec=bash -c 'pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY qemu-system-x86_64 -m 2048 -boot d -enable-kvm -smp 3 -net nic -net user -hda /home/mhsabbagh/android.img'
Terminal=false
Type=Application
StartupNotify=true
Categories=GTK;
```

再强调一次，你必需使用你系统上的本地镜像路径来替换 `/home/mhsabbagh/android.img` 。然后保存文件（`Ctrl+X`，然后按 `Y`，然后按回车）。

注意，我们需要使用 `pkexec` 来使用 root 权限运行 QEMU ，因为从较新的版本开始，普通用户不允许通过 libvirt 访问 KVM 技术；这就是为什么它将每次要求你输入 root 密码的原因。

现在，你将在应用程序菜单中看到安卓图标，你可以在你想使用安卓的任何时间来简单地单击该图标，QEMU 程序将启动：

### 总结

我们向你展示如何在你的 Linux 系统上安装和运行安卓 8.1 Oreo 。从现在起，在没有其它一些软件的（像 Blutsticks 和类似的方法）的情况下，你可以更容易地完成基于安卓的任务。在这里，你有一个完整工作和功能的安卓系统，你可以随心所欲地操作它，如果一些东西出错，你可以简单地干掉该镜像文件，然后随时再一次重新运行安装程序。

你之前尝试过 android x86 吗？你的体验如何？

---

via: <https://fosspost.org/tutorials/install-android-8-1-oreo-on-linux>

作者：[M.Hanny Sabbagh](https://fosspost.org/author/mhsabbagh) 选题：[lujun9972](https://github.com/lujun9972) 译者：[robsean](https://github.com/robsean) 校对：[wxy](https://github.com/wxy)

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


使用 FVWM 自定义 Linux 桌面

# 使用 FVWM 自定义 Linux 桌面

>
> 本文是 24 天 Linux 桌面特别系列的一部分。如果你正在寻找轻巧、快速且简单的 Linux 窗口管理器，那么 FVWM 可以胜任。但是，如果你正在寻找可以深入、探索和魔改的窗口管理器，那么 FVWM 是必须的。
>
>
>

[FVWM](http://www.fvwm.org/) 窗口管理器最早脱胎于对 1993 年的 [TWM](https://en.wikipedia.org/wiki/Twm) 的修改。经过几年的迭代，诞生了一个可高度自定义的环境，它可以配置任何行为、动作或事件。它支持自定义键绑定、鼠标手势、主题、脚本等。

尽管 FVWM 在安装后即可投入使用，但默认分发版本仅提供了极其少的配置。这是开始自定义桌面环境的良好基础，但是，如果你只想将其用作桌面，那么可能要安装由其它用户发布的完整配置版本。FVWM 有几种不同的分发版，包括模仿 Windows 95 的 FVWM95（至少在外观和布局上）。我尝试了 [FVWM-Crystal](https://www.box-look.org/p/1018270/)，这是一个具有一些现代 Linux 桌面约定的现代主题。

可以从 Linux 发行版的软件仓库中安装要尝试的 FVWM 分发版。如果找不到特定的 FVWM 分发版，那么可以安装基础的 FVWM2 包，然后进入 [Box-Look.org](http://box-look.org) 手动下载主题包。这样就需要更多的工作，但比从头开始构建要少。

安装后，请注销当前的桌面会话，以便你可以登录 FVWM。默认情况下，会话管理器（KDM、GDM、LightDM 或 XDM，取决于你的设置）将继续登录到以前的桌面，因此你必须在登录之前覆盖该桌面。

对于 GDM：

对于 KDM：

### FVWM 桌面

无论你使用什么主题和配置，当你在桌面上单击鼠标左键时，FVWM 至少会显示一个菜单。菜单的内容取决于你所安装的内容。FVWM-Crystal 分发版中的菜单包含对常用首选项的快速访问，例如屏幕分辨率、壁纸设置、窗口装饰等。

同 FVWM 中的几乎所有东西一样，你可以编辑菜单中你要想的内容，但 FVWM-Crystal 的特色在于其应用菜单栏。应用菜单位于屏幕的左上角，每个图标都包含了相关的应用启动器的菜单。例如，GIMP 图标表示图像编辑器，KDevelop 图标表示集成开发环境（IDE），GNU 图标表示文本编辑器，等等，具体取决于你在系统上安装的程序。

FVWM-Crystal 还提供了虚拟桌面、任务栏、时钟和应用栏。

关于背景，你可以使用与 FVWM-Crystal 捆绑在一起的壁纸，也可以使用 `feh` 命令设置自己的壁纸（你可能需要从仓库中安装它）。此命令有一些设置背景的选项，包括 `--bg-scale` 使用你选择的图片缩放填充屏幕，`--bg-fill` 直接填充而不缩放图片，等等。

```
$ feh --bg-scale ~/Pictures/wallpapers/mybackground.jpg
```

大多数配置文件都包含在 `$HOME/.fvwm-crystal` 中，某些系统范围的默认文件位于 `/usr/share/fvwm-crystal`。

### 自己尝试一下

FVWM 是大多作为一个桌面构建平台，它也是窗口管理器。它不会为你做到面面俱到，它期望你来配置尽可能的一切。

如果你正在寻找轻巧、快速且简单的窗口管理器，那么 FVWM 可以胜任。但是，如果你正在寻找可以深入、探索和魔改的窗口管理器，那么 FVWM 是必须的。

---

via: <https://opensource.com/article/19/12/fvwm-linux-desktop>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[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 编程：循环

Summary: 本文是 Bash 编程系列三篇中的最后一篇，来学习使用循环执行迭代的操作。

本文是 Bash 编程系列三篇中的最后一篇，来学习使用循环执行迭代的操作。

# 怎样用 Bash 编程：循环

>
> 本文是 Bash 编程系列三篇中的最后一篇，来学习使用循环执行迭代的操作。
>
>
>

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

Bash 是一种强大的用于命令行和 shell 脚本的编程语言。本系列的三部分都是基于我的三集 [Linux 自学课程](http://www.both.org/?page_id=1183) 写的，探索怎么用 CLI 进行 bash 编程。

本系列的 [第一篇文章](/article-11552-1.html) 讨论了 bash 编程的一些简单命令行操作，如使用变量和控制操作符。[第二篇文章](/article-11687-1.html) 探讨了文件、字符串、数字等类型和各种各样在执行流中提供控制逻辑的的逻辑运算符，还有 bash 中不同种类的扩展。本文是第三篇（也是最后一篇），意在考察在各种迭代的操作中使用循环以及怎么合理控制循环。

### 循环

我使用过的所有编程语言都至少有两种循环结构来用来执行重复的操作。我经常使用 `for` 循环，然而我发现 `while` 和 `until` 循环也很有用处。

#### for 循环

我的理解是，在 bash 中实现的 `for` 命令比大部分语言灵活，因为它可以处理非数字的值；与之形成对比的是，诸如标准 C 语言的 `for` 循环只能处理数字类型的值。

Bash 版的 `for` 命令基本的结构很简单：

```
for Var in list1 ; do list2 ; done
```

解释一下：“对于 `list1` 中的每一个值，把 `$Var` 设置为那个值，使用该值执行 `list2` 中的程序语句；`list1` 中的值都执行完后，整个循环结束，退出循环。” `list1` 中的值可以是一个简单的显式字符串值，也可以是一个命令执行后的结果（`` 包含其内的命令执行的结果，本系列第二篇文章中有描述）。我经常使用这种结构。

要测试它，确认 `~/testdir` 仍然是当前的工作目录（PWD）。删除目录下所有东西，来看下这个显式写出值列表的 `for` 循环的简单的示例。这个列表混合了字母和数字 — 但是不要忘了，在 bash 中所有的变量都是字符串或者可以被当成字符串来处理。

```
[student@studentvm1 testdir]$ rm *
[student@studentvm1 testdir]$ for I in a b c d 1 2 3 4 ; do echo $I ; done
a
b
c
d
1
2
3
4
```

给变量赋予更有意义的名字，变成前面版本的进阶版：

```
[student@studentvm1 testdir]$ for Dept in "Human Resources" Sales Finance "Information Technology" Engineering Administration Research ; do echo "Department $Dept" ; done
Department Human Resources
Department Sales
Department Finance
Department Information Technology
Department Engineering
Department Administration
Department Research
```

创建几个目录（创建时显示一些处理信息）：

```
[student@studentvm1 testdir]$ for Dept in "Human Resources" Sales Finance "Information Technology" Engineering Administration Research ; do echo "Working on Department $Dept" ; mkdir "$Dept"  ; done
Working on Department Human Resources
Working on Department Sales
Working on Department Finance
Working on Department Information Technology
Working on Department Engineering
Working on Department Administration
Working on Department Research
[student@studentvm1 testdir]$ ll
total 28
drwxrwxr-x 2 student student 4096 Apr  8 15:45  Administration
drwxrwxr-x 2 student student 4096 Apr  8 15:45  Engineering
drwxrwxr-x 2 student student 4096 Apr  8 15:45  Finance
drwxrwxr-x 2 student student 4096 Apr  8 15:45 'Human Resources'
drwxrwxr-x 2 student student 4096 Apr  8 15:45 'Information Technology'
drwxrwxr-x 2 student student 4096 Apr  8 15:45  Research
drwxrwxr-x 2 student student 4096 Apr  8 15:45  Sales
```

在 `mkdir` 语句中 `$Dept` 变量必须用引号包裹起来；否则名字中间有空格（如 `Information Technology`）会被当做两个独立的目录处理。我一直信奉的一条实践规则：所有的文件和目录都应该为一个单词（中间没有空格）。虽然大部分现代的操作系统可以处理名字中间有空格的情况，但是系统管理员需要花费额外的精力去确保脚本和 CLI 程序能正确处理这些特例。（即使它们很烦人，也务必考虑它们，因为你永远不知道将拥有哪些文件。）

再次删除 `~/testdir` 下的所有东西 — 再运行一次下面的命令：

```
[student@studentvm1 testdir]$ rm -rf * ; ll
total 0
[student@studentvm1 testdir]$ for Dept in Human-Resources Sales Finance Information-Technology Engineering Administration Research ; do echo "Working on Department $Dept" ; mkdir "$Dept"  ; done
Working on Department Human-Resources
Working on Department Sales
Working on Department Finance
Working on Department Information-Technology
Working on Department Engineering
Working on Department Administration
Working on Department Research
[student@studentvm1 testdir]$ ll
total 28
drwxrwxr-x 2 student student 4096 Apr  8 15:52 Administration
drwxrwxr-x 2 student student 4096 Apr  8 15:52 Engineering
drwxrwxr-x 2 student student 4096 Apr  8 15:52 Finance
drwxrwxr-x 2 student student 4096 Apr  8 15:52 Human-Resources
drwxrwxr-x 2 student student 4096 Apr  8 15:52 Information-Technology
drwxrwxr-x 2 student student 4096 Apr  8 15:52 Research
drwxrwxr-x 2 student student 4096 Apr  8 15:52 Sales
```

假设现在有个需求，需要列出一台 Linux 机器上所有的 RPM 包并对每个包附上简短的描述。我为北卡罗来纳州工作的时候，曾经遇到过这种需求。由于当时开源尚未得到州政府的“批准”，而且我只在台式机上使用 Linux，对技术一窍不通的老板（PHB）需要我列出我计算机上安装的所有软件，以便他们可以“批准”一个特例。

你怎么实现它？有一种方法是，已知 `rpm –qa` 命令提供了 RPM 包的完整描述，包括了白痴老板想要的东西：软件名称和概要描述。

让我们一步步执行出最后的结果。首先，列出所有的 RPM 包：

```
[student@studentvm1 testdir]$ rpm -qa
perl-HTTP-Message-6.18-3.fc29.noarch
perl-IO-1.39-427.fc29.x86_64
perl-Math-Complex-1.59-429.fc29.noarch
lua-5.3.5-2.fc29.x86_64
java-11-openjdk-headless-11.0.ea.28-2.fc29.x86_64
util-linux-2.32.1-1.fc29.x86_64
libreport-fedora-2.9.7-1.fc29.x86_64
rpcbind-1.2.5-0.fc29.x86_64
libsss_sudo-2.0.0-5.fc29.x86_64
libfontenc-1.1.3-9.fc29.x86_64
<snip>
```

用 `sort` 和 `uniq` 命令对列表进行排序和打印去重后的结果（有些已安装的 RPM 包具有相同的名字）：

```
[student@studentvm1 testdir]$ rpm -qa | sort | uniq
a2ps-4.14-39.fc29.x86_64
aajohan-comfortaa-fonts-3.001-3.fc29.noarch
abattis-cantarell-fonts-0.111-1.fc29.noarch
abiword-3.0.2-13.fc29.x86_64
abrt-2.11.0-1.fc29.x86_64
abrt-addon-ccpp-2.11.0-1.fc29.x86_64
abrt-addon-coredump-helper-2.11.0-1.fc29.x86_64
abrt-addon-kerneloops-2.11.0-1.fc29.x86_64
abrt-addon-pstoreoops-2.11.0-1.fc29.x86_64
abrt-addon-vmcore-2.11.0-1.fc29.x86_64
<snip>
```

以上命令得到了想要的 RPM 列表，因此你可以把这个列表作为一个循环的输入信息，循环最终会打印每个 RPM 包的详细信息：

```
[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done
```

这段代码产出了多余的信息。当循环结束后，下一步就是提取出白痴老板需要的信息。因此，添加一个 `egrep` 命令用来搜索匹配 `^Name` 或 `^Summary` 的行。脱字符（`^`）表示行首，整个命令表示显示所有以 Name 或 Summary 开头的行。

```
[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary"
Name        : a2ps
Summary     : Converts text and other types of files to PostScript
Name        : aajohan-comfortaa-fonts
Summary     : Modern style true type font
Name        : abattis-cantarell-fonts
Summary     : Humanist sans serif font
Name        : abiword
Summary     : Word processing program
Name        : abrt
Summary     : Automatic bug detection and reporting tool
<snip>
```

在上面的命令中你可以试试用 `grep` 代替 `egrep` ，你会发现用 `grep` 不能得到正确的结果。你也可以通过管道把命令结果用 `less` 过滤器来查看。最终命令像这样：

```
[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary" > RPM-summary.txt
```

这个命令行程序用到了管道、重定向和 `for` 循环，这些全都在一行中。它把你的 CLI 程序的结果重定向到了一个文件，这个文件可以在邮件中使用或在其他地方作为输入使用。

这个一次一步构建程序的过程让你能看到每步的结果，以此来确保整个程序以你期望的流程进行且输出你想要的结果。

白痴老板最终收到了超过 1900 个不同的 RPM 包的清单，我严重怀疑根本就没人读过这个列表。我给了他们想要的东西，没有从他们嘴里听到过任何关于 RPM 包的信息。

### 其他循环

Bash 中还有两种其他类型的循环结构：`while` 和 `until` 结构，两者在语法和功能上都类似。这些循环结构的基础语法很简单：

```
while [ expression ] ; do list ; done
```

逻辑解释：表达式（`expression`）结果为 true 时，执行程序语句 `list`。表达式结果为 false 时，退出循环。

```
until [ expression ] ; do list ; done
```

逻辑解释：执行程序语句 `list`，直到表达式的结果为 true。当表达式结果为 true 时，退出循环。

#### While 循环

`while` 循环用于当逻辑表达式结果为 true 时执行一系列程序语句。假设你的 PWD 仍是 `~/testdir`。

最简单的 `while` 循环形式是这个会一直运行下去的循环。下面格式的条件语句永远以 `true` 作为返回。你也可以用简单的 `1` 代替 `true`，结果一样，但是这解释了 true 表达式的用法。

```
[student@studentvm1 testdir]$ X=0 ; while [ true ] ; do echo $X ; X=$((X+1)) ; done | head
0
1
2
3
4
5
6
7
8
9
[student@studentvm1 testdir]$
```

既然你已经学了 CLI 的各部分知识，那就让它变得更有用处。首先，为了防止变量 `$X` 在前面的程序或 CLI 命令执行后有遗留的值，设置 `$X` 的值为 0。然后，因为逻辑表达式 `[ true ]` 的结果永远是 1，即 true，在 `do` 和 `done` 中间的程序指令列表会一直执行 — 或者直到你按下 `Ctrl+C` 抑或发送一个 2 号信号给程序。那些程序指令是算数扩展，用来打印变量 `$X` 当前的值并加 1.

《[系统管理员的 Linux 哲学](https://www.apress.com/us/book/9781484237298)》的信条之一是追求优雅，实现优雅的一种方式就是简化。你可以用操作符 `++` 来简化这个程序。在第一个例子中，变量当前的值被打印出来，然后变量的值增加了。可以在变量后加一个 `++` 来表示这个逻辑：

```
[student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((X++)) ; done | head
0
1
2
3
4
5
6
7
8
9
```

现在删掉程序最后的 `| head` 再运行一次。

在下面这个版本中，变量在值被打印之前就自增了。这是通过在变量之前添加 `++` 操作符实现的。你能看出区别吗？

```
[student@studentvm1 ~]$ X=0 ; while [ true ] ; do echo $((++X)) ; done | head
1
2
3
4
5
6
7
8
9
```

你已经把打印变量的值和自增简化到了一条语句。类似 `++` 操作符，也有 `--` 操作符。

你需要一个在循环到某个特定数字时终止循环的方法。把 true 表达式换成一个数字比较表达式来实现它。这里有一个循环到 5 终止的程序。在下面的示例代码中，你可以看到 `-le` 是 “小于或等于” 的数字逻辑操作符。整个语句的意思：只要 `$X` 的值小于或等于 5，循环就一直运行。当 `$X` 增加到 6 时，循环终止。

```
[student@studentvm1 ~]$ X=0 ; while [ $X -le 5 ] ; do echo $((X++)) ; done
0
1
2
3
4
5
[student@studentvm1 ~]$
```

#### Until 循环

`until` 命令非常像 `while` 命令。不同之处是，它直到逻辑表达式的值是 `true` 之前，会一直循环。看一下这种结构最简单的格式：

```
[student@studentvm1 ~]$ X=0 ; until false  ; do echo $((X++)) ; done | head
0
1
2
3
4
5
6
7
8
9
[student@studentvm1 ~]$
```

它用一个逻辑比较表达式来计数到一个特定的值：

```
[student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ]  ; do echo $((X++)) ; done
0
1
2
3
4
[student@studentvm1 ~]$ X=0 ; until [ $X -eq 5 ]  ; do echo $((++X)) ; done
1
2
3
4
5
[student@studentvm1 ~]$
```

### 总结

本系列探讨了构建 Bash 命令行程序和 shell 脚本的很多强大的工具。但是这仅仅是你能用 Bash 做的很多有意思的事中的冰山一角，接下来就看你的了。

我发现学习 Bash 编程最好的方法就是实践。找一个需要多个 Bash 命令的简单项目然后写一个 CLI 程序。系统管理员们要做很多适合 CLI 编程的工作，因此我确信你很容易能找到自动化的任务。

很多年前，尽管我对其他的 Shell 语言和 Perl 很熟悉，但还是决定用 Bash 做所有系统管理员的自动化任务。我发现，有时稍微搜索一下，我可以用 Bash 实现我需要的所有事情。

---

via: <https://opensource.com/article/19/10/programming-bash-loops>

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

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


在 Fedora 中使用 Cockpit 创建虚拟机

# 在 Fedora 中使用 Cockpit 创建虚拟机

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

本文向你展示如何在 Fedora 31 上使用安装 Cockpit 所需软件来创建和管理虚拟机。Cockpit 是一个[交互式管理界面](https://cockpit-project.org/)，可让你在任何受支持的 Web 浏览器上访问和管理系统。随着 [virt-manager 逐渐被废弃](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/8.0_release_notes/rhel-8_0_0_release#virtualization_4)，鼓励用户使用 Cockpit 来替换它。

Cockpit 是一个正在活跃开发的项目，它有许多扩展其工作的插件。例如，其中一个是 “Machines”，它与 libvirtd 交互并允许用户创建和管理虚拟机。

### 安装软件

先决所需软件是 `libvirt`、`cockpit` 和 `cockpit-machines`。要将它们安装在 Fedora 31 上，请在终端[使用 sudo](https://fedoramagazine.org/howto-use-sudo/) 运行以下命令：

```
$ sudo dnf install libvirt cockpit cockpit-machines
```

Cockpit 也在 “Headless Management” 软件包组中。该软件组对于仅通过网络访问的基于 Fedora 的服务器很有用。在这里，请使用以下命令进行安装：

```
$ sudo dnf groupinstall "Headless Management"
```

### 设置 Cockpit 服务

安装了必要的软件包后，就该启用服务了。`libvirtd` 服务运行虚拟机，而 Cockpit 有一个激活的套接字服务，可让你访问 Web GUI：

```
$ sudo systemctl enable libvirtd --now
$ sudo systemctl enable cockpit.socket --now
```

这应该足以运行虚拟机并通过 Cockpit 对其进行管理。（可选）如果要从网络上的另一台设备访问并管理计算机，那么需要将该服务开放给网络。为此，请在防火墙配置中添加新规则：

```
$ sudo firewall-cmd --zone=public --add-service=cockpit --permanent
$ sudo firewall-cmd --reload
```

要确认服务正在运行并且没有发生任何问题，请检查服务的状态：

```
$ sudo systemctl status libvirtd
$ sudo systemctl status cockpit.socket
```

此时一切都应该正常工作。Cockpit Web GUI 应该可通过 <https://localhost:9090> 或 <https://127.0.0.1:9090> 访问。或者，在连接到同一网络的任何其他设备上的 Web 浏览器中输入本地网络 IP。（如果未设置 SSL 证书，那么可能需要允许来自浏览器的连接。）

### 创建和安装机器

使用系统的用户名和密码登录界面。你还可以选择是否允许在此会话中将密码用于管理任务。

选择 “Virtual Machines”，然后选择 “Create VM” 来创建一台新的虚拟机。控制台为你提供几个选项：

* 使用 Cockpit 的内置库下载操作系统
* 使用系统上已下载的安装媒体
* 指向系统安装树的 URL
* 通过 [PXE](https://en.wikipedia.org/wiki/Preboot_Execution_Environment) 协议通过网络引导媒体

输入所有必要的参数。然后选择 “Create” 启动新虚拟机。

此时，将出现一个图形控制台。大多数现代 Web 浏览器都允许你使用键盘和鼠标与 VM 控制台进行交互。现在，你可以完成安装并使用新的 VM，就像[过去通过 virt-manager](https://fedoramagazine.org/full-virtualization-system-on-fedora-workstation-30/) 一样。

*照片由 [Miguel Teixeira](https://flickr.com/photos/miguelteixeira/) 发布于 [Flickr](https://flickr.com/photos/miguelteixeira/2964851828/)（CC BY-SA 2.0）*

---

via: <https://fedoramagazine.org/create-virtual-machines-with-cockpit-in-fedora/>

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


使用 Java 持久化 API

Summary: 我们通过为自行车商店构建示例应用程序来学习如何使用 JPA。

我们通过为自行车商店构建示例应用程序来学习如何使用 JPA。

# 使用 Java 持久化 API

>
> 我们通过为自行车商店构建示例应用程序来学习如何使用 JPA。
>
>
>

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

对应用开发者来说，<ruby> Java 持久化 API <rt>  Java Persistence API </rt></ruby>（JPA）是一项重要的 java 功能，需要透彻理解。它为 Java 开发人员定义了如何将对象的方法调用转换为访问、持久化及管理存储在 NoSQL 和关系型数据库中的数据的方案。

本文通过构建自行车借贷服务的教程示例来详细研究 JPA。此示例会使用 Spring Boot 框架、MongoDB 数据库（[已经不开源](https://www.techrepublic.com/article/mongodb-ceo-tells-hard-truths-about-commercial-open-source/)）和 Maven 包管理来构建一个大型应用程序，并且构建一个创建、读取、更新和删除（CRUD）层。这儿我选择 NetBeans 11 作为我的 IDE。

此教程仅从开源的角度来介绍 Java 持久化 API 的工作原理，不涉及其作为工具的使用说明。这全是关于编写应用程序模式的学习，但对于理解具体的软件实现也很益处。可以从我的 [GitHub 仓库](https://github.com/StephonBrown/SpringMongoJava)来获取相关代码。

### Java: 不仅仅是“豆子”

Java 是一门面向对象的编程语言，自 1996 年发布第一版 Java 开发工具（JDK）起，已经变化了很多很多。要了解其各种发展及其虚拟机本身就是一堂历史课。简而言之，和 Linux 内核很相似，自发布以来，该语言已经向多个方向分支发展。有对社区免费的标准版本、有针对企业的企业版本及由多家供应商提供的开源替代品。主要版本每六个月发布一次，其功能往往差异很大，所以确认选用版本前得先做些研究。

总而言之，Java 的历史很悠久。本教程重点介绍 Java 11 的开源实现 [JDK 11](https://openjdk.java.net/projects/jdk/11/)。因其是仍然有效的长期支持版本之一。

* **Spring Boot** 是由 Pivotal 公司开发的大型 Spring 框架的一个模块。Spring 是 Java 开发中一个非常流行的框架。它支持各种框架和配置，也为 WEB 应用程序及安全提供了保障。Spring Boot 为快速构建各种类型的 Java 项目提供了基本的配置。本教程使用 Spring Boot 来快速编写控制台应用程序并针对数据库编写测试用例。
* **Maven** 是由 Apache 开发的项目/包管理工具。Maven 通过 `POM.xml` 文件来管理包及其依赖项。如果你使用过 NPM 的话，可能会非常熟悉包管理器的功能。此外 Maven 也用来进行项目构建及生成功能报告。
* **Lombok** 是一个库，它通过在对象文件里面添加注解来自动创建 getters/setters 方法。像 C# 这些语言已经实现了此功能，Lombok 只是把此功能引入 Java 语言而已。
* **NetBeans** 是一款很流行的开源 IDE，专门用于 Java 开发。它的许多工具都随着 Java SE 和 EE 的版本更新而更新。

我们会用这组工具为一个虚构自行车商店创建一个简单的应用程序。会实现对 `Customer` 和 `Bike` 对象集合的的插入操作。

### 酿造完美

导航到 [Spring Initializr](https://start.spring.io/) 页面。该网站可以生成基于 Spring Boot 和其依赖项的基本项目。选择以下选项：

1. **项目：** Maven 工程
2. **语言：** Java
3. **Spring Boot：** 2.1.8（或最稳定版本）
4. **项目元数据：** 无论你使用什么名字，其命名约定都是像 `com.stephb` 这样的。
	* 你可以保留 Artifact 名字为 “Demo”。
5. **依赖项：** 添加：
	* Spring Data MongoDB
	* Lombok

点击 **下载**，然后用你的 IDE（例如 NetBeans） 打开此新项目。

#### 模型层概要

在项目里面，<ruby> 模型 <rt>  model </rt></ruby>代表从数据库里取出的信息的具体对象。我们关注两个对象：`Customer` 和 `Bike`。首先，在 `src` 目录创建 `dto` 目录；然后，创建两个名为 `Customer.java` 和 `Bike.java` 的 Java 类对象文件。其结构如下示：

```
package com.stephb.JavaMongo.dto;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;

/**
 *
 * @author stephon
 */
@Getter @Setter
public class Customer {

        private @Id String id;
        private String emailAddress;
        private String firstName;
        private String lastName;
        private String address;

}
```

*Customer.Java*

```
package com.stephb.JavaMongo.dto;

import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;

/**
 *
 * @author stephon
 */
@Getter @Setter
public class Bike {
        private @Id String id;
        private String modelNumber;
        private String color;
        private String description;

        @Override
        public String toString() {
                return "This bike model is " + this.modelNumber + " is the color " + this.color + " and is " + description;
        }
}
```

*Bike.java*

如你所见，对象中使用 Lombok 注解来为定义的<ruby> 属性 <rt>  properties </rt></ruby>/<ruby> 特性 <rt>  attributes </rt></ruby>生成 getters/setters 方法。如果你不想对该类的所有特性都生成 getters/setters 方法，可以在属性上专门定义这些注解。这两个类会变成容器，里面携带有数据，无论在何处想显示信息都可以使用。

#### 配置数据库

我使用 [Mongo Docker](https://hub.docker.com/_/mongo) 容器来进行此次测试。如果你的系统上已经安装了 MongoDB，则不必运行 Docker 实例。你也可以登录其官网，选择系统信息，然后按照安装说明来安装 MongoDB。

安装后，就可以使用命令行、GUI（例如 MongoDB Compass）或用于连接数据源的 IDE 驱动程序来与新的 MongoDB 服务器进行交互。到目前为止，可以开始定义数据层了，用来拉取、转换和持久化数据。需要设置数据库访问属性，请导航到程序中的 `applications.properties` 文件，然后添加如下内容：

```
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=BikeStore
```

#### 定义数据访问对象/数据访问层

<ruby> 数据访问层 <rt>  data access layer </rt></ruby>（DAL）中的<ruby> 数据访问对象 <rt>  data access objects </rt></ruby>（DAO）定义了与数据库中的数据的交互过程。令人惊叹的就是在使用 `spring-boot-starter` 后，查询数据库的大部分工作已经完成。

让我们从 `Customer` DAO 开始。在 `src` 下的新目录 `dao` 中创建一个接口文件，然后再创建一个名为 `CustomerRepository.java` 的 Java 类文件，其内容如下示：

```
package com.stephb.JavaMongo.dao;

import com.stephb.JavaMongo.dto.Customer;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 *
 * @author stephon
 */
public interface CustomerRepository extends MongoRepository<Customer, String>{
        @Override
        public List<Customer> findAll();
        public List<Customer> findByFirstName(String firstName);
        public List<Customer> findByLastName(String lastName);
}
```

这个类是一个接口，扩展或继承于 `MongoRepository` 类，而 `MongoRepository` 类依赖于 DTO （`Customer.java`）和一个字符串，它们用来实现自定义函数查询功能。因为你已继承自此类，所以你可以访问许多方法函数，这些函数允许持久化和查询对象，而无需实现或引用自己定义的方法函数。例如，在实例化 `CustomerRepository` 对象后，你就可以直接使用 `Save` 函数。如果你需要扩展更多的功能，也可以重写这些函数。我创建了一些自定义查询来搜索我的集合，这些集合对象是我自定义的元素。

`Bike` 对象也有一个存储源负责与数据库交互。与 `CustomerRepository` 的实现非常类似。其实现如下所示：

```
package com.stephb.JavaMongo.dao;

import com.stephb.JavaMongo.dto.Bike;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 *
 * @author stephon
 */
public interface BikeRepository extends MongoRepository<Bike,String>{
        public Bike findByModelNumber(String modelNumber);
        @Override
        public List<Bike> findAll();
        public List<Bike> findByColor(String color);
}
```

#### 运行程序

现在，你已经有了一种结构化数据的方式，可以对数据进行提取、转换和持久化，然后运行这个程序。

找到 `Application.java` 文件（有可能不是此名称，具体取决于你的应用程序名称，但都会包含有 “application” ）。在定义此类的地方，在后面加上 `implements CommandLineRunner`。这将允许你实现 `run` 方法来创建命令行应用程序。重写 `CommandLineRunner` 接口提供的 `run` 方法，并包含如下内容用来测试 `BikeRepository` ：

```
package com.stephb.JavaMongo;

import com.stephb.JavaMongo.dao.BikeRepository;
import com.stephb.JavaMongo.dao.CustomerRepository;
import com.stephb.JavaMongo.dto.Bike;
import java.util.Scanner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JavaMongoApplication implements CommandLineRunner {
                @Autowired
                private BikeRepository bikeRepo;
                private CustomerRepository custRepo;

    public static void main(String[] args) {
                        SpringApplication.run(JavaMongoApplication.class, args);
    }
        @Override
        public void run(String... args) throws Exception {
                Scanner scan = new Scanner(System.in);
                String response = "";
                boolean running = true;
                while(running){
                        System.out.println("What would you like to create? \n C: The Customer \n B: Bike? \n X:Close");
                        response = scan.nextLine();
                        if ("B".equals(response.toUpperCase())) {
                                String[] bikeInformation = new String[3];
                                System.out.println("Enter the information for the Bike");
                                System.out.println("Model Number");
                                bikeInformation[0] = scan.nextLine();
                                System.out.println("Color");
                                bikeInformation[1] = scan.nextLine();
                                System.out.println("Description");
                                bikeInformation[2] = scan.nextLine();

                                Bike bike = new Bike();
                                bike.setModelNumber(bikeInformation[0]);
                                bike.setColor(bikeInformation[1]);
                                bike.setDescription(bikeInformation[2]);

                                bike = bikeRepo.save(bike);
                                System.out.println(bike.toString());

                        } else if ("X".equals(response.toUpperCase())) {
                                System.out.println("Bye");
                                running = false;
                        } else {
                                System.out.println("Sorry nothing else works right now!");
                        }
                }

        }
}
```

其中的 `@Autowired` 注解会自动依赖注入 `BikeRepository` 和 `CustomerRepository` Bean。我们将使用这些类来从数据库持久化和采集数据。

已经好了。你已经创建了一个命令行应用程序。该应用程序连接到数据库，并且能够以最少的代码执行 CRUD 操作

### 结论

从诸如对象和类之类的编程语言概念转换为用于在数据库中存储、检索或更改数据的调用对于构建应用程序至关重要。Java 持久化 API（JPA）正是为 Java 开发人员解决这一难题的重要工具。你正在使用 Java 操纵哪些数据库呢？请在评论中分享。

---

via: <https://opensource.com/article/19/10/using-java-persistence-api>

作者：[Stephon Brown](https://opensource.com/users/stephb) 选题：[lujun9972](https://github.com/lujun9972) 译者：[runningwater](https://github.com/runningwater) 校对：[wxy](https://github.com/wxy)

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


为什么 Python 代码要写得美观而明确

# 为什么 Python 代码要写得美观而明确

>
> 欢迎阅读“Python 光明节（Pythonukkah）”系列文章，这个系列文章将会讨论《Python 之禅》。我们首先来看《Python 之禅》里的前两个原则：美观与明确。
>
>
>

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

早在 1999 年，Python 的贡献者之一，Tim Peters 就提出了《[Python 之禅](https://www.python.org/dev/peps/pep-0020/)》，直到二十年后的今天，《Python 之禅》中的 19 条原则仍然对整个社区都产生着深远的影响。为此，就像庆典光明的<ruby> 光明节 <rt>  Hanukkah </rt></ruby>一样，我们举行了这一次的“<ruby> Python 光明节 <rt>  Pythonukkah </rt></ruby>”。首先，我们会讨论《Python 之禅》中的前两个原则：美观和明确。

>
> “Hanukkah is the Festival of Lights,
>
>
> Instead of one day of presents, we get eight crazy nights.”
>
>
> —亚当·桑德勒，[光明节之歌](https://en.wikipedia.org/wiki/The_Chanukah_Song)
>
>
>

### <ruby> 美观胜于丑陋 <rp>  （ </rp> <rt>  Beautiful is better than ugly </rt> <rp>  ） </rp></ruby>

著名的《[<ruby> 计算机程序的构造和解释 <rt>  Structure and Interpretation of Computer Programs </rt></ruby>](https://en.wikipedia.org/wiki/Structure_and_Interpretation_of_Computer_Programs)》中有这么一句话：<ruby> 代码是写给人看的，只是恰好能让机器运行。 <rt>  Programs must be written for people to read and only incidentally for machines to execute. </rt></ruby>机器并不在乎代码的美观性，但人类在乎。

阅读美观的代码对人们来说是一种享受，这就要求在整套代码中保持一致的风格。使用诸如 [Black](https://opensource.com/article/19/5/python-black)、[flake8](https://opensource.com/article/19/5/python-flake8)、[Pylint](https://opensource.com/article/19/10/python-pylint-introduction) 这一类工具能够有效地接近这一个目标。

但实际上，只有人类自己才知道什么才是真正的美观。因此，代码审查和协同开发是其中的不二法门，同时，在开发过程中倾听别人的意见也是必不可少的。

最后，个人的主观能动性也很重要，否则一切工具和流程都会变得毫无意义。只有意识到美观的重要性，才能主动编写出美观的代码。

这就是为什么美观在众多原则当中排到了首位，它让“美”成为了 Python 社区的一种价值。如果有人要问，”我们*真的*在乎美吗？“社区会以代码给出肯定的答案。

### <ruby> 明确胜于隐晦 <rp>  （ </rp> <rt>  Explicit is better than implicit </rt> <rp>  ） </rp></ruby>

人类会欢庆光明、惧怕黑暗，那是因为光能够让我们看到难以看清的事物。同样地，尽管有些时候我们会不自觉地把代码写得含糊不清，但明确地编写代码确实能够让我们理解很多抽象的概念。

“为什么类方法中要将 `self` 显式指定为第一个参数？”

这个问题已经是老生常谈了，但网络上很多流传已久的回答都是不准确的。在编写<ruby> 元类 <rt>  metaclass </rt></ruby>时，显式指定 `self` 参数就显得毫无意义。如果你没有编写过元类，希望你可以尝试一下，这是很多 Python 程序员的必经之路。

显式指定 `self` 参数的原因并不是 Python 的设计者不想将这样的元类视为“默认”元类，而是因为第一个参数必须是*显式*的。

即使 Python 中确实允许非显式的情况存在（例如上下文变量），但我们还是应该提出疑问：某个东西是不是有存在的必要呢？如果非显式地传递参数会不会出现问题呢？有些时候，由于种种原因，这是会有问题的。总之，在写代码时一旦能够优先考虑到明确性，至少意味着能对不明确的地方提出疑问并对结果作出有效的估计。

---

via: <https://opensource.com/article/19/12/zen-python-beauty-clarity>

作者：[Moshe Zadka](https://opensource.com/users/moshez) 选题：[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 MLVWM 打造复古苹果桌面

# 使用 Linux MLVWM 打造复古苹果桌面

>
> 本文是 24 天 Linux 桌面特别系列的一部分。如果老式的苹果电脑是用开源 POSIX 构建的呢？你可以通过构建 Macintosh 式的虚拟窗口管理器来实现。
>
>
>

想象一下穿越到另一段平行历史，Apple II GS 和 MacOS 7 是基于开源 [POSIX](https://opensource.com/article/19/7/what-posix-richard-stallman-explains) 构建的，它使用了与现代 Linux 相同的所有惯例，例如纯文本配置文件和模块化系统设计。这样的操作系统将为其用户带来什么？你可以使用 [Macintosh 式的虚拟窗口管理器（MLVWM）](http://www2u.biglobe.ne.jp/%7Ey-miyata/mlvwm.html)来回答这些问题（甚至更多！）。

### 安装 MLVWM

MLVWM 安装并不容易，并且可能不在你的发行版软件仓库中。如果你有时间理解翻译不佳的 README 文件，编辑一些配置文件，收集并调整一些旧的 .xpm 图片，编辑一两个 Xorg 选项，那么你就可以体验 MLVWM。不管怎么说，这是一个新奇的窗口管理器，其最新版本可以追溯到 2000 年。

要编译 MLVWM，你必须安装 imake，它提供了 `xmkmf` 命令。你可以从发行版的软件仓库中安装 imake，也可以直接从 [Freedesktop.org](http://cgit.freedesktop.org/xorg/util/imake) 获得。假设你已经有 `xmkmf` 命令，请进入包含 MLVWM 源码的目录，然后运行以下命令进行构建：

```
$ xmkmf -a
$ make
```

构建后，编译后的 `mlvwm` 二进制文件位于 `mlvwm` 目录中。将其移动到[你的 PATH](https://opensource.com/article/17/6/set-path-linux) 的任何位置：

```
$ mv mlvwm/mlvwm /usr/local/bin/
```

#### 编辑配置文件

现在已经安装好 MLVWM，但是如果不调整几个配置文件并仔细放好所需的图像文件，它将无法正确启动。示例配置文件位于你下载的源代码的 `sample_rc` 目录中。将文件 `Mlvwm-Netscape` 和 `Mlvwm-Xterm` 复制到你的主目录：

```
$ cp sample_rc/Mlvwm-{Netscape,Xterm} $HOME
```

将 `Mlvwmrc` 改名为 `$HOME/.mlvwmrc`（是的，即使示例文件的名称看似是大写字母，但你也必须使用小写的 “m”）：

```
$ cp sample_rc/Mlvwmrc $HOME/.mlvwmrc
```

打开 `.mlwmrc` 并找到第 54-55 行，它们定义了 MLVWM 在菜单和 UI 中使用的像素图的路径（`IconPath`）：

```
# Set icon search path. It needs before "Style".
IconPath /usr/local/include/X11/pixmaps:/home2/tak/bin/pixmap
```

调整路径以匹配你填充图像的路径（我建议使用 `$HOME/.local/share/pixmaps`）。MLVWM 不提供像素图，因此需要你提供构建桌面所需图标。

即使你有位于系统其他位置的像素图（例如 `/usr/share/pixmaps`），也要这样做，因为你需要调整像素图的大小，你可能也不想在系统范围内执行此操作。

```
# Set icon search path. It needs before "Style".
IconPath /home/seth/.local/share/pixmaps
```

#### 选择像素图

你已将 `.local/share/pixmaps` 目录定义为像素图源路径，但是该目录和图像均不存在。创建目录：

```
$ mkdir -p $HOME/.local/share/pixmaps
```

现在，配置文件将图像分配给菜单项和 UI 元素，但是系统中不存在这些图像。要解决此问题，请通读配置文件并找到每个 .xpm 图像。对于配置中列出的每个图像，将具有相同文件名的图像（或更改配置文件中的文件名）添加到你的 IconPath 目录。

`.mlvwmrc` 文件的注释很好，因此你可以大致了解要编辑的内容。无论如何，这只是第一步。你可以随时回来更改桌面外观。

这有些例子。

此代码块设置屏幕左上角的图标：

```
# Register the menu
Menu Apple, Icon label1.xpm, Stick
```

`label1.xpm` 图像实际上在源代码的 `pixmap` 目录中，但我更喜欢使用来自 `/usr/share/pixmaps` 的 `Penguin.xpm`（在 Slackware 上）。无论使用什么，都必须将自定义像素图放在 `~/.local/share/pixmaps` 中，并在配置中更改像素图的名称，或者重命名像素图以匹配配置文件中当前的名称。

此代码块定义了左侧菜单中列出的应用：

```
"About this Workstation..." NonSelect, Gray, Action About
"" NonSelect
"Terminal"      Icon mini-display.xpm, Action Exec "kterm" exec kterm -ls
"Editor"  Action Exec "mule" exec mule, Icon mini-edit.xpm
"calculator" Action Exec "xcal" exec xcalc, Icon mini-calc.xpm
END
```

通过遵循与配置文件中相同的语法，你可以自定义像素图并将自己的应用添加到菜单中（例如，我将 `mule` 更改为 `emacs`）。这是你在 MLVWM GUI 中打开应用的入口，因此请列出你要快速访问的所有内容。你可能还希望包括指向 `/usr/share/applications` 文件夹的快捷方式。

```
"Applications" Icon Penguin.xpm, Action Exec "thunar /usr/share/applications" exec thunar /usr/share/applications
```

完成编辑配置文件并将自己的图像添加到 IconPath 目录后，必须将所有像素图的大小都调整为大约 16x16 像素。（MLVWM 的默认设置不一致，因此存在变化空间。）你可以使用 ImageMagick 进行批量操作：

```
$ for i in ~/.local/share/mlvwm-pixmaps/*xpm ; do convert -resize '16x16^' $i; done
```

### 启动 MLVWM

最简单的运行 MLVWM 的方式是让 Xorg 完成大部分工作。首先，你必须创建一个 `$HOME/.xinitrc` 文件。我从 Slackware 复制了这个，它也是从 Xorg 拿来的：

```
#!/bin/sh
# $XConsortium: xinitrc.cpp,v 1.4 91/08/22 11:41:34 rws Exp $

userresources=$HOME/.Xresources
usermodmap=$HOME/.Xmodmap
sysresources=/etc/X11/xinit/.Xresources
sysmodmap=/etc/X11/xinit/.Xmodmap

# merge in defaults and keymaps

if [ -f $sysresources ]; then
    xrdb -merge $sysresources
fi

if [ -f $sysmodmap ]; then
    xmodmap $sysmodmap
fi

if [ -f $userresources ]; then
    xrdb -merge $userresources
fi

if [ -f $usermodmap ]; then
    xmodmap $usermodmap
fi

# Start the window manager:
if [ -z "$DESKTOP_SESSION" -a -x /usr/bin/ck-launch-session ]; then
  exec ck-launch-session /usr/local/bin/mlvwm
else
  exec /usr/local/bin/mlvwm
fi
```

根据此文件，`startx` 命令的默认操作是启动 MLVWM。但是，你的发行版可能对于图形服务器启动（或被终止以重新启动）时会发生的情况有其他做法，因此此文件可能对你没有什么帮助。在许多发行版上，你可以添加 .desktop 文件到 `/usr/share/xsessions` 中，以将其列在 GDM 或 KDM 菜单中，因此创建名为 `mlvwm.desktop` 的文件并输入：

```
[Desktop Entry]
Name=Mlvwm
Comment=Macintosh-like virtual window manager
Exec=/usr/local/bin/mlvwm
TryExec=ck-launch-session /usr/local/bin/mlvwm
Type=Application
```

从桌面会话注销并重新登录到 MLVWM。默认情况下，会话管理器（KDM、GDM 或 LightDM，具体取决于你的设置）将继续登录到以前的桌面，因此在登录之前必须覆盖它。

对于 GDM：

对于 SDDM：

#### 强制启动

如果 MLVWM 无法启动，请尝试安装 XDM，这是一个轻量级会话管理器，它不会查询 `/usr/share/xsessions` 的内容，而是执行经过身份验证用户的所有 `.xinitrc` 操作。

### 打造自己的复古苹果

MLVWM 桌面未经打磨、不完美、模仿到位且充满乐趣。你看到的许多菜单项都是未实现的，但你可以使它们变得活跃且有意义。

这是一次让你时光倒流、改变历史，让老式苹果系列电脑成为开源堡垒的机会。成为一名修正主义者，设计你自己的复古苹果桌面，最重要的是，它有乐趣。

---

via: <https://opensource.com/article/19/12/linux-mlvwm-desktop>

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


网络广告商的像素追踪是如何工作的？

Summary: 我终于弄明白像素追踪（tracking pixels）在实际中是如何工作的了。

我终于弄明白像素追踪（tracking pixels）在实际中是如何工作的了。

# 网络广告商的像素追踪是如何工作的？

昨天，我和一名记者谈到了一个问题：广告商是如何在互联网上对人们进行追踪的？我们津津有味地查看了 Firefox 的开发者工具（虽然我不是一个互联网隐私专家，但至少还会使用开发者工具中的“network”标签页），从中我终于弄明白<ruby> 像素追踪 <rt>  tracking pixels </rt></ruby>在实际中是如何工作的了。

### 问题：Facebook 怎么知道你逛了 Old Navy？

我时常听人们说起这种有些诡异的上网经历：你在线上浏览了一个商品，一天之后，竟然看到了同一款靴子（或者是别的什么你当时浏览的商品）的广告。这就是所谓的“再营销”，但它到底是如何实现的呢？

在本文中，我们来进行一个小实验，看看 Facebook 究竟是怎么知道你在线上浏览了什么商品的。这里使用 Facebook 作为示例，只是因为很容易找到使用了 Facebook 像素追踪技术的网站；其实，几乎所有互联网广告公司都会使用类似的追踪技术。

### 准备：允许第三方追踪器，同时关闭广告拦截器

我使用的浏览器是 Firefox，但是 Firefox 默认拦截了很多这种类型的追踪，所以需要修改 Firefox 的隐私设置，才能让这种追踪生效。

首先，我将隐私设置从默认设置（[截图](https://jvns.ca/images/trackers.png)）修改为允许第三方追踪器的个性化设置（[截图](https://jvns.ca/images/firefox-insecure-settings.png)），然后禁用了一些平时运行的隐私保护扩展。

### 像素追踪：关键不在于 gif，而在于请求参数

像素追踪是网站用来追踪你的一个 1x1 大小的 gif。就其本身而言，一个小小的 1x1 gif 显然起不到什么作用。那么，像素追踪到底是如何进行追踪的？其中涉及两个方面：

1. 通过使用像素追踪上的**请求参数**，网站可以添加额外的信息，比如你正在访问的页面。这样一来，请求的就不是 `https://www.facebook.com/tr/`（这个链接是一个 44 字节大小的 1x1 gif），而是 `https://www.facebook.com/tr/?the_website_you're_on`。（邮件营销人员会使用类似的技巧，通过为像素追踪指定一个独特的 URL，弄清楚你是否打开了某一封邮件。）
2. 在发送该请求的同时，还发送了相应的 cookie。这样一来广告商就可以知道，访问 oldnavy.com 的这个人和在同一台电脑上使用 Facebook 的是同一个人。

### Old Navy 网站上的 Facebook 像素追踪

为了对此进行验证，我在 Old Navy（GAP 旗下的一个服装品牌）网站上浏览了一个商品，相应的 URL 是 `https://oldnavy.gap.com/browse/product.do?pid=504753002&cid=1125694&pcid=1135640&vid=1&grid=pds_0_109_1`（这是一件“男款短绒格子花呢大衣”）。

在我浏览这个商品的同时，页面上运行的 Javascript（用的应该是[这段代码](https://developers.facebook.com/docs/facebook-pixel/implementation/)）向 facebook.com 发送了一个请求。在开发者工具中，该请求看上去是这样的：（我屏蔽了大部分 cookie 值，因为其中有一些是我的登录 cookie）

下面对其进行拆解分析：

1. 我的浏览器向如下 URL 发送了一个请求；

```
https://www.facebook.com/tr/?id=937725046402747&ev=PageView&dl=https%3A%2F%2Foldnavy.gap.com%2Fbrowse%2Fproduct.do%3Fpid%3D504753002%26cid%3D1125694%26pcid%3Dxxxxxx0%26vid%3D1%26grid%3Dpds_0_109_1%23pdp-page-content&rl=https%3A%2F%2Foldnavy.gap.com%2Fbrowse%2Fcategory.do%3Fcid%3D1135640%26mlink%3D5155%2Cm_mts_a&if=false&ts=1576684838096&sw=1920&sh=1080&v=2.9.15&r=stable&a=tmtealium&ec=0&o=30&fbp=fb.1.1576684798512.1946041422&it=15xxxxxxxxxx4&coo=false&rqm=GET
```
2. 与该请求同时发送的，还有一个名为 `fr` 的 cookie，取值为

```
10oGXEcKfGekg67iy.AWVdJq5MG3VLYaNjz4MTNRaU1zg.Bd-kxt.KU.F36.0.0.Bd-kx6.
```

（估计是我的 Facebook 广告追踪 ID）

在所发送的像素追踪查询字符串里，有三个值得注意的地方：

* 我当前访问的页面：`https://oldnavy.gap.com/browse/product.do?pid=504753002&cid=1125694&pcid=1135640&vid=1&grid=pds_0_109_1#pdp-page-content`
* 引导我来到当前页面的上一级页面：`https://oldnavy.gap.com/browse/category.do?cid=1135640&mlink=5155,m_mts_a`；
* 作为我的身份标识的 cookie：`10oGXEcKfGekg67iy.AWVdJq5MG3VLYaNjz4MTNRaU1zg.Bd-kxt.KU.F36.0.0.Bd-kx6.`

### 下面来逛逛 Facebook！

下面来逛逛 Facebook 吧。我之前已经登入了 Facebook，猜猜看，我的浏览器发送给 Facebook 的 cookie 是什么？

不出所料，正是之前见过的 `fr` cookie：`10oGXEcKfGekg67iy.AWVdJq5MG3VLYaNjz4MTNRaU1zg.Bd-kxt.KU.F36.0.0.Bd-kx6.`。Facebook 现在一定知道我（Julia Evans，这个 Facebook 账号所关联的人）在几分钟之前访问了 Old Navy 网站，并且浏览了“男款短绒格子花呢大衣”，因为他们可以使用这个 cookie 将数据串联起来。

### 这里涉及到的是第三方 cookie

Facebook 用来追踪我访问了哪些网站的 cookie，属于所谓的“第三方 cookie”，因为 Old Navy 的网站使用它为一个第三方（即 facebook.com）确认我的身份。这和用来维持登录状态的“第一方 cookie”有所不同。

Safari 和 Firefox 默认都会拦截许多第三方 cookie（所以需要更改 Firefox 的隐私设置，才能够进行这个实验），而 Chrome 目前并不进行拦截（很可能是因为 Chrome 的所有者正是一个广告公司）。（LCTT 译注：Chrome 可以设置阻拦）

### 网站上的像素追踪有很多

如我所料，网站上的像素追踪有 **很多**。比如，wrangler.com 在我的浏览器里加载了来自不同域的 19 个不同的像素追踪。wrangler.com 上的像素追踪分别来自：`ct.pinterest.com`、`af.monetate.net`、`csm.va.us.criteo.net`、`google-analytics.com`、`dpm.demdex.net`、`google.ca`、`a.tribalfusion.com`、`data.photorank.me`、`stats.g.doubleclick.net`、`vfcorp.dl.sc.omtrdc.net`、`ib.adnxs.com`、`idsync.rlcdn.com`、`p.brsrvr.com`，以及 `adservice.google.com`。

Firefox 贴心地指出，如果使用 Firefox 的标准隐私设置，其中的大部分追踪器都会被拦截：

### 浏览器的重要性

浏览器之所以如此重要，是因为你的浏览器最终决定了发送你的什么信息、发送到哪些网站。Old Navy 网站上的 Javascript 可以请求你的浏览器向 Facebook 发送关于你的追踪信息，但浏览器可以拒绝执行。浏览器的决定可以是：“哈，我知道 facebook.com/tr/ 是一个像素追踪，我不想让我的用户被追踪，所以我不会发送这个请求”。

浏览器还可以允许用户对上述行为进行配置，方法包括更改浏览器设置，以及安装浏览器扩展（所以才会有如此多的隐私保护扩展）。

### 摸清其中原理，实为一件趣事

在我看来，弄清楚 cookie/像素追踪是怎么用于对你进行追踪的，实在是一件趣事（尽管有点吓人）。我之前大概明白其中的道理，但是并没有亲自查看过像素追踪上的 cookie，也没有看过发送的查询参数上究竟包含什么样的信息。

当然，明白了其中的原理，也就更容易降低被追踪的概率了。

### 可以采取的措施

为了尽量避免在互联网上被追踪，我采取了几种简单的措施:

* 安装一个广告拦截器（比如 ublock origin 之类）。广告拦截器可以针对许多追踪器的域进行拦截。
* 使用目前默认隐私保护强度更高的 Firefox/Safari，而不是 Chrome。
* 使用 [Facebook Container](https://addons.mozilla.org/en-CA/firefox/addon/facebook-container/) 这个 Firefox 扩展。该扩展针对 Facebook 进一步采取了防止追踪的措施。

虽然在互联网上被追踪的方式还有很多（尤其是在使用手机应用的时候，因为在这种情况下，你没有和像对浏览器一样的控制程度），但是能够理解这种追踪方法的工作原理，稍微减少一些被追踪的可能性，也总归是一件好事。

---

via: <https://jvns.ca/blog/how-tracking-pixels-work/>

作者：[Julia Evans](https://jvns.ca/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[chen-ni](https://github.com/chen-ni) 校对：[wxy](https://github.com/wxy)

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


如何在 Ubuntu 和其他 Linux 发行版中启动、停止和重启服务

Summary: 服务是必不可少的后台进程，它通常随系统启动，并在关机时关闭。

服务是必不可少的后台进程，它通常随系统启动，并在关机时关闭。

# 如何在 Ubuntu 和其他 Linux 发行版中启动、停止和重启服务

服务是必不可少的后台进程，它通常随系统启动，并在关机时关闭。如果你是系统管理员，那么你会定期处理服务。如果你是普通桌面用户，你可能会遇到需要重启服务的情况，例如[安装 Barrier 来用于在计算机之间共享鼠标和键盘](https://itsfoss.com/keyboard-mouse-sharing-between-computers/)。或[在使用 ufw 设置防火墙](https://itsfoss.com/set-up-firewall-gufw/)时。

今天，我将向你展示两种管理服务的方式。你将学习在 Ubuntu 或任何其他 Linux 发行版中启动、停止和重启服务。

>
> systemd 与 init
>
>
> 如今，Ubuntu 和许多其他发行版都使用 systemd 而不是旧的 init。
>
>
> 在 systemd 中，可以使用 `systemctl` 命令管理服务。
>
>
> 在 init 中，你可以使用 `service` 命令管理服务。
>
>
> 你会注意到，即使你的 Linux 系统使用 systemd，它仍然可以使用 `service` 命令（与 init 系统一起使用的）。这是因为 `service` 命令实际上已重定向到 `systemctl`。systemd 引入了向后兼容性，因为系统管理员们习惯使用 `service` 命令。
>
>
> 在本教程中，我将同时展示 `systemctl` 和 `service` 命令。
>
>
>

我用的是 Ubuntu 18.04，但其他版本的过程也一样。

### 方法 1：使用 systemd 在 Linux 中管理服务

我从 systemd 开始，因为它被广泛接受。

#### 1、列出所有服务

为了管理服务，你首先需要知道系统上有哪些服务可用。你可以使用 systemd 的命令列出 Linux 系统上的所有服务：

```
systemctl list-unit-files --type service -all
```

此命令将输出所有服务的状态。服务状态有<ruby> 启用 <rt>  enabled </rt></ruby>、<ruby> 禁用 <rt>  disabled </rt></ruby>、<ruby> 屏蔽 <rt>  masked </rt></ruby>（在取消屏蔽之前处于非活动状态）、<ruby> 静态 <rt>  static </rt></ruby>和<ruby> 已生成 <rt>  generated </rt></ruby>。

与 [grep 命令](https://linuxhandbook.com/grep-command-examples/) 结合，你可以仅显示正在运行的服务：

```
sudo systemctl | grep running
```

现在，你知道了如何引用所有不同的服务，你可以开始主动管理它们。

**注意：** 下列命令中的 `<service-name>` 应该用你想管理的服务名代替。（比如：network-manager、ufw 等）

#### 2、启动服务

要在 Linux 中启动服务，你只需使用它的名字：

```
systemctl start <service-name>
```

#### 3、停止服务

要停止 systemd 服务，可以使用 `systemctl` 命令的 `stop` 选项：

```
systemctl stop <service-name>
```

#### 4、重启服务

要重启 systemd 服务，可以使用：

```
systemctl restart <service-name>
```

#### 5、检查服务状态

你可以通过打印服务状态来确认你已经成功执行特定操作：

```
systemctl status <service-name>
```

这将以以下方式输出：

这是 systemd 的内容。现在切换到 init。

### 方法 2：使用 init 在 Linux 中管理服务

init 的命令和 systemd 的一样简单。

#### 1、列出所有服务

要列出所有 Linux 服务，使用：

```
service --status-all
```

前面的 `[ – ]` 代表**禁用**，`[ + ]` 代表**启用**。

#### 2、启动服务

要在 Ubuntu 和其他发行版中启动服务，使用命令：

```
service <service-name> start
```

#### 3、停止服务

停止服务同样简单。

```
service <service-name> stop
```

#### 4、重启服务

如果你想重启服务，命令是：

```
service <service-name> restart
```

#### 5、检查服务状态

此外，要检查是否达到了预期的结果，你可以输出服务状态：

```
service <service-name> status
```

这将以以下方式输出：

最重要的是，这将告诉你某项服务是否处于活跃状态（正在运行）。

### 总结

今天，我详细介绍了两种在 Ubuntu 或任何其他 Linux 系统上管理服务的非常简单的方法。 希望本文对你有所帮助。

你更喜欢哪种方法？ 让我在下面的评论中知道！

---

via: <https://itsfoss.com/start-stop-restart-services-linux/>

作者：[Sergiu](https://itsfoss.com/author/sergiu/) 选题：[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/) 荣誉推出


Unix 即将迎来 50 岁

# Unix 即将迎来 50 岁

Unix 时间（又称为“<ruby> 纪元时间 <rt>  epoch time </rt></ruby>”）是自 1970 年 1 月 1 日以来经过的秒数。当 Unix 即将 50 岁时，让我们看一下让内核开发人员担心的地方。

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

对于 Unix 而言，2020 年是重要的一年。在这一年年初，Unix 进入 50 岁。

尽管 Unix 的某些早期开发早于其“纪元”的正式开始，但 1970 年 1 月 1 日仍然是 POSIX 时间的零点，也是公认的 Unix 的万物之始。自那一刻算起，2020 年 1 月 1 日将是其 50 周年。（LCTT 译注：实际上，在 1971/11/3 出版的第一版《Unix 程序员手册》中，将 1971/1/1 作为 Unix 纪元的开始，并且一秒钟记录 60 个数，但是后来发现这样 32 位整型数字只能记录两年多，后来这个纪元被一再重新定义，改为从 1970/1/1 开始，每秒 1 个数。）

### Unix 时间与人类时间

就人类时间而言，50 年是很重要的。就 Unix 时间而言，50 年没有什么特别的。48.7 年同样重要。

Unix（包括 Linux）系统将日期/时间值存储为自 1970-01-01 00:00:00 UTC 以来经过的秒数（32 位整型）。要确定自该时间以来经过了多少秒钟，看看 Unix 时间值是什么样子，你可以发出如下命令：

```
$ date +%s
1576883876
```

`％s` 参数告诉 `date` 命令将当前日期/时间显示为自 1970-01-01 开始以来的秒数。

### Unix 系统可以管理多少时间？

要了解 Unix 系统可以容纳多少时间，我们需要查看 32 位字段的容量。可以这样计算：

```
$ echo '2^32' | bc
4294967296
```

但是，由于 Unix 需要容纳负数，因此它会为数字的符号保留一位，从而将其减少为：

```
$ echo '2^31' | bc
2147483648
```

并且，由于 Unix 计数以 0 开头，这意味着我们有 2,147,483,648 个值，但最大的可能值为 2,147,483,647 个。Unix 日期/时间值不能超过该数字——就像汽车上的里程表可能不能超过 999,999 英里一样。加 1 该值就变为了 -2147483648。（LCTT 译注：此处原文描述有误，已修改。在达到最大值之后，即 2038/1/19 03:14:07，下 1 秒导致符号位变为 1，其余 31 位为 0，即 -2147483648，时间变为 1901/12/13 20:45:52，这就是 Y2K38 问题。）

### 一年有多少秒？

大多数年份的秒数可以这样计算：每天的小时数乘以每小时的分钟数乘以每分钟的秒数乘以一年中的天数：

```
$ expr 24 \* 60 \* 60 \* 365
31536000
```

在闰年，我们再增加一天：

```
$ expr 24 \* 60 \* 60 \* 366
31622400
```

（LCTT 译注：Unix 时间将一天精确定义为 24 \* 60 \* 60 = 86400 秒，忽略闰秒。）

### Unix 将如何庆祝其 50 岁生日？

2020 年 1 月 1 日中午 12:00 是纪元时间的 1577836800。这个计算有些棘手，但主要是因为我们必须适应闰年。自该纪元开始以来，我们经历了 12 个闰年，从 1972 年开始，到上一个闰年是 2016 年。而且，当我们达到 2020 年时，我们将有 38 个常规年份。

这是使用 `expr` 命令进行的计算，以计算这 50 年的秒数：

```
$ expr 24 \* 60 \* 60 \* 365 \* 38 + 24 \* 60 \* 60 \* 366 \* 12
1577836800
```

前半部分是计算 38 个非闰年的秒数。然后，我们加上闰年的 366 天的类似计算。或者，你可以使用前面介绍的每年秒数，然后执行以下操作：

```
$ expr 31536000 \* 38 + 31622400 \* 12
1577836800
```

这种跟踪日期和时间的方式使 Unix 系统完全不受 Y2K 恐慌的影响，1999 年末人们开始担心进入 2000 年会对计算机系统造成严重破坏，但是实际遇到的问题比人们担心的少得多。实际上，只有以两位数格式存储年份的应用程序才会将年份变为 00，以表示时间倒退。尽管如此，许多应用程序开发人员还是做了很多额外的繁琐工作，以确保 2000 年到来时，他们的系统不会出现严重问题。

### Unix 时间何时会遇到问题？

在 2038 年之前，Unix 系统不会遇到 Y2K 类型的问题，直到如上所述存储的日期将超过其 32 位空间分配。但这距离现在已经只有 18 年了，内核开发人员已经在研究如何避免灾难。但现在开始恐慌还为时过早。

2038 年的问题有时称为 Y2K38 问题。我们必须在 2038 年 1 月 19 日星期二之前解决这个问题。如果问题到时候仍未解决，则该日期之后的系统可能会认为是 1901 年。解决该问题的一种方法是切换为日期/时间信息的 64 位表示形式。有些人认为，即使那样，也会有比听起来更复杂的问题。无论如何，恐慌还为时过早。并且，与此同时，也许在新年前夜演唱了《Auld Lang Syne》之后，你可以向 Unix 唱《生日快乐》歌了。Unix 50 岁了，这仍然是大事。

（LCTT 译注：建议阅读一下 Unix 时间的[维基百科](https://en.wikipedia.org/wiki/Unix_time)页面，有更多有趣和不为人知的信息。）

---

via: <https://www.networkworld.com/article/3511428/unix-is-turning-50-what-does-that-mean.html>

作者：[Sandra Henry-Stocker](https://www.networkworld.com/author/Sandra-Henry_Stocker/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


内向者的 DevOps

# 内向者的 DevOps

>
> 我们邀请 Opensource.com 的 DevOps 团队，希望他们能够谈一谈作为 DevOps 内向者的休验，同时给 DevOps 外向者一些建议。下面是他们的回答。
>
>
>

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

我们邀请我们的 [DevOps 团队](https://opensource.com/devops-team) 谈一谈他们作为一个内向者的体验，并给外向者们一些建议。但是在我们开始了解他们的回答之前，让我们先来定义一下这些词汇。

### “内向者”是什么意思？

内向者通常指的是一部分人群，当他们和别人相处的时候，会使他们的能量耗尽，而不是激发他们更多的能量。当我们思考我们是如何恢复能量时，这是一个非常有用的词汇：内向者通常需要更多的独处时间来恢复能量，特别是和一群人在一起很长时间后。关于内向者的一个非常大的误解就是他们一定是“害羞的”，但是科学表明，那不过是另一种不同的性格特征。

内向性与外向性是通过 [Myers Briggs 类型指标](https://www.myersbriggs.org/my-mbti-personality-type/mbti-basics/extraversion-or-introversion.htm?bhcp=1) 而为人所知的，现在也常常被称作一个 [光谱](https://lifehacker.com/lets-quit-it-with-the-introvert-extrovert-nonsense-1713772952) 的两端。虽然这个世界看起来好像外向者比内向者要多，但是心理学者则倾向于认为大部分人在光谱上的位置是落在 [中间性格或偏内向性格的](https://www.psychologytoday.com/us/blog/the-gen-y-guide/201710/the-majority-people-are-not-introverts-or-extroverts)。

现在，我们来看看问答。

### DevOps 技术主管可以通过哪些方式来让内向者感觉他们是团队的一部分并且愿意分享他们的想法？

“每个人都会不大一样，所以观察敏锐就很重要了。从 GitLab 过来的一个人告诉我，他们的哲学就是如果他们没有提供任何意见，那么他们就是被排除在外的。如果有人在一个会议上没有提供任何的意见，那就想办法让他们加入进来。**当我知道一个内向者对我们将要讨论的会议论题感兴趣的时候，我会提前请他写一些书面文本。有非常多的会议其实是可以避免的，只要通过把讨论放到 Slack 或者 GitLab 上就行了，内向者会更愿意参与进来**。在站立会议中，每个人都会交代最新的进展，在这个环境下，内向者表现得很好。有时候我们在其实会议上会重复做一些事情，仅仅是为了保证每个人都有时间发言。我同时也会鼓励内向者在工作小组或者社区小组面前发言，以此来锻炼他们的这些技能。”—— 丹·巴克

“**我觉得别人对我做的最好的事情，就是他们保证了当重大问题来临的时候，我拥有必要的技能去回答它**。彼时，我作为一名非常年轻的入伍空军的一员，我需要给我们部队的高级领导做状态简报的汇报。我必须在任何时候都有一些可用的数据点，以及在实现我们确立的目标的过程中，产生延误以及偏差的背后的原因。那样的经历推动着我从一个‘幕后人员’逐渐变得更加愿意和别人分享自己的观点和想法。”—— 克里斯·肖特

“**通过文化去领导。为你的同僚一起设计和尝试仪式。**你可以为给你的小组或团队设计一个小的每周仪式，甚至给你的部门或组织设计一个年度的大仪式。它的意义在于去尝试一些事物，并观察你在其中的领导角色。去找到你们文化当中的代沟以及对立。回顾团队的信仰和行为。你能从哪里观察到对立？你们的文化中缺失了什么？从一个小陈述开始‘我从 X 和 Y 之间看到了对立’，或者‘我的团队缺少了 Z’。接着，将代沟与对立转换为问题：写下三个‘我们如何能……(How might we’s, HMWs)’。”—— 凯瑟琳·路易斯

“内向者不是一个不同的群体，他们要么是在分享他们的想法之前想得太多或等得太久的一些人，要么就是一些根本不知道发生了什么的人。我就是第一种，我想太多了，有时候还担心我的意见会被其他人嘲笑，或者没有什么意思，或者想偏了。形成那样的思维方式很难，但它同时也在吞噬着我学习更好事物的机会。有一次，我们团队在讨论一个实现问题。我当时的老大一次又一次地问我，为什么我没有作为团队中更具经验的人参与进来，然后我就（集齐了全宇宙的力量之后）开口说我想说的大家都已经说过了。他说，有时候我可以重复说一次，事情纷繁，如果你能够重复一遍你的想法，即使它已经被讨论过了，也会大有裨益。好吧，虽然它不是一种特别信服的方式，但是我知道了至少有人想听听我怎么说，它给了我一点信心。

“现在，我所使用的让团队中的人发言的方法是**我经常向内向的人求助，即使我知道解决方法，并且在团队会议和讨论中感谢他们来建立他们的自信心，通过给他们时间让他们一点一点的从他们寡言的本性中走出来，从而跟团队分享很多的知识**。他们在外面的世界中可能仍然会有一点点孤立，但是在团队里面，有些会成为我们可以信赖的人。”—— 阿布希什克·塔姆拉卡尔

“我给参加会议的内向者的建议是，找一个同样要参加会议的朋友或者同事，这样到时你就会有人可以跟你一起舒服地交谈，在会议开始之前，提前跟其他的与会者（朋友、行业联系人、前同事等等）约着见个面或者吃顿饭，**要注意你的疲劳程度，并且照顾好自己**：如果你需要重新恢复能量，就跳过那些社交或者夜晚的活动，在事后回顾中记录一下自己的感受。”—— 伊丽莎白·约瑟夫

### 和一个内向者倾向的同事一起工作时，有什么提高生产效率的小建议？

“在保证质量时，生产效率会越来越具备挑战性。在大多数时候，工作中的一个小憩或者轻松随意的交谈，可能正是我们的创造性活动中需要的一个火花。再说一次，我发现当你的团队中有内向者时， Slack 和 Github 会是一个非常有用的用于交换想法以及和其他人互动的媒介。**我同时也发现，结对编程对于大部分的内向者也非常有用，虽然一对一的交流对于他们来说，并不像交税那么频繁，但是生产质量和效率的提升却是重大的**。但是，当一个内向者在独自工作的时间，团队中的所有人都不应该去打断他们。最好是发个邮件，或者使用没有那么强的侵入性的媒介。”—— 丹·巴克

“给他们趁手的工具，让他们工作并归档他们的工作。**让他们能够在他们的工作上做到最好**。要足够经常地去检查一下，保证他们没有走偏路，但是要记住，相比外向者而言，这样做是更大的一种让人分心的困扰。”—— 克里斯·肖特

“**当我低着头的时候，不要打断我。真的，别打断我！**当我沉浸在某件事物中时，这样做会造成我至少需要花费两个小时，才能让我的大脑重新回到之前的状态。感觉很痛苦。真的。你可以发个邮件让我去有白板的地方。然后从客户的角度而不是你的角度——通过画图的方式——分享下有什么问题。要知道，可能同时会有十几个客户问题缠绕在我的脑海中，如果你的问题听起来就是‘这样子做会让我在我的领导面前显得很好’的那一类问题，那么相比我脑袋中已经有的真正的客户问题而言，它不会得到更多的关注的。画个图，给我点时间思考。当我准备分享我的看法的时候，保证有多支马克笔可以使用。准备好接受你对问题的假设有可能完全是错误的。”—— 凯瑟琳·路易斯

“感谢和鼓励就是解决的方法，感谢可能不是一份工作评估，但是感谢能让人舒服地感受到自己并不仅仅是一个活着的独立实体，**因而每个人都能够感觉到自己是被倾听的，而不是被嘲笑或者低估的**。”—— 阿布希什克·塔姆拉卡尔

### 结语

在与内向的 DevOps 爱好者的这次交谈中，我们最大的启迪就是平等：其他人需要被怎样对待，就怎样对待他们，同时你想被怎样对待，就去要求别人怎样对待你。无论你是内向还是外向，我们都需要承认我们并非全以相同的一种方式体验这个世界。我们的同事应当被给予足够的空间以完成他们的工作，通过讨论他们的需求作为了解如何支持他们的开始。我们的差异正是我们的社区如此特别的原因，它让我们的工作对更多的人更加的有用。与别人沟通最有效的方式，就是对于你们两者而言都可行的方式。

---

via: <https://opensource.com/article/19/7/devops-introverted-people>

作者：[Matthew Broberg](https://opensource.com/users/mbbroberg) 选题：[lujun9972](https://github.com/lujun9972) 译者：[XLCYun](https://github.com/XLCYun) 校对：[wxy](https://github.com/wxy)

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


如何在 Ubuntu 和其它 Linux 发行版上更新 grub

# 如何在 Ubuntu 和其它 Linux 发行版上更新 grub

在这篇文章中，你将学习在 Ubuntu 或任何其它 Linux 发行版上更新 grub 。你也将学习一个或两个关于更新这个 grub 过程如何工作的事情。

### 如何更新 grub

Ubuntu 和很多其它的 Linux 发行版提供一个易使用的称为 `update-grub` 命令行实用程序。

为更新 grub ，你所要的全部工作就是使用 `sudo` 在终端中运行这个命令。

```
sudo update-grub
```

你应该看到一个像这样的输出：

```
[email protected]:~$ sudo update-grub
[sudo] password for abhishek:
Sourcing file `/etc/default/grub'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.0.0-37-generic
Found initrd image: /boot/initrd.img-5.0.0-37-generic
Found linux image: /boot/vmlinuz-5.0.0-36-generic
Found initrd image: /boot/initrd.img-5.0.0-36-generic
Found linux image: /boot/vmlinuz-5.0.0-31-generic
Found initrd image: /boot/initrd.img-5.0.0-31-generic
Found Ubuntu 19.10 (19.10) on /dev/sda4
Found MX 19 patito feo (19) on /dev/sdb1
Adding boot menu entry for EFI firmware configuration
done
```

你可能看到一个类似的称为 `update-grub2` 的命令。不需要在 `update-grub` 和 `update-grub2` 之间感到害怕或不知所措。这两个命令执行相同的动作。

大约在 10 年前，当 grub2 刚刚被引进时，`update-grub2` 命令也被引进。现在，`update-grub2` 只是一个链接到 `update-grub` 的符号，它们都更新 grub2 配置（因为 grub2 是默认的）。

#### 不能找到 update-grub 命令？这里是在这种情况下该做什么

它可能是，你的 Linux 发行版可能没有可用的 `update-grub` 命令。

在这种情况下你该做什么？你如何在这样一个 Linux 发行版上更新 grub ？

在这里不需要惊慌。`update-grub` 命令只是一个入口，用于运行 `grub-mkconfig -o /boot/grub/grub.cfg` 来生成 grub2 配置文件。

这意味着你可以在任意 Linux 发行版上使用下面的命令更新 grub ：

```
sudo grub-mkconfig -o /boot/grub/grub.cfg
```

当然，记住 `update-grub` 命令比上面的命令容易很多，这是为什么它在一开始被创建的原因。

### update-grub 是如何工作的？

当你安装一个 Linux 发行版时，它（通常）要求你安装 [grub 启动引导程序](https://en.wikipedia.org/wiki/GNU_GRUB)。

grub 的一部分安装在 MBR/ESP 分区上。grub 的剩余部分保留在 Linux 发行版的 `/boot/grub` 目录中。

依据它的 [man 页面](https://manpages.debian.org/testing/grub-legacy/update-grub.8.en.html)，`update-grub` 通过查找 `/boot` 目录来工作。所有以 [vmlinuz-](https://www.ibm.com/developerworks/community/blogs/mhhaque/entry/anatomy_of_the_initrd_and_vmlinuz?lang=en) 开头的文件将被作为内核来对待，并且它们将得到一个 grub 菜单项。它也将为与所找到内核版本相同的 [ramdisk](https://en.wikipedia.org/wiki/Initial_ramdisk) 镜像添加 initrd 行。

它也使用 [os-prober](https://packages.debian.org/sid/utils/os-prober) 为其它操作系统查找所有磁盘分区。如果找到其它操作系统，它添加它们到 grub 菜单。

### 为什么你需要更新 grub ？

在有很多场景下你需要更新 grub。

假设你修改 grub 配置文件（`/etc/default/grub`）以 [更改默认启动顺序](https://itsfoss.com/grub-customizer-ubuntu/) 或减少默认启动时间。除非你更新 grub ，否则你的修改将不会生效。

另一种情况是，你在同一个电脑系统上安装多个 Linux 发行版。

例如，在我的 Intel NUC 上，我有两个磁盘。第一个磁盘有 Ubuntu 19.10 ，并且我在其上面安装了 Ubuntu 18.04 。第二个操作系统（Ubuntu 18.04）安装了其自己的 grub ，现在 grub 启动屏幕由 Ubuntu 18.04 grub 控制。

在第二个磁盘上，我安装了 MX Linux ，但是这次我没有安装 grub。我希望现有的 grub（由 Ubuntu 18.04 控制）来处理所有的操作系统项目。

现在，在这种情况中，在 Ubuntu 18.04 上的 grub 需要更新，以便它能够看到 [MX Linux](https://mxlinux.org/) 。

如上图所示，当我更新 grub 时，它在 18.04 上找到很多安装的 Linux 内核, 以及在不同的分区上 Ubntu 19.10 和 MX Linux 。

如果你想让 MX Linux 控制 grub ，我可以使用 [grub-install](https://www.gnu.org/software/grub/manual/grub/html_node/Installing-GRUB-using-grub_002dinstall.html) 命令来在 MX Linux 上安装 grub，然后在 MX Linux 上的 grub 将开始控制 grub 启动屏幕。你已经明白这点，对吧？

使用一个像 [Grub Customizer](https://itsfoss.com/customize-grub-linux/) 的 GUI 工具是在 grub 中进行更改的一种简单的方法。

### 最后…

最初，我打算保持它为一篇短文作为一种快速提示。但是后来我想解释一些与之相关的东西，以便（相对）新的 Linux 用户能够学到更多，而不仅仅是一个简单命令。

你喜欢它吗？你有一些问题或建议吗？请随意发表评论。

---

via: <https://itsfoss.com/update-grub/>

作者：[Abhishek Prakash](https://itsfoss.com/author/abhishek/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[robsean](https://github.com/robsean) 校对：[wxy](https://github.com/wxy)

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


使用 KDE Plasma 定制 Linux 桌面

KDE值得尝试，UI不错

KDE还行

# 使用 KDE Plasma 定制 Linux 桌面

>
> 本文是 24 天 Linux 桌面特别系列的一部分。如果你认为没有太多自定义桌面的需要，KDE Plasma 可能适合你。
>
>
>

KDE 社区的 Plasma 桌面是开源桌面环境中的巅峰之作。KDE 很早就进入了 Linux 桌面环境市场，但是由于它的基础 Qt 工具包当时没有完全开放的许可证，因此才有 [GNOME](https://opensource.com/article/19/12/gnome-linux-desktop) 桌面。在此之后，Qt 开源了，并且 KDE（及其衍生产品，例如 [Trinity 桌面](https://opensource.com/article/19/12/linux-trinity-desktop-environment-tde)）开始蓬勃发展。

你可能会在发行版的软件仓库中找到 KDE 桌面，或者可以下载并安装将 KDE 作为默认桌面的发行版。在安装之前，请注意，KDE 提供了完整、集成且强大的桌面体验，因此会同时安装几个 KDE 应用。如果你已经在运行其他桌面，那么将发现有几个冗余的应用（两个 PDF 阅读器、多个媒体播放器、两个或多个文件管理器，等等）。如果你只想尝试而不是一直使用 KDE 桌面，那么可以在虚拟机，如 [GNOME Boxes](https://opensource.com/article/19/5/getting-started-gnome-boxes-virtualization) 中安装基于 KDE 的发行版，也可以尝试使用可引导的操作系统，例如 [Porteus](https://opensource.com/article/19/6/linux-distros-to-try)。

### KDE 桌面之旅

乍一看，[KDE Plasma](https://kde.org/plasma-desktop) 桌面相对无聊，但让人感到舒适。它有行业标准的布局：左下角弹出应用菜单，中间是任务栏，右边是系统托盘。这正是你对标准家用或商用计算机的期望。

但是，使 KDE 与众不同的是，你几乎可以更改任何想要的东西。Qt 工具包可以以令人惊讶的方式分割和重新排列，这意味着你实质上可以使用 KDE 的部件作为基础来设计自己的桌面。桌面行为的可用设置也很多。KDE 可以充当标准桌面、平铺窗口管理器以及两者之间的任意形式。你可以通过窗口类、角色、类型、标题或它们的任意组合来创建自己的窗口规则，因此，如果希望特定应用的行为不同于其他行为，那么可以创建全局设置的例外。

此外，它还有丰富的小部件集合，使你可以自定义与桌面交互的方式。它有一个类似 GNOME 的全屏应用启动器，一个类似 Unity 的 dock 启动器和仅有图标的任务栏，以及一个传统的任务栏。你可以在屏幕的任何边缘上创建和放置面板。

实际上，它有太多的自定义项了，因此 KDE 最常见的批评之一是它的*太过可定制化*，所以请记住，自定义项是可选的。你可以在默认配置下使用 Plasma 桌面，并仅在你认为必要时逐步进行更改。Plasma 桌面配置选项最重要的不是它们的数目，而是它们容易发现和直观，它们都在系统设置应用或者右键单击中。

事实是，在 KDE 上，几乎绝不会只有一种方法可以完成任何给定的任务，并且它的用户将这个视为其最大的优势。KDE 中没有隐含的工作流，只有默认的。并且可以更改所有默认设置，直到你需要桌面做的成为你的习惯。

### 一致性和集成

KDE 社区以一致性和集成为荣，出色的开发人员、社区管理以及 KDE 库使其成为可能。KDE 的开发人员不只是桌面开发人员。它们提供了[惊人的应用集合](https://kde.org/applications/)，每个应用都使用 KDE 库创建，这些库扩展并标准化了常见的 Qt 小部件。使用 KDE 几个月后，无论是打开 [DigiKam](https://opensource.com/life/16/5/how-use-digikam-photo-management) 进行照片管理，还是打开 Kmail 来检查电子邮件，还是打开 KTorrent 来获取最新的 ISO 或者使用 Dolphin 管理文件，你的肌肉记忆会在你思考之前直接带你进入对应 UI。

### 尝试 KDE

KDE 适合所有人。使用其默认设置可获得流畅、原始的桌面体验，或对其进行自定义以使其成为自己专属。它是一个稳定、有吸引力且强大的桌面环境，可能有你想要在 Linux 完成要做的事的一切。

---

via: <https://opensource.com/article/19/12/linux-kde-plasma>

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


每个 Kubernetes 应聘者应该知道的 5 个面试题

# 每个 Kubernetes 应聘者应该知道的 5 个面试题

>
> 如果你是要面试 Kubernetes 相关职位的应聘者，这里给出了要提问的问题以及这些问题的重要性。
>
>
>

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

面试对面试官及候选人来说都很不容易。最近，我发现面试 Kubernetes 相关工作的候选人似乎尤其困难。为什么呢？一方面，很难找到可以回答他们问题的人。而且，不管回答者回答的怎样，都很难确定他们是否有正确的经验。

跳过这个问题，让我们来看看面试 [Kubernetes](https://kubernetes.io/) 求职者时应该提问的一些问题。

### Kubernetes 是什么？

我发现这个问题是面试中最好的问题之一。我经常听到有人说“我用 Kubernetes 工作”，但是当我问道“Kubernetes 是什么”时，从来都没有得到过一个满意答案。

我最喜欢 [Chris Short](https://twitter.com/ChrisShort) 给出的答案：“Kubernetes 就是带有一些 YAML 文件的 API 。”

虽然他的回答没有错，但我会给你更详细的解释。 Kubernetes 是一个可移植容器的编排工具，用于自动执行管理、监控、扩展和部署容器化应用程序。

我认为“用于部署容器化应用程序的编排工具”这个回答可能与你期望的答案差不多了。能回答出这个，我觉得已经很不错了。尽管许多人认为 Kubernetes 做了更多更棒的工作，但总的来说，它为其核心功能——容器编排——添加了许多 API。

我认为，这是你在面试中可以提问的最好的问题之一，因为它至少证明了候选人是否知道 Kubernetes 是什么。

### Kubernetes 的节点和 Pod 有什么区别?

该问题揭示了候选人对 Kubernetes 复杂性的初步了解。它将面试对话转换为对体系结构的概述，并可能导向许多有趣的后续细节问题。我已经听到了无数次关于该问题的错误解释了。

[节点](https://kubernetes.io/docs/concepts/architecture/nodes/) 是工作计算机。该计算机可以是虚拟机（VM）或物理计算机，具体取决于你是在虚拟机监控程序上运行还是在裸机上运行。该节点包含用于运行容器的服务，包括 kubelet、kube-proxy 和容器运行时。

[Pod](https://kubernetes.io/docs/concepts/workloads/pods/pod/) 包括：一个或多个**容器**、具有共享**网络**和**存储**，以及有关如何运行一起部署的容器的**规范**。这四个细节都很重要。更进一步，职位申请人应从技术层面解释，Pod 是 Kubernetes 可以创建和管理的最小可部署单元，而不是容器。

对于这个问题，我听到的最好的简答是：“节点是计算机，而 Pod 是容器运行于其中的东西。”这个区别很重要。Kubernetes 管理员的大部分工作是知道什么时间要部署什么，而节点的部署成本可能非常非常高，具体取决于它们的运行位置。我不希望有人一遍又一遍地部署节点，他们需要做的就是部署一堆 Pod。

### kubectl 是什么？（你怎么发音？）

这个问题是我优先级较高的问题之一，但可能与你和你的团队无关。在我的团队中，我们不会使用图形化界面来管理 Kubernetes 环境，我们使用命令行操作。

那么什么是 [kubectl](https://kubernetes.io/docs/reference/kubectl/kubectl/)？它是 Kubernetes 的命令行界面。你可以从该界面获取并设置任何内容，从收集日志和事件到编辑部署环境和机密文件。随机提问候选人关于如何使用此工具对测试候选人对 kubectl 的熟悉度是很有帮助的。

你是怎么读的？好吧，你随便吧（对此有很大的分歧），但是我很高兴向你介绍我朋友 [Waldo](https://opensource.com/article/18/12/kubectl-definitive-pronunciation-guide) 的精彩视频演示。

### 命名空间是什么？

在多次面试中，我都没有得到关于这个问题的答案。我不确定在其他环境中使用的命名空间是否会在我所在的团队经常使用。我在这里给出一个简短的答案：命名空间是 Pod 中的虚拟集群。这种抽象可以使你将多个虚拟集保留在多个环境中以此来进行隔离。

### 容器是什么?

了解 Pod 中正在部署的内容总是有帮助的，因为如果都不知道其中部署的是什么，何谈部署？容器是打包代码及其所有依赖项的软件的标准单元。我收到了两个可以接受的答案，其中包括：a）精简的操作系统镜像，以及 b）在受限的操作系统环境中运行的应用程序。如果你可以叫得出使用 [Docker](https://opensource.com/resources/what-docker) 以外的其他容器的编排软件（例如你最喜欢的公共云的容器服务），则可以得到加分。

### 其他问题

如果你想知道为什么我没有在此问题列表中添加更多问题，那么我可以给出一个简单的答案：我所列出的这些问题是在面试候选人时应了解的最基本的问题。接下来的问题应该是基于具体的团队、环境及组织。当你仔细研究这些内容时，尝试寻找有关技术如何相互作用的有趣问题，以了解人们如何应对基础架构挑战。考虑一下你的团队最近遇到的挑战（中断），要求逐步进行部署，或者考虑改善团队积极想要改进的策略（例如减少部署时间）。问题越不抽象，对面试后真正重要的技能的询问就越多。

没有两个环境是完全相同的。这也适用于面试中。我在每次面试中都会混合提问。我也有一个测试面试者的小环境。我经常发现回答问题是最容易的部分，而你所做的工作才是对你的真正的考验。

我给面试官的最后一点建议是：如果你遇到一个很有潜力但没有经验的候选人时，请给他们一个证明自己的机会。如果当初没有人看到我的潜力，没有给我机会的话，我不会拥有今天的知识和经验。

还有哪些重要的问题？请留言告诉我们。

---

via: <https://opensource.com/article/19/12/kubernetes-interview-questions>

作者：[Jessica Repka](https://opensource.com/users/jrepka) 选题：[lujun9972](https://github.com/lujun9972) 译者：[Morisun029](https://github.com/Morisun029) 校对：[wxy](https://github.com/wxy)

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


应用推荐：来自 KDE 的 Falkon 开源 Web 浏览器

这是一个非常不错的浏览器，简洁，但非常稳定值得推荐

在win10系统安装Falkon浏览器打开提示缺少：msvcr120.dll文件

# 应用推荐：来自 KDE 的 Falkon 开源 Web 浏览器

>
> Falkon 是基于 QtWebEngine 的 Web 浏览器，它以前称为 Qupzilla。在本周的“应用推荐”中，我们来看看这个开源软件。
>
>
>

### Falkon：适用于 Linux（和 Windows）的开源 Web 浏览器

首先，[Falkon](https://www.falkon.org/) 并不是一款新的 Web 浏览器。它自 2010 年以来一直在开发中，但被称为 Qupzilla。2017 年，QupZilla 移到 KDE 旗下，并更名为 Falkon。处于 KDE 旗下意味着项目会按照 KDE 标准积极维护。

它使用 [QtWebEngine](https://wiki.qt.io/QtWebEngine) 渲染引擎，这是 Chromium 核心的简化版本。

在本文中，我将仔细研究它提供的功能以及与 Linux 上其他主流 Web 浏览器的不同之处。

### Falkon 浏览器的功能

我认为它可能不是流行的浏览器，但我发现它足以浏览现代 Web 服务。让我重点介绍 Falkon 的主要功能，如果你觉得它很有趣，请尝试一下。

#### 简单的用户界面

我知道这不完全是一项“功能”，但是用户体验（UX）至关重要。尽管是轻量级的浏览器，但你会拥有一个不错的界面。你不会觉得使用的是一款源自 2000 年早期的浏览器。

#### AdBlock 扩展

它附带了 AdBlock 扩展程序，如果你想在浏览网站时摆脱广告，它的效果很好。你还可以自定义 AdBlock 扩展的行为。

#### DuckDuckGo 作为默认搜索引擎

如果你不喜欢使用 Google，那么这是一件好事，它将这个[主打隐私的搜索引擎](https://itsfoss.com/privacy-search-engines/)设为默认搜索引擎。

#### 会话管理器

Falkon 在浏览器菜单的可用选项中包含了一个有用的会话管理器。你可以用它还原特定的近期会话，这应该能派上用场。

#### 扩展支持

它确实支持添加扩展，但你不能从 Chrome/Firefox 插件市场添加扩展。你只能选择有限的一组扩展。

#### 主题支持

Falkon 还允许你在某种程度上自定义外观。如果要更改浏览器的外观，可以尝试一下。

#### 其他基本设置

我还尝试了其他设置/功能，例如添加书签或管理密码。或者，管理网页的通知。我还试了 YouTube，没有任何问题。

当然，这不是一个详尽的评测。但是，Falkon 确实拥有浏览器中需要的所有基本功能（除非你有特定要求）。

### 安装 Falkon 浏览器

你可以在软件中心轻松找到 Falkon 浏览器。如果没有，你可以从它的[官方下载页面](https://www.falkon.org/download/)中找到 Flatpak/Snap 包。你还可以在下载页面上找到 Windows 的安装程序。

[Download Falkon Browser](https://www.falkon.org/download/)

### 总结

作为 KDE 产品，Falkon 是为 KDE 桌面环境量身定制的。一些 KDE 发行版（例如 OpenMandriva）使用 Falkon 作为默认的 Web 浏览器。

Falkon 浏览器适合那些正在寻求轻巧且功能丰富的 Web 浏览器的人。值得尝试的另一个替代是 [Midori](https://itsfoss.com/midori-browser/)。

我认为，除非你需要大量的扩展、跨平台同步并且需要访问某些特定于浏览器的网站，不然它是一个很好的替代浏览器。

你如何看待 Falkon 浏览器？请在下面的评论中让我知道你的想法。

---

via: <https://itsfoss.com/falkon-browser/>

作者：[Ankush Das](https://itsfoss.com/author/ankush/) 选题：[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/) 荣誉推出


Fedora 上的桌面环境内存占用测试

KDE often uses more RAM but provides more functions.

# Fedora 上的桌面环境内存占用测试

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

Fedora 中有 40 多种桌面环境（DE）。每种桌面环境都有自己的优点和缺点。通常，根据功能、外观和其它品质，选择桌面是一件非常个人的偏好。但有时，你选择的桌面环境还会受到硬件限制。

本文旨在帮助人们根据桌面环境占用的基准内存来比较 Fedora 桌面环境。为了缩小范围，我们仅查看具有正式 Fedora Live 镜像的桌面环境。

### 安装与系统配置

每个桌面环境都安装在自己的 KVM 虚拟机上。每个虚拟机都有 1 个 CPU、4GB 内存、15GB virtio 固态磁盘，以及 RHEL 8.0 kvm 上所有其他标准配置。

用于安装的镜像是标准的 Fedora 31 Live 镜像。对于 GNOME，该镜像是 “Fedora 工作站”。对于其它桌面，使用了相应的 Spin 版本。未对“<ruby> 糖葫芦 <rt>  Sugar On A Stick </rt></ruby>”（SOAS）进行测试，因为它不容易安装到本地驱动器上。

用 Live CD 启动虚拟机，然后选择“安装到硬盘”。在安装过程中，仅使用默认值。创建了一个 root 用户和一个普通用户。安装并重新启动后，live 镜像已确认不在虚拟 CDROM 中。

每个桌面环境的设置都没有改动。它们每个都以 Live CD 环境中默认的设置运行。每个桌面环境都是通过普通用户登录的。打开了一个终端，在每台虚拟机中都使用 `sudo` 运行了 `dnf -y update`。在更新后，在该 sudo 终端中，每台虚拟机都运行 `/sbin/shutdown -h now` 以关闭。

### 测试方式

每台机器都已启动。桌面环境已通过普通用户登录。打开了三个桌面终端。xterm 从未使用过，始终用的是该桌面环境的终端，例如 konsole。

在一个终端中，启动 `top` 并按下 `M`，以显示按内存排序的进程。在另一个终端中，一个简单的 `while` 循环每 30 秒显示一次 `free -m`。第三个终端闲置。

然后，我等待了 5 分钟。这样就可以让所有启动的服务都启动完成。我记录了最终的 `free` 结果，以及 `top` 中最终的前三名内存使用者。

### 结果

* Cinnamon
	+ 使用了624 MB
	+ cinnamon 4.8% / Xorg 2.2% / dnfdragora 1.8%
* GNOME
	+ 使用了 612 MB
	+ gnome-shell 6.9% / gnome-software 1.8% / ibus-x11 1.5%
* KDE
	+ 使用了 733 MB
	+ plasmashell 6.2% / kwin\_x11 3.6% / akonadi\_mailfil 2.9%
* LXDE
	+ 使用了 318 MB
	+ Xorg 1.9% / nm-applet 1.8% / dnfdragora 1.8%
* LXQt
	+ 使用了 391 MB
	+ lxqt-panel 2.2% / pcmanfm-qt 2.1% / Xorg 2.1%
* MATE
	+ 使用了 465 MB
	+ Xorg 2.5% / dnfdragora 1.8% / caja 1.5%
* XFCE
	+ 使用了 448 MB
	+ Xorg 2.3% / xfwm4 2.0% / dnfdragora 1.8%

### 结论

我会让数字说明一切。

请记住，这些数字来自默认的 Live 安装环境。如果删除或添加服务和功能，则内存使用量将发生变化。但是，如果要根据内存消耗确定桌面环境，这是一个很好的基准。

---

via: <https://fedoramagazine.org/fedora-desktops-memory-footprints/>

作者：[Troy Dawson](https://fedoramagazine.org/author/tdawson/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


为什么 Vim 爱好者喜欢 Herbstluftwm Linux 窗口管理器

# 为什么 Vim 爱好者喜欢 Herbstluftwm Linux 窗口管理器

>
> 本文是 24 天 Linux 桌面特别系列的一部分。如果你是 Vim 爱好者，请试试 Herbstluftwm，这是一个受到 “Vim 方式”启发的平铺式 Linux 窗口管理器。
>
>
>

每个人都喜欢 Vim（除了 Dvorak 和 Emacs 用户）。Vim 非常流行，它不仅仅是个编辑器，还有整个都使用 Vim 键绑定来浏览网页的 Web 浏览器，在非常流行的 [Zsh](https://opensource.com/article/19/9/getting-started-zsh) 终端仿真器中也有 Vim 模式。此外，还有一个名为 [herbstluftwm](https://herbstluftwm.org) 的窗口管理器，它部分模仿了 “Vim 方式”。Herbstluftwm 取消了窗口，而是在程序载入和使用时使用平铺的贴片或者象限代替。你可以使用键盘（`Alt+h`、`Alt+j`、`Alt+k` 和 `Alt+l`）从一个平铺贴片移动到另一个平铺贴片。

可以从发行版软件仓库安装 Herbstluftwm。安装后，请退出当前桌面会话，以便可以登录到新会话。默认情况下，会话管理器（KDM、GDM、LightDM 或 XDM，具体取决于你的设置）将继续登录到以前的桌面，因此在登录之前必须覆盖它。

在 GDM 中：

在 SDDM 中：

### Herbstluftwm 桌面之旅

第一次登录 Herbstluftwm 时，你只会看到一个绿屏，边缘有深绿色边框。你所看到的是初始的平铺贴片，其中没有加载任何应用程序。要启动默认应用，请按 `Alt+Enter`。

文档中强调使用 `$HOME/.config/herbstluftwm/autostart` 作为登录时启动重要应用的配置文件。对于不必在每次登录时启动的应用，可以使用 xterm 作为启动守护进程。与往常一样，在命令后加一个 `&` 符号会将 shell 的控制权返回给你。例如，要启动 Emacs：

```
% emacs &
```

这将在新的平铺贴片中启动 Emacs 窗口，然后返回命令行。

#### 切换平铺贴片

要从一个平铺贴片移动到另一个平铺贴片，请使用经典的 `h`、`j`、`k` 或 `l` 与 `Alt` 的 Vim 导航组合键。例如，要从终端切换到其下方的平铺贴片中的应用（即屏幕底部），请按 `Alt+j`。要返回，请按 `Alt+k`。左移和右移分别为 `Alt+h` 和 `Alt+l`。

#### 分割屏幕

你可以使用 `Alt+o` 垂直分割屏幕，使用 `Alt+u` 水平分割屏幕。

要删除空白平铺贴片，请移动到该平铺贴片，然后按 `Alt+r`。

### 配置 herbstluftwm

除了 `Alt` 键绑定外，你还可通过 `herbstclient` 命令与 Herbstluftwm 进行通信。此命令可以在 shell 中交互，或者你可在配置文件中保留你的首选项。

你可以查看 Herbstluftwm 中的所有可用属性：

```
$ herbstclient attr
```

Herbstluftwm 的默认行为定义在其默认配置文件中，你可以将其复制到你的家目录并进行修改。启动后，Herbstluftwm 执行配置文件中包含的命令。例如，你觉得使用以 `Alt` 为中心的键绑定很笨拙（它传统上是应用内保留快捷键），那你可以在配置文件中更改触发 Herbstluftwm 操作的键：

```
% mkdir ~/.config/herbstluftwm
% cp /usr/xdg/herbstluftwm/autostart ~/.config/herbstluftwm
% sed -i 's/Mod=Mod1/Mod=Mod4/' ~/.config/herbstluftwm
% herbstclient reload
```

这将使 Herbstluftwm 的修饰键更改为 `Super` 键（“Windows” 或 “Tux” 键，具体取决于你的键盘）。

使用 `autostart` 文件，你可以设置自定义键绑定，为特定类型的应用创建标签，以便以一致的方式平铺应用，并执行更多操作。

### 为何你要尝试 herbstluftwm

Herbstluftwm 是一个平铺窗口管理器的很好例子。它默认平铺窗口，并允许用户定义全局规则的例外。它使用类似 Vim 的导航方式，但可以快速简单地覆盖它。它可能是你一直在寻找的平铺管理器，所以请马上尝试一下。

---

via: <https://opensource.com/article/19/12/herbstluftwm-linux-desktop>

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


如何使用 Ansible 同步 GitHub 和 GitLab

Summary: 通过使用 Ansible 镜像 Git 存储库，保护对重要项目的访问。

通过使用 Ansible 镜像 Git 存储库，保护对重要项目的访问。

# 如何使用 Ansible 同步 GitHub 和 GitLab

>
> 通过使用 Ansible 镜像 Git 存储库，保护对重要项目的访问。
>
>
>

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

开源无处不在。它在家里的计算机上、在工作场所的计算机上、在互联网上，并且很多都由 [Git](https://opensource.com/resources/what-is-git) 管理。由于 Git 是分布式的，因此许多人也将其视为一种众包的备份解决方案。从理论上讲，每当有人将 Git 存储库克隆到其本地计算机时，他们就创建了该项目源代码的备份。如果有 100 个人这样做，则存储库就有 100 个备份副本。

从理论上讲，这可以缓解“灾难”的影响，例如当项目维护者[突然决定删除存储库](https://github.com/AntiMicro/antimicro/issues/3)或[莫名其妙地阻止所有流量](https://opensource.com/article/19/10/how-community-saved-artwork-creative-commons)，导致开发人员们无头苍蝇般地寻找谁拥有主分支的最新版本。类似的，整个代码托管站点也会消失。没有人会想到 Google Code、Microsoft CodePlex 或 Gitorious 会在鼎盛时期将被关闭。

简而言之，如果在过去的几十年中互联网教给了我们一些东西，那就是依靠互联网神奇地创建备份并不是冗余的最可靠途径。

此外，对于许多人来说，很多开源项目都托管在 GitHub 上是个问题 —— GitHub 并不是开放平台。许多开发人员和用户都希望支持诸如 GitLab 之类的堆栈并与之交互，它具有开源社区版本。

### 使用 Ansible 管理 Git

Git 的去中心方式对于解决这个问题很有用。使用纯 Git，你可以使用一个 `push` 命令轻松地将其推到两个或多个存储库。但是，为了使其在发生意外故障时有用，你必须经常与 Git 存储库进行交互（特别是推送）。此外，即使你可能永远不会自己推送或拉出代码，也可能有一些要备份的存储库。

但是，使用 Ansible，你可以自动执行项目主分支（或其他任何分支）的 Git 拉取，然后自动进行存储库到“异地”镜像的 Git 推送。换句话说，你可以让你的计算机定期从 GitHub 拉取并推送到 GitLab 或 [Gitolite](https://opensource.com/article/19/4/server-administration-git) 或 Gitea（或你喜欢的任何 Git 托管主机）。

### Ansible 模块

如果不是因其出色的模块集合，那么 Ansible 就没那么出色。像 Python 的第三方库或 Linux 的应用程序一样，这个技术引擎的一个有用而令人惊讶的简单技巧是，Ansible 以其他人贡献的组件而闻名。因为本文正在研究如何有效和可靠地备份 Git 存储库，所以这里使用的模块是 [Git 模块](https://docs.ansible.com/ansible/latest/modules/git_module.html)和 [ini\_file](https://docs.ansible.com/ansible/latest/modules/ini_file_module.html) 模块。

首先，创建一个名为 `mirror.yaml` 的文件作为<ruby> 剧本 <rt>  playbook </rt></ruby>。你可以像通常使用 Ansible 一样，从 `name` 和 `task` 条目开始。本示例将 `localhost` 添加到 `hosts` 列表中，以便在控制器计算机（你现在坐在前面的计算机）上运行<ruby> 动作 <rt>  play </rt></ruby>，但是在现实生活中，你可能会在特定的主机或一组网络上的主机上运行它。

```
---
- name: "Mirror a Git repo with Ansible"
  hosts: localhost
  tasks:
```

### Git 拉取和克隆

如果要进行备份，则需要最新代码的副本。明显，在 Git 仓库中实现这一目标的方法是执行 `git pull`。 但是，`pull` 会假定克隆已经存在，而写得很好的 Ansible 动作（Ansible 脚本）则尽可能少的假定。最好告诉 Ansible 先克隆存储库。

将你的第一个任务添加到剧本：

```
---
- name: "Mirror a Git repo with Ansible"
  hosts: localhost
  vars:
    git_dir: /tmp/soso.git
  tasks:

  - name: "Clone the git repo"
    git:
       repo: 'https://github.com/ozkl/soso.git'
       dest: '{{ git_dir }}'
       clone: yes
       update: yes
```

这个例子使用了开源的、类似于 Unix 的操作系统 soso 作为我要镜像的存储库。这是一个完全任意的选择，绝不意味着我对该存储库的未来缺乏信心。它还使用变量来引用目标文件夹 `/tmp/soso.git`，这很方便，并且如果以后你希望将它扩展为一个通用的镜像脚本也会受益。在现实生活中，你的工作机上可能会比 `/tmp` 具有更永久的位置，例如 `/home/gitmirrors/soso.git` 或 `/opt/gitmirrors/soso.git`。

运行你的剧本：

```
$ ansible-playbook mirror.yaml
```

首次运行该剧本时，Ansible 会正确检测到 Git 存储库在本地尚不存在，因此将其克隆。

```
PLAY [Ansible Git mirror] ********

TASK [Gathering Facts] ***********
ok: [localhost]

TASK [Clone git repo] ************
changed: [localhost]

PLAY RECAP ***********************
localhost: ok=2 changed=1 failed=0 [...]
```

如果你再次运行该剧本，Ansible 会正确检测到自上次运行以来没有任何更改，并且会报告未执行任何操作：

```
localhost: ok=2 changed=0 failed=0 [...]
```

接下来，必须指示 Ansible 将存储库推送到另一个 Git 服务器。

### Git 推送

Ansible 中的 Git 模块不提供 `push` 功能，因此该过程的一部分是手动的。但是，在将存储库推送到备用镜像之前，你必须具有一个镜像，并且必须将镜像配置为备用<ruby> 远程服务器 <rt>  remote </rt></ruby>。

首先，必须将备用的远程服务器添加到 Git 配置。因为 Git 配置文件是 INI 样式的配置，所以你可以使用 `ini_file` Ansible 模块轻松地添加所需的信息。将此添加到你的剧本：

```
 - name: "Add alternate remote"
    ini_file: dest={{ git_dir }}/.git/config section='remote \"mirrored\"' option=url value='git@gitlab.com:example/soso-mirror.git'
    tags: configuration
```

为此，你必须在目标服务器上有一个空的存储库（在本例中为 [GitLab.com](http://GitLab.com)）。如果需要在剧本中创建目标存储库，可以按照 Steve Ovens 的出色文章《[如何使用 Ansible 通过 SSH 设置 Git 服务器](https://opensource.com/article/17/8/ansible-environment-management)》来完成。

最后，直接使用 Git 将 HEAD 推送到备用远程服务器：

```
 - name: "Push the repo to alternate remote"
    shell: 'git --verbose --git-dir={{ git_dir }}/.git push mirrored HEAD'
```

像往常一样运行该剧本，然后使该过程自动化，这样你就不必再次直接运行它了。你可以使用变量和特定的 Git 命令来调整脚本以适应你的需求，但是通过常规的拉取和推送操作，可以确保驻留在一台服务器上的重要项目可以安全地镜像到另一台服务器上。

这是完整的剧本，供参考：

```
---
- name: "Mirror a Git repository with Ansible"
  hosts: localhost
  vars:
    git_dir: /tmp/soso.git

  tasks:

  - name: "Clone the Git repo"
    git:
       repo: 'https://github.com/ozkl/soso.git'
       dest: '{{ git_dir }}'
       clone: yes
       update: yes

  - name: "Add alternate remote"
    ini_file: dest={{ git_dir }}/.git/config section='remote \"mirrored\"' option=url value='git@gitlab.com:example/soso-mirror.git'
    tags: configuration

  - name: "Push the repo to alternate remote"
    shell: 'git --verbose --git-dir={{ git_dir }}/.git push mirrored HEAD'
```

---

via: <https://opensource.com/article/19/11/how-host-github-gitlab-ansible>

作者：[Seth Kenlon](https://opensource.com/users/seth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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