全功能的二进制文件分析工具 Radare2 指南

Summary: Radare2 是一个为二进制分析定制的开源工具。

十分感谢，介绍的很详细。 Radare2，分析二进制的工具。有时间的话，研究一下

你好，请教一下 ii 命令显示二进制所有导入的库，那个lib字段为啥全是空的？有什么办法把lib字段显示出来吗？

Radare2 是一个为二进制分析定制的开源工具。

>
> Radare2 是一个为二进制分析定制的开源工具。
>
>
>

![](/data/attachment/album/202102/01/112611baw4gpqlch10ps1c.jpg "Binary code on a computer screen")

在《[Linux 上分析二进制文件的 10 种方法](/article-12187-1.html)》中，我解释了如何使用 Linux 上丰富的原生工具集来分析二进制文件。但如果你想进一步探索你的二进制文件，你需要一个为二进制分析定制的工具。如果你是二进制分析的新手，并且大多使用的是脚本语言，这篇文章《[GNU binutils 里的九种武器](/article-11441-1.html)》可以帮助你开始学习编译过程和什么是二进制。

### 为什么我需要另一个工具？

如果现有的 Linux 原生工具也能做类似的事情，你自然会问为什么需要另一个工具。嗯，这和你用手机做闹钟、做笔记、做相机、听音乐、上网、偶尔打电话和接电话的原因是一样的。以前，使用单独的设备和工具处理这些功能 —— 比如拍照的实体相机，记笔记的小记事本，起床的床头闹钟等等。对用户来说，有一个设备来做多件（但相关的）事情是*方便的*。另外，杀手锏就是独立功能之间的*互操作性*。

