使用 GDB 查看程序的栈空间

Summary: 这是一个快速教程，介绍如何使用 GDB 查看 C 程序的栈空间。

这是一个快速教程，介绍如何使用 GDB 查看 C 程序的栈空间。

![](/data/attachment/album/202107/05/103738f00boylephggpeyh.jpg)

昨天我和一些人在闲聊的时候，他们说他们并不真正了解栈是如何工作的，而且也不知道如何去查看栈空间。

这是一个快速教程，介绍如何使用 GDB 查看 C 程序的栈空间。我认为这对于 Rust 程序来说也是相似的。但我这里仍然使用 C 语言，因为我发现用它更简单，而且用 C 语言也更容易写出错误的程序。

### 我们的测试程序

这里是一个简单的 C 程序，声明了一些变量，从标准输入读取两个字符串。一个字符串在堆上，另一个字符串在栈上。

```
#include <stdio.h>
#include <stdlib.h>

int main() {
    char stack_string[10] = "stack";
    int x = 10;
    char *heap_string;

    heap_string = malloc(50);

    printf("Enter a string for the stack: ");
    gets(stack_string);
    printf("Enter a string for the heap: ");
    gets(heap_string);
    printf("Stack string is: %s\n", stack_string);
    printf("Heap string is: %s\n", heap_string);
    printf("x is: %d\n", x);
}

```

这个程序使用了一个你可能从来不会使用的极为不安全的函数 `gets` 。但我是故意这样写的。当出现错误的时候，你就知道是为什么了。

### 第 0 步：编译这个程序

我们使用 `gcc -g -O0 test.c -o test` 命令来编译这个程序。

`-g` 选项会在编译程序中将调式信息也编译进去。这将会使我们查看我们的变量更加容易。

`-O0` 选项告诉 gcc 不要进行优化，我要确保我们的 `x` 变量不会被优化掉。

### 第一步：启动 GDB

像这样启动 GDB：

```
$ gdb ./test

```

它打印出一些 GPL 信息，然后给出一个提示符。让我们在 `main` 函数这里设置一个断点：

```
(gdb) b main

```

然后我们就可以运行程序：

```
(gdb) b main
Starting program: /home/bork/work/homepage/test
Breakpoint 1, 0x000055555555516d in main ()

(gdb) run
Starting program: /home/bork/work/homepage/test

Breakpoint 1, main () at test.c:4
4   int main() {

```

好了，现在程序已经运行起来了。我们就可以开始查看栈空间了。

### 第二步：查看我们变量的地址

让我们从了解我们的变量开始。它们每个都在内存中有一个地址，我们可以像这样打印出来：

```
(gdb) p &x
$3 = (int *) 0x7fffffffe27c
(gdb) p &heap_string
$2 = (char **) 0x7fffffffe280
(gdb) p &stack_string
$4 = (char (*)[10]) 0x7fffffffe28e

```

因此，如果我们查看那些地址的堆栈，那我们应该能够看到所有的这些变量！

### 概念：栈指针

我们将需要使用栈指针，因此我将尽力对其进行快速解释。

有一个名为 ESP 的 x86 寄存器，称为“<ruby> 栈指针 <rt>  stack pointer </rt></ruby>”。 基本上，它是当前函数的栈起始地址。 在 GDB 中，你可以使用 `$sp` 来访问它。 当你调用新函数或从函数返回时，栈指针的值会更改。

### 第三步：在 `main` 函数开始的时候，我们查看一下在栈上的变量

首先，让我们看一下 main 函数开始时的栈。 现在是我们的堆栈指针的值：

```
(gdb) p $sp
$7 = (void *) 0x7fffffffe270

```

因此，我们当前函数的栈起始地址是 `0x7fffffffe270`，酷极了。

现在，让我们使用 GDB 打印出当前函数堆栈开始后的前 40 个字（即 160 个字节）。 某些内存可能不是栈的一部分，因为我不太确定这里的堆栈有多大。 但是至少开始的地方是栈的一部分。

![](/data/attachment/album/202107/05/103921zcw86wzokre8gure.jpg)

我已粗体显示了 `stack_string`，`heap_string` 和 `x` 变量的位置，并改变了颜色：

* `x` 是红色字体，并且起始地址是 `0x7fffffffe27c`
* `heap_string` 是蓝色字体，起始地址是 `0x7fffffffe280`
* `stack_string` 是紫色字体，起始地址是 `0x7fffffffe28e`

你可能会在这里注意到的一件奇怪的事情是 `x` 的值是 0x5555，但是我们将 `x` 设置为 `10`！ 那是因为直到我们的 `main` 函数运行之后才真正设置 `x` ，而我们现在才到了 `main` 最开始的地方。

### 第三步：运行到第十行代码后，再次查看一下我们的堆栈

让我们跳过几行，等待变量实际设置为其初始化值。 到第 10 行时，`x` 应该设置为 `10`。

首先我们需要设置另一个断点：

```
(gdb) b test.c:10
Breakpoint 2 at 0x5555555551a9: file test.c, line 11.

```

然后继续执行程序：

```
(gdb) continue
Continuing.

Breakpoint 2, main () at test.c:11
11      printf("Enter a string for the stack: ");

```

好的！ 让我们再来看看堆栈里的内容！ `gdb` 在这里格式化字节的方式略有不同，实际上我也不太关心这些（LCTT 译注:可以查看 GDB 手册中 `x` 命令，可以指定 `c` 来控制输出的格式）。 这里提醒一下你，我们的变量在栈上的位置：

* `x` 是红色字体，并且起始地址是 `0x7fffffffe27c`
* `heap_string` 是蓝色字体，起始地址是 `0x7fffffffe280`
* `stack_string` 是紫色字体，起始地址是 `0x7fffffffe28e`

![](/data/attachment/album/202107/05/104033oe61ylv1rq9inp8p.png)

在继续往下看之前，这里有一些有趣的事情要讨论。

### `stack_string` 在内存中是如何表示的

现在（第 10 行），`stack_string` 被设置为字符串`stack`。 让我们看看它在内存中的表示方式。

我们可以像这样打印出字符串中的字节（LCTT 译注：可以通过 `c` 选项直接显示为字符）：

```
(gdb) x/10x stack_string
0x7fffffffe28e: 0x73    0x74    0x61    0x63    0x6b    0x00    0x00    0x00
0x7fffffffe296: 0x00    0x00

```

`stack` 是一个长度为 5 的字符串，相对应 5 个 ASCII 码- `0x73`、`0x74`、`0x61`、`0x63` 和 `0x6b`。`0x73` 是字符 `s` 的 ASCII 码。 `0x74` 是 `t` 的 ASCII 码。等等...

同时我们也使用 `x/1s` 可以让 GDB 以字符串的方式显示：

```
(gdb) x/1s stack_string
0x7fffffffe28e: "stack"

```

### `heap_string` 与 `stack_string` 有何不同

你已经注意到了 `stack_string` 和 `heap_string` 在栈上的表示非常不同：

* `stack_string` 是一段字符串内容（`stack`）
* `heap_string` 是一个指针，指向内存中的某个位置

这里是 `heap_string` 变量在内存中的内容：

```
0xa0  0x92  0x55  0x55  0x55  0x55  0x00  0x00

```

这些字节实际上应该是从右向左读：因为 x86 是小端模式，因此，`heap_string` 中所存放的内存地址 `0x5555555592a0`

另一种方式查看 `heap_string` 中存放的内存地址就是使用 `p` 命令直接打印 ：

```
(gdb) p heap_string
$6 = 0x5555555592a0 ""

```

### 整数 x 的字节表示

`x` 是一个 32 位的整数，可由 `0x0a 0x00 0x00 0x00` 来表示。

我们还是需要反向来读取这些字节（和我们读取 `heap_string` 需要反过来读是一样的），因此这个数表示的是 `0x000000000a` 或者是 `0x0a`，它是一个数字 `10`;

这就让我把把 `x` 设置成了 `10`。

### 第四步：从标准输入读取

好了，现在我们已经初始化我们的变量，我们来看一下当这段程序运行的时候，栈空间会如何变化：

```
printf("Enter a string for the stack: ");
gets(stack_string);
printf("Enter a string for the heap: ");
gets(heap_string);

```

我们需要设置另外一个断点：

```
(gdb) b test.c:16
Breakpoint 3 at 0x555555555205: file test.c, line 16.

```

然后继续执行程序：

```
(gdb) continue
Continuing.

```

我们输入两个字符串，为栈上存储的变量输入 `123456789012` 并且为在堆上存储的变量输入 `bananas`;

### 让我们先来看一下 `stack_string`（这里有一个缓存区溢出）

```
(gdb) x/1s stack_string
0x7fffffffe28e: "123456789012"

```

这看起来相当正常，对吗？我们输入了 `12345679012`，然后现在它也被设置成了 `12345679012`（LCTT 译注：实测 gcc 8.3 环境下，会直接段错误）。

但是现在有一些很奇怪的事。这是我们程序的栈空间的内容。有一些紫色高亮的内容。

![](/data/attachment/album/202107/05/104127zttxld1nlbg9lp9z.png)

令人奇怪的是 **`stack_string` 只支持 10 个字节**。但是现在当我们输入了 13 个字符以后，发生了什么？

这是一个典型的缓冲区溢出，`stack_string` 将自己的数据写在了程序中的其他地方。在我们的案例中，这还没有造成问题，但它会使你的程序崩溃，或者更糟糕的是，使你面临非常糟糕的安全问题。

例如，假设 `stack_string` 在内存里的位置刚好在 `heap_string` 之前。那我们就可能覆盖 `heap_string` 所指向的地址。我并不确定 `stack_string` 之后的内存里有一些什么。但我们也许可以用它来做一些诡异的事情。

### 确实检测到了有缓存区溢出

当我故意写很多字符的时候：

```
 ./test
Enter a string for the stack: 01234567891324143
Enter a string for the heap: adsf
Stack string is: 01234567891324143
Heap string is: adsf
x is: 10
*** stack smashing detected ***: terminated
fish: Job 1, './test' terminated by signal SIGABRT (Abort)

```

这里我猜是 `stack_string` 已经到达了这个函数栈的底部，因此额外的字符将会被写在另一块内存中。

当你故意去使用这个安全漏洞时，它被称为“堆栈粉碎”，而且不知何故有东西在检测这种情况的发生。

我也觉得这很有趣，虽然程序被杀死了，但是当缓冲区溢出发生时它不会立即被杀死——在缓冲区溢出之后再运行几行代码，程序才会被杀死。 好奇怪！

这些就是关于缓存区溢出的所有内容。

### 现在我们来看一下 `heap_string`

我们仍然将 `bananas` 输入到 `heap_string` 变量中。让我们来看一下内存中的样子。

这是在我们读取了字符串以后，`heap_string` 在栈空间上的样子：

![](/data/attachment/album/202107/05/104208s0lao7a0y1aa1oaa.png)

需要注意的是，这里的值是一个地址。并且这个地址并没有改变，但是我们来看一下指向的内存上的内容。

```
(gdb) x/10x 0x5555555592a0
0x5555555592a0: 0x62    0x61    0x6e    0x61    0x6e    0x61    0x73    0x00
0x5555555592a8: 0x00    0x00

```

看到了吗，这就是字符串 `bananas` 的字节表示。这些字节并不在栈空间上。他们存在于内存中的堆上。

### 堆和栈到底在哪里？

我们已经讨论过栈和堆是不同的内存区域，但是你怎么知道它们在内存中的位置呢？

每个进程都有一个名为 `/proc/$PID/maps` 的文件，它显示了每个进程的内存映射。 在这里你可以看到其中的栈和堆。

```
$ cat /proc/24963/maps
... lots of stuff omitted ...
555555559000-55555557a000 rw-p 00000000 00:00 0                          [heap]
... lots of stuff omitted ...
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]

```

需要注意的一件事是，这里堆地址以 `0x5555` 开头，栈地址以 `0x7fffff` 开头。 所以很容易区分栈上的地址和堆上的地址之间的区别。

### 像这样使用 gdb 真的很有帮助

这有点像旋风之旅，虽然我没有解释所有内容，但希望看到数据在内存中的实际情况可以使你更清楚地了解堆栈的实际情况。

我真的建议像这样来把玩一下 gdb —— 即使你不理解你在内存中看到的每一件事，我发现实际上像这样看到我程序内存中的数据会使抽象的概念，比如“栈”和“堆”和“指针”更容易理解。

### 更多练习

一些关于思考栈的后续练习的想法（没有特定的顺序）：

