Rust 包管理器 Cargo 入门

Summary: 了解 Rust 的软件包管理器和构建工具。

了解 Rust 的软件包管理器和构建工具。

# Rust 包管理器 Cargo 入门

>
> 了解 Rust 的软件包管理器和构建工具。
>
>
>

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

[Rust](https://www.rust-lang.org/) 是一种现代编程语言，可提供高性能、可靠性和生产力。几年来，它一直被 StackOverflow 调查评为[最受欢迎的语言](https://insights.stackoverflow.com/survey/2019#technology-_-most-loved-dreaded-and-wanted-languages)。

除了是一种出色的编程语言之外，Rust 还具有一个称为 Cargo 的构建系统和软件包管理器。Cargo 处理许多任务，例如构建代码、下载库或依赖项等等。这两者捆绑在一起，因此在安装 Rust 时会得到 Cargo。

### 安装 Rust 和 Cargo

在开始之前，你需要安装 Rust 和 Cargo。Rust 项目提供了一个可下载的脚本来处理安装。要获取该脚本，请打开浏览器以访问 [https://sh.rustup.rs](https://sh.rustup.rs/) 并保存该文件。阅读该脚本以确保你对它的具体行为有所了解，然后再运行它：

```
$ sh ./rustup.rs
```

你也可以参考这个[安装 Rust](https://www.rust-lang.org/tools/install) 的网页以获取更多信息。

安装 Rust 和 Cargo 之后，你必须<ruby> 获取 <rt>  source </rt></ruby> `env` 文件中的配置：

```
$ source $HOME/.cargo/env
```

更好的办法是，将所需目录添加到 `PATH` 环境变量中：

```
export PATH=$PATH:~/.cargo/bin
```

如果你更喜欢使用软件包管理器（例如 Linux 上的 DNF 或 Apt），请在发行版本的存储库中查找 Rust 和 Cargo 软件包，并进行相应的安装。 例如：

```
$ dnf install rust cargo
```

安装并设置它们后，请验证你拥有的 Rust 和 Cargo 版本：

```
$ rustc --version
rustc 1.41.0 (5e1a79984 2020-01-27)
$ cargo --version
cargo 1.41.0 (626f0f40e 2019-12-03)
```

### 手动构建和运行 Rust

从在屏幕上打印“Hello, world!”的简单程序开始。打开你喜欢的文本编辑器，然后键入以下程序：

```
$ cat hello.rs
fn main() {
    println!("Hello, world!");
}
```

以扩展名 `.rs` 保存文件，以将其标识为 Rust 源代码文件。

使用 Rust 编译器 `rustc` 编译程序：

```
$ rustc hello.rs
```

编译后，你将拥有一个与源程序同名的二进制文件：

```
$ ls -l
total 2592
-rwxr-xr-x. 1 user group 2647944 Feb 13 14:14 hello
-rw-r--r--. 1 user group      45 Feb 13 14:14 hello.rs
$
```

执行程序以验证其是否按预期运行：

```
$ ./hello
Hello, world!
```

这些步骤对于较小的程序或任何你想快速测试的东西就足够了。但是，在进行涉及到多人的大型程序时，Cargo 是前进的最佳之路。

### 使用 Cargo 创建新包

Cargo 是 Rust 的构建系统和包管理器。它可以帮助开发人员下载和管理依赖项，并帮助创建 Rust 包。在 Rust 社区中，Rust 中的“包”通常被称为“crate”（板条箱），但是在本文中，这两个词是可以互换的。请参阅 Rust 社区提供的 Cargo [FAQ](https://doc.rust-lang.org/cargo/faq.html) 来区分。

如果你需要有关 Cargo 命令行实用程序的任何帮助，请使用 `--help` 或 `-h` 命令行参数：

```
$ cargo –help
```

要创建一个新的包，请使用关键字 `new`，跟上包名称。在这个例子中，使用 `hello_opensource` 作为新的包名称。运行该命令后，你将看到一条消息，确认 Cargo 已创建具有给定名称的二进制包：

```
$ cargo new hello_opensource
     Created binary (application) `hello_opensource` package
```

运行 `tree` 命令以查看目录结构，它会报告已创建了一些文件和目录。首先，它创建一个带有包名称的目录，并且在该目录内有一个存放你的源代码文件的 `src` 目录：

```
$ tree .
.
└── hello_opensource
    ├── Cargo.toml
    └── src
        └── main.rs

2 directories, 2 files
```

Cargo 不仅可以创建包，它也创建了一个简单的 “Hello, world” 程序。打开 `main.rs` 文件看看：

```
$ cat hello_opensource/src/main.rs
fn main() {
    println!("Hello, world!");
}
```

下一个要处理的文件是 `Cargo.toml`，这是你的包的配置文件。它包含有关包的信息，例如其名称、版本、作者信息和 Rust 版本信息。

程序通常依赖于外部库或依赖项来运行，这使你可以编写应用程序来执行不知道如何编码或不想花时间编码的任务。你所有的依赖项都将在此文件中列出。此时，你的新程序还没有任何依赖关系。打开 `Cargo.toml` 文件并查看其内容：

```
$ cat hello_opensource/Cargo.toml
[package]
name = "hello_opensource"
version = "0.1.0"
authors = ["user <user@mail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
```

### 使用 Cargo 构建程序

到目前为止，一切都很顺利。现在你已经有了一个包，可构建一个二进制文件（也称为可执行文件）。在此之前，进入包目录：

```
$ cd hello_opensource/
```

你可以使用 Cargo 的 `build` 命令来构建包。注意消息说它正在“编译”你的程序：

```
$ cargo build
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 0.38s
```

运行 `build` 命令后，检查项目目录发生了什么：

```
$ tree .
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        │   ├── hello_opensource-147b8a0f466515dd
        │   └── hello_opensource-147b8a0f466515dd.d
        ├── examples
        ├── hello_opensource
        ├── hello_opensource.d
        └── incremental
            └── hello_opensource-3pouh4i8ttpvz
                ├── s-fkmhjmt8tj-x962ep-1hivstog8wvf
                │   ├── 1r37g6m45p8rx66m.o
                │   ├── 2469ykny0eqo592v.o
                │   ├── 2g5i2x8ie8zed30i.o
                │   ├── 2yrvd7azhgjog6zy.o
                │   ├── 3g9rrdr4hyk76jtd.o
                │   ├── dep-graph.bin
                │   ├── query-cache.bin
                │   ├── work-products.bin
                │   └── wqif2s56aj0qtct.o
                └── s-fkmhjmt8tj-x962ep.lock

9 directories, 17 files
```

哇！编译过程产生了许多中间文件。另外，你的二进制文件将以与软件包相同的名称保存在 `./target/debug` 目录中。

### 使用 Cargo 运行你的应用程序

现在你的二进制文件已经构建好了，使用 Cargo 的 `run` 命令运行它。如预期的那样，它将在屏幕上打印 `Hello, world!`。

```
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/hello_opensource`
Hello, world!
```

或者，你可以直接运行二进制文件，该文件位于：

```
$ ls -l ./target/debug/hello_opensource
-rwxr-xr-x. 2 root root 2655552 Feb 13 14:19 ./target/debug/hello_opensource
```

如预期的那样，它产生相同的结果：

```
$ ./target/debug/hello_opensource
Hello, world!
```

假设你需要重建包，并丢弃早期编译过程创建的所有二进制文件和中间文件。Cargo 提供了一个方便的`clean` 选项来删除所有中间文件，但源代码和其他必需文件除外：

```
$ cargo clean
$ tree .
.
├── Cargo.lock
├── Cargo.toml
└── src
    └── main.rs

1 directory, 3 files
```

对程序进行一些更改，然后再次运行以查看其工作方式。例如，下面这个较小的更改将 `Opensource` 添加到 `Hello, world!` 字符串中：

```
$ cat src/main.rs
fn main() {
    println!("Hello, Opensource world!");
}
```

现在，构建该程序并再次运行它。这次，你会在屏幕上看到 `Hello, Opensource world!`：

```
$ cargo build
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 0.39s

$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/hello_opensource`
Hello, Opensource world!
```

### 使用 Cargo 添加依赖项

Cargo 允许你添加程序需要运行的依赖项。使用 Cargo 添加依赖项非常容易。每个 Rust 包都包含一个 `Cargo.toml` 文件，其中包含一个依赖关系列表（默认为空）。用你喜欢的文本编辑器打开该文件，找到 `[dependencies]` 部分，然后添加要包含在包中的库。例如，将 `rand` 库添加为依赖项：

```
$ cat Cargo.toml
[package]
name = "hello_opensource"
version = "0.1.0"
authors = ["test user <test@mail.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rand = "0.3.14"
```

试试构建你的包，看看会发生什么。

```
$ cargo build
    Updating crates.io index
   Compiling libc v0.2.66
   Compiling rand v0.4.6
   Compiling rand v0.3.23
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 4.48s
```

现在，Cargo 会联系 [Crates.io](http://crates.io)（这是 Rust 用于存储 crate（或包）的中央仓库），并下载和编译 `rand`。但是，等等 —— `libc` 包是怎么回事？你没有要安装 libc 啊。是的，`rand` 包依赖于 `libc` 包；因此，Cargo 也会下载并编译 `libc`。

库的新版本会不断涌现，而 Cargo 提供了一种使用 `update` 命令更新其所有依赖关系的简便方法：

```
cargo update
```

你还可以选择使用 `-p` 标志跟上包名称来更新特定的库：

```
cargo update -p rand
```

### 使用单个命令进行编译和运行

到目前为止，每当对程序进行更改时，都先使用了 `build` 之后是 `run`。有一个更简单的方法：你可以直接使用 `run` 命令，该命令会在内部进行编译并运行该程序。要查看其工作原理，请首先清理你的软件包目录：

```
$ cargo clean
$ tree .
.
├── Cargo.lock
├── Cargo.toml
└── src
    └── main.rs

1 directory, 3 files
```

现在执行 `run`。输出信息表明它已进行编译，然后运行了该程序，这意味着你不需要每次都显式地运行 `build`：

```
$ cargo run
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 0.41s
     Running `target/debug/hello_opensource`
Hello, world!
```

### 在开发过程中检查代码

在开发程序时，你经常会经历多次迭代。你需要确保你的程序没有编码错误并且可以正常编译。你不需要负担在每次编译时生成二进制文件的开销。Cargo 为你提供了一个 `check` 选项，该选项可以编译代码，但跳过了生成可执行文件的最后一步。首先在包目录中运行 `cargo clean`：

```
$ tree .
.
├── Cargo.lock
├── Cargo.toml
└── src
    └── main.rs

1 directory, 3 files
```

现在运行 `check` 命令，查看对目录进行了哪些更改：

```
$ cargo check
    Checking hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
```

该输出显示，即使在编译过程中创建了中间文件，但没有创建最终的二进制文件或可执行文件。这样可以节省一些时间，如果该包包含了数千行代码，这非常重要：

```
$ tree .
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        │   ├── hello_opensource-842d9a06b2b6a19b.d
        │   └── libhello_opensource-842d9a06b2b6a19b.rmeta
        ├── examples
        └── incremental
            └── hello_opensource-1m3f8arxhgo1u
                ├── s-fkmhw18fjk-542o8d-18nukzzq7hpxe
                │   ├── dep-graph.bin
                │   ├── query-cache.bin
                │   └── work-products.bin
                └── s-fkmhw18fjk-542o8d.lock

9 directories, 9 files
```

要查看你是否真的节省了时间，请对 `build` 和 `check` 命令进行计时并进行比较。首先，计时 `build` 命令：

```
$ time cargo build
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 0.40s

real    0m0.416s
user    0m0.251s
sys     0m0.199s
```

在运行 `check` 命令之前清理目录：

```
$ cargo clean
```

计时 `check` 命令：

```
$ time cargo check
    Checking hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 0.15s

real    0m0.166s
user    0m0.086s
sys     0m0.081s
```

显然，`check` 命令要快得多。

### 建立外部 Rust 包

到目前为止，你所做的这些都可以应用于你从互联网上获得的任何 Rust crate。你只需要下载或克隆存储库，移至包文件夹，然后运行 `build` 命令，就可以了：

```
git clone <github-like-url>
cd <package-folder>
cargo build
```

### 使用 Cargo 构建优化的 Rust 程序

到目前为止，你已经多次运行 `build`，但是你注意到它的输出了吗？不用担心，再次构建它并密切注意：

```
$ cargo build
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished dev [unoptimized + debuginfo] target(s) in 0.36s
```

看到了每次编译后的 `[unoptimized + debuginfo]` 文本了吗？这意味着 Cargo 生成的二进制文件包含大量调试信息，并且未针对执行进行优化。开发人员经常经历开发的多次迭代，并且需要此调试信息进行分析。同样，性能并不是开发软件时的近期目标。因此，对于现在而言是没问题的。

但是，一旦准备好发布软件，就不再需要这些调试信息。而是需要对其进行优化以获得最佳性能。在开发的最后阶段，可以将 `--release` 标志与 `build` 一起使用。仔细看，编译后，你应该会看到 `[optimized]` 文本：

```
$ cargo build --release
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
    Finished release [optimized] target(s) in 0.29s
```

如果愿意，你可以通过这种练习来了解运行优化软件与未优化软件时节省的时间。

### 使用 Cargo 创建库还是二进制文件

任何软件程序都可以粗略地分类为独立二进制文件或库。一个独立二进制文件也许即使是当做外部库使用的，自身也是可以运行的。但是，作为一个库，是可以被另一个独立二进制文件所利用的。到目前为止，你在本教程中构建的所有程序都是独立二进制文件，因为这是 Cargo 的默认设置。 要创建一个**库**，请添加 `--lib` 选项：

```
$ cargo new --lib libhello
     Created library `libhello` package
```

这次，Cargo 不会创建 `main.rs` 文件，而是创建一个 `lib.rs` 文件。 你的库的代码应该是这样的：

```
$ tree .
.
└── libhello
    ├── Cargo.toml
    └── src
        └── lib.rs

2 directories, 2 files
```

Cargo 就是这样的，不要奇怪，它在你的新库文件中添加了一些代码。通过移至包目录并查看文件来查找添加的内容。默认情况下，Cargo 在库文件中放置一个测试函数。

### 使用 Cargo 运行测试

Rust 为单元测试和集成测试提供了一流的支持，而 Cargo 允许你执行以下任何测试：

```
$ cd libhello/

$ cat src/lib.rs
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
```

Cargo 有一个方便的 `test` 命令，可以运行代码中存在的任何测试。尝试默认运行 Cargo 在库代码中放入的测试：

```
$ cargo test
   Compiling libhello v0.1.0 (/opensource/libhello)
    Finished test [unoptimized + debuginfo] target(s) in 0.55s
     Running target/debug/deps/libhello-d52e35bb47939653

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests libhello

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

### 深入了解 Cargo 内部

你可能有兴趣了解在运行一个 Cargo 命令时它底下发生了什么。毕竟，在许多方面，Cargo 只是个封装器。要了解它在做什么，你可以将 `-v` 选项与任何 Cargo 命令一起使用，以将详细信息输出到屏幕。

这是使用 `-v` 选项运行 `build` 和 `clean` 的几个例子。

在 `build` 命令中，你可以看到这些给定的命令行选项触发了底层的 `rustc`（Rust 编译器）：

```
$ cargo build -v
   Compiling hello_opensource v0.1.0 (/opensource/hello_opensource)
     Running `rustc --edition=2018 --crate-name hello_opensource src/main.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=147b8a0f466515dd -C extra-filename=-147b8a0f466515dd --out-dir /opensource/hello_opensource/target/debug/deps -C incremental=/opensource/hello_opensource/target/debug/incremental -L dependency=/opensource/hello_opensource/target/debug/deps`
    Finished dev [unoptimized + debuginfo] target(s) in 0.36s
```

而 `clean` 命令表明它只是删除了包含中间文件和二进制文件的目录：

```
$ cargo clean -v
    Removing /opensource/hello_opensource/target
```

### 不要让你的技能生锈

要扩展你的技能，请尝试使用 Rust 和 Cargo 编写并运行一个稍微复杂的程序。很简单就可以做到：例如，尝试列出当前目录中的所有文件（可以用 9 行代码完成），或者尝试自己回显输入。小型的实践应用程序可帮助你熟悉语法以及编写和测试代码的过程。

本文为刚起步的 Rust 程序员提供了大量信息，以使他们可以开始入门 Cargo。但是，当你开始处理更大、更复杂的程序时，你需要对 Cargo 有更深入的了解。当你准备好迎接更多内容时，请下载并阅读 Rust 团队编写的开源的《[Cargo 手册](https://doc.rust-lang.org/cargo)》，看看你可以创造什么！

---

via: <https://opensource.com/article/20/3/rust-cargo>

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


九种用开源拯救地球的方法

Summary: 这些主意都用到了有关的开源技巧。

这些主意都用到了有关的开源技巧。

# 九种用开源拯救地球的方法

>
> 这些主意都用到了有关的开源技巧。
>
>
>

人们可以做些什么来拯救地球？这个问题可能会让人感到压抑，因为有时我们感觉个人可以做的贡献太少了。但是作为地球公民，我们从来不是一个人。所以，我向我们的作家社区征集了一些开源软件或硬件可以帮助改变现状的方法。以下是他们的回复。

### 九种利用开源的方法来拯救地球的方式

##### 1、在你的终端禁用闪烁的光标

这听起来可能有点傻，但是那个无关紧要的闪烁的光标可能导致[每小时两瓦特的额外电力开销](https://www.redhat.com/archives/fedora-devel-list/2009-January/msg02406.html)。如果要禁用光标闪烁，可以通过更改终端设置：<ruby> 编辑 <rt>  Edit </rt></ruby> > <ruby> 偏好设置 <rt>  Preferences </rt></ruby> > <ruby> 光标 <rt>  Cursor </rt></ruby> > <ruby> 光标闪烁 <rt>  Cursor blinking </rt></ruby> > <ruby> 禁用 <rt>  Disabled </rt></ruby>。

*由 Mars Toktonaliev 推荐*

##### 2、减少有关动物产品和加工食物的消费

这样做的一种方法是在你的手机中添加这些开源的 App：Daily Dozen、OpenFoodFacts、OpenVegeMap 和 Food Restrictions。这些 App 可以帮助你准备一份健康的素食饮食计划，为你找到素食主义者和严格素食主义者可以就餐的餐厅，还可以帮助你把你的饮食需求告诉别人，即使他们不和你讲同一种语言。如果想要了解更多有关这些的 App 的信息，你可以阅读《[4 款“吃草”的开源应用](/article-10926-1.html)》。

*由 Joshua Allen Holm 推荐*

##### 3、让旧电脑重焕新生

怎么做？当然是用 Linux。通过给那些自己得不到新电脑的人创造一台新电脑来传递爱心，同时也可以避免让这台电脑进到垃圾填埋场。可以在 [The Asian Penguins](https://opensource.com/article/19/2/asian-penguins-close-digital-divide) 看看我们是怎么做的。

*由 Stu Keroff 推荐*

##### 4、在你不使用设备时关闭它们

你可以使用带有主插座和控制插座的“智能插座板”。把你的电脑连接到主插座上，这样的话当你打开电脑时所有你连接到控制插座上的设备如显示器，打印机等也都会打开。一个更简单的、技术含量更低的方法是使用一个带有计时器的插座板。我在家里就是用的这个。你可以用计时器上的开关设定一个定时开关电源的时间表。这样可以在没有人在家时自动关闭网络打印机。或者以我的用了六年的笔记本电脑为例，我通过一个交替使用外接电源（插座打开）和使用电脑电池（插座关闭）的电源计划延长了电脑电池的寿命。

*由 Jim Hall 推荐*

##### 5、减少供暖通风系统（HVAC）的使用

在夏天，透过窗户的阳光可以为室内提供很多热量。使用 Home Assistant 可以[基于一天中的时间的](https://www.home-assistant.io/components/cover/)，甚至是基于太阳高度角[自动调节](https://www.home-assistant.io/docs/automation/trigger/#sun-trigger)窗帘和遮阳棚。

*由 Michael Hrivnak 推荐*

##### 6、出门就把恒温器关闭或调低

如果你的家用恒温器具有“离开”功能，你很容易忘记在出门时启用它。借助自动化，任何连接到网络的恒温器都可以在你不在家时自动节省能量。[Stataway](https://github.com/mhrivnak/stataway) 就是一个这样项目。它通过调用你的手机的 GPS 坐标来决定是将你的恒温器设置为“在家”还是“离开”。

*由 Michael Hrivnak 推荐*

##### 7、为未来储蓄算力

我有一个主意：创建一个可以读取可选的能量阵列（如风能或太阳能）的输出的脚本。这个脚本应该将计算集群中的服务器从睡眠模式更改为激活模式，直到过量的电能（超出可以储存的部分）被用尽。然后在高产能时段使用这些过量的电能来进行需要大量计算的项目，比如渲染。这个过程本质应该是免费的，因为使用的能量无法被储存起来挪作它用。我相信现有的监控、能量管理和服务器阵列工具一定可以实现这个功能。那么剩下的只是一些整合上的问题，就可以让整个系统工作起来。

*由 Terry Hancock 推荐*

##### 8、关掉你的灯

根据<ruby>   人工夜空亮度图集  <rt>  World Atlas of Artificial Night Sky Brightness </rt></ruby>的说法，光污染影响了全世界超过 80% 的人口。这一结论在 2016 年（遵循 CC-NC 4.0 协议）发表在公开访问的期刊《<ruby> 科学进展 <rt>  Science Advances </rt></ruby>》上。关闭外部照明是一个可以使野生生物、人类健康受益并让我们享受夜晚的天空的快速途径，而且可以减少能量消耗。访问 [darksky.org](http://darksky.org/) 来查看更多减少外部照明影响的方法。

*由 Michael Hrivnak 推荐*

##### 9、减少你的 CPU 数量

就我个人而言，我记得我以前有很多在地下室运行的电脑作为我的 IT 游乐场/实验室。我现在对于能源消耗更加注意了，所以确实大大地减少了我的 CPU 数量。我现在更喜欢利用虚拟机、区域和容器等技术。另外，我很高兴有小型电脑和 SoC 电脑这种东西，比如树莓派，因为我可以用一台这样的电脑做很多事情，比如运行一个 DNS 或者 Web 服务器，而无需使整个屋子变热并积累昂贵的电费账单。

P.S. 这些电脑都运行于 Linux、FreeBSD，或者 Raspbian 系统！

*由 Alan Formy-Duvall 推荐*

---

via: <https://opensource.com/article/19/4/save-planet>

作者：[Jen Wike Huger](https://opensource.com/users/jen-wike/users/alanfdoss/users/jmpearce)  选题：[lujun9972](https://github.com/lujun9972) 译者：[MFGJT](https://github.com/MFGJT) 校对：[wxy](https://github.com/wxy)

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


Summary: Linux 与 Windows 10 相比的一个优势是它更安全，但是 Linux 系统并不是绝对可靠的。

比较方法不对，已经暴露出来的漏洞更多并不能说明更不安全，毕竟windows漏洞不能从源代码分析得到。

win7是09年发布的，win10是15年发布的，时间跨度都不一样，比较数量没有意义

# 报告称 Windows 比 Debian Linux 和 Android 更安全

Linux 与 Windows 10 相比的一个优势是它更安全，但是 Linux 系统并不是绝对可靠的，<ruby> 美国国家标准技术研究院 <rp>  （ </rp> <rt>  National Institute of Standards and Technology </rt> <rp>  ） </rp></ruby>（NIST）的<ruby>   国家漏洞数据库  <rp>  （ </rp> <rt>  National Vulnerability Database </rt> <rp>  ） </rp></ruby>（NVD）的最新数据似乎证实了这一点。

### Windows 中的安全缺陷更少

根据其数据，在 1999 - 2019 年期间，Debian Linux 是所有操作系统中带有安全漏洞最多的一个。在此期间，在 Debian Linux 中报告了 3067 个漏洞，在 Ubuntu 中报告了 2007 个漏洞。另一方面，Windows 7 受到了 1283 个漏洞的困扰，在 Windows 10 中才发现了 1111 个漏洞。

从历史上看，Windows 并不是为安全而设计的，但是从 Windows XP 开始微软更加重视 Windows 的安全性，在 Windows XP 中就包括了各种安全功能和强大的防火墙。为了应对日益增长的安全性问题，微软还开始给 Windows 更新更多的安全性和隐私功能，但是 Windows 的一个主要目标仍然是为大多数个人和商用计算机提供了动力。

另外，对于更早的 Windows 7 而言这个数字实际上要低于 Windows 10。例如，在 2019 年，Windows 7 中发现了 250 个安全缺陷，而 Windows 10 中发现了 357 个安全缺陷。

重要的是要知道，计算机上的许多漏洞都是由硬件组件（例如芯片组和驱动程序）引起的，而不是由操作系统本身引起的。 许多 Windows 漏洞都是针对企业的，因此，某些漏洞可能不会对最终用户造成不良影响。

不过，值得注意的是，Debian Linux 表示其社区通常会在几天内修复该漏洞。另一方面，Windows 用户有时必须等待一个月。

### 整体微软产品线安全缺陷最多

但是回溯这整整 20 年来看，这些数据所描述的景象更加完整。在查看整个公司的产品时，微软产品的安全缺陷比任何其他公司都要多。自 1999 年以来，微软产品总共发现了 6814 个漏洞。以下是前 5 名：

1. 微软：6814 个安全缺陷
2. 甲骨文：6115 个安全缺陷
3. IBM：4679 个安全缺陷
4. 谷歌：4572 个安全缺陷
5. 苹果：4512 个安全缺陷

### Android 的安全缺陷数量持续霸榜

近年来，在所有技术产品中，安全缺陷数量逐年保持稳定高位的是谷歌的 Android 操作系统。根据该数据报告，Android 在 2019 年、2017 年和 2016 年是所有操作系统中安全缺陷最多的一个。只有在 2018 年，Android 才从冠军席位上临时掉下来一次，当年 Debian GNU/Linux 的安全缺陷更多。在 2019 年，Android 凭借着 414 个安全缺陷位居榜首，而 Debian Linux 以 360 个安全缺陷“夺得”亚军，而 Windows 10/Windows Server 2016&2019 以 357 个安全缺陷“屈居”季军。

以下是历年来安全缺陷最多的产品：

也许最令人担忧的趋势是，随着操作系统和其他软件产品变得越来越复杂，漏洞在最近 20 年中才有所增加。1999 年，仅报告了 894 个技术漏洞。而在 2019 年报告了 12174 个技术漏洞，增长了 14 倍以上。

不过，对此数据的解读，Android 发言人发表了以下声明：

>
> “我们致力于提高透明度，并每月发布有关 Android 中已解决的问题的公共安全公告，以加强生态系统的安全性。我们不同意这样的观点，即衡量操作系统中已解决的安全问题的数量来表示平台的安全性。这实际上是 Android 生态系统按预期工作的开放性的结果。”
>
>
>

Ref：[softpedia.com](https://news.softpedia.com/news/debian-linux-was-the-most-vulnerable-operating-system-in-the-last-20-years-529387.shtml)，[fastcompany.com](https://www.fastcompany.com/90473597/android-had-the-most-vulnerabilities-of-any-os-in-2019-says-report)，[windowslatest.com](https://www.windowslatest.com/2020/03/09/windows-linux-android-vulnerabilities-report/)


Calculator N+：一款智能手机上的开源科学计算器

Summary: 这个 Android 应用可在掌中计算许多高级数学函数。

这个 Android 应用可在掌中计算许多高级数学函数。

# Calculator N+：一款智能手机上的开源科学计算器

>
> 这个 Android 应用可在掌中计算许多高级数学函数。
>
>
>

移动电话每天都在变得越来越强大，因此毫不奇怪它们可以击败不太久前的大多数计算机。这也意味着移动手机上的工具每天都在变得越来越强大。

之前，我写过一篇 [两款 Linux 桌面端可用的科学计算器](/article-9643-1.html)，我接着将介绍 [Calculator N+](https://github.com/tranleduy2000/ncalc)，这是一款很棒的适用于 Android 设备的计算机代数系统（CAS）应用，采用 GPL v3.0 许可证下。

Calculator N+ 被认为是“适用于 Android 的强大计算器”，但这是一个谦虚的说法。它不仅可以以任意精度工作，还可以显示根数和分数等*很多*功能。

寻找多项式根？可以。分解因数？可以。导数、积分和极限？可以。数论（模算术、组合学、素因数分解）？可以。

你还可以求解方程系统、简化表达式（包括三角函数）、转换单位，只要你想到的，它都能做！

其结果以 LaTeX 输出。左上方的菜单提供了许多强大的功能，只需触摸一下即可使用。同样在该菜单中，你将找到该应用所有功能的帮助文件。在屏幕的右上角，你可以在精确表示法和十进制表示法之间切换。最后，点击屏幕底部的蓝色栏，即可访问应用中的所有函数库。不过要小心！如果你不是数学家、物理学家或工程师，那么这么长的列表会看上去很吓人。

所有这些功能都来自 [Symja 库](https://github.com/axkr/symja_android_library)，这是另一个出色的 GPL 3 项目。

这两个项目都处于积极开发中，并且每个版本都在不断完善。特别是，Calculator N+ 的 v3.4.6 在用户界面（UI）品质方面取得了重大飞跃。虽然还是存在一些不够好的地方，但是要在智能手机的小巧的用户界面中发挥如此强大的功能是一项艰巨的任务，我认为应用开发人员正在很好地解决其剩余的问题。对他们表示敬意！

如果你是老师、学生或在理工科领域工作，请试试 Calculator N+。它是免费、无广告、开源的，并可以满足你所有的数学需求。（当然，除了数学考试期间，为防止作弊绝对不允许使用智能手机。）

可以在 [Google Play 商店](https://play.google.com/store/apps/details?id=com.duy.calculator.free)找到 Calculator N+，也可以使用 GitHub 页面上的说明[从源代码构建](https://github.com/tranleduy2000/ncalc/blob/master/README.md)。

如果你知道用于科学或工程的其他有用的开源应用，请在评论中告知我们。

---

via: <https://opensource.com/article/19/11/calculator-n-mobile>

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


Session：一款不需要电话号码的开源通信应用

Summary: Signal 作为一款私人通信应用，正在变得愈发流行。而我们下面要介绍开源应用 Session 则是 Signal 的一个复刻fork，它的一大亮点是并不需要提供手机号码即可以开始使用。

打不开pc的官网，能分享下pc端app吗

下载后连接不上是为什么

同问

同问

要翻墙的

要翻墙的

要先翻墙，然后才能注册账号，注册好之后就可以正常使用了，就不用翻墙了。

# Session：一款不需要电话号码的开源通信应用

Signal 作为一款私人通信应用，正在变得愈发流行。而我们下面要介绍开源应用 Session 则是 Signal 的一个<ruby> 复刻 <rt>  fork </rt></ruby>，它的一大亮点是并不需要提供手机号码即可以开始使用。

### Session：一款真正意义上的私人通信应用

对于私人通信服务来说，有没有既能保护通信安全性，又尊重用户跨平台隐私的集大成者呢？很多注重个人隐私的用户似乎都在寻找这个问题的答案。

最近，我留意到 [Loki 基金会](https://loki.foundation/)开发的一款叫做 [Session](https://getsession.org/) 的开源通信应用。从技术上来说，Session 是另一款[开源、加密的通信应用 Signal](/article-11764-1.html) 的一个复刻。

在本文中，我会讲述我自己使用 Session 的体验，以及 Session 的一些主要功能。

Session 在这个领域中算是一款比较新的应用了，因此我还会在文章的最后提到它的一些不足之处。

### Session 的一些主要功能

接下来我会重点介绍 Session 的主要功能，可以供你参考这款应用是否值得使用。

#### Session 的使用过程中不需要提供手机号码

在 Signal 或者其它类似的通信应用中，用户都需要提供手机号码才得以成功注册。注重隐私的用户们都认为这样的做法会潜藏着巨大的安全隐患。

而使用 Session 则简单得多。在 PC 或手机上安装应用之后，只需要点击“<ruby> 创建账号 <rt>  Create Account </rt></ruby>”，无须提供手机号码，它就会生成一个类似 05652245af9a8bfee4f5a8138fd5c….. 这样的随机且唯一的 Session ID。

此后，把 Session ID 分享给想要添加的联系人就可以了。Session 还支持二维码，其他人可以通过扫描二维码添加你的 Session ID 为好友。

#### Session 使用了区块链等加密技术

对[区块链](https://en.wikipedia.org/wiki/Blockchain)有所了解的用户都很期待区块链能为普罗大众做出什么有实际意义的应用，而 Session 可以算得上其中一个。尽管 Session 的核心是基于区块链的，但普通用户在使用时并不需要真正弄懂区块链。

如果你好奇它的工作原理，可以参考这篇[官方的博客文章](https://getsession.org/how-session-protects-your-anonymity-with-blockchain-and-crypto/)，里面有相关的解释。

#### 跨平台支持

这样严格保护隐私的应用，是否能在不同平台上使用？

答案是肯定的。首先，它支持 Linux 和 Android 平台，同时也支持 Windows/Mac/iOS 平台。因此跨平台、跨设备的消息同步是没有问题的。

#### 包含基本隐私选项

毫无疑问，基本的隐私功能是必须有的，这是作为一个以安全为卖点的应用所必备的体验。

最基本的选项包括：

* **消息有效期**：你可以控制一条消息在接收者阅读前的保留时长
* **已读回执**：消息发送者可以知晓你已经阅读该消息

#### Session 使用去中心化网络保护你的元数据

尽管 Session 不使用<ruby> 端对端 <rt>  peer-to-peer </rt></ruby>技术，但它也不使用中心化的服务器。

Session 采用了去中心化的架构实现消息的传输和路由。如果你不熟悉这方面的内容，可以关注 Session 的官方博客，尝试了解[中心化网络和去中心化网络的区别](https://getsession.org/centralisation-vs-decentralisation-in-private-messaging/)，以及它的实际工作原理。

同时，这样的网络架构还有助于保护诸如与 IP 地址相关的信息等元数据。

#### 其它功能

除了专注于隐私之外，Session 也支持群聊、语音消息、发送附件等通信应用的基本功能。

### 在 Linux 上安装 Session

在[官方下载页面](https://getsession.org/download/)中可以下载到对应的 .AppImage 文件。如果你不了解这个文件的使用方法，可以查阅我们的[相关文章](https://itsfoss.com/use-appimage-linux/)。

另外，你也可以在它的 [Github 发布页面](https://github.com/loki-project/session-desktop/releases) 获取到对应的 .deb 安装文件。

* [下载 Session](https://getsession.org/download/)

### 我使用 Session 的体验

我在各种平台上都试用过 Session，其中在 PC 上我使用了 Pop!\_OS 19.10 的 .AppImage 文件运行这个应用。

总的来说，使用的体验很不错，用户界面也没有出现问题。

在设置中备份了密码（也称为<ruby> 种子 <rt>  seed </rt></ruby>）后，可以很方便地恢复账号。

当然，我也发现了一些需要改进的地方：

* 在接受好友请求时会出现延迟
* 设备间连接的方式不太直观
* 当你在不同的设备上使用同一个 Session ID 向同一个人回复消息时，对方会收到两个不同的对话

### 总结

当然，最完美的事物是不存在的。我也会一直使用 Session 并考虑它发展的方向，这是一个注重隐私的用户应该做的事情。

欢迎在评论区发表你的看法。

---

via: <https://itsfoss.com/session-messenger/>

作者：[Ankush Das](https://itsfoss.com/author/ankush/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[HankChow](https://github.com/HankChow) 校对：[wxy](https://github.com/wxy)

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


在 Linux 命令行中转换大小写

# 在 Linux 命令行中转换大小写

>
> 转换文本的大小写可能非常繁琐，尤其是当你要避免无意间的拼写错误时。幸运的是，Linux 提供了一些命令，可以使工作变得非常容易。
>
>
>

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

有很多方法可以在 Linux 命令行中将文本从小写更改为大写，反之亦然。实际上，有一组这样的命令可以选择。这篇文章检验了一些最佳的命令来完成这项工作，以及你该如何让它们正常工作。

### 使用 tr

`tr`（translate）命令是在命令行或脚本中最容易使用的命令之一。如果你要确定要一串大写字符串，你只需将它传给 `tr`，如下所示：

```
$ echo Hello There | tr [:lower:] [:upper:]
HELLO THERE
```

下面是一个在脚本中使用这个命令的例子，当你要确保添加到文件中的所有文本都使用大写形式以保持一致性时（LCTT 译注：这里输入部门名称作为示例）：

```
#!/bin/bash

echo -n "Enter department name: "
read dept
echo $dept | tr [:lower:] [:upper:] >> depts
```

将顺序切换为 `[:upper:] [:lower:]` 会产生相反的效果，将所有大写的部门名称都转换为小写：

```
echo $dept | tr [:upper:] [:lower:] >> depts
```

同样，你可以使用 `sed` 命令的 `A-Z` 和 `a-z` 字符串完成相同的操作：

```
echo $dept | tr a-z A-Z >> depts
```

毫无疑问，反转 `a-z` 和 `A-Z` 字符串的顺序将产生相反的效果，将文本全部变为小写。

### 使用 awk

`awk` 命令可让你使用它的 `toupper` 和 `tolower` 选项执行相同的操作。上例脚本中的命令可以用这种方式代替：

```
echo $dept | awk '{print toupper($0)}' >> depts
```

相反操作（切换为小写）如下所示：

```
echo $dept | awk '{print tolower($0)}' >> depts
```

### 使用 sed

`sed`（stream editor）命令也可用于切换大小写。它与上面显示的两个命令中的第一个具有相同的效果。

```
echo $dept | sed 's/[a-z]/\U&/g' >> depts
```

从大写字母切换到小写字母只需将行尾附近的 `U` 替换为 `L`。

```
echo $dept | sed 's/[A-Z]/\L&/g' >> depts
```

### 操作文件中的文本

`awk` 和 `sed` 都能更改整个文件的文本大小写。因此，你发现你的老板需要所有部门名称的小写么？没问题。只需带上文件名运行以下命令：

```
$ awk '{print tolower($0)}' depts
finance
billing
bookkeeping
```

如果要覆盖 `depts` 文件，而不仅仅是以小写形式显示，则需要执行以下操作：

```
$ awk '{print tolower($0)}' depts > depts-
$ mv depts- depts
```

但是，使用 `sed` 进行更改，你可以避免最后一步，因为 `sed` 可以“原地”编辑文件，如下所示，文件完整，但文本全部小写：

```
$ sed 's/[A-Z]/\L&/g' depts
```

### 仅将首字母转换为大写

要仅将字符串中单词的首字母转换为大写，那么可以执行以下操作：

```
$ echo design \& engineering| sed -e "s/\b\(.\)/\u\1/g"
Design & Engineering
```

该命令将确保首字母大写，但不会更改其余字母。

### 确保只有首字母大写

当要更改文本以使只有首字母大写时，这更具挑战性。假设你正在处理一个工作人员姓名列表，并且希望以正常的“名 姓”方式对其格式化。

#### 使用 sed

你可以使用更复杂的 `sed` 命令来确保以下结果：

```
$ echo design \& ENGINEERING | sed 's/\b\([[:alpha:]]\)\([[:alpha:]]*\)\b/\u\1\L\2/g'
Design & Engineering
```

#### 使用 Python

如果你已安装 Python，你可以运行这样的命令，它还可以设置文本格式，以便每个单词只有首字母大写，并且它可能比上面显示的 `sed` 命令更易于解析：

```
$ echo -n "design & engineering" | python3 -c "import sys; print(sys.stdin.read().title())"
Design & Engineering
```

有多种方法可以在大小写之间更改文本格式。哪种方法效果最好取决于你要处理的是单个字符串还是整个文件，以及想要的最终结果。

---

via: <https://www.networkworld.com/article/3529409/converting-between-uppercase-and-lowercase-on-the-linux-command-line.html>

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

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


为了做个动画 SVG，我手工写的分镜头

Summary: 分镜头真的很痛苦

# 为了做个动画 SVG，我手工写的分镜头

可能很多同学注意到了，我们的公众号文章前一段时间悄悄的变化了一些版式，最明显的就说各级标题从原来的渐变色条状变成了如今的样式：居中，无底色，以图标做分隔。喏，就是这样的：

### 这是一个示例的一级标题哈

这里可能有细心的同学会发现，这个图标是会动的，而且是一个“俄罗斯方块”游戏。是的，其实这个图标的原型来自于我之前给 Linux 中国设计的新徽标——当时还举办过徽标征集大赛，只是后来大家都觉得老的徽标更适应，所以没有更换。

不过我个人是挺喜欢这个样式的，所以这里就将它引入进来做标题图标了。

最初是将一个静态的 PNG 图片放到这里的，大家可以注意到开始有几天的公众号文章里面是用的静态的图标；然后几天后，我突然有了一些童心，觉得既然是模仿“俄罗斯方块”游戏的风格，为什么不能动起来呢？

说实在的，老王我是真没有动画基础，哦不，连美工基础都没有。虽然我能用一些软件拼凑出一些简单的洋葱头动画，但是要做到比较复杂和较多的帧数，那么动画 GIF 文件就会比较大。

正好我还会一点点 AI，于是用 AI 重新绘制了这个图标，并导出了 SVG 文件——我知道，这是纯文本的。然后我就可以用我心爱的文本编辑器（你猜是什么编辑器）打开直接修改代码了。

用编辑器打开后，啊哦，这里的数字都很不精确啊——不，很精确啊，都保留了小数点后好多位呢。有点强迫症的我给它们归并到一个比较舒服的整数和倍数上。

然后，怎么动起来呢？没学过，只能现去网上学习 SVG 动画的指令，一边看着别人做的极炫的动画流口水，一边反复地试错。

终于，能自己动了。但是又发现，这动画真是一帧一个状态啊，怎么计算呢？这个时候感觉自己的脑力不够了，于是就找张纸开始画分镜头图，反反复复地画了好几张。这是最终定稿的一张，就这也经过了大量涂改。

然后，最终的 SVG 代码大概是这样的：

虽然我还想加入一些更有趣的变化，比如旋转方向什么的，但是会搞得太复杂了。总之，这是老王第一次做 SVG 动画，肯定有很多浅陋之处，贻笑大方了。

最后，说一句，分镜头真的很痛苦，要一个个数据计算，一个数据错了，后面全错了。

顺便，这个 SVG 文件可以在这里下载： <https://linux.cn/static/image/common/linux-logo-2019-t.svg>


在 Python 调试过程中设置不中断的断点

# 在 Python 调试过程中设置不中断的断点

>
> 你对如何让调试器变得更快产生过兴趣吗？本文将分享我们在为 Python 构建调试器时得到的一些经验。
>
>
>

整段故事讲的是我们在 [Rookout](https://rookout.com/) 公司的团队为 Python 调试器开发不中断断点的经历，以及开发过程中得到的经验。我将在本月于旧金山举办的 [PyBay 2019](https://pybay.com/) 上介绍有关 Python 调试过程的更多细节，但现在就让我们立刻开始这段故事。

### Python 调试器的心脏：sys.set\_trace

在诸多可选的 Python 调试器中，使用最广泛的三个是：

* pdb，它是 Python 标准库的一部分
* PyDev，它是内嵌在 Eclipse 和 Pycharm 等 IDE 中的调试器
* ipdb，它是 IPython 的调试器

Python 调试器的选择虽多，但它们几乎都基于同一个函数：`sys.settrace`。 值得一提的是， [sys.settrace](https://docs.python.org/3/library/sys.html#sys.settrace) 可能也是 Python 标准库中最复杂的函数。

简单来讲，`settrace` 的作用是为解释器注册一个跟踪函数，它在下列四种情形发生时被调用：

* 函数调用
* 语句执行
* 函数返回
* 异常抛出

一个简单的跟踪函数看上去大概是这样：

```
def simple_tracer(frame, event, arg):
  co = frame.f_code
  func_name = co.co_name
  line_no = frame.f_lineno
  print("{e} {f} {l}".format(
e=event, f=func_name, l=line_no))
  return simple_tracer
```

在分析函数时我们首先关注的是参数和返回值，该跟踪函数的参数分别是：

* `frame`，当前堆栈帧，它是包含当前函数执行时解释器里完整状态的对象
* `event`，事件，它是一个值可能为 `call`、`line`、`return` 或 `exception` 的字符串
* `arg`，参数，它的取值基于 `event` 的类型，是一个可选项

该跟踪函数的返回值是它自身，这是由于解释器需要持续跟踪两类跟踪函数：

* **全局跟踪函数（每线程）**：该跟踪函数由当前线程调用 `sys.settrace` 来设置，并在解释器创建一个新的堆栈帧时被调用（即代码中发生函数调用时）。虽然没有现成的方式来为不同的线程设置跟踪函数，但你可以调用 `threading.settrace` 来为所有新创建的 `threading` 模块线程设置跟踪函数。
* **局部跟踪函数（每一帧）**：解释器将该跟踪函数的值设置为全局跟踪函数创建帧时的返回值。同样也没有现成的方法能够在帧被创建时自动设置局部跟踪函数。

该机制的目的是让调试器对被跟踪的帧有更精确的把握，以减少对性能的影响。

### 简单三步构建调试器 （我们最初的设想）

仅仅依靠上文提到的内容，用自制的跟踪函数来构建一个真正的调试器似乎有些不切实际。幸运的是，Python 的标准调试器 pdb 是基于 Bdb 构建的，后者是 Python 标准库中专门用于构建调试器的基类。

基于 Bdb 的简易断点调试器看上去是这样的：

```
import bdb
import inspect

class Debugger(bdb.Bdb):
  def __init__(self):
      Bdb.__init__(self)
      self.breakpoints = dict()
      self.set_trace()

def set_breakpoint(self, filename, lineno, method):
  self.set_break(filename, lineno)
  try :
      self.breakpoints[(filename, lineno)].add(method)
  except KeyError:
      self.breakpoints[(filename, lineno)] = [method]

def user_line(self, frame):
  if not self.break_here(frame):
      return

  # Get filename and lineno from frame
  (filename, lineno, _, _, _) = inspect.getframeinfo(frame)

  methods = self.breakpoints[(filename, lineno)]
  for method in methods:
      method(frame)
```

这个调试器类的全部构成是：

1. 继承 `Bdb`，定义一个简单的构造函数来初始化基类，并开始跟踪。
2. 添加 `set_breakpoint` 方法，它使用 `Bdb` 来设置断点，并跟踪这些断点。
3. 重载 `Bdb` 在当前用户行调用的 `user_line` 方法，该方法一定被一个断点调用，之后获取该断点的源位置，并调用已注册的断点。

### 这个简易的 Bdb 调试器效率如何呢？

Rookout 的目标是在生产级性能的使用场景下提供接近普通调试器的使用体验。那么，让我们来看看先前构建出来的简易调试器表现的如何。

为了衡量调试器的整体性能开销，我们使用如下两个简单的函数来进行测试，它们分别在不同的情景下执行了 1600 万次。请注意，在所有情景下断点都不会被执行。

```
def empty_method():
   pass

def simple_method():
   a = 1
   b = 2
   c = 3
   d = 4
   e = 5
   f = 6
   g = 7
   h = 8
   i = 9
   j = 10
```

在使用调试器的情况下需要大量的时间才能完成测试。糟糕的结果指明了，这个简陋 `Bdb` 调试器的性能还远不足以在生产环境中使用。

### 对调试器进行优化

降低调试器的额外开销主要有三种方法：

1. **尽可能的限制局部跟踪**：由于每一行代码都可能包含大量事件，局部跟踪比全局跟踪的开销要大得多。
2. **优化 `call` 事件并尽快将控制权还给解释器**：在 `call` 事件发生时调试器的主要工作是判断是否需要对该事件进行跟踪。
3. **优化 `line` 事件并尽快将控制权还给解释器**：在 `line` 事件发生时调试器的主要工作是判断我们在此处是否需要设置一个断点。

于是我们复刻了 `Bdb` 项目，精简特征、简化代码，针对使用场景进行优化。这些工作虽然得到了一些效果，但仍无法满足我们的需求。因此我们又继续进行了其它的尝试，将代码优化并迁移至 `.pyx` 使用 [Cython](https://cython.org/) 进行编译，可惜结果（如下图所示）依旧不够理想。最终，我们在深入了解 CPython 源码之后意识到，让跟踪过程快到满足生产需求是不可能的。

### 放弃 Bdb 转而尝试字节码操作

熬过先前对标准调试方法进行的试验-失败-再试验循环所带来的失望，我们将目光转向另一种选择：字节码操作。

Python 解释器的工作主要分为两个阶段：

1. **将 Python 源码编译成 Python 字节码**：这种（对人类而言）不可读的格式专为执行的效率而优化，它们通常缓存在我们熟知的 `.pyc` 文件当中。
2. **遍历 解释器循环中的字节码**： 在这一步中解释器会逐条的执行指令。

我们选择的模式是：使用**字节码操作**来设置没有全局额外开销的**不中断断点**。这种方式的实现首先需要在内存中的字节码里找到我们感兴趣的部分，然后在该部分的相关机器指令前插入一个函数调用。如此一来，解释器无需任何额外的工作即可实现我们的不中断断点。

这种方法并不依靠魔法来实现，让我们简要地举个例子。

首先定义一个简单的函数：

```
def multiply(a, b):
   result = a * b
   return result
```

在 [inspect](https://docs.python.org/2/library/inspect.html) 模块（其包含了许多实用的单元）的文档里，我们得知可以通过访问 `multiply.func_code.co_code` 来获取函数的字节码：

```
'|\x00\x00|\x01\x00\x14}\x02\x00|\x02\x00S'
```

使用 Python 标准库中的 [dis](https://docs.python.org/2/library/dis.html) 模块可以翻译这些不可读的字符串。调用 `dis.dis(multiply.func_code.co_code)` 之后，我们就可以得到：

```
  4          0 LOAD_FAST               0 (a)
             3 LOAD_FAST               1 (b)
             6 BINARY_MULTIPLY
             7 STORE_FAST              2 (result)

  5         10 LOAD_FAST               2 (result)
            13 RETURN_VALUE
```

与直截了当的解决方案相比，这种方法让我们更靠近发生在调试器背后的事情。可惜 Python 并没有提供在解释器中修改函数字节码的方法。我们可以对函数对象进行重写，不过那样做的效率满足不了大多数实际的调试场景。最后我们不得不采用一种迂回的方式来使用原生拓展才能完成这一任务。

### 总结

在构建一个新工具时，总会学到许多事情的工作原理。这种刨根问底的过程能够使你的思路跳出桎梏，从而得到意料之外的解决方案。

在 Rookout 团队中构建不中断断点的这段时间里，我学到了许多有关编译器、调试器、服务器框架、并发模型等等领域的知识。如果你希望更深入的了解字节码操作，谷歌的开源项目 [cloud-debug-python](https://github.com/GoogleCloudPlatform/cloud-debug-python) 为编辑字节码提供了一些工具。

---

via: <https://opensource.com/article/19/8/debug-python>

作者：[Liran Haimovitch](https://opensource.com/users/liranhaimovitch) 选题：[lujun9972](https://github.com/lujun9972) 译者：[caiichenr](https://github.com/caiichenr) 校对：[wxy](https://github.com/wxy)

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


Ubuntu 上 Wireshark 的安装与使用

# Ubuntu 上 Wireshark 的安装与使用

>
> 在本教程中，你将学习如何在 Ubuntu 和其它基于 Ubuntu 的发行版上安装最新的 Wireshark。同时你也将学习如何在没有 sudo 的情况下来运行 Wireshark，以及如何设置它来进行数据包嗅探。
>
>
>

[Wireshark](https://www.wireshark.org/) 是一款自由开源的网络协议分析器，它在全球被广泛使用。

通过使用 Wireshark，你可以实时捕获网络的传入和传出数据包，并将其用于网络故障排除、数据包分析、软件和通信协议开发等。

它适用于所有主流的桌面操作系统，如 Windows、Linux、macOS、BSD 等。

在本教程中，我将指导你在 Ubuntu 和其他基于 Ubuntu 的发行版上安装 Wireshark 。我还将介绍如何设置和配置 Wireshark 来捕获数据包。

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

Wireshark 适用于所有主流 Linux 发行版。你应该查看[官方安装说明](https://www.wireshark.org/docs/wsug_html_chunked/ChBuildInstallUnixInstallBins.html)。因为在本教程中，我将着重在仅基于 Ubuntu 的发行版上安装最新版本的 Wireshark 。

Wireshark 可以在 Ubuntu 的 Universe 存储库中找到。你可以[启用 universe 存储库](https://itsfoss.com/ubuntu-repositories/)，然后按如下方式安装：

```
sudo add-apt-repository universe
sudo apt install wireshark
```

这种方法的一个小问题是，你可能并不总是得到最新版本的 Wireshark 。

例如，在 Ubuntu 18.04 中，如果你使用 [apt](https://itsfoss.com/apt-command-guide/) 命令检查 Wireshark 的可用版本，可用版本会显示是 2.6 。

```
abhishek@nuc:~$ apt show wireshark
Package: wireshark
Version: 2.6.10-1~ubuntu18.04.0
Priority: optional
Section: universe/net
Origin: Ubuntu
Maintainer: Balint Reczey <rbalint@ubuntu.com>
```

然而， [Wireshark 3.2 稳定版](https://www.wireshark.org/news/20191218.html)已经在几个月前发布了。当然，新版本拥有新的特性。

那么在这种情况下，你应该怎么办呢？谢天谢地， Wireshark 开发者提供了一种官方 PPA 方式，你可以使用它在 Ubuntu 和其它基于 Ubuntu 的发行版上安装最新稳定版本的 Wireshark.

我希望你熟悉 PPA。如果没有，请[阅读我们关于 PPA 的优秀指南，以便完全理解它](https://itsfoss.com/ppa-guide/)。

打开终端并逐个使用以下命令：

```
sudo add-apt-repository ppa:wireshark-dev/stable
sudo apt update
sudo apt install wireshark
```

即使安装了旧版本的 Wireshark ，它也将更新为新版本。

安装时，系统将询问你是否允许非超级用户捕获数据包。选择“Yes”允许，选择“No”限制非超级用户捕获数据包，最后完成安装。

### 不使用 sudo 运行 Wireshark

如果在上一次安装中选择了“No”，则以 root 用户身份运行以下命令：

```
sudo dpkg-reconfigure wireshark-common
```

然后按 `tab` 键并使用回车键选择“No”：

由于你允许非超级用户捕获数据包，因此你必须将该用户添加到 `wireshark` 组。使用 [usermod](https://linuxhandbook.com/usermod-command/) 命令将自己添加到 `wireshark` 组。

```
sudo usermod -aG wireshark $(whoami)
```

最后，[重启你的 Ubuntu 系统](https://itsfoss.com/schedule-shutdown-ubuntu/)对你的系统进行必要的修改。

>
> 冷知识
>
>
> Wireshark 于 1998 年首次发布，最初被称为 Ethereal 。2006 年，由于商标问题，开发商不得不将其名称改为 Wireshark 。
>
>
>

### 启动 Wireshark

你可以从应用程序启动器或者命令行启动 Wireshark 应用。

如果从命令行启动，只需要在你的控制台中输入 `wireshark`：

```
wireshark
```

要是从**图形化界面**启动，需要在搜索栏搜索 Wireshark 应用，并按回车键。

现在，让我们来玩玩 Wireshark 吧。

### 使用 Wireshark 捕获数据包

当你启动 Wireshark 的时候，你会看到一个接口列表，你可以使用它来捕获这个接口接收和发送的数据包。

你可以使用 Wireshark 监视许多类型的接口，例如，有线、外部设备等。根据你的偏好，你可以从下图中的标记区域选择在欢迎屏幕中显示特定类型的接口。

例如，我只列出了**有线**网络接口。

接下来，要开始捕获数据包，你必须选择接口（在我的示例中是 `ens33` ），然后单击“Start capturing packets”图标，如下图所示。

你还可以同时从多个接口捕获数据包。只需按住 `CTRL` 按钮，同时单击要捕获的接口，然后点击“Start capturing packets”图标，如下图所示。

接下来，我尝试在终端中使用 `ping google.com` 命令，如你所见，捕获了许多数据包。

现在你可以选择任何数据包来检查该特定数据包。在点击一个特定的包之后，你可以看到与它相关的 TCP/IP 协议的不同层的信息。

你还可以在底部看到该特定数据包的原始数据，如下图所示。

>
> 这就是为什么端到端加密很重要。
>
>
> 假设你正在登录一个不使用 HTTPS 的网站。与你在同一网络上的任何人都可以嗅探数据包，并在原始数据中看到用户名和密码。
>
>
> 这就是为什么现在大多数聊天应用程序使用端到端加密，而大多数网站使用 https （而不是 http）。
>
>
>

#### 在 Wireshark 中停止数据包捕获

你可以点击如图所示的红色图标停止捕获数据包。

#### 将捕获的数据包保存成文件

你可以单击下图中标记的图标，将捕获的数据包保存到文件中以备将来使用。

**注意**：输出可以导出为 XML、PostScript、CSV 或纯文本。

接下来，选择一个目标文件夹，键入文件名并单击“Save”。

然后选择文件并单击“Open”。

现在你可以随时打开和分析保存的数据包。要打开文件，请按 `\+o`，或从 Wireshark 转到 “File > Open”。

捕获的数据包将从文件中加载。

### 结语

Wireshark 支持许多不同的通信协议。有许多选项和功能，使你能够以独特的方式捕获和分析网络数据包。你可以从 Wireshark 的[官方文档](https://www.wireshark.org/docs/https://www.wireshark.org/docs/)了解更多关于 Wireshark 的信息。

我希望这个教程能帮助你在 Ubuntu 上安装 Wireshark 。请让我知道你的问题和建议。

---

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

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

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


新启用的服务号和我们的小程序们

Summary: 向大家汇报一下

# 新启用的服务号和我们的小程序们

### 我们的小程序们

发轫于三年前 Bestony 开发了我们 Linux 中国的第一款小程序“运维密码”之后，我们陆陆续续的又开发了一些微信小程序，给大家提供一些或有用、或有趣的小功能。

这里我做个整理：

#### 运维密码

这是一个 OTP 口令管理器，用于提供双因子认证功能。基本功能完善，不过存在一些小 bug，功能上也许久没有更新了。目前还在计划中的 2.0 版本还遥遥无期……

相关文章

* 《[Linux 中国发布的第一款小程序：「运维密码」，你的好帮手》](/article-8317-1.html)
* 《[SSH 安全加固篇：通过“运维密码”小程序实现 SSH 双因子认证](/article-8354-1.html)》
* 《[开源啦！「运维密码」小程序携全新 UI 开源啦！](/article-8401-1.html)》

#### Linux

这是一个 Linux 命令用法速查的小工具，数据来源于 tldr.sh ，我们在这个小程序中不但提供了命令速查的功能，而且提供了一种众包的翻译机制。目前已经几乎全部翻译完成了，当然，已经翻译的条目也在时不时的改进完善之中。

相关文章：

* 《[推荐一款社区驱动的 Linux 命令速查小程序](/article-10528-1.html)》
* 《[“Linux”小程序发布一个月后，我们发现了什么](/article-10612-1.html)》
* 《[云开发与 WePY，快速实现 Linux 命令查询小程序](/article-10660-1.html)》
* 《[“Linux” 小程序发布 Web 版，现在你可以在 PC 上快速查询命令啦！](/article-11843-1.html)》

#### Linux文章

这是一个以一种比较奇特的方式来搜索、阅读我们发布的全部文章的小程序，我给它的定位是我们的官网小程序。尤其是，目前我们官网已经停止注册，而没有注册是无法在站内搜索文章的，这个小程序可以弥补这个需求窗口。

相关文章：

* 《[我们做了一个极简的文章列表小程序](/article-10760-1.html)》
* 《[你或许不需要一个独立 APP：我们用小程序来做社区的官方应用](/article-10942-1.html)》

#### 文章助手

鉴于微信公众号文章中的链接在大部分情况下都不能点击，虽然我们提供了比较好的解决方案来解决访问链接的需求（通过原文链接提供站内链接、图片等素材的访问），但是很多人还是直觉上会去点击链接，而又失望。所以我们通过将链接包装到小程序当中提供一种更佳的链接访问的用户体验。

相关文章：

* 《[文章助手：让你的公众号文章链接可以点击](/article-10838-1.html)》
* 《[“文章助手”的助手](/article-10896-1.html)》
* 《[“文章助手”小程序已服务十万次 URL 访问](/article-11850-1.html)》

### 新的服务号

早在 2013 年 3 月，我们就[开设了微信公众号](/article-1014-1.html)，而除了主号“Linux中国”之外，还有[若干矩阵号](/article-6838-1.html)，以服务于不同侧面的读者。不过后面由于精力所限和内容量的问题，我们又关闭了大部分矩阵号。

不过，我们现在又将其中一个服务号重新激活，以做这些小程序（以及将来可能的其它产品服务）的支持，比如说提供消息推送、更新信息等等。

这个号就是“璃霓思”——这个名字也是“Linux”的谐音。

当然，除此之外，我们还有两个公众号，这里一起汇总一下：

#### 璃霓思

这就是我们产品服务号，每个月最多只能推送四次，因此推送频率和时间完全没准，不过，如果感兴趣我们的产品/服务，这里可以及时收到消息，而不会被遗漏。

除了这些小程序们，我们主要的工作还是集中在翻译的文章发布上，这些都可以在下面的公众号上看到。

#### Linux中国

这是我们的主号，每天更新的内容主要来自于我们的翻译组 LCTT 的贡献所出。内容涉及到开发、运维、安全、开源文化等等，由于翻译组选题广泛，译者偏好不同，因此这个号发布的内容深浅不一，方向各异。

#### Linux

这是我们的精选号，会对主号发布的内容精选后，延后几天发布出来，如果觉得主号内容比较繁杂，可以只关注这个号，相对来说比较精要。

最后，希望大家多多支持，多多提出建议。


可在 Linux 桌面使用的 3 个电子书阅读器应用

Summary: 任意一个开源电子书应用都能使你在大屏设备上的阅读体验得到提升。

任意一个开源电子书应用都能使你在大屏设备上的阅读体验得到提升。

# 可在 Linux 桌面使用的 3 个电子书阅读器应用

>
> 任意一个开源电子书应用都能使你在大屏设备上的阅读体验得到提升。
>
>
>

我通常使用手机或 Kobo 阅读器阅读电子书，总是没有在大屏设备上阅读书籍那么爽。很多人经常在自己的笔记本或桌面电脑上阅读电子书，如果你有这种需求（或者你认为以后会遇到这种情况），我想向你介绍三种 Linux 桌面下的电子书阅读器。

### Bookworm（书虫）

[Bookworm](https://babluboy.github.io/bookworm/) 意在成为一个“简洁、专注的电子书阅读器”。事实证明它也确实做到了。Bookworm 内置一系列基础功能，有人抱怨它太过*简单*，缺少*功能性*（虽然这词显然有点指意不明）。Bookworm 起到了应有的作用而没有无关的花哨功能。

该应用的界面整洁干净。

你可通过以下方式查看书籍：

* 空格键前往下一页
* 上下方向键按行移动
* 左右方向键跳转至前后章节

你也可以通过添加注释或书签跳转至特定页面。

Bookworm 没有太多设置选项。你能调整书籍字体大小及间距，开启双页模式或夜间模式。在应用中添加新文件夹后，Bookworm 会自动扫描文件夹中的电子书。

Bookworm 支持常用的电子书格式：EPUB、PDF、MOBI、[FB2](https://en.wikipedia.org/wiki/FictionBook)，你还能用它阅读 [CBR](https://en.wikipedia.org/wiki/Comic_book_archive) 和 CBZ 格式的数字版漫画。我只在 Bookworm 上测试了前三种格式，PDF 倒是能打开，但加载速度很慢，格式也很难看。

### Foliate

单从功能上来说，[Foliate](https://johnfactotum.github.io/foliate/) 确实比 Bookworm 强上一些。Foliate 不仅功能更强，它还有更多设置选项。这个功能多样、简单干净的应用满足了所有要求。

在 Foliate 中可以通过空格、方向键、向上或向下翻页键浏览电子书，这里没什么特别的。

你还可以在书籍中添加注释、查找以及翻译字句、查询字词含义。如果你电脑上安装了智能语音应用， Foliate 还能将文本朗读出来。

Foliate 与 Bookworm 相比有更多自定义选项。你能在应用中修改字体类型及大小、行间距、电子书页边距，也可以调高或降低屏幕亮度，从应用内置的四个主题中选择一个等。

你可以在 Foliate 上阅读 EPUB、MOBI、AZW、AZW3 格式的电子书。如果你不了解，我可以提前告诉你，后三种格式是亚马逊 Kindle 阅读器上架的书籍的闭源格式。

### Calibre 电子书阅读器

这个[电子书阅读器](https://calibre-ebook.com/about)是 [Calibre](https://opensourcemusings.com/managing-your-ebooks-with-calibre) 电子书管理工具的一个组件，就像它的前代一样，电子书阅读器这部分并不是软件整体最棒的部分。

不过别被上面的话吓到，它也的确是个桌面电子书阅读器。

在 Calibre 电子书阅读器中，你可以通过方向键、向上/向下翻页键以及空格浏览书籍，还能在在线字典中查找词语含义，添加书签。这一阅读器没有注释功能，但内置的搜索引擎却很好用，你还能将书籍保存为 PDF 格式（虽然我不太明白你为什么要这么做）。

不过参数设置这里确是它出彩的地方，它的可选设置比 Bookworm 和 Foliate 加起来都多，从字体到文本布局，页面分割方式你都能改。除此之外，你还能自定义应用按键设置，将你喜欢的词典网站添加进来，方便阅读查找。

Calibre 电子书阅读器一个很有用的功能，就是把自行设置的 CSS 配置文件效果应用到电子书上。赘言一句，CSS 是一种调整网页格式的方法（这类文件就是许多电子书的一个组成部分）。如果你是使用 CSS 的高手，你可以将自己的 CSS 文件复制粘贴到配置窗口的 “User stylesheet” 部分，这就是个性化的究极办法。

据开发者描述，这一电子书阅读器“能支持所有主流电子书格式”。如果你想知道具体支持格式是什么，[这是列表链接](https://manual.calibre-ebook.com/faq.html#what-formats-does-calibre-support-conversion-to-from)。我测试了列表中的一小部分格式，没有发现问题。

### 留在最后的话

不管你只是单纯想找个电子书阅读器，还是有个更多复杂功能的应用，上文提到的三个选择都很不错，而且它们都能提升你在大屏设备上的阅读体验。

---

via: <https://opensource.com/article/20/2/linux-ebook-readers>

作者：[Scott Nesbitt](https://opensource.com/users/scottnesbitt) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wenwensnow](https://github.com/wenwensnow) 校对：[wxy](https://github.com/wxy)

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


从 apt 升级中排除/保留/阻止特定软件包的三种方法

Summary: 有时，由于某些应用依赖性，你可能会意外更新不想更新的软件包。

有时，由于某些应用依赖性，你可能会意外更新不想更新的软件包。

# 从 apt 升级中排除/保留/阻止特定软件包的三种方法

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

有时，由于某些应用依赖性，你可能会意外更新不想更新的软件包。这在全系统更新或自动包升级时经常会发生。如果发生这种情况，可能会破坏应用的功能。这会造成严重的问题，你需要花费大量时间来解决问题。

如何避免这种情况？如何从 `apt-get` 更新中排除软件包？

>
> 如果你要[从 Yum Update 中排除特定软件包](https://www.2daygeek.com/redhat-centos-yum-update-exclude-specific-packages/)，请参考这篇。
>
>
>

是的，可以在 Debian 和 Ubuntu 系统上使用以下三种方法来完成。

* [apt-mark 命令](https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/)
* [dpkg 命令](https://www.2daygeek.com/dpkg-command-to-manage-packages-on-debian-ubuntu-linux-mint-systems/)
* aptitude 命令

我们将分别详细展示。

### 方法 1：如何使用 apt-mark 命令排除 Debian/Ubuntu 系统上的软件包更新

`apt-mark` 用于将软件包标记/取消标记为自动安装。

`hold` 选项用于将软件包标记为保留，以防止软件包被自动安装、升级或删除。

`unhold` 选项用于取消先前面的设置，以允许重复执行所有操作。

运行以下命令以使用 `apt-mark` 命令保留指定的软件包。

```
$ sudo apt-mark hold nano
nano set on hold.
```

保留软件包后，请运行以下 `apt-mark` 命令查看它们。

```
$ sudo apt-mark showhold
nano
```

这表明在执行完整的系统更新时，不会升级 nano 包。

```
$ sudo apt update

Reading package lists… Done
Building dependency tree
Reading state information… Done
Calculating upgrade… Done
The following packages have been kept back:
  nano
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
```

运行以下命令，使用 `apt-mark` 命令取消保留 nano 包。

```
$ sudo apt-mark unhold nano
Canceled hold on nano.
```

### 方法 2：如何使用 dpkg 命令在 Debian/Ubuntu 系统上排除软件包更新

`dpkg` 命令是一个 CLI 工具，用于安装、构建、删除和管理 Debian 软件包。`dpkg` 的主要且更用户友好的前端是 `aptitude`。

运行以下命令使用 `dpkg` 命令阻止给定的软件包。

语法：

```
$ echo "package_name hold" | sudo dpkg --set-selections
```

运行以下 `dpkg` 命令以保留 apache2 包。

```
$ echo "apache2 hold" | sudo dpkg --set-selections
```

保留软件包后，请运行以下命令查看它们。

```
$ sudo dpkg --get-selections | grep "hold"
apache2                        hold
```

它会显示在执行完整的系统更新时，不会升级 apache2包。

```
$ sudo apt update

Reading package lists… Done
Building dependency tree
Reading state information… Done
Calculating upgrade… Done
The following packages have been kept back:
  apache2
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
```

运行以下命令，使用 `dpkg` 命令取消对指定软件包的保留。

语法：

```
$ echo "package_name install" | sudo dpkg --set-selections
```

运行以下命令，使用 `dpkg` 命令取消保留 apache2 包。

```
$ echo "apache2 install" | sudo dpkg --set-selections
```

### 方法 3：如何使用 aptitude 命令排除 Debian/Ubuntu 系统上的软件包更新

`aptitude` 命令是 Debian 及其衍生版本的基于文本的软件包管理界面。

它允许用户查看软件包列表并执行软件包管理任务，例如安装、升级和删除软件包。它可以从可视界面或命令行执行操作。

运行以下命令，使用 `aptitude` 命令保留指定的软件包。

```
$ sudo aptitude hold python3
```

保留某些软件包后，请运行以下命令查看它们。

```
$ sudo dpkg --get-selections | grep "hold"
或者
$ sudo apt-mark showhold

python3
```

这表明在执行完整的系统更新时，不会升级 python3 软件包。

```
$ sudo apt update

Reading package lists… Done
Building dependency tree
Reading state information… Done
Calculating upgrade… Done
The following packages have been kept back:
  python3
0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
```

使用 `aptitude` 命令运行以下命令以解除对 python3 软件包的保留。

```
$ sudo aptitude unhold python3
```

---

via: <https://www.2daygeek.com/debian-ubuntu-exclude-hold-prevent-packages-from-apt-get-upgrade/>

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

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


安装 pip 轻松管理 PyPI 软件包

# 安装 pip 轻松管理 PyPI 软件包

>
> 在 Linux、Mac 或 Windows 上为旧版 Python 安装 pip。
>
>
>

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

Python 是一种功能强大、流行广泛的编程语言，在常规编程、数据科学等很多方面它都有丰富的软件包可供使用。但这些软件包通常都不会在 Python 安装时自动附带，而是需要由用户自行下载、安装和管理。所有的这些软件包（包括库和框架）都存放在一个名叫 [PyPI](https://pypi.org/)（也就是 <ruby> Python 软件包索引 <rt>  Python Package Index </rt></ruby>）的中央存储库当中，而 `pip`（也就是<ruby> 首选安装程序 <rt>  Preferred Installer Program </rt></ruby>）则是管理这个中央存储库的工具。

在安装 `pip` 之后，管理 PyPI 的软件包就变得很方便了。大部分的软件包都可以通过在终端或者命令行界面执行 `python -m pip install <软件包名>` 这样的命令来完成安装。

较新版本的 Python 3（3.4 或以上）和 Python 2（2.7.9 或以上）都已经预装了 `pip`，旧版本的 Python 没有自带 `pip`，但可以另外安装。

在这篇文章中，我将会介绍 `pip` 在 Linux、Mac 和 Windows 系统上的安装过程。想要了解更多详细信息，可以参考 [pip.pypa](https://pip.pypa.io/en/stable/installing/) 的文档。

### 首先需要安装 Python

首先你的系统中需要安装好 Python，否则 `pip` 安装器无法理解任何相关的命令。你可以在命令行界面、Bash 或终端执行 `python` 命令确认系统中是否已经安装 Python，如果系统无法识别 `python` 命令，请先[下载 Python](https://www.python.org/downloads/) 并安装。安装完成后，你就可以看到一些引导你安装 `pip` 的提示语了。

### 在 Linux 上安装 pip

在不同发行版的 Linux 上，安装 `pip` 的命令也有所不同。

在 Fedora、RHEL 或 CentOS 上，执行以下命令安装：

```
$ sudo dnf install python3
```

在 Debian 或 Ubuntu 上，使用 `apt` 包管理工具安装：

```
$ sudo apt install python3-pip
```

其它的发行版可能还会有不同的包管理工具，比如 Arch Linux 使用的是 `pacman`：

```
$ sudo pacman -S python-pip
```

执行 `pip --version` 命令就可以确认 `pip` 是否已经正确安装。

在 Linux 系统上安装 `pip` 就是这样简单，你可以直接跳到“使用 pip”部分继续阅读。

### 在 Mac 上安装 pip

MacOS 已经预装了 Python，但 Python 版本一般是比较旧的。如果你要使用 Python 的话，建议[另外安装 Python 3](https://opensource.com/article/19/5/python-3-default-mac)。

在 Mac 上可以使用 [homebrew](https://brew.sh) 安装 Python 3：

```
$ brew update && brew upgrade python
```

如果你安装的是以上提到的新版本 Python 3，它会自带 `pip` 工具。你可以使用以下命令验证：

```
$ python3 -m pip --version
```

如果你使用的是 Mac，安装过程也到此结束，可以从“使用 pip”部分继续阅读。

### 在 Windows 上安装 pip

以下 `pip` 安装过程是针对 Windows 8 和 Windows 10 的。下面文章中的截图是 Windows 10 环境下的截图，但对 Windows 8 同样适用。

首先确认 [Python 已经安装完成](https://opensource.com/article/19/8/how-install-python-windows)。

如果你想在 Windows 系统上像 Linux 一样使用包管理工具，[Chocolatey](https://opensource.com/article/20/3/chocolatey) 是一个不错的选择，它可以让 Python 的调用和更新变得更加方便。Chocolatey 在 PowerShell 中就可以运行，只需要简单的命令，Python 就可以顺利安装。

```
PS> choco install python
```

接下来就可以使用 `pip` 安装所需的软件包了。

### 使用 pip

在 Linux、BSD、Windows 和 Mac 上，`pip` 都是以同样的方式使用的。

例如安装某个库：

```
python3 -m pip install foo --user
```

卸载某个已安装的库：

```
python3 -m pip uninstall foo
```

按照名称查找软件包：

```
python3 -m pip search foo
```

将 `pip` 更新到一个新版本：

```
$ sudo pip install --upgrade pip
```

需要注意的是，在 Windows 系统中不需要在前面加上 `sudo` 命令，这是因为 Windows 通过独有的方式管理用户权限，对应的做法是[创建一个执行策略例外](https://opensource.com/article/20/3/chocolatey#admin)。

```
python -m pip install --upgrade pip
```

希望本文介绍的的方法能对你有所帮助，欢迎在评论区分享你的经验。

---

via: <https://opensource.com/article/20/3/pip-linux-mac-windows>

作者：[Vijay Singh Khatri](https://opensource.com/users/vijaytechnicalauthor) 选题：[lujun9972](https://github.com/lujun9972) 译者：[HankChow](https://github.com/HankChow) 校对：[wxy](https://github.com/wxy)

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


Emacs 调试秘籍之 GUD 调试器

Summary: 本文简短地对 Emacs 的调试工具 GUD 的特性进行了探索。

本文简短地对 Emacs 的调试工具 GUD 的特性进行了探索。

# Emacs 调试秘籍之 GUD 调试器

>
> 本文简短地对 Emacs 的调试工具 GUD 的特性进行了探索。
>
>
>

如果你是一个 C 或 C++ 开发者，你很可能已经使用过 GDB（GNU 调试器），毫无疑问，它是现今最强大、最无可匹敌的调试器之一。它唯一的缺点就是它基于命令行，虽然仍能提供许多强大的功能，但有时也会具有一些局限性。这也就是为什么聪明的人们开始追求整合了编辑器和调试器的<ruby> 图形化 <rt>  GUI </rt></ruby><ruby> 集成开发环境 <rt>  Integrated Development Environment </rt></ruby>。仍有些开发者坚信使用鼠标会降低工作效率，在 GUI 上用鼠标点～点～点～是来自恶魔的诱惑。

因为 Emacs 是现今最酷的文本编辑器之一，我将为你展示如何在不碰鼠标且不离开 Emacs 的情况下，实现写代码、编译代码、调试代码的过程。

GUD（LCTT 译注：全称<ruby> 大统一调试器 <rt>  Grand Unified Debugger </rt></ruby>，鉴于其缩写形式更为人熟知，以下全文将使用缩写替代此全称）是 Emacs 下的一个<ruby> 模式 <rt>  mode </rt></ruby>，用于在 Emacs 中运行 GDB。它向 GDB 提供了 Emacs 的所有特性，使用户无需离开编辑器就可以对代码进行调试。

### 使用 GUD 的前期准备

如果你正在使用一个 Linux 机器，很可能你已经安装了 GDB 和 gcc，接下来就是要确保已经安装了 Emacs。以下的内容我将假设读者熟悉 GDB 并且至少用它做过基本的调试。如果你未曾接触过 GDB，你可以做个快速入门，这些资料在网上随处可得。

对于那些 Emacs 新手，我将向你介绍一些基本术语。纵览整篇文章，你将看到诸如 `C-c M-x` 等快捷键。此处 `C` 代表 `Ctrl` 键，`M` 代表 `Alt` 键。`C-c` 代表 `Ctrl` 键和 `c` 键被同时按下。如果你看到 `C-c c`，它代表同时按下 `Ctrl` 键和 `c` 键，释放后紧接着按下 `c` 键。在 Emacs 中，编辑文本的主要区域被称为<ruby> 主缓冲区 <rt>  main buffer </rt></ruby>，而在 Emacs 窗口下方用于输入命令的区域被称为<ruby> 迷你缓冲区 <rt>  mini buffer </rt></ruby>。

启动 Emacs，并按下 `C-x C-f` 来创建一个新文件。Emacs 将提示你输入一个文件名，此处让我们将文件命名为 `buggyFactorial.cpp`。一旦文件打开，输入如下代码：

```
#include<iostream>
#include <assert.h>

int factorial(int num) {
  int product = 1;
  while(num--) {
    product *= num;
  }
  return product;
}
int main() {
  int result = factorial(5);
  assert(result == 120);
}
```

使用 `C-x C-s` 快捷键保存文件。文件保存完毕，是时候进行编译了。按下 `M-x`，在弹出的<ruby> 提示符 <rt>  prompt </rt></ruby>后输入 `compile` 并点击回车。然后在提示符后，将内容替换为 `g++ -g buggyFactorial.cpp` 并再次点击回车。

这将在 Emacs 中开启另一个缓冲区，显示编译的状态。如果你的代码输入没有错误，你将预期得到如图 2 所示的缓冲区。

要想隐藏编译缓冲区，首先确保你的光标在编译缓冲区中（你可以不使用鼠标，而是通过 `C-x o` 快捷键将光标从一个缓冲区移动到另一个），然后按下 `C-x 0`。下一步就是运行代码，并观察是否运行良好。按下 `M-!` 快捷键并在迷你缓冲区的提示符后面输入 `./a.out`。

你可以看到迷你缓冲区中显示断言失败。很明显代码中有错误，因为 5 的阶乘是 120。那么让我们现在开始调试吧。

### 使用 GUD 调式代码

现在，我们的代码已经编译完成，是时候看看到底哪里出错了。按下 `M-x` 快捷键并在提示符后输入 `gdb`。在接下来的提示符后，输入 `gdb -i=mi a.out`。如果一切顺利，GDB 会在 Emacs 缓冲区中启动，你会看到如图 4 所示的窗口。

在 `gdb` 提示符后，输入 `break main` 来设置断点，并输入 `r` 来运行程序。程序会开始运行并停在 `main()` 函数处。

一旦 GDB 到达了 `main` 处设置的断点，就会弹出一个新的缓冲区显示你正在调试的代码。注意左侧的红点，正是你设置断点的位置，同时会有一个小的标志提示你当前代码运行到了哪一行。当前，该标志就在断点处（如图 5）。

为了调试 `factorial` 函数，我们需要单步运行。想要达到此目的，你可以在 GBD 提示符使用 GDB 命令 `step`，或者使用 Emacs 快捷键 `C-c C-s`。还有其它一些快捷键，但我更喜欢 GDB 命令。因此我将在本文的后续部分使用它们。

单步运行时让我们注意一下局部变量中的阶乘值。参考图 6 来设置在 Emacs 帧中显示局部变量值。

在 GDB 提示符中进行单步运行并观察局部变量值的变化。在循环的第一次迭代中，我们发现了一个问题。此处乘法的结果应该是 5 而不是 4。

本文到这里也差不多结束了，读者可以自行探索发现 GUD 模式这片新大陆。GDB 中的所有命令都可以在 GUD 模式中运行。我将此代码的修复留给读者作为一个练习。看看你在调试的过程中，可以做哪一些定制化，来使你的工作流更加简单和高效。

---

via: <https://opensourceforu.com/2019/09/debugging-in-emacs-the-grand-unified-debugger/>

作者：[Vineeth Kartha](https://opensourceforu.com/author/vineeth-kartha/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[cycoe](https://github.com/cycoe) 校对：[wxy](https://github.com/wxy)

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


“文章助手”小程序发布新版 0.3.0

Summary: 增加了一个新特性：在呈现链接时，也提供链接的更多信息

增加了一个新特性：在呈现链接时，也提供链接的更多信息

# “文章助手”小程序发布新版 0.3.0

我们开发的公益小程序“文章助手”增加了一个新特性：在呈现链接时，也提供链接的更多信息，比如该链接的大小、网速和部分内容摘要。这样有助于读者在访问链接前就对该链接有所了解。

之所以没有提供链接全文，主要考虑如下：

* 全文展示需要付出更多的资源（包括页面内的所有素材）
* 链接的内容可能不适合公开展示
* 直接展示全部内容可能违背了微信相关的规定

关于“文章助手”，更多信息请参照这些介绍：

* 《[文章助手：让你的公众号文章链接可以点击](/article-10838-1.html)》
* 《[“文章助手”的助手](/article-10896-1.html)》
* 《[“文章助手”小程序已服务十万次 URL 访问](/article-11850-1.html)》

### 更多动态

#### 谈谈“页面内容接入”

最近对我们的两个小程序配置了“页面内容接入”，并编写了主动推送的功能。

按微信官方的说法，可以“让微信更好的收录到小程序的页面信息，页面信息将可能被用于 搜索、扫条码 ，可帮助小程序获取更多流量。”

已经推送并开始收录的“Linux文章”是我们的官方网站的小程序，主要功能是提供站内文章的阅读和搜索。从目前推送和收录的情况看，从 3 月 9 号开始推送，基本上一天后全部推送完成（一万余个 URL），然后微信以一天最多 800 余篇的速度开始收录，到昨天，已经收录了 3000 余篇。

（上图中 3 月 12 号的推送收录数据可能数据出错了）

总体来看，收录情况还可以。不过我们另外一个提供 Linux 命令查询的小程序“Linux”在 3 月 13 日推送了 URL 之后，至今尚未开始接受推送数据。

此外，从这两天观察小程序的访问来源看，也没有看到来自搜一搜之类的来源的数据增高。从个人的使用体验上，也没注意过搜一搜有类似推荐行为。估计目前还在数据积累阶段，小程序的内容接入还没有实际发挥作用。


如何使用 bind 设置 DNS 服务器

Summary: 本指南将向你展示如何配置一个主 DNS 系统以及客户端。

本指南将向你展示如何配置一个主 DNS 系统以及客户端。

# 如何使用 bind 设置 DNS 服务器

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

<ruby> 域名系统 <rt>  Domain Name System </rt></ruby>，我们更通常称为 DNS 的系统，可以将域名翻译或转换为与该域关联的 IP 地址。DNS 是能够让你通过名称找到自己喜欢的网站而不是在浏览器中输入 IP 地址的原因。本指南将向你展示如何配置一个主 DNS 系统以及客户端。

以下是本文示例中使用的系统细节：

```
dns01.fedora.local    （192.168.1.160）- 主 DNS 服务器
client.fedora.local     （192.168.1.136）- 客户端
```

### DNS 服务器配置

使用 `sudo` 安装 bind 包：

```
$ sudo dnf install bind bind-utils -y
```

bind 包提供了 `/etc/named.conf` 配置文件，来供你配置 DNS 服务器。

编辑 `/etc/named.conf` 文件：

```
sudo vi /etc/named.conf
```

查找以下行：

```
listen-on port 53 { 127.0.0.1; };
```

添加主 DNS 服务器的 IP 地址，如下所示：

```
listen-on port 53 { 127.0.0.1; 192.168.1.160; };
```

查找以下行：

```
allow-query  { localhost; };
```

添加本地网络范围。该示例系统使用的 IP 地址在 192.168.1.X 的范围内。指定如下：

```
allow-query  { localhost; 192.168.1.0/24; };
```

指定转发和反向区域。<ruby> 区域文件 <rt>  Zone file </rt></ruby>就是具有系统上 DNS 信息（例如 IP 地址和主机名）的文本文件。<ruby> 转发区域文件 <rt>  forward zone file </rt></ruby>使得将主机名转换为 IP 地址成为可能。<ruby> 反向区域文件 <rt>  reverse zone file </rt></ruby>则相反。它允许远程系统将 IP 地址转换为主机名。

在 `/etc/named.conf` 文件的底部查找以下行：

```
include "/etc/named.rfc1912.zones";
```

在此处，你将在**该行的正上方**指定区域文件信息，如下所示：

```
zone "dns01.fedora.local" IN {
  type master;
  file "forward.fedora.local";
  allow-update { none; };
};

zone "1.168.192.in-addr.arpa" IN {
  type master;
  file "reverse.fedora.local";
  allow-update { none; };
};
```

`forward.fedora.local` 和 `reverse.fedora.local` 文件是要创建的区域文件的名称。它们可以是任意名字。

保存并退出。

#### 创建区域文件

创建你在 `/etc/named.conf` 文件中指定的转发和反向区域文件：

```
$ sudo vi /var/named/forward.fedora.local
```

添加以下行：

```
$TTL 86400
@   IN  SOA     dns01.fedora.local. root.fedora.local. (
        2011071001  ;Serial
        3600        ;Refresh
        1800        ;Retry
        604800      ;Expire
        86400       ;Minimum TTL
)
@       IN  NS          dns01.fedora.local.
@       IN  A           192.168.1.160
dns01           IN  A   192.168.1.160
client          IN  A   192.168.1.136
```

所有**粗体**（LCTT 译注：本译文中无法呈现粗体）内容都特定于你的环境。保存文件并退出。接下来，编辑 `reverse.fedora.local` 文件：

```
$ sudo vi /var/named/reverse.fedora.local
```

添加以下行：

```
$TTL 86400
@   IN  SOA     dns01.fedora.local. root.fedora.local. (
        2011071001  ;Serial
        3600        ;Refresh
        1800        ;Retry
        604800      ;Expire
        86400       ;Minimum TTL
)
@       IN  NS          dns01.fedora.local.
@       IN  PTR         fedora.local.
dns01           IN  A   192.168.1.160
client          IN  A   192.168.1.136
160     IN  PTR         dns01.fedora.local.
136     IN  PTR         client.fedora.local.
```

所有**粗体**（LCTT 译注：本译文中无法呈现粗体）内容都特定于你的环境。保存文件并退出。

你还需要配置 SELinux 并为配置文件添加正确的所有权。

```
sudo chgrp named -R /var/named
sudo chown -v root:named /etc/named.conf
sudo restorecon -rv /var/named
sudo restorecon /etc/named.conf
```

配置防火墙：

```
sudo firewall-cmd --add-service=dns --perm
sudo firewall-cmd --reload
```

#### 检查配置是否存在语法错误

```
sudo named-checkconf /etc/named.conf
```

如果没有输出或返回错误，那么你的配置有效。

检查转发和反向区域文件。

```
$ sudo named-checkzone forward.fedora.local /var/named/forward.fedora.local

$ sudo named-checkzone reverse.fedora.local /var/named/reverse.fedora.local
```

你应该看到 “OK” 的响应：

```
zone forward.fedora.local/IN: loaded serial 2011071001
OK

zone reverse.fedora.local/IN: loaded serial 2011071001
OK
```

#### 启用并启动 DNS 服务

```
$ sudo systemctl enable named
$ sudo systemctl start named
```

#### 配置 resolv.conf 文件

编辑 `/etc/resolv.conf` 文件：

```
$ sudo vi /etc/resolv.conf
```

查找你当前的 `nameserver` 行。在示例系统上，使用调制解调器/路由器充当名称服务器，因此当前看起来像这样：

```
nameserver 192.168.1.1
```

这需要更改为主 DNS 服务器的 IP 地址：

```
nameserver 192.168.1.160
```

保存更改并退出。

不幸的是需要注意一点。如果系统重启或网络重启，那么 NetworkManager 会覆盖 `/etc/resolv.conf` 文件。这意味着你将丢失所做的所有更改。

为了防止这种情况发生，请将 `/etc/resolv.conf` 设为不可变：

```
$ sudo chattr +i /etc/resolv.conf
```

如果要重新设置，就需要允许其再次被覆盖：

```
$ sudo chattr -i /etc/resolv.conf
```

#### 测试 DNS 服务器

```
$ dig fedoramagazine.org
```

```
; <<>> DiG 9.11.13-RedHat-9.11.13-2.fc30 <<>> fedoramagazine.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8391
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 6

;; OPT PSEUDOSECTION:
 ; EDNS: version: 0, flags:; udp: 4096
 ; COOKIE: c7350d07f8efaa1286c670ab5e13482d600f82274871195a (good)
 ;; QUESTION SECTION:
 ;fedoramagazine.org.        IN  A

;; ANSWER SECTION:
 fedoramagazine.org.    50  IN  A   35.197.52.145

;; AUTHORITY SECTION:
 fedoramagazine.org.    86150   IN  NS  ns05.fedoraproject.org.
 fedoramagazine.org.    86150   IN  NS  ns02.fedoraproject.org.
 fedoramagazine.org.    86150   IN  NS  ns04.fedoraproject.org.

;; ADDITIONAL SECTION:
 ns02.fedoraproject.org.    86150   IN  A   152.19.134.139
 ns04.fedoraproject.org.    86150   IN  A   209.132.181.17
 ns05.fedoraproject.org.    86150   IN  A   85.236.55.10
 ns02.fedoraproject.org.    86150   IN  AAAA    2610:28:3090:3001:dead:beef:cafe:fed5
 ns05.fedoraproject.org.    86150   IN  AAAA    2001:4178:2:1269:dead:beef:cafe:fed5

 ;; Query time: 830 msec
 ;; SERVER: 192.168.1.160#53(192.168.1.160)
 ;; WHEN: Mon Jan 06 08:46:05 CST 2020
 ;; MSG SIZE  rcvd: 266
```

需要检查几件事以验证 DNS 服务器是否正常运行。显然，取得结果很重要，但这本身并不意味着 DNS 服务器实际上正常工作。

顶部的 `QUERY`、`ANSWER` 和 `AUTHORITY` 字段应显示为非零，如我们的示例所示：

```
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 6
```

并且 `SERVER` 字段应有你的 DNS 服务器的 IP 地址：

```
;; SERVER: 192.168.1.160#53(192.168.1.160)
```

如果这是你第一次运行 `dig` 命令，请注意完成查询要花费 830 毫秒的时间：

```
;; Query time: 830 msec
```

如果再次运行它，查询将会更快：

```
$ dig fedoramagazine.org
```

```
;; Query time: 0 msec
;; SERVER: 192.168.1.160#53(192.168.1.160)
```

### 客户端配置

客户端配置将简单得多。

安装 bind 程序：

```
$ sudo dnf install bind-utils -y
```

编辑 `/etc/resolv.conf` 文件，并将主 DNS 配置为唯一的名称服务器：

```
$ sudo vi /etc/resolv.conf
```

它看起来像这样：

```
nameserver 192.168.1.160
```

保存更改并退出。然后，使 `/etc/resolv.conf` 文件不可变，防止其被覆盖并变回默认设置：

```
$ sudo chattr +i /etc/resolv.conf
```

#### 测试客户端

你应该获得与 DNS 服务器相同的结果：

```
$ dig fedoramagazine.org
```

```
; <<>> DiG 9.11.13-RedHat-9.11.13-2.fc30 <<>> fedoramagazine.org
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8391
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 6

;; OPT PSEUDOSECTION:
 ; EDNS: version: 0, flags:; udp: 4096
 ; COOKIE: c7350d07f8efaa1286c670ab5e13482d600f82274871195a (good)
 ;; QUESTION SECTION:
 ;fedoramagazine.org.        IN  A

;; ANSWER SECTION:
 fedoramagazine.org.    50  IN  A   35.197.52.145

;; AUTHORITY SECTION:
 fedoramagazine.org.    86150   IN  NS  ns05.fedoraproject.org.
 fedoramagazine.org.    86150   IN  NS  ns02.fedoraproject.org.
 fedoramagazine.org.    86150   IN  NS  ns04.fedoraproject.org.

;; ADDITIONAL SECTION:
 ns02.fedoraproject.org.    86150   IN  A   152.19.134.139
 ns04.fedoraproject.org.    86150   IN  A   209.132.181.17
 ns05.fedoraproject.org.    86150   IN  A   85.236.55.10
 ns02.fedoraproject.org.    86150   IN  AAAA    2610:28:3090:3001:dead:beef:cafe:fed5
 ns05.fedoraproject.org.    86150   IN  AAAA    2001:4178:2:1269:dead:beef:cafe:fed5

 ;; Query time: 1 msec
 ;; SERVER: 192.168.1.160#53(192.168.1.160)
 ;; WHEN: Mon Jan 06 08:46:05 CST 2020
 ;; MSG SIZE  rcvd: 266
```

确保 `SERVER` 输出的是你 DNS 服务器的 IP 地址。

你的 DNS 服务器设置完成了，现在所有来自客户端的请求都会经过你的 DNS 服务器了！

---

via: <https://fedoramagazine.org/how-to-setup-a-dns-server-with-bind/>

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


简单是 Python 编程的第一要则

# 简单是 Python 编程的第一要则

>
> 本文是 Python 之禅特别系列的第二篇，我们将要关注其中第三与第四条原则：简单与复杂。
>
>
>

>
> Il semble que la perfection soit atteinte non quand il n'y a plus rien à ajouter, mais quand il n'y plus rien à retrancher.
>
>
> It seems that perfection is finally attained not when there is no longer anything to add, but when there is no longer anything to take away.
>
>
> “完美并非无可增，而是不可减。”
>
>
> —Antoine de Saint-Exupéry, [Terre des Hommes](https://en.wikipedia.org/wiki/Wind,_Sand_and_Stars), 1939
>
>
>

编程时最常有的考量是与复杂性的斗争，只想写出让旁人无从下手的繁杂代码，对每个程序员来讲都算不上难事。倘若未能触及代码的简繁取舍，那么 《[Python 之禅](https://www.python.org/dev/peps/pep-0020/)》 就有了一角残缺。

### <ruby> 简单胜过复杂 <rt>  Simple is better than complex </rt></ruby>

尚有选择余地时，应该选简单的方案。Python 少有*不可为*之事，这意味着设计出巴洛克风格（LCTT 译注：即夸张和不理性）的程序只为解决浅显的问题不仅有可能，甚至很简单。

正因如此，编程时应当谨记，代码的简单性是最易丢失，却最难复得的。

这意味着，在可以选用函数来表达时不要去引入额外的类；避免使用强力的第三方库往往有助于你针对迫切的问题场景设计更妥当的简短函数。不过其根本的意图，旨在让你减少对将来的盘算，而去着重解决手头的问题。

以简单和优美作为指导原则的代码相比那些想要囊括将来一切变数的，在日后要容易修改得多。

### <ruby> 复杂胜过错综复杂 <rt>  Complex is better than complicated </rt></ruby>

把握用词的精确含义对于理解这条令人费解的原则是至关重要的。形容某事<ruby> 复杂 <rt>  complex </rt></ruby>，是说它由许多部分组成，着重组成成分之多；而形容某事<ruby> 错综复杂 <rt>  complicated </rt></ruby>，则是指其包含着差异巨大、难以预料的行为，强调的是各组成部分之间的杂乱联系。

解决困难问题时，往往没有可行的简单方案。此时，最 Python 化的策略是“<ruby> 自底向上 <rt>  bottom-up </rt></ruby>”地构建出简单的工具，之后将其组合用以解决该问题。

这正是<ruby> 对象组合 <rt>  object composition </rt></ruby>这类技术的闪耀之处，它避免了错综复杂的继承体系，转而由独立的对象把一些方法调用传递给别的独立对象。这些对象都能独立地测试与部署，最终却可以组成一体。

“自底建造” 的另一例即是<ruby>   单分派泛函数  <rt>  singledispatch </rt></ruby>的使用，抛弃了错综复杂的对象之后，我们得到是简单、几乎无行为的对象以及独立的行为。

---

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

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

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


如何组织构建多文件 C 语言程序（二）

Summary: 我将在本系列的第二篇中深入研究由多个文件组成的 C 程序的结构。

我将在本系列的第二篇中深入研究由多个文件组成的 C 程序的结构。

# 如何组织构建多文件 C 语言程序（二）

>
> 我将在本系列的第二篇中深入研究由多个文件组成的 C 程序的结构。
>
>
>

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

在[第一篇](/article-11935-1.html)中，我设计了一个名为[喵呜喵呜](https://github.com/jnyjny/MeowMeow.git)的多文件 C 程序，该程序实现了一个玩具[编解码器](https://en.wikipedia.org/wiki/Codec)。我也提到了程序设计中的 Unix 哲学，即在一开始创建多个空文件，并建立一个好的结构。最后，我创建了一个 `Makefile` 文件夹并阐述了它的作用。在本文中将另一个方向展开：现在我将介绍简单但具有指导性的喵呜喵呜编解码器的实现。

当读过我的《[如何写一个好的 C 语言 main 函数](/article-10949-1.html)》后，你会觉得喵呜喵呜编解码器的 `main.c` 文件的结构很熟悉，其主体结构如下：

```
/* main.c - 喵呜喵呜流式编解码器 */

/* 00 系统包含文件 */
/* 01 项目包含文件 */
/* 02 外部声明 */
/* 03 定义 */
/* 04 类型定义 */
/* 05 全局变量声明（不要用）*/
/* 06 附加的函数原型 */

int main(int argc, char *argv[])
{
  /* 07 变量声明 */
  /* 08 检查 argv[0] 以查看该程序是被如何调用的 */
  /* 09 处理来自用户的命令行选项 */
  /* 10 做点有用的事情 */
}

/* 11 其它辅助函数 */
```

### 包含项目头文件

位于第二部分中的 `/* 01 项目包含文件 */` 的源代码如下：

```
/* main.c - 喵呜喵呜流式编解码器 */
...
/* 01 项目包含文件 */
#include "main.h"
#include "mmecode.h"
#include "mmdecode.h"
```

`#include` 是 C 语言的预处理命令，它会将该文件名的文件内容拷贝到当前文件中。如果程序员在头文件名称周围使用双引号（`""`），编译器将会在当前目录寻找该文件。如果文件被尖括号包围（`<>`），编译器将在一组预定义的目录中查找该文件。

[main.h](https://github.com/JnyJny/meowmeow/blob/master/main.h) 文件中包含了 [main.c](https://github.com/JnyJny/meowmeow/blob/master/main.c) 文件中用到的定义和类型定义。我喜欢尽可能多将声明放在头文件里，以便我在我的程序的其他位置使用这些定义。

头文件 [mmencode.h](https://github.com/JnyJny/meowmeow/blob/master/mmencode.h) 和 [mmdecode.h](https://github.com/JnyJny/meowmeow/blob/master/mmdecode.h) 几乎相同，因此我以 `mmencode.h` 为例来分析。

```
/* mmencode.h - 喵呜喵呜流编解码器 */

#ifndef _MMENCODE_H
#define _MMENCODE_H

#include <stdio.h>

int mm_encode(FILE *src, FILE *dst);

#endif /* _MMENCODE_H */
```

`#ifdef`、`#define`、`#endif` 指令统称为 “防护” 指令。其可以防止 C 编译器在一个文件中多次包含同一文件。如果编译器在一个文件中发现多个定义/原型/声明，它将会产生警告。因此这些防护措施是必要的。

在这些防护内部，只有两个东西：`#include` 指令和函数原型声明。我在这里包含了 `stdio.h` 头文件，以便于能在函数原型中使用 `FILE` 定义。函数原型也可以被包含在其他 C 文件中，以便于在文件的命名空间中创建它。你可以将每个文件视为一个独立的命名空间，其中的变量和函数不能被另一个文件中的函数或者变量使用。

编写头文件很复杂，并且在大型项目中很难管理它。不要忘记使用防护。

### 喵呜喵呜编码的最终实现

该程序的功能是按照字节进行 `MeowMeow` 字符串的编解码，事实上这是该项目中最简单的部分。截止目前我所做的工作便是支持允许在适当的位置调用此函数：解析命令行，确定要使用的操作，并打开将要操作的文件。下面的循环是编码的过程：

```
/* mmencode.c - 喵呜喵呜流式编解码器 */
...
   while (!feof(src)) {

     if (!fgets(buf, sizeof(buf), src))
       break;

     for(i=0; i<strlen(buf); i++) {
       lo = (buf[i] & 0x000f);
       hi = (buf[i] & 0x00f0) >> 4;
       fputs(tbl[hi], dst);
       fputs(tbl[lo], dst);
     }
   }
```

简单的说，当文件中还有数据块时（ `feof(3)` ），该循环读取（`feof(3)` ）文件中的一个数据块。然后将读入的内容的每个字节分成两个 `hi` 和 `lo` 的<ruby> 半字节 <rt>  nibble </rt></ruby>。半字节是半个字节，即 4 个位。这里的奥妙之处在于可以用 4 个位来编码 16 个值。我将 `hi` 和 `lo` 用作 16 个字符串查找表 `tbl` 的索引，表中包含了用半字节编码的 `MeowMeow` 字符串。这些字符串使用 `fputs(3)` 函数写入目标 `FILE` 流，然后我们继续处理缓存区的下一个字节。

该表使用 [table.h](https://github.com/JnyJny/meowmeow/blob/master/table.h) 中的宏定义进行初始化，在没有特殊原因（比如：要展示包含了另一个项目的本地头文件）时，我喜欢使用宏来进行初始化。我将在未来的文章中进一步探讨原因。

### 喵呜喵呜解码的实现

我承认在开始工作前花了一些时间。解码的循环与编码类似：读取 `MeowMeow` 字符串到缓冲区，将编码从字符串转换为字节

```
 /* mmdecode.c - 喵呜喵呜流式编解码器 */
 ...
 int mm_decode(FILE *src, FILE *dst)
 {
   if (!src || !dst) {
     errno = EINVAL;
     return -1;
   }
   return stupid_decode(src, dst);
 }
```

这不符合你的期望吗？

在这里，我通过外部公开的 `mm_decode()` 函数公开了 `stupid_decode()` 函数细节。我上面所说的“外部”是指在这个文件之外。因为 `stupid_decode()` 函数不在该头文件中，因此无法在其他文件中调用它。

当我们想发布一个可靠的公共接口时，有时候会这样做，但是我们还没有完全使用函数解决问题。在本例中，我编写了一个 I/O 密集型函数，该函数每次从源中读取 8 个字节，然后解码获得 1 个字节写入目标流中。较好的实现是一次处理多于 8 个字节的缓冲区。更好的实现还可以通过缓冲区输出字节，进而减少目标流中单字节的写入次数。

```
/* mmdecode.c - 喵呜喵呜流式编解码器 */
...
int stupid_decode(FILE *src, FILE *dst)
{
  char           buf[9];
  decoded_byte_t byte;
  int            i;

  while (!feof(src)) {
    if (!fgets(buf, sizeof(buf), src))
      break;
    byte.field.f0 = isupper(buf[0]);
    byte.field.f1 = isupper(buf[1]);
    byte.field.f2 = isupper(buf[2]);
    byte.field.f3 = isupper(buf[3]);
    byte.field.f4 = isupper(buf[4]);
    byte.field.f5 = isupper(buf[5]);
    byte.field.f6 = isupper(buf[6]);
    byte.field.f7 = isupper(buf[7]);

    fputc(byte.value, dst);
  }
  return 0;
}
```

我并没有使用编码器中使用的位移方法，而是创建了一个名为 `decoded_byte_t` 的自定义数据结构。

```
/* mmdecode.c - 喵呜喵呜流式编解码器 */
...

typedef struct {
  unsigned char f7:1;
  unsigned char f6:1;
  unsigned char f5:1;
  unsigned char f4:1;
  unsigned char f3:1;
  unsigned char f2:1;
  unsigned char f1:1;
  unsigned char f0:1;
} fields_t;

typedef union {
  fields_t      field;
  unsigned char value;
} decoded_byte_t;
```

初次看到代码时可能会感到有点儿复杂，但不要放弃。`decoded_byte_t` 被定义为 `fields_t` 和 `unsigned char` 的 **联合**。可以将联合中的命名成员看作同一内存区域的别名。在这种情况下，`value` 和 `field` 指向相同的 8 位内存区域。将 `field.f0` 设置为 `1` 也将会设置 `value` 中的最低有效位。

虽然 `unsigned char` 并不神秘，但是对 `fields_t` 的类型定义（`typedef`）也许看起来有些陌生。现代 C 编译器允许程序员在结构体中指定单个位字段的值。字段所在的类型是一个无符号整数类型，并在成员标识符后紧跟一个冒号和一个整数，该整数指定了位字段的长度。

这种数据结构使得按字段名称访问字节中的每个位变得简单，并可以通过联合中的 `value` 字段访问组合后的值。我们依赖编译器生成正确的移位指令来访问字段，这可以在调试时为你节省不少时间。

最后，因为 `stupid_decode()` 函数一次仅从源 `FILE` 流中读取 8 个字节，所以它效率并不高。通常我们尝试最小化读写次数，以提高性能和降低调用系统调用的开销。请记住：少量的读取/写入大的块比大量的读取/写入小的块好得多。

### 总结

用 C 语言编写一个多文件程序需要程序员要比只是是一个 `main.c` 做更多的规划。但是当你添加功能或者重构时，只需要多花费一点儿努力便可以节省大量时间以及避免让你头痛的问题。

回顾一下，我更喜欢这样做：多个文件，每个文件仅有简单功能；通过头文件公开那些文件中的小部分功能；把数字常量和字符串常量保存在头文件中；使用 `Makefile` 而不是 Bash 脚本来自动化处理事务；使用 `main()` 函数来处理命令行参数解析并作为程序主要功能的框架。

我知道我只是蜻蜓点水般介绍了这个简单的程序，并且我很高兴知道哪些事情对你有所帮助，以及哪些主题需要详细的解释。请在评论中分享你的想法，让我知道。

---

via: <https://opensource.com/article/19/7/structure-multi-file-c-part-2>

作者：[Erik O'Shaughnessy](https://opensource.com/users/jnyjny) 选题：[lujun9972](https://github.com/lujun9972) 译者：[萌新阿岩](https://github.com/mengxinayan) 校对：[wxy](https://github.com/wxy)

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


Basilisk：一个有着经典的外观和扩展的 Firefox 复刻

# Basilisk：一个有着经典的外观和扩展的 Firefox 复刻

>
> Basilisk 是一个 Firefox 复刻，它支持旧版的扩展等更多功能。在这里，我们看一下它的功能并尝试一下。
>
>
>

### Basilisk：基于 XUL 的开源 Web 浏览器

尽管最好使用 Linux 上的常规浏览器（如 Firefox 或 Chromium），但了解其他浏览器也没坏处。最近，我偶然发现了一个 Firefox 复刻：[Basilisk](https://www.basilisk-browser.org/) 浏览器，它有经典的 Firefox 用户界面以及对旧版扩展的支持（就像 [Waterfox](https://itsfoss.com/waterfox-browser/) 一样）。

如果你迫切需要使用旧版扩展程序或怀念 Firefox 的经典外观，Basilisk 浏览器可以帮到你。这个浏览器是由 [Pale Moon](https://www.palemoon.org) 浏览器背后的团队维护（这是我接下来要介绍的另一个 Firefox 复刻）。

如果你正在寻找开源 [Chrome 替代品](https://itsfoss.com/open-source-browsers-linux/)，那么你可以快速了解一下 Basilisk 提供的功能。

**注意：**Basilisk 是开发中软件。即使我在使用时没有遇到重大的可用性问题，但你也不应依赖它作为唯一使用的浏览器。

### Basilisk 浏览器的特性

Basilisk 开箱即用。但是，在考虑使用之前，可能需要先看一下以下这些特性：

* 基于 [XUL](https://developer.mozilla.org/en-US/docs/Archive/Mozilla/XUL) 的 Web 浏览器
* 它具有 “Australis” Firefox 界面，这在 v29–v56 的 Firefox 版本中非常流行。
* 支持 [NPAPI](https://wiki.mozilla.org/NPAPI) 插件（Flash、Unity、Java 等）
* 支持 XUL/Overlay Mozilla 形式的扩展。
* 使用 [Goanna](https://en.wikipedia.org/wiki/Goanna_(software)) 开源浏览器引擎，它是 Mozilla [Gecko](https://developer.mozilla.org/en-US/docs/Mozilla/Gecko) 的复刻
* 不使用 Rust 或 Photon 用户界面
* 仅支持 64 位系统

### 在 Linux 上安装 Basilisk

你可能没有在软件中心中找到它。因此，你必须前往其官方[下载页面](https://www.basilisk-browser.org/download.shtml)获得 tarball（tar.xz）文件。

下载后，只需将其解压缩并进入文件夹。接下来，你将在其中找到一个 `Basilisk` 可执行文件。你只需双击或右键单击并选择 “运行” 即可运行它。

你可以查看它的 [GitHub 页面](https://github.com/MoonchildProductions/Basilisk)获取更多信息。

你也可以按照下面的步骤使用终端进入下载的文件夹，并运行文件：

```
cd basilisk-latest.linux64
cd basilisk
./basilisk
```

* [下载 Basilisk](https://www.basilisk-browser.org/)

### 使用 Basilisk 浏览器

如果你想要支持旧版扩展，Basilisk 是不错的 Firefox 复刻。它是由 Pale Moon 背后的团队积极开发的，对于希望获得 Mozilla Firefox（在 Quantum 更新之前）经典外观，且不包括现代 Web 支持的用户而言，它可能是一个不错的选择。

浏览网页没有任何问题。但是，我注意到 YouTube 将其检测为过时的浏览器，并警告说它将很快停止支持它。

**因此，我不确定 Basilisk 是否适合所有现有的 Web 服务 —— 但是，如果你确实需要使用 Firefox 较早版本中的扩展，那这是一个解决方案。**

### 总结

你认为这个 Firefox 复刻值得尝试吗？你喜欢哪个？在下面的评论中分享你的想法。

---

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

作者：[Ankush Das](https://itsfoss.com/author/ankush/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


你所不知道的用 less 查看文件的高级用法

Summary: 使用 less 文件查看器的一些技巧。

使用 less 文件查看器的一些技巧。

# 你所不知道的用 less 查看文件的高级用法

>
> 使用 less 文件查看器的一些技巧。
>
>
>

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

最近，我正在拜读 Scott Nesbitt 的文章《[在 Linux 命令行中使用 less 来查看文本文件](http://opensource.com/article/18/4/using-less-view-text-files-command-line)》，并受到了一些启发，所以我想分享一些使用 `less` 命令的技巧。

### LESS 环境变量

如果你定义了环境变量 `LESS`（例如在 `.bashrc` 中），那么 `less` 会将其视为一个选项列表，就像在命令行中传递给它一样。

我这样定义：

```
LESS='-C -M -I -j 10 -# 4'
```

它的意思是：

* `-C` – 通过不从底部滚动来加快全屏打印速度。
* `-M` – 在最后一行（状态行）显示更多信息。你可以使用 `-PM` 来自定义显示的信息，但我通常只用 `-M`。
* `-I` – 忽略搜索中的大小写。
* `-j 10` – 在终端的第 10 行而不是第一行显示搜索结果。这样，每次按 `n` 或（`N`） 跳到下一个（或上一个）匹配项时，就会有 10 条上下文。
* `-# 4` – 当按下向右或向左的箭头时，会向右或向左跳四个字符。默认情况时跳转半个屏幕，我觉得太多了。一般来说，`less` 似乎（至少部分）是按最初开发它时的环境优化的，那时使用慢速调制解调器和低带宽的互联网连接，所以跳过半个屏幕是有意义的。

### PAGER 环境变量

许多程序使用在 `PAGER` 环境变量中的命令来显示信息。因此，你可以在 `.bashrc` 中设置 `PAGER=less`，然后让程序运行 `less`。查看手册页（`man 7 environ`）中是否有其它此类变量。

### -S

`-S` 告诉 `less` 将长行切断而不是将它们换行。除非我在（或我要）查看文件，否则我很少需要这样做。幸运的是，你可以在 `less` 中输入所有命令行选项，就像它们是键盘命令一样。因此，如果我想在文件已经打开的情况下隔断长行，我可以简单地输入 `-S`。（LCTT 译注：注意大写 `S` ，并按回车）

这是我经常使用的一个例子：

```
su - postgres
export PAGER=less  # 因为我不用在所有的机器上编辑 postgres 的 .bashrc
psql
```

有时当我查看一个 `SELECT` 命令的输出非常宽时，我会输入 `-S` 以便将其格式化的漂亮一些。如果当我按下右箭头想查看更多内容时它跳得太远（因为我没有设置 `-#`），则可以输入 `-#8`，那么每次按下右箭头都会向右移动八个字符。

有时在多次输入 `-S` 之后，我会退出 psql 并设置环境变量后再次运行它：

```
export LESS=-S
```

### F

命令 `F` 可以使 `less` 像 `tail -f` 一样工作，等待更多的数据被添加到文件后再显示它们。与 `tail -f` 相比，它的一个优点是，高亮显示搜索匹配仍然有效。因此，你可以输入 `less /var/log/logfile`，搜索某些内容时，它将高亮显示所有出现的内容（除非你使用了 `-g`），然后按下 `F` 键，当更多数据写入到日志时，`less` 将显示它并高亮新的匹配项。

按下 `F` 后，可以按 `Ctrl+C` 来停止其查找新数据（这不会干掉它），这样你可以返回文件查看旧内容，搜索其它内容等，然后再次按 `F` 键来查看更多新数据。

### 搜索

搜索使用系统的正则表达式库，这通常意味着你可以使用扩展正则表达式。特别是，搜索 `one|two|three` 可以找到并高亮所有的 one、two 或 three。

我经常使用的另一种模式是 `.*someting.*`，特别是对于一些很长的日志行（例如，跨越多个终端宽度的行），它会高亮整行。这种模式使查看一行的起始和结束位置变得更加容易。我还会结合其它内容，例如 `.*one thing.*|.*another thing.*`，或者使用 `key: .*|.*marker.*` 来查看 `key` 的内容。例如，一个日志文件中包含一些字典/哈希的转储。它会高亮相关的标记行，这样我就看到上下文了，甚至，如果我知道这个值被引号引起来的话，就可以：

```
key: '[^']*'|.*marker.*
```

`less` 会保留你的搜索项的历史纪录，并将其保存到磁盘中以备将来调用。当你按下 `/` 或 `?` 时，可以使用向上或向下箭头浏览历史记录（以及进行基本的行编辑）。

在撰写本文时，我无意间看了下 `less` 手册页，发现了一个非常有用的功能：使用 `&!pattern` 跳过无关的行。例如，当我在 `/var/log/messages` 中寻找内容时，经常会一个个迭代使用以下命令：

```
cat /var/log/messages | egrep -v 'systemd: Started Session' | less
cat /var/log/messages | egrep -v 'systemd: Started Session|systemd: Starting Session' | less
cat /var/log/messages | egrep -v 'systemd: Started Session|systemd: Starting Session|User Slice' | less
cat /var/log/messages | egrep -v 'systemd: Started Session|systemd: Starting Session|User Slice|dbus' | less
cat /var/log/messages | egrep -v 'systemd: Started Session|systemd: Starting Session|User Slice|dbus|PackageKit Daemon' | less
```

但是现在我知道如何在 `less` 中做同样的事情。例如，我可以输入 `&!systemd: Started Session`，然后想要隐藏 `systemd: Starting Session`，所以我输入 `&!`，并使用向上箭头从历史记录中获得上一次搜索的结果。然后我接着输入 `|systemd: Starting Session` 并按下回车，继续以相同的方式添加更多条目，直到我过滤掉足够多的条目，看到更有趣的内容。

### =

命令 `=` 显示有关文件和位置的更多信息，甚至比 `-M` 更多。如果文件非常大，计算 `=` 花费的时间太长，可以按下 `Ctrl+C`，它将停止尝试计算。

如果你正在查看的内容来自管道而不是文件，则 `=`（和 `-M`）不会显示未知内容，包括文件中的行数和字节数。要查看这些数据，如果你知道管道命令将很快结束，则可以使用 `G` 跳到最后，然后 `less` 将开始显示这些信息。

如果按下 `G` 并且写入管道的命令花费的时间比预期的长，你可以按下 `Ctrl+C`，该命令将被终止。即使你没有按 `G`，`Ctrl+C` 键也会杀死它。因此，如果你不想终止命令，请不要意外按下 `Ctrl+C`。出于这个原因，如果命令执行了某些操作（不仅是显示信息），通常更安全的做法是将其输出写入文件并在单独的终端中查看文件，而不是使用管道。

### 为什么你需要 less

`less` 是一个非常强大的程序，与该领域中较新的竞争者（例如 `most` 和 `more`）不同，你可能会在几乎所有的系统上找到它，就像 `vi` 一样。因此，即使你使用 GUI 查看器或编辑器，花一些时间浏览 `less` 手册页也是值得的，至少可以了解一下它的用处。这样，当你需要做一些已有的功能可能提供的工作时，就会知道如何要搜索手册页或互联网来找到所需的内容。

有关更多信息，访问 [less 主页](http://www.greenwoodsoftware.com/less/)。该网站有一个不错的常见问题解答，其中包含更多提示和技巧。

---

via: <https://opensource.com/article/18/5/advanced-use-less-text-file-viewer>

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


6 件你应该用 Emacs 做的事

# 6 件你应该用 Emacs 做的事

>
> 下面六件事情你可能都没有意识到可以在 Emacs 下完成。此外还有我们的新备忘单，拿去，充分利用 Emacs 的功能吧。
>
>
>

想象一下使用 Python 的 IDLE 界面来编辑文本。你可以将文件加载到内存中，编辑它们，并保存更改。但是你执行的每个操作都由 Python 函数定义。例如，调用 `upper()` 来让一个单词全部大写，调用 `open` 打开文件，等等。文本文档中的所有内容都是 Python 对象，可以进行相应的操作。从用户的角度来看，这与其他文本编辑器的体验一致。对于 Python 开发人员来说，这是一个丰富的 Python 环境，只需在配置文件中添加几个自定义函数就可以对其进行更改和开发。

这就是 [Emacs](https://www.gnu.org/software/emacs/) 对 1958 年的编程语言 [Lisp](https://en.wikipedia.org/wiki/Lisp_(programming_language)) 所做的事情。在 Emacs 中，运行应用程序的 Lisp 引擎与输入文本之间无缝结合。对 Emacs 来说，一切都是 Lisp 数据，因此一切都可以通过编程进行分析和操作。

这造就了一个强大的用户界面（UI）。但是，如果你是 Emacs 的普通用户，你可能对它的能力知之甚少。下面是你可能没有意识到 Emacs 可以做的六件事。

### 使用 Tramp 模式进行云端编辑

Emacs 早在网络流行化之前就实现了透明的网络编辑能力了，而且时至今日，它仍然提供了最流畅的远程编辑体验。Emacs 中的 [Tramp 模式](https://www.gnu.org/software/tramp/)（以前称为 RPC 模式）代表着 “<ruby> 透明的远程（文件）访问，多协议 <rt>  Transparent Remote (file) Access，Multiple Protocol </rt></ruby>”，这准确说明了它提供的功能：通过最流行的网络协议轻松访问你希望编辑的远程文件。目前最流行、最安全的能用于远程编辑的协议是 [OpenSSH](https://www.openssh.com/)，因此 Tramp 使用它作为默认的协议。

在 Emacs 22.1 或更高版本中已经包含了 Tramp，因此要使用 Tramp，只需使用 Tramp 语法打开一个文件。在 Emacs 的 “File” 菜单中，选择 “Open File”。当在 Emacs 窗口底部的小缓冲区中出现提示时，使用以下语法输入文件名：

```
/ssh:user@example.com:/path/to/file
```

如果需要交互式登录，Tramp 会提示你输入密码。但是，Tramp 直接使用 OpenSSH，所以为了避免交互提示，你可以将主机名、用户名和 SSH 密钥路径添加到你的 `~/.ssh/config` 文件。与 Git 一样，Emacs 首先使用你的 SSH 配置，只有在出现错误时才会停下来询问更多信息。

Tramp 非常适合编辑并没有放在你的计算机上的文件，它的用户体验与编辑本地文件没有明显的区别。下次，当你 SSH 到服务器启动 Vim 或 Emacs 会话时，请尝试使用 Tramp。

### 日历

如果你喜欢文本多过图形界面，那么你一定会很高兴地知道，可以使用 Emacs 以纯文本的方式安排你的日程（或生活），而且你依然可以在移动设备上使用开源的 [Org 模式](https://orgmode.org/)查看器来获得华丽的通知。

这个过程需要一些配置，以创建一个方便的方式来与移动设备同步你的日程（我使用 Git，但你可以调用蓝牙、KDE Connect、Nextcloud，或其他文件同步工具），此外你必须在移动设备上安装一个 Org 模式查看器（如 [Orgzly](https://f-droid.org/en/packages/com.orgzly/)）以及 Git 客户程序。但是，一旦你搭建好了这些基础，该流程就会与你常用的（或正在完善的，如果你是新用户）Emacs 工作流完美地集成在一起。你可以在 Emacs 中方便地查阅日程、更新日程，并专注于任务上。议程上的变化将会反映在移动设备上，因此即使在 Emacs 不可用的时候，你也可以保持井然有序。

感兴趣了？阅读我的关于[使用 Org mode 和 Git 进行日程安排](/article-11320-1.html)的逐步指南。

### 访问终端

有[许多终端模拟器](/article-11814-1.html)可用。尽管 Emacs 中的 Elisp 终端仿真器不是最强大的通用仿真器，但是它有两个显著的优点：

1. **打开在 Emacs 缓冲区之中**：我使用 Emacs 的 Elisp shell，因为它在 Emacs 窗口中打开很方便，我经常全屏运行该窗口。这是一个小而重要的优势，只需要输入 `Ctrl+x+o`（或用 Emacs 符号来表示就是 `C-x o`）就能使用终端了，而且它还有一个特别好的地方在于当运行漫长的作业时能够一瞥它的状态报告。
2. **在没有系统剪贴板的情况下复制和粘贴特别方便**：无论是因为懒惰不愿将手从键盘移动到鼠标，还是因为在远程控制台运行 Emacs 而无法使用鼠标，在 Emacs 中运行终端有时意味着可以从 Emacs 缓冲区中很快地传输数据到 Bash。

要尝试 Emacs 终端，输入 `Alt+x`（用 Emacs 符号表示就是 `M-x`），然后输入 `shell`，然后按回车。

### 使用 Racket 模式

[Racket](http://racket-lang.org/) 是一种激动人心的新兴 Lisp 方言，拥有动态编程环境、GUI 工具包和充满激情的社区。学习 Racket 的默认编辑器是 DrRacket，它的顶部是定义面板，底部是交互面板。使用该设置，用户可以编写影响 Racket 运行时环境的定义。就像旧的 [Logo Turtle](https://en.wikipedia.org/wiki/Logo_(programming_language)#Turtle_and_graphics) 程序，但是有一个终端而不是仅仅一个海龟。

*由 PLT 提供的 LGPL 示例代码*

基于 Lisp 的 Emacs 为资深 Racket 编程人员提供了一个很好的集成开发环境（IDE）。它尚未附带 [Racket 模式](https://www.racket-mode.com/)，但你可以使用 Emacs 包安装程序安装 Racket 模式和辅助扩展。要安装它，按下 `Alt+X`（用 Emacs 符号表示就是 `M-x`），键入 `package-install`，然后按回车。接着输入要安装的包 `racet-mode`，按回车。

使用 `M-x racket-mode` 进入 Racket 模式。如果你是 Racket 新手，而对 Lisp 或 Emacs 比较熟悉，可以从这份优秀的[图解 Racket](https://docs.racket-lang.org/quick/index.html) 入手。

### 脚本

你可能知道，Bash 脚本在自动化和增强 Linux 或 Unix 体验方面很流行。你可能听说过 Python 在这方面也做得很好。但是你知道 Lisp 脚本可以用同样的方式运行吗？有时人们会对 Lisp 到底有多有用感到困惑，因为许多人是通过 Emacs 来了解 Lisp 的，因此有一种潜在的印象，即在 21 世纪运行 Lisp 的惟一方法是在 Emacs 中运行。幸运的是，事实并非如此，Emacs 是一个很好的 IDE，它支持将 Lisp 脚本作为一般的系统可执行文件来运行。

除了 Elisp 之外，还有两种流行的现代 Lisp 可以很容易地用来作为独立脚本运行。

1. **Racket**：你可以通过在系统上运行 Racket 来提供运行 Racket 脚本所需的运行时支持，或者你可以使用 `raco exe` 产生一个可执行文件。`raco exe` 命令将代码和运行时支持文件一起打包，以创建可执行文件。然后，`raco distribution` 命令将可执行文件打包成可以在其他机器上工作的发行版。Emacs 有许多 Racket 工具，因此在 Emacs 中创建 Racket 文件既简单又有效。
2. **GNU Guile**：[GNU Guile](https://www.gnu.org/software/guile/)（<ruby> GNU 通用智能语言扩展 <rt>  GNU Ubiquitous Intelligent Language for Extensions </rt></ruby> 的缩写）是 [Scheme](https://en.wikipedia.org/wiki/Scheme_(programming_language)) 编程语言的一个实现，它可以用于为桌面、互联网、终端等创建应用程序和游戏。Emacs 中的 Scheme 扩展众多，使用任何一个扩展来编写 Scheme 都很容易。例如，这里有一个用 Guile 编写的 “Hello world” 脚本：

```
#!/usr/bin/guile -s
!#

(display "hello world")
     (newline)
```

用 `guile` 编译并允许它：

```
$ guile ./hello.scheme
;;; compiling /home/seth/./hello.scheme
;;; compiled [...]/hello.scheme.go
hello world
$ guile ./hello.scheme
hello world
```

### 无需 Emacs 允许 Elisp

Emacs 可以作为 Elisp 的运行环境，但是你无需按照传统印象中的必须打开 Emacs 来运行 Elisp。`--script` 选项可以让你使用 Emacs 作为引擎来执行 Elisp 脚本，而无需运行 Emacs 图形界面（甚至也无需使用终端）。下面这个例子中，`-Q` 选项让 Emacs 忽略 `.emacs` 文件，从而避免由于执行 Elisp 脚本时产生延迟（若你的脚本依赖于 Emacs 配置中的内容，那么请忽略该选项）。

```
emacs -Q --script ~/path/to/script.el
```

### 下载 Emacs 备忘录

Emacs 许多重要功能都不是只能通过 Emacs 来实现的；Org 模式是 Emacs 扩展也是一种格式标准，流行的 Lisp 方言大多不依赖于具体的应用，我们甚至可以在没有可见或可交互式 Emacs 实例的情况下编写和运行 Elisp。然后若你对为什么模糊代码和数据之间的界限能够引发创新和效率感到好奇的话，那么 Emacs 是一个很棒的工具。

幸运的是，现在是 21 世纪，Emacs 有了带有传统菜单的图形界面以及大量的文档，因此学习曲线不再像以前那样。然而，要最大化 Emacs 对你的好处，你需要学习它的快捷键。由于 Emacs 支持的每个任务都是一个 Elisp 函数，Emacs 中的任何功能都可以对应一个快捷键，因此要描述所有这些快捷键是不可能完成的任务。你只要学习使用频率 10 倍于不常用功能的那些快捷键即可。

我们汇聚了最常用的 Emacs 快捷键成为一份 Emacs 备忘录以便你查询。将它挂在屏幕附近或办公室墙上，把它作为鼠标垫也行。让它触手可及经常翻阅一下。每次翻两下可以让你获得十倍的学习效率。而且一旦开始编写自己的函数，你一定不会后悔获取了这个免费的备忘录副本的！

* [这里下载 Emacs 备忘录（需注册）](https://opensource.com/downloads/emacs-cheat-sheet)

---

via: <https://opensource.com/article/20/1/emacs-cheat-sheet>

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

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


6 个可以尝试的树莓派教程

Summary: 这些树莓派项目均旨在简化你的生活并提高生产力。

这些树莓派项目均旨在简化你的生活并提高生产力。

# 6 个可以尝试的树莓派教程

>
> 这些树莓派项目均旨在简化你的生活并提高生产力。
>
>
>

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

没有什么比体验树莓派创作结果更令人兴奋了。经过数小时的编程、测试和徒手构建，你的项目终于开始成形，你不禁大喊 “哇哦！”树莓派可以带给日常生活的可能性让我着迷。无论你是想学习新知识、尝试提高效率还是只是乐在其中，本文总有一个树莓派项目适合你。

### 设置 VPN 服务器

本[教程](https://opensource.com/article/19/6/raspberry-pi-vpn-server)教你如何使用树莓派添加一个网络安全层。这个项目不仅有实际好处，而且还能为你带来很多乐趣。额外的安全性使你可以放心地做其它项目，例如下面列出的项目。

### 创建一个物体跟踪摄像机

树莓派之所以具有吸引力，是因为它提供了较低的入门门槛来学习机器学习等新技术。这份[分步指南](https://opensource.com/article/20/1/object-tracking-camera-raspberry-pi)提供了详尽的说明，说明了如何构建一个全景摄像头，以便使用 TensorFlow 和树莓派跟踪运动。

### 使用照片幻灯片展示你最喜欢的回忆

你是否曾经问过自己：“我应该怎么处理这些数码照片？”。如果你像我一样这样想过，那么答案是“是”。在朋友和家人圈子中，我被公认为摄像爱好者。这就是为什么我喜欢这个树莓派项目。在[本教程](https://opensource.com/article/19/2/wifi-picture-frame-raspberry-pi)中，你将学习如何设置照片幻灯片，以便轻松地在家里展示自己喜欢的回忆，而无需打印机！

### 玩复古电子游戏

如果你对复古游戏系统怀有怀旧之情，那么可以尝试[本教程](https://opensource.com/article/19/3/amiga-raspberry-pi)。了解包括树莓派在内的哪些设备可以运行 Amiga 模拟器。完成设置后，你将可在树莓派上玩自己喜欢的 Amiga 游戏。

### 为你的娱乐中心搭建时钟

在过去的十年中，家庭娱乐中心发生了很大的变化。我的家人完全依靠流媒体服务来观看节目和电影。我之所以爱它是因为我可以通过移动设备或语音助手控制电视。但是，当你不再能一眼看到时钟时，便会失去一定程度的便利！请遵循[这些步骤](https://opensource.com/article/17/7/raspberry-pi-clock)，使用树莓派从头开始搭建自己的时钟显示。

### 扩大自制啤酒的生产规模

在[本教程](https://opensource.com/article/17/7/brewing-beer-python-and-raspberry-pi)中，经验丰富的家庭酿酒师分享了他建立电动啤酒酿造系统的经验。该项目需要在硬件和零件上进行更多的前期投资，但由此产生的效率和一致性让这些值得。为此祝贺！

如果你是像我这样的树莓派新手，那么我建议你阅读我们这些可下载的树莓派指南。我们的[单页速查表](https://opensource.com/downloads/getting-started-raspberry-pi-cheat-sheet)提供了入门指南。有关更多技巧和教程，我们的[综合指南](https://opensource.com/downloads/raspberry-pi-guide)涵盖了一些主题，例如选择树莓派、保持更新、为社区做出贡献等。

你会尝试哪个树莓派项目？让我们在评论中知道。

---

via: <https://opensource.com/article/20/3/raspberry-pi-tutorials>

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


适用于初学者的基本 kubectl 和 Helm 命令

Summary: 去杂货店“采购”这些命令，你需要用这些 Kubernetes 工具来入门。

去杂货店“采购”这些命令，你需要用这些 Kubernetes 工具来入门。

# 适用于初学者的基本 kubectl 和 Helm 命令

>
> 去杂货店“采购”这些命令，你需要用这些 Kubernetes 工具来入门。
>
>
>

最近，我丈夫告诉我他即将要去参加一个工作面试，面试时他需要在计算机上运行一些基本命令。他对这场面试感到焦虑，但是对于他来说，学习和记住事情的最好方法是将不了解的事物比喻为非常熟悉的事物。因为我们的谈话是在我逛杂货店试图决定当晚要烹饪的食物之后进行的，所以这启发我用一次去杂货店的行程来介绍 `kubectl` 和 `helm` 命令。

[Helm](https://helm.sh/)（“舵轮”）是在 Kubernetes（来自希腊语，意思是“舵手” 或 “领航员”）中管理应用程序的工具。你可以轻松地使用你的应用程序信息来部署“<ruby> 海图 <rt>  chart </rt></ruby>”，从而可以在你的 Kubernetes 环境中几分钟之内让它们就绪并预配置好。在学习新知识时，查看示例的“海图”以了解其用法总是很有帮助的，因此，如果有时间，请查看这些成型的“[海图](https://github.com/helm/charts/tree/master/stable)”。（LCTT 译注：Kubernetes 生态中大量使用了和航海有关的比喻，因此本文在翻译时也采用了这些比喻）

[kubectl](https://kubernetes.io/docs/reference/kubectl/kubectl/) 是与 Kubernetes 环境交互的命令行界面，允许你配置和管理集群。它需要一些配置才能在环境中工作，因此请仔细阅读其[文档](https://kubernetes.io/docs/reference/kubectl/overview/)以了解你需要做什么。

我会在示例中使用命名空间，你可以在我的文章《[Kubernetes 命名空间入门](/article-11749-1.html)》中了解它。

现在我们已经准备好了，让我们开始 `kubectl`和 `helm` 基本命令的购物之旅！

### 用 Helm 列出清单

你去商店之前要做的第一件事是什么？好吧，如果你做事有条理，会创建一个“清单”。同样，这是我将解释的第一个基本的 Helm 命令。

在一个用 Helm 部署的应用程序中，`list` 命令提供有关应用程序当前版本的详细信息。在此示例中，我有一个已部署的应用程序：Jenkins CI/CD 应用程序。运行基本的 `list` 命令总是会显示默认的命名空间。由于我没有在默认的命名空间中部署任何内容，因此不会显示任何内容：

```
$helm list
NAME    NAMESPACE    REVISION    UPDATED    STATUS    CHART    APP VERSION
```

但是，如果运行带有额外标志的命令，则会显示我的应用程序和信息：

```
$helm list --all-namespaces
NAME     NAMESPACE  REVISION  UPDATED                   STATUS      CHART           APP  VERSION
jenkins  jenkins        1         2020-01-18 16:18:07 EST   deployed    jenkins-1.9.4   lts
```

最后，我可以指示 `list` 命令只检查我想从中获取信息的命名空间：

```
$helm list --namespace jenkins
NAME     NAMESPACE  REVISION  UPDATED                   STATUS    CHART          APP VERSION
jenkins    jenkins      1              2020-01-18 16:18:07 EST  deployed  jenkins-1.9.4  lts
```

现在我有了一个清单，并且知道该清单上有什么，我可以使用 `get` 命令来“获取”我的物品！我会从 Kubernetes 集群开始，看看我能从中获取到什么？

### 用 Kubectl 获取物品

`kubectl get` 命令提供了有关 Kubernetes 中许多事物的信息，包括“<ruby> 吊舱 <rt>  Pod </rt></ruby>”、节点和命名空间。同样，如果没有指定命名空间标志，就会使用默认的命名空间。首先，我获取集群中的命名空间以查看正在运行的命名空间：

```
$kubectl get namespaces
NAME             STATUS   AGE
default          Active   53m
jenkins          Active   44m
kube-node-lease  Active   53m
kube-public      Active   53m
kube-system      Active   53m
```

现在我已经知道了在我的环境中运行的有哪些命名空间了，接下来获取节点并查看有多少个节点正在运行：

```
$kubectl get nodes
NAME       STATUS   ROLES       AGE   VERSION
minikube   Ready    master  55m   v1.16.2
```

我有一个节点正在运行，这主要是因为我的 Minikube 运行在一台小型服务器上。要得到在我的这一个节点上运行的“吊舱”可以这样：

```
$kubectl get pods
No resources found in default namespace.
```

啊哦，它是空的。我将通过以下方式获取 Jenkins 命名空间中的内容：

```
$kubectl get pods --namespace jenkins
NAME                      READY  STATUS   RESTARTS  AGE
jenkins-7fc688c874-mh7gv  1/1    Running  0         40m
```

好消息！这里发现了一个“吊舱”，它还没有重新启动过，已运行了 40 分钟了。好的，如今我知道“吊舱”已经装好，所以我想看看用 Helm 命令可以得到什么。

### 用 Helm 获取信息

`helm get` 命令稍微复杂一点，因为这个“获取”命令所需要的不仅仅是一个应用程序名称，而且你可以从应用程序中请求多个内容。我会从获取用于制作该应用程序的值开始，然后展示“获取全部”的操作结果的片段，该操作将提供与该应用程序相关的所有数据。

```
$helm get values jenkins -n jenkins
USER-SUPPLIED VALUES:
null
```

由于我只安装了最小限度的稳定版，因此配置没有更改。如果我运行“获取全部”命令，我将得到所有的“海图”：

```
$helm get all jenkins -n jenkins
```

这会产生大量数据，因此我始终建议保留一份 Helm “海图”的副本，以便你可以查看“海图”中的模板。我还创建自己的值来了解自己所拥有的。

现在，我把所有的商品都放在购物车中了，我会检查一下“描述”它们包含什么的标签。这些示例仅与 `kubectl` 命令有关，它们描述了我通过 Helm 部署的内容。

### 用 kubectl 查看描述

正如我使用“获取”命令（该命令可以描述 Kubernetes 中的几乎所有内容）所做的那样，我将示例限定到命名空间、“吊舱”和节点上。由于我知道它们每一个是什么，因此这很容易。

```
$kubectl describe ns jenkins
Name:           jenkins
Labels:         <none>
Annotations:  <none>
Status:         Active
No resource quota.
No resource limits.
```

我可以看到我的命名空间的名称，并且它是活动的，没有资源或限额限制。

`describe pods` 命令会产生大量信息，因此我这里提供的是一小段输出。如果你在不使用“吊舱”名称的情况下运行该命令，它将返回名称空间中所有“吊舱”的信息，这可能会很麻烦。因此，请确保在此命令中始终包含“吊舱”名称。例如：

```
$kubectl describe pods jenkins-7fc688c874-mh7gv --namespace jenkins
```

这会提供容器的状态、管理方式、标签以及“吊舱”中所使用的镜像（还有很多其它信息）。没有在这个简化过的输出中包括的数据有：在 Helm 配置值文件中应用的各种条件下的资源请求和限制、初始化容器和存储卷信息。如果你的应用程序由于资源不足而崩溃，或者是一个需要运行前置脚本进行配置的初始配置容器，或者生成不应该存储于纯文本 YAML 文件中的隐藏密码，则此数据很有用。

最后，我将使用 `describe node` 命令，当然，它是用来描述节点的。由于本示例只有一个名为 Minikube 的示例，因此我将使用这个名字。如果你的环境中有多个节点，则必须包含你想查找的的节点名称。

与“吊舱”一样，这个节点的命令会产生大量数据，因此我将仅包括输出片段。

```
$kubectl describe node minikube
```

注意，`describe node` 是更重要的基本命令之一。如此图所示，该命令返回统计信息，该信息指示节点何时资源用尽，并且该数据非常适合在需要扩展时（如果你的环境中没有自动扩展）向你发出警报。此输出片段中未包含的其它内容包括：对所有资源和限制的请求所占的百分比，以及资源的使用期限和分配（例如，对于我的应用程序而言）。

### 买单

使用这些命令，我完成了“购物”并得到了我想要的一切。希望这些基本命令也能在你使用 Kubernetes 的日常工作中提供帮助。

我鼓励你经常使用命令行并学习“帮助”部分中的速记标志，你可以通过运行以下命令来查看这些标志：

```
$helm --help
```

或

```
$kubectl -h
```

### 花生酱和果冻

有些东西像花生酱和果冻一样混在一起。Helm 和 `kubectl` 就有点像那样交错在一起。

我经常在自己的环境中使用这些工具。因为它们在很多地方都有很多相似之处，所以在使用其中一个之后，我通常需要跟进另一个。例如，我可以进行 Helm 部署，并使用 `kubectl` 观察它是否失败。一起试试它们，看看它们能为你做什么。

---

via: <https://opensource.com/article/20/2/kubectl-helm-commands>

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


如何在 Linux 中更改 MAC 地址

Summary: 在向你展示如何在 Linux 中更改 Mac 地址之前，让我们首先讨论为什么要更改它。

# 如何在 Linux 中更改 MAC 地址

在向你展示如何在 Linux 中更改 MAC 地址之前，让我们首先讨论为什么要更改它。

可能有几个原因。也许你不希望在公共网络上公开你的实际 [MAC 地址](https://en.wikipedia.org/wiki/MAC_address)（也称为物理地址）？还有可能是网络管理员可能已在路由器或防火墙中阻止了特定的 MAC 地址。

一个实用的“好处”是某些公共网络（例如机场 WiFi）允许在有限的时间内免费上网。如果你还想继续使用，那么伪造 Mac 地址可能会欺骗网络，让它认为是一台新设备。这也是一个有名的原因。

我将展示更改 MAC 地址（也称为欺骗/伪造 MAC 地址）的步骤。

### 在 Linux 中更改 MAC 地址

让我们一步步来：

#### 查找你的 MAC 地址和网络接口

让我们找出一些[关于 Linux 中网卡的细节](https://itsfoss.com/find-network-adapter-ubuntu-linux/)。使用此命令获取网络接口详细信息：

```
ip link show
```

在输出中，你将看到一些详细信息以及 MAC 地址：

```
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eno1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN mode DEFAULT group default qlen 1000
    link/ether 94:c6:f8:a7:d7:30 brd ff:ff:ff:ff:ff:ff
3: enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DORMANT group default qlen 1000
    link/ether 38:42:f8:8b:a7:68 brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
    link/ether 42:02:07:8f:a7:38 brd ff:ff:ff:ff:ff:ff
```

如你所见，在这里，我的网络接口称为 `enp0s31f6`，MAC 地址为 `38:42:f8:8b:a7:68`。

你可能需要在安全的地方记录下来，以便稍后还原到该原始 MAC 地址。

现在你可以继续更改 MAC 地址。

注意！

如果在当前使用的网络接口上执行此操作，那么可能会中断你的网络连接。因此，请在其他网卡上尝试使用此方法，或者准备重启网络。

#### 方法 1：使用 Macchanger 更改 MAC 地址

[Macchanger](https://github.com/alobbs/macchanger) 是查看、修改和操作网卡 MAC 地址的简单程序。它几乎在所有 GNU/Linux 操作系统中都可用，你可以使用发行版的包安装程序进行安装。

在 Arch Linux 或 Manjaro 上：

```
sudo pacman -S macchanger
```

在 Fedora、CentOS 和 RHEL 上：

```
sudo dnf install macchanger
```

在 Debian、Ubuntu、Linux Mint、Kali Linux 上：

```
sudo apt install macchanger
```

**重要！**系统会要求你选择是否应将 `macchanger` 设置为在每次启动或关闭网络设备时自动运行。每当你接到网线或重启 WiFi 时，它都会提供一个新的 MAC 地址。

我建议不要自动运行它，除非你确实需要每次更改 MAC 地址。因此，选择“No”（按 `Tab` 键），然后按回车键继续。

**如何使用 Macchanger 更改 MAC 地址**

你还记得网络接口名称吗？你在前面的步骤中获得了它。

现在，要将随机 MAC 地址分配给该网卡，请使用：

```
sudo macchanger -r enp0s31f6
```

更改 MAC 后，使用以下命令进行验证：

```
ip addr
```

现在你将看到已经伪造 MAC。

要将 MAC 地址更改为特定值，请使用以下命令指定自定义 MAC 地址：

```
macchanger --mac=XX:XX:XX:XX:XX:XX
```

其中 XX:XX:XX:XX:XX:XX 是你要更改的新 MAC。

最后，要将 MAC 地址恢复为其原始硬件值，请运行以下命令：

```
macchanger -p enp0s31f6
```

但是，你不必如此。重启系统后，更改将自动丢失，并且实际的 MAC 地址将再次恢复。

你可以随时查看手册页以获取更多详细信息。

#### 方法 2：使用 iproute2 更改 Mac 地址（中级知识）

我建议你使用 macchanger，但如果你不想使用它，那么可以使用另一种方法在 Linux 中更改 MAC 地址。

首先，使用以下命令关闭网卡：

```
sudo ip link set dev enp0s31f6 down
```

接下来，使用以下命令设置新的 MAC：

```
sudo ip link set dev enp0s31f6 address XX:XX:XX:XX:XX:XX
```

最后，使用以下命令重新打开网络：

```
sudo ip link set dev enp0s31f6 up
```

现在，验证新的 MAC 地址：

```
ip link show enp0s31f6
```

就是这些了。你已经成功地在 Linux 中修改了 MAC 地址。敬请期待 FOSS 更多有关 Linux 教程和技巧的文章。

---

via: <https://itsfoss.com/change-mac-address-linux/>

作者：[Dimitrios Savvopoulos](https://itsfoss.com/author/itsfoss/) 选题：[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: 我们已经开发了几个小程序，因此，最近几天，我将它们链接了起来。

我们已经开发了几个小程序，因此，最近几天，我将它们链接了起来。

# 把小程序链接起来

我们已经开发了几个小程序，分别是用于显示 Linux 命令用法的“**Linux**”、用于显示和搜索 Linux 中国文章的“**Linux文章**”，以及改善公众号文章内链接访问体验的“**文章助手**”。这几个独立的小程序各司其职，也在一定领域有所重叠和关联，因此，最近几天，我将它们链接了起来。

### 从 “Linux” 链接到“Linux文章”

首先，在“Linux”小程序内显示命令用法的页面上，在“延伸阅读”部分会推荐相关文章，之前这个部分的数据是采用远程 API 的方式来呈现 <https://linux.cn> 网站上的相关文章。不过，这些文章的内容其实在我们的“Linux文章”小程序内也可以访问，而且还是原生的小程序体验，所以，我们将两个小程序进行了关联。

一方面，采用云开发提供的访问另外一个云空间的方式，在“Linux”小程序内调用“Linux文章”小程序的云函数来获取相关文章（顺便做了一个重构）。

另外一方面，在“Linux”小程序的“延伸阅读”里展示的相关文章标题，点击后会跳转到“Linux文章”中对应的文章。当然，由于小程序本身的限制，在跳转前会做个确认提示，如果选“是”则跳转，如果选“否”，我们展示保留了回退模式，依然可以用 webview 方式访问远程网站上的文章，只是 webview 体验没有专门为小程序环境做过优化。

### 从“Linux文章”链接到“文章助手”

其实最初“文章助手”小程序的灵感就来自于“Linux文章”小程序，所以，一直以来在“Linux文章”中就保留着“文章助手”小程序中相关的功能，包括复制链接、显示链接信息等，甚至还有一些更多的功能。

不过，考虑到“文章助手”小程序会在链接管理方面更加深入，比如前一段时间，我们就为“文章助手”小程序添加了显示链接的更多信息的功能。而将这些功能再回迁到“Linux文章”小程序不但代码臃肿，而且需要维护两个不同模块，显然不够专业。

因此，我去除了“Linux文章”小程序中的链接管理功能，并指向到了“文章助手”小程序，这样，将来在“文章助手”小程序中可以提供更丰富的链接管理功能。此外，目前在“Linux文章”小程序中的直接访问微信链接的功能，我也会之后移植到“文章助手”小程序上。

最后，我在想，从“文章助手”小程序到“Linux”小程序是否也有关联的场景呢？目前还没有成熟的想法，或许之后会找到合适的场景吧。

### 总结

通过几天的努力，我将三个原本彼此独立的小程序彼此关联了起来。

我感觉，在小程序的功能和定位上，解耦小程序的功能有助于开发出健壮而轻快的小程序。而让小程序可以彼此配合，则可以形成小程序之间的联动和互补。虽然现在小程序之间跳转会弹出一个确认提示颇为破坏用户体验，但是这个事情也是利弊参半的。

另外一点就是，善于利用小程序的云开发环境的远程调用，可以让小程序之间更容易联动起来。


10 篇对初学者和专家都有用的 Linux 命令教程

# 10 篇对初学者和专家都有用的 Linux 命令教程

>
> 在这有关 Linux 命令的十大文章中，了解如何使 Linux 发挥所需的作用。
>
>
>

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

**很好地**使用 Linux 意味着了解有哪些命令以及它们可以为你执行的功能。

### 《在 Linux 命令行下使用“原力”》

<ruby> 原力 <rt>  force </rt></ruby>有光明的一面和黑暗的一面。正确理解这个对于真正掌握它至关重要。Alan Formy-Duval 在他的文章《[在 Linux 命令行下使用“原力”](/article-10881-1.html)》中，解释了一些流行的、有时是危险的命令的 `-f` 选项（也称为 `--force`）。

### 《Linux useradd 命令介绍》

共享帐户是一个坏主意。相反，请使用典型的 `useradd` 命令为不同的人（甚至是不同的角色）分配单独的帐户。作为其经典的 Linux 管理基础系列的一部分，Alan Formy-Duval 提供了《[Linux useradd 命令介绍](/article-11756-1.html)》，并且像往常一样，他用**朴实明白的语言**对其进行了解释，以便新老管理员都可以理解。

### 《用 Linux 命令显示硬件信息》

机器**里面**是什么？有时不使用螺丝刀检查硬件很有用。无论是你正在使用的计算机，还是在商店购买前进行测试的计算机、或者是正在尝试维修的计算机，在《[用 Linux 命令显示硬件信息](/article-11422-1.html)》中，Howard Fosdick 提供了或流行或晦涩难懂的命令，以帮助你深入了解计算机的硬件信息。

### 《如何在 Linux 上使用 gocryptfs 加密文件》

从社会保险号到个人信件再到亲人，我们的文件中包含了许多私人数据。在《[如何在 Linux 上使用 gocryptfs 加密文件](https://opensource.com/article/19/8/how-encrypt-files-gocryptfs)》中，Brian Bex Exelbierd 解释了如何保持\**隐私*的私密性。此外，他展示了一种加密文件的方式，这种方式对你现有的工作流程几乎没有影响。这不是复杂的 PGP 风格的密钥管理和后台密钥代理的难题，这是快速、无缝和安全的文件加密。

### 《如何使用 rsync 的高级用法进行大型备份》

在新的一年中，许多人会下定决心要更加努力地进行备份。Alan Formy-Duval 早在几年前就已经做出了解决方案，因为在《[如何使用 rsync 的高级用法进行大型备份](/article-10865-1.html)》中，他表现出对文件同步命令的极其熟悉。你可能不会马上记住所有语法，但其思路是读取和处理选项、构造备份命令，然后使其自动化。这是使用 `rsync` 的明智方法，也是可靠地执行备份的**唯一**方法。

### 《在 Linux 命令行使用 more 查看文本文件》

在 Scott Nesbitt 的文章《[在 Linux 命令行使用 more 查看文本文件](/article-10531-1.html)》中，古老而良好的默认分页器 `more` 引起了人们的关注。许多人安装和使用 `less`，因为它比 `more` 更灵活。但是，随着越来越多的系统在新出现的容器中实现，有时甚至不存在像 `less` 或 `most` 之类的新颖的豪华工具。了解和使用`more` 很简单，这是常见的默认设置，并且是生产系统最后的调试工具。

### 《关于 sudo 你可能不知道的》

`sudo` 命令因其过失而闻名。人们知道 `sudo` 一词，我们大多数人认为我们知道它的作用。我们的观点是正确的，但是正如 Peter Czanik 在他的文章《[关于 sudo 你可能不知道的](/article-11595-1.html)》中所揭示的那样，该命令所包含的不仅仅是“<ruby> 西蒙说的 <rt>  Simon says </rt></ruby>”（LCTT 译注：国外的一个儿童游戏）。就像这个经典的童年游戏一样，`sudo` 命令功能强大，也容易犯愚蠢的错误 —— 有更多的可能产生可怕都后果，而这是你绝不想遇上的事情！

### 《怎样用 Bash 编程：语法和工具》

如果你是 Linux、BSD 或 Mac（以及近来的 Windows）用户，你也许使用过交互式 Bash shell。它是快速的、一次性命令的绝佳 shell，这就是为什么这么多 Linux 用户喜欢将其用作主要用户界面的原因。但是，Bash 不仅仅是个命令提示符。它也是一种编程语言，如果你已经在使用 Bash 命令，那么自动化的道路从未如此简单过。在 David Both 的出色作品《[怎样用 Bash 编程：语法和工具](/article-11552-1.html)》中对其进行全面了解。

### 《精通 Linux 的 ls 命令》

`ls` 命令是那些两个字母的命令之一。单字母命令是针对慢速终端的优化，因为慢速终端的输入的每个字母都会导致明显的延迟，而这对于懒惰的打字员来说也是不错的奖励。一如既往地，Seth Kenlon 清晰实用地解释了你可以怎样《[精通 Linux 的 ls 命令](/article-11159-1.html)》。最重要的是，在“一切都是文件”的系统中，列出文件至关重要。

### 《Linux cat 命令入门》

`cat` 命令（con*cat*enate 的缩写）看似简单。无论是使用它来快速查看文件的内容还是将内容通过管道传输到另一个命令，你都可能没有充分利用 `cat` 的功能。Alan Formy-Duval 的《[Linux cat 命令入门](https://opensource.com/article/19/2/getting-started-cat-command)》提供了一些新思路，可以使你没有打开文件的感觉就可以看到文件内容。另外，了解各种有关 `zcat` 的知识，这样你就可以无需解压缩就可以得到压缩文件的内容！这是一件小而简单的事情，但是**这**是使 Linux 很棒的原因。

### 继续旅程

不要让这些关于 Linux 命令的 10 篇最佳文章成为你的旅程终点。关于 Linux 及其多才多艺的提示符，还有更多值得去发现，因此，请继续关注以获取更多知识。而且，如果你想让我们介绍一个 Linux 命令，请在评论中告诉我们。

---

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

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


共享、免费还是公有？开源软件的真正定义

# 共享、免费还是公有？开源软件的真正定义

>
> 如果你认为开源软件是共享软件、免费软件和公有领域软件的代名词，那么你并不是唯一有这种看法的人。
>
>
>

当你听到“<ruby> 开源软件 <rp>  （ </rp> <rt>  open source </rt> <rp>  ） </rp></ruby>”一词时，你是否认为它与诸如<ruby> 共享软件 <rp>  （ </rp> <rt>  shareware </rt> <rp>  ） </rp></ruby>、<ruby> 免费软件 <rp>  （ </rp> <rt>  freeware </rt> <rp>  ） </rp></ruby>或<ruby> 公有领域软件 <rp>  （ </rp> <rt>  public domain </rt> <rp>  ） </rp></ruby>之类的术语同义？ 如果是这样的话，你并不是唯一有这种看法的人。在软件行业内外的许多人都认为这些术语是一样的。本文说明了这些术语的不同之处，认为开源是一种变革性的许可和开发模式。分享我与以上几种软件打交道的经验，可能是探究差异的最佳方法。

### 共享软件和免费软件

早在 1982 年，当我在 Apple II Plus 上用 BASIC 编写代码时，我就开始从事计算机程序员的工作。我回想起去家乡当地的计算机商店，并在塑料袋中找到看起来价格高昂的装有游戏和实用程序软件的软盘。请记住，这是从一个中学生的角度来看的。

但是，有一些软件可以免费或以最低价格获得。依据具体许可模式，它被称为共享软件或免费软件。在共享软件模式下，你只能在一定时间内使用该软件，如果你发现它有用，则要求你将支票寄给该软件的作者。

但是，某些共享软件实际上也鼓励你复制并提供给你的朋友。这种模式通常称为免费软件。也就是说，共享软件和免费软件确切定义之间的差异十分微小，因此很容易将两者简单地统称为“共享软件”。我虽不能肯定，但是我不记得我是否向任何软件作者提供过使用共享软件的费用，主要是因为我在十几岁的时候就没有钱，但是我肯定喜欢使用这些软件程序，并且从中学到了很多有关计算机的知识。

回顾过去，我现在意识到，如果该软件是根据开源许可条款而非共享软件条款提供的，那么作为一名新兴的程序员，我本可以在成长中学到很多东西，并且可以取得更多成就。这是因为几乎没有共享软件会提供源代码（即，人类可读的软件形式）。共享软件还包含许可限制，禁止接收者试图泄露其源代码。如果无法访问源代码，则很难了解该软件的实际工作方式，从而很难扩展或更改其功能。这使得最终用户完全依赖共享软件原始作者进行任何更改或改进。

使用共享软件模式，任何开发人员社区几乎都不可能对代码施加影响，并进一步围绕代码进行创新。再分发和商业使用也可能受到进一步的限制。尽管共享软件可能在价格方面是免费的（至少在最初是免费的），但它在自由权利方面并不是免费的，并且不允许你通过探索代码的内部原理来学习和创新。

这就引出了一个大问题：*它与开源软件有何不同？*

### 开源许可的基础

首先，我们需要了解“开源”是指许可模式和软件开发模式，两者与共享软件都有很大不同。在一种称为非<ruby> “左版” <rp>  （ </rp> <rt>  copyleft </rt> <rp>  ） </rp></ruby>开源许可的开源形式下，向用户提供了关键的自由权利，例如对访问源代码没有限制；可以出于任何目的出售、使用或赠送该软件；可以修改软件。

这种形式的许可也不需要支付任何使用费或许可费。因为许可是高度宽松的，不需要谈判就可以使用，这种许可模式的一个惊人结果是它具有独特的能力，可以使无数软件开发人员协作起来对代码进行新的、有用的更改和创新。尽管从技术上讲，在这种许可模式下不需要提供源代码，但是几乎所有人都可以使用它来查看、学习、修改和分发给他人。

非“左版”开源许可的另一个方面是，此类软件的任何接收者都可以添加其他许可限制。这意味着以这种许可形式对代码进行许可的初始作者，无法阻止接收者可能依据限制性更强的条款不再进一步许可给其他人。例如：

>
> 假设作者 Noah 编写了一些软件，并根据非“左版”开源许可将其分发给了接收者 Aviva。然后，Aviva 修改并改进了 Noah 的软件，她有权根据非“左版”开源许可条款使用该软件。然后，Aviva 可以决定对可能限制该软件使用的任何接收者施加进一步的限制，例如在何处或如何使用它（例如，Aviva 可以增加一项限制，规定该软件只能在以下地区使用：加利福尼亚，并且不允许在任何核电厂中使用）。 即使 Aviva 可以访问源代码，也可以选择永远不将修改后的源代码发布给他人。
>
>
>

不幸的是，有无数的专有软件公司以上述方式使用非“左版”开源许可软件。实际上，共享软件程序可以通过添加共享软件类型限制（例如，无法访问源代码或排除商业用途）来使用非“左版”开源许可软件，从而将非“左版”开源许可代码转换为共享软件许可模式。

幸运的是，许多使用非“左版”开源许可软件的专有软件公司都看到了发布源代码的好处。这些组织一般通过诸如 GitHub 之类的软件存储平台向其接收者或更广泛的开源社区提供修改后的源代码，从而继续保持开源模式的持久性，实现创新的良性循环。这并不是完全出于慈善目的（或者至少通常不是这样）：这些公司希望鼓励社区创新和进一步改进，从而使他们也一并受益。

同时，许多专有软件公司不选择这样做，这也完全符合非“左版”开源许可证条款的规定。

### “左版”许可的开源软件

1989 年，一种新的被称为 GNU 通用公共许可证（也称为 GPL 许可证）的开源许可证被开发出来，其目的是确保软件“生来自由”（如同言论自由），并且能始终保持这种自由，这与非“左版”开源许可软件有时会发生的情况不同。作为版权法的独特适用，只要遵守这些规则（稍后会再介绍），GPL 许可证能够确保持续的软件自由。版权的这种独特适用称为<ruby> “左版” <rp>  （ </rp> <rt>  copyleft </rt> <rp>  ） </rp></ruby>。

与非“左版”开源软件一样，“左版”许可证允许接收者不受限制地使用该软件、检查源代码、修改软件，以及将原始或经修改的软件进一步分发给其他接收者。与非“左版”开源许可证不同，“左版”开源许可证要求所有接收者必须也具有这些相同的自由权利。除非不遵守规则，否则这些自由权利决不能被收回。

使“左版”开源许可证能够强制执行，并促使人们遵守法规的原因是版权法的适用。如果“左版”代码的接收者不遵守许可条款（例如，对软件使用添加任何其他限制或不提供源代码），则其许可将被终止，并且由于他不再享有使用该软件的法律许可，他将成为版权侵犯者。因此，该“左版”许可软件任何下游接收者的自由权利得以保障。

### 超越基础：其他软件许可模式

我在前面提到了公有领域软件，尽管它通常与开源软件混为一谈，但是这种模式有所不同。公有领域软件是指已采取步骤查看后获知没有与该软件相对应的版权存在，最常见的情况是软件版权到期或被作者放弃。（在许多国家/地区，版权保护机制尚不明确，这就是为什么某些公有领域软件可能选择开源许可模式作为备选方案的原因。）使用公有领域软件无需许可证。尽管如果源代码可获取的话，许多人会认为公有领域软件是开源软件的一种形式，但无需许可证是否让公有领域软件成为“开源软件”，是存在很多争论的主题。

有趣的是，有许多开源项目利用公有领域软件的小模块来实现某些功能。甚至还有声称整个程序属于公有领域的软件，例如实现了 SQL 数据库引擎并在许多应用程序和设备中使用的 SQLite。没有许可条款的软件也是很常见的。

许多人错误地认为这种未经许可的软件是开源软件，属于公有领域，或者不受限制地免费使用。在大多数国家（包括美国），软件的版权在其创建时就已存在。这意味着不以许可证的形式许可就不能使用它，除非它以某种方式放弃版权，并将其放置在公有领域。此通用规则存在一些例外情况，例如法律层面的默示许可或合理使用。但是在如何将它们应用于特定状况方面，情况非常复杂。在意图让其遵守开源许可条款的情况下，我不建议提供没有许可条款的软件，因为这会导致混乱和潜在的滥用。

### 开源软件的好处

就像我之前说的那样，开源是高效的软件开发模式，并具有推动创新的巨大能力。但这到底意味着什么？

开源许可模式的好处之一是大大减少了创新方面的摩擦，尤其是原始作者以外的其他用户所进行的创新。这种摩擦是有限的，因为使用开源软件通常不需要协商许可条款，从而大大简化并降低了使用成本。反过来，这创建了一种开源生态系统，它鼓励快速修改和组合现有技术以形成新的事物。这些修改通常能回馈到开源生态系统中，从而构造了一个创新循环。

驱动大量事物（从你的烤面包机到火星飞行器）运转的无数种软件，正是这种轻松地将各种程序组合在一起的能力的直接结果——开源开发模式让所有这些软件得以成为现实。

---

作者简介：Jeffrey R. Kaufman 是全球领先的开源软件解决方案供应商<ruby> 红帽公司 <rp>  （ </rp> <rt>  Red Hat </rt> <rp>  ） </rp></ruby>开源法务团队的资深商务法律顾问，还担任<ruby> 北卡罗来纳大学 <rp>  （ </rp> <rt>  University of North Carolina </rt> <rp>  ） </rp></ruby>的兼职法律教授。在任职红帽公司之前，Jeffrey曾担任<ruby> 高通公司 <rp>  （ </rp> <rt>  Qualcomm </rt> <rp>  ） </rp></ruby>的专利和开源法律顾问。

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