同样，即使许多 Linux 工具都有特定的用途，但在一个工具中捆绑类似（和更好）的功能是非常有用的。这就是为什么我认为 [Radare2](https://rada.re/n/) 应该是你需要处理二进制文件时的首选工具。

根据其 [GitHub 简介](https://github.com/radareorg/radare2)，Radare2（也称为 r2）是一个“类 Unix 系统上的逆向工程框架和命令行工具集”。它名字中的 “2” 是因为这个版本从头开始重写的，使其更加模块化。

### 为什么选择 Radare2？

有大量（非原生的）Linux 工具可用于二进制分析，为什么要选择 Radare2 呢？我的理由很简单。

首先，它是一个开源项目，有一个活跃而健康的社区。如果你正在寻找新颖的功能或提供着 bug 修复的工具，这很重要。

其次，Radare2 可以在命令行上使用，而且它有一个功能丰富的图形用户界面（GUI）环境，叫做 Cutter，适合那些对 GUI 比较熟悉的人。作为一个长期使用 Linux 的用户，我对习惯于在 shell 上输入。虽然熟悉 Radare2 的命令稍微有一点学习曲线，但我会把它比作 [学习 Vim](https://opensource.com/article/19/3/getting-started-vim)。你可以先学习基本的东西，一旦你掌握了它们，你就可以继续学习更高级的东西。很快，它就变成了肌肉记忆。

第三，Radare2 通过插件可以很好的支持外部工具。例如，最近开源的 [Ghidra](https://ghidra-sre.org/) 二进制分析和<ruby> 逆向工具 <rt>  reversing tool </rt></ruby>很受欢迎，因为它的反编译器功能是逆向软件的关键要素。你可以直接从 Radare2 控制台安装 Ghidra 反编译器并使用，这很神奇，让你两全其美。

### 开始使用 Radare2

要安装 Radare2，只需克隆其存储库并运行 `user.sh` 脚本。如果你的系统上还没有一些预备软件包，你可能需要安装它们。一旦安装完成，运行 `r2 -v` 命令来查看 Radare2 是否被正确安装：

```
$ git clone https://github.com/radareorg/radare2.git
$ cd radare2
$ ./sys/user.sh

# version

$ r2 -v
radare2 4.6.0-git 25266 @ linux-x86-64 git.4.4.0-930-g48047b317
commit: 48047b3171e6ed0480a71a04c3693a0650d03543 build: 2020-11-17__09:31:03
$

```

#### 获取二进制测试样本

现在 `r2` 已经安装好了，你需要一个样本二进制程序来试用它。你可以使用任何系统二进制文件（`ls`、`bash` 等），但为了使本教程的内容简单，请编译以下 C 程序：

```
$ cat adder.c

```

```
#include <stdio.h>

int adder(int num) {
        return num + 1;
}

int main() {
        int res, num1 = 100;
        res = adder(num1);
        printf("Number now is  : %d\n", res);
        return 0;
}

```

```
$ gcc adder.c -o adder
$ file adder
adder: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=9d4366f7160e1ffb46b14466e8e0d70f10de2240, not stripped
$ ./adder
Number now is  : 101

```

#### 加载二进制文件

要分析二进制文件，你必须在 Radare2 中加载它。通过提供文件名作为 `r2` 命令的一个命令行参数来加载它。你会进入一个独立的 Radare2 控制台，这与你的 shell 不同。要退出控制台，你可以输入 `Quit` 或 `Exit` 或按 `Ctrl+D`：

```
$ r2 ./adder
 -- Learn pancake as if you were radare!
[0x004004b0]> quit
$

```

#### 分析二进制

在你探索二进制之前，你必须让 `r2` 为你分析它。你可以通过在 `r2` 控制台中运行 `aaa` 命令来实现：

```
$ r2 ./adder
 -- Sorry, radare2 has experienced an internal error.
[0x004004b0]>
[0x004004b0]>
[0x004004b0]> aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
[0x004004b0]>

```

这意味着每次你选择一个二进制文件进行分析时，你必须在加载二进制文件后输入一个额外的命令 `aaa`。你可以绕过这一点，在命令后面跟上 `-A` 来调用 `r2`；这将告诉 `r2` 为你自动分析二进制：

```
$ r2 -A ./adder
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
 -- Already up-to-date.
[0x004004b0]>

```

#### 获取一些关于二进制的基本信息

在开始分析一个二进制文件之前，你需要一些背景信息。在许多情况下，这可以是二进制文件的格式（ELF、PE 等）、二进制的架构（x86、AMD、ARM 等），以及二进制是 32 位还是 64 位。方便的 `r2` 的 `iI` 命令可以提供所需的信息：

```
[0x004004b0]> iI
arch     x86
baddr    0x400000
binsz    14724
bintype  elf
bits     64
canary   false
class    ELF64
compiler GCC: (GNU) 8.3.1 20190507 (Red Hat 8.3.1-4)
crypto   false
endian   little
havecode true
intrp    /lib64/ld-linux-x86-64.so.2
laddr    0x0
lang     c
linenum  true
lsyms    true
machine  AMD x86-64 architecture
maxopsz  16
minopsz  1
nx       true
os       linux
pcalign  0
pic      false
relocs   true
relro    partial
rpath    NONE
sanitiz  false
static   false
stripped false
subsys   linux
va       true

[0x004004b0]>
[0x004004b0]>

```

### 导入和导出

通常情况下，当你知道你要处理的是什么样的文件后，你就想知道二进制程序使用了什么样的标准库函数，或者了解程序的潜在功能。在本教程中的示例 C 程序中，唯一的库函数是 `printf`，用来打印信息。你可以通过运行 `ii` 命令看到这一点，它显示了该二进制所有导入的库：

```
[0x004004b0]> ii
[Imports]
nth vaddr      bind   type   lib name
―――――――――――――――――――――――――――――――――――――
1   0x00000000 WEAK   NOTYPE     _ITM_deregisterTMCloneTable
2   0x004004a0 GLOBAL FUNC       printf
3   0x00000000 GLOBAL FUNC       __libc_start_main
4   0x00000000 WEAK   NOTYPE     __gmon_start__
5   0x00000000 WEAK   NOTYPE     _ITM_registerTMCloneTable

```

该二进制也可以有自己的符号、函数或数据。这些函数通常显示在 `Exports` 下。这个测试的二进制导出了两个函数：`main` 和 `adder`。其余的函数是在编译阶段，当二进制文件被构建时添加的。加载器需要这些函数来加载二进制文件（现在不用太关心它们）：

```
[0x004004b0]>
[0x004004b0]> iE
[Exports]

nth paddr       vaddr      bind   type   size lib name
――――――――――――――――――――――――――――――――――――――――――――――――――――――
82   0x00000650 0x00400650 GLOBAL FUNC   5        __libc_csu_fini
85   ---------- 0x00601024 GLOBAL NOTYPE 0        _edata
86   0x00000658 0x00400658 GLOBAL FUNC   0        _fini
89   0x00001020 0x00601020 GLOBAL NOTYPE 0        __data_start
90   0x00000596 0x00400596 GLOBAL FUNC   15       adder
92   0x00000670 0x00400670 GLOBAL OBJ    0        __dso_handle
93   0x00000668 0x00400668 GLOBAL OBJ    4        _IO_stdin_used
94   0x000005e0 0x004005e0 GLOBAL FUNC   101      __libc_csu_init
95   ---------- 0x00601028 GLOBAL NOTYPE 0        _end
96   0x000004e0 0x004004e0 GLOBAL FUNC   5        _dl_relocate_static_pie
97   0x000004b0 0x004004b0 GLOBAL FUNC   47       _start
98   ---------- 0x00601024 GLOBAL NOTYPE 0        __bss_start
99   0x000005a5 0x004005a5 GLOBAL FUNC   55       main
100  ---------- 0x00601028 GLOBAL OBJ    0        __TMC_END__
102  0x00000468 0x00400468 GLOBAL FUNC   0        _init

[0x004004b0]>

```

### 哈希信息

如何知道两个二进制文件是否相似？你不能只是打开一个二进制文件并查看里面的源代码。在大多数情况下，二进制文件的哈希值（md5sum、sha1、sha256）是用来唯一识别它的。你可以使用 `it` 命令找到二进制的哈希值：

```
[0x004004b0]> it
md5 7e6732f2b11dec4a0c7612852cede670
sha1 d5fa848c4b53021f6570dd9b18d115595a2290ae
sha256 13dd5a492219dac1443a816ef5f91db8d149e8edbf26f24539c220861769e1c2
[0x004004b0]>

```

### 函数

代码按函数分组；要列出二进制中存在的函数，请运行 `afl` 命令。下面的列表显示了 `main` 函数和 `adder` 函数。通常，以 `sym.imp` 开头的函数是从标准库（这里是 glibc）中导入的：

```
[0x004004b0]> afl
0x004004b0    1 46           entry0
0x004004f0    4 41   -> 34   sym.deregister_tm_clones
0x00400520    4 57   -> 51   sym.register_tm_clones
0x00400560    3 33   -> 32   sym.__do_global_dtors_aux
0x00400590    1 6            entry.init0
0x00400650    1 5            sym.__libc_csu_fini
0x00400658    1 13           sym._fini
0x00400596    1 15           sym.adder
0x004005e0    4 101          loc..annobin_elf_init.c
0x004004e0    1 5            loc..annobin_static_reloc.c
0x004005a5    1 55           main
0x004004a0    1 6            sym.imp.printf
0x00400468    3 27           sym._init
[0x004004b0]>

```

### 交叉引用

在 C 语言中，`main` 函数是一个程序开始执行的地方。理想情况下，其他函数都是从 `main` 函数调用的，在退出程序时，`main` 函数会向操作系统返回一个退出状态。这在源代码中是很明显的，然而，二进制程序呢？如何判断 `adder` 函数的调用位置呢？

你可以使用 `axt` 命令，后面加上函数名，看看 `adder` 函数是在哪里调用的；如下图所示，它是从 `main` 函数中调用的。这就是所谓的<ruby> 交叉引用 <rt>  cross-referencing </rt></ruby>。但什么调用 `main` 函数本身呢？从下面的 `axt main` 可以看出，它是由 `entry0` 调用的（关于 `entry0` 的学习我就不说了，留待读者练习）。

```
[0x004004b0]> axt sym.adder
main 0x4005b9 [CALL] call sym.adder
[0x004004b0]>
[0x004004b0]> axt main
entry0 0x4004d1 [DATA] mov rdi, main
[0x004004b0]>

```

### 寻找定位

在处理文本文件时，你经常通过引用行号和行或列号在文件内移动；在二进制文件中，你需要使用地址。这些是以 `0x` 开头的十六进制数字，后面跟着一个地址。要找到你在二进制中的位置，运行 `s` 命令。要移动到不同的位置，使用 `s` 命令，后面跟上地址。

函数名就像标签一样，内部用地址表示。如果函数名在二进制中（未剥离的），可以使用函数名后面的 `s` 命令跳转到一个特定的函数地址。同样，如果你想跳转到二进制的开始，输入 `s 0`：

```
[0x004004b0]> s
0x4004b0
[0x004004b0]>
[0x004004b0]> s main
[0x004005a5]>
[0x004005a5]> s
0x4005a5
[0x004005a5]>
[0x004005a5]> s sym.adder
[0x00400596]>
[0x00400596]> s
0x400596
[0x00400596]>
[0x00400596]> s 0
[0x00000000]>
[0x00000000]> s
0x0
[0x00000000]>

```

### 十六进制视图

通常情况下，原始二进制没有意义。在十六进制模式下查看二进制及其等效的 ASCII 表示法会有帮助：

```
[0x004004b0]> s main
[0x004005a5]>
[0x004005a5]> px
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x004005a5  5548 89e5 4883 ec10 c745 fc64 0000 008b  UH..H....E.d....
0x004005b5  45fc 89c7 e8d8 ffff ff89 45f8 8b45 f889  E.........E..E..
0x004005c5  c6bf 7806 4000 b800 0000 00e8 cbfe ffff  ..x.@...........
0x004005d5  b800 0000 00c9 c30f 1f40 00f3 0f1e fa41  .........@.....A
0x004005e5  5749 89d7 4156 4989 f641 5541 89fd 4154  WI..AVI..AUA..AT
0x004005f5  4c8d 2504 0820 0055 488d 2d04 0820 0053  L.%.. .UH.-.. .S
0x00400605  4c29 e548 83ec 08e8 57fe ffff 48c1 fd03  L).H....W...H...
0x00400615  741f 31db 0f1f 8000 0000 004c 89fa 4c89  t.1........L..L.
0x00400625  f644 89ef 41ff 14dc 4883 c301 4839 dd75  .D..A...H...H9.u
0x00400635  ea48 83c4 085b 5d41 5c41 5d41 5e41 5fc3  .H...[]A\A]A^A_.
0x00400645  9066 2e0f 1f84 0000 0000 00f3 0f1e fac3  .f..............
0x00400655  0000 00f3 0f1e fa48 83ec 0848 83c4 08c3  .......H...H....
0x00400665  0000 0001 0002 0000 0000 0000 0000 0000  ................
0x00400675  0000 004e 756d 6265 7220 6e6f 7720 6973  ...Number now is
0x00400685  2020 3a20 2564 0a00 0000 0001 1b03 3b44    : %d........;D
0x00400695  0000 0007 0000 0000 feff ff88 0000 0020  ...............
[0x004005a5]>

```

### 反汇编

如果你使用的是编译后的二进制文件，则无法查看源代码。编译器将源代码转译成 CPU 可以理解和执行的机器语言指令；其结果就是二进制或可执行文件。然而，你可以查看汇编指令（的助记词）来理解程序正在做什么。例如，如果你想查看 `main` 函数在做什么，你可以使用 `s main` 寻找 `main` 函数的地址，然后运行 `pdf` 命令来查看反汇编的指令。

要理解汇编指令，你需要参考体系结构手册（这里是 x86），它的应用二进制接口（ABI，或调用惯例），并对堆栈的工作原理有基本的了解：

```
[0x004004b0]> s main
[0x004005a5]>
[0x004005a5]> s
0x4005a5
[0x004005a5]>
[0x004005a5]> pdf
            ; DATA XREF from entry0 @ 0x4004d1
┌ 55: int main (int argc, char **argv, char **envp);
│           ; var int64_t var_8h @ rbp-0x8
│           ; var int64_t var_4h @ rbp-0x4
│           0x004005a5      55             push rbp
│           0x004005a6      4889e5         mov rbp, rsp
│           0x004005a9      4883ec10       sub rsp, 0x10
│           0x004005ad      c745fc640000.  mov dword [var_4h], 0x64    ; 'd' ; 100
│           0x004005b4      8b45fc         mov eax, dword [var_4h]
│           0x004005b7      89c7           mov edi, eax
│           0x004005b9      e8d8ffffff     call sym.adder
│           0x004005be      8945f8         mov dword [var_8h], eax
│           0x004005c1      8b45f8         mov eax, dword [var_8h]
│           0x004005c4      89c6           mov esi, eax
│           0x004005c6      bf78064000     mov edi, str.Number_now_is__:__d ; 0x400678 ; "Number now is  : %d\n" ; const char *format
│           0x004005cb      b800000000     mov eax, 0
│           0x004005d0      e8cbfeffff     call sym.imp.printf         ; int printf(const char *format)
│           0x004005d5      b800000000     mov eax, 0
│           0x004005da      c9             leave
└           0x004005db      c3             ret
[0x004005a5]>

```

这是 `adder` 函数的反汇编结果：

```
[0x004005a5]> s sym.adder
[0x00400596]>
[0x00400596]> s
0x400596
[0x00400596]>
[0x00400596]> pdf
            ; CALL XREF from main @ 0x4005b9
┌ 15: sym.adder (int64_t arg1);
│           ; var int64_t var_4h @ rbp-0x4
│           ; arg int64_t arg1 @ rdi
│           0x00400596      55             push rbp
│           0x00400597      4889e5         mov rbp, rsp
│           0x0040059a      897dfc         mov dword [var_4h], edi     ; arg1
│           0x0040059d      8b45fc         mov eax, dword [var_4h]
│           0x004005a0      83c001         add eax, 1
│           0x004005a3      5d             pop rbp
└           0x004005a4      c3             ret
[0x00400596]>

```

### 字符串

查看二进制中存在哪些字符串可以作为二进制分析的起点。字符串是硬编码到二进制中的，通常会提供重要的提示，可以让你将重点转移到分析某些区域。在二进制中运行 `iz` 命令来列出所有的字符串。这个测试二进制中只有一个硬编码的字符串：

```
[0x004004b0]> iz
[Strings]
nth paddr      vaddr      len size section type  string
―――――――――――――――――――――――――――――――――――――――――――――――――――――――
0   0x00000678 0x00400678 20  21   .rodata ascii Number now is  : %d\n

[0x004004b0]>

```

### 交叉引用字符串

和函数一样，你可以交叉引用字符串，看看它们是从哪里被打印出来的，并理解它们周围的代码：

```
[0x004004b0]> ps @ 0x400678
Number now is  : %d

[0x004004b0]>
[0x004004b0]> axt 0x400678
main 0x4005c6 [DATA] mov edi, str.Number_now_is__:__d
[0x004004b0]>

```

### 可视模式

当你的代码很复杂，有多个函数被调用时，很容易迷失方向。如果能以图形或可视化的方式查看哪些函数被调用，根据某些条件采取了哪些路径等，会很有帮助。在移动到感兴趣的函数后，可以通过 `VV` 命令来探索 `r2` 的可视化模式。例如，对于 `adder` 函数：

```
[0x004004b0]> s sym.adder
[0x00400596]>
[0x00400596]> VV

```

![Radare2 Visual mode](/data/attachment/album/202102/01/112635hqi5513d1e5bx8d8.png "Radare2 Visual mode")

*(Gaurav Kamathe, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/))*

### 调试器

到目前为止，你一直在做的是静态分析 —— 你只是在看二进制文件中的东西，而没有运行它，有时你需要执行二进制文件，并在运行时分析内存中的各种信息。`r2` 的内部调试器允许你运行二进制文件、设置断点、分析变量的值、或者转储寄存器的内容。

用 `-d` 标志启动调试器，并在加载二进制时添加 `-A` 标志进行分析。你可以通过使用 `db <function-name>` 命令在不同的地方设置断点，比如函数或内存地址。要查看现有的断点，使用 `dbi` 命令。一旦你放置了断点，使用 `dc` 命令开始运行二进制文件。你可以使用 `dbt` 命令查看堆栈，它可以显示函数调用。最后，你可以使用 `drr` 命令转储寄存器的内容：

```
$ r2 -d -A ./adder
Process with PID 17453 started...
= attach 17453 17453
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
 -- git checkout hamster
[0x7f77b0a28030]>
[0x7f77b0a28030]> db main
[0x7f77b0a28030]>
[0x7f77b0a28030]> db sym.adder
[0x7f77b0a28030]>
[0x7f77b0a28030]> dbi
0 0x004005a5 E:1 T:0
1 0x00400596 E:1 T:0
[0x7f77b0a28030]>
[0x7f77b0a28030]> afl | grep main
0x004005a5    1 55           main
[0x7f77b0a28030]>
[0x7f77b0a28030]> afl | grep sym.adder
0x00400596    1 15           sym.adder
[0x7f77b0a28030]>
[0x7f77b0a28030]> dc
hit breakpoint at: 0x4005a5
[0x004005a5]>
[0x004005a5]> dbt
0  0x4005a5           sp: 0x0                 0    [main]  main sym.adder+15
1  0x7f77b0687873     sp: 0x7ffe35ff6858      0    [??]  section..gnu.build.attributes-1345820597
2  0x7f77b0a36e0a     sp: 0x7ffe35ff68e8      144  [??]  map.usr_lib64_ld_2.28.so.r_x+65034
[0x004005a5]> dc
hit breakpoint at: 0x400596
[0x00400596]> dbt
0  0x400596           sp: 0x0                 0    [sym.adder]  rip entry.init0+6
1  0x4005be           sp: 0x7ffe35ff6838      0    [main]  main+25
2  0x7f77b0687873     sp: 0x7ffe35ff6858      32   [??]  section..gnu.build.attributes-1345820597
3  0x7f77b0a36e0a     sp: 0x7ffe35ff68e8      144  [??]  map.usr_lib64_ld_2.28.so.r_x+65034
[0x00400596]>
[0x00400596]>
[0x00400596]> dr
rax = 0x00000064
rbx = 0x00000000
rcx = 0x7f77b0a21738
rdx = 0x7ffe35ff6948
r8 = 0x7f77b0a22da0
r9 = 0x7f77b0a22da0
r10 = 0x0000000f
r11 = 0x00000002
r12 = 0x004004b0
r13 = 0x7ffe35ff6930
r14 = 0x00000000
r15 = 0x00000000
rsi = 0x7ffe35ff6938
rdi = 0x00000064
rsp = 0x7ffe35ff6838
rbp = 0x7ffe35ff6850
rip = 0x00400596
rflags = 0x00000202
orax = 0xffffffffffffffff
[0x00400596]>

```

### 反编译器

能够理解汇编是二进制分析的前提。汇编语言总是与二进制建立和预期运行的架构相关。一行源代码和汇编代码之间从来没有 1:1 的映射。通常，一行 C 源代码会产生多行汇编代码。所以，逐行读取汇编代码并不是最佳的选择。

这就是反编译器的作用。它们试图根据汇编指令重建可能的源代码。这与用于创建二进制的源代码绝不完全相同，它是基于汇编的源代码的近似表示。另外，要考虑到编译器进行的优化，它会生成不同的汇编代码以加快速度，减小二进制的大小等，会使反编译器的工作更加困难。另外，恶意软件作者经常故意混淆代码，让恶意软件的分析人员望而却步。

Radare2 通过插件提供反编译器。你可以安装任何 Radare2 支持的反编译器。使用 `r2pm -l` 命令可以查看当前插件。使用 `r2pm install` 命令来安装一个示例的反编译器 `r2dec`：

```
$ r2pm  -l
$
$ r2pm install r2dec
Cloning into 'r2dec'...
remote: Enumerating objects: 100, done.
remote: Counting objects: 100% (100/100), done.
remote: Compressing objects: 100% (97/97), done.
remote: Total 100 (delta 18), reused 27 (delta 1), pack-reused 0
Receiving objects: 100% (100/100), 1.01 MiB | 1.31 MiB/s, done.
Resolving deltas: 100% (18/18), done.
Install Done For r2dec
gmake: Entering directory '/root/.local/share/radare2/r2pm/git/r2dec/p'
[CC] duktape/duktape.o
[CC] duktape/duk_console.o
[CC] core_pdd.o
[CC] core_pdd.so
gmake: Leaving directory '/root/.local/share/radare2/r2pm/git/r2dec/p'
$
$ r2pm  -l
r2dec
$

```

### 反编译器视图

要反编译一个二进制文件，在 `r2` 中加载二进制文件并自动分析它。在本例中，使用 `s sym.adder` 命令移动到感兴趣的 `adder` 函数，然后使用 `pdda` 命令并排查看汇编和反编译后的源代码。阅读这个反编译后的源代码往往比逐行阅读汇编更容易：

```
$ r2 -A ./adder
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze function calls (aac)
[x] Analyze len bytes of instructions for references (aar)
[x] Check for vtables
[x] Type matching analysis for all functions (aaft)
[x] Propagate noreturn information
[x] Use -AA or aaaa to perform additional experimental analysis.
 -- What do you want to debug today?
[0x004004b0]>
[0x004004b0]> s sym.adder
[0x00400596]>
[0x00400596]> s
0x400596
[0x00400596]>
[0x00400596]> pdda
    ; assembly                               | /* r2dec pseudo code output */
                                             | /* ./adder @ 0x400596 */
                                             | #include <stdint.h>
                                             |
    ; (fcn) sym.adder ()                     | int32_t adder (int64_t arg1) {
                                             |     int64_t var_4h;
                                             |     rdi = arg1;
    0x00400596 push rbp                      |
    0x00400597 mov rbp, rsp                  |
    0x0040059a mov dword [rbp - 4], edi      |     *((rbp - 4)) = edi;
    0x0040059d mov eax, dword [rbp - 4]      |     eax = *((rbp - 4));
    0x004005a0 add eax, 1                    |     eax++;
    0x004005a3 pop rbp                       |
    0x004005a4 ret                           |     return eax;
                                             | }
[0x00400596]>

```

### 配置设置

随着你对 Radare2 的使用越来越熟悉，你会想改变它的配置，以适应你的工作方式。你可以使用 `e` 命令查看 `r2` 的默认配置。要设置一个特定的配置，在 `e` 命令后面添加 `config = value`：

```
[0x004005a5]> e | wc -l
593
[0x004005a5]> e | grep syntax
asm.syntax = intel
[0x004005a5]>
[0x004005a5]> e asm.syntax = att
[0x004005a5]>
[0x004005a5]> e | grep syntax
asm.syntax = att
[0x004005a5]>

```

要使配置更改永久化，请将它们放在 `r2` 启动时读取的名为 `.radare2rc` 的启动文件中。这个文件通常在你的主目录下，如果没有，你可以创建一个。一些示例配置选项包括：

```
$ cat ~/.radare2rc
e asm.syntax = att
e scr.utf8 = true
eco solarized
e cmd.stack = true
e stack.size = 256
$

```

### 探索更多

你已经看到了足够多的 Radare2 功能，对这个工具有了一定的了解。因为 Radare2 遵循 Unix 哲学，即使你可以从它的主控台做各种事情，它也会在下面使用一套独立的二进制来完成它的任务。

探索下面列出的独立二进制文件，看看它们是如何工作的。例如，用 `iI` 命令在控制台看到的二进制信息也可以用 `rabin2 <binary>` 命令找到：

```
$ cd bin/
$
$ ls
prefix  r2agent    r2pm  rabin2   radiff2  ragg2    rarun2   rasm2
r2      r2-indent  r2r   radare2  rafind2  rahash2  rasign2  rax2
$

```

你觉得 Radare2 怎么样？请在评论中分享你的反馈。

---

via: <https://opensource.com/article/21/1/linux-radare2>

作者：[Gaurav Kamathe](https://opensource.com/users/gkamathe) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


硬核观察 | 瞠目结舌：为了重新启用 Flash 支持，南非税务局发布了自己的 Web 浏览器

Summary: 更多：• 微软宣布开源可扩展存储引擎 ESE，几乎用在所有 Windows 之中 • 我们可能高估了每天的 COBOL 事务数量

说明一刀切在有些场景行不通。

flash这个有定制个浏览器的功夫直接做个客户端好了，反正只能访问指定网站，跟客户端没什么区别了

![](/data/attachment/album/202102/01/125419r51nw5noyowr0leo.jpg)

#### 瞠目结舌：为了重新启用 Flash 支持，南非税务局发布了自己的 Web 浏览器

![](/data/attachment/album/202102/01/124826mfvayosycvcofytt.jpg)

据 [zdnet](https://www.zdnet.com/article/south-african-government-releases-its-own-browser-just-to-re-enable-flash-support/) 报道称，南非税务局发布这个定制浏览器的“唯一的目的是重新启用 Adobe Flash Player 支持，而不是将其现有的网站从使用 Flash 移植到基于 HTML 的网页表单中。”

该机构称自己“受到定时炸弹机制的影响”，从 Flash 停用的当天开始，该机构无法通过网站接收任何报税信息，而上传的表单被设计成 Flash 小部件。尽管有三年半的先机，南非税务局并没有选择将其 Flash 小部件移植到基本的 HTML 和 JS 表单中。相反，他们决定采取一个在 IT 决策史上最令人瞠目结舌的错误决定，[发布自己的 Web 浏览器](https://twitter.com/sarstax/status/1353699405912797184)。

该浏览器是 Chromium 浏览器的简化版，有两个功能：第一个是重新启用 Flash 支持。第二是让用户“能且只能”访问南非税务局的官方网站。并且，该浏览器只有 Windows 版本。

当然，这么有“创举”的事情，也绝非南非税务局一家，ZDnet 也提到了中国大连有了类似的“[解决方案](/article-13051-1.html)”。我觉得，很快就会有其它的机构“有样学样”……

#### 微软宣布开源可扩展存储引擎 ESE，几乎用在所有 Windows 之中

![](/data/attachment/album/202102/01/124953sspwv9kpvdt9tsfs.jpg)

微软的 <ruby> <a href="https://github.com/microsoft/Extensible-Storage-Engine">  可扩展存储引擎 </a> <rt>  Extensible Storage Engine </rt></ruby>（ESE） 是一个非 SQL 数据库引擎。它最早在 Windows NT 3.51 中推出，并在 90 年代重写了两次，在此后的 20 年中进行了大量更新。微软使用它已有 25 年之久，它至今仍是微软的核心技术之一。

它运行在 Office 365 邮箱存储后台服务器的 10 万台机器和数百万块磁盘上。它还可以运行在带有 TB 级内存的大型 SMP 系统上运行，用于大型活动目录部署。

最重要的是，目前在每一台 Windows 客户端计算机都有多个 ESE 数据库实例运行在低内存模式下。ESE 自 Windows XP 以来一直用于 Windows 客户端产品之中，这包括超过 10 亿台 Windows 10 设备。

而最近，微软决定以 MIT 许可证[开源](https://github.com/microsoft/Extensible-Storage-Engine)它，并且开源的代码要比运行在 Windows 之中的还要新一些。我觉得，微软真是开源楷模，连这么重要、成熟的核心模块都开源出来了，给微软一个大大的赞！

#### 我们可能高估了每天的 COBOL 事务数量

![](/data/attachment/album/202102/01/125200ztbn63oqk289h46v.jpg)

据说“[每天有 300 亿个客户信息控制系统（CICS）/ COBOL 交易](https://web.archive.org/web/20010620220800/http://cobolreport.com/columnists/tscott/01082001.htm)”。这个数字后来被引用了无数次。然而，这可能[错误](https://developers.slashdot.org/story/21/01/30/2128205/are-we-overestimating-the-number-of-cobol-transactions-each-day)的。

据说，最初是 DataPro 在 1997 年对 421 家公司进行了一次[调查](https://books.google.de/books?id=IKbZ7dEVokwC&pg=PT68&dq=%22421+mainframe+shops%22&hl=de&sa=X&ved=2ahUKEwjc-L2jgIHuAhUylosKHZCiBBcQ6AEwAHoECAAQAg#v=onepage&q=%22421%20mainframe%20shops%22&f=false)，得出结论是：每天有 200 亿笔 CICS 交易。然后，这数字变成了 “300 亿 CICS 交易”。而在 2 年后，又莫名从 “CICS 交易”变成了 “COBOL 交易”。随后，随着 DataPro 于 1997 年被 Gartner 公司收购，这个数据就又变成了“来自 Gartner” 的了。

同样，还有一些无稽之谈或过时的数据也是来源于该报告：有 2000 亿行 COBOL 代码；这是世界上所有源代码的 60-80%；每年新写 50 亿行 COBOL 代码；世界上有 200 万名 COBOL 开发人员；COBOL 处理 95% 的柜台交易、ATM 刷卡或类似的交易。这些统统是有一定的误读或限制条件下的数据，也有的数据在二十多年后已经时过境迁了。

所以，不要随便引用数据，哪怕是来自于“权威”来源。


《代码英雄》们的史诗，是由开源贡献者们谱就的

谢谢LCTT

![](/data/attachment/album/202102/02/114717bcgmqcrokcjrk7qt.jpg)

2020 年 7 月 21 日，Linux 中国翻译团队 LCTT 旗下的第一个特别兴趣小组（SIG）—— LCRH，在红帽公司的鼎力支持下诞生。LCRH 的目标是翻译红帽公司《代码英雄》播客的脚本为适合国人阅读理解的中文脚本。

而到了半年后，LCRH 翻译的中文脚本已经正式更新发布了前三季节目，共计 24 篇文章，时长约 12 个小时，篇幅长达 25 万字，堪比一本长篇小说！

《代码英雄》的英文名为《Command Line Heroes》，作为红帽（Red Hat）公司精心制作的原创音频播客，讲述开发人员、程序员、黑客、极客和开源反叛者们是如何彻底改变技术前景的真实史诗。在这一目前仍在持续更新的系列播客中，红帽公司邀请了诸多亲历了开源技术发展史上一些关键事件的人物和代表性的业界技术领袖，来一同探讨开源、操作系统、容器等或源远流长、或鲸吞天下的开源技术。在将这个播客在引入中国时，红帽公司希望其能展现出这些顶级黑客、开发领袖的英姿风貌，因而将其中文名称定名为《[代码英雄](https://linux.cn/talk/clh/)》。

让这些代码英雄的风貌传播给中国开源和技术爱好者的，是来自 LCRH 的 30 多位贡献者，他们通过自己的辛苦努力，对每一篇文章都经过多人、多次的反复斟酌，力求将代码英雄们的史诗传奇介绍给国人，带给广大的技术开发者。

以下是我们已经发布的前三季的《代码英雄》，更多精制译文正在贡献者们的努力下逐渐加工出来。

* [[重制版]《代码英雄》第一季（1）：操作系统战争（上）](/article-12494-1.html "[重制版]《代码英雄》第一季（1）：操作系统战争（上）")
* [[重制版]《代码英雄》第一季（2）：操作系统战争（下）Linux 的崛起](/article-12508-1.html "[重制版]《代码英雄》第一季（2）：操作系统战争（下）Linux 崛起")
* [[重制版]《代码英雄》第一季（3）：敏捷革命](/article-12514-1.html "[重制版]《代码英雄》第一季（3）：敏捷革命")
* [《代码英雄》第一季（4）：DevOps，拆掉那堵墙](/article-12529-1.html "《代码英雄》第一季（4）：DevOps，拆掉那堵墙")
* [《代码英雄》第一季（5）：容器竞赛](/article-12535-1.html "《代码英雄》第一季（5）：容器竞赛")
* [《代码英雄》第一季（6）：揭秘云计算](/article-12551-1.html "《代码英雄》第一季（6）：揭秘云计算")
* [《代码英雄》第一季（7）：开启未来](/article-12557-1.html "《代码英雄》第一季（7）：开启未来")
* [《代码英雄》第二季（1）：按下启动键](/article-12578-1.html "《代码英雄》第二季（1）：按下启动键")
* [《代码英雄》第二季（2）：Hello, World](/article-12595-1.html "《代码英雄》第二季（2）：Hello, World")
* [《代码英雄》第二季（3）：准备提交](/article-12603-1.html "《代码英雄》第二季（3）：准备提交")
* [《代码英雄》第二季（4）：更好的失败](/article-12625-1.html "《代码英雄》第二季（4）：更好的失败")
* [《代码英雄》第二季（5）：关于 DevSecOps 的故事](/article-12641-1.html "《代码英雄》第二季（5）：关于 DevSecOps 的故事")
* [《代码英雄》第二季（6）：数据大爆炸](/article-12649-1.html "《代码英雄》第二季（6）：数据大爆炸")
* [《代码英雄》第二季（7）：无服务器](/article-12717-1.html "《代码英雄》第二季（7）：无服务器")
* [《代码英雄》第二季（8）：开源好奇号](/article-12744-1.html "《代码英雄》第二季（8）：开源好奇号")
* [《代码英雄》第二季（9）：特别篇 - 开发者推广大使圆桌会议](/article-12770-1.html "《代码英雄》第二季（9）：特别篇 - 开发者推广大使圆桌会议")
* [《代码英雄》第三季（1）：Python 的故事](/article-12795-1.html "《代码英雄》第三季（1）：Python 的故事")
* [《代码英雄》第三季（2）：学习 BASIC](/article-12828-1.html "《代码英雄》第三季（2）：学习 BASIC")
* [《代码英雄》第三季（3）：创造 JavaScript](/article-12853-1.html "《代码英雄》第三季（3）：创造 JavaScript")
* [《代码英雄》第三季（4）：深入 Perl 语言的世界](/article-12881-1.html "《代码英雄》第三季（4）：深入 Perl 语言的世界")
* [《代码英雄》第三季（5）： 基础设施的影响](/article-12909-1.html "《代码英雄》第三季（5）： 基础设施的影响")
* [《代码英雄》第三季（6）：Bash Shell 中的英雄](/article-12951-1.html "《代码英雄》第三季（6）：Bash Shell 中的英雄")
* [《代码英雄》第三季（7）：与机器对话](/article-13027-1.html "《代码英雄》第三季（7）：与机器对话")
* [《代码英雄》第三季（8）：C 语言之巨变](/article-13066-1.html "《代码英雄》第三季（8）：C 语言之巨变")

在 LCRH 的[代码仓库](https://github.com/LCTT/LCRH/)中，记录了 35 名[贡献者](https://github.com/LCTT/LCRH/graphs/contributors)的 460 次代码提交。这些贡献者们有的人尚在高校，有的人已从业多年；有的人身在中国，有的人求学海外。但对于开源技术的热爱、对于开源贡献的坚持，让他们造就了 LCRH，造就了中文版的《代码英雄》。

作为一个开发者，《代码英雄》所讲述的历史让我悠然神往，技术领袖们对开源和技术的观点使我可以高屋建瓴地看清乱花迷眼的技术本质。而这一切，都是由 LCTT/LCRH 的贡献者带来的，感谢这些可爱的贡献者！

《代码英雄》SIG 欢迎对于开源和技术感兴趣的你，[参与到我们当中来](/article-12436-1.html)，和我们一起贡献代码英雄的世界！你可以在 QQ 中搜索群 **940139452**，加入我们，参与贡献，具体贡献流程可以进群后了解。

除了《代码英雄》SIG，如果你对技术翻译感兴趣，也愿意以这种方式参与开源贡献，也欢迎加入到 [LCTT](https://linux.cn/lctt/)（Linux 中国翻译团队）当中来。同样的，在 QQ 中搜索群：**198889102** 即可加入我们，加群时请说明是“**志愿者**”，并在加入群后修改群名片为你的 GitHub 的 ID，参与贡献！


Nextcloud 是如何成为终极开源生产力套件的

Summary: Nextcloud 可以取代你用于协作、组织和任务管理的许多在线应用。

Nextcloud 可以取代你用于协作、组织和任务管理的许多在线应用。

>
> Nextcloud 可以取代你用于协作、组织和任务管理的许多在线应用。
>
>
>

![](/data/attachment/album/202102/02/121553uhl3pjljjkhj0h8p.jpg "Working on a team, busy worklife")

在前几年，这个年度系列涵盖了单个的应用。今年，我们除了关注 2021 年的策略外，还将关注一体化解决方案。欢迎来到 2021 年 21 天生产力的第十一天。

基于 Web 的服务几乎可以在任何地方访问你的数据，它们每小时可以支持数百万用户。不过对于我们中的一些人来说，由于各种原因，运行自己的服务比使用大公司的服务更可取。也许我们的工作是受监管的或有明确安全要求。也许我们有隐私方面的考虑，或者只是喜欢能够自己构建、运行和修复事物。不管是什么情况，[Nextcloud](https://nextcloud.com/) 都可以提供你所需要的大部分服务，但是是在你自己的硬件上。

![NextCloud Dashboard displaying service options](/data/attachment/album/202102/02/121635znsnea771easlhfs.jpg)

*Nextcloud 控制面板（Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

大多数时候，当我们想到 Nextcloud 时，我们会想到文件共享和同步，类似于 Dropbox、OneDrive 和 Google Drive 等商业产品。然而，如今，它是一个完整的生产力套件，拥有电子邮件客户端、日历、任务和笔记本。

有几种方法可以安装和运行 Nextcloud。你可以把它安装到裸机服务器上、在 Docker 容器中运行，或者作为虚拟机运行。如果可以考虑，还有一些托管服务将为你运行 Nextcloud。最后，有适用于所有主流操作系统的应用，包括移动应用，以便随时访问。

![Nextcloud virtual machine](/data/attachment/album/202102/02/121704me585e858t5k85dz.png "Nextcloud virtual machine")

*Nextcloud 虚拟机（Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

默认情况下，Nextcloud 会安装文件共享和其他一些相关应用（或附加组件）。你可以在管理界面中找到“应用”页面，这里允许你安装单个附加组件和一些预定义的相关应用捆绑。对我而言，我选择了 “Groupware Bundle”，其中包括“邮件”、“日历”、“联系人”和 “Deck”。“Deck” 是一个轻量级的看板，用于处理任务。我也安装了“记事本”和“任务”应用。

Nextcloud “邮件” 是一个非常直白的 IMAP 邮件客户端。虽然 Nextcloud 没有将 IMAP 或 SMTP 服务器作为软件包的一部分，但你可以很容易地在操作系统中添加一个或使用远程服务。“日历”应用是相当标准的，也允许你订阅远程日历。有一个缺点是，远程日历（例如，来自大型云提供商）是只读的，所以你可以查看但不能修改它们。

![NextCoud App Interface](/data/attachment/album/202102/02/121857zngqihl6iu7z7kiz.jpg "NextCoud App Interface")

*Nextcloud 应用界面 （Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

“记事本” 是一个简单的文本记事本，允许你创建和更新简短的笔记、日记和相关的东西。“任务” 是一款待办事项应用，支持多个列表、任务优先级、完成百分比以及其他一些用户期待的标准功能。如果你安装了 “Deck”，它的任务卡也会被列出来。每个看板都会显示自己的列表，所以你可以使用 “Deck” 或 “任务” 来跟踪完成的内容。

“Deck” 本身就是一个看板应用，将任务以卡片的形式呈现在流程中。如果你喜欢看板流程，它是一个追踪进度的优秀应用。

![Taking notes](/data/attachment/album/202102/02/121938j8i8bdzk3fr59b5f.jpg "Taking notes in Nextcloud")

*做笔记 （Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

Nextcloud 中所有的应用都原生支持通过标准协议进行共享。与一些类似的解决方案不同，它的分享并不是为了完成功能列表中的一项而加上去的。分享是 Nextcloud 存在的主要原因之一，所以使用起来非常简单。你还可以将链接分享到社交媒体、通过电子邮件分享等。你可以用一个 Nextcloud 取代多个在线服务，它在任何地方都可以访问，以协作为先。

---

via: <https://opensource.com/article/21/1/nextcloud-productivity>

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


硬核观察 | Excel 现在具备了图灵完备性，成为第一大编程语言

Summary: 更多：• Perl.com 官网被劫持 • 据称 IBM 已经将其区块链团队削减殆尽

![](/data/attachment/album/202102/02/135441go0li9lqg6i00zp9.jpg)

#### Excel 现在具备了图灵完备性，成为第一大编程语言

![](/data/attachment/album/202102/02/135004lj2inbuz4vjm52ml.jpg)

如果一种编程语言可以实现任何可能的算法，那么它就具备了图灵完备性。微软通过引入 LAMBDA，Excel 现在[具备了图灵完备性](https://www.microsoft.com/en-us/research/blog/lambda-the-ultimatae-excel-worksheet-function/)，Excel 转变成一种全面的编程语言。

自 20 世纪 80 年代发布以来，Excel 为每天使用它的数百万人提供了决策依据。它也是世界上使用最广泛的编程语言。Excel 公式的编写者比世界上所有 C、C++、C#、Java 和 Python 程序员的总和还要多一个数量级。但是我们通常不将 Excel 视作一种全面的编程语言，因为它有两大缺点：其一是公式语言只支持数字、字符串和布尔值等标量值，其二是不支持定义新函数。

而在 2019 年，Excel 的数据类型超越了文本和数字，允许单元格包含一级记录。接着，在去年 12 月微软宣布了 LAMBDA 功能，解决了第二个缺陷。LAMBDA 允许用户使用 Excel 的公式语言定义新的函数。通过 LAMBDA，理论上可以用 Excel 的公式语言写任何计算，从而满足了图灵完备。LAMBDA 目前提供给了 Beta 测试用户。

我觉得，这一下，将“程序员”群体扩大了好几倍！

#### Perl.com 官网被劫持

![](/data/attachment/album/202102/02/135023afrxkhk5hvsxo76r.jpg)

日暮西山的 Perl 语言已经不再流行，虽然也在努力自救，但是整个生态的衰败依旧难以遏制，现在已经很少有新人学习 Perl 语言了。但是 Perl 依然是重要的基础设施，很多软件仍然是用 Perl 写的，Perl 的 CPAN 仓库依然是一个宝库。

上周末，[The Perl NOC 报道称](https://log.perl.org/2021/01/perlcom-hijacked.html)，Perl.com 被劫持，被指向了一个停车网站。更严重的是，它被用于分发恶意软件。目前该网站页面访问无显示，但是加载了作用不明的 JavaScript 脚本。Perl.com 曾被用作通过 CPAN 分发模块的镜像或备份。如果你的 CPAN 配置使用了它，请尽快修改。当前管理员已经在尝试恢复该域名的控制权，但是目前尚无明确进展。该域名是如何被劫持的细节也不得而知。

作为一名老 Perl 程序员，听到此事，实在是感到痛心，这是多么垂暮的社区，才能对基础设施的安全疏忽至此！

#### 据称 IBM 已经将其区块链团队削减殆尽

![](/data/attachment/album/202102/02/135037wjp2jy8sjjj6yuu8.jpg)

据四位熟悉情况的人称，IBM 已经将其区块链团队[削减殆尽](https://www.coindesk.com/ibm-blockchain-revenue-misses-job-cuts-sources)。据一位消息人士称，“其实不会再有区块链团队了。IBM 的大部分区块链人员都已经离开了。”，而另外一位称，“IBM 的区块链部门连续两年大幅度错过了收入目标”。但 IBM 的一位发言人否认了这些说法，“我们的区块链业务做得很好”。IBM 称，“我们调整了一些领导人和业务部门，以继续推动增长 —— 我们每年都会这样做。”

其实，作为目前热点的区块链，在我看来，有些联盟链项目本身就是伪概念。如果上述情况属实，不知道国内的相关区块链行业会不会也有类似变化。


使用 Ansible 的第一天

>
> 一名系统管理员分享了如何使用 Ansible 在网络中配置计算机并把其带入实际工作的信息和建议。
>
>
>

![](/data/attachment/album/202102/03/105826sn41jj0i8evu19nn.jpg "People work on a computer server with devices")

无论是第一次还是第五十次，启动并运行一台新的物理或虚拟计算机都非常耗时，而且需要大量的工作。多年来，我一直使用我创建的一系列脚本和 RPM 来安装所需的软件包，并为我喜欢的工具配置各种选项。这种方法效果很好，简化了我的工作，而且还减少了在键盘上输入命令的时间。

我一直在寻找更好的工作方式。近几年来，我一直在听到并且读到有关 [Ansible](https://www.ansible.com/) 的信息，它是一个自动配置和管理系统的强大工具。Ansible 允许系统管理员在一个或多个<ruby> 剧本 <rt>  playbook </rt></ruby>中为每个主机指定一个特定状态，然后执行各种必要的任务，使主机进入该状态。这包括安装或删除各种资源，例如 RPM 或 Apt 软件包、配置文件和其它文件、用户、组等等。

因为一些琐事，我推迟了很长一段时间学习如何使用它。直到最近，我遇到了一个我认为 Ansible 可以轻松解决的问题。

这篇文章并不会完整地告诉你如何入门 Ansible，相反，它只是对我遇到的问题和我在一些隐秘的地方发现的信息的做了一些记录。我在各种在线讨论和问答小组中找到的有关 Ansible 的许多信息都是错误的。错误范围包括明显的老旧信息（没有任何日期或来源的迹象），还有一些是完全错误的信息。

本文所介绍的内容是有用的，尽管可能还有其它方法可以完成相同的事情，但我使用的是 Ansible 2.9.13 和 [Python](https://www.python.org/) 3.8.5。

### 我的问题

我所有的最佳学习经历都始于我需要解决的问题，这次也不例外。

我一直在做一个小项目，修改 [Midnight Commander](https://midnight-commander.org/) 文件管理器的配置文件，并将它们推送到我网络上的各种系统中进行测试。尽管我有一个脚本可以自动执行这个操作，但它仍然需要使用命令行循环来提供我想要推送新代码的系统名称。我对配置文件进行了大量的更改，这使我必须频繁推送新的配置文件。但是，就在我以为我的新配置刚刚好时，我发现了一个问题，所以我需要在修复后再进行一次推送。

这种环境使得很难跟踪哪些系统有新文件，哪些没有。我还有几个主机需要区别对待。我对 Ansible 的一点了解表明，它可能能够满足我的全部或大部分工作。

### 开始

我读过许多有关 Ansible 的好文章和书籍，但从来没有在“我必须现在就把这个做好！”的情况下读过。而现在 —— 好吧，就是现在！

在重读这些文档时，我发现它们主要是在讨论如何从 GitHub 开始安装并使用 Ansible，这很酷。但是我真的只是想尽快开始，所以我使用 DNF 和 Fedora 仓库中的版本在我的 Fedora 工作站上安装了它，非常简单。

但是后来我开始寻找文件位置，并尝试确定需要修改哪些配置文件、将我的剧本保存在什么位置，甚至一个剧本怎么写以及它的作用，我脑海中有一大堆（到目前为止）悬而未决的问题。

因此，不不需要进一步描述我的困难的情况下，以下是我发现的东西以及促使我继续前进的东西。

### 配置

Ansible 的配置文件保存在 `/etc/ansible` 中，这很有道理，因为 `/etc/` 是系统程序应该保存配置文件的地方。我需要使用的两个文件是 `ansible.cfg` 和 `hosts`。

#### ansible.cfg

在进行了从文档和线上找到的一些实践练习之后，我遇到了一些有关弃用某些较旧的 Python 文件的警告信息。因此，我在 `ansible.cfg` 中将 `deprecation_warnings` 设置为 `false`，这样那些愤怒的红色警告消息就不会出现了：

```
deprecation_warnings = False

```

这些警告很重要，所以我稍后将重新回顾它们，并弄清楚我需要做什么。但是现在，它们不会再扰乱屏幕，也不会让我混淆实际上需要关注的错误。

#### hosts 文件

与 `/etc/hosts` 文件不同，`hosts` 文件也被称为<ruby> 清单 <rt>  inventory </rt></ruby>文件，它列出了网络上的主机。此文件允许将主机分组到相关集合中，例如“servers”、“workstations”和任何你所需的名称。这个文件包含帮助和大量示例，所以我在这里就不详细介绍了。但是，有些事情你必须知道。

主机也可以列在组之外，但是组对于识别具有一个或多个共同特征的主机很有帮助。组使用 INI 格式，所以服务器组看起来像这样：

```
[servers]
server1
server2
......

```

这个文件中必须有一个主机名，这样 Ansible 才能对它进行操作。即使有些子命令允许指定主机名，但除非主机名在 `hosts` 文件中，否则命令会失败。一个主机也可以放在多个组中。因此，除了 `[servers]` 组之外，`server1` 也可能是 `[webservers]` 组的成员，还可以是 `[ubuntu]` 组的成员，这样以区别于 Fedora 服务器。

Ansible 很智能。如果 `all` 参数用作主机名，Ansible 会扫描 `hosts` 文件并在它列出的所有主机上执行定义的任务。Ansible 只会尝试在每个主机上工作一次，不管它出现在多少个组中。这也意味着不需要定义 `all` 组，因为 Ansible 可以确定文件中的所有主机名，并创建自己唯一的主机名列表。

另一件需要注意的事情是单个主机的多个条目。我在 DNS 文件中使用 `CNAME` 记录来创建别名，这些别名指向某些主机的 [A 记录](https://en.wikipedia.org/wiki/List_of_DNS_record_types)，这样，我可以将一个主机称为 `host1` 或 `h1` 或 `myhost`。如果你在 `hosts` 文件中为同一主机指定多个主机名，则 Ansible 将尝试在所有这些主机名上执行其任务，它无法知道它们指向同一主机。好消息是，这并不会影响整体结果；它只是多花了一点时间，因为 Ansible 会在次要主机名上工作，它会确定所有操作均已执行。

### Ansible 实情

我阅读过 Ansible 的大多数材料都谈到了 Ansible <ruby> <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html#ansible-facts">  实情 </a> <rt>  facts </rt></ruby>，它是与远程系统相关的数据，包括操作系统、IP 地址、文件系统等等。这些信息可以通过其它方式获得，如 `lshw`、`dmidecode` 或 `/proc` 文件系统等。但是 Ansible 会生成一个包含此信息的 JSON 文件。每次 Ansible 运行时，它都会生成这些实情数据。在这个数据流中，有大量的信息，都是以键值对形式出现的：`<"variable-name": "value">`。所有这些变量都可以在 Ansible 剧本中使用，理解大量可用信息的最好方法是实际显示一下：

```
# ansible -m setup <hostname> | less

```

明白了吗？你想知道的有关主机硬件和 Linux 发行版的所有内容都在这里，它们都可以在剧本中使用。我还没有达到需要使用这些变量的地步，但是我相信在接下来的几天中会用到。

### 模块

上面的 `ansible` 命令使用 `-m` 选项来指定 `setup` 模块。Ansible 已经内置了许多模块，所以你对这些模块不需要使用 `-m`。也可以安装许多下载的模块，但是内置模块可以完成我目前项目所需的一切。

### 剧本

<ruby> 剧本 <rt>  playbook </rt></ruby>几乎可以放在任何地方。因为我需要以 root 身份运行，所以我将它放在了 `/root/ansible` 下。当我运行 Ansible 时，只要这个目录是当前的工作目录（PWD），它就可以找到我的剧本。Ansible 还有一个选项，用于在运行时指定不同的剧本和位置。

剧本可以包含注释，但是我看到的文章或书籍很少提及此。但作为一个相信记录一切的系统管理员，我发现使用注释很有帮助。这并不是说在注释中做和任务名称同样的事情，而是要确定任务组的目的，并确保我以某种方式或顺序记录我做这些事情的原因。当我可能忘记最初的想法时，这可以帮助以后解决调试问题。

剧本只是定义主机所需状态的任务集合。在剧本的开头指定主机名或清单组，并定义 Ansible 将在其上运行剧本的主机。

以下是我的一个剧本示例：

```
################################################################################
# This Ansible playbook updates Midnight commander configuration files.        #
################################################################################
- name: Update midnight commander configuration files
  hosts: all

  tasks:
  - name: ensure midnight commander is the latest version
    dnf:
      name: mc
      state: present

  - name: create ~/.config/mc directory for root
    file:
      path: /root/.config/mc
      state: directory
      mode: 0755
      owner: root
      group: root

  - name: create ~/.config/mc directory for dboth
    file:
      path: /home/dboth/.config/mc
      state: directory
      mode: 0755
      owner: dboth
      group: dboth

  - name: copy latest personal skin
    copy:
      src: /root/ansible/UpdateMC/files/MidnightCommander/DavidsGoTar.ini
      dest: /usr/share/mc/skins/DavidsGoTar.ini
      mode: 0644
      owner: root
      group: root

  - name: copy latest mc ini file
    copy:
      src: /root/ansible/UpdateMC/files/MidnightCommander/ini
      dest: /root/.config/mc/ini
      mode: 0644
      owner: root
      group: root

  - name: copy latest mc panels.ini file
    copy:
      src: /root/ansible/UpdateMC/files/MidnightCommander/panels.ini
      dest: /root/.config/mc/panels.ini
      mode: 0644
      owner: root
      group: root
<截断>

```

剧本从它自己的名字和它将要操作的主机开始，在本文中，所有主机都在我的 `hosts` 文件中。`tasks` 部分列出了使主机达到所需状态的特定任务。这个剧本从使用 DNF 更新 Midnight Commander 开始（如果它不是最新的版本的话）。下一个任务确保创建所需的目录（如果它们不存在），其余任务将文件复制到合适的位置，这些 `file` 和 `copy` 任务还可以为目录和文件设置所有权和文件模式。

剧本细节超出了本文的范围，但是我对这个问题使用了一点蛮力。还有其它方法可以确定哪些用户需要更新文件，而不是对每个用户的每个文件使用一个任务。我的下一个目标是简化这个剧本，使用一些更先进的技术。

运行剧本很容易，只需要使用 `ansible-playbook` 命令。`.yml` 扩展名代表 YAML，我看到过它的几种不同含义，但我认为它是“<ruby> 另一种标记语言 <rt>  Yet Another Markup Language </rt></ruby>”，尽管有些人声称 YAML 不是这种语言。

这个命令将会运行剧本，它会更新 Midnight Commander 文件：

```
# ansible-playbook -f 10 UpdateMC.yml

```

`-f` 选项指定 Ansible 使用 10 个线程来执行操作。这可以大大加快整个任务的完成速度，特别是在多台主机上工作时。

### 输出

剧本运行时会列出每个任务和执行结果。`ok` 代表任务管理的机器状态已经完成，因为在任务中定义的状态已经为真，所以 Ansible 不需要执行任何操作。

`changed` 表示 Ansible 已经执行了指定的任务。在这种情况下，任务中定义的机器状态不为真，所以执行指定的操作使其为真。在彩色终端上，`TASK` 行会以彩色显示。我的终端配色为“amber-on-black”，`TASK` 行显示为琥珀色，`changed` 是棕色，`ok` 为绿色，错误是红色。

下面的输出是我最终用于在新主机执行安装后配置的剧本：

```
PLAY [Post-installation updates, package installation, and configuration]

TASK [Gathering Facts]
ok: [testvm2]

TASK [Ensure we have connectivity]
ok: [testvm2]

TASK [Install all current updates]
changed: [testvm2]

TASK [Install a few command line tools]
changed: [testvm2]

TASK [copy latest personal Midnight Commander skin to /usr/share]
changed: [testvm2]

TASK [create ~/.config/mc directory for root]
changed: [testvm2]

TASK [Copy the most current Midnight Commander configuration files to /root/.config/mc]
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/DavidsGoTar.ini)
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/ini)
changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightCommander/panels.ini)

TASK [create ~/.config/mc directory in /etc/skel]
changed: [testvm2]

<截断>

```

### cowsay

如果你的计算机上安装了 [cowsay](https://en.wikipedia.org/wiki/Cowsay) 程序，你会发现 `TASK` 的名字出现在奶牛的语音泡泡中：

```
 ____________________________________
< TASK [Ensure we have connectivity] >
 ------------------------------------
        \   ^__^
         \  (oo)\\_______
            (__)\       )\/\
                ||----w |
                ||     ||

```

如果你没有这个有趣的程序，你可以使用发行版的包管理器安装 Cowsay 程序。如果你有这个程序但不想要它，可以通过在 `/etc/ansible/ansible.cfg` 文件中设置 `nocows=1` 将其禁用。

我喜欢这头奶牛，它很有趣，但是它会占用我的一部分屏幕。因此，在它开始妨碍我使用时，我就把它禁用了。

### 目录

与我的 Midnight Commander 任务一样，经常需要安装和维护各种类型的文件。创建用于存储剧本的目录树的“最佳实践”和系统管理员一样多，至少与编写有关 Ansible 书和文章的作者数量一样多。

我选择了一个对我有意义的简单结构：

```
/root/ansible
└── UpdateMC
    ├── files
    │   └── MidnightCommander
    │       ├── DavidsGoTar.ini
    │       ├── ini
    │       └── panels.ini
    └── UpdateMC.yml

```

你可以使用任何结构。但是请注意，其它系统管理员可能需要使用你设置的剧本来工作，所以目录应该具有一定程度的逻辑。当我使用 RPM 和 Bash 脚本执行安装任务后，我的文件仓库有点分散，绝对没有任何逻辑结构。当我为许多管理任务创建剧本时，我将介绍一个更有逻辑的结构来管理我的目录。

### 多次运行剧本

根据需要或期望多次运行剧本是安全的。只有当主机状态与任务中指定的状态不匹配时，才会执行每个任务。这使得很容易从先前的剧本运行中遇到的错误中恢复。因为当剧本遇到错误时，它将停止运行。

在测试我的第一个剧本时，我犯了很多错误并改正了它们。假设我的修正正确，那么剧本每次运行，都会跳过那些状态已与指定状态匹配的任务，执行不匹配状态的任务。当我的修复程序起作用时，之前失败的任务就会成功完成，并且会执行此任务之后的任务 —— 直到遇到另一个错误。

这使得测试变得容易。我可以添加新任务，并且在运行剧本时，只有新任务会被执行，因为它们是唯一与测试主机期望状态不匹配的任务。

### 一些思考

有些任务不适合用 Ansible，因为有更好的方法可以实现特定的计算机状态。我想到的场景是使 VM 返回到初始状态，以便可以多次使用它来执行从已知状态开始的测试。让 VM 进入特定状态，然后对此时的计算机状态进行快照要容易得多。还原到该快照与 Ansible 将主机返回到之前状态相比，通常还原到快照通常会更容易且更快。在研究文章或测试新代码时，我每天都会做几次这样的事情。

在完成用于更新 Midnight Commander 的剧本之后，我创建了一个新的剧本，用于在新安装的 Fedora 主机上执行安装任务。我已经取得了不错的进步，剧本比我第一个的更加复杂，但没有那么粗暴。

在使用 Ansible 的第一天，我创建了一个解决问题的剧本，我还开始编写第二个剧本，它将解决安装后配置的大问题，在这个过程中我学到了很多东西。

尽管我真的很喜欢使用 [Bash](https://opensource.com/downloads/bash-cheat-sheet) 脚本来管理任务，但是我发现 Ansible 可以完成我想要的一切，并且可以使系统保持在我所需的状态。只用了一天，我就成为了 Ansible 的粉丝。

### 资源

我找到的最完整、最有用的参考文档是 Ansible 网站上的[用户指南](https://docs.ansible.com/ansible/latest/user_guide/index.html)。本文仅供参考，不作为入门文档。

多年来，我们已经发布了许多[有关 Ansible 的文章](https://opensource.com/tags/ansible)，我发现其中大多数对我的需求很有帮助。Enable Sysadmin 网站上也有很多对我有帮助 [Ansible 文章](https://www.redhat.com/sysadmin/topics/ansible)。你可以通过查看本周（2020 年 10 月 13 日至 14 日）的 [AnsibleFest](https://www.ansible.com/ansiblefest) 了解更多信息。该活动完全是线上的，可以免费注册。

---

via: <https://opensource.com/article/20/10/first-day-ansible>

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


使用 Joplin 更快地找到你的笔记

>
> 在多个手写和数字平台上整理笔记是一个严峻的挑战。这里有一个小技巧，可以更好地组织你的笔记，并快速找到你需要的东西。
>
>
>

![](/data/attachment/album/202102/03/120141dkiqil1vlqiz6wql.jpg "Working from home at a laptop")

在前几年，这个年度系列涵盖了单个的应用。今年，我们除了关注 2021 年的策略外，还将关注一体化解决方案。欢迎来到 2021 年 21 天生产力的第十五天。

保持生产力也意味着（在某种程度上）要有足够的组织能力，以便找到笔记并在需要时参考它们。这不仅是对我自己的挑战，也是与我交谈的很多人的挑战。

多年来，我在应用中单独或使用数字笔记、纸质笔记、便签、数字便签、Word 文档、纯文本文件以及一堆我忘记的其他格式的组合。这不仅让寻找笔记变得困难，而且知道把它们放在哪里是一个更大的挑战。

![Stacks of paper notes on a desk](/data/attachment/album/202102/03/120202ue9d05xnwbbd945l.jpg)

*一堆笔记 （Jessica Cherry, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

还有就是做笔记最重要的一点：如果你以后找不到它，笔记就没有任何价值。知道含有你所需信息的笔记存在于你保存笔记的*某处*，根本没有任何帮助。

我是如何为自己解决这个问题的呢？正如他们所说，这是一个过程，我希望这也是一个对其他人有效的过程。

我首先看了看自己所做的笔记种类。不同的主题需要用不同的方式保存吗？由于我为我的播客手写笔记，而几乎所有其他的东西都使用纯文本笔记，我需要两种不同的方式来维护它们。对于手写的笔记，我把它们都放在一个文件夹里，方便我参考。

![Man holding a binder full of notes](/data/attachment/album/202102/03/120222eynno0zc1hcnoncd.jpg)

*三年多的笔记 （Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

为了保存我的数字笔记，我需要将它们全部集中到一个地方。这个工具需要能够从多种设备上访问，具有有用的搜索功能，并且能够导出或共享我的笔记。在尝试了很多很多不同的选项之后，我选择了 [Joplin](https://joplinapp.org/)。Joplin 可以让我用 Markdown 写笔记，有一个相当不错的搜索功能，有适用于所有操作系统（包括手机）的应用，并支持几种不同的设备同步方式。另外，它还有文件夹*和*标签，因此我可以按照对我有意义的方式将笔记分组。

![Organized Joplin notes management page](/data/attachment/album/202102/03/120238yk9nngzqgfnf99z3.jpg)

*我的 Joplin*

我花了一些时间才把所有的东西都放在我想要的地方，但最后，这真的是值得的。现在，我可以找到我所做的笔记，而不是让它们散落在我的办公室、不同的机器和各种服务中。

---

via: <https://opensource.com/article/21/1/notes-joplin>

作者：[Kevin Sonney](https://opensource.com/users/ksonney) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


硬核观察 | 阿里云成立十一年来首次盈利

Summary: 更多：• 互联网安全研究小组准备用 Rust 重写 Apache 的 SSL/TLS 模块 • Linux 恶意软件 Kobalos 可利用 OpenSSH 软件后门窃取证书

淘宝天猫支付宝用阿里云机器不给钱吗

![](/data/attachment/album/202102/03/154952h4iivvlwrioezifi.jpg)

#### 阿里云成立十一年来首次盈利

![](/data/attachment/album/202102/03/150658b9huk669oi9ll66c.jpg)

据[报道](https://www.huxiu.com/article/408107.html "https://www.huxiu.com/article/408107.html")，2 月 2 日晚间，阿里巴巴发布了 2021 财年第三季度（也就是自然年 2020 年第四季度）财报，云计算业务收入同比增长 50% 至人民币 161.15 亿元，调整后息税折旧摊销前利润为 2400 万元人民币。这是阿里云首次实现了盈利。而 2019 年同期亏损 3.56 亿元人民币。

作为国内最早投入的云服务商，阿里云曾连续多年在阿里内部拿到低绩效。但在阿里的大力支持下，阿里云成为国内乃至亚洲市场份额第一的云服务商。终于在 11 年之后，守得云开日出，实现了盈亏平衡！阿里云加油！

#### 互联网安全研究小组准备用 Rust 重写 Apache 的 SSL/TLS 模块

![](/data/attachment/album/202102/03/150715jcr8xhrpzzmp8ibs.jpg)

作为 Let's Encrypt 加密倡议的发起者之一，互联网安全研究小组（ISRG）刚刚宣布，他们将使用 Rustles 库取代 OpenSSL，为 httpd 重写一个新的 TLS 模块（mod-tls），并希望在将来可以取代 Apache httpd 默认使用的 mod\_ssl。

经历了十年的发展，Rust 编程语言已经变得相当成熟，默认情况下仅允许编译内存安全型的应用程序。这一宣布得到了 Apache httpd 联合创始人的支持：“我意识到这项重大改进可对许多人提供保护，并且能够让 httpd 在不久的将来继续发光发热。”

在关键性的基础设施方面，Rust 已经展现出了取代 C 语言的潜力。有志于从事基础软件开发的同学，可以考虑尽快学习和使用 Rust 进行开发了。

#### Linux 恶意软件 Kobalos 可利用 OpenSSH 软件后门窃取证书

![](/data/attachment/album/202102/03/150757pzfimi820oax2avi.jpg)

[ESET](https://www.cnbeta.com/articles/tech/1086111.htm "https://www.cnbeta.com/articles/tech/1086111.htm")警告称，一款被挂有木马的 OpenSSH 软件，被用于从 HPC 高性能计算集群中窃取 SSH 证书。它渗透了一些主要目标，包括美国政府、欧洲大学、以及亚洲某些大型 ISP 的系统，受害者主要集中在大型系统和超级计算机领域。除了 Linux、FreeBSD 和 Solaris，安全专家还发现了能够在 AIX、甚至 Windows 平台上运行的恶意软件变种的蛛丝马迹。

无论是否是因为这个恶意软件，都建议为 SSH 服务器连接同时启用双因素身份验证。


Python 代码一致性的重要性

>
> 本文是 Python 之禅特殊系列的一部分，重点是第十二、十三和十四原则：模糊性和明确性的作用。
>
>
>

![](/data/attachment/album/202102/03/231758po1lcicxmxyjxlba.jpg "Two animated computers waving one missing an arm")

最小惊喜原则是设计用户界面时的一个 [准则](https://www.uxpassion.com/blog/the-principle-of-least-surprise/)。它是说，当用户执行某项操作时，程序执行的事情应该使用户尽量少地感到意外。这和孩子们喜欢一遍又一遍地读同一本书的原因是一样的：没有什么比能够预测并让预测成真更让人欣慰的了。

在开发 [ABC 语言](https://en.wikipedia.org/wiki/ABC_(programming_language))（Python 的灵感来源）的过程中，一个重要的见解是，编程设计是用户界面，需要使用与 UI 设计者相同的工具来设计。值得庆幸的是，从那以后，越来越多的语言采用了 UI 设计中的<ruby> 可承受性 <rt>  affordance </rt></ruby>和<ruby> 人体工程学 <rt>  ergonomics </rt></ruby>的概念，即使它们的应用并不严格。

这就引出了 [Python 之禅](https://www.python.org/dev/peps/pep-0020/) 中的三个原则。

### <ruby> 面对歧义，要拒绝猜测的诱惑 <rt>  In the face of ambiguity, refuse the temptation to guess </rt></ruby>

`1 + "1"` 的结果应该是什么? `"11"` 和 `2` 都是猜测。这种表达方式是*歧义的*：无论如何做都会让一些人感到惊讶。

一些语言选择猜测。在 JavaScript 中，结果为 `"11"`。在 Perl 中，结果为 `2`。在 C 语言中，结果自然是空字符串。面对歧义，JavaScript、Perl 和 C 都在猜测。

在 Python 中，这会引发 `TypeError`：这不是能忽略的错误。捕获 `TypeError` 是非典型的：它通常将终止程序或至少终止当前任务（例如，在大多数 Web 框架中，它将终止对当前请求的处理）。

Python 拒绝猜测 `1 + "1"` 的含义。程序员必须以明确的意图编写代码：`1 + int("1")`，即 `2`；或者 `str(1) + "1"`，即 `"11"`；或 `"1"[1:]`，这将是一个空字符串。通过拒绝猜测，Python 使程序更具可预测性。

### <ruby> 尽量找一种，最好是唯一一种明显的解决方案 <rt>  There should be one—and preferably only one—obvious way to do it </rt></ruby>

预测也会出现偏差。给定一个任务，你能预知要实现该任务的代码吗？当然，不可能完美地预测。毕竟，编程是一项具有创造性的任务。

但是，不必有意提供多种冗余方式来实现同一目标。从某种意义上说，某些解决方案或许 “更好” 或 “更 <ruby> Python 化 <rt>  Pythonic </rt></ruby>”。

对 Python 美学欣赏部分是因为，可以就哪种解决方案更好进行健康的辩论。甚至可以持不同观点而继续编程。甚至为使其达成一致，接受不同意的观点也是可以的。但在这一切之下，必须有一种这样的认识，即正确的解决方案终将会出现。我们必须希望，通过商定实现目标的最佳方法，而最终达成真正的一致。

### <ruby> 虽然这种方式一开始可能并不明显（除非你是荷兰人） <rt>  Although that way may not be obvious at first (unless you're Dutch) </rt></ruby>

这是一个重要的警告：首先，实现任务的最佳方法往往*不*明显。观念在不断发展。Python 也在进化。逐块读取文件的最好方法，可能要等到 Python 3.8 时使用 [walrus 运算符](https://www.python.org/dev/peps/pep-0572/#abstract)（`:=`）。

逐块读取文件这样常见的任务，在 Python 存在近 *30年* 的历史中并没有 “唯一的最佳方法”。

当我在 1998 年从 Python 1.5.2 开始使用 Python 时，没有一种逐行读取文件的最佳方法。多年来，知道字典中是否有某个键的最佳方法是使用关键字 `.haskey`，直到 `in` 操作符出现才发生改变。

只是要意识到找到实现目标的一种（也是唯一一种）方法可能需要 30 年的时间来尝试其它方法，Python 才可以不断寻找这些方法。这种历史观认为，为了做一件事用上 30 年是可以接受的，但对于美国这个存在仅 200 多年的国家来说，人们常常会感到不习惯。

从 Python 之禅的这一部分来看，荷兰人，无论是 Python 的创造者 [Guido van Rossum](https://en.wikipedia.org/wiki/Guido_van_Rossum) 还是著名的计算机科学家 [Edsger W. Dijkstra](http://en.wikipedia.org/wiki/Edsger_W._Dijkstra)，他们的世界观是不同的。要理解这一部分，某种程度的欧洲人对时间的感受是必不可少的。

---

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

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

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


开源项目的版权声明已无存在必要？

Summary: 保留简略的版权声明即可，无需投入过多资源维护。

因为有人不守法，法律就没意义了？<br />
脑洞比我的大。

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

哈哈哈！

steven_zdg988 [Chrome Mobile 77.0|Android 10]

建议译者写书吧，下次贴上新书我会考虑买来看看

建议译者写书吧，下次贴上新书我会考虑买来看看

保留简略的版权声明即可，无需投入过多资源维护。

>
> 保留简略的版权声明即可，无需投入过多资源维护。
>
>
>

![](/data/attachment/album/202102/04/085612fjj2a6zj5rzhj5fq.jpg)

<ruby> 版权声明 <rp>  （ </rp> <rt>  Copyright Notice </rt> <rp>  ） </rp></ruby>在源代码中的应用并不一致且维护不善，结果导致它无法成为良好的信息来源。那是否应该投入更多资源来维护版权声明呢？答案是不需要。

版权声明是单行字符串，通常包括单词“版权”（或某些替代词，如 ©）、名称（通常是个人或公司）和年份。

在本文中，我不关注许可证或许可证声明（有时可能包括版权声明）。我关于版权声明维护的资源投入应该保持低优先级的建议不适用于许可证信息。许可证信息应清晰呈现并保持准确。如果你邀请其他人使用你的软件并对其进行操作，请通过提供并维护清晰的许可证信息来明确其授予的权限。

再说回版权声明：它们的法律意义是什么呢？如果你认为版权声明符合法律要求或至少提供了重要的法律权益，请三思。此类声明在开源软件中的法律意义是如此之小，以至于人们可以轻易地找到超出其法律意义的实际做法。

尽管此类声明可能看起来很重要，但它们在当今源代码中的存在很大程度上是过去美国版权法的残余影响。曾经有一段时间，如果未在已出版的材料中包含版权声明，依据美国版权法，版权人可能会完全丧失权利；当美国最终加入《[伯尔尼公约](https://www.wipo.int/treaties/en/ip/berne/)》并成为缔约国时，情况发生了变化（美国于 1988 年 11 月 16 日加入该条约，并于 1989 年 3 月 1 日在美国生效）。

如果开源软件中的此类声明要想具备实效，则一个项目可以采用能够以更少的投入来维护并且仍然获得一些实用价值的约定，不必为了满足美国对“版权声明”的法定要求而去维护版权声明。

由于美国版权法一直是推动版权声明使用的重要因素，因此我将在此进行更深入的探讨。美国版权局发布了名为《[通函-3号-版权声明](https://www.copyright.gov/circs/circ03.pdf)》的指导文件，包括：

*“在* *1989* *年* *3* *月* *1* *日之前首次出版的所有作品都必须放置版权声明，但下面讨论的某些情况例外。**如果省略了该声明或在使用该声明时出现了错误，则通常该作品在美国将失去版权保护。**版权声明对于* *1989* *年* *3* *月* *1* *日或之后出版的作品、未出版的作品和外国作品是可选的；但是，将版权声明包括在你的作品中将享有法律权益。”*

上面我加粗强调的那句话清楚地表明，在 1988 年的美国，版权声明就非常重要。但是，当美国与其他许多国家一起加入《伯尔尼公约》时，美国法律对版权声明的关键作用被消除了。公约规定：“享有和行使这些权利不需经过任何手续……”

麻省理工学院的软件项目（The X Window System）和加州大学伯克利分校的软件项目（Berkeley Software Distribution）中诞生了早期的开源许可证文本，彼时严格的“放置版权声明否则丧失权利”要求仍然有效（或至少在为这些许可证文本做出贡献的人们心中是明确的）。诞生于这种时机的结果是，许可证文本中仍存在有关复制版权声明的明确描述。

随着基于早期文本的许可证的继续广泛使用，大多数开源软件开发人员已经看到，版权声明似乎在许可证中显得很重要。但是这些文本是在考虑较早的法律制度的情况下创建的。现在，距《伯尔尼公约》（大多数其他国家已经接受）的“无需手续性要求”规定首次适用于美国的时间已经过去 30 年了。要了解《伯尔尼公约》的通过程度，请参阅管理该公约的世界知识产权组织维护的[缔约方清单](https://www.wipo.int/treaties/en/ShowResults.jsp?lang=en&treaty_id=15)。

你可能想知道上面引用中提到的那些“法律权益”具体指什么，答案在 3 号通函的末尾：

>
> 尽管对于未出版的作品、外国作品或于1989年3月1日或之后出版的作品，版权声明是可选的，但使用版权声明具有以下好处：
>
>
> * 版权声明使潜在用户意识到该作品拥有版权。
> * 对于已发表的作品，版权声明可能会阻止版权侵权诉讼中的被告试图减轻其基于无辜侵权辩护的损害赔偿或禁令救济的责任。
> * 版权声明标识了在首次发布作品时版权所有者的权利，供寻求使用该作品的许可方使用。
> * 版权声明标识首次出版的年份，对于匿名作品、假名作品或出租作品而言，可用于确定版权保护期限。
> * 版权声明可能会通过标识版权所有者并设定版权期限来防止其成为孤儿作品。
>
>
>

上面就是所谓的那些“法律权益”。

我引用了美国版权局第 3 号通函，因为与基本法规相比，它对要求的措辞更具可读性。美国联邦一级的成文法被编入所谓的《美国法典》，该法典被组织为一组<ruby> “卷” <rp>  （ </rp> <rt>  Title </rt> <rp>  ） </rp></ruby>。第 17 卷是版权。版权声明的详细信息位于该卷的第 401-406 部分。可以从 17 USC 401 开始。在版权声明中需包含三个要素描述的有关法规要求，请参见 [17 USC 401（b）](https://www.copyright.gov/title17/92chap4.html#401)。如果要查看“疏忽对无辜侵权者的影响”的详细信息，请参见 [17 USC 405（b）](https://www.copyright.gov/title17/92chap4.html#405)。

为了提供更准确的信息，为什么不清理代码库中的版权声明？尴尬的是，[17 USC 506（c）（欺诈性版权声明）](https://www.copyright.gov/title17/92chap5.html#506)、[17 USC 506（d）（欺诈性删除版权声明）](https://www.copyright.gov/title17/92chap5.html#506)和 [17 USC 1202（a）（虚假版权管理信息）](https://www.copyright.gov/title17/92chap12.html#1202)提供了一些不利因素（即使仅限于不良意图）。由于价值较低且存在一定风险（如果在进行更改时出错），因此难怪没有更多资源用于维护版权声明。

有些人和一些公司强调将详细的版权声明放入根据开源许可证提供的代码中。其他人则没有。随着开源项目的发展，某些贡献中可能包含版权声明，而其他贡献则没有。即使文件的内容与原始版本相比发生了很大的变化，文件也可以包含原始版权声明，而不包含其他版权声明。或者以后的贡献者可以向以前没有版权声明的文件中添加一个版权声明。那作为版权声明要素的“该作品的首次出版年份”呢？这意味着什么？不同的人有不同的做法。已更新？那其他贡献提交之后呢？

至于从挖掘版权声明数据中得出结论，要谨慎。期望值不要那么高。

那开源项目应该怎么做呢？

请提供并维护清晰、准确的许可证信息。

对于版权声明来说，很难证明为维护版权声明的详细信息而进行的投入是合理的。但是有些人可能希望会出现版权声明。至于“软件的起源”，也许仅仅参考项目本身而不是尝试捕获更细粒度的内容可能会更有用和更准确。公开年份？手动维护源文件中的麻烦程度导致其不大值得；源管理工具以较低的资源成本提供了更准确的信息。

有关实用方法的更多详细信息，我建议你将注意力集中在对版权声明实践的重新思考上，可以参考 Steve Winslow 于 2020 年 1 月 10 日发布的《[开源软件项目中的版权声明](https://www.linuxfoundation.org/blog/2020/01/copyright-notices-in-open-source-software-projects/)》。

---

作者简介：Scott Peterson 是红帽公司（Red Hat）法律团队成员。很久以前，一位工程师就一个叫做 GPL 的奇怪文件向 Scott 征询法律建议，这个致命的问题让 Scott 走上了探索包括技术标准和开源软件在内的协同开发法律问题的纠结之路。

译者简介：薛亮，集慧智佳知识产权咨询公司互联网事业部总监，擅长专利检索、专利分析、竞争对手跟踪、FTO 分析、开源软件知识产权风险分析，致力于为互联网企业、高科技公司提供知识产权咨询服务。

![](/data/attachment/album/202102/04/085738ztovsnv2tt9t6sez.jpg)


将你的树莓派用作生产力源泉

Summary: 树莓派已经从主要为黑客和业余爱好者服务，成为了小型生产力工作站的可靠选择。

官方64位Debian Gnu/Linux什么时候才能出来，这个我挺关注

这种无关痛痒的文章，有翻译的价值吗？

强行生产力

文章确实没看出来有多大价值被翻译

树莓派已经从主要为黑客和业余爱好者服务，成为了小型生产力工作站的可靠选择。

>
> 树莓派已经从主要为黑客和业余爱好者服务，成为了小型生产力工作站的可靠选择。
>
>
>

![](/data/attachment/album/202102/04/103826pjbxb7j1m8ok6ezf.jpg "Team checklist and to dos")

在前几年，这个年度系列涵盖了单个的应用。今年，我们除了关注 2021 年的策略外，还将关注一体化解决方案。欢迎来到 2021 年 21 天生产力的第十六天。

[树莓派](https://www.raspberrypi.org/)是一台相当棒的小电脑。它体积小，功能却出奇的强大，而且非常容易设置和使用。我曾将它们用于家庭自动化项目、面板和专用媒体播放器。但它也能成为生产力的动力源泉么？

答案相当简单：是的。

![Geary and Calendar apps on the Raspberry Pi](/data/attachment/album/202102/04/103433i0dllltoqhavqr0q.jpg)

*Geary 和 Calendar 应用 （Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

基本的 [Raspbian](https://www.raspbian.org/) 安装包括 [Claw Mail](https://www.claws-mail.org/)，这是一个轻量级的邮件客户端。它的用户界面有点过时了，而且非常的简陋。如果你是一个 [Mutt 用户](http://www.mutt.org/)，它可能会满足你的需求。

我更喜欢安装 [Geary](https://wiki.gnome.org/Apps/Geary)，因为它也是轻量级的，而且有一个现代化的界面。另外，与 Claws 不同的是，Geary 默认支持富文本 （HTML） 邮件。我不喜欢富文本电子邮件，但它已经成为必要的，所以对它有良好的支持是至关重要的。

默认的 Raspbian 安装不包含日历，所以我添加了 [GNOME 日历](https://wiki.gnome.org/Apps/Calendar) ，因为它可以与远程服务通信（因为我的几乎所有日历都在云提供商那里）。

![GTG and GNote open on Raspberry Pi](/data/attachment/album/202102/04/104029je999sg159vgdvpp.jpg)

*GTG 和 GNote（Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

那笔记和待办事项清单呢？有很多选择，但我喜欢用 [GNote](https://wiki.gnome.org/Apps/Gnote) 来做笔记，用 [Getting-Things-GNOME!](https://wiki.gnome.org/Apps/GTG) 来做待办事项。两者都相当轻量级，并且可以相互同步，也可以同步到其他服务。

你会注意到，我在这里使用了不少 GNOME 应用。为什么不直接安装完整的 GNOME 桌面呢？在内存为 4Gb（或 8Gb）的树莓派 4 上，GNOME 工作得很好。你需要采取一些额外的步骤来禁用 Raspbian 上的默认 wifi 设置，并用 Network Manager 来代替它，但这个在网上有很好的文档，而且真的很简单。

GNOME 中包含了 [Evolution](https://opensource.com/business/18/1/desktop-email-clients)，它将邮件、日历、笔记、待办事项和联系人管理整合到一个应用中。与 Geary 和 GNOME Calendar 相比，它有点重，但在树莓派 4 上却很稳定。这让我很惊讶，因为我习惯了 Evolution 有点消耗资源，但树莓派 4 却和我的品牌笔记本一样运行良好，而且资源充足。

![Evolution on Raspbian](/data/attachment/album/202102/04/104447oexluxl868kgl3gl.jpg)

*Raspbian 上的 Evolution （Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

树莓派在过去的几年里进步很快，已经从主要为黑客和业余爱好者服务，成为了小型生产力工作站的可靠选择。

---

via: <https://opensource.com/article/21/1/raspberry-pi-productivity>

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


硬核观察 | 谷歌云计算业务去年亏损 56 亿美元

Summary: 更多：• CNNIC 发布第 47 次《中国互联网络发展状况统计报告》 • 文档基金会发布 LibreOffice 7.1 “社区”版

谷歌牛人那么多，最后只有广告赚钱

![](/data/attachment/album/202102/04/122513g5v8k4tt18z8b671.jpg)

#### 谷歌云计算业务去年亏损 56 亿美元

![](/data/attachment/album/202102/04/122137trh2z2zic9jni8a8.jpg)

谷歌刚刚[披露了](https://www.cnbc.com/2021/02/02/google-cloud-lost-5point61-billion-on-13point06-billion-revenue-last-year.html)最新财报，透露其云计算业务去年全年收入 130.6 亿美元，全年亏损 56.1 亿美元。

这是谷歌首次公开云计算业务的营业收入指标。谷歌最主要收入来自于广告，云计算业务是其多元化收入来源的重要一环。由于该公司在销售人员上进行了大量投资，该部门的亏损正在增加。在 2018 年，该公司的云计算业务收入 58.4 亿美元，亏损 43.5 亿美元，在2019 年收入 89.2 亿美元，亏损 46.5 亿美元。

#### CNNIC 发布第 47 次《中国互联网络发展状况统计报告》

![](/data/attachment/album/202102/04/122148ymt88jhshjpuhb0z.jpg)

该[报告](http://www.cac.gov.cn/2021-02/03/c_1613923423079314.htm)显示，截至 2020 年 12 月，IPv6 地址数量为 57634 块/32，较 2019 年底增长 13.3%。我国域名总数为 4198 万个。其中，.CN 域名总数为 1897 万个，占我国域名总数的 45.2%；.COM 域名数量为 1263 万个，占我国域名总数的 31.1%。我国国际出口带宽为11511397Mbps，较2019年底增长30.4%。

另外一个值得注意的数据是，截至 2020 年 12 月，我国网络视频（含短视频）用户规模达 9.27 亿，占网民整体的 93.7%；其中，短视频用户规模达 8.73 亿，占网民整体的 88.3%。

#### 文档基金会发布 LibreOffice 7.1 “社区”版

![](/data/attachment/album/202102/04/122202ypa62ipppl6gni6y.jpg)

刚刚发布的 [LibreOffice 7.1](https://blog.documentfoundation.org/blog/2021/02/03/libreoffice-7-1-community/) 现在明确打上了 “社区” 标签。自从之前文档基金会表示将 LibreOffice 分为社区版和企业版之后，引来了社区的一些不同看法。文档基金会表示 “‘社区’标签强调了该软件并非针对企业，也没有针对企业的支持需求进行优化”。

因为越来越多的企业选择了志愿者支持的版本，而不是针对其需求进行优化的版本。文档基金会认为这给该项目带来了两方面的负面影响：一是志愿者的时间没有得到很好的利用，因为他们不得不把时间花在为企业解决问题上，而这些问题却没有为社区提供任何回报；二是生态系统企业的净损失。

对于这种做法，我觉得，有可持续发展的生态的开源项目，才是有生命力的开源项目。只是文档基金会可以在具体的社区和产品策略上做得更好一些。


3 个电子邮件错误以及如何避免它们

>
> 自动化是美好的，但也不总是那样。确保你的电子邮件自动回复和抄送配置正确，这样你就不会浪费大家的时间。
>
>
>

![](/data/attachment/album/202102/05/090335a888nqn7pcolblzn.jpg "Computer screen with files or windows open")

在前几年，这个年度系列涵盖了单个的应用。今年，我们除了关注 2021 年的策略外，还将关注一体化解决方案。欢迎来到 2021 年 21 天生产力的第十七天。

好了，我们已经谈到了一些我们应该对电子邮件做的事情：[不要再把它当作即时通讯工具](https://opensource.com/article/21/1/email-rules)、[优先处理事情](https://opensource.com/article/21/1/prioritize-tasks)、[努力达到收件箱 0 新邮件](https://opensource.com/article/21/1/inbox-zero)，以及[有效过滤](https://opensource.com/article/21/1/email-filter)。但哪些事情是我们不应该做的呢？

![Automated email reply](/data/attachment/album/202102/05/090345awbi2rvfibri2gvi.png)

*你真幸运 （Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

### 1、请不要对所有事情自动回复

邮件列表中总有些人，他们去度假了，并设置了一个“我在度假”的自动回复信息。然而，他们没有正确地设置，所以它对列表上的每一封邮件都会回复“我在度假”，直到管理员将其屏蔽或取消订阅。

我们都感受到了这种痛苦，我承认过去至少有一次，我就是那个人。

从我的错误中吸取教训，并确保你的自动回复器或假期信息对它们将回复谁和多久回复一次有限制。

![An actual email with lots of CC'd recipients](/data/attachment/album/202102/05/090346uju85868uz4f84u8.png)

*这是一封真实的电子邮件 （Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

### 2、请不要抄送给所有人

我们都至少做过一次。我们需要发送邮件的人员众多，因此我们只需抄送他们*所有人*。有时这是有必要的，但大多数时候，它并不是。当然，你邀请每个人在庭院吃生日蛋糕，或者你的表姐要结婚了，或者公司刚拿到一个大客户，这都是好事。如果你有邮件列表的话，请用邮件列表，如果没有的话，请给每个人密送。说真的，密送是你的朋友。

### 3、回复所有人不是你的朋友

![Reply options in Kmail](/data/attachment/album/202102/05/090346hjno951p19ngenrj.jpg "Reply options in Kmail")

这一条与上一条是相辅相成的。我不知道有多少次看到有人向一个名单（或者是一个大群的人）发送信息，而这个信息本来是要发给一个人的。我见过这样发送的相对好的邮件，以及随之而来的纪律处分邮件。

认真地说，除非必须，不要使用“回复全部”按钮。即使是这样，也要确保你*真的*需要这样做。

有些电子邮件应用比其他应用管理得更好。Kmail，[KDE Kontact](https://opensource.com/article/21/1/kde-kontact) 的电子邮件组件，在**回复**工具栏按钮的子菜单中，有几个不同的回复选项。你可以选择只回复给**发件人**字段中的任何实体（通常是一个人，但有时是一个邮件列表），或者回复给作者（在抄送或密送中去除每一个人），或者只回复给一个邮件列表，或者回复*所有人*（不要这样做）。看到明确列出的选项，的确可以帮助你了解谁会收到你要发送的邮件副本，这有时比你想象的更发人深省。我曾经发现，当我意识到一个评论并不一定会对一个复杂的讨论的最终目标有所帮助时，我就会把邮件的收件人改为只是作者，而不是整个列表。

（另外，如果你写的邮件可能会给你的 HR 或公司带来麻烦，请在点击发送之前多考虑下。——

希望你已经*不再*在电子邮件中这么做了。如果你认识的人是这样的呢？欢迎与他们分享。

---

via: <https://opensource.com/article/21/1/email-mistakes>

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


通过编写一个简单的游戏学习 JavaScript

>
> 通过使用一个简单的游戏来练习一些基本的 JavaScript 概念，迈出创建交互性动态 Web 内容的第一步。
>
>
>

![](/data/attachment/album/202102/05/151531z6fzqx8vk8tdan81.jpg "Javascript code close-up with neon graphic overlay")

可以肯定地说，没有 [JavaScript](https://opensource.com/tags/javascript)，大多数现代 Web 都将不存在。它是三种标准 Web 技术（以及 HTML 和 CSS ）之一，它使任何人都可以创建我们在万维网体验中所期待的交互式、动态内容。从 [React](https://opensource.com/article/20/11/reactjs-tutorial) 这样的框架到 [D3](https://opensource.com/article/18/9/open-source-javascript-chart-libraries) 这样的数据可视化库，很难想象没有它的 Web。

现在有很多东西要学习，开始学习这种流行语言的好方法是编写一个简单的应用程序以熟悉某些概念。 最近，一些人写了关于如何通过编写简单的猜谜游戏来学习自己喜欢的语言的文章，因此这是一个很好的起点！

### 现在开始吧

JavaScript 有许多种风格，但我将从最基本的开始，通常称为 “普通 JavaScript”。 JavaScript 主要是一种客户端脚本语言，因此它可以在任何标准浏览器中运行，而无需安装任何程序。你只需要一个代码编辑器（[Brackets](https://opensource.com/article/20/12/brackets) 就是一个不错的选择）和一个 Web 浏览器。

### HTML 用户界面

JavaScript 在 Web 浏览器中运行，并与其他标准 Web 技术 HTML 和 CSS 交互。要创建此游戏，你首先需要使用 HTML（超文本标记语言）来创建供玩家使用的简单界面。如果你不清楚，HTML 是一种标记语言，用于为 Web 内容提供结构。

首先，先创建一个 HTML 文件。该文件应具有 `.html` 扩展名，以使浏览器知道它是 HTML 文档。你可以将文件命名为 `guessingGame.html`。

在此文件中使用一些基本的 HTML 标签来显示游戏的标题、玩法说明，供玩家用来输入和提交其猜测的交互式元素以及用于向玩家提供反馈的占位符：

```
<!DOCTYPE>
  <html>
    <head>
      <meta charset="UTF-8" />
      <title> JavaScript Guessing Game </title>
    </head>
    <body>
      <h1>Guess the Number!</h1>
      <p>I am thinking of a number between 1 and 100. Can you guess what it is?</p>

      <label for="guess">My Guess</label>
      <input type="number" id="guess">
      <input type="submit" id="submitGuess" value="Check My Guess">

      <p id="feedback"></p>
    </body>
  </html>

```

`<h1>` 和 `<p>` 元素使浏览器知道在页面上显示什么类型的文本。标签对 `<h1></h1>` 表示标签之间的文本（`Guess the Number!`）是标题。后面的一组 `<p>` 标签表示带有说明的短文本是一个段落。此代码块末尾的空 `<p>` 标签用作占位符，用于根据用户的输入提供一些反馈。

### `<script>` 标签

在网页中包含 JavaScript 的方法有很多种，但是对于像这样的简短脚本，可以使用一组 `<script>` 标签并将 JavaScript 直接写在 HTML 文件中。 这些 `<script>` 标签应位于 HTML 文件末尾附近的 `</body>` 标签之前。

现在，你可以开始在这两个脚本标签之间编写 JavaScript。 最终文件如下所示：

```
<!DOCTYPE>
<html>

<head>
  <meta charset="UTF-8" />
  <title> JavaScript Guessing Game </title>
</head>

<body>
  <h1>Guess the Number!</h1>
  <p>I am thinking of a number between 1 and 100. Can you guess what it is?</p>

  <form>
    <label for="guess">My Guess</label>
    <input type="number" id="guess">
    <input type="submit" id="submitGuess" value="Check My Guess">
  </form>

  <p id="feedback"></p>

  <script>
    const randomNumber = Math.floor(Math.random() * 100) + 1
    console.log('Random Number', randomNumber)

    function checkGuess() {
      let myGuess = guess.value
      if (myGuess === randomNumber) {
        feedback.textContent = "You got it right!"
      } else if (myGuess > randomNumber) {
        feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
      } else if (myGuess < randomNumber) {
       feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
     }
   }
   submitGuess.addEventListener('click', checkGuess)
 </script>

</body>

</html>

```

要在浏览器中运行此文件，请双击文件或打开你喜欢的浏览器,点击菜单，然后选择**文件->打开文件**。（如果使用 Brackets 软件，也可以使用角落处的闪电图标在浏览器中打开文件）。

### 生成伪随机数

猜谜游戏的第一步是为玩家生成一个数字供玩家猜测。JavaScript 包含几个内置的全局对象，可帮助你编写代码。要生成随机数，请使用 `Math` 对象。

JavaScript中的 [Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math) 具有处理和数学相关的属性和功能。你将使用两个数学函数来生成随机数，供你的玩家猜测。

[Math.random()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random)，会将生成一个介于 0 和 1 之间的伪随机数。（`Math.random` 包含 0 但不包含 1。这意味着该函数可以生成 0 ，永远不会产生 1）

对于此游戏，请将随机数设置在 1 到 100 之间以缩小玩家的选择范围。取刚刚生成的小数，然后乘以 100，以产生一个介于 0 到……甚至不是 100 之间的小数。至此，你将需要其他步骤来解决这个问题。

现在，你的数字仍然是小数，但你希望它是一个整数。为此，你可以使用属于 `Math` 对象的另一个函数 [Math.floor()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor)。`Math.floor()` 的目的是返回小于或等于你作为参数指定的数字的最大整数，这意味着它会四舍五入为最接近的整数：

```
Math.floor(Math.random() * 100)

```

这样你将得到 0 到 99 之间的整数，这不是你想要的范围。你可以在最后一步修复该问题，即在结果中加 1。瞧！现在，你有一个（有点）随机生成的数字，介于 1 到 100 之间：

```
Math.floor(Math.random() * 100) + 1

```

### 变量

现在，你需要存储随机生成的数字，以便可以将其与玩家的猜测进行比较。为此，你可以将其存储到一个 **变量**。

JavaScript 具有不同类型的变量，你可以选择这些类型，具体取决于你要如何使用该变量。对于此游戏，请使用 `const` 和 `let`。

* `let` 用于指示变量在整个程序中可以改变。
* `const` 用于指示变量不应该被修改。

`const` 和 `let` 还有很多要说的，但现在知道这些就足够了。

随机数在游戏中仅生成一次，因此你将使用 `const` 变量来保存该值。你想给变量起一个清楚地表明要存储什么值的名称，因此将其命名为 `randomNumber`：

```
const randomNumber

```

有关命名的注意事项：JavaScript 中的变量和函数名称以驼峰形式编写。如果只有一个单词，则全部以小写形式书写。如果有多个单词，则第一个单词均为小写，其他任何单词均以大写字母开头，且单词之间没有空格。

### 打印到控制台

通常，你不想向任何人显示随机数，但是开发人员可能想知道生成的数字以使用它来帮助调试代码。 使用 JavaScript，你可以使用另一个内置函数 [console.log()](https://developer.mozilla.org/en-US/docs/Web/API/Console/log) 将数字输出到浏览器的控制台。

大多数浏览器都包含开发人员工具，你可以通过按键盘上的 `F12` 键来打开它们。从那里，你应该看到一个 **控制台** 标签。打印到控制台的所有信息都将显示在此处。由于到目前为止编写的代码将在浏览器加载后立即运行，因此，如果你查看控制台，你应该会看到刚刚生成的随机数！

![Javascript game with console](/data/attachment/album/202102/05/151559etyfyhs7uvhafa5u.png "Javascript game with console")

### 函数

接下来，你需要一种方法来从数字输入字段中获得玩家的猜测，将其与你刚刚生成的随机数进行比较，并向玩家提供反馈，让他们知道他们是否正确猜到了。为此，编写一个函数。 **函数** 是执行一定任务的代码块。函数是可以重用的，这意味着如果你需要多次运行相同的代码，则可以调用函数，而不必重写执行任务所需的所有步骤。

根据你使用的 JavaScript 版本，有许多不同的方法来编写或声明函数。由于这是该语言的基础入门，因此请使用基本函数语法声明函数。

以关键字 `function` 开头，然后起一个函数名。好的做法是使用一个描述该函数的功能的名称。在这个例子中，你正在检查玩家的猜测的数，因此此函数的名字可以是 `checkGuess`。在函数名称之后，写上一组小括号，然后写上一组花括号。 你将在以下花括号之间编写函数的主体：

```
function checkGuess() {}

```

### 使用 DOM

JavaScript 的目的之一是与网页上的 HTML 交互。它通过文档对象模型（DOM）进行此操作，DOM 是 JavaScript 用于访问和更改网页信息的对象。现在，你需要从 HTML 中获取数字输入字段中玩家的猜测。你可以使用分配给 HTML 元素的 `id` 属性（在这种情况下为 `guess`）来做到这一点：

```
<input type="number" id="guess">

```

JavaScript 可以通过访问玩家输入到数字输入字段中的数来获取其值。你可以通过引用元素的 ID 并在末尾添加 `.value` 来实现。这次，使用 `let` 定义的变量来保存用户的猜测值：

```
let myGuess = guess.value

```

玩家在数字输入字段中输入的任何数字都将被分配给 `checkGuess` 函数中的 `myGuess` 变量。

### 条件语句

下一步是将玩家的猜测与游戏产生的随机数进行比较。你还想给玩家反馈，让他们知道他们的猜测是太高，太低还是正确。

你可以使用一系列条件语句来决定玩家将收到的反馈。**条件语句** 在运行代码块之前检查是否满足条件。如果不满足条件，则代码停止，继续检查下一个条件，或者继续执行其余代码，而无需执行条件块中的代码：

```
if (myGuess === randomNumber){
  feedback.textContent = "You got it right!"
}
else if(myGuess > randomNumber) {
  feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
}
else if(myGuess < randomNumber) {
  feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
}

```

第一个条件块使用比较运算符 `===` 将玩家的猜测与游戏生成的随机数进行比较。比较运算符检查右侧的值，将其与左侧的值进行比较，如果匹配则返回布尔值 `true`，否则返回布尔值 `false`。

如果数字匹配（猜对了！），为了让玩家知道。通过将文本添加到具有 `id` 属性 `feedback` 的 `<p>` 标记中来操作 DOM。就像上面的 `guess.value` 一样，除了不是从 DOM 获取信息，而是更改其中的信息。`<p>` 元素没有像 `<input>` 元素那样的值，而是具有文本，因此请使用 `.textContent` 访问元素并设置要显示的文本：

```
feedback.textContent = "You got it right!"

```

当然，玩家很有可能在第一次尝试时就猜错了，因此，如果 `myGuess` 和 `randomNumber` 不匹配，请给玩家一个线索，以帮助他们缩小猜测范围。如果第一个条件失败，则代码将跳过该 `if` 语句中的代码块，并检查下一个条件是否为 `true`。 这使你进入 `else if` 块：

```
else if(myGuess > randomNumber) {
  feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
}

```

如果你将其作为句子阅读，则可能是这样的：“如果玩家的猜测等于随机数，请让他们知道他们猜对了。否则，请检查玩家的猜测是否大于 `randomNumber`，如果是，则显示玩家的猜测并告诉他们太高了。”

最后一种可能性是玩家的猜测低于随机数。 要检查这一点，再添加一个 `else if` 块：

```
else if(myGuess < randomNumber) {
  feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
}

```

### 用户事件和事件监听器

如果你看上面的代码，则会看到某些代码在页面加载时自动运行，但有些则不会。你想在玩游戏之前生成随机数，但是你不想在玩家将数字输入到数字输入字段并准备检查它之前检查其猜测。

生成随机数并将其打印到控制台的代码不在函数的范围内，因此它将在浏览器加载脚本时自动运行。 但是，要使函数内部的代码运行，你必须对其进行调用。

调用函数有几种方法。在此，你希望该函数在用户单击 “Check My Guess” 按钮时运行。单击按钮将创建一个用户事件，然后 JavaScript 可以 “监听” 这个事件，以便知道何时需要运行函数。

代码的最后一行将事件侦听器添加到按钮上，以在单击按钮时调用函数。当它“听到”该事件时，它将运行分配给事件侦听器的函数：

```
submitGuess.addEventListener('click', checkGuess)

```

就像访问 DOM 元素的其他实例一样，你可以使用按钮的 ID 告诉 JavaScript 与哪个元素进行交互。 然后，你可以使用内置的 `addEventListener` 函数来告诉 JavaScript 要监听的事件。

你已经看到了带有参数的函数，但花点时间看一下它是如何工作的。参数是函数执行其任务所需的信息。并非所有函数都需要参数，但是 `addEventListener` 函数需要两个参数。它采用的第一个参数是将为其监听的用户事件的名称。用户可以通过多种方式与 DOM 交互，例如键入、移动鼠标，键盘上的 `TAB` 键和粘贴文本。在这种情况下，你正在监听的用户事件是单击按钮，因此第一个参数将是 `click`。

`addEventListener`的第二个所需的信息是用户单击按钮时要运行的函数的名称。 这里我们需要 `checkGuess` 函数。

现在，当玩家按下 “Check My Guess” 按钮时，`checkGuess` 函数将获得他们在数字输入字段中输入的值，将其与随机数进行比较，并在浏览器中显示反馈，以使玩家知道他们猜的怎么样。 太棒了！你的游戏已准备就绪。

### 学习 JavaScript 以获取乐趣和收益

这一点点的平凡无奇的 JavaScript 只是这个庞大的生态系统所提供功能的一小部分。这是一种值得花时间投入学习的语言，我鼓励你继续挖掘并学习更多。

---

via: <https://opensource.com/article/21/1/learn-javascript>

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


硬核观察 | 极客用了 55 小时 B 站直播复刻爆火的 Clubhouse

Summary: 更多：• 开源 Magma 项目将成为 5G 领域的 Linux • M1 Mac 设备上已可以运行 Linux

从头开始写，哪怕是模仿，为了快，就按原文说的用sdk，光sdk，搭建环境，看文档以及写一些验证测试，起码也要一天。台上10分钟，台下十年功。

![](/data/attachment/album/202102/05/170158hc3z1010m0n0vgxh.jpg)

#### 极客用了 55 小时 B 站直播复刻爆火的 Clubhouse

![](/data/attachment/album/202102/05/165937oxhlc9lpfnnqsipv.jpg)

Clubhouse 是最近爆火的音频社交平台，现在邀请码已经被炒到了 100 美元一个。不过这款应用的功能和使用方式并不复杂，于是一位叫 Bestony 的极客试着写出一个复刻版，并全程进行了 B 站直播。顺便提一句，这位 Bestony 也是我们 “Linux 中国”的合伙人。

作为直播编码的成果，最终他在 GitHub 发布了一个名为 “[NESHouse](https://github.com/bestony/neshouse)” 的项目，用户只需要访问[网页版本](https://neshouse.com/admin.html)就能建立房间，并通过链接邀请他人加入。Bestony 在 Twitter 上表示，自己原本打算花费 72 小时来制作这个项目，但实际用时 55 小时，由于采用 NES（红白机）风格，所以取名为“NESHouse”。

NESHouse 并不是一个商业项目，更多是为工程师和极客们提供的实验性产品。NESHouse 的代码是开源的。出于快速开发的目的，他使用了声网的音频服务，同时也是为了评估 Clubhouse 项目中有多少工作是由它自己的工程师完成。

想要了解这款开源软件背后的一些思考和花絮的，可以看看这篇 CSDN 对 Bestony 的[采访](https://mp.weixin.qq.com/s/mUGGkxdTIngLzd9zX96AeA)。明天我们也会发表一篇深入采访，以飨更多想要效仿的技术爱好者。

在这个技术时代，你需要的就是想法和行动力，就能撬动更多的场景。

#### 开源 Magma 项目将成为 5G 领域的 Linux

![](/data/attachment/album/202102/05/164904mt4mm2agigigi4t2.jpg)

[Magma](https://www.magmacore.org/) 由 Facebook 开发，并于 [2019 年开源](https://www.facebook.com/fbOpenSource/posts/today-we-open-sourced-magma-a-software-platform-that-gives-network-operators-an-/2052421168139967/)，旨在帮助电信运营商快速、便捷地部署移动网络。这种容器化的网络功能可以与移动网络现有的后端整合，并在网络边缘轻松推出新服务。Magma 运营商可以大规模地构建和增强现代高效的移动网络。它可以与现有的 LTE 和新近诞生的 5G 网络进行整合。

该项目将托管在 Linux 基金会之下，并得到了多家电信企业、联盟和基金会的支持，被期许为 5G 领域的 Linux。这倒是打破电信垄断和将 5G 网络铺到更多角度的好技术，就是不知道会不会也造成更多伪造基站？

#### M1 Mac 设备上已可以运行 Linux

![](/data/attachment/album/202102/05/165210opx24dfzcmnccqnx.jpg)

独立开发者 Hector Martin 正通过众筹的方式推进移植工作，近日他发布了拥有 [18 个补丁的套件](https://lore.kernel.org/lkml/20210204203951.52105-1-marcan@marcan.st/)，已经能够在搭载苹果 M1 芯片的 Mac Mini、MacBook Pro 和 MacBook Air 上初步运行 Linux。

我觉得 Linus Torvalds 用上 M1 Mac 的日子不远了。


放弃 ifconfig，拥抱 ip 命令

Summary: 开始使用现代方法配置 Linux 网络接口。

ip输出格式比较反人类

开始使用现代方法配置 Linux 网络接口。

>
> 开始使用现代方法配置 Linux 网络接口。
>
>
>

![](/data/attachment/album/202102/05/233847lpg1lnz7kl2czgfj.jpg "Tips and gears turning")

在很长一段时间内，`ifconfig` 命令是配置网络接口的默认方法。它为 Linux 用户提供了很好的服务，但是网络很复杂，所以配置网络的命令必须健壮。`ip` 命令是现代系统中新的默认网络命令，在本文中，我将向你展示如何使用它。

`ip` 命令工作在 [OSI 网络栈](https://en.wikipedia.org/wiki/OSI_model) 的两个层上：第二层（数据链路层）和第三层（网络 或 IP）层。它做了之前 `net-tools` 包的所有工作。

### 安装 ip

`ip` 命令包含在 `iproute2util` 包中，它可能已经在你的 Linux 发行版中安装了。如果没有，你可以从发行版的仓库中进行安装。

### ifconfig 和 ip 使用对比

`ip` 和 `ifconfig` 命令都可以用来配置网络接口，但它们做事方法不同。接下来，作为对比，我将用它们来执行一些常见的任务。

#### 查看网口和 IP 地址

如果你想查看主机的 IP 地址或网络接口信息，`ifconfig` （不带任何参数）命令提供了一个很好的总结。

```
$ ifconfig

eth0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
       ether bc:ee:7b:5e:7d:d8  txqueuelen 1000  (Ethernet)
       RX packets 0  bytes 0 (0.0 B)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 0  bytes 0 (0.0 B)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

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

wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
       inet 10.1.1.6  netmask 255.255.255.224  broadcast 10.1.1.31
       inet6 fdb4:f58e:49f:4900:d46d:146b:b16:7212  prefixlen 64  scopeid 0x0<global>
       inet6 fe80::8eb3:4bc0:7cbb:59e8  prefixlen 64  scopeid 0x20<link>
       ether 08:71:90:81:1e:b5  txqueuelen 1000  (Ethernet)
       RX packets 569459  bytes 779147444 (743.0 MiB)
       RX errors 0  dropped 0  overruns 0  frame 0
       TX packets 302882  bytes 38131213 (36.3 MiB)
       TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

```

新的 `ip` 命令提供了类似的结果，但命令是 `ip address show`，或者简写为 `ip a`:

```
$ ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
   link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
   inet 127.0.0.1/8 scope host lo
      valid_lft forever preferred_lft forever
   inet6 ::1/128 scope host
      valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
   link/ether bc:ee:7b:5e:7d:d8 brd ff:ff:ff:ff:ff:ff
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
   link/ether 08:71:90:81:1e:b5 brd ff:ff:ff:ff:ff:ff
   inet 10.1.1.6/27 brd 10.1.1.31 scope global dynamic wlan0
      valid_lft 83490sec preferred_lft 83490sec
   inet6 fdb4:f58e:49f:4900:d46d:146b:b16:7212/64 scope global noprefixroute dynamic
      valid_lft 6909sec preferred_lft 3309sec
   inet6 fe80::8eb3:4bc0:7cbb:59e8/64 scope link
      valid_lft forever preferred_lft forever

```

#### 添加 IP 地址

使用 `ifconfig` 命令添加 IP 地址命令为：

```
$ ifconfig eth0 add 192.9.203.21

```

`ip` 类似：

```
$ ip address add 192.9.203.21 dev eth0

```

`ip` 中的子命令可以缩短，所以下面这个命令同样有效：

```
$ ip addr add 192.9.203.21 dev eth0

```

你甚至可以更短些：

```
$ ip a add 192.9.203.21 dev eth0

```

#### 移除一个 IP 地址

添加 IP 地址与删除 IP 地址正好相反。

使用 `ifconfig`，命令是：

```
$ ifconfig eth0 del 192.9.203.21

```

`ip` 命令的语法是：

```
$ ip a del 192.9.203.21 dev eth0

```

#### 启用或禁用组播

使用 `ifconfig` 接口来启用或禁用 <ruby> <a href="https://en.wikipedia.org/wiki/Multicast">  组播 </a> <rt>  multicast </rt></ruby>：

```
# ifconfig eth0 multicast

```

对于 `ip`，使用 `set` 子命令与设备（`dev`）以及一个布尔值和 `multicast` 选项：

```
# ip link set dev eth0 multicast on

```

#### 启用或禁用网络

每个系统管理员都熟悉“先关闭，然后打开”这个技巧来解决问题。对于网络接口来说，即打开或关闭网络。

`ifconfig` 命令使用 `up` 或 `down` 关键字来实现：

```
# ifconfig eth0 up

```

或者你可以使用一个专用命令：

```
# ifup eth0

```

`ip` 命令使用 `set` 子命令将网络设置为 `up` 或 `down` 状态：

```
# ip link set eth0 up

```

#### 开启或关闭地址解析功能（ARP）

使用 `ifconfig`，你可以通过声明它来启用：

```
# ifconfig eth0 arp

```

使用 `ip`，你可以将 `arp` 属性设置为 `on` 或 `off`：

```
# ip link set dev eth0 arp on

```

### ip 和 ipconfig 的优缺点

`ip` 命令比 `ifconfig` 更通用，技术上也更有效，因为它使用的是 `Netlink` 套接字，而不是 `ioctl` 系统调用。

`ip` 命令可能看起来比 `ifconfig` 更详细、更复杂，但这是它拥有更多功能的一个原因。一旦你开始使用它，你会了解它的内部逻辑（例如，使用 `set` 而不是看起来随意混合的声明或设置）。

最后，`ifconfig` 已经过时了（例如，它缺乏对网络命名空间的支持），而 `ip` 是为现代网络而生的。尝试并学习它，使用它，你会由衷高兴的！

---

via: <https://opensource.com/article/21/1/ifconfig-ip-linux>

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


7 个 Bash 教程，提高你的命令行技能（2021 版）

>
> Bash 是大多数 Linux 系统上的默认命令行 shell。所以你为什么不试着学习如何最大限度地利用它呢？
>
>
>

![](/data/attachment/album/202102/06/001837cujo0ql3utfobrrj.jpg "Terminal command prompt on orange background")

Bash 是大多数 Linux 系统上的默认命令行 shell。所以你为什么不试着学习如何最大限度地利用它呢？今年，我们推荐了许多很棒的文章来帮助你充分利用 Bash shell 的强大功能。以下是一些关于 Bash 阅读次数最多的文章：

### 《通过重定向在 Linux 终端任意读写数据》

输入和输出重定向是任何编程或脚本语言的基础功能。从技术上讲，只要你与电脑互动，它就会自然而然地发生。输入从 stdin（标准输入，通常是你的键盘或鼠标）读取，输出到 stdout（标准输出，一般是文本或数据流），而错误被发送到 stderr（标准错误，一般和标准输出是一个位置）。了解这些数据流的存在，使你能够在使用 Bash 等 shell 时控制信息的去向。Seth Kenlon [分享](/article-12385-1.html)了这些很棒的技巧，可以让你在不需要大量鼠标移动和按键的情况下从一个地方获取数据。你可能不经常使用重定向，但学习使用它可以为你节省大量不必要的打开文件和复制粘贴数据的时间。

### 《系统管理员 Bash 脚本入门》

Bash 是自由开源软件，所以任何人都可以安装它，不管他们运行的是 Linux、BSD、OpenIndiana、Windows 还是 macOS。Seth Kenlon [帮助](https://opensource.com/article/20/4/bash-sysadmins-ebook)你学习如何使用 Bash 的命令和特性，使其成为最强大的 shell 之一。

### 《针对大型文件系统可以试试此 Bash 脚本》

你是否曾经想列出一个目录中的所有文件，只显示其中的文件，不包括其他内容？或者只显示目录？如果你有，那么 Nick Clifton 的[文章](/article-12025-1.html)可能正是你正在寻找的。Nick 分享了一个漂亮的 Bash 脚本，它可以列出目录、文件、链接或可执行文件。该脚本使用 `find` 命令进行搜索，然后运行 `ls` 显示详细信息。对于管理大型 Linux 系统的人来说，这是一个漂亮的解决方案。

### 《用 Bash 工具对你的 Linux 系统配置进行快照》

你可能想与他人分享你的 Linux 配置，原因有很多。你可能需要帮助排除系统上的一个问题，或者你对自己创建的环境非常自豪，想向其他开源爱好者展示它。Don Watkins 向我们[展示](https://opensource.com/article/20/1/screenfetch-neofetch)了 screenFetch 和 Neofetch 来捕获和分享你的系统配置。

### 《6 个方便的 Git 脚本》

Git 已经成为一个无处不在的代码管理系统。了解如何管理 Git 存储库可以简化你的开发体验。Bob Peterson [分享](/article-11797-1.html)了 6 个 Bash 脚本，它们将使你在使用 Git 存储库时更加轻松。`gitlog` 打印当前补丁的简略列表，并与主版本相对照。这个脚本的不同版本可以显示补丁的 SHA1 id 或在一组补丁中搜索字符串。

### 《改进你 Bash 脚本的 5 种方法》

系统管理员通常编写各种或长或短的 Bash 脚本，以完成各种任务。Alan Formy-Duval [解释](https://opensource.com/article/20/1/improve-bash-scripts)了如何使 Bash 脚本更简单、更健壮、更易于阅读和调试。我们可能会考虑到我们需要使用诸如 Python、C 或 Java 之类的语言来实现更高的功能，但其实也不一定需要。因为 Bash 脚本语言就已经非常强大。要最大限度地发挥它的效用，还有很多东西要学。

### 《我珍藏的 Bash 秘籍》

Katie McLaughlin 帮助你提高你的工作效率，用别名和其他快捷方式解决你经常忘记的事情。当你整天与计算机打交道时，找到可重复的命令并标记它们以方便以后使用是非常美妙的。Katie [总结](/article-11841-1.html)了一些有用的 Bash 特性和帮助命令，可以节省你的时间。

这些 Bash 小技巧将一个已经很强大的 shell 提升到一个全新的级别。也欢迎分享你自己的建议。

---

via: <https://opensource.com/article/21/1/bash>

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

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


硬核观察 | Chromium 改进了滥用，让访问根服务器的 DNS 查询锐减 41%

Summary: 更多：• 德国警方查获了 6000 万美元的比特币，但是没有密码 • Mac 软件包管理工具 Homebrew 3 发布

![](/data/attachment/album/202102/06/110640ugle3gki2t9gf2e2.jpg)

#### Chromium 改进了滥用，让访问根服务器的 DNS 查询锐减 41%

![](/data/attachment/album/202102/06/110245vunyouizwnosnnw5.png)

去年 8 月，亚太互联网络信息中心（APNIC）[报告](https://www.solidot.org/story?sid=65317) 称，Chromium 浏览器中检查网络是否存在 DNS 拦截的代码会导致大量的垃圾 DNS 查询流量。据统计这产生了 45.8% 的对 DNS 根服务器的流量，约计每天查询 600 亿次。

此后，Chromium 团队重新设计了代码，在 Android 设备上禁用了重定向测试，并推出了多状态 DNS 拦截策略，支持禁用桌面浏览器的重定向测试。该功能在 2020 年 11 月中旬上线后，据[统计](https://blog.apnic.net/2021/02/04/how-chromium-reduces-root-dns-traffic/)，对根服务器的 DNS 查询量迅速下降。在新版本发布之前，根服务器系统的查询量峰值为每天约 1430 亿次。此后，流量已降至每天约 840 亿次查询。

作为具有市场垄断地位的广泛使用的软件，一个小小的举动就能影响很大。这让我想起来微信的域名，这么多年来一直是 weixin.qq.com，如果使用顶级域名，或更短的域名，想必能为中国互联网省下很多无谓的流量。

#### 德国警方查获了 6000 万美元的比特币，但是没有密码

![](/data/attachment/album/202102/06/110408zq1ew5m0wm6j9y3y.jpg)

据 [路透社](https://www.reuters.com/article/us-crypto-currency-germany-password/police-seize-60-million-of-bitcoin-now-wheres-the-password-idUSKBN2A511T) 报道，这名当事人因在人们的电脑上秘密安装比特币挖矿软件而被判刑两年多，并已在监狱中服刑。检察官扣押了他的加密钱包，但是没有得到密码，当事人称自己忘记了。

加密钱包可以使用密码来保护私钥，因此，如果没有密码就无法解锁钱包以取出存储于其中的比特币。警方多次努力破解密码以获取这 1700 多个比特币，然而无济于事。当然，检察官也已经“确保该男子无法获得这笔慷慨的资金”了。

所以，这些比特币也可以算是丢失了吧。

#### Mac 软件包管理工具 Homebrew 3 发布

![](/data/attachment/album/202102/06/110414bufudenzznndnunu.jpg)

热门 macOS 软件包管理工具 Homebrew 在本周五发布的 3.0.0 版本[更新](https://brew.sh/2021/02/05/homebrew-3.0.0/)中， 宣布了对 M1 芯片以及后续 Apple Silicon 芯片的原生支持。不过，Homebrew 还没有像 Intel x86\_64 那样，为 Apple Silicon 上的所有软件包提供支持。Homebrew 呼吁社区帮助制作更多支持 Apple Silicon 的软件包。

现在的问题是，使用 Apple Silicon 的用户还太少，所以软件包也不会很快得到增长。但是能原生支持，就为进一步增加软件包数量铺平了道路。


我是如何在 72 小时内复刻 ClubHouse 的

Summary: 大家好，我是白宦成（@bestony），前几天在 B 站直播写 ClubHouse 复刻版的开发者。

乍一看以为是 fork 了 clickhouse

![](/data/attachment/album/202102/06/221421x7en2g2qgzcoff2g.jpg)

大家好，我是白宦成（@bestony），前几天在 B 站直播写 [ClubHouse 复刻版](https://github.com/bestony/neshouse)的开发者。当然，除了这个身份，在真实生活中，我还是 Linux 中国开源社区的技术负责人，负责开发我们自己的自用工具和平台。

作为一个 indiehacker（自诩的），我想和大家一起来复盘一下，这一次的直播活动和意料之外的爆火。

### 为什么要做 NESHouse

![](/data/attachment/album/202102/06/115418ypdtnz073bvsb733.png)

我其实想到复刻 ClubHouse 的时间是非常早的，我是在 2 月 1 日拿到了 ClubHouse 的邀请码，在试玩了一段时间以后，就觉得这个软件还不错，理念很有意思，但并没有太在意，放在了一边。可到了晚上，因为知道 Elon Musk 要来做分享，作为一个比较欣赏他的人，我自然不能错过，但遗憾的是，当我打开 ClubHouse 的时候，已经有太多的人涌入这个 App，几乎无法使用，总是不停的卡顿。

这时让我产生了怀疑：**这个东西到底有多少的工作量？为什么这么容易性能卡顿？**

结合实际的使用发现，有些时候，我可以正常聊天，但是却会报错，可以发现**问题不在语音服务，而是在 ClubHouse 自身的业务能力不足以支撑超过预期的访问量**。

我上一份工作是在一家云计算企业工作，所以相对来说，对云计算产品有一定的了解。在我看来，这样的一个产品的增量，很难把现有的云计算产品的服务容量打穿，你能想象 ClubHouse 把 AWS、GCP、Azure 等云服务厂商打穿么？

我觉得，要么是开发者的大规模服务的架构经验不足，虽然用了云，但是没设计好，无法充分适应弹性；要么是开发者没有对超过预判的访问量做的预案不足。

这就让我思考，**我能否复刻一个 ClubHouse？用一些更加具有弹性的服务？给大家打个样？** 云计算是好，但用起来也要姿势对，才能不出问题。

### 72 小时复刻一个 ClubHouse，是一个什么概念？

既然要复刻项目，自然要做的不能和碰瓷的一样（这里鄙视几家碰瓷的 App，拿很久之前写的具备了语音聊天的 App，来碰瓷 ClubHouse）。

但我又不希望在这个事情上花费太多的事情，我还有很多更重要的事情要做，所以我选择了 72 小时。48 小时或 24 小时是一般的黑客松的时间长度，但我确实又不熟悉这个项目，所以用 72 小时比较稳妥。

于是便立了一个 Flag ，说**我要在 72 小时内，复刻一个 ClubHouse**。立了个 Flag，说干就干。关于这 72 小时，我希望可以强调两点，也希望这两点能够帮助到你。

![](/data/attachment/album/202102/06/115419em0lwpq9fqfg40zq.png)

#### 1. 明确自己要做的和不要做的

我的时间和精力以及资源都有限，所以并不是什么东西我都能要的。比如在做复刻的时候，考虑到我如果开发原生的 App 或者小程序，就需要提交审核。那我就不能选择做 App，不然 72 小时到了，审核还没过，就食言了。也是出于审核的考虑，**我最终选择了使用 Web 的方式来开发 NESHouse**。

而到了具体的功能特性层面，受限于 Web 和 App 的机制不同，我很难要求用户必须做什么样的操作，也很难确保 App 响应什么样的功能，因此，我对于 ClubHouse 的功能进行了一些删减，邀请上台之类的功能，我就选择性的先不做，将重点放在更加重要的功能中。

**在开发黑客松项目的时候，一定要先想清楚自己要什么，不要什么，这样才能确保自己在给定的时间内完成自己的工作。不然大概率会发现时间马上要截止，但核心功能还没有研发完成。**

#### 2. 选择一些新的、以后可能会用到的技术

在这次项目开发的时候，我选择的前端技术栈并非我过去惯用的 React、Vue ，而是一个相对小众 JS 框架的 Alpine.js。

选择 Alpine.js 的原因很简单，我后续需要在其它的项目上使用这个框架，但我此刻确实也不熟悉。**如果我在这 72 小时里把这个工具用了一遍，如果评估觉得不错，我就可以在后续的项目中使用，如果这次我用的不太好，那我损失的也只有 72 小时，比在正式项目中使用的损失成本要低很多**。

而在另外的两个服务，选择起来就简单多了：

* LeanCloud 的云服务我使用了很多年，使用体验也很不错，而且他们这种 Serverless 云服务，可以让我在开发 [NESHouse](https://github.com/bestony/neshouse) 的时候，免于去写很重的部署和基础逻辑，更加专注在业务逻辑上。
* 音频服务我则选择了国内用户比较多，开发起来也比较方面的声网，声网的 API 比较简单， NESHouse 中的声网音频接入只用 4 行代码就实现了。

除此之外，便是使用了 NES.css 这样的 CSS 框架，来让这个项目更加的有趣，更加的 Funny。

**对于开发黑客松项目的时候，可以想想自己能否接受这一次的失败，如果可以接受自己的失败，不妨将这次黑客松看做是一次玩的机会，玩一玩新的技术，就算失败了，也不过是损失给定的时间。但如果你在工作项目中出现了问题，损失可就大了。**

### 总结

72 个小时的复刻对于我来说不算难，实际上我也只花了 55 个小时就复刻成功了。但更难的，是如何让一个开源项目持续的成长下去，持续的获得用户、获得关注。

最后，大家感兴趣的话，可以移步复刻这个[项目](https://github.com/bestony/neshouse)，看看你能不能做一个自己的 ClubHouse： <https://github.com/bestony/neshouse> 。


编写 GIMP 脚本使图像处理更快

Summary: 通过向一批图像添加效果来学习 GIMP 的脚本语言 Script-Fu。

通过向一批图像添加效果来学习 GIMP 的脚本语言 Script-Fu。

>
> 通过向一批图像添加效果来学习 GIMP 的脚本语言 Script-Fu。
>
>
>

![](/data/attachment/album/202102/06/231011c0xhvxitxjv899qv.jpg "Painting art on a computer screen")

前一段时间，我想给方程图片加一个黑板式的外观。我开始是使用 [GIMP](https://www.gimp.org/) 来处理的，我对结果很满意。问题是我必须对图像执行几个操作，当我想再次使用此样式，不想对所有图像重复这些步骤。此外，我确信我会很快忘记这些步骤。

![Fourier transform equations](/data/attachment/album/202102/06/231049kyoir5ewk57r7ooc.png "Fourier transform equations")

*傅立叶变换方程式（Cristiano Fontana，[CC BY-SA 4.0] [4](https://creativecommons.org/licenses/by-sa/4.0/)）*

GIMP 是一个很棒的开源图像编辑器。尽管我已经使用了多年，但从未研究过其批处理功能或 [Script-Fu](https://docs.gimp.org/en/gimp-filters-script-fu.html) 菜单。这是探索它们的绝好机会。

### 什么是 Script-Fu？

[Script-Fu](https://docs.gimp.org/en/gimp-concepts-script-fu.html) 是 GIMP 内置的脚本语言。是一种基于 [Scheme](https://en.wikipedia.org/wiki/Scheme_(programming_language)) 的编程语言。如果你从未使用过 Scheme，请尝试一下，因为它可能非常有用。我认为 Script-Fu 是一个很好的入门方法，因为它对图像处理具有立竿见影的效果，所以你可以很快感觉到自己的工作效率的提高。你也可以使用 [Python](https://docs.gimp.org/en/gimp-filters-python-fu.html) 编写脚本，但是 Script-Fu 是默认选项。

为了帮助你熟悉 Scheme，GIMP 的文档提供了深入的 [教程](https://docs.gimp.org/en/gimp-using-script-fu-tutorial.html)。Scheme 是一种类似于 [Lisp](https://en.wikipedia.org/wiki/Lisp_%28programming_language%29) 的语言，因此它的主要特征是使用 [前缀](https://en.wikipedia.org/wiki/Polish_notation) 表示法和 [许多括号](https://xkcd.com/297/)。函数和运算符通过前缀应用到操作数列表中：

```
(函数名 操作数 操作数 ...)

(+ 2 3)
↳ 返回 5

(list 1 2 3 5)
↳ 返回一个列表，包含 1、 2、 3 和 5

```

我花了一些时间才找到完整的 GIMP 函数列表文档，但实际上很简单。在 **Help** 菜单中，有一个 **Procedure Browser**，其中包含所有可用的函数的丰富详尽文档。

![GIMP Procedure Browser](/data/attachment/album/202102/06/231050qgwt5shy5ricchk4.png "GIMP Procedure Browser")

### 使用 GIMP 的批处理模式

你可以使用 `-b` 选项以批处理的方式启动 GIMP。`-b` 选项的参数可以是你想要运行的脚本，或者用一个 `-` 来让 GIMP 进入交互模式而不是命令行模式。正常情况下，当你启动 GIMP 的时候，它会启动图形界面，但是你可以使用 `-i` 选项来禁用它。

### 开始编写你的第一个脚本

创建一个名为 `chalk.scm` 的文件，并把它保存在 **Preferences** 窗口中 **Folders** 选项下的 **Script** 中指定的 `script` 文件夹下。就我而言，是在 `$HOME/.config/GIMP/2.10/scripts`。

在 `chalk.scm` 文件中，写入下面的内容：

```
(define (chalk filename grow-pixels spread-amount percentage)
   (let* ((image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
          (drawable (car (gimp-image-get-active-layer image)))
          (new-filename (string-append "modified_" filename)))
     (gimp-image-select-color image CHANNEL-OP-REPLACE drawable '(0 0 0))
     (gimp-selection-grow image grow-pixels)
     (gimp-context-set-foreground '(0 0 0))
     (gimp-edit-bucket-fill drawable BUCKET-FILL-FG LAYER-MODE-NORMAL 100 255 TRUE 0 0)
     (gimp-selection-none image)
     (plug-in-spread RUN-NONINTERACTIVE image drawable spread-amount spread-amount)
     (gimp-drawable-invert drawable TRUE)
     (plug-in-randomize-hurl RUN-NONINTERACTIVE image drawable percentage 1 TRUE 0)
     (gimp-file-save RUN-NONINTERACTIVE image drawable new-filename new-filename)
     (gimp-image-delete image)))

```

### 定义脚本变量

在脚本中， `(define (chalk filename grow-pixels spread-amound percentage) ...)` 函数定义了一个名叫 `chalk` 的新函数。它的函数参数是 `filename`、`grow-pixels`、`spread-amound` 和 `percentage`。在 `define` 中的所有内容都是 `chalk` 函数的主体。你可能已经注意到，那些名字比较长的变量中间都有一个破折号来分割。这是类 Lisp 语言的惯用风格。

`(let* ...)` 函数是一个特殊<ruby> 过程 <rt>  procedure </rt></ruby>，可以让你定义一些只有在这个函数体中才有效的临时变量。临时变量有 `image`、`drawable` 以及 `new-filename`。它使用 `gimp-file-load` 来载入图片，这会返回它所包含的图片的一个列表。并通过 `car` 函数来选取第一项。然后，它选择第一个活动层并将其引用存储在 `drawable` 变量中。最后，它定义了包含图像新文件名的字符串。

为了帮助你更好地了解该过程，我将对其进行分解。首先，启动带 GUI 的 GIMP，然后你可以通过依次点击 **Filters → Script-Fu → Console** 来打开 Script-Fu 控制台。 在这种情况下，不能使用 `let *`，因为变量必须是持久的。使用 `define` 函数定义 `image` 变量，并为其提供查找图像的正确路径：

```
(define image (car (gimp-file-load RUN-NONINTERACTIVE "Fourier.png" "Fourier.png")))

```

似乎在 GUI 中什么也没有发生，但是图像已加载。 你需要通过以下方式来让图像显示：

```
(gimp-display-new image)

```

![GUI with the displayed image](/data/attachment/album/202102/06/231050dd5romwuuwou1u5k.png "GUI with the displayed image")

现在，获取活动层并将其存储在 `drawable` 变量中：

```
(define drawable (car (gimp-image-get-active-layer image)))

```

最后，定义图像的新文件名：

```
(define new-filename "modified_Fourier.png")

```

运行命令后，你将在 Script-Fu 控制台中看到以下内容：

![Script-Fu console](/data/attachment/album/202102/06/231050d10cb4bimb10zing.png "Script-Fu console")

在对图像执行操作之前，需要定义将在脚本中作为函数参数的变量：

```
(define grow-pixels 2)
(define spread-amount 4)
(define percentage 3)

```

### 处理图片

现在，所有相关变量都已定义，你可以对图像进行操作了。 脚本的操作可以直接在控制台上执行。第一步是在活动层上选择黑色。颜色被写成一个由三个数字组成的列表，即 `(list 0 0 0)` 或者是 `'(0 0 0)`:

```
(gimp-image-select-color image CHANNEL-OP-REPLACE drawable '(0 0 0))

```

![Image with the selected color](/data/attachment/album/202102/06/231051n9idg9lp3pv8iafg.png "Image with the selected color")

扩大选取两个像素：

```
(gimp-selection-grow image grow-pixels)

```

![Image with the selected color](/data/attachment/album/202102/06/231051z870vffzmu8f8uru.png "Image with the selected color")

将前景色设置为黑色，并用它填充选区：

```
(gimp-context-set-foreground '(0 0 0))
(gimp-edit-bucket-fill drawable BUCKET-FILL-FG LAYER-MODE-NORMAL 100 255 TRUE 0 0)

```

![Image with the selection filled with black](/data/attachment/album/202102/06/231051l2nntint8k29iqug.png "Image with the selection filled with black")

删除选区：

```
(gimp-selection-none image)

```

![Image with no selection](/data/attachment/album/202102/06/231052xic5hj50rjmz5r0e.png "Image with no selection")

随机移动像素：

```
(plug-in-spread RUN-NONINTERACTIVE image drawable spread-amount spread-amount)

```

![Image with pixels moved around](/data/attachment/album/202102/06/231052gojzxa6a9v7z9aox.png "Image with pixels moved around")

反转图像颜色：

```
(gimp-drawable-invert drawable TRUE)

```

![Image with pixels moved around](/data/attachment/album/202102/06/231052teq5tomua5vdo5q5.png "Image with pixels moved around")

随机化像素：

```
(plug-in-randomize-hurl RUN-NONINTERACTIVE image drawable percentage 1 TRUE 0)

```

![Image with pixels moved around](/data/attachment/album/202102/06/231052luneua1ebr9r6u66.png "Image with pixels moved around")

将图像保存到新文件：

```
(gimp-file-save RUN-NONINTERACTIVE image drawable new-filename new-filename)

```

![Equations of the Fourier transform and its inverse](/data/attachment/album/202102/06/231053gdrxjhvwq4bqaxsj.png "Equations of the Fourier transform and its inverse")

*傅立叶变换方程 (Cristiano Fontana, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/))*

### 以批处理模式运行脚本

现在你知道了脚本的功能，可以在批处理模式下运行它：

```
gimp -i -b '(chalk "Fourier.png" 2 4 3)' -b '(gimp-quit 0)'

```

在运行 `chalk` 函数之后，它将使用 `-b` 选项调用第二个函数 `gimp-quit` 来告诉 GIMP 退出。

### 了解更多

本教程向你展示了如何开始使用 GIMP 的内置脚本功能，并介绍了 GIMP 的 Scheme 实现：Script-Fu。如果你想继续前进，建议你查看官方文档及其[入门教程](https://docs.gimp.org/en/gimp-using-script-fu-tutorial.html)。如果你不熟悉 Scheme 或 Lisp，那么一开始的语法可能有点吓人，但我还是建议你尝试一下。这可能是一个不错的惊喜。

---

via: <https://opensource.com/article/21/1/gimp-scripting>

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


防止通知疲劳的 4 个技巧

>
> 不要让提醒淹没自己：设置重要的提醒，让其它提醒消失。你会感觉更好，工作效率更高。
>
>
>

![](/data/attachment/album/202102/06/234924mo3okotjlv7lo3yo.jpg "Working on a team, busy worklife")

在前几年，这个年度系列涵盖了单个的应用。今年，我们除了关注 2021 年的策略外，还将关注一体化解决方案。欢迎来到 2021 年 21 天生产力的第十八天。

当我和人们谈论生产力时，我注意到一件事，那就是几乎每个人都是为了保持更清晰的头脑。我们不是把所有的约会都记在脑子里，而是把它们放在一个数字日历上，在事件发生前提醒我们。我们有数字或实体笔记，这样我们就不必记住某件事的每一个小细节。我们有待办事项清单，提醒我们去做该做的事情。

![Text box offering to send notifications](/data/attachment/album/202102/06/234954z35xozttqqluzlut.png)

*NOPE（Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

如此多的应用、网站和服务想要提醒我们每一件小事，我们很容易就把它们全部调出来。而且，如果我们不这样做，我们将开始遭受**提醒疲劳**的困扰 —— 这时我们处于边缘的状态，只是等待下一个提醒，并生活在恐惧之中。

提醒疲劳在那些因工作而被随叫随到的人中非常常见。它也发生在那些 **FOMO** （错失恐惧症）的人身上，从而对每一个关键词、标签或在社交媒体上提到他们感兴趣的事情都会设置提醒。

此时，设置能引起我们的注意，但不会被忽略的提醒是件棘手的事情。不过，我确实有一些有用的提示，这样重要的提醒可能会在这个忙碌的世界中越过我们自己的心理过滤器。

![Alert for a task](/data/attachment/album/202102/06/234954uk1kg6bwmym66yb6.png)

*我可以忽略这个，对吧？（Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

1. 弄清楚什么更适合你：视觉提醒或声音提醒。我使用视觉弹出和声音的组合，但这对我是有效的。有些人需要触觉提醒。比如手机或手表的震动。找到适合你的那一种。
2. 为重要的提醒指定独特的音调或视觉效果。我有一个朋友，他的工作页面的铃声最响亮、最讨厌。这旨在吸引他的注意力，让他看到提醒。我的显示器上有一盏灯，当我在待命时收到工作提醒时，它就会闪烁红灯，以及发送通知到我手机上。
3. 关掉那些实际上无关紧要的警报。社交网络、网站和应用都希望得到你的关注。它们不会在意你是否错过会议、约会迟到，或者熬夜到凌晨 4 点。关掉那些不重要的，让那些重要的可以被看到。
4. 每隔一段时间就改变一下。上个月有效的东西，下个月可能就不行了。我们会适应、习惯一些东西，然后我们会忽略。如果有些东西不奏效，就换个东西试试吧！它不会伤害你，即使无法解决问题，也许你也会学到一些新知识。

![Blue alert indicators light](/data/attachment/album/202102/06/234955ztpvwpwupeezebpb.png)

*蓝色是没问题。红色是有问题。（Kevin Sonney, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)）*

### 开源和选择

一个好的应用可以通知提供很多选择。我最喜欢的一个是 Android 的 Etar 日历应用。[Etar 可以从开源 F-droid 仓库中获得](https://f-droid.org/en/packages/ws.xsoh.etar/)。

Etar 和许多开源应用一样，为你提供了很多选项，尤其是通知设置。

![Etar](/data/attachment/album/202102/06/234956xgeerewrevedjewv.jpg "Etar")

通过 Etar，你可以激活或停用弹出式通知，设置打盹时间、打盹延迟、是否提醒你已拒绝的事件等。结合有计划的日程安排策略，你可以通过控制数字助手对你需要做的事情进行提示的频率来改变你一天的进程。

提醒和警报真的很有用，只要我们收到重要的提醒并予以注意即可。这可能需要做一些实验，但最终，少一些噪音是好事，而且更容易注意到真正需要我们注意的提醒。

---

via: <https://opensource.com/article/21/1/alert-fatigue>

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


硬核观察 | 你在运行树莓派 OS 吗？微软知道你

Summary: 更多：• 32 亿电子邮件和明文密码被泄露 • Chrome 88 中普遍推出了通过二维码分享网页的功能

![](/data/attachment/album/202102/07/153826yal62ga6653fk3zk.jpg)

#### 你在运行树莓派 OS 吗？微软知道你

![](/data/attachment/album/202102/07/154038x73jtjfjuj0zjkdj.png)

树莓派基金会官方支持的操作系统是基于 Debian 的树莓派 OS（原名 Raspbian）。然而，最近树莓派 OS 中的一个[变化](https://www.reddit.com/r/linux/comments/lbu0t1/microsoft_repo_installed_on_all_raspberry_pis/)，让每一个运行树莓派的用户在进行 apt 更新时都会[通知](https://hothardware.com/news/raspberry-pi-microsoft-repository-phones-home-added-pi-os)一下微软。

在最近的更新中，它在所有运行树莓派 OS 的机器上都安装了一个微软的 apt 存储库，并且是在无需管理员同意的情况下进行的。这主要是为了安装微软的 VS Code 编辑器。然而，其带来的副作用是，每次你在树莓派上进行 `apt update` 时，它都会联系一下微软的服务器。换言之，微软会知道谁正在使用树莓派 OS、他的 IP 地址等信息。

当社区质疑树莓派在做此改变时没有通知社区，而且是静默改变的，希望树莓派基金会可以更加透明时，树莓派的创始人回应称，“我不明白为什么你会认为这是一件有争议的事情。我们一直是这样做的，而从没有发布过关于如何选择不要的博文。”

开源社区对大型商业企业的警惕是可以理解的，即使是再拥抱开源的企业，也是一个商业公司，因此，总是有一些在意软件自由的人会特别在意和商业公司保持界限，尤其是那些曾经有不良历史的企业。我认为，树莓派基金会此举有些草率，而且创始人的回复略失轻佻。看来他们对树莓派 OS 所基于 Debian 追求的自由有些不以为然。

#### 32 亿电子邮件和明文密码被泄露

![](/data/attachment/album/202102/07/153925irzxlexed0fxdznb.png)

近日，一个超过 30 亿的用户凭证库被发布在网上，其数据是由以往多次用户数据违规泄露事件汇编而成，这个汇编集合被称为 COMB。它包含了过 32 亿个电子邮件和明文密码，拥有像 Netflix、LinkedIn、Bitcoin 等大平台的用户数据。COMB 被放入到一个受密码保护的加密容器中，里面的内容按照数据字母顺序排列在一个树状结构中。

虽然并不是新泄露的密码，不过，无论如何，还是要经常修改你的密码，并使用双因子认证加以保护。如果你担心你的邮件和密码是否被泄露，可以在此查询：<https://cybernews.com/personal-data-leak-check/> 。

#### Chrome 88 中普遍推出了通过二维码分享网页的功能

![](/data/attachment/album/202102/07/154002tzr1peoewyzpopwo.jpg)

此前该功能已经存在于 Chrome 中已经有一段时间了，但并没有被展示出来。而在 Chrome 88 中，70% 的 Chrome 桌面用户都已经被自动开启了该功能。该功能可以通过点击地址栏，或者通过右键点击网页来调出。

这个功能是打通手机和 PC 之间分享网址的一个好方式。之前也有第三方的浏览器扩展可以做到，而现在内置的这个小功能，并不复杂，是一个方便的功能。


EndeavourOS：填补 Antergos 在 ArchLinux 世界留下的空白

Summary: 今天，我们将着眼于 Antergos 的“精神继承人”之一：EndeavourOS。

![](/data/attachment/album/202102/07/225558rdb85bmm6uumro71.jpg)

我相信我们的大多数读者都知道 [Antergos 项目的终结](https://itsfoss.com/antergos-linux-discontinued/)。在这一消息宣布之后，Antergos 社区的成员创建了几个发行版来继承 Antergos。今天，我们将着眼于 Antergos 的“精神继承人”之一：[EndeavourOS](https://endeavouros.com/)。

### EndeavourOS 不是 Antergos 的分支

在我们开始之前，我想非常明确地指出，EndeavourOS 并不是一个 Antergos 的复刻版本。开发者们以 Antergos 为灵感，创建了一个基于 Arch 的轻量级发行版。

![Endeavouros First Boot](/data/attachment/album/202102/07/225623gz2spp7psasktw44.png)

根据 [这个项目网站](https://endeavouros.com/info-2/) 的说法，EndeavourOS 的诞生是因为 Antergos 社区的人们想要保持 Antergos 的精神。他们的目标很简单：“让 Arch 拥有一个易于使用的安装程序和一个友好、有帮助的社区，在掌握系统的过程中能够有一个社区可以依靠。”

与许多基于 Arch 的发行版不同，EndeavourOS 打算像 [原生 Arch](https://endeavouros.com/info-2/) 那样使用，“所以没有一键式安装你喜欢的应用程序的解决方案，也没有一堆你最终不需要的预装应用程序。”对于大多数人来说，尤其是那些刚接触 Linux 和 Arch 的人，会有一个学习曲线，但 EndeavourOS 的目标是建立一个大型友好的社区，鼓励人们提出问题并了解他们的系统。

![Endeavouros Installing](/data/attachment/album/202102/07/225624ovdie5ymbmrez786.png)

### 正在进行的工作

EndeavourOS 在 [2019 年 5 月 23 日首次宣布成立](https://forum.antergos.com/topic/11780/endeavour-antergos-community-s-next-stage) 随后 [在 7 月 15 日发布第一个版本](https://endeavouros.com/endeavouros-first-stable-release-has-arrived/)。不幸的是，这意味着开发人员无法将他们计划的所有功能全部整合进来。（LCTT 译注：本文原文发表于 2019 年，而现在，EndeavourOS 还在持续活跃着。）

例如，他们想要一个类似于 Antergos 的在线安装，但却遇到了[当前选项的问题](https://endeavouros.com/what-to-expect-on-the-first-release/)。“Cnchi 运行在 Antergos 生态系统之外会造成严重的问题，需要彻底重写才能发挥作用。RebornOS 的 Fenix 安装程序还没有完全成型，需要更多时间才能正常运行。”于是现在，EndeavourOS 将会和 [Calamares 安装程序](https://calamares.io/) 一起发布。

EndeavourOS 会提供 [比 Antergos 少的东西](https://endeavouros.com/what-to-expect-on-the-first-release/)：它的存储库比 Antergos 小，尽管他们会附带一些 AUR 包。他们的目标是提供一个接近 Arch 却不是原生 Arch 的系统。

![Endeavouros Updating With Kalu](/data/attachment/album/202102/07/225625dybgzwwyz4w4kkwa.png)

开发者[进一步声明](https://endeavouros.com/second-week-after-the-stable-release/) :

>
> “Linux，特别是 Arch，核心精神是自由选择，我们提供了一个基本的安装，让你在一个精细的层面上方便地探索各项选择。我们永远不会强行为你作决定，比如为你安装 GUI 应用程序，如 Pamac，甚至采用沙盒解决方案，如 Flatpak 或 Snaps。想安装成什么样子完全取决于你，这是我们与 Antergos 或 Manjaro 的主要区别，但与 Antergos 一样，如果你安装的软件包遇到问题，我们会尽力帮助你。”
>
>
>

### 体验 EndeavourOS

我在 [VirtualBox](https://itsfoss.com/install-virtualbox-ubuntu/) 中安装了 EndeavourOS，并且研究了一番。当我第一次启动时，我看到一个窗口，里面有关于安装的 EndeavourOS 网站的链接。它还有一个安装按钮和一个手动分区工具。Calamares 安装程序的安装过程非常顺利。

在我重新启动到新安装的 EndeavourOS 之后，迎接我的是一个彩色主题的 XFCE 桌面。我还收到了一堆通知消息。我使用过的大多数基于 Arch 的发行版都带有一个 GUI 包管理器，比如 [pamac](https://aur.archlinux.org/packages/pamac-aur/) 或 [octopi](https://octopiproject.wordpress.com/)，以进行系统更新。EndeavourOS 配有 [kalu](https://github.com/jjk-jacky/kalu)（kalu 是 “Keeping Arch Linux Up-to-date” 的缩写）。它可以更新软件包、可以看 Archlinux 新闻、可以更新 AUR 包等等。一旦它检查到有更新，它就会显示通知消息。

我浏览了一下菜单，看看默认安装了什么。默认的安装并不多，连办公套件都没有。他们想让 EndeavourOS 成为一块空白画布，让任何人都可以创建他们想要的系统。他们正朝着正确的方向前进。

![Endeavouros Desktop](/data/attachment/album/202102/07/225627ipvbp5f5ww8i5px2.png)

### 总结思考

EndeavourOS 还很年轻。第一个稳定版本都没有发布多久。它缺少一些东西，最重要的是一个在线安装程序。这就是说，我们无法估计他能够走到哪一步。（LCTT 译注：本文发表于 2019 年）

虽然它不是 Antergos 的精确复刻，但 EndeavourOS 希望复制 Antergos 最重要的部分——热情友好的社区。很多时候，Linux 社区对初学者似乎是不受欢迎甚至是完全敌对的。我看到越来越多的人试图与这种消极情绪作斗争，并将更多的人引入 Linux。随着 EndeavourOS 团队把焦点放在社区建设上，我相信一个伟大的发行版将会诞生。

如果你当前正在使用 Antergos，有一种方法可以让你[不用重装系统就切换到 EndeavourOS](https://forum.endeavouros.com/t/how-to-switch-from-antergos-to-endevouros/105/2)

如果你想要一个 Antergos 的精确复刻，我建议你去看看 [RebornOS](https://rebornos.org/)。他们目前正在开发一个名为 Fenix 的 Cnchi 安装程序的替代品。

你试过 EndeavourOS 了吗？你的感受如何？

---

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

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

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


Zint：用这个开源工具生成二维码

Summary: Zint 可以轻松生成 50 多种类型的自定义条码。

Zint 可以轻松生成 50 多种类型的自定义条码。

>
> Zint 可以轻松生成 50 多种类型的自定义条码。
>
>
>

![](/data/attachment/album/202102/07/231854y8ffstg0m6l2fcmz.jpg "Working from home at a laptop")

二维码是一种很好的可以向人们提供信息的方式，且没有打印的麻烦和费用。大多数人的智能手机都支持二维码扫描，无论其操作系统是什么。

你可能想使用二维码的原因有很多。也许你是一名教师，希望通过补充材料来测试你的学生，以增强学习效果，或者是一家餐厅，需要在遵守社交距离准则的同时提供菜单。我经常行走于自然小径，那里贴有树木和其他植物的标签。用二维码来补充这些小标签是一种很好的方式，它可以提供关于公园展品的额外信息，而无需花费和维护标识牌。在这些和其他情况下，二维码是非常有用的。

在互联网上搜索一个简单的、开源的方法来创建二维码时，我发现了 [Zint](http://www.zint.org.uk/)。Zint 是一个优秀的开源 （GPLv3.0） 生成条码的解决方案。根据该项目的 [GitHub 仓库](https://github.com/zint/zint)：“Zint 是一套可以方便地对任何一种公共领域条形码标准的数据进行编码的程序，并允许你将这种功能集成到你自己的程序中。”

Zint 支持 50 多种类型的条形码，包括二维码（ISO 18004），你可以轻松地创建这些条形码，然后复制和粘贴到 word 文档、博客、维基和其他数字媒体中。人们可以用智能手机扫描这些二维码，快速链接到信息。

### 安装 Zint

Zint 适用于 Linux、macOS 和 Windows。

你可以在基于 Ubuntu 的 Linux 发行版上使用 `apt` 安装 Zint 命令：

```
$ sudo apt install zint

```

我还想要一个图形用户界面（GUI），所以我安装了 Zint-QT：

```
$ sudo apt install zint-qt

```

请参考手册的[安装部分](http://www.zint.org.uk/Manual.aspx?type=p&page=2)，了解 macOS 和 Windows 的说明。

### 用 Zint 生成二维码

安装好后，我启动了它，并创建了我的第一个二维码，这是一个指向 [Opensource.com](http://Opensource.com) 的链接。

![Generating QR code with Zint](/data/attachment/album/202102/07/231908lu7kj9a8aq7ps82m.png "Generating QR code with Zint")

Zint 的 50 多个其他条码选项包括许多国家的邮政编码、DotCode、EAN、EAN-14 和通用产品代码 （UPC）。[项目文档](http://www.zint.org.uk/)中包含了它可以渲染的所有代码的完整列表。

你可以将任何条形码复制为 BMP 或 SVG，或者将输出保存为你应用中所需要的任何尺寸的图像文件。这是我的 77x77 像素的二维码。

![QR code](/data/attachment/album/202102/07/231908u1zjepgzun07u21q.png "QR code")

该项目维护了一份出色的用户手册，其中包含了在[命令行](http://zint.org.uk/Manual.aspx?type=p&page=4)和 [GUI](http://zint.org.uk/Manual.aspx?type=p&page=3) 中使用 Zint 的说明。你甚至可以[在线](http://www.barcode-generator.org/)试用 Zint。对于功能请求或错误报告，请[访问网站](https://lists.sourceforge.net/lists/listinfo/zint-barcode)或[发送电子邮件](mailto:zint-barcode@lists.sourceforge.net)。

---

via: <https://opensource.com/article/21/2/zint-barcode-generator>

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


硬核观察 | 微软的 VS Code 有 1400 万用户，而全球开发者才 2400 万

Summary: 更多：• 量子计算机发现 AES 等加密算法存在重大缺陷 • 微软将在今年 4 月用 Chromium 版本干掉原始版本的 Edge 浏览器

![](/data/attachment/album/202102/08/184730mamrjr5a3gar8gaa.jpg)

#### 微软的 VS Code 有 1400 万用户，而全球开发者才 2400 万

![](/data/attachment/album/202102/08/185202zhuqmorccajxs88b.jpg)

据统计，世界上大约有 [2400 万开发者](https://www.statista.com/statistics/627312/worldwide-developer-population/)。而根据微软的数据，已经有 1400 万用户在使用微软的 VS Code，仅仅在 2020 年就增加了 500 万用户。当然，这些用户不全是专业开发者，DevOps、IT 管理、学生，甚至记者等各种职业和行业的人都在使用它。

不过，使用 VS Code 的专业开发者也很多，据[微软的说法](https://www.zdnet.com/article/visual-studio-code-how-microsofts-any-os-any-programming-language-any-software-plan-is-paying-off/)，“我们有近 200 万 Python 开发者使用 VS Code，远超过 100 万的 C++ 开发者在使用 VS Code。甚至我们的 Java 使用者也接近 100 万。”

微软开发的轻量级的、开源的 VS Code 取得了出乎意料的成功，再加上微软的 Windows Terminal、WSL 等，只能说调转枪口的微软认真做起来开源，十分可怕。

#### 量子计算机发现 AES 等加密算法存在重大缺陷

![](/data/attachment/album/202102/08/184754mvcolgbvbl49gngf.jpg)

Terra Quantum 公司拥有一支由约 80 名量子物理学家、密码学家和数学家组成的团队，其研究[发现](https://www.bloombergquint.com/onweb/a-swiss-company-says-it-found-weakness-that-imperils-encryption)了影响对称加密密码的重大缺陷，这包括被广泛用于保护互联网上传输的数据和加密文件的安全的 AES 加密算法。其研究发现，即使是 AES 加密的最强版本，也可能被几年后可能出现的量子计算机破译。他们是在研究如何逆转哈希函数时有了这一发现的。并且，据此发现，他们开发了一种新的量子计算机无法破解的加密协议，新协议利用了一种被称为量子密钥分配的方法。

我认为，如果几年后量子计算能打破现有的主流加密算法，并可投入实际使用，整个基于这些对称和非对称加密算法建立起来的互联网安全，都岌岌可危。但是，我相信，量子计算不是摧毁互联网和信息世界的武器，也会是加强信息安全的重要盾牌。

#### 微软将在今年 4 月用 Chromium 版本干掉原始版本的 Edge 浏览器

![](/data/attachment/album/202102/08/184803l0xuuz0rhvjjrj3s.jpg)

微软已经宣布，作为周二补丁更新的一部分，微软 Edge 的原始版本将在 4 月份从用户的 Windows 10 上被删除。微软不但[夸赞](https://techcommunity.microsoft.com/t5/microsoft-365-blog/new-microsoft-edge-to-replace-microsoft-edge-legacy-with-april-s/ba-p/2114224)了自家的 Chromium Edge，还踩了 Google Chrome 一脚，“新的 Edge 提供了内置的安全性和与微软安全生态系统的最佳互操作性，同时对 Windows 10 上的企业来说比 Chrome 浏览器更安全。”

抛弃 Edge 最积极不是用户，是微软自己。当然，原始版 Edge 也不孤单，因为当年 IE 也是这样被抛弃。

虽然从产品策略和用户体验来说，Chromium 版 Edge 都是一个好事，但是我总觉得在这个浏览器吞噬世界的时代，Chromium 取得垄断性胜利不是好事。