* 尝试将另一个函数添加到 `test.c` 并在该函数的开头创建一个断点，看看是否可以从 `main` 中找到堆栈！ 他们说当你调用一个函数时“堆栈会变小”，你能在 gdb 中看到这种情况吗？
* 从函数返回一个指向栈上字符串的指针，看看哪里出了问题。 为什么返回指向栈上字符串的指针是不好的？
* 尝试在 C 中引起堆栈溢出，并尝试通过在 gdb 中查看堆栈溢出来准确理解会发生什么！
* 查看 Rust 程序中的堆栈并尝试找到变量！
* 在 [噩梦课程](https://github.com/guyinatuxedo/nightmare) 中尝试一些缓冲区溢出挑战。每个问题的答案写在 README 文件中，因此如果你不想被宠坏，请避免先去看答案。 所有这些挑战的想法是给你一个二进制文件，你需要弄清楚如何导致缓冲区溢出以使其打印出 `flag` 字符串。

---

via: <https://jvns.ca/blog/2021/05/17/how-to-look-at-the-stack-in-gdb/>

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

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


使用 Python 解析配置文件

Summary: 第一步是选择配置文件的格式：INI、JSON、YAML 或 TOML。

第一步是选择配置文件的格式：INI、JSON、YAML 或 TOML。

>
> 第一步是选择配置文件的格式：INI、JSON、YAML 或 TOML。
>
>
>

![](/data/attachment/album/202107/05/113551tm0d0yp0px0xzp0n.jpg "Python programming language logo with question marks")

有时，程序需要足够的参数，将它们全部作为命令行参数或环境变量既不让人愉快也不可行。 在这些情况下，你将需要使用配置文件。

有几种流行的配置文件格式。其中包括古老的（虽然有时定义不明确）INI 格式，虽然流行但有时难以手写的 JSON 格式，使用广泛但有时在细节方面令人意外的 YAML 格式，以及很多人还没有听说过的最新出现的 TOML。

你的首要任务是选择一种格式，然后记录该选择。解决了这个简单的部分之后就是时候解析配置了。

有时，在配置中拥有一个与“抽象“数据相对应的类是一个不错的想法。因为这段代码不会对配置做任何事情，所以这是展示解析逻辑最简单的方式。

想象一下文件处理器的配置：它包括一个输入目录、一个输出目录和要提取的文件。

配置类的抽象定义可能类似于：

```
from __future__ import annotations

```

```
import attr

@attr.frozen
class Configuration:
    @attr.frozen
    class Files:
        input_dir: str
        output_dir: str
    files: Files
    @attr.frozen
    class Parameters:
        patterns: List[str]
    parameters: Parameters

```

为了使特定于格式的代码更简单，你还需要编写一个函数来从字典中解析此类。请注意，这假设配置将使用破折号，而不是下划线。 这种差异并不少见。

```
def configuration_from_dict(details):
    files = Configuration.Files(
        input_dir=details["files"]["input-dir"],
        output_dir=details["files"]["output-dir"],
    )
    parameters = Configuration.Paraneters(
        patterns=details["parameters"]["patterns"]
    )
    return Configuration(
        files=files,
        parameters=parameters,
    )

```

### JSON

JSON（JavaScript Object Notation）是一种类似于 JavaScript 的格式。

以下是 JSON 格式的示例配置：

```
json_config = """
{
    "files": {
        "input-dir": "inputs",
        "output-dir": "outputs"
    },
    "parameters": {
        "patterns": [
            "*.txt",
            "*.md"
        ]
    }
}
"""

```

解析逻辑使用 `json` 模块将 JSON 解析为 Python 的内置数据结构（字典、列表、字符串），然后从字典中创建类：

```
import json
def configuration_from_json(data):
    parsed = json.loads(data)
    return configuration_from_dict(parsed)

```

### INI

INI 格式，最初只在 Windows 上流行，之后成为配置标准格式。

这是与 INI 相同的配置：

```
ini_config="""
[files]
input-dir = inputs
output-dir = outputs

[parameters]
patterns = ['*.txt', '*.md']
"""

```

Python 可以使用内置的 `configparser` 模块解析它。解析器充当类似 `dict` 的对象，因此可以直接传递给 `configuration_from_dict`：

```
import configparser

def configuration_from_ini(data):
    parser = configparser.ConfigParser()
    parser.read_string(data)
    return configuration_from_dict(parser)

```

### YAML

YAML（Yet Another Markup Language）是 JSON 的扩展，旨在更易于手动编写。为了实现了这一点，部分原因是有一个很长的规范。

以下是 YAML 中的相同配置：

```
yaml_config = """
files:
  input-dir: inputs
  output-dir: outputs
parameters:
  patterns:
  - '*.txt'
  - '*.md'
"""

```

要让 Python 解析它，你需要安装第三方模块。最受欢迎的是`PyYAML`（`pip install pyyaml`）。 YAML 解析器还返回可以传递给 `configuration_from_dict` 的内置 Python 数据类型。但是，YAML 解析器需要一个字节流，因此你需要将字符串转换为字节流。

```
import io
import yaml
def configuration_from_yaml(data):
    fp = io.StringIO(data)
    parsed = yaml.safe_load(fp)
    return configuration_from_dict(parsed)

```

### TOML

TOML（Tom's Own Markup Language）旨在成为 YAML 的轻量级替代品。其规范比较短，已经在一些地方流行了（比如 Rust 的包管理器 Cargo 就用它来进行包配置）。

这是与 TOML 相同的配置：

```
toml_config = """
[files]
input-dir = "inputs"
output-dir = "outputs"

[parameters]
patterns = [ "*.txt", "*.md",]
"""

```

为了解析 TOML，你需要安装第三方包。最流行的一种被简单地称为 `toml`。 与 YAML 和 JSON 一样，它返回基本的 Python 数据类型。

```
import toml
def configuration_from_toml(data):
    parsed = toml.loads(data)
    return configuration_from_dict(parsed)

```

### 总结

选择配置格式是一种微妙的权衡。但是，一旦你做出决定，Python 就可以使用少量代码来解析大多数流行的格式。

---

via: <https://opensource.com/article/21/6/parse-configuration-files-python>

作者：[Moshe Zadka](https://opensource.com/users/moshez) 选题：[lujun9972](https://github.com/lujun9972) 译者：[zepoch](https://github.com/zepoch) 校对：[wxy](https://github.com/wxy)

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


硬核观察 #323 REvil：有史以来最大的一次全球勒索软件攻击

Summary: 更多：• 自由软件基金会宣布改进董事会治理的下一步举措 • 著名开源软件被收购后开始收集用户数据

![](/data/attachment/album/202107/05/151859yi9pnl06qhk8kwq0.jpg)

### REvil：有史以来最大的一次全球勒索软件攻击

![](/data/attachment/album/202107/05/151915zxupusecqs30cxjs.jpg)

此次 REvil 通过 Kaseya VSA 供应链进行的勒索攻击已经影响到了 17 个国家的数千客户，大部分都是小型企业。这此事件被称之为“[有史以来最大的一次全球勒索软件攻击](https://apnews.com/article/joe-biden-europe-government-and-politics-technology-business-fc0df4c42f8cd6148bf936ca24bb5cbe)”。Kaseya 公司周五呼吁客户立即关闭他们的 VSA 服务器，并在周日表示，希望在未来几天内推出补丁。据美联社采访的专家称，这些攻击可能是为了利用美国庆祝建国的三天周末。

一个好的迹象是，在过去的 48 小时内，从互联网上可以到达的 Kaseya VSA 实例的数量已经从超过 2200 个下降到最后一次扫描中的[不到 140 个](https://csirt.divd.nl/2021/07/04/Kaseya-Case-Update-2/)。

>
> 正如我们昨天说到的，利用供应链进行的勒索攻击难以防范，也会愈演愈烈。
>
>
>

### 自由软件基金会宣布改进董事会治理的下一步举措

![](/data/attachment/album/202107/05/151940nioipiop99ywiy13.jpg)

FSF 董事会[宣布](https://www.fsf.org/news/fsf-takes-next-step-in-commitment-to-improving-board-governance)，他们聘请了一位专业顾问，以帮助自由软件基金会设计和执行所需的变革。将在半年内实现：一个透明的由社区支持的确定新董事会成员和评估现有董事会成员的过程；一份明确列出所有董事会成员责任的董事会成员协议；一套道德准则，阐明 FSF 的价值观；更加集中和精简的董事会程序。

FSF 董事会还在评估自 2002 年以来对其章程的首次修改建议。这些修订的目标是确保用户自由不会因董事会、成员或敌对法庭的变化而受到影响，特别是关注各种 GPL 许可证的未来。

>
> 作为最老牌的自由软件方面的基金会，FSF 在开放治理方面却并不“先进”，很高兴 FSF 能看到并改进这一点。
>
>
>

### 著名开源软件被收购后开始收集用户数据

![](/data/attachment/album/202107/05/151955n7tulut9yshx4pgg.jpg)

著名开源音频处理软件 Audacity 于两个月前被一家叫作 Muse Group 的公司收购。该公司同时还拥有其它著名音乐电子项目。一个月前其隐私政策的[变化显示](https://fosspost.org/audacity-is-now-a-spyware/)该工具正在收集其用户的数据，并与其他公司共享，同时还将数据发送到俄罗斯。虽然 Audacity 并不是一个手机应用，但程序设计者依然试图利用该软件从用户电脑上获取数据。

在各大开源社区中出现了许多愤怒的回应，GitHub 和 Reddit 上的用户纷纷呼吁尽快分叉该软件。

>
> 当一个开源软件易主之后，对它之前积累的信任需要重新评估。
>
>
>


我在进入技术行业之前的奇怪工作

Summary: 你永远不会知道从你的第一份工作会走到哪里！

你永远不会知道从你的第一份工作会走到哪里！

>
> 你永远不会知道从你的第一份工作会走到哪里！
>
>
>

![Yellow plane flying in the air, Beechcraft D17S](/data/attachment/album/202107/06/112346wptqwcrzgcwrpn2h.jpg "Yellow plane flying in the air, Beechcraft D17S")

在我从事技术工作之前，我做过一些奇怪的工作。

我是一家飞机修理厂的初级助理，这意味着我的工作要在溶剂中清洗肮脏的金属零件（哇，70 年代的事情可和现在不一样）。我在那里最有趣的工作是熨烫涤纶飞机的布料，放到一架正在修理中的漂亮的老式<ruby> 比奇交错式双翼机 <rt>  Beechcraft Staggerwing </rt></ruby>的木制副翼和水平稳定器上。

在大学期间的一个夏天，我在同一个机场的一个团队工作，混合阻燃剂，然后把它注入灭火飞机（“<ruby> <a href="https://worldairphotography.wordpress.com/2016/08/22/air-tanker-history-in-canada-part-one/amp/">  水轰炸机 </a> <rt>  water bomber </rt></ruby>”）。那可能是我做过的最脏的工作了，但是给飞机装载还是挺酷的。有一个离地面约两米的小挡板，你可以在把填充软管连接到接头后把手指伸进去。然后泵上的人启动泵。当你觉得你的手指湿了，就挥手让管理泵的人停止泵。与此同时，在你前方几米处运行的右侧径向引擎噪音极大，螺旋桨吹掉了你身上因混合阻燃剂而积聚的红色粉尘。如果你搞砸了，让飞机装得太满，他们就得滑到一块地方，把货卸在那里，否则他们会太重而无法起飞。

另外两个夏天，我在当地的百事可乐、七喜、Orange Crush 经销商那里工作，给商店和餐馆送一箱箱的软饮料。这绝对是我做过的最重的体力活了。想想看，在一辆手推车上堆放着五层高的木箱，每个木箱里装着一打 750 毫升的软饮料玻璃瓶。想想把它搬到二楼的餐厅，想想那家餐厅每周要运 120 箱……爬 24 次楼，然后又带着所有的空瓶子下来。一辆小卡车上通常会有 300 箱左右的软饮料。我们的工资是按载重计算的，而不是按小时计算的，所以我们的目标是早点完工，然后去海滩。

### 我的技术工作

送苏打水是我大学期间最后一份暑期工作。第二年我毕业了，获得了数学学位，还修了很多计算机课程，尤其是数值分析。我在技术领域的第一份工作，是为一家小型电脑服务咨询公司工作。我用 SPSS 对一些运动钓鱼调查做了一些分析，写了几百行 PL/1，在我们按时间租来的服务部门的 IBM 3800 激光打印机上打印演唱会门票，并开始研究一些程序来分析森林统计数据。我最终为需要林业统计的客户工作，在 20 世纪 80 年代中期成为合伙人。那时我们已经不仅仅是测量树木，也不再使用<ruby> 分时服务部门 <rt>  timesharing bureau </rt></ruby>来进行计算了。我们买了一台 UNIX 小型计算机，我们在 80 年代后期升级到 SUN 工作站网络。

我在一个大型开发项目上工作了一段时间，它的总部设在马来西亚吉隆坡。然后我们买了第一个地理信息系统，在 80 年代末和 90 年代，我的大部分时间都在和我们的客户一起工作，他们需要定制软件来满足他们的业务需求。到了 21 世纪初，我的三个老合伙人都准备退休了，我试图弄明白，我是如何融入我们这个不再是小公司的，大约 200 名员工的长期图景。我们新的员工老板也不明白这一点，2002 年，我来到智利，想看看智利-加拿大自由贸易协定，是否提供了一个合理的机会，把我们的部分业务转移到拉丁美洲。

该业务在 2004 年正式成立。与此同时，加拿大的母公司由于一些投资组合受到严重影响，在 2007-2009 年的经济衰退的情况下，这些投资似乎不再那么明智，它在 2011 年被迫倒闭。然而，那时候，智利子公司还在经营，所以我们原来的雇员和我成了合伙人，通过资产出售买下了它。直到今天，它仍在运行，在社会环境领域做了很多很酷的事情，我经常参与其中，特别是当我可靠的数学和计算背景有用的时候。

作为一个副业，我为一个在印度以买卖赛马为业的人开发和支持一个赛马信息系统。

---

via: <https://opensource.com/article/21/5/weird-jobs-tech>

作者：[Chris Hermansen](https://opensource.com/users/clhermansen) 选题：[lujun9972](https://github.com/lujun9972) 译者：[MM-BCY](https://github.com/MM-BCY) 校对：[wxy](https://github.com/wxy)

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


使用 Tokei 查看有关代码的统计信息

Summary: 了解有关项目编程语言的详细信息。

了解有关项目编程语言的详细信息。

>
> 了解有关项目编程语言的详细信息。
>
>
>

![](/data/attachment/album/202107/06/114306ar6zjnrr92rn2vnz.jpg "A screen of code.")

近来，GitHub 添加了一个小指标来展示项目的细节，包括项目使用的编程语言。在这之前，对一个新的贡献者来说，了解他们感兴趣的项目的信息是较为困难的。

这个补充很有帮助，但是如果您想知道有关本地存储库中项目的相同信息该怎么办呢？ 这正是 [Tokei](https://github.com/XAMPPRocky/tokei) 派上用场的地方。这是一个当你想和精通不同语言的人想要构建一个项目时可以告诉你项目的代码数据的特别有用的工具。

### 探索 Tokei

据其 [README](https://github.com/XAMPPRocky/tokei/blob/master/README.md)，“Tokei 是一个可以展示你的代码数据的程序。Tokei 将会展示文件的数量，和这些文件中不同语言的代码、注释、空白的行数。”它的 v.12.1.0 版本 [elaborates](https://github.com/XAMPPRocky/tokei/releases/tag/v12.1.0) 是这样子介绍的，“Tokei 是一个快速准确的代码分析 CLI 工具和库，可以使你轻松快速地在你的代码库中看到有多少空白、评论和代码行”。它能够识别超过 150 种编程语言。

```
$ ./tokei ~/exa/src ~/Work/wildfly/jaxrs
==================
Language   Files Lines Code Comments Blank
Java        46    6135  4324  945     632
XML         23    5211  4839  473     224
---------------------------------
Rust
Markdown
-----------------------------------
Total

```

### 安装 Tokei

在 Fedora 上安装 Tokei：

```
$ sudo dnf install tokei

```

用 Rust's Cargo 包管理器安装：

```
$ cargo install tokei

```

### 使用 Tokei

要列出当前目录中的代码统计：

```
$ tokei
===============================================================================
 Language            Files        Lines         Code     Comments       Blanks
===============================================================================
 Ada                    10         2840         1681          560          599
 Assembly                4         2508         1509          458          541
 GNU Style Assembly      4         2751         1528          748          475
 Autoconf               16         2294         1153          756          385
 Automake                1           45           34            0           11
 BASH                    4         1895         1602          133          160
 Batch                   2            4            4            0            0
 C                     330       206433       150241        23402        32790
 C Header              342        60941        24682        29143         7116
 CMake                  48         4572         3459          548          565
 C#                      9         1615          879          506          230
 C++                     5          907          599          136          172
 Dockerfile              2           16           10            0            6
 Fish                    1           87           77            5            5
 HTML                    1          545          544            1            0
 JSON                    5         8995         8995            0            0
 Makefile               10          504          293           72          139
 Module-Definition      12         1183         1046           65           72
 MSBuild                 1          141          140            0            1
 Pascal                  4         1443         1016          216          211
 Perl                    2          189          137           16           36
 Python                  4         1257          949          112          196
 Ruby                    1           23           18            1            4
 Shell                  15         1860         1411          222          227
 Plain Text             35        29425            0        26369         3056
 TOML                   64         3180         2302          453          425
 Visual Studio Pro|     30        14597        14597            0            0
 Visual Studio Sol|      6          655          650            0            5
 XML                     1          116           95           17            4
 YAML                    2           81           56           12           13
 Zsh                     1           59           48            8            3
-------------------------------------------------------------------------------
 Markdown               55         4677            0         3214         1463
 |- C                    1            2            2            0            0
 |- Rust                19          336          268           20           48
 |- TOML                23           61           60            0            1
 (Total)                           5076          330         3234         1512
-------------------------------------------------------------------------------
 Rust                  496       210966       188958         5348        16660
 |- Markdown           249        17676         1551        12502         3623
 (Total)                         228642       190509        17850        20283
===============================================================================
 Total                1523       566804       408713        92521        65570
===============================================================================
$

```

下面的命令打印出了支持的语言和拓展：

```
$ tokei -l
ABNF
ABAP
ActionScript
Ada
Agda
Alex
Alloy
Arduino C++
AsciiDoc
ASN.1
ASP
ASP.NET
Assembly
GNU Style Assembly

```

如果你在两个文件夹上运行 `tokei` 并指定其位置作为参数，它将以先入先出的规则打印单个文件的统计数据：

![Running Tokei on two files](/data/attachment/album/202107/06/114317m2uz52zb1foqz5u9.png "Running Tokei on two files")

默认情况下，`tokei` 仅仅输出有关语言的数据，但是使用 `--files` 标记可提供单个文件统计信息：

```
$ tokei ~/exa/src --files
===========================================================================================
 Language                              Files      Lines      Code             Comments     Blanks
===========================================================================================
 Rust                                   54          9339        7070             400       1869
 |- Markdown                            33          1306           0            1165        141
 (Total)                                           10645        7070        1565       2010
-------------------------------------------------------------------------------------------
 /home/ssur/exa/src/theme/default_theme.rs           130         107           0         23
 /home/ssur/exa/src/output/render/times.rs            30          24           0          6
 /home/ssur/exa/src/output/render/users.rs            98          76           0         22
 /home/ssur/exa/src/output/render/size.rs            182         141           3         38
 /home/ssur/exa/src/output/render/octal.rs           116          88           0         28
 /home/ssur/exa/src/output/render/mod.rs              33          20           3         10
 /home/ssur/exa/src/output/render/inode.rs            28          20           0          8
 /home/ssur/exa/src/output/render/links.rs            87          65           0         22
 /home/ssur/exa/src/output/render/groups.rs          123          93           0         30
 |ome/ssur/exa/src/output/render/filetype.rs          31          26           0          5
 /home/ssur/exa/src/output/render/blocks.rs           57          40           0         17
 /home/ssur/exa/src/output/render/git.rs             108          87           0         21
 |/ssur/exa/src/output/render/permissions.rs         204         160           3         41
 /home/ssur/exa/src/output/grid.rs                    67          51           3         13
 /home/ssur/exa/src/output/escape.rs                  26          18           4          4
 /home/ssur/exa/src/theme/lsc.rs                     235         158          39         38
 /home/ssur/exa/src/options/theme.rs                 159         124           6         29
 /home/ssur/exa/src/options/file_name.rs              46          39           0          7
 /home/ssur/exa/src/options/flags.rs                  84          63           6         15
 /home/ssur/exa/src/fs/mod.rs                         10           8           0          2
 /home/ssur/exa/src/fs/feature/mod.rs                 33          25           0          8
-- /home/ssur/exa/src/output/time.rs ---------------------------------------------------------------
 |- Rust                                             215          170          5         40
 |- Markdown                                          28            0         25          3

```

### 总结

我发现使用 `tokei` 来了解我的代码统计数据十分容易。另一个使用 `tokei` 的好处就是它可以用作为一个很容易集成到其他项目的库。访问 Tokei 的 [Crate.io page](https://crates.io/crates/tokei) 和 [Docs.rs](https://docs.rs/tokei/12.1.2/tokei/) 网站来了解其更多用法。如果你想参与其中，你也可以通过它的 [GitHub 仓库](https://github.com/XAMPPRocky/tokei) 来为 Tokei 作贡献。

你是否觉得 Tokei 很有用呢？可以在下方的评论区告诉我们。

---

via: <https://opensource.com/article/21/6/tokei>

作者：[Sudeshna Sur](https://opensource.com/users/sudeshna-sur) 选题：[lujun9972](https://github.com/lujun9972) 译者：[zepoch](https://github.com/zepoch) 校对：[wxy](https://github.com/wxy)

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


如何用 Rust 编写一个 Linux 内核模块

Rust要支棱起来了。

还是用ada吧

来自广东佛山的 Chrome Mobile 71.0|Android 6.0 用户

为什么内核配置中的General setup  --->Rust support找不到，rustc编译环境已经安装了

有没有解决啊，我的也是这种情况

![](/data/attachment/album/202107/06/123438wl3c1llssams0aa5.jpg)

>
> 编者按：近些年来 Rust 语言由于其内存安全性和性能等优势得到了很多关注，尤其是 Linux 内核也在准备将其集成到其中，因此，我们特邀阿里云工程师苏子彬为我们介绍一下如何在 Linux 内核中集成 Rust 支持。
>
>
>

2021 年 4 月 14 号，一封主题名为《[Rust support](https://lkml.org/lkml/2021/4/14/1023)》的邮件出现在 LKML 邮件组中。这封邮件主要介绍了向内核引入 Rust 语言支持的一些看法以及所做的工作。邮件的发送者是 [Miguel Ojeda](https://ojeda.dev/)，为内核中 Compiler attributes、.clang-format 等多个模块的维护者，也是目前 Rust for Linux 项目的维护者。

Rust for Linux 项目目前得到了 [Google 的大力支持](https://www.zdnet.com/article/rust-in-the-linux-kernel-just-got-a-big-boost-from-google/)，[Miguel Ojeda](https://ojeda.dev/) 当前的全职工作就是负责 Rust for Linux 项目。

长期以来，内核使用 C 语言和汇编语言作为主要的开发语言，部分辅助语言包括 Python、Perl、shell 被用来进行代码生成、打补丁、检查等工作。2016 年 Linux 25 岁生日时，在对 Linus Torvalds 的一篇 [采访](https://www.infoworld.com/article/3109150/linux-at-25-linus-torvalds-on-the-evolution-and-future-of-linux.html)中，他就曾表示过：

>
> 这根本不是一个新现象。我们有过使用 Modula-2 或 Ada 的系统人员，我不得不说 Rust 看起来比这两个灾难要好得多。
>
>
> 我对 Rust 用于操作系统内核并不信服（虽然系统编程不仅限于内核），但同时，毫无疑问，C 有很多局限性。
>
>
>

在最新的对 [Rust support](https://lkml.org/lkml/2021/4/14/1023) 的 RFC 邮件的回复中，他更是说：

>
> 所以我对几个个别补丁做了回应，但总体上我不讨厌它。
>
>
>

没有用他特有的回复方式来反击，应该就是暗自喜欢了吧。

目前 Rust for Linux 依然是一个独立于上游的项目，并且主要工作还集中的驱动接口相关的开发上，并非一个完善的项目。

项目地址： <https://github.com/Rust-for-Linux/linux>

### 为什么是 Rust

在 [Miguel Ojeda](https://ojeda.dev/) 的第一个 RFC 邮件中，他已经提到了 “Why Rust”，简单总结下：

* 在<ruby> 安全子集 <rt>  safe subset </rt></ruby>中不存在未定义行为，包括内存安全和数据竞争；
* 更加严格的类型检测系统能够进一步减少逻辑错误；
* 明确区分 `safe` 和 `unsafe` 代码；
* 更加面向未来的语言：`sum` 类型、模式匹配、泛型、RAII、生命周期、共享及专属引用、模块与可见性等等；
* 可扩展的独立标准库；
* 集成的开箱可用工具：文档生成、代码格式化、linter 等，这些都基于编译器本身。

### 编译支持 Rust 的内核

根据 [Rust for Linux 文档](https://github.com/Rust-for-Linux/linux/blob/rust/Documentation/rust/quick-start.rst)，编译一个包含 Rust 支持的内核需要如下步骤：

1. 安装 `rustc` 编译器。Rust for Linux 不依赖 cargo，但需要最新的 beta 版本的 `rustc`。使用 `rustup`命令安装：

```
rustup default beta-2021-06-23

```
2. 安装 Rust 标准库的源码。Rust for Linux 会交叉编译 Rust 的 `core` 库，并将这两个库链接进内核镜像。

```
rustup component add rust-src

```
3. 安装 `libclang` 库。`libclang` 被 `bindgen` 用做前端，用来处理 C 代码。`libclang` 可以从 [llvm 官方主页](https://github.com/llvm/llvm-project/releases) 下载预编译好的版本。
4. 安装 `bindgen` 工具，`bindgen` 是一个自动将 C 接口转为 RustFFI 接口的库：

```
cargo install --locked --version 0.56.0 bindgen

```
5. 克隆最新的 Rust for Linux 代码：

```
git clone https://github.com/Rust-for-Linux/linux.git

```
6. 配置内核启用 Rust 支持：

```
Kernel hacking
  -> Sample kernel code
    -> Rust samples

```
7. 构建：

```
LIBCLANG_PATH=/path/to/libclang make -j LLVM=1 bzImage

```

这里我们使用 `clang` 作为默认的内核编译器，使用 `gcc` 理论上是可以的，但还处于 [早期实验](https://github.com/Rust-for-Linux/linux/blob/rust/Documentation/rust/quick-start.rst#building) 阶段。

### Rust 是如何集成进内核的

#### 目录结构

为了将 Rust 集成进内核中，开发者首先对 Kbuild 系统进行修改，加入了相关配置项来开启/关闭 Rust 的支持。

此外，为了编译 `rs` 文件，添加了一些 `Makefile` 的规则。这些修改分散在内核目录中的不同文件里。

Rust 生成的目标代码中的符号会因为 `Mangling` 导致其长度超过同样的 C 程序所生成符号的长度，因此，需要对内核的符号长度相关的逻辑进行补丁。开发者引入了 “大内核符号”的概念，用来在保证向前兼容的情况下，支持 Rust 生成的目标文件符号长度。

其他 Rust 相关的代码都被放置在了 `rust` 目录下。

#### 在 Rust 中使用 C 函数

Rust 提供 FFI（<ruby> 外部函数接口 <rt>  Foreign Function Interface </rt></ruby>）用来支持对 C 代码的调用。[Bindgen](https://github.com/rust-lang/rust-bindgen) 是一个 Rust 官方的工具，用来自动化地从 C 函数中生成 Rust 的 FFI 绑定。内核中的 Rust 也使用该工具从原生的内核 C 接口中生成 Rust 的 FFI 绑定。

```
quiet_cmd_bindgen = BINDGEN $@
      cmd_bindgen = \
	$(BINDGEN) $< $(shell grep -v '^\#\|^$$' $(srctree)/rust/bindgen_parameters) \
		--use-core --with-derive-default --ctypes-prefix c_types \
		--no-debug '.*' \
		--size_t-is-usize -o $@ -- $(bindgen_c_flags_final) -DMODULE

$(objtree)/rust/bindings_generated.rs: $(srctree)/rust/kernel/bindings_helper.h \
	$(srctree)/rust/bindgen_parameters FORCE
	$(call if_changed_dep,bindgen)

```

#### ABI

Rust 相关的代码会单独从 `rs` 编译为 `.o`，生成的目标文件是标准的 ELF 文件。在链接阶段，内核的链接器将 Rust 生成的目标文件与其他 C 程序生成的目标文件一起链接为内核镜像文件。因此，只要 Rust 生成的目标文件 ABI 与 C 程序的一致，就可以无差别的被链接（当然，被引用的符号还是要存在的）。

#### Rust 的 `alloc` 与 `core` 库

目前 Rust for Linux 依赖于 `core` 库。在 `core` 中定义了基本的 Rust 数据结构与语言特性，例如熟悉的 `Option<>` 和 `Result<>` 就是 `core` 库所提供。

这个库被交叉编译后被直接链接进内核镜像文件，这也是导致启用 Rust 的内核镜像文件尺寸较大的原因。在未来的工作中，这两个库会被进一步被优化，去除掉某些无用的部分，例如浮点操作，Unicode 相关的内容，Futures 相关的功能等。

之前的 Rust for Linux 项目还依赖于 Rust 的 `alloc` 库。Rust for Linux 定义了自己的 `GlobalAlloc` 用来管理基本的堆内存分配。主要被用来进行堆内存分配，并且使用 `GFP_KERNEL` 标识作为默认的内存分配模式。

不过在在最新的 [拉取请求](https://github.com/Rust-for-Linux/linux/pull/402) 中，社区已经将移植并修改了 Rust的 `alloc` 库，使其能够在尽量保证与 Rust 上游统一的情况下，允许开发者定制自己的内存分配器。不过目前使用自定义的 `GFP_` 标识来分配内存依然是不支持的，但好消息是这个功能正在开发中。

### “Hello World” 内核模块

用一个简单的 Hello World 来展示如何使用 Rust 语言编写驱动代码，`hello_world.rs`:

```
#![no_std]
#![feature(allocator_api, global_asm)]

use kernel::prelude::*;

module! {
    type: HelloWorld,
    name: b"hello_world",
    author: b"d0u9",
    description: b"A simple hello world example",
    license: b"GPL v2",
}

struct HelloWorld;

impl KernelModule for HelloWorld {
    fn init() -> Result<Self> {
        pr_info!("Hello world from rust!\n");

        Ok(HelloWorld)
    }
}

impl Drop for HelloWorld {
    fn drop(&mut self) {
        pr_info!("Bye world from rust!\n");
    }
}

```

与之对应的 `Makefile`：

```
obj-m := hello_world.o

```

构建：

```
make -C /path/to/linux_src M=$(pwd) LLVM=1 modules

```

之后就和使用普通的内核模块一样，使用 `insmod` 工具或者 `modprobe` 工具加载就可以了。在使用体验上是没有区别的。

#### `module! { }` 宏

这个宏可以被认为是 Rust 内核模块的入口，因为在其中定义了一个内核模块所需的所有信息，包括：`Author`、`License`、`Description` 等。其中最重要的是 `type` 字段，在其中需要指定内核模块结构的名字。在这个例子中：

```
module! {
    ...
    type: HelloWorld,
    ...
}

struct HelloWorld;

```

#### `module_init()` 与 `module_exit()`

在使用 C 编写的内核模块中，这两个宏定义了模块的入口函数与退出函数。在 Rust 编写的内核模块中，对应的功能由 `trait KernelModule` 和 `trait Drop` 来实现。`trait KernelModule` 中定义 `init()` 函数，会在模块驱动初始化时被调用；`trait Drop` 是 Rust 的内置 trait，其中定义的 `drop()` 函数会在变量生命周期结束时被调用。

#### 编译与链接

所有的内核模块文件会首先被编译成 `.o` 目标文件，之后由内核链接器将这些 `.o` 文件和自动生成的模块目标文件 `.mod.o` 一起链接成为 `.ko` 文件。这个 `.ko` 文件符合动态库 ELF 文件格式，能够被内核识别并加载。

### 其他

完整的介绍 Rust 是如何被集成进内核的文章可以在 [我的 Github](https://github.com/d0u9/Linux-Device-Driver-Rust/tree/master/00_Introduction_to_Rust_Module_in_Linux) 上找到，由于写的仓促，可能存在一些不足，还请见谅。

---

作者：苏子彬，阿里云 PAI 平台开发工程师，主要从事 Linux 系统及驱动的相关开发，曾为 PAI 平台编写 FPGA 加速卡驱动。


硬核观察 #324 因不满厂商不修复被黑客入侵的游戏，玩家入侵了它的另一款游戏

Summary: 更多：• BSD 中也在“传播”新冠 • Ubuntu 21.10 开始利用 Zstd 压缩软件包

图弄岔了。

![](/data/attachment/album/202107/06/145835sa9cdnrx1hnxntt3.jpg)

### 因不满厂商不修复被黑客入侵的游戏，玩家入侵了它的另一款游戏

![](/data/attachment/album/202107/06/145843ifr8vu0xzhgzmguv.jpg)

2019 年年初，已经发行 5 年的《Titanfall》出现了非常严重的漏洞，黑客可以利用漏洞让其他玩家无法游戏。明知道存在这个严重问题，EA 和 Respawn 也不对其进行修复和完善，而依然在 Steam 和 Origin 上积极销售这款游戏。

因对此不满，一名黑客玩家决定以相同方式入侵该游戏开发商的另一款热门游戏《Apex Legends》，导致大量玩家无法正常游戏。黑客玩家希望能通过这种方式引起公众关注，并向 Respawn 施加压力希望修复《Titanfall》。此后，Respawn 在 Twitter 上承认了这些问题，并表示会“积极调查”这些问题。

>
> 以这种方式取得了关注和可能的解决也是够奇葩的。
>
>
>

### BSD 中也在“传播”新冠

![](/data/attachment/album/202107/06/145901x979ycyy64cbcz6y.jpg)

DragonFlyBSD 从 NetBSD [移植](https://www.phoronix.com/scan.php?page=news_item&px=DragonFlyBSD-COVID)了一个 COVID 软件包。这个软件包包含了 COVID-19 基因组数据，以及鼓励接种疫苗和其他步骤以帮助防止新冠传播的手册页。这个 `covid` 工具是一个简单的 C 程序，它将打印出早已公开的 COVID-19 基因组。NetBSD 的这个 covid 工具是在 Linus Torvalds 最近鼓励大家接种这种冠状病毒的疫苗之后推出的。

>
> 这是技术人的幽默。
>
>
>

### Ubuntu 21.10 开始利用 Zstd 压缩软件包

![](/data/attachment/album/202107/06/145914g4i57h455ee54py0.jpg)

过去三年里，整个 Ubuntu/Debian 生态系统已经有了广泛而成熟的 Zstd 支持，它被添加到 Ubuntu 的 APT 和 dpkg 中，只读压缩支持也被移植到 Ubuntu 16.04 LTS 版本。Ubuntu 将在 Ubuntu 21.10 中[切换](https://balintreczey.hu/blog/hello-zstd-compressed-debs-in-ubuntu/)到 zstd 压缩的 .deb 软件包，但这比最初的计划晚了三年。hello/2.10-2ubuntu3 将会是第一个 zstd 压缩的 Ubuntu 软件包。这是继 Fedora RPM 等发行版本之后，又一个主流发行版利用 Facebook 开发的 [Zstandard](https://engineering.fb.com/2018/12/19/core-data/zstandard/) 压缩技术。

>
> 即便是在 Linux 中，一项没有伤害的新技术的普及也需要漫长的时间。
>
>
>


TIOBE 编程社区指数 20 年

Summary: 2021 年 7 月版的 TIOBE 编程社区指数已经出来了，榜单前几名有点拥挤。

![](/data/attachment/album/202107/07/094722qzde8z6p55slb6sd.jpg)

2021 年 7 月版的 [TIOBE 编程社区指数](https://www.tiobe.com/tiobe-index/)已经出来了，榜单前几名有点拥挤。

该指数首次发布于 2001 年 7 月，当时 TIOBE 首席执行官 Paul Jansen 开始了“一个个人爱好项目，想看看哪些语言有需求”。从那时起，确定一种语言的受欢迎程度（也就是在该指数中的位置）的方法基本保持不变：通过计算列表中的热门搜索引擎的 “+<语言> programming” 的查询的点击率并将其标准化来计算评级。

2004 年，谷歌方式的改变使得 TIOBE 增加了更多的搜索引擎，以减少波动。然而，目前使用的大多数合格的引擎都属于谷歌家族，所以那里的变化仍然会影响整体结果。对该指数的批评往往归结为其意义不大，因为像新版本或临时问题这样的单一事件有可能大大改变排名的结果。

TIOBE 公司成立于 Eindhoven，主要以其 TICS 产品而闻名，这是一个测量软件代码质量的框架。它的名字是“The Importance Of Being Earnest”的缩写，意在反映该公司“真诚和专业的态度”（我们想，这也为奥斯卡•王尔德的鉴赏家提供了一点笑料）。

20 年前，TIOBE 指数的最高排名是由 Java、C 和 C++ 组成的。这与今天的情况没有太大区别，只是 Python 取代了 C++ 的位置，而且这三个顶级竞争者显然比以前更接近。

在连续 15 个月占据最高位置的 C 和排名第三的 Python 之间，这次的差距只有 0.67%。一年前，两者之间的差距约为 7.36%，因此 2020 年的年度语言似乎正处于一个清晰的轨道上。最新一期的 [PYPL 指数](https://pypl.github.io/PYPL.html)已经看到 Python 在那里牢牢占据榜首，它在过去五年中的受欢迎程度增长最快。同时，在 TIOBE 指数中排名第二的 Java 似乎正在继续失去地位。

Jansen [解释](https://www.tiobe.com/tiobe-index/)说 Python 的持续上升与“数据挖掘和人工智能领域的蓬勃发展”有关。然而，这不可能全部的原因，因为像 R、Matlab 和 Julia 这样的语言在该领域也很常见，目前在该榜单中略有回落，要么更多是停滞不前。拥有一个比较成熟的工具生态系统，包括像 NumPy、TensorFlow 和 PyTorch 这样的重量级工具，以及相对稳固的 IDE 支持，肯定有助于 Python 的排名攀升。

除了少数例外，前十名与去年的排名基本保持一致。R 从第 8 位下降到第 12 位，Swift 从第 10 位下降到第 16 位，为中坚力量 PHP 和 SQL 腾出了一点空间。

再往下看，前 30 名中还有一点有趣的变化，Go 从第 20 名爬升到 2 月份的第 13 名。

Rust 也有些许进步，从第 30 位跃升至第 27 位。除其他原因外，这可能是由于人们对 Rust for Linux 项目的兴趣越来越大，该项目旨在为 Linux 内核带来内存安全，并在[最近](https://www.memorysafety.org/blog/supporting-miguel-ojeda-rust-in-linux/)开始获得资金支持。

---

via: <https://devclass.com/2021/07/05/20-years-of-tiobe-programming-community-index-go-gets-a-bounce/>

作者： [Julia Schmidt](https://devclass.com/author/julia/) 选题：[wxy](https://github.com/wxy) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](/article-13553-1.html) 荣誉推出


Jim Hall，你觉得 Fedora 怎么样?

Summary: 我们最近采访了 Jim Hall，了解他是如何使用 Fedora 的。

Fedora稳定么，其实桌面环境最害怕的就是崩溃，Linux比起Windows确实要快速不少

我们最近采访了 Jim Hall，了解他是如何使用 Fedora 的。

![](/data/attachment/album/202107/07/103939pvv8qlv82bq2vs3n.jpg)

我们最近采访了 Jim Hall，了解他是如何使用 Fedora 的。这个 Fedora 杂志 [系列](https://fedoramagazine.org/tag/how-do-you-fedora) 中的一篇。该系列介绍了 Fedora 用户以及他们如何使用 Fedora 来完成任务。如果你对本系列的后继采访感兴趣，请通过 [反馈表](https://fedoramagazine.org/submit-an-idea-or-tip) 与我们联系。

### Jim Hall 是谁？

Jim Hall 曾担任高等教育和政府部门的首席信息官超过 8 年，最近创办了咨询公司 [Hallmentum](https://hallmentum.com/)。他的大部分工作包括培训、研讨会和指导，帮助新的 IT 领导者发展领导技能，也帮助当前的 IT 领导者更好地发挥领导力。除了咨询，Jim 还担任大学的兼职教师，目前教授管理信息系统（MIS）和技术与专业写作课程。

Jim 是如何成长的? Jim 童年时代的英雄来自电视和电影，包括蝙蝠侠和汉索罗。Jim 长期以来最喜欢看的电影是《星球大战：新希望》。Jim 说：“我是一个星球大战迷。”Jim 最喜欢吃意大利菜，“我喜欢意大利菜！我最喜欢的意大利菜可能是炖鸡”。Jim 的观点是，诚实、创造力、想象力、好奇心和开放性是一个人所能拥有的五个好品质。

他喜欢写作，非常好的是他的日常工作主要是写作。他花了很多时间为像 [OpenSource.com](http://OpenSource.com)、 CloudSavvy IT 和 Linux Magazine 等网站撰写“如何”类文章。现在他正在写一本关于 C 编程的书。除了写作，他还玩电子游戏来放松。他有一台 PlayStation 4 游戏机，大多数周六下午他都会坐在电视机前玩游戏。

### Fedora 社区

Jim 从 1993 年开始使用 Linux。他的第一个 Linux 发行版是 Softlanding Linux System（SLS）1.03，运行 Linux 内核 0.99，补丁级别 11。“从那以后，我一直是家里的全职 Linux 用户”。Jim 在很久以前参加了 Fedora Core 时代的一个 Linux 会议之后，开始更多参与到 Fedora 中。Jim 在这遇见了 Tom “Spot” Callaway，他们开始谈论 Fedora。“Spot 鼓励我用另一种方式来做贡献：找到 bug 并报告它们。这就是我参与测试所有 Beta 版本的原因”。

Jim 想在 Fedora 改变什么? 他想在 [getfedora.com](http://getfedora.com) 上看到一个倒计时，告诉大家新的 Beta 版本或新的完整版本是什么时候发布的，这是 Fedora 项目的一个改变。并且 Jim 想让人们都知道，使用 Fedora 是多么容易。“对开源做出贡献最具挑战性的事情是，弄清楚如何做出他们的第一个贡献。”Jim 补充道，“我不知道我和其他开发人员一样是‘Fedora 项目成员’。我只是个用户。但是作为一个从 1993、1994 年就开始参与开发开源软件的人，我努力成为社区中一个有用的成员。因此，我利用一切机会尝试新的 Fedora 版本，甚至是 Beta 版，如果我发现问题，就会告诉大家。”

### 你用什么硬件？

Jim 目前正在运行一台 ThinkCentre M720 Tiny。它配置了第 8 代酷睿 i3-8100T（3.10GHz，6MB 缓存）、32GB（16GB + 16GB）DDR4 2666MHz、英特尔显卡、256GB 固态硬盘 PCIe-NVME Opal M.2、英特尔 8265 802.11AC 和 蓝牙 4.2。他的显示器是华硕 VE248H。 Jim 说：“这一切在Fedora上都很好用！”。

他使用 Perixx Periboard-512 人体工程学经典分体式键盘，它从 1998 年开始取代了他最初的微软 Natural Keyboard Elitee PS/2 键盘。Jim 说： “我有时候会把我的 Perixx 键盘换成 Unicomp 的 IBM Model M USB 克隆键盘。我很喜欢这种带有扣动式弹簧动作的点击式键盘。我的是‘灰白色’，所以它有种经典的外观和感觉”

### 你用什么软件？

Jim 目前运行的是 Fedora 33，之前是 Fedora 33 Beta 和 Fedora 32。Jim 说：“我使用 GNOME 3 作为我的桌面。我发现默认设置适合我的大多数需求，所以我没有加载任何 GNOME 扩展，但我确实使用‘设置’和 ‘GNOME Tweaks’ 调整了一些东西。所以我没有做什么大的改变。例如，我将默认用户界面字体改为使用 Droid Sans Regular 字体。并且我用‘设置’来改变键盘快捷键，用 `Alt-Tab` 键来切换窗口，而不是切换应用程序。我是在 `Alt-Tab` 工作流程中长大的，所以我已经习惯了。”他使用火狐和谷歌浏览器来作为他的 Web 浏览器。

为了经营他的咨询业务，Jim 依赖于一套应用程序：

* 使用 [LibreOffice](https://www.libreoffice.org/) 去写他的书。例如，他去年出版了 《[Coaching Buttons](https://www.amazon.com/Coaching-Buttons-Jim-Hall/dp/0359834930)》，他完全使用 LibreOffice 来写这本书。最近他写了一本关于 [用 C 语言编写 FreeDOS 程序的书](https://www.freedos.org/books/) 也用了 LibreOffice 。
![Libre Office Writer](/data/attachment/album/202107/07/103940h2o923m9fp6mqpgr.png)
* [INKSCAPE](https://inkscape.org/) 为他创建了矢量格式的公司标志。他的标志可以完美地放大缩小，从文件上的小角落图像到大幅面的海报或横幅。并且 INKSCAPE 允许他导出各种通用格式。Jim 说他的广告合作伙伴很欣赏 INKSCAPE 可以输出到EPS（Encapsulated Postscript），这使得在产品上打印他的标志变得很容易。
* [GIMP](https://www.gimp.org/) 用于其他图形，例如闪屏图片。“我的闪屏图片是我们公司的标志被放在了背景照片上，在我需要额外装饰的地方，比如印刷材料，我用它来替代普通标志。我也在我的网站上使用了闪屏图片的一个版本”。
* [QEMU](https://www.qemu.org/) 用来运行虚拟机，在他那里可以启动 [FreeDOS](https://www.freedos.org/)。“我喜欢使用 QEMU，因为我可以在命令行中设置所有需要的选项，这使我在配置虚拟机时有了很大的灵活性。为了更方便，我将所有选项放入到一个脚本中，用它来运行QEMU，每次都是相同的选项”。
![QEMU – running as easy as in FreeDOS](/data/attachment/album/202107/07/103940f6gp6uurpa769aub.png)
* [Scribus](https://www.scribus.net/) 是用来打印产品的。Scribus 很容易用来创建具有“全出血”的印刷品，这意味着任何颜色的背景都会与纸张的边缘重叠。全出血需要一个特殊的打印准备文件，与打印区域重叠。它甚至还提供了切割标记，以便打印机准确地知道要修剪的位置。
![Scribus – Postcard](/data/attachment/album/202107/07/103941o75osu8w4osqe60h.png)

---

via: <https://fedoramagazine.org/jim-hall-how-do-you-fedora/>

作者：[Karimi Hari Priya](https://fedoramagazine.org/author/haripriya21/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[zz-air](https://github.com/zz-air) 校对：[wxy](https://github.com/wxy)

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


Fotoxx：用于管理和编辑大型照片集合的开源应用

![](/data/attachment/album/202107/07/131024ej2kzv824zqb4zz8.jpg)

说到 [Linux 中的照片管理软件](https://itsfoss.com/linux-photo-management-software/)，Shotwell 可能是其中最有名的。难怪它在许多发行版中都预装了。

但是，如果你正在寻找一个类似 Shotwell 而速度更快的应用，Fotoxx 可能是一个不错的选择。

它可能没有一个现代的用户界面，但它在处理大量照片集合时速度很快。这一点很重要，因为索引和显示成千上万张照片的缩略图可能需要相当多的时间和计算资源。

### 用 Fotoxx 在 Linux 中管理照片并编辑它们

![Fotoxx interface](/data/attachment/album/202107/07/131030rwu8189i5uuk4q1w.jpg)

正如你在上面的截图中看到的，它没有漂亮的界面。看起来更像是一个 2010 年左右的应用。它在视觉上的不足，在功能和性能上得到了弥补。

你可以导入大量的照片，包括 RAW 图像。这些图片保持原样。它们不会被复制或移动。它们只是在应用中被索引。

你可以编辑图像元数据，如标签、地理标签、日期、评级、标题等。你可以根据这些元数据来搜索图片。

它还有一个地图功能，可以分组并显示属于某个地点的图片（基于图片上的地理标签数据）。

![Map view](/data/attachment/album/202107/07/131033tkyx47spi4yaaae6.jpg)

由于它专注于管理大型照片集合，有几个批处理功能，可以重命名、调整大小、复制/移动、转换图像格式和编辑元数据。

你可以选择图片来创建相册和幻灯片，所有这些都是在去重图片的情况下进行的。照片可以组合成 360 度的全景图。

Fotoxx 还有几个编辑功能，可以用来修饰图片，添加效果（如素描、绘画）、修剪、旋转等。

还有一些选项可以去除旧的、扫描照片打印件上的红眼和尘斑。

我可以继续列举功能清单，但这太长了。它的网站描述了它的[全部功能](https://kornelix.net/fotoxx/fotoxx.html)，你应该去看看。

### 在 Linux 上安装 Fotoxx

请记住，**Fotoxx 的开发者建议使用一台强大的计算机**，有 4 个以上的 CPU 核心，16GB 以上的内存，以便正常运行。较小的计算机可能会很慢，或可能无法编辑大型图像。

Fotoxx 在大多数 Linux 发行版中都有，如 Debian、Ubuntu、Fedora 和 Arch Linux。只需使用你的发行版的包管理器或软件中心来搜索 Fotoxx 并安装它。

在基于 Ubuntu 和 Debian 的发行版上，你可以使用 apt 命令来安装它，像这样：

```
sudo apt install fotoxx

```

当你第一次运行它时，它会要求搜索主目录中的图像。你可以继续使用它，或者将搜索位置限制在选定的文件夹。

![](/data/attachment/album/202107/07/131035uiivhvds54vvitsh.png)

我注意到，尽管在一分钟左右的时间内索引了 4700 多张，但它并没有立即开始显示图片。我不得不**点击 Gallery->All Folders，然后选择文件夹，然后它就显示了图片**。所以，这一点要记住。

Fotoxx 是一个功能广泛的工具，你需要一些时间来适应它并探索它的[所有功能](https://kornelix.net/fotoxx/fotoxx.html)。它的网站列出了几个例子，你应该看看。

正如我前面所说，它不是最漂亮的应用，但它大量的功能列表可以完成任务。如果你是一个摄影师或有大量的图片收藏，你可以试试 Fotoxx，看看它是否符合你的需要。当你试过后，请在评论区分享你的经验。

---

via: <https://itsfoss.com/fotoxx/>

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


硬核观察 #325 孙正义以 16 亿美元买下了“雅虎”在日本的名称权

Summary: 更多：• 波兰极客用一张软盘运行了最新的 Linux 系统 • 减肥失败的 Firefox Lite 终于胖死了

![](/data/attachment/album/202107/07/153439qlx6wbqff7l11377.jpg)

### 孙正义以 16 亿美元买下了“雅虎”在日本的名称权

![](/data/attachment/album/202107/07/153534tc6ldzz15f5d55cl.jpg)

雅虎曾经是孙正义早期的大笔投资之一，他随后成立了合资公司雅虎日本，随着雅虎出售其核心资产，该公司变成了 Z 控股公司。这次孙正义终于又将雅虎这个名字拿了回来，软银同意以 16 亿美元的价格[购买](https://www.bloomberg.com/news/articles/2021-07-06/the-yahoo-brand-is-still-worth-1-6-billion-to-masayoshi-son)雅虎在日本的名称权。这笔交易是在 Verizon 的媒体部门以 50 亿美元的价格出售给私募股权公司 Apollo 之后进行的。

>
> 雅虎这个传奇的互联网品牌，虽然日暮西山，但总还是有人在意它的。就是不知道雅虎在中国的名称权是不是还有人在意。
>
>
>

### 波兰极客用一张软盘运行了最新的 Linux 系统

![](/data/attachment/album/202107/07/153524j6lzcjglu8oh87om.jpg)

曾经用软盘运行 Linux 操作系统是可行的，但是随着 Linux 越来越复杂，一张软盘已经不足以承载一个 Linux 系统了。一位波兰极客采用最新的 Linux 5.13 内核、BusyBox 将 Linux 放到一张 1.44MB 的 3 英寸[软盘](https://bits.p1x.in/floppinux-an-embedded-linux-on-a-single-floppy/)中，并且可以运行其上的磁盘杂志。当然，这种极度精简的系统所能运行的应用非常有限。感兴趣的同学，可以跟着[教程](https://bits.p1x.in/floppinux-an-embedded-linux-on-a-single-floppy/)做一张自己的软盘 Linux，即便是你没有软驱和软盘，你也可以在 QEMU 中体验一下。

>
> 虽然没有太多的实用价值，但是这种极客乐趣才是最重要的。
>
>
>

### 减肥失败的 Firefox Lite 终于胖死了

![](/data/attachment/album/202107/07/153552dbmf0mfi5o77qd85.jpg)

Firefox Lite 是为 Mozilla 为特定市场提供的精简版本，不过 Mozilla 宣布已经于 6 月 30 日停止支持。2017 年它以 Firefox Rocket 名字出现，其重点是运行速度快，同时最大限度地减少数据使用。不幸的是经过多次版本更新，Firefox Lite 到 2020 年已经变得臃肿不堪。Mozilla 表示结束对 Firefox Lite 的开发和支持是因为重新设计的 Firefox 应用程序的速度足以使“精简版”成为多余。

>
> 可见“减肥”有多重要。
>
>
>


如何解析 Bash 程序的配置文件

>
> 将配置文件与代码分离，使任何人都可以改变他们的配置，而不需要任何特殊的编程技巧。
>
>
>

![](/data/attachment/album/202107/08/163606y3287i6c7dqq0223.jpg "bash logo on green background")

将程序配置与代码分离是很重要的。它使非程序员能够改变配置而不需要修改程序的代码。如果是编译好的二进制可执行文件，这对非程序员来说是不可能的，因为它不仅需要访问源文件（我们在开源程序中会这样），而且还需要程序员的技能组合。很少有人有这种能力，而且大多数人都不想学习它。

对于像 Bash 这样的 shell 语言，由于 shell 脚本没有被编译成二进制格式，所以从定义上讲，源码是可以访问的。尽管有这种开放性，但对于非程序员来说，在 shell 脚本中钻研和修改它们并不是一个特别好的主意。即使是经验丰富的开发人员和系统管理员，也会意外地做出一些导致错误或更糟的改变。

因此，将配置项放在容易维护的文本文件中，提供了分离，并允许非程序员编辑配置，而不会有对代码进行意外修改的危险。许多开发者对用编译语言编写的程序都是这样做的，因为他们并不期望用户是开发者。由于许多相同的原因，对解释型 shell 语言这样做也是有意义的。

### 通常的方式

和其他许多语言一样, 你可以为 Bash 程序编写代码，来读取并解析 ASCII 文本的配置文件、读取变量名称并在程序代码执行时设置值。例如，一个配置文件可能看起来像这样：

```
var1=LinuxGeek46
var2=Opensource.com

```

程序将读取文件，解析每一行，并将值设置到每个变量中。

### 源引

Bash 使用一种更简单的方法来解析和设置变量, 叫做<ruby> 源引 <rt>  sourcing </rt></ruby>。从一个可执行的 shell 程序中获取一个外部文件是一种简单的方法，可以将该文件的内容完整地引入 shell 程序中。在某种意义上，这很像编译语言的 `include` 语句，在运行时包括库文件。这样的文件可以包括任何类型的 Bash 代码，包括变量赋值。

（LCTT 译注：对于使用 `source` 或 `.` 命令引入另外一个文件的行为，我们首倡翻译为“源引”。）

像往常一样，演示比解释更容易。

首先，创建一个 `~/bin` 目录（如果它还不存在的话），并将其作为当前工作目录（PWD）。[Linux 文件系统分层标准](http://refspecs.linuxfoundation.org/fhs.shtml) 将 `~/bin` 定义为用户存储可执行文件的适当位置。

在这个目录下创建一个新文件。将其命名为 `main`，并使其可执行：

```
[dboth@david bin]$ touch main
[dboth@david bin]$ chmod +x main
[dboth@david bin]$

```

在这个可执行文件中添加以下内容：

```
#!/bin/bash
Name="LinuxGeek"
echo $Name

```

并执行这个 Bash 程序：

```
[dboth@david bin]$ ./main
LinuxGeek
[dboth@david bin]$

```

创建一个新的文件并命名为 `~/bin/data`。这个文件不需要是可执行的。在其中添加以下信息：

```
# Sourced code and variables
echo "This is the sourced code from the data file."
FirstName="David"
LastName="Both"

```

在 `main` 程序中增加三行，看起来像这样：

```
#!/bin/bash
Name="LinuxGeek"
echo $Name
source ~/bin/data
echo "First name: $FirstName"
echo "LastName: $LastName"

```

重新运行该程序：

```
[dboth@david bin]$ ./main
LinuxGeek
This is the sourced code from the data file.
First name: David
LastName: Both
[dboth@david bin]$

```

关于源引还有一件非常酷的事情要知道。你可以使用一个单点（`.`）作为 `source` 命令的快捷方式。改变 `main` 文件，用 `.` 代替 `source`。

```
#!/bin/bash
Name="LinuxGeek"
echo $Name
. ~/bin/data
echo "First name: $FirstName"
echo "LastName: $LastName"

```

并再次运行该程序。其结果应该与之前的运行完全相同。

### 运行 Bash

每一台使用 Bash 的 Linux 主机（几乎所有主机都是，因为 Bash 是所有发行版的默认 shell），都包括一些优秀的、内置的源引示例。

每当 Bash shell 运行时，它的环境必须被配置成可以使用的样子。有五个主要文件和一个目录用于配置 Bash 环境。它们和它们的主要功能如下：

* `/etc/profile`: 系统级的环境和启动程序
* `/etc/bashrc`: 系统级的函数和别名
* `/etc/profile.d/`: 包含系统级的脚本的目录，用于配置各种命令行工具，如 `vim` 和 `mc` 以及系统管理员创建的任何自定义配置脚本
* `~/.bash_profile`: 用户特定的环境和启动程序
* `~/.bashrc`: 用户特定的别名和函数
* `~/.bash_logout`: 用户特定的命令，在用户注销时执行

试着通过这些文件追踪执行顺序，确定它在非登录 Bash 初始化和登录 Bash 初始化中使用的顺序。我在我的 Linux 培训系列《[使用和管理 Linux：从零到系统管理员](http://www.both.org/?page_id=1183)》的第一卷第 17 章中这样做过。

给你一个提示。这一切都从 `~/.bashrc` 脚本开始。

### 总结

这篇文章探讨了在 Bash 程序中引用代码和变量的方法。这种从配置文件中解析变量的方法是快速、简单和灵活的。它提供了一种将 Bash 代码与变量赋值分开的方法，以使非程序员能够设置这些变量的值。

---

via: <https://opensource.com/article/21/6/bash-config>

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


用 4 天时间，手把手教你成为 Linux 生态贡献者

Summary: 而为了让更多的人能够参与到为 Linux 生态贡献当中，我们将免费开放这场训练营给所有有志于参与 Linux 生态贡献的同学

没提华为我就报名了。我是认真的。

来自223.104.210.184的 Chrome Mobile 77.0|Android 10 用户

你参加不参加跟华为有什么关系，你是沙雕吗？

最下面的奖品是华为资助的233333333

![](/data/attachment/album/202107/08/175008ssgp4m414umpbpuy.jpg)

大家好，我是老王。在过去的十数年里， **Linux 中国**秉承着在中国推广 Linux 生态，让更多的人知道 Linux、了解 Linux 和用上 Linux 生态的理念，我们翻译了大量的开源和技术文章，让更多的人熟悉 Linux、使用 Linux。

而时间过了这么久，我们也在思考，能否有一种方式，除了翻译文章，让大家更好的参与到 Linux 生态的贡献之中，于是 —— **“Linux 应用生态贡献训练营”**诞生了！而为了让更多的人能够参与到为 Linux 生态贡献当中，我们将**免费开放这场训练营给所有有志于参与 Linux 生态贡献的同学**，不仅如此，我们还将为每一位完成训练营任务的同学，**颁发训练营结业证书，并赠送一本 Linux 图书，以奖励他为 Linux 生态贡献的热情。**

我知道你可能有很多问题想要问，就让我一一道来：

### 一、什么是 Linux 应用生态贡献训练营？

提起 Linux 贡献，可能你想到的都是 Linux 内核的贡献者。 Linux 贡献者是整个 Linux 生态中最为出名的，也是最为困难的。 而相比于每个人都去试图做一件困难、且不好做的事情，我更推荐你从软件打包开始贡献，**相比于为内核贡献代码，为 Linux 贡献软件是一个更加简单、低成本参与的活动，你只需要有一台电脑，和一个为 Linux 生态做贡献的心，就可以开始参与！**

![](/data/attachment/album/202107/08/171135kqlw3ddrwrk5l1r8.png)

软件是我们使用操作系统的方式，我们会使用操作系统之上的软件来完成我们的工作，而一个操作系统的繁荣兴盛也难以离开应用软件。 Linux 难以流行的问题也是其上的软件生态不完善。在这种情况下，我们可以通过向发行版仓库中贡献软件来降低 Linux 的使用成本，让发行版用户可以更好的使用对应的发行版。

![](/data/attachment/album/202107/08/171304azakkkpskowkkz8s.jpg)

此外，软件也是我们自己日常的使用工具，你可以想象，如果你有一天，在自己的服务器上，使用 `yum` 命令，安装的一个软件包，背后的打包和维护者就是你自己，你会不会因此感到骄傲呢？

### 二、如何判断你是否适合参与？

就如前面所说，为 Linux 内核贡献是一件不容易的事情，但为 Linux 生态贡献软件，并不复杂，你只需要掌握基本的编程能力（使用过任何一门编程语言编写程序），并且有一颗想要为 Linux 生态贡献的心，就可以参与到本次的训练营中，学习如何为 Linux 生态贡献应用。

除此之外，本次的训练营将会以**直播 + 群内答疑**的形式进行，因此，你需要预留出一些时间来收看直播或后续的录播。为了方便大家的工作和学习，我们将直播时间安排在每天晚上的 **9:00 ~ 10:00 ，每天一个小时，带着大家学 Linux 软件打包**。

除此之外，我们还希望你能：

1. 愿意花时间在推动 Linux 普及上；
2. 愿意投入精力在学习上；
3. 愿意与其他同学一起进步。

### 三、加入以后你将获得什么？

在训练营期间，你将会获得：

1. 老师每天晚上的直播讲学：老师每天晚上 9:00 ～ 10:00 在线为你讲解关于 Linux 打包的各种知识。
2. 手把手教你做贡献：老师将会带着你，手把手学习如何为发行版贡献软件包和代码，让你知道如何为 Linux 生态贡献软件包。
3. 群答疑：除了直播以外，老师还会在群内为你进行群答疑，你有关于 Linux 打包的任何问题，都可以在群内提问，老师会为你答疑解惑。

**当你完成了课程学习，完成每一次任务的打卡后，****你还可以在训练营结营的时候，获得训练营的结业证书和一本 Linux 方面的书籍，帮助你在 Linux 的道路上越走越远。**

### 四、报名信息

#### 学习时间

本次训练营学习时间为 2021 年 7 月 9 日 21 点至 2021 年 7 月 12 日 21 点。

#### 学习内容

* DAY 1：Linux 应用打包基础；
* DAY 2：基于 RPM 的 Linux 应用打包；
* DAY 3：实践 RPM 应用打包；
* DAY 4：实践任务：自行打包一款Linux 应用。

#### 学习形式

本次训练营将会采用**直播授课 + 群内答疑**的形式来完成。

#### 学习内容

本次训练营将会以 RPM 软件系统为基础，为训练营学员教授如何使用为 RPM 软件包生态贡献软件包。

本次训练营内容涵盖理论和实践部分，除了介绍包管理基础，还介绍了软件打包的实践环节。

#### 费用问题

本次训练营为 Linux 中国**免费**训练营，**免费开放**给所有有志于 Linux 应用生态贡献的爱好者参与。**本训练营绝不收费，也无后续收费的课程。**

#### 如何报名

[点击此链接](https://jinshuju.net/f/WJKMrS)即可报名，报名成功后，你将会收到入营信息。

### 五、更多奖励

除了收获 Linux 知识和我们颁发的训练营结业证书外，还有更多奖励。

本次赠书包括：

![](/data/attachment/album/202107/08/173812mee9q0qj509100bi.jpg)

此外，为了激励大家更好的参与训练营学习，我们还和 openEuler 社区达成合作，可以推荐成员参与 openEuler 社区贡献打榜赛，贡献应用者有机会赢得 **HUAWEI nova 8、HUAWEI WATCH GT 2 Pro 新年款、HUAWEI FreeBuds Pro 真无线耳机、树莓派 4B 官方配件基础套餐**和 **openEuler 社区纪念品。**


硬核观察 #326 法官发布临时禁令，要求勒索团伙不得发布窃取的数据

Summary: 更多：• 诉讼称谷歌曾试图扼杀三星 Galaxy 应用商店 • Visa 与 50 多家加密货币公司达成支付合作

![](/data/attachment/album/202107/08/190159hi6spzfpqlandppp.jpg)

### 法官发布临时禁令，要求勒索团伙不得发布窃取的数据

![](/data/attachment/album/202107/08/190221actb77m8u7k578k3.jpg)

某知名商业律师事务所在 6 月 12 日遭到网络攻击，不少私人数据因此被泄露。但近日该公司赢得了一项[法庭禁令](https://www.judiciary.uk/judgments/new-square-limited-v-person-or-persons-unknown-privacy-order/)，禁止网络犯罪分子使用、公布或向任何一方传达有关被盗数据或其部分内容。不过在暗网黑客论坛上似乎还没有黑客泄露任何相关的数据。

>
> 真是奇葩的法庭禁令。
>
>
>

### 诉讼称谷歌曾试图扼杀三星 Galaxy 应用商店

![](/data/attachment/album/202107/08/190233a4rrlrrb1ihp9n0h.jpg)

在美国三十几个州的总检察长组成的联盟提起的反垄断诉讼中，指控谷歌非法试图控制 Android 系统的应用分发。诉讼称谷歌使用与 Android 手机制造商的收入分成协议，“直接禁止”预装其他一些应用商店，并且它“试图直接付钱给三星，让它放弃与顶级开发商的关系。”该诉讼还称，谷歌贿赂应用程序开发人员，以阻止他们在其它 Android 应用商店上架。

这些指控挑战了谷歌对其政策的核心辩护之一，即与苹果的 iOS 规则不同，Android 系统既允许竞争性应用商店，也允许侧载应用。该诉讼声称这种开放性是一个幌子。

谷歌称这是“一场无视 Android 系统开放性的毫无意义的诉讼。……你可以选择从竞争对手的应用商店或直接从开发者的网站下载该应用。我们没有像其他移动操作系统那样施加限制”。

>
> 到底谷歌的开放性是真的还是假的呢？
>
>
>

### Visa 与 50 多家加密货币公司达成支付合作

![](/data/attachment/album/202107/08/190240b2ab4u9isfhai2i3.jpg)

2021 上半年，与加密货币相关的 Visa 卡支付已超过 10 亿美元。周三的时候，Visa 宣布正在与包括 FTX 和 Coinbase 在内的 50 多家加密货币企业展开合作，以允许用户在全球 7000 万商户轻松转换和使用加密货币。商户不需要做出任何改变，相关交易与 Visa 的其它业务没有任何不同。这意味着，即使在那些不接受加密货币的商户，用户也可顺畅地使用 Visa 提供的相关支付服务。

>
> 这种支付机构对加密货币的支持是对加密货币的普及的有力支持。
>
>
>


如何在 Go 中嵌入 Python

Summary: 在 Go 应用程序中嵌入 Python 的原因有很多

在 Go 应用程序中嵌入 Python 的原因有很多

![](/data/attachment/album/202107/09/123330cgk3ktfu3y3qtyy7.png)

如果你看一下 [新的 Datadog Agent](https://github.com/DataDog/datadog-agent/)，你可能会注意到大部分代码库是用 Go 编写的，尽管我们用来收集指标的检查仍然是用 Python 编写的。这大概是因为 Datadog Agent 是一个 [嵌入了](https://docs.python.org/2/extending/embedding.html) CPython 解释器的普通 Go 二进制文件，可以在任何时候按需执行 Python 代码。这个过程通过抽象层来透明化，使得你可以编写惯用的 Go 代码而底层运行的是 Python。

在 Go 应用程序中嵌入 Python 的原因有很多：

* 它在过渡期间很有用；可以逐步将现有 Python 项目的部分迁移到新语言，而不会在此过程中丢失任何功能。
* 你可以复用现有的 Python 软件或库，而无需用新语言重新实现。
* 你可以通过加载去执行常规 Python 脚本来动态扩展你软件，甚至在运行时也可以。

理由还可以列很多，但对于 Datadog Agent 来说，最后一点至关重要：我们希望做到无需重新编译 Agent，或者说编译任何内容就能够执行自定义检查或更改现有检查。

嵌入 CPython 非常简单，而且文档齐全。解释器本身是用 C 编写的，并且提供了一个 C API 以编程方式来执行底层操作，例如创建对象、导入模块和调用函数。

在本文中，我们将展示一些代码示例，我们将会在与 Python 交互的同时继续保持 Go 代码的惯用语，但在我们继续之前，我们需要解决一个间隙：嵌入 API 是 C 语言，但我们的主要应用程序是 Go，这怎么可能工作？

![](/data/attachment/album/202107/09/123332ok9ofot98a8unobk.png)

### 介绍 cgo

有 [很多好的理由](https://dave.cheney.net/2016/01/18/cgo-is-not-go) 说服你为什么不要在堆栈中引入 cgo，但嵌入 CPython 是你必须这样做的原因。[cgo](https://golang.org/cmd/cgo/) 不是语言，也不是编译器。它是 <ruby> <a href="https://en.wikipedia.org/wiki/Foreign_function_interface">  外部函数接口 </a> <rt>  Foreign Function Interface </rt></ruby>（FFI），一种让我们可以在 Go 中使用来调用不同语言（特别是 C）编写的函数和服务的机制。

当我们提起 “cgo” 时，我们实际上指的是 Go 工具链在底层使用的一组工具、库、函数和类型，因此我们可以通过执行 `go build` 来获取我们的 Go 二进制文件。下面是使用 cgo 的示例程序：

```
package main

// #include <float.h>
import "C"
import "fmt"

func main() {
    fmt.Println("Max float value of float is", C.FLT_MAX)
}

```

在这种包含头文件情况下，`import "C"` 指令上方的注释块称为“<ruby> 序言 <rt>  preamble </rt></ruby>”，可以包含实际的 C 代码。导入后，我们可以通过“C”伪包来“跳转”到外部代码，访问常量 `FLT_MAX`。你可以通过调用 `go build` 来构建，它就像普通的 Go 一样。

如果你想查看 cgo 在这背后到底做了什么，可以运行 `go build -x`。你将看到 “cgo” 工具将被调用以生成一些 C 和 Go 模块，然后将调用 C 和 Go 编译器来构建目标模块，最后链接器将所有内容放在一起。

你可以在 [Go 博客](https://blog.golang.org/c-go-cgo) 上阅读更多有关 cgo 的信息，该文章包含更多的例子以及一些有用的链接来做进一步了解细节。

现在我们已经了解了 cgo 可以为我们做什么，让我们看看如何使用这种机制运行一些 Python 代码。

![](/data/attachment/album/202107/09/123332swrpoxxox6xxhx0u.png)

### 嵌入 CPython：一个入门指南

从技术上讲，嵌入 CPython 的 Go 程序并没有你想象的那么复杂。事实上，我们只需在运行 Python 代码之前初始化解释器，并在完成后关闭它。请注意，我们在所有示例中使用 Python 2.x，但我们只需做很少的调整就可以应用于 Python 3.x。让我们看一个例子：

```
package main

// #cgo pkg-config: python-2.7
// #include <Python.h>
import "C"
import "fmt"

func main() {
    C.Py_Initialize()
    fmt.Println(C.GoString(C.Py_GetVersion()))
    C.Py_Finalize()
}

```

上面的例子做的正是下面 Python 代码要做的事：

```
import sys
print(sys.version)

```

你可以看到我们在序言加入了一个 `#cgo` 指令；这些指令被会被传递到工具链，让你改变构建工作流程。在这种情况下，我们告诉 cgo 调用 `pkg-config` 来收集构建和链接名为 `python-2.7` 的库所需的标志，并将这些标志传递给 C 编译器。如果你的系统中安装了 CPython 开发库和 pkg-config，你只需要运行 `go build` 来编译上面的示例。

回到代码，我们使用 `Py_Initialize()` 和 `Py_Finalize()` 来初始化和关闭解释器，并使用 `Py_GetVersion` C 函数来获取嵌入式解释器版本信息的字符串。

如果你想知道，所有我们需要放在一起调用 C 语言 Python API的 cgo 代码都是模板代码。这就是为什么 Datadog Agent 依赖 [go-python](https://github.com/sbinet/go-python) 来完成所有的嵌入操作；该库为 C API 提供了一个 Go 友好的轻量级包，并隐藏了 cgo 细节。这是另一个基本的嵌入式示例，这次使用 go-python：

```
package main

import (
    python "github.com/sbinet/go-python"
)

func main() {
    python.Initialize()
    python.PyRun_SimpleString("print 'hello, world!'")
    python.Finalize()
}

```

这看起来更接近普通 Go 代码，不再暴露 cgo，我们可以在访问 Python API 时来回使用 Go 字符串。嵌入式看起来功能强大且对开发人员友好，是时候充分利用解释器了：让我们尝试从磁盘加载 Python 模块。

在 Python 方面我们不需要任何复杂的东西，无处不在的“hello world” 就可以达到目的：

```
# foo.py
def hello():
    """
    Print hello world for fun and profit.
    """
    print "hello, world!"

```

Go 代码稍微复杂一些，但仍然可读：

```
// main.go
package main

import "github.com/sbinet/go-python"

func main() {
    python.Initialize()
    defer python.Finalize()

    fooModule := python.PyImport_ImportModule("foo")
    if fooModule == nil {
        panic("Error importing module")
    }

    helloFunc := fooModule.GetAttrString("hello")
    if helloFunc == nil {
        panic("Error importing function")
    }

    // The Python function takes no params but when using the C api
    // we're required to send (empty) *args and **kwargs anyways.
    helloFunc.Call(python.PyTuple_New(0), python.PyDict_New())
}

```

构建时，我们需要将 `PYTHONPATH` 环境变量设置为当前工作目录，以便导入语句能够找到 `foo.py` 模块。在 shell 中，该命令如下所示：

```
$ go build main.go && PYTHONPATH=. ./main
hello, world!

```

![](/data/attachment/album/202107/09/123333j3ybqtxkxy7lrtqt.png)

### 可怕的全局解释器锁

为了嵌入 Python 必须引入 cgo ，这是一种权衡：构建速度会变慢，垃圾收集器不会帮助我们管理外部系统使用的内存，交叉编译也很难。对于一个特定的项目来说，这些问题是否是可以争论的，但我认为有一些不容商量的问题：Go 并发模型。如果我们不能从 goroutine 中运行 Python，那么使用 Go 就没有意义了。

在处理并发、Python 和 cgo 之前，我们还需要知道一些事情：它就是<ruby> 全局解释器锁 <rt>  Global Interpreter Lock </rt></ruby>，即 GIL。GIL 是语言解释器（CPython 就是其中之一）中广泛采用的一种机制，可防止多个线程同时运行。这意味着 CPython 执行的任何 Python 程序都无法在同一进程中并行运行。并发仍然是可能的，锁是速度、安全性和实现简易性之间的一个很好的权衡，那么，当涉及到嵌入时，为什么这会造成问题呢？

当一个常规的、非嵌入式的 Python 程序启动时，不涉及 GIL 以避免锁定操作中的无用开销；在某些 Python 代码首次请求生成线程时 GIL 就启动了。对于每个线程，解释器创建一个数据结构来存储当前的相关状态信息并锁定 GIL。当线程完成时，状态被恢复，GIL 被解锁，准备被其他线程使用。

当我们从 Go 程序运行 Python 时，上述情况都不会自动发生。如果没有 GIL，我们的 Go 程序可以创建多个 Python 线程，这可能会导致竞争条件，从而导致致命的运行时错误，并且很可能出现分段错误导致整个 Go 应用程序崩溃。

解决方案是在我们从 Go 运行多线程代码时显式调用 GIL；代码并不复杂，因为 C API 提供了我们需要的所有工具。为了更好地暴露这个问题，我们需要写一些受 CPU 限制的 Python 代码。让我们将这些函数添加到前面示例中的 `foo.py` 模块中：

```
# foo.py
import sys

def print_odds(limit=10):
    """
    Print odds numbers < limit
    """
    for i in range(limit):
        if i%2:
            sys.stderr.write("{}\n".format(i))

def print_even(limit=10):
    """
    Print even numbers < limit
    """
    for i in range(limit):
        if i%2 == 0:
            sys.stderr.write("{}\n".format(i))

```

我们将尝试从 Go 并发打印奇数和偶数，使用两个不同的 goroutine（因此涉及线程）：

```
package main

import (
    "sync"

    "github.com/sbinet/go-python"
)

func main() {
    // The following will also create the GIL explicitly
    // by calling PyEval_InitThreads(), without waiting
    // for the interpreter to do that
    python.Initialize()

    var wg sync.WaitGroup
    wg.Add(2)

    fooModule := python.PyImport_ImportModule("foo")
    odds := fooModule.GetAttrString("print_odds")
    even := fooModule.GetAttrString("print_even")

    // Initialize() has locked the the GIL but at this point we don't need it
    // anymore. We save the current state and release the lock
    // so that goroutines can acquire it
    state := python.PyEval_SaveThread()

    go func() {
        _gstate := python.PyGILState_Ensure()
        odds.Call(python.PyTuple_New(0), python.PyDict_New())
        python.PyGILState_Release(_gstate)

        wg.Done()
    }()

    go func() {
        _gstate := python.PyGILState_Ensure()
        even.Call(python.PyTuple_New(0), python.PyDict_New())
        python.PyGILState_Release(_gstate)

        wg.Done()
    }()

    wg.Wait()

    // At this point we know we won't need Python anymore in this
    // program, we can restore the state and lock the GIL to perform
    // the final operations before exiting.
    python.PyEval_RestoreThread(state)
    python.Finalize()
}

```

在阅读示例时，你可能会注意到一个模式，该模式将成为我们运行嵌入式 Python 代码的习惯写法：

1. 保存状态并锁定 GIL。
2. 执行 Python。
3. 恢复状态并解锁 GIL。

代码应该很简单，但我们想指出一个微妙的细节：请注意，尽管借用了 GIL 执行，有时我们通过调用 `PyEval_SaveThread()` 和 `PyEval_RestoreThread()` 来操作 GIL，有时（查看 goroutines 里面）我们对 `PyGILState_Ensure()` 和 `PyGILState_Release()` 来做同样的事情。

我们说过当从 Python 操作多线程时，解释器负责创建存储当前状态所需的数据结构，但是当同样的事情发生在 C API 时，我们来负责处理。

当我们用 go-python 初始化解释器时，我们是在 Python 上下文中操作的。因此，当调用 `PyEval_InitThreads()` 时，它会初始化数据结构并锁定 GIL。我们可以使用 `PyEval_SaveThread()` 和 `PyEval_RestoreThread()` 对已经存在的状态进行操作。

在 goroutines 中，我们从 Go 上下文操作，我们需要显式创建状态并在完成后将其删除，这就是 `PyGILState_Ensure()` 和 `PyGILState_Release()` 为我们所做的。

![](/data/attachment/album/202107/09/123334mfkhcf5xcc5djef1.png)

### 释放 Gopher

在这一点上，我们知道如何处理在嵌入式解释器中执行 Python 的多线程 Go 代码，但在 GIL 之后，另一个挑战即将来临：Go 调度程序。

当一个 goroutine 启动时，它被安排在可用的 `GOMAXPROCS` 线程之一上执行，[参见此处](https://morsmachine.dk/go-scheduler) 可了解有关该主题的更多详细信息。如果一个 goroutine 碰巧执行了系统调用或调用 C 代码，当前线程会将线程队列中等待运行的其他 goroutine 移交给另一个线程，以便它们有更好的机会运行； 当前 goroutine 被暂停，等待系统调用或 C 函数返回。当这种情况发生时，线程会尝试恢复暂停的 goroutine，但如果这不可能，它会要求 Go 运行时找到另一个线程来完成 goroutine 并进入睡眠状态。 goroutine 最后被安排给另一个线程，它就完成了。

考虑到这一点，让我们看看当一个 goroutine 被移动到一个新线程时，运行一些 Python 代码的 goroutine 会发生什么：

1. 我们的 goroutine 启动，执行 C 调用并暂停。GIL 被锁定。
2. 当 C 调用返回时，当前线程尝试恢复 goroutine，但失败了。
3. 当前线程告诉 Go 运行时寻找另一个线程来恢复我们的 goroutine。
4. Go 调度器找到一个可用线程并恢复 goroutine。
5. goroutine 快完成了，并在返回之前尝试解锁 GIL。
6. 当前状态中存储的线程 ID 来自原线程，与当前线程的 ID 不同。
7. 崩溃！

所幸，我们可以通过从 goroutine 中调用运行时包中的 `LockOSThread` 函数来强制 Go runtime 始终保持我们的 goroutine 在同一线程上运行：

```
go func() {
    runtime.LockOSThread()

    _gstate := python.PyGILState_Ensure()
    odds.Call(python.PyTuple_New(0), python.PyDict_New())
    python.PyGILState_Release(_gstate)
    wg.Done()
}()

```

这会干扰调度器并可能引入一些开销，但这是我们愿意付出的代价。

### 结论

为了嵌入 Python，Datadog Agent 必须接受一些权衡：

* cgo 引入的开销。
* 手动处理 GIL 的任务。
* 在执行期间将 goroutine 绑定到同一线程的限制。

为了能方便在 Go 中运行 Python 检查，我们很乐意接受其中的每一项。但通过意识到这些权衡，我们能够最大限度地减少它们的影响，除了为支持 Python 而引入的其他限制，我们没有对策来控制潜在问题：

* 构建是自动化和可配置的，因此开发人员仍然需要拥有与 `go build` 非常相似的东西。
* Agent 的轻量级版本，可以使用 Go 构建标签，完全剥离 Python 支持。
* 这样的版本仅依赖于在 Agent 本身硬编码的核心检查（主要是系统和网络检查），但没有 cgo 并且可以交叉编译。

我们将在未来重新评估我们的选择，并决定是否仍然值得保留 cgo；我们甚至可以重新考虑整个 Python 是否仍然值得，等待 [Go 插件包](https://golang.org/pkg/plugin/) 成熟到足以支持我们的用例。但就目前而言，嵌入式 Python 运行良好，从旧代理过渡到新代理再简单不过了。

你是一个喜欢混合不同编程语言的多语言者吗？你喜欢了解语言的内部工作原理以提高你的代码性能吗？

---

via: <https://www.datadoghq.com/blog/engineering/cgo-and-python/>

作者：[Massimiliano Pippi](https://github.com/masci) 译者：[Zioyi](https://github.com/Zioyi) 校对：[wxy](https://github.com/wxy)

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


硬核观察 #327 OnePlus 承认以“省电”的名义限制了 300 个流行应用的性能

Summary: 更多：• REvil 恶意软件被发现会避开以俄语为主要语言的系统 • 微软 12 个月内已向安全专家支付 1360 万美元漏洞赏金

![](/data/attachment/album/202107/09/170748yau8au0e8ooeue8n.jpg)

### OnePlus 承认以“省电”的名义限制了 300 个流行应用的性能

![](/data/attachment/album/202107/09/170840l5usdfnkizz3kw7n.jpg)

这 300 个流行应用的性能被人为[限制](https://arstechnica.com/gadgets/2021/07/oneplus-admits-to-throttling-phones-after-launch-to-improve-battery-life/)运行在低速核心而不是快速核心上。这些流行应用被加入到了最快核心的黑名单里，而基准测试应用和不知名应用则能充分利用全部性能。测试应用 Geekbench 随后以操纵基准测试的理由移除了 OnePlus 9 和 9 Pro 的测试结果。

OnePlus 之后承认在发售新手机之后收到了部分用户希望改进电池寿命和热管理的反馈，它的研发团队所采取的改进方法是“优化”包括 Chrome 在内的 300 个流行应用的性能。这导致 Chrome 的性能下降了 75-85%。

>
> 我是不会买这种手机的。
>
>
>

### REvil 恶意软件被发现会避开以俄语为主要语言的系统

![](/data/attachment/album/202107/09/170858jeedkeludwfvvoke.jpg)

NBC News 报道称：近期活跃的大规模 REvil 勒索软件活动，被发现会避开俄语等前苏联为主要语言的机器。恶意软件的开发者，似乎不想惹恼俄罗斯当局，否则他们将耗费更长的前期准备时间。目前全球约 1500 家公司受到影响，初步预估其为史上最大规模的勒索软件攻击。有专家建议，可通过在 Windows 计算机上安装俄语虚拟键盘的方式，来防止他们的计算机感染 REvil 恶意软件。

>
> 这就很难说明它们和俄罗斯完全没关系了。
>
>
>

### 微软 12 个月内已向安全专家支付 1360 万美元漏洞赏金

![](/data/attachment/album/202107/09/170913m4ii9kwksxpz8jnn.jpg)

根据目前所有科技厂商公开的赏金金额，微软支付的赏金是最高的。这些赏金是 2020 年 7 月 1 日至 2021 年 6 月 30 日期间发放的，共有 341 名安全专家为 17 个 BUG 悬赏项目提交了 1261 个漏洞。最高的赏金是 20 万美元，是报告微软操作系统虚拟化技术 Hyper-V 中的一个漏洞。平均每个项目平均赏金超过 10000 美元。大多数漏洞报告来自居住在中国、美国和以色列的研究人员。

而在去年同期，微软也支付了差不多的赏金。向 327 名安全研究人员授予了 1370 万美元，用于 15 个漏洞赏金项目的 1226 个漏洞报告。

>
> 微软因系统广泛使用而漏洞被挖掘的最多，微软为此花费的资金还是非常值得的。
>
>
>


Linux 中国倾心打造 — 《Linux 技术图谱》上线

Summary: 我们联合阿里云开发者社区，历时数月，投入十余位专家工程师，共同打造了这份《Linux 技术图谱》。

软广？

![](/data/attachment/album/202107/09/171925x6oh3hmywluw44m1.jpg)

### 想学 Linux 吗？免费的那种

相信你对 Linux 有所了解。Linux 操作系统（发行版），全称 GNU/Linux，是一种免费使用和自由传播的类 UNIX 操作系统。它具有自由、开源、可靠、安全、稳定、多平台等特点。与被更多人所熟知的 Windows 不同的是，Linux 是一套开放源代码的、可以自由传播的类 Unix 操作系统软件。

这样的特点也让 Linux 操作系统在很多场景内都备受欢迎。

但正因为它的“自由、开放”，也让 Linux 的知识点和学习变得复杂琐碎起来。在人人都在快餐学习的时代，怎样去更快捷、系统的学习有关 Linux 的知识？怎么高效的学习 Linux 知识？如何在学习中形成自己的知识脉络？...... 这些都是有志于从事技术工作和改变职业发展道路的你所面临的问题。

### 如何学习 Linux？

如果你对如何学习 Linux 有困惑，感觉到无从着手，不用担心 ，“Linux 中国”开源技术社区十余年如一日地致力于让 Linux 可以在中国更普及，**我们****联合阿里云开发者社区，历时数月，****投入十余位专家工程师，****共同打造了****这份《****Linux 技术图谱****》****，****真正****帮助不懂 Linux** **而又希望学习** **Linux 的你，更好更快的上手 Linux。**

### 什么是《Linux 技术图谱》？

这份《Linux 技术图谱》是由 Linux 中国的各位特聘专家和社区成员，结合自身工作经验和业界习惯，特地制定和研发的一套学习路线。对于 Linux 学习者来说，可以按图索骥，跟随图谱安排进行 Linux 的学习，从一个不懂 Linux 的人，成长为一个懂 Linux、用 Linux ，直至成为以此为专业职业的工程师。

**这份《****Linux 技术图谱****》****涵盖****了《****Linux** **基础知识》****、****《服务器硬件基础》****、****《****Linux** **系统管理进阶》****、****《****Linux 企业****常用服务》****、****《高性能集群负载》****等共计 19 门课程，11 门在线实验室和 5 本电子书，4** **门线上学习训练营内容**，涉及到在技术工作中的绝大多数场景，可以帮助你更好的完成自己的学习和工作。

不仅如此，Linux 中国还为大家制作了相应的视频课程、电子书手册、线上体验实验室，帮助你学好 Linux ，将 Linux 真正落实到你的工作当中去。

**如果现在的你，正面临着如何学习 Linux 的困扰，那就不妨从这份《Linux 技术图谱》开始，好好学习 Linux！**

### 三个理由，让你选择《Linux 技术图谱》

这份《Linux 技术图谱》突出了以下三个特点：

1. **《Linux 技术图谱》由 Linux 中国与阿里巴巴的技术专家共同拟定：**它是由 Linux 中国负责起草，并与阿里巴巴的技术专家多次沟通修改，最终确定下来的技术图谱内容。技术图谱中的内容得到了业界专家的认可，值得学习。
2. **《Linux 技术图谱》所提供的各项资料，均为知名企业的专家工程师撰写：**为了能够让技术图谱更有价值，我们特别邀请了一些曾经或现在任职在知名企业工作的优秀工程师，来与我们共建内容，帮助大家学习 Linux 技术。
3. **《Linux 技术图谱》内容结构丰富立体，可以帮助你更好的学习 Linux：**它提供了学习路线、视频课程、电子书、实验体验，可以让你从观看视频、课后辅导和训练，到掌握 Linux 技能，真正将 Linux 内化为自己的一项技能。

### 免费的？！没错，完全免费！

我们知道很多人在 Linux 学习的路上踩过很多坑。一方面，互联网上充斥着各种良莠不齐的 Linux 培训内容，花了钱，可能还没学到什么东西；另一方面，好不容易碰到一个免费的课程，却发现只是一个付费课程的前奏，刚刚让你看到 Linux 的大门，后续的内容却需要缴纳不菲的费用来学习。

我们知道大家所面临的这些困扰，我们也一直将推广 Linux 作为愿景，所以，我们选择将这份 **Linux 技术图谱以及相关课程、****电子书、实验室****免费开放**给大家，让大家可以放心学习、开心学习，再也不需要全网去找盗版资源了，现在你可以直接在网上免费学习全部的完整课程内容。

此外，我们还邀请课程老师为大家安排了后续的课程训练营活动。如果你对于后续的课程训练营活动感兴趣，可以关注 LInux 中国微信公众号的后续活动。我们将会在后续的活动中，带你学习 Linux，手把手教你掌握 Linux 的奥秘！**这些训练营也是免费的！**

这份《Linux 技术图谱》得到了阿里云开发者社区的大力支持，得以**完全免费**地提供给大家。不仅仅是课程、电子书、实验室，还有后继的训练营，全部完全免费。**之前我们免费推出一些训练营时，也有很多人不敢置信地一再确认是否“完全”免费，没错，就是完全免费！**

### Linux 中国倾心打造的 19 门课程，现在正式上线了

![](/data/attachment/album/202107/09/172037jpvy3w22q3srzcr9.jpg)

[点此进入阿里云技术社区](https://click.aliyun.com/m/1000280751/)，获取完整《[Linux 技术图谱](https://click.aliyun.com/m/1000280751/)》。


如何在 FreeDOS 上归档文件

>
> 虽然有一个 FreeDOS 版的 tar，但 DOS 上事实上的标准归档工具是 Zip 和 Unzip。
>
>
>

![](/data/attachment/album/202107/10/063340wp088ozz1fo9f1e1.jpg "Filing cabinet for organization")

在 Linux 上，你可能熟悉标准的 Unix 归档命令：`tar`。FreeDOS 上也有 `tar` 的版本（还有其他一些流行的归档程序），但 DOS 上事实上的标准归档程序是 Zip 和 Unzip。Zip 和 Unzip 都默认安装在 FreeDOS 1.3 RC4 中。

Zip 文件格式最初是由 PKWARE 的 Phil Katz 在 1989 年为 PKZIP 和 PKUNZIP 这对 DOS 归档工具构思的。Katz 将 Zip 文件的规范作为一个开放标准发布，因此任何人都可以创建 Zip 档案。作为开放规范的结果，Zip 成为 DOS 上的一个标准归档格式。[Info-ZIP](http://infozip.sourceforge.net/) 项目实现了一套开源的 `ZIP` 和 `UNZIP` 程序。

### 对文件和目录进行压缩

你可以在 DOS 命令行中使用 `ZIP` 来创建文件和目录的归档。这是一个方便的方法，可以为你的工作做一个备份，或者发布一个“包”，在未来的 FreeDOS 发布中使用。例如，假设我想为我的项目源码做一个备份，其中包含这些源文件：

![dir](/data/attachment/album/202107/10/063402gfc78b1bf7yrzvqq.png "I'd like to archive these files")

*我想把这些文件归档*

`ZIP` 有大量的命令行选项来做不同的事情，但我最常使用的命令行选项是 `-r` 来处理目录和子目录 *递归*，以及使用 `-9` 来提供可能的最大压缩。`ZIP` 和 `UNZIP` 使用类似 Unix 的命令行，所以你可以在破折号后面组合选项：`-9r` 将提供最大压缩并在 Zip 文件中包括子目录。

![zip](/data/attachment/album/202107/10/063402zjjjy3i3j4dj6176.png "Zipping a directory tree")

*压缩一个目录树*

在我的例子中，`ZIP` 能够将我的源文件从大约 33KB 压缩到大约 22KB，为我节省了 11KB 的宝贵磁盘空间。你可能会得到不同的压缩率，这取决于你给 `ZIP` 的选项，或者你想在 Zip 文件中存储什么文件（以及有多少）。一般来说，非常长的文本文件（如源码）会产生良好的压缩效果，而非常小的文本文件（如只有几行的 DOS “批处理”文件）通常太短，无法很好地压缩。

### 解压文件和目录

将文件保存到 Zip 文件中是很好的，但你最终会需要将这些文件解压到某个地方。让我们首先检查一下我们刚刚创建的 Zip 文件里有什么。为此，使用 `UNZIP`命令。你可以在 `UNZIP`中使用一堆不同的选项，但我发现我只使用几个常用的选项。

要列出一个 Zip 文件的内容，使用 `-l` （“list”） 选项。

![unzip -l](/data/attachment/album/202107/10/063403hwqfq787b8hfmllh.png "Listing the archive file contents with unzip")

*用 unzip 列出归档文件的内容*

该输出允让我看到 Zip 文件中的 14 个条目：13 个文件加上 `SRC` 目录。

如果我想提取整个 Zip 文件，我可以直接使用 `UNZIP` 命令并提供 Zip 文件作为命令行选项。这样就可以从我当前的工作目录开始提取 Zip 文件了。除非我正在恢复某个东西的先前版本，否则我通常不想覆盖我当前的文件。在这种情况下，我希望将 Zip 文件解压到一个新的目录。你可以用 `-d` （“destination”） 命令行选项指定目标路径。

![unzip -d temp](/data/attachment/album/202107/10/063403ham1aqows2ormg1i.png "You can unzip into a destination path with -d")

*你可以用 -d 来解压到目标路径*

有时我想从一个 Zip 文件中提取一个文件。在这个例子中，假设我想提取一个 DOS 可执行程序 `TEST.EXE`。要提取单个文件，你要指定你想提取的 Zip 文件的完整路径。默认情况下，`UNZIP` 将使用 Zip 文件中提供的路径解压该文件。要省略路径信息，你可以添加 `-j`（“junk the path”） 选项。

你也可以组合选项。让我们从 Zip 文件中提取 `SRC\TEST.EXE` 程序，但省略完整路径并将其保存在 `TEMP` 目录下：

![unzip -j](/data/attachment/album/202107/10/063403k9ng88cgsysr8jx8.png "Combining options with unzip")

*unzip 组合选项*

因为 Zip 文件是一个开放的标准，所以我们会今天继续看到 Zip 文件。每个 Linux 发行版都可以通过 Info-ZIP 程序支持 Zip 文件。你的 Linux 文件管理器可能也支持 Zip 文件。在 GNOME 文件管理器中，你应该可以右击一个文件夹并从下拉菜单中选择“压缩”。你可以选择创建一个包括 Zip 文件在内的新的归档文件。

创建和管理 Zip 文件是任何 DOS 用户的一项关键技能。你可以在 Info-ZIP 网站上了解更多关于 `ZIP` 和 `UNZIP` 的信息，或者在命令行上使用 `h`（“帮助”）选项来打印选项列表。

---

via: <https://opensource.com/article/21/6/archive-files-freedos>

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

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


用开源移动应用 PlantNet 来识别花草和树木

Summary: PlantNet 将开源技术与众包知识结合起来，帮助你成为业余植物学家。

PlantNet 将开源技术与众包知识结合起来，帮助你成为业余植物学家。

>
> PlantNet 将开源技术与众包知识结合起来，帮助你成为业余植物学家。
>
>
>

![Fire pink flower in Maggie Valley, NC](/data/attachment/album/202107/10/065440wif6qixz5zfwf557.jpg "Fire pink flower in Maggie Valley, NC")

在我居住的地方很多小路和道路两旁都有花草树木。我所在的社区因其每年的枫树节而闻名，枫树对我来说很容易识别。然而，还有许多其他的树我无法识别名字。花也是如此：蒲公英很容易发现，但我不知道在我的步行道上的野花的名字。

最近，我的妻子告诉我了 PlantNet，一个可以识别这些花草和树木的移动应用。它可以在 iOS 和 Android 上使用，而且是免费的，所以我决定试试。

### 以开源的方式识别植物

我在手机上下载了这个应用程序，开始用它来识别我在村子周围散步时的一些花草和树木。随着我对这个应用的熟悉，我注意到我拍摄的图片（以及其他用户拍摄的图片）是以知识共享署名-相同方式共享（CC-BY-SA）的许可方式共享的。进一步的调查显示，PlantNet 是 [开源](https://github.com/plantnet) 的。如果你喜欢，你可以匿名使用该应用，或者成为社区的注册成员。

根据 [Cos4Cloud](https://cos4cloud-eosc.eu/citizen-science-innovation/cos4cloud-citizen-observatories/plntnet/) 公民科学项目，“PlantNet 是一个参与性的公民科学平台，用于收集、分享和审查基于自动识别的植物观察结果。它的目标是监测植物的生物多样性，促进公众对植物知识的获取”。它使用图像识别技术来清点生物多样性。

该项目的开发始于 2009 年，由法国的植物学家和计算机科学家进行。它最初是一个 [Web 应用](https://identify.plantnet.org/)，而智能手机应用程序于 2013 年推出。该项目是 [Floris'Tic](http://floristic.org/) 倡议的一部分，这是法国的另一个项目，旨在促进植物科学的科学、技术和工业文化。

PlantNet 允许用户利用智能手机的摄像头来收集视觉标本，并由软件和社区进行识别。然后，这些照片将与全世界数百万加入 PlantNet 网络的人分享。

该项目说：“PlantNet 系统的工作原理是，比较用户通过他们寻求鉴定的植物器官（花、果实、叶……）的照片传送的视觉模式。这些图像被分析，并与每天协作制作和充实的图像库进行比较。然后，该系统提供一个可能的物种清单及其插图”。

### 使用 PlantNet

该应用很容易使用。从你的智能手机上的应用图标启动它。

![PlantNet smartphone icon](/data/attachment/album/202107/10/065440t1rz5q54363so544.jpg "PlantNet smartphone icon")

当应用打开时，你会看到你已经在资料库中收集的标本。显示屏底部的相机图标允许你使用你的相机将图片添加到你的照片库。

![Pl@ntnet homescreen](/data/attachment/album/202107/10/065440yeqaa8v9saicwdks.jpg "Pl@ntnet homescreen")

选择“相机”选项，将手机的摄像头对准你想识别的树木或花草。拍完照后，点击与你想识别的标本相匹配的选项（叶、花、树皮、果实等）。

![Selecting plant type to identify](/data/attachment/album/202107/10/065441esvkxxl5l9lx8kvx.jpg "Selecting plant type to identify")

例如，如果你想通过叶子的特征来识别一个标本，请选择**叶子**。PlantNet 对其识别的确定程度进行了分配，从高到低的百分比不等。你还可以使用你的智能手机的 GPS 功能，将位置信息自动添加到你的数据收集中，你还可以添加注释。

![Identified plant](/data/attachment/album/202107/10/065441o0eke0myamiux0ef.jpg "Identified plant")

你可以在你的智能手机上或通过你的用户 ID（如果你创建了一个账户）登录网站，访问你上传的所有观测数据，并跟踪社区是否批准了它们。从网站界面上，你也可以下载 CSV 或电子表格格式的观察记录。

![Pl@ntnet provides user stats](/data/attachment/album/202107/10/065441zu9xf2yyxez0ef6p.jpg "Pl@ntnet provides user stats")

### 很好的户外活动

我特别喜欢 PlantNet 与维基百科的链接，这样我就可以阅读更多关于我收集的植物数据的信息。

目前全球大约有 1200 万 PlantNet 用户，所以数据集一直在增长。该应用是免费使用的，每天最多可以有 500 个请求。它还有一个 API，以 JSON 格式提供数据，所以你甚至可以把 Pl antNet 的视觉识别引擎作为一个 Web 服务使用。

PlantNet 的一个非常好的地方是，它结合了众包知识和开源技术，将用户相互联系起来，并与很好的户外活动联系起来。没有比这更好的理由来支持开源软件了。

关于该应用及其开发者的完整描述可在 [YouTube](https://www.youtube.com/watch?v=W_cBqaPfRFE) 上找到（有法语、英文字幕）。你也可以在 [PlantNet](https://plantnet.org/) 的网站上了解更多该项目。

---

via: <https://opensource.com/article/21/7/open-source-plantnet>

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


硬核观察 #328 测试期间 M1 Mac 的超长电池续航表现曾令苹果高管认为出了 bug

Summary: 更多：• 多数情况下 Windows 11 的 WSL2 的性能几乎与原生 Ubuntu 相同 • 受到抵制后，日本政府取消传真机的计划实际上失败了

新冠期间，我们这把文件直接规定不允许使用网络上报疫情情况只能先传真发送然后纸质送达相关部门。

![](/data/attachment/album/202107/10/075737xt6yykyk0gziyez6.jpg)

### 测试期间 M1 Mac 的超长电池续航表现曾令苹果高管认为出了 bug

![](/data/attachment/album/202107/10/075755ry5v85kb525ykvq5.jpg)

M1 MacBook Air 和 M1 MacBook Pro 带来了扎扎实实的两位数电池续航时间。苹果公司产品营销副总裁在测试期间一度认为，操作系统的电池指示器出了 bug：“当我们看到第一台系统被把玩了几个小时后，电池指示器甚至没有多大动静，我们想‘哦，伙计，那是一个错误，电池指示器坏了’。然后 Tim 在笑着说，‘不，这就是它应该有的样子’，这是很惊人的。”

>
> 这真是出了一个 “bug”，居然能做到性能和续航双开花。
>
>
>

### 多数情况下 Windows 11 的 WSL2 的性能几乎与原生 Ubuntu 相同

![](/data/attachment/album/202107/10/075954sj3a3n3jss6x7xp2.jpg)

近日，外媒 Phoronix 对 Windows 11 的 WSL2 的性能进行了[测试](https://www.phoronix.com/scan.php?page=article&item=windows11-wsl2-preview)。测试表明，对于 CPU 敏感的工作负载，WSL2 的性能与 Ubuntu Linux 本身相当。但在一些情况下，Windows 11 的 WSL2 实现还不如 Windows 10 下的性能好，当然，估计 Windows 11 正式推出时会有改善。尤其是当涉及到 I/O 时，WSL2 的性能往往比裸机 Linux 慢得多，但至少比原来的 WSL1 性能好。

>
> 真是有点忧虑 Windows 会这样“吞噬”了 Linux。
>
>
>

### 受到抵制后，日本政府取消传真机的计划实际上失败了

![](/data/attachment/album/202107/10/075843siuopj908uud0jo8.jpg)

日本的一个促进行政改革的内阁机构决定在本月底前废除传真机的使用，并在日本的各部委和机构改用电子邮件。此举将使更多的人能够在家工作，在冠状病毒大流行期间仍有太多的人去办公室发送和接收传真。然而，在遇到“传真爱好者”官员的抵制后，该计划实际上被[取消](https://www.theguardian.com/world/2021/jul/07/japanese-fax-fans-rally-to-defence-of-much-maligned-machine)了。数以百计的政府办公室非但没有拥抱数字时代，反而为这种备受指责的机器进行辩护，他们担心敏感信息的安全和“对通信环境的焦虑”。日本内阁机构的一名官员说：“尽管许多部委和机构可能已经停止使用传真机，但我不能自豪地说，我们成功地摆脱了大多数传真机。”

>
> 这是越原始越安全么？我看其实还是懒于改变现状的心态吧。
>
>
>


在 Linux 上使用 Tealdeer 替代手册页

Debian Gnu/Linux上开始支持了吗？？

>
> Tealder 是 Rust 版本的 tldr，对常用的命令提供了易于理解的说明信息。
>
>
>

![](/data/attachment/album/202107/11/204638catii1ro21jmjzmi.jpg "computer screen ")

手册页是我开始探索 Linux 时最常用的资源。当然，对于初学者熟悉命令行指令而言，`man` 是最频繁使用的指令。但是手册页中有大量的选项和参数列表，很难被解读，这使得你很难理解你想知道的东西。如果你想要一个更简单的解决方案，有基于例子的输出，我认为 [tldr](https://github.com/tldr-pages/tldr) （<ruby> 太长不读 <rt>  too long dnot's read </rt></ruby>）是最好的选择。

### Tealdeer 是什么?

[Tealdeer](https://github.com/dbrgn/tealdeer) 是 tldr 的一个基于 Rust 的实现。它是一个社区驱动的手册页，给出了非常简单的命令工作原理的例子。Tealdeer 最棒的地方在于它几乎包含了所有你通常会用到的命令。

### 安装 Tealdeer

在 Linux 系统，你可以从软件仓库安装 Tealdeer，比如在 [Fedora](https://src.fedoraproject.org/rpms/rust-tealdeer) 上:

```
$ sudo dnf install tealdeer

```

在 macOS 可以使用 [MacPorts](https://opensource.com/article/20/11/macports) 或者 [Homebrew](https://opensource.com/article/20/6/homebrew-mac)。 同样，你可以使用 Rust 的 Cargo 包管理器来编译和安装此工具:

```
$ cargo install tealdeer

```

### 使用 Tealdeer

输入 `tldr-list` 返回 tldr 所支持的手册页，比如 `touch`、`tar`、`dnf`、`docker`、`zcat`、`zgrep` 等：

```
$ tldr --list
2to3
7z
7za
7zr
[
a2disconf
a2dismod
a2dissite
a2enconf
a2enmod
a2ensite
a2query
[...]

```

使用 `tldr` 跟上具体的命令（比如 `tar` ）能够显示基于示例的手册页，描述了你可以用该命令做的所有选项。

```
$ tldr tar

  Archiving utility.
  Often combined with a compression method, such as gzip or bzip2.
  More information: <https://www.gnu.org/software/tar>.

  [c]reate an archive and write it to a [f]ile:

      tar cf target.tar file1 file2 file3

  [c]reate a g[z]ipped archive and write it to a [f]ile:

      tar czf target.tar.gz file1 file2 file3

  [c]reate a g[z]ipped archive from a directory using relative paths:

      tar czf target.tar.gz --directory=path/to/directory .

  E[x]tract a (compressed) archive [f]ile into the current directory [v]erbosely:

      tar xvf source.tar[.gz|.bz2|.xz]

  E[x]tract a (compressed) archive [f]ile into the target directory:

      tar xf source.tar[.gz|.bz2|.xz] --directory=directory

  [c]reate a compressed archive and write it to a [f]ile, using [a]rchive suffix to determine the compression program:

      tar caf target.tar.xz file1 file2 file3

```

如需控制缓存：

```
$ tldr --update
$ tldr --clear-cache

```

你能够控制 Tealdeer 输出的颜色选项，有三种模式选择：一直、自动、从不。默认选项是自动，但我喜欢颜色提供的额外信息，所以我在我的 `~/.bashrc`文件中增加了这个别名：

```
alias tldr='tldr --color always'

```

### 结论

Tealdeer 的美妙之处在于不需要网络连接就可以使用，只有更新缓存的时候才需要联网。因此，即使你处于离线状态，依然能够查找和学习你新学到的命令。更多信息，请查看该工具的 [说明文档](https://dbrgn.github.io/tealdeer/intro.html)。

你会使用 Tealdeer 么？或者你已经在使用了？欢迎留言让我们知道。

---

via: <https://opensource.com/article/21/6/tealdeer-linux>

作者：[Sudeshna Sur](https://opensource.com/users/sudeshna-sur) 选题：[lujun9972](https://github.com/lujun9972) 译者：[ddl-hust](https://github.com/ddl-hust) 校对：[wxy](https://github.com/wxy)

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


硬核观察 #329 乌克兰从加密货币矿场查封了 3800 台索尼 PS4 主机

Summary: 更多：• 开发人员终于从 Java 8 转向 Java 11 • 广告商花了更多的钱来锁定安卓用户

![](/data/attachment/album/202107/11/221049e2vtwjjjwpct2j6t.jpg)

### 乌克兰从加密货币矿场查封了 3800 台索尼 PS4 主机

![](/data/attachment/album/202107/11/221104p47emm34abnxqx71.jpg)

乌克兰安全局查封了某地的一个大型非法加密货币挖矿矿场，然而，他们在本次执法行动中除了查获到 500 张以上的显卡外，还查获了 3800 台 PS4 游戏机！

因为初代 PS4 集成了具有 18 个计算单元的 GPU，单精度算力在 1.84 TFLOPs 左右；升级后的 PS4 Pro 机型则集成了具有 36 个计算单元的 GPU，算力也提升到了 4.2 TFLOPs 。

>
> 不只是对显卡下手了，连游戏机都不放过。
>
>
>

### 开发人员终于从 Java 8 转向 Java 11

![](/data/attachment/album/202107/11/221144qv35aikau4ka3ud0.jpg)

以前对 Java 社区的[报告](https://sdtimes.com/java/report-java-8-remains-the-most-dominant-version-of-java/)发现，开发人员仍然主要使用 Java 8。但根据 Snyk 的《[2021 年 JVM 生态系统报告](https://snyk.io/jvm-ecosystem-report-2021/)》，今年 61.5% 的受访者在部分生产环境中使用 Java 11，近 12% 的人在使用最新的版本 Java 15。然而，一半的 Java 11 用户仍然在他们的生产环境中使用 Java 8。此外，44% 的开发者在生产中使用免费的 AdoptOpenJDK 发行版作为他们的 JDK 之一，48% 在开发中使用。

>
> 虽然逐步迁移到最新版本了，但是由于运行旧版本 JDK 上的老应用，开发人员还是难以放弃和迁移。
>
>
>

### 广告商花了更多的钱来锁定安卓用户

![](/data/attachment/album/202107/11/221118zbonzzfx33fo5r9o.jpg)

今年 4 月初，苹果公司开始强制要求“应用跟踪透明度”，这让用户可以选择是否可以跨应用程序跟踪。现在，一些广告公司报告说 iOS 的支出降低了，但 Android 的广告支出却增加了 10% 以上。有趣的是，只有大约 66% 的用户真正拒绝了追踪。

>
> 好吧，那就追踪安卓吧，反正谷歌是一家广告公司。
>
>
>


如何在 Ubuntu Linux 上安装 Zlib

thank you

thank you bro

thank you

thanks

very useful!!!thank you

thank you

thank you

thank you

thank you

thanks very very very much

i love you

thank you very much

thank you

thank you!!!

thank you

thank you

![](/data/attachment/album/202107/12/095552ndjee050i099j0j6.jpg)

[Zlib](https://zlib.net/) 是一个用于数据压缩的开源库。

作为使用者，你可能会遇到需要安装 zlib（或 zlib-devel 包）作为另一个应用程序的依赖项的情况。

但问题来了，如果你尝试在 Ubuntu 上安装 zlib，它会抛出 “unable to locate package zlib” 错误。

```
sudo apt install zlib
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package zlib

```

为什么会看到这个 [Ubable to locate package 错误](https://itsfoss.com/unable-to-locate-package-error-ubuntu/)呢？因为没有名为 zlib 的包。

如果你 [使用 apt search 命令](https://itsfoss.com/apt-search-command/)，你会发现有几个包可以让你安装：zlib 1g 和 zlib 1g-dev。当你知道这些后，只需一个 `apt` 命令就可以安装它们。

### 在基于 Ubuntu 的 Linux 发行版上安装 Zlib

打开终端，使用以下命令：

```
sudo apt install zlib1g

```

请记住 `g` 前面的字母是数字 `1`，而不是小写的字母 `L`。很多人在输入命令时都会犯这个错误。

另一个包，zlib 1g-dev 是开发包。只有在你需要时才安装它，否则你应该使用 zlib 1g 包。

```
sudo apt install zlib1g-dev

```

你也可以 [Zlib 网站](https://zlib.net/) 下载源代码并安装它。但是，除非你有充分的理由，否则我不推荐使用源代码方式来安装 zlib。例如，如果你需要最新或特定版本的 zlib，但该版本在发行版的仓库中不可用。

有趣的是，像安装 zlib 这样看似很小的东西可能会变得很麻烦，有两个原因：一个是不同的包名；另一个是包含“隐藏”数字 1，它与小写 L 混淆了。

我希望这个快速提示能帮助到你。随意在评论部分留下你的问题、建议或简单的一句 “thank you”。

---

via: <https://itsfoss.com/install-zlib-ubuntu/>

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

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


在 Linux 命令行中收发 Gmail 邮件

点赞。生命在于折腾。

>
> 即使你用的是诸如 Gmail 的托管邮件服务，你也可以通过 Mutt 在终端里收发电子邮件。
>
>
>

![](/data/attachment/album/202107/12/104952frwgx4oz4xrinbxl.jpg "young woman working on a laptop")

我喜欢在 Linux 终端上读写电子邮件的便捷，因此我是 [Mutt](http://www.mutt.org/) 这个轻量简洁的电子邮件客户端的忠实用户。对于电子邮件服务来说，不同的系统配置和网络接入并不会造成什么影响。这个客户端通常隐藏在我 Linux 终端的 [某个标签页或者某个终端复用器的面板](https://opensource.com/article/21/5/linux-terminal-multiplexer) 上，需要用的时候随时可以调出来，不需要使用的时候放到后台，就不需要在桌面上一直放置一个电子邮件客户端的应用程序。

当今我们大多数人使用的都是托管电子邮件账号，在这种使用场景中并不会与电子邮件协议发生过多的直接交互。而 Mutt（以及更早的 ELM）是在更简单的时代创建的，那时候检查邮件只是对 `uucp` 的调用，以及对 `/var/mail` 的读取。当然 Mutt 也很与时俱进，随着各种流行的协议（如 POP、IMAP、LDAP）出现，它都实现了良好的支持。因此，即使我们使用的是 Gmail 这种邮件服务，也可以与 Mutt 无缝衔接。

如今在大多数情况下，用户都不会拥有自己的电子邮件服务器，大部分用户都会选择 Gmail，因此下文会以 Mutt + Gmail 为例作介绍。如果你比较注重电子邮件隐私，不妨考虑 [ProtonMail](https://protonmail.com) 或者 [Tutanota](https://tutanota.com)，它们都提供完全加密的电子邮件服务。其中 Tutanota 包含很多 [开源组件](https://github.com/tutao/tutanota)，而 ProtonMail 则为付费用户提供 [IMAP 桥接](https://protonmail.com/bridge/)，简化了在非浏览器环境下的邮件访问。不过，很多公司、学校和组织都没有自己的电子邮件服务，而是使用 Gmail 提供的邮件服务，这样一来，大部分用户都会有一个 Gmail 邮箱。

当然，如果你自己就 [拥有电子邮件服务器](https://www.redhat.com/sysadmin/configuring-email-server)，那么使用 Mutt 就更简单了。下面我们开始介绍。

### 安装 Mutt

在 Linux 系统上，一般可以直接从发行版提供的软件库中安装 Mutt，另外需要在家目录中创建一个 `.mutt` 目录以存放配置文件：

```
$ sudo dnf install mutt
$ mkdir ~/.mutt

```

在 MacOS 上，可以通过 [MacPorts](https://opensource.com/article/20/11/macports) 或者 [Homebrew](https://opensource.com/article/20/6/homebrew-mac) 安装；在 Windows 上则可以使用 [Chocolatey](https://opensource.com/article/20/3/chocolatey) 安装。

Mutt 是一个<ruby> 邮件用户代理 <rt>  Mail User Agent </rt></ruby>（MUA），因此它的作用是读取、编写以及向外部邮件池发送邮件。向邮件服务器实际传输邮件是其它应用或邮件服务的工作，尽管它们可以和 Mutt 进行协作，让我们看起来是 Mutt 完成了所有功能，但实际上并非如此。在弄懂了两者之间的区别之后，我们会对 Mutt 的配置更加清楚。

这也是为什么除了 Mutt 之外，我们还需要视乎进行通信的服务种类选择一些辅助应用程序。在本文中我使用的是 IMAP 服务，这可以让我本地的电子邮件副本与电子邮件服务提供商的远程邮件副本保持同步。如果你选择 POP 服务，配置的难度就更下一个台阶了，也无需依赖其它外部工具。我们需要 OfflineIMAP 这个 Python 应用程序来实现 IMAP 的集成，这个应用程序可以在 [它的 GitHub 存储库](https://github.com/OfflineIMAP/offlineimap3) 获取。

OfflineIMAP 目前仍然在从 Python 2 移植到 Python 3，目前需要手动安装，但以后你也可以通过 `python3 -m pip` 命令进行安装。

OfflineIMAP 依赖于 `imaplib2` 库，这个库也在努力开发当中，所以我更喜欢手动安装。同样地，也是通过 Git 将代码库克隆到本地，进入目录后使用 `pip` 安装。

首先安装 `rfc6555` 依赖：

```
$ python3 -m pip install --user rfc6555

```

然后从源码安装 `imaplib2`：

```
$ git clone git@github.com:jazzband/imaplib2.git
$ pushd imaplib2.git
$ python3 -m pip install --upgrade --user .
$ popd

```

最后从源码安装 OfflineIMAP：

```
$ git clone git@github.com:OfflineIMAP/offlineimap3.git
$ pushd offlineimap3.git
$ python3 -m pip install --upgrade --user .
$ popd

```

如果你使用的是 Windows 上的 Cygwin，那么你还需要安装 [Portlocker](https://pypi.org/project/portalocker)。

### 配置 OfflineIMAP

OfflineIMAP 默认使用 `~/.offlineimaprc` 这个配置文件，在它的代码库中会有一个名为 `offlineimap.conf` 的配置模板，可以直接将其移动到家目录下：

```
$ mv offlineimap3.git/offlineimap.conf ~/.offlineimaprc`

```

你可以使用任何文本编辑器打开浏览这个配置文件，它的注释很完善，便于了解各个可用的配置项。

以下是我的 `.offlineimaprc` 配置文件，为了清晰起见，我把其中的注释去掉了。对于你来说其中有些配置项的值可能会略有不同，但或许会为你的配置带来一些启发：

```
[general]
ui = ttyui
accounts = %your-gmail-username%
pythonfile = ~/.mutt/password_prompt.py
fsync = False

[Account %your-gmail-username%]
localrepository = %your-gmail-username%-Local
remoterepository = %your-gmail-username%-Remote
status_backend = sqlite
postsynchook = notmuch new

[Repository %your-gmail-username%-Local]
type = Maildir
localfolders = ~/.mail/%your-gmail-username%-gmail.com
nametrans = lambda folder: {'drafts':  '[Gmail]/Drafts',
                            'sent':    '[Gmail]/Sent Mail',
                            'flagged': '[Gmail]/Starred',
                            'trash':   '[Gmail]/Trash',
                            'archive': '[Gmail]/All Mail',
                            }.get(folder, folder)

[Repository %your-gmail-username%-Remote]
maxconnections = 1
type = Gmail
remoteuser = %your-gmail-username%@gmail.com
remotepasseval = '%your-gmail-API-password%'
## remotepasseval = get_api_pass()
sslcacertfile = /etc/ssl/certs/ca-bundle.crt
realdelete = no
nametrans = lambda folder: {'[Gmail]/Drafts':    'drafts',
                            '[Gmail]/Sent Mail': 'sent',
                            '[Gmail]/Starred':   'flagged',
                            '[Gmail]/Trash':     'trash',
                            '[Gmail]/All Mail':  'archive',
                            }.get(folder, folder)
folderfilter = lambda folder: folder not in ['[Gmail]/Trash',
                                             '[Gmail]/Important',
                                             '[Gmail]/Spam',
                                             ]

```

配置文件里有两个可以替换的值，分别是 `%your-gmail-username%` 和 `%your-gmail-API-password%`。其中第一个值需要替换为 Gmail 用户名，也就是邮件地址中 `@gmail.com` 左边的部分。而第二个值则需要通过双因素身份验证（2FA）后从 Google 获取（即使你在查收邮件时不需要使用 2FA）。

### 为 Gmail 设置双因素身份验证（2FA）

Google 希望用户通过 Gmail 网站收发电子邮件，因此当你在 Gmail 网站以外操作电子邮件时，实际上是被 Google 作为“开发者”看待（尽管你没有进行任何开发工作）。也就是说，Google 会认为你正在创建一个应用程序。要获得开发者层面的应用程序密码，就必须设置双因素身份验证。完成了这个过程以后，就可以获得一个应用程序密码，Mutt 可以通过这个密码在浏览器以外的环境登录到你的电子邮箱中。

为了安全起见，你还可以在 Google 的 [账号安全](https://myaccount.google.com/security) 页面中添加一个用于找回的电子邮件地址。

在账号安全页面中，点击“<ruby> 两步验证 <rt>  2-step Verification </rt></ruby>”开始设置 2FA，设置过程中需要用到一部手机。

激活 2FA 之后，账号安全页面中会出现“<ruby> 应用程序密码 <rt>  App Passwords </rt></ruby>”选项，点击就可以为 Mutt 创建一个新的应用程序密码。在 Google 生成密码之后，将其替换 `.offlineimaprc` 配置文件中的 `%your-gmail-API-password%` 值。

直接将应用程序密码记录在 `.offlineimaprc` 文件中，这种以纯文本形式存储的做法有一定的风险。长期以来我都是这样做的，而且感觉良好，因为我的家目录是加密的。但出于安全考虑，我现在已经改为使用 GnuPG 加密应用程序密码，这部分内容不在本文的讨论范围，关于如何设置 GPG 密码集成，可以参考我的 [另一篇文章](https://opensource.com/article/21/6/enter-invisible-passwords-using-python-module)。

### 在 Gmail 启用 IMAP

在你永远告别 Gmail 网页界面之前，还有最后一件事：你必须启用 Gmail 账户的 IMAP 访问。

在 Gmail 网站页面中，点击右上角的“cog”图标，选择“<ruby> 查看所有设置 <rt>  See all settings </rt></ruby>”。在 Gmail 设置页面中，点击“POP/IMAP”标签页，并选中“<ruby> 启用 IMAP <rt>  enable IMAP </rt></ruby>”，然后保存设置。

现在就可以在浏览器以外访问你的 Gmail 电子邮件了。

### 配置 Mutt

Mutt 的配置过程相对简单。和 [.bashrc](https://opensource.com/article/18/9/handy-bash-aliases)、[.zshrc](https://opensource.com/article/19/9/adding-plugins-zsh)、`.emacs` 这些配置文件一样，网络上有很多优秀的 .muttrc 配置文件可供参照。我自己的 `.muttrc` 配置文件则借鉴了 [Kyle Rankin](https://twitter.com/kylerankin)、[Paul Frields](https://twitter.com/stickster) 等人的配置项和想法。下面列出我的配置文件的一些要点：

```
set ssl_starttls=yes
set ssl_force_tls=yes

set from='tux@example.com'
set realname='Tux Example'

set folder = imaps://imap.gmail.com/
set spoolfile = imaps://imap.gmail.com/INBOX
set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
set smtp_url="smtp://smtp.gmail.com:25"
set move = no
set imap_keepalive = 900
set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"

# Paths
set folder           = ~/.mail
set alias_file       = ~/.mutt/alias
set header_cache     = "~/.mutt/cache/headers"
set message_cachedir = "~/.mutt/cache/bodies"
set certificate_file = ~/.mutt/certificates
set mailcap_path     = ~/.mutt/mailcap
set tmpdir           = ~/.mutt/temp
set signature        = ~/.mutt/sig
set sig_on_top       = yes

# Basic Options
set wait_key = no
set mbox_type = Maildir
unset move               # gmail does that

# Sidebar Patch
set sidebar_visible = yes
set sidebar_width   = 16
color sidebar_new color221 color233

## Account Settings
# Default inbox
set spoolfile = "+example.com/INBOX"

# Mailboxes to show in the sidebar.
mailboxes +INBOX \
          +sent \
          +drafts

# Other special folder
set postponed = "+example.com/drafts"

# navigation
macro index gi "<change-folder>=example.com/INBOX<enter>" "Go to inbox"
macro index gt "<change-folder>=example.com/sent" "View sent"

```

整个配置文件基本是开箱即用的，只需要将其中的 `Tux Example`和 `example.com` 替换为你的实际值，并将其保存为 `~/.mutt/muttrc` 就可以使用了。

### 启动 Mutt

在启动 Mutt 之前，需要先启动 `offlineimap` 将远程邮件服务器上的邮件同步到本地。在首次启动的时候耗时可能会比较长，只需要让它整晚运行直到同步完成就可以了。

在同步完成后，启动 Mutt：

```
$ mutt

```

Mutt 会提示你打开用于管理电子邮件的目录权限，并展示收件箱的视图。

![Mutt email client](/data/attachment/album/202107/12/105003nysa3xy9wzl194n0.png "Mutt email client")

### 学习使用 Mutt

在学习使用 Mutt 的过程中，你可以找到最符合你使用习惯的 `.muttrc` 配置。例如我的 `.muttrc` 配置文件集成了使用 Emacs 编写邮件、使用 LDAP 搜索联系人、使用 GnuPG 对邮件进行加解密、链接获取、HTML 视图等等一系列功能。你可以让 Mutt 做到任何你想让它做到的事情，你越探索，就能发现越多。

---

via: <https://opensource.com/article/21/7/gmail-linux-terminal>

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


硬核观察 #330 SolarWinds 和 Kaseya 攻击动摇了对 SaaS 模式的信心

Summary: 更多：• 针对 Kaseya 的巨大勒索软件攻击可能是完全可以避免的 • Tor 项目希望用 Rust 取代 C 代码

![](/data/attachment/album/202107/12/113623bdv33f5vlih99jp5.jpg)

### SolarWinds 和 Kaseya 攻击动摇了对 SaaS 模式的信心

![](/data/attachment/album/202107/12/113636lnxsxnaxa3uz75a0.jpg)

先是 SolarWinds，现在是 Kaseya。管理服务提供商（MSP）大量使用的 SaaS 软件现在已经成为两次成功的网络攻击的目标。大约 1500 家“下游”企业在他们自己的“上游”供应商被入侵后，现在 MSP 正在[重新评估](https://www.channelinsider.com/managed-services/kaseya-breach-shakes-faith-in-itsm-platforms/)他们管理 IT 的方法。

许多 MSP 特别纠结的决定是，他们应该在多大程度上继续依赖可能被恶意软件破坏的 IT 服务管理平台，而不是建立和保护自己的定制平台。后一种方法对恶意软件没有免疫力，但由于网络犯罪分子越来越多地把精力集中在能够对下游造成更大破坏的平台上，因此可能不太容易成为目标。

>
> 这就和大规模云计算的副作用一样，这种成规模的云服务一旦出问题就是大问题。
>
>
>

### 针对 Kaseya 的巨大勒索软件攻击可能是完全可以避免的

![](/data/attachment/album/202107/12/113653t7634zs7a3uqa7z3.jpg)

据报道，Kaseya 公司的软件在 2018 年至 2019 年期间至少有两次被用来启动勒索软件，而它并没有对其安全策略进行重大反思。

前 Kaseya 员工在接受[采访](https://www.bloomberg.com/news/articles/2021-07-10/kaseya-failed-to-address-security-before-hack-ex-employees-say)时称，他们在 2017 年至 2020 年期间多次警告高管 Kaseya 产品的严重安全缺陷，但该公司并没有真正解决这些问题。该公司使用的是旧代码，实施的是差劲的加密，甚至没有对软件进行常规修补。甚至一名员工声称，他在向高管发送了一份长达 40 页的安全问题简报两周后被解雇。

>
> 如果因此发生的勒索可以向软件供应商索赔，那我想他们可能就会重视了。
>
>
>

### Tor 项目希望用 Rust 取代 C 代码

![](/data/attachment/album/202107/12/113705b4tyejxxhzqgqvhh.jpg)

ZOMG 周二宣布，它将向注重隐私的 Tor 项目提供 67 万美元的资助，以继续开发 Arti，这是一个 Tor 客户端的 Rust 语言实现，它将更可靠、更安全，并且更容易被其他软件使用。Tor 项目联合创始人[说](https://sg.finance.yahoo.com/news/tor-project-receives-670k-zcash-123137966.html)，“根据我们的非正式审计，自 2016 年以来，Tor 大约有一半的安全问题在 Rust 中是不可能出现的，其他许多问题的可能性也会小很多。”

>
> 我们已经看到很多传统的 C 语言开发的项目和软件正在或已经迁移到 Rust 了。
>
>
>


让你的大脑在这个夏天保持忙碌的 7 本开源指南

>
> 下载我们的免费指南之一：开发一个基于 Python 的电子游戏；使用开源工具来让你的生活井井有条；完成家庭自动化项目；或尝试你的树莓派家用实验室。
>
>
>

![](/data/attachment/album/202107/12/225953hynu3qud32s1jn1z.jpg "One chair on a sandy beach")

（LCTT 译注：[opensource.com](http://opensource.com) 的免费电子书需要免费注册一个用户才能下载。）

### 开启一个新的树莓派项目

近十年来，树莓派一直俘获着开源爱好者的心和手。你可以用树莓派做无数的项目，无论是 [监控你的花园](https://opensource.com/article/21/5/monitor-greenhouse-open-source)、[设置家长监控](https://opensource.com/article/21/3/raspberry-pi-parental-control)（尤其是在那些漫长的夏天），甚至从你自己的后院 [跟踪飞机](https://opensource.com/article/21/3/tracking-flights-raspberry-pi)。如果这些很酷的项目激起了你的兴趣，但你的树莓派仍在吃灰，那么你需要下载我们的指南来促使你开始行动。在你知道它之前，你需要学习 [如何管理它们](https://opensource.com/article/21/5/raspberry-pi-cockpit)，因为你将与很多树莓派一起工作！

**下载：《[如何开始使用你的树莓派](https://opensource.com/downloads/raspberry-pi-guide)》**

### 设计你的开源智能家庭

一个聪明且有用的方式去使用树莓派的方式是去设计你的智能家庭。使用家庭助手或其他的开源工具，你的家可以按你自己的设置进行自动化而无需借助第三方平台。作者 [Steve Ovens](https://opensource.com/downloads/home-automation-ebook) 用这本家庭自动化集锦的手写电子书来指导你的每一步工作。

**下载：《[使用开源工具实现家庭自动化的实用指南](https://opensource.com/downloads/home-automation-ebook)》**

### 将事情梳理地井井有条

可能你并没做好准备使得你的家庭完全自动化，但是你可能会对梳理你的思维有兴趣。为什么不从你的 to-do 列表开始呢？在贡献者 [Kevin Sonney](https://opensource.com/users/ksonney) 的生产力指导下，你将会熟悉六个开源工具的使用，从而帮你把事情安排得井井有条。一旦你完成了他的教程，你就会感到事情井井有条，在这个夏天终于有时间放松了。

**下载：《[六个可以将事情梳理地井井有条的开源工具](https://opensource.com/downloads/organization-tools)》**

### 学习如何写代码

电脑无处不在。能吐槽一下很多编程语言对初学者不是很友好吗？

有许多为初学者设计的编程语言。Bash 是 Linux 和 macOS 终端中使用的相同的脚本语言，如果你新开始写代码，Bash 将会是一个伟大的开始。你可以以 [互动的方式学习它](https://opensource.com/article/19/10/learn-bash-command-line-games#bashcrawl)，之后下载我们的电子书以了解更多。

**下载：《[Bash 编程指南](https://opensource.com/downloads/bash-programming-guide)》**

### 用 Python 写一个游戏

另一个初学者喜欢的编程语言是 Python。它不仅受到仅仅学习编码的中小学生的欢迎，还被专业程序员用来做 [网站开发](https://opensource.com/article/18/4/flask)、[视频编辑](https://opensource.com/article/21/2/linux-python-video) 以及 [云端自动化](https://opensource.com/article/19/2/quickstart-guide-ansible)。无论你最终的目标是什么，开始学习 Python 的一个有趣的方式是编写一个自己的游戏。

**下载：《[Python 游戏开发指南](https://opensource.com/downloads/python-gaming-ebook)》**

### 发现使用 Jpuyter 的巧妙方法

为了让 Python 具有交互性且易于分享，Jupyter 项目提供了基于 Web 的发展环境。你可以在“笔记本”文件中写代码，然后将其发送给其他用户，以便他们轻松复制和可视化你所做的。它是代码、文档和演示文稿的完美组合，而且非常灵活。下载 Moshe Zadka 的多方面指南了解更多关于 Jupyter。

**下载：《[使用 Jupyer 的六种惊艳方式](https://opensource.com/downloads/jupyter-guide)》**

### 在你的家庭实验室里尝试 Kubernetes

现在，你已经在你的树莓派上安装了 Linux，已经登录，已设置新用户并 [配置了 sudo](https://opensource.com/article/19/10/know-about-sudo) 使得能够进入管理员模式，你正在 [运行所有你需要的服务](https://opensource.com/article/20/5/systemd-units) 。之后呢？

如果你对 Linux 和服务器管理感到满意，你的下一步可能是云服务。可以读一下 Chris Collins 的电子书，从你的家庭实验室的舒适中了解所有关于容器，吊舱和集群的信息。

**下载: 《[在你的树莓派家庭实验室上运行 Kubernetes](https://opensource.com/downloads/kubernetes-raspberry-pi)》**

### 福利：书籍列表

只工作不休息是不健康的。夏天（或任何季节，它是在你的世界的一部分）假期是为了休息，没有什么比坐在门廊或海滩上读一本好书更休闲人心的。下面是一些最近列出的书，以激发一些想法：

* [8 本供开源技术专家读的书（2021）](https://opensource.com/article/21/6/2021-opensourcecom-summer-reading-list)
* [十几本适合所有年龄段的书](https://opensource.com/article/20/6/summer-reading-list)
* [8 本提升领导力的书籍](https://enterprisersproject.com/article/2021/5/8-leadership-books-self-improvement)
* [6 本必读的云架构书籍](https://www.redhat.com/architect/books-cloud-architects)
* 我们的第一份 [2010 年的书籍列表](https://opensource.com/life/10/8/open-books-opensourcecom-summer-reading-list)

---

via: <https://opensource.com/article/21/7/open-source-guides>

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

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


用 Groovy 解析 JSON 配置文件

>
> 抛开关于是否使用 JSON 作为配置格式的争论，只需学习如何用 Groovy 来解析它。
>
>
>

![](/data/attachment/album/202107/12/232406vpp4qrv6ee5a3erz.jpg "Looking back with binoculars")

应用程序通常包括某种类型的默认或“开箱即用”的状态或配置，以及某种让用户根据自己的需要定制配置的方式。

例如，[LibreOffice Writer](https://www.libreoffice.org/discover/writer/) 通过其菜单栏上的**工具 > 选项**，可以访问诸如用户数据、字体、语言设置等（以及更多的）设置。一些应用程序（如 LibreOffice）提供了一个点选式的用户界面来管理这些设置。有些，像 [Tracker](https://gitlab.gnome.org/GNOME/tracker)（GNOME 的“任务”，用于索引文件）使用 XML 文件。还有一些，特别是基于 JavaScript 的应用，使用 JSON，尽管它有许多人抗议（例如，[这位作者](https://www.lucidchart.com/techblog/2018/07/16/why-json-isnt-a-good-configuration-language/) 和 [这位其他作者](https://medium.com/trabe/stop-using-json-config-files-ab9bc55d82fa)）。

在这篇文章中，我将回避关于是否使用 JSON 作为配置文件格式的争论，并解释如何使用 [Groovy 编程语言](https://groovy-lang.org/) 来解析这类信息。Groovy 以 Java 为基础，但有一套不同的设计重点，使 Groovy 感觉更像 Python。

### 安装 Groovy

由于 Groovy 是基于 Java 的，它也需要安装 Java。你可能会在你的 Linux 发行版的软件库中找到最近的、合适的 Java 和 Groovy 版本。或者，你可以按照其网站上的 [说明](https://groovy.apache.org/download.html) 安装 Groovy。 Linux 用户的一个不错的选择是 [SDKMan](https://sdkman.io/)，你可以使用它来获取 Java、Groovy 和许多其他相关工具的多个版本。 对于本文，我将使用我的发行版的 OpenJDK11 和 SDKMan 的 Groovy 3.0.7。

### 演示的 JSON 配置文件

在这个演示中，我从 [Drupal](https://www.drupal.org/node/2008800) 中截取了这个 JSON 文件，它是 Drupal CMS 使用的主要配置文件，并将其保存在文件 `config.json` 中：

```
{
 "vm": {
  "ip": "192.168.44.44",
  "memory": "1024",
  "synced_folders": [
   {
    "host_path": "data/",
    "guest_path": "/var/www",
    "type": "default"
   }
  ],
  "forwarded_ports": []
 },
 "vdd": {
  "sites": {
   "drupal8": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "box@example.com",
    "site_name": "Drupal 8",
    "site_mail": "box@example.com",
    "vhost": {
     "document_root": "drupal8",
     "url": "drupal8.dev",
     "alias": ["www.drupal8.dev"]
    }
   },
   "drupal7": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "box@example.com",
    "site_name": "Drupal 7",
    "site_mail": "box@example.com",
    "vhost": {
     "document_root": "drupal7",
     "url": "drupal7.dev",
     "alias": ["www.drupal7.dev"]
    }
   }
  }
 }
}

```

这是一个漂亮的、复杂的 JSON 文件，有几层结构，如：

```
<>.vdd.sites.drupal8.account_name

```

和一些列表，如：

```
<>.vm.synced_folders

```

这里，`<>` 代表未命名的顶层。让我们看看 Groovy 是如何处理的。

### 用 Groovy 解析 JSON

Groovy 自带的 `groovy.json` 包，里面有各种很酷的东西。其中最好的部分是 `JsonSlurper` 类，它包括几个 `parse()` 方法，可以将 JSON 转换为 Groovy 的 `Map`，一种根据键值存储的数据结构。

下面是一个简短的 Groovy 程序，名为 `config1.groovy`，它创建了一个 `JsonSlurper` 实例，然后调用其中的 `parse()` 方法来解析文件中的 JSON，并将其转换名为 `config` 的 `Map` 实例，最后将该 map 输出：

```
import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

def config = jsonSlurper.parse(new File('config.json'))

println "config = $config"

```

在终端的命令行上运行这个程序：

```
$ groovy config1.groovy
config = [vm:[ip:192.168.44.44, memory:1024, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 8, site_mail:box@example.com, vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 7, site_mail:box@example.com, vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
$

```

输出显示了一个有两个键的顶层映射：`vm` 和 `vdd`。每个键都引用了它自己的值的映射。注意 `forwarded_ports` 键所引用的空列表。

这很容易，但它所做的只是把东西打印出来。你是如何获得各种组件的呢？下面是另一个程序，显示如何访问存储在 `config.vm.ip` 的值：

```
import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

def config = jsonSlurper.parse(new File('config.json'))

println "config.vm.ip = ${config.vm.ip}"

```

运行它：

```
$ groovy config2.groovy
config.vm.ip = 192.168.44.44
$

```

是的，这也很容易。 这利用了 Groovy 速记，这意味着：

```
config.vm.ip

```

在 Groovy 中等同于：

```
config['vm']['ip']

```

当 `config` 和 `config.vm` 都是 `Map` 的实例，并且都等同于在 Java 中的:

```
config.get("vm").get("ip")

```

仅仅是处理 JSON 就这么多了。如果你想有一个标准的配置并让用户覆盖它呢？在这种情况下，你可能想在程序中硬编码一个 JSON 配置，然后读取用户配置并覆盖任何标准配置的设置。

假设上面的配置是标准的，而用户只想覆盖其中的一点，只想覆盖 `vm` 结构中的 `ip` 和 `memory` 值，并把它放在 `userConfig.json` 文件中:

```
{
 "vm": {
  "ip": "201.201.201.201",
  "memory": "4096",
 }
}

```

你可以用这个程序来做：

```
import groovy.json.JsonSlurper

def jsonSlurper = new JsonSlurper()

// 使用 parseText() 来解析一个字符串，而不是从文件中读取。
// 这给了我们一个“标准配置”
def standardConfig = jsonSlurper.parseText("""
{
 "vm": {
  "ip": "192.168.44.44",
  "memory": "1024",
  "synced_folders": [
   {
    "host_path": "data/",
    "guest_path": "/var/www",
    "type": "default"
   }
  ],
  "forwarded_ports": []
 },
 "vdd": {
  "sites": {
   "drupal8": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "box@example.com",
    "site_name": "Drupal 8",
    "site_mail": "box@example.com",
    "vhost": {
     "document_root": "drupal8",
     "url": "drupal8.dev",
     "alias": ["www.drupal8.dev"]
    }
   },
   "drupal7": {
    "account_name": "root",
    "account_pass": "root",
    "account_mail": "box@example.com",
    "site_name": "Drupal 7",
    "site_mail": "box@example.com",
    "vhost": {
     "document_root": "drupal7",
     "url": "drupal7.dev",
     "alias": ["www.drupal7.dev"]
    }
   }
  }
 }
}
""")

// 打印标准配置
println "standardConfig = $standardConfig"

//读入并解析用户配置信息
def userConfig = jsonSlurper.parse(new File('userConfig.json'))

// 打印出用户配置信息
println "userConfig = $userConfig"

// 一个将用户配置与标准配置合并的函数
def mergeMaps(Map input, Map merge) {
  merge.each { k, v ->
    if (v instanceof Map)
      mergeMaps(input[k], v)
    else
      input[k] = v
  }
}

// 合并配置并打印出修改后的标准配置
mergeMaps(standardConfig, userConfig)

println "modified standardConfig $standardConfig"

```

以下列方式运行：

```
$ groovy config3.groovy
standardConfig = [vm:[ip:192.168.44.44, memory:1024, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 8, site_mail:box@example.com, vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 7, site_mail:box@example.com, vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
userConfig = [vm:[ip:201.201.201.201, memory:4096]]
modified standardConfig [vm:[ip:201.201.201.201, memory:4096, synced_folders:[[host_path:data/, guest_path:/var/www, type:default]], forwarded_ports:[]], vdd:[sites:[drupal8:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 8, site_mail:box@example.com, vhost:[document_root:drupal8, url:drupal8.dev, alias:[www.drupal8.dev]]], drupal7:[account_name:root, account_pass:root, account_mail:box@example.com, site_name:Drupal 7, site_mail:box@example.com, vhost:[document_root:drupal7, url:drupal7.dev, alias:[www.drupal7.dev]]]]]]
$

```

以 `modified standardConfig` 开头的一行显示，`vm.ip` and `vm.memory` 的值被覆盖了。

眼尖的读者会注意到，我没有检查畸形的 JSON，也没有仔细确保用户的配置是有意义的（不创建新字段，提供合理的值，等等）。所以用这个递归方法来合并两个映射在现实中可能并不那么实用。

好吧，我必须为家庭作业留下 *一些* 东西，不是吗？

### Groovy 资源

Apache Groovy 网站有很多很棒的 [文档](http://groovy-lang.org/documentation.html)。另一个很棒的 Groovy 资源是 [Mr. Haki](https://blog.mrhaki.com/)。学习 Groovy 的一个非常好的理由是继续学习 [Grails](https://grails.org/)，它是一个非常高效的全栈 Web 框架，建立在 Hibernate、Spring Boot 和 Micronaut 等优秀组件之上。

---

via: <https://opensource.com/article/21/6/groovy-parse-json>

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


硬核观察 #331 阿里巴巴使用量子计算来保护支付宝的金融交易

Summary: 更多：• 微软的内部 Linux 发行版 CBL-Mariner 发布 1.0 稳定版 • 谷歌的证书授权服务正式可用

![](/data/attachment/album/202107/13/201722o6aymcq0frr6hhpv.jpg)

### 阿里巴巴使用量子计算来保护支付宝的金融交易

![](/data/attachment/album/202107/13/201731vwzvjqh4hnci88ui.jpg)

阿里巴巴拥有自己的 11 量子比特的量子系统和模拟器，这包括一个 32 量子比特的服务，并通过与中国科学院的合作演示了一个 64 量子比特的模拟机。

据他们发表的一篇[论文](https://www.nature.com/articles/s41534-021-00442-x)，利用量子模拟平台，阿里巴巴使用自己的云计算在后处理阶段提供了四种不同类型生成器的随机数生成。这项[量子安全](https://www.nextplatform.com/2021/07/12/alibabas-key-to-cryptosecurity-is-its-own-quantum-platform/)工作已经在生产环境运行了一年多。这听起来可能是一个简单的功能，但它是安全金融交易的关键。与过去的方法相比，量子随机数生成已被证明是最安全的加密方法。

>
> 没想到阿里巴巴已经不声不响地将量子计算用在了保障金融安全上了。
>
>
>

### 微软的内部 Linux 发行版 CBL-Mariner 发布 1.0 稳定版

![](/data/attachment/album/202107/13/201749kv5thspjal5jzaeu.jpg)

微软创建的 Linux 发行版除了 Azure Cloud Switch 以外，还有一个 [CBL-Mariner](https://github.com/microsoft/CBL-Mariner/)（CBL 是 “Common Base Linux”的缩写），这是一个[内部发行版](https://blog.jreypo.io/2021/07/09/a-look-into-cbl-mariner-microsoft-internal-linux-distribution/)，但也是公开和开源的。CBL-Mariner 除了一些预编译的 RPM，没有提供官方的构建版本。它的目标不是成为一个通用的 Linux 发行版，而是让微软的各个工程团队可以用于他们不同的使用情况。它被用于 WSL、Azure Sphere OS、SONiC 以及微软其他基于 Linux 的工作。CBL-Mariner 以安全为重点，利用 RPM 与 DNF 进行软件包管理。

上周，经过几个月的迭代，CBL-Mariner 发布了 [1.0 稳定版](https://github.com/microsoft/CBL-Mariner/releases/tag/1.0-stable)。

>
> 我觉得微软不会发行一个正式的 Linux 发行版吧？不过也难说。
>
>
>

### 谷歌的证书授权服务正式可用

![](/data/attachment/album/202107/13/201809gyzfzg9z7fwww2gq.jpg)

谷歌的[证书授权服务](https://cloud.google.com/blog/products/identity-security/google-cloud-certificate-authority-service-is-now-ga)（CAS）是一项可扩展的服务，用于通过自动化管理和部署私人证书，以及管理公钥基础设施（PKI）。谷歌云 CAS 提供了一个高度可扩展和可用的私有 CA。除了身份管理、加强数据传输的安全性和创建数字签名服务之外，谷歌还将 CAS 用在物联网中作为“随用随付”解决方案。

>
> 但是我还是喜欢 Let's Encrypt 的免费证书。
>
>
>