在 GitLab CI 中使用 Docker 构建 Go 项目

![](/data/attachment/album/201805/10/115107wk2k2tmtvm1xkvt1.jpg)

### 介绍

这篇文章是我在 CI 环境（特别是在 Gitlab 中）的 Docker 容器中构建 Go 项目的研究总结。我发现很难解决私有依赖问题（来自 Node/.NET 背景），因此这是我写这篇文章的主要原因。如果 Docker 镜像上存在任何问题或提交请求，请随时与我们联系。

### dep

由于 dep 是现在管理 Go 依赖关系的最佳选择，因此在构建前之前运行 `dep ensure`。

注意：我个人不会将我的 `vendor/` 文件夹提交到源码控制，如果你这样做，我不确定这个步骤是否可以跳过。

使用 Docker 构建的最好方法是使用 `dep ensure -vendor-only`。 [见这里](https://github.com/golang/dep/blob/master/docs/FAQ.md#how-do-i-use-dep-with-docker)。

### Docker 构建镜像

我第一次尝试使用 `golang:1.10`，但这个镜像没有：

* curl
* git
* make
* dep
* golint

我已经创建好了用于构建的镜像（[github](https://github.com/sjdweb/go-docker-build/blob/master/Dockerfile) / [dockerhub](https://hub.docker.com/r/sjdweb/go-docker-build/)），我会保持更新，但我不提供任何担保，因此你应该创建并管理自己的 Dockerhub。

### 内部依赖关系

我们完全有能力创建一个有公共依赖关系的项目。但是如果你的项目依赖于另一个私人 Gitlab 仓库呢？

在本地运行 `dep ensure` 应该可以和你的 git 设置一起工作，但是一旦在 CI 上不适用，构建就会失败。

#### Gitlab 权限模型

这是在 [Gitlab 8.12 中添加的](https://docs.gitlab.com/ce/user/project/new_ci_build_permissions_model.html)，这个我们最关心的有用的功能是在构建期提供的 `CI_JOB_TOKEN` 环境变量。

这基本上意味着我们可以像这样克隆[依赖仓库](https://docs.gitlab.com/ce/user/project/new_ci_build_permissions_model.html#dependent-repositories)：

```
git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/myuser/mydependentrepo

```

然而，我们希望使这更友好一点，因为 `dep` 在试图拉取代码时不会奇迹般地添加凭据。

我们将把这一行添加到 `.gitlab-ci.yml` 的 `before_script` 部分。

```
before_script:
  - echo -e "machine gitlab.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc

```

使用 `.netrc` 文件可以指定哪个凭证用于哪个服务器。这种方法可以避免每次从 Git 中拉取（或推送）时输入用户名和密码。密码以明文形式存储，因此你不应在自己的计算机上执行此操作。这实际用于 Git 在背后使用 `cURL`。 [在这里阅读更多](https://github.com/bagder/everything-curl/blob/master/usingcurl-netrc.md)。

### 项目文件

#### Makefile

虽然这是可选的，但我发现它使事情变得更容易。

配置这些步骤意味着在 CI 脚本（和本地）中，我们可以运行 `make lint`、`make build` 等，而无需每次重复步骤。

```
GOFILES = $(shell find . -name '*.go' -not -path './vendor/*')
GOPACKAGES = $(shell go list ./...  | grep -v /vendor/)

default: build

workdir:
    mkdir -p workdir

build: workdir/scraper

workdir/scraper: $(GOFILES)
    GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o workdir/scraper .

test: test-all

test-all:
    @go test -v $(GOPACKAGES)

lint: lint-all

lint-all:
    @golint -set_exit_status $(GOPACKAGES)

```

#### .gitlab-ci.yml

这是 Gitlab CI 魔术发生的地方。你可能想使用自己的镜像。

```
image: sjdweb/go-docker-build:1.10

stages:
  - test
  - build

before_script:
  - cd $GOPATH/src
  - mkdir -p gitlab.com/$CI_PROJECT_NAMESPACE
  - cd gitlab.com/$CI_PROJECT_NAMESPACE
  - ln -s $CI_PROJECT_DIR
  - cd $CI_PROJECT_NAME
  - echo -e "machine gitlab.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > ~/.netrc
  - dep ensure -vendor-only

lint_code:
  stage: test
  script:
    - make lint

unit_tests:
  stage: test
  script:
    - make test

build:
  stage: build
  script:
    - make

```

### 缺少了什么

我通常会用我的二进制文件构建 Docker 镜像，并将其推送到 Gitlab 容器注册库中。

你可以看到我正在构建二进制文件并退出，你至少需要将该二进制文件（例如生成文件）存储在某处。

---

via: <https://seandrumm.co.uk/blog/building-go-projects-with-docker-on-gitlab-ci/>

作者：[SEAN DRUMM](https://seandrumm.co.uk/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


Red Hat 的去 Docker 化容器实践

![](/data/attachment/album/201805/10/122423nn342z26ornon21o.jpg)

最近几年，开源项目 Docker (已更名为[Moby](https://mobyproject.org/)) 在容器普及化方面建树颇多。然而，它的功能特性不断集中到一个单一、庞大的系统，该系统由具有 root 权限运行的守护进程 `dockerd` 管控，这引发了人们的焦虑。对这些焦虑的阐述，具有代表性的是 Red Hat 公司的容器团队负责人 Dan Walsh 在 [KubeCon + CloudNativecon](http://events.linuxfoundation.org/events/kubecon-and-cloudnativecon-north-america) 会议中的[演讲](https://kccncna17.sched.com/event/CU8j/cri-o-hosted-by-daniel-walsh-red-hat)。Walsh 讲述了他的容器团队目前的工作方向，即使用一系列更小、可协同工作的组件替代 Docker。他的战斗口号是“拒绝臃肿的守护进程”，理由是与公认的 Unix 哲学相违背。

### Docker 模块化实践

就像我们在[早期文献](https://lwn.net/Articles/741897/)中看到的那样，容器的基础操作不复杂：你首先拉取一个容器镜像，利用该镜像创建一个容器，最后启动这个容器。除此之外，你要懂得如何构建镜像并推送至镜像仓库。大多数人在上述这些步骤中使用 Docker，但其实 Docker 并不是唯一的选择，目前的可替换选择是 `rkt`。rkt 引发了一系列标准的创建，包括运行时标准 CRI，镜像标准 OCI 及网络标准 CNI 等。遵守这些标准的后端，如 [CRI-O](http://cri-o.io/) 和 Docker，可以与 [Kubernetes](https://kubernetes.io/) 为代表的管理软件协同工作。

这些标准促使 Red Hat 公司开发了一系列实现了部分标准的“核心应用”供 Kubernetes 使用，例如 CRI-O 运行时。但 Kubernetes 提供的功能不足以满足 Red Hat 公司的 [OpenShift](https://www.openshift.com/) 项目所需。开发者可能需要构建容器并推送至镜像仓库，实现这些操作需要额外的一整套方案。

事实上，目前市面上已有多种构建容器的工具。来自 Sysdig 公司的 Michael Ducy 在[分会场](https://kccncna17.sched.com/event/CU6B/building-better-containers-a-survey-of-container-build-tools-i-michael-ducy-chef)中回顾了 Docker 本身之外的 8 种镜像构建工具，而这也很可能不是全部。Ducy 将理想的构建工具定义如下：可以用可重现的方式创建最小化镜像。最小化镜像并不包含操作系统，只包含应用本身及其依赖。Ducy 认为 [Distroless](https://github.com/GoogleCloudPlatform/distroless), [Smith](https://github.com/oracle/smith) 及 [Source-to-Image](https://github.com/openshift/source-to-image) 都是很好的工具，可用于构建最小化镜像。Ducy 将最小化镜像称为“微容器”。

<ruby> 可重现镜像 <rt>  reproducible container </rt></ruby>是指构建多次结果保持不变的镜像。为达到这个目标，Ducy 表示应该使用“宣告式”而不是“命令式”的方式。考虑到 Ducy 来自 Chef 配置管理工具领域，你应该能理解他的意思。Ducy 给出了符合标准的几个不错的实现，包括 [Ansible 容器](https://www.ansible.com/ansible-container)、 [Habitat](https://www.habitat.sh/)、 [nixos-容器](https://nixos.org/nixos/manual/#ch-containers)和 [Simth](https://github.com/oracle/smith) 等，但你需要了解这些项目对应的编程语言。Ducy 额外指出 Habitat 构建的容器自带管理功能，如果你已经使用了 systemd、 Docker 或 Kubernetes 等外部管理工具，Habitat 的管理功能可能是冗余的。除此之外，我们还要提到从 Docker 和 [Buildah](https://github.com/projectatomic/buildah) 项目诞生的新项目 [BuildKit](https://github.com/moby/buildkit)， 它是 Red Hat 公司 [Atomic 工程](https://www.projectatomic.io/)的一个组件。

### 使用 Buildah 构建容器

![\[Buildah logo\]](/data/attachment/album/201805/10/122437qhminlii9nhbwbbw.png "Buildah logo")

Buildah 名称显然来自于 Walsh 风趣的 [波士顿口音](https://en.wikipedia.org/wiki/Boston_accent)； 该工具的品牌宣传中充满了波士顿风格，例如 logo 使用了波士顿梗犬（如图所示）。该项目的实现思路与 Ducy 不同：为了构建容器，与其被迫使用宣告式配置管理的方案，不如构建一些简单工具，结合你最喜欢的配置管理工具使用。这样你可以如愿的使用命令行，例如使用 `cp` 命令代替 Docker 的自定义指令 `COPY` 。除此之外，你可以使用如下工具为容器提供内容：1) 配置管理工具，例如Ansible 或 Puppet；2) 操作系统相关或编程语言相关的安装工具，例如 APT 和 pip； 3) 其它系统。下面展示了基于通用 shell 命令的容器构建场景，其中只需要使用 `make` 命令即可为容器安装可执行文件。

```
# 拉取基础镜像, 类似 Dockerfile 中的 FROM 命令
buildah from redhat

# 挂载基础镜像, 在其基础上工作
crt=$(buildah mount)
ap foo $crt
make install DESTDIR=$crt

# 下一步，生成快照
buildah commit

```

有趣的是，基于这个思路，你可以复用主机环境中的构建工具，无需在镜像中安装这些依赖，故可以构建非常微小的镜像。通常情况下，构建容器镜像时需要在容器中安装目标应用的构建依赖。例如，从源码构建需要容器中有编译器工具链，这是因为构建并不在主机环境进行。大量的容器也包含了 `ps` 和 `bash` 这样的 Unix 命令，对微容器而言其实是多余的。开发者经常忘记或无法从构建好的容器中移除一些依赖，增加了不必要的开销和攻击面。

Buildah 的模块化方案能够以非 root 方式进行部分构建；但`mount` 命令仍然需要 `CAP_SYS_ADMIN`，有一个 [工单](https://github.com/projectatomic/buildah/issues/171) 试图解决该问题。但 Buildah 与 Docker [都有](https://github.com/projectatomic/buildah/issues/158)同样的[限制](https://github.com/moby/moby/issues/27886#issuecomment-281278525)，即无法在容器内构建容器。对于 Docker，你需要使用“特权”模式运行容器，一些特殊的环境很难满足这个条件，例如 [GitLab 持续集成](https://about.gitlab.com/features/gitlab-ci-cd/)；即使满足该条件，配置也特别[繁琐](https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/)。

手动提交的步骤可以对创建容器快照的时间节点进行细粒度控制。Dockerfile 每一行都会创建一个新的快照；相比而言，Buildah 的提交检查点都是事先选择好的，这可以减少不必要的快照并节省磁盘空间。这也有利于隔离私钥或密码等敏感信息，避免其出现在公共镜像中。

Docker 构建的镜像是非标准的、仅供其自身使用；相比而言，Buildah 提供[多种输出格式](https://github.com/projectatomic/buildah/blob/master/docs/buildah-push.md)，其中包括符合 OCI 标准的镜像。为向后兼容，Buildah 提供了一个“使用 Dockerfile 构建”的命令，即 [`buildah bud`](https://github.com/projectatomic/buildah/blob/master/docs/buildah-bud.md)， 它可以解析标准的 Dockerfile。Buildah 提供 `enter` 命令直接查看镜像内部信息，`run` 命令启动一个容器。实现这些功能仅使用了 `runc` 在内的标准工具，无需在后台运行一个“臃肿的守护进程”。

Ducy 对 Buildah 表示质疑，认为采用非宣告性不利于可重现性。如果允许使用 shell 命令，可能产生很多预想不到的情况；例如，一个 shell 脚本下载了任意的可执行程序，但后续无法追溯文件的来源。shell 命令的执行受环境变量影响，执行结果可能大相径庭。与基于 shell 的工具相比，Puppet 或 Chef 这样的配置管理系统在理论上更加可靠，因为它们的设计初衷就是收敛于最终配置；事实上，可以通过配置管理系统调用 shell 命令。但 Walsh 对此提出反驳，认为已有的配置管理工具可以在 Buildah 的基础上工作，用户可以选择是否使用配置管理；这样更加符合“机制与策略分离”的经典 Unix 哲学。

目前 Buildah 处于测试阶段，Red Hat 公司正努力将其集成到 OpenShift。我写这篇文章时已经测试过 Buildah，它缺少一些文档，但基本可以稳定运行。尽管在错误处理方面仍有待提高，但它确实是一款值得你关注的容器工具。

### 替换其它 Docker 命令行

Walsh 在其演讲中还简单介绍了 Red hat 公司 正在开发的另一个暂时叫做 [libpod](https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/) 的项目。项目名称来源于 Kubernetes 中的 “pod”， 在 Kubernetes 中 “pod” 用于分组主机内的容器，分享名字空间等。

Libpod 提供 `kpod` 命令，用于直接检查和操作容器存储。Walsh 分析了该命令发挥作用的场景，例如 `dockerd` 停止响应或 Kubernetes 集群崩溃。基本上，`kpod` 独立地再次实现了 `docker` 命令行工具。`kpod ps` 返回运行中的容器列表，`kpod images` 返回镜像列表。事实上，[命令转换速查手册](https://github.com/projectatomic/libpod/blob/master/transfer.md#development-transfer) 中给出了每一条 Docker 命令对应的 `kpod` 命令。

这种模块化实现的一个好处是，当你使用 `kpod run` 运行容器时，容器直接作为当前 shell 而不是 `dockerd` 的子进程启动。理论上，可以直接使用 systemd 启动容器，这样可以消除 `dockerd` 引入的冗余。这让[由套接字激活的容器](http://0pointer.de/blog/projects/socket-activated-containers.html)成为可能，但暂时基于 Docker 实现该特性[并不容易](https://legacy-developer.atlassian.com/blog/2015/03/docker-systemd-socket-activation/)，[即使借助 Kubernetes](https://github.com/kubernetes/kubernetes/issues/484) 也是如此。但我在测试过程中发现，使用 `kpod` 启动的容器有一些基础功能性缺失，具体而言是网络功能（!），相关实现在[活跃开发](https://github.com/projectatomic/libpod/issues/129)过程中。

我们最后提到的命令是 `push`。虽然上述命令已经足以满足本地使用容器的需求，但没有提到远程仓库，借助远程仓库开发者可以活跃地进行应用打包协作。仓库也是持续部署框架的核心组件。[skopeo](https://github.com/projectatomic/skopeo) 项目用于填补这个空白，它是另一个 Atomic 成员项目，按其 `README` 文件描述，“包含容器镜像及镜像库的多种操作”。该项目的设计初衷是，在不用类似 `docker pull` 那样实际去下载可能体积庞大的镜像的前提下，检查容器镜像的内容。Docker [拒绝加入](https://github.com/moby/moby/pull/14258) 检查功能，建议通过一个额外的工具实现该功能，这促成了 Skopeo 项目。除了 `pull`、`push`，Skopeo 现在还可以完成很多其它操作，例如在，不产生本地副本的情况下将镜像在不同的仓库中复制和转换。由于部分功能比较基础，可供其它项目使用，目前很大一部分 Skopeo 代码位于一个叫做 [containers/image](https://github.com/containers/image) 的基础库。[Pivotal](https://pivotal.io/)、 Google 的 [container-diff](https://github.com/GoogleCloudPlatform/container-diff) 、`kpod push` 及 `buildah push` 都使用了该库。

`kpod` 与 Kubernetes 并没有紧密的联系，故未来可能会更换名称（事实上，在本文刊发过程中，已经更名为 [`podman`](https://github.com/projectatomic/libpod/blob/master/docs/podman.1.md)），毕竟 Red Hat 法务部门还没有明确其名称。该团队希望实现更多 pod 级别的命令，这样可以对多个容器进行操作，有点类似于 [`docker compose`](https://docs.docker.com/compose/overview/#compose-documentation) 实现的功能。但在这方面，[Kompose](http://kompose.io/) 是更好的工具，可以通过 [复合 YAML 文件](https://docs.docker.com/compose/compose-file/) 在 Kubernetes 集群中运行容器。按计划，我们不会实现类似于 [`swarm`] 的 Docker 命令，这部分功能最好由 Kubernetes 本身完成。

目前看来，已经持续数年的 Docker 模块化努力终将硕果累累。但目前 `kpod` 处于快速迭代过程中，不太适合用于生产环境，不过那些工具的与众不同的设计理念让人很感兴趣，而且其中大部分的工具已经可以用于开发环境。目前只能通过编译源码的方式安装 libpod，但最终会提供各个发行版的二进制包。

>
> 本文[最初发表](https://lwn.net/Articles/741841/)于 [Linux Weekly News](http://lwn.net/)。
>
>
>

---

via: <https://anarc.at/blog/2017-12-20-docker-without-docker/>

作者：[Anarcat](https://anarc.at) 译者：[pinewall](https://github.com/pinewall) 校对：[wxy](https://github.com/wxy)

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


在 Ubuntu 和 Linux Mint 中轻松安装 Android Studio

Summary: Android Studio 可以通过源代码安装，但在这篇文章中，我们将看到如何在 Ubuntu 18.04、16.04 和相应的 Linux Mint 变体中安装 Android Studio。

[Android Studio](http://developer.android.com/sdk/installing/studio.html) 是谷歌自己的 Android 开发 IDE，是带 ADT 插件的 Eclipse 的不错替代品。Android Studio 可以通过源代码安装，但在这篇文章中，我们将看到**如何在 Ubuntu 18.04、16.04 和相应的 Linux Mint 变体**中安装 Android Studio。

在继续安装 Android Studio 之前，请确保你已经[在 Ubuntu 中安装了 Java](https://itsfoss.com/install-java-ubuntu-1404/)。

![How to install Android Studio in Ubuntu](/data/attachment/album/201805/10/224829sscqqgz4q4m2scf2.jpg)

### 使用 Snap 在 Ubuntu 和其他发行版中安装 Android Studio

自从 Ubuntu 开始专注于 Snap 软件包以来，越来越多的软件开始提供易于安装的 Snap 软件包。Android Studio 就是其中之一。Ubuntu 用户可以直接在软件中心找到 Android Studio 程序并从那里安装。

![Install Android Studio in Ubuntu from Software Center](/data/attachment/album/201805/10/224830t48s84415w8zlz4s.jpg)

如果你在软件中心安装 Android Studio 时看到错误，则可以使用 [Snap 命令](https://itsfoss.com/install-snap-linux/) 安装 Android Studio。

```
sudo snap install android-studio --classic

```

非常简单！

### 另一种方式 1：在 Ubuntu 中使用 umake 安装 Android Studio

你也可以使用 Ubuntu Developer Tools Center，现在称为 [Ubuntu Make](https://wiki.ubuntu.com/ubuntu-make)，轻松安装 Android Studio。Ubuntu Make 提供了一个命令行工具来安装各种开发工具和 IDE 等。Ubuntu Make 在 Ubuntu 仓库中就有。

要安装 Ubuntu Make，请在终端中使用以下命令：

```
sudo apt-get install ubuntu-make

```

安装 Ubuntu Make 后，请使用以下命令在 Ubuntu 中安装 Android Studio：

```
umake android

```

在安装过程中它会给你的几个选项。我认为你可以处理。如果你决定卸载 Android Studio，则可以按照以下方式使用相同的 umake 工具：

```
umake android --remove

```

### 另一种方式 2：通过非官方的 PPA 在 Ubuntu 和 Linux Mint 中安装 Android Studio

感谢 [Paolo Ratolo](https://plus.google.com/+PaoloRotolo)，我们有一个 PPA，可用于 Ubuntu 16.04、14.04、Linux Mint 和其他基于 Ubuntu 的发行版中轻松安装 Android Studio。请注意，它将下载大约 650MB 的数据。请注意你的互联网连接以及数据费用（如果有的话）。

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

```
sudo apt-add-repository ppa:paolorotolo/android-studio
sudo apt-get update
sudo apt-get install android-studio

```

这不容易吗？虽然从源代码安装程序很有趣，但拥有这样的 PPA 总是不错的。我们看到了如何安装 Android Studio，现在来看看如何卸载它。

### 卸载 Android Studio：

如果你还没有安装 PPA Purge：

```
sudo apt-get install ppa-purge

```

现在使用 PPA Purge 来清除已安装的 PPA：

```
sudo apt-get remove android-studio
sudo ppa-purge ppa:paolorotolo/android-studio

```

就是这些了。我希望这能够帮助你**在 Ubuntu 和 Linux Mint 上安装 Android Studio**。在运行 Android Studio 之前，请确保[在 Ubuntu 中安装了Java](https://itsfoss.com/install-java-ubuntu-1404/ "How To Install Java On Ubuntu 14.04")。在类似的文章中，我建议你阅读[如何安装和配置 Ubuntu SDK](https://itsfoss.com/install-configure-ubuntu-sdk/) 和[如何在 Ubuntu 中轻松安装 Microsoft Visual Studio](https://itsfoss.com/install-visual-studio-code-ubuntu/)。

欢迎提出任何问题或建议。再见 ：）

---

via: <https://itsfoss.com/install-android-studio-ubuntu-linux/>

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

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


系统调用，让世界转起来！

Summary: 我其实不想将它分解开给你看，用户应用程序其实就是一个可怜的瓮中大脑。

我其实不想将它分解开给你看，用户应用程序其实就是一个可怜的瓮中大脑。


如何使用 Vim 编辑器编辑多个文件

Summary: 在本教程中，我们将学习使用 vim 编辑器同时编辑多个文件。相信我，很有意思哒。

![](/data/attachment/album/201805/11/092242ho3kzb83ykq3oeo3.png)

有时候，您可能需要修改多个文件，或要将一个文件的内容复制到另一个文件中。在图形用户界面中，您可以在任何图形文本编辑器（如 gedit）中打开文件，并使用 `CTRL + C` 和 `CTRL + V` 复制和粘贴内容。在命令行模式下，您不能使用这种编辑器。不过别担心，只要有 `vim` 编辑器就有办法。在本教程中，我们将学习使用 `vim` 编辑器同时编辑多个文件。相信我，很有意思哒。

### 安装 Vim

Vim 编辑器可在大多数 Linux 发行版的官方软件仓库中找到，所以您可以用默认的软件包管理器来安装它。例如，在 Arch Linux 及其变体上，您可以使用如下命令：

```
$ sudo pacman -S vim

```

在 Debian 和 Ubuntu 上：

```
$ sudo apt-get install vim

```

在 RHEL 和 CentOS 上：

```
$ sudo yum install vim

```

在 Fedora 上：

```
$ sudo dnf install vim

```

在 openSUSE 上：

```
$ sudo zypper install vim

```

### 使用 Linux 的 Vim 编辑器同时编辑多个文件

现在让我们谈谈正事，我们可以用两种方法做到这一点。

#### 方法一

有两个文件，即 `file1.txt` 和 `file2.txt`，带有一堆随机单词：

```
$ cat file1.txt
ostechnix
open source
technology
linux
unix

$ cat file2.txt
line1
line2
line3
line4
line5

```

现在，让我们同时编辑这两个文件。请运行：

```
$ vim file1.txt file2.txt

```

Vim 将按顺序显示文件的内容。首先显示第一个文件的内容，然后显示第二个文件，依此类推。

![](/data/attachment/album/201805/11/092244tzblsjnulu7444fs.png)

##### 在文件中切换

要移至下一个文件，请键入：

```
:n

```

![](/data/attachment/album/201805/11/092246efi8tflg33mi893e.png)

要返回到前一个文件，请键入：

```
:N

```

如果有任何未保存的更改，Vim 将不允许您移动到下一个文件。要保存当前文件中的更改，请键入：

```
ZZ

```

请注意，是两个大写字母 `ZZ`（`SHIFT + zz`）。

要放弃更改并移至上一个文件，请键入：

```
:N!

```

要查看当前正在编辑的文件，请键入：

```
:buffers

```

![](/data/attachment/album/201805/11/092247imzyu77li7q7a76z.png)

您将在底部看到加载文件的列表。

![](/data/attachment/album/201805/11/092249ebzvit9jlih2li9l.png)

要切换到下一个文件，请输入 `:buffer`，后跟缓冲区编号。例如，要切换到第一个文件，请键入：

```
:buffer 1

```

![](/data/attachment/album/201805/11/092250i7iyhalgqwil7gam.png)

##### 打开其他文件进行编辑

目前我们正在编辑两个文件，即 `file1.txt` 和 `file2.txt`。我想打开另一个名为 `file3.txt` 的文件进行编辑。

您会怎么做？这很容易。只需键入 `:e`，然后输入如下所示的文件名即可：

```
:e file3.txt

```

![](/data/attachment/album/201805/11/092252arlvqvyjll1ryhil.png)

现在你可以编辑 `file3.txt` 了。

要查看当前正在编辑的文件数量，请键入：

```
:buffers

```

![](/data/attachment/album/201805/11/092254wkm2sbh1mpq1uhm4.png)

请注意，对于使用 `:e` 打开的文件，您无法使用 `:n` 或 `:N` 进行切换。要切换到另一个文件，请输入 `:buffer`，然后输入文件缓冲区编号。

##### 将一个文件的内容复制到另一个文件中

您已经知道了如何同时打开和编辑多个文件。有时，您可能想要将一个文件的内容复制到另一个文件中。这也是可以做到的。切换到您选择的文件，例如，假设您想将 `file1.txt` 的内容复制到 `file2.txt` 中：

首先，请切换到 `file1.txt`：

```
:buffer 1

```

将光标移动至在想要复制的行的前面，并键入`yy` 以抽出（复制）该行。然后，移至 `file2.txt`：

```
:buffer 2

```

将光标移至要从 `file1.txt` 粘贴复制行的位置，然后键入 `p`。例如，您想要将复制的行粘贴到 `line2` 和 `line3` 之间，请将鼠标光标置于行前并键入 `p`。

输出示例：

```
line1
line2
ostechnix
line3
line4
line5

```

![](/data/attachment/album/201805/11/092255yfqfybbwjggzhfwb.png)

要保存当前文件中所做的更改，请键入：

```
ZZ

```

再次提醒，是两个大写字母 ZZ（`SHIFT + z`）。

保存所有文件的更改并退出 vim 编辑器，键入：

```
:wq

```

同样，您可以将任何文件的任何行复制到其他文件中。

##### 将整个文件内容复制到另一个文件中

我们知道如何复制一行，那么整个文件的内容呢？也是可以的。比如说，您要将 `file1.txt` 的全部内容复制到 `file2.txt` 中。

先打开 `file2.txt`：

```
$ vim file2.txt

```

如果文件已经加载，您可以通过输入以下命令切换到 `file2.txt`：

```
:buffer 2

```

将光标移动到您想要粘贴 `file1.txt` 的内容的位置。我想在 `file2.txt` 的第 5 行之后粘贴 `file1.txt` 的内容，所以我将光标移动到第 5 行。然后，键入以下命令并按回车键：

```
:r file1.txt

```

![](/data/attachment/album/201805/11/092257fcb3msdzfud4uejj.png)

这里，`r` 代表 “read”。

现在您会看到 `file1.txt` 的内容被粘贴在 `file2.txt` 的第 5 行之后。

```
line1
line2
line3
line4
line5
ostechnix
open source
technology
linux
unix

```

![](/data/attachment/album/201805/11/092258eryma12zwereogg2.png)

要保存当前文件中的更改，请键入：

```
ZZ

```

要保存所有文件的所有更改并退出 vim 编辑器，请输入：

```
:wq

```

#### 方法二

另一种同时打开多个文件的方法是使用 `-o` 或 `-O` 标志。

要在水平窗口中打开多个文件，请运行：

```
$ vim -o file1.txt file2.txt

```

![](/data/attachment/album/201805/11/092300a4mvdkifffhs7vr4.png)

要在窗口之间切换，请按 `CTRL-w w`（即按 `CTRL + w` 并再次按 `w`）。或者，您可以使用以下快捷方式在窗口之间移动：

* `CTRL-w k` – 上面的窗口
* `CTRL-w j` – 下面的窗口

要在垂直窗口中打开多个文件，请运行：

```
$ vim -O file1.txt file2.txt file3.txt

```

![](/data/attachment/album/201805/11/092302e4onkfgodnf9gzfk.png)

要在窗口之间切换，请按 `CTRL-w w`（即按 `CTRL + w` 并再次按 `w`）。或者，使用以下快捷方式在窗口之间移动：

* `CTRL-w l` – 左面的窗口
* `CTRL-w h` – 右面的窗口

其他的一切都与方法一的描述相同。

例如，要列出当前加载的文件，请运行：

```
:buffers

```

在文件之间切换：

```
:buffer 1

```

打开其他文件，请键入：

```
:e file3.txt

```

将文件的全部内容复制到另一个文件中：

```
:r file1.txt

```

方法二的唯一区别是，只要您使用 `ZZ` 保存对当前文件的更改，文件将自动关闭。然后，您需要依次键入 `:wq` 来关闭文件。但是，如果您按照方法一进行操作，输入 `:wq` 时，所有更改将保存在所有文件中，并且所有文件将立即关闭。

有关更多详细信息，请参阅手册页。

```
$ man vim

```

### 建议阅读

您现在掌握了如何在 Linux 中使用 vim 编辑器编辑多个文件。正如您所见，编辑多个文件并不难。Vim 编辑器还有更强大的功能。我们接下来会提供更多关于 Vim 编辑器的内容。

再见！

---

via: <https://www.ostechnix.com/how-to-edit-multiple-files-using-vim-editor/>

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

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


关于 BPF 和 eBPF 的笔记

![](/data/attachment/album/201805/12/083555mztunjjnnrbjjlw4.jpg)

今天，我喜欢的 meetup 网站上有一篇我超爱的文章！[Suchakra Sharma](http://suchakra.in/)（[@tuxology](https://twitter.com/tuxology) 在 twitter/github）的一篇非常棒的关于传统 BPF 和在 Linux 中最新加入的 eBPF 的讨论文章，正是它促使我想去写一个 eBPF 的程序！

这篇文章就是 —— [BSD 包过滤器：一个新的用户级包捕获架构](http://www.vodun.org/papers/net-papers/van_jacobson_the_bpf_packet_filter.pdf)

我想在讨论的基础上去写一些笔记，因为，我觉得它超级棒！

开始前，这里有个 [幻灯片](https://speakerdeck.com/tuxology/the-bsd-packet-filter) 和一个 [pdf](http://step.polymtl.ca/%7Esuchakra/PWL-Jun28-MTL.pdf)。这个 pdf 非常好，结束的位置有一些链接，在 PDF 中你可以直接点击这个链接。

### 什么是 BPF？

在 BPF 出现之前，如果你想去做包过滤，你必须拷贝所有的包到用户空间，然后才能去过滤它们（使用 “tap”）。

这样做存在两个问题：

1. 如果你在用户空间中过滤，意味着你将拷贝所有的包到用户空间，拷贝数据的代价是很昂贵的。
2. 使用的过滤算法很低效。

问题 #1 的解决方法似乎很明显，就是将过滤逻辑移到内核中。（虽然具体实现的细节并没有明确，我们将在稍后讨论）

但是，为什么过滤算法会很低效？

如果你运行 `tcpdump host foo`，它实际上运行了一个相当复杂的查询，用下图的这个树来描述它：

![](/data/attachment/album/201805/12/083612y4v2r8vbfcjvr1vo.png)

评估这个树有点复杂。因此，可以用一种更简单的方式来表示这个树，像这样：

![](/data/attachment/album/201805/12/083613px2ddm0nxrrmn2nm.png)

然后，如果你设置 `ether.type = IP` 和 `ip.src = foo`，你必然明白匹配的包是 `host foo`，你也不用去检查任何其它的东西了。因此，这个数据结构（它们称为“控制流图” ，或者 “CFG”）是表示你真实希望去执行匹配检查的程序的最佳方法，而不是用前面的树。

### 为什么 BPF 要工作在内核中

这里的关键点是，包仅仅是个字节的数组。BPF 程序是运行在这些字节的数组之上。它们不允许有循环（loop），但是，它们 *可以* 有聪明的办法知道 IP 包头（IPv6 和 IPv4 长度是不同的）以及基于它们的长度来找到 TCP 端口：

```
x = ip_header_length
port = *(packet_start + x + port_offset)

```

（看起来不一样，其实它们基本上都相同）。在这个论文/幻灯片上有一个非常详细的虚拟机的描述，因此，我不打算解释它。

当你运行 `tcpdump host foo` 后，这时发生了什么？就我的理解，应该是如下的过程。

1. 转换 `host foo` 为一个高效的 DAG 规则
2. 转换那个 DAG 规则为 BPF 虚拟机的一个 BPF 程序（BPF 字节码）
3. 发送 BPF 字节码到 Linux 内核，由 Linux 内核验证它
4. 编译这个 BPF 字节码程序为一个<ruby> 原生 <rt>  native </rt></ruby>代码。例如，这是个[ARM 上的 JIT 代码](https://github.com/torvalds/linux/blob/v4.10/arch/arm/net/bpf_jit_32.c#L512) 以及 [x86](https://github.com/torvalds/linux/blob/v3.18/arch/x86/net/bpf_jit_comp.c#L189) 的机器码
5. 当包进入时，Linux 运行原生代码去决定是否过滤这个包。对于每个需要去处理的包，它通常仅需运行 100 - 200 个 CPU 指令就可以完成，这个速度是非常快的！

### 现状：eBPF

毕竟 BPF 出现已经有很长的时间了！现在，我们可以拥有一个更加令人激动的东西，它就是 eBPF。我以前听说过 eBPF，但是，我觉得像这样把这些片断拼在一起更好（我在 4 月份的 netdev 上我写了这篇 [XDP & eBPF 的文章](https://jvns.ca/blog/2017/04/07/xdp-bpf-tutorial/)回复）

关于 eBPF 的一些事实是：

* eBPF 程序有它们自己的字节码语言，并且从那个字节码语言编译成内核原生代码，就像 BPF 程序一样
* eBPF 运行在内核中
* eBPF 程序不能随心所欲的访问内核内存。而是通过内核提供的函数去取得一些受严格限制的所需要的内容的子集
* 它们 *可以* 与用户空间的程序通过 BPF 映射进行通讯
* 这是 Linux 3.18 的 `bpf` 系统调用

### kprobes 和 eBPF

你可以在 Linux 内核中挑选一个函数（任意函数），然后运行一个你写的每次该函数被调用时都运行的程序。这样看起来是不是很神奇。

例如：这里有一个 [名为 disksnoop 的 BPF 程序](https://github.com/iovisor/bcc/blob/0c8c179fc1283600887efa46fe428022efc4151b/examples/tracing/disksnoop.py)，它的功能是当你开始/完成写入一个块到磁盘时，触发它执行跟踪。下图是它的代码片断：

```
BPF_HASH(start, struct request *);
void trace_start(struct pt_regs *ctx, struct request *req) {
    // stash start timestamp by request ptr
    u64 ts = bpf_ktime_get_ns();
    start.update(&req, &ts);
}
...
b.attach_kprobe(event="blk_start_request", fn_name="trace_start")
b.attach_kprobe(event="blk_mq_start_request", fn_name="trace_start")

```

本质上它声明一个 BPF 哈希（它的作用是当请求开始/完成时，这个程序去触发跟踪），一个名为 `trace_start` 的函数将被编译进 BPF 字节码，然后附加 `trace_start` 到内核函数 `blk_start_request` 上。

这里使用的是 `bcc` 框架，它可以让你写 Python 式的程序去生成 BPF 代码。你可以在 <https://github.com/iovisor/bcc> 找到它（那里有非常多的示例程序）。

### uprobes 和 eBPF

因为我知道可以附加 eBPF 程序到内核函数上，但是，我不知道能否将 eBPF 程序附加到用户空间函数上！那会有更多令人激动的事情。这是 [在 Python 中使用一个 eBPF 程序去计数 malloc 调用的示例](https://github.com/iovisor/bcc/blob/00f662dbea87a071714913e5c7382687fef6a508/tests/lua/test_uprobes.lua)。

### 附加 eBPF 程序时应该考虑的事情

* 带 XDP 的网卡（我之前写过关于这方面的文章）
* tc egress/ingress （在网络栈上）
* kprobes（任意内核函数）
* uprobes（很明显，任意用户空间函数？？像带调试符号的任意 C 程序）
* probes 是为 dtrace 构建的名为 “USDT probes” 的探针（像 [这些 mysql 探针](https://dev.mysql.com/doc/refman/5.7/en/dba-dtrace-ref-query.html))。这是一个 [使用 dtrace 探针的示例程序](https://github.com/iovisor/bcc/blob/master/examples/tracing/mysqld_query.py)
* [JVM](http://blogs.microsoft.co.il/sasha/2016/03/31/probing-the-jvm-with-bpfbcc/)
* 跟踪点
* seccomp / landlock 安全相关的事情
* 等等

### 这个讨论超级棒

在幻灯片里有很多非常好的链接，并且在 iovisor 仓库里有个 [LINKS.md](https://github.com/iovisor/bcc/blob/master/LINKS.md)。虽然现在已经很晚了，但是我马上要去写我的第一个 eBPF 程序了！

---

via: <https://jvns.ca/blog/2017/06/28/notes-on-bpf---ebpf/>

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

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


强制关闭你的系统的内核模块

Summary: 一个同学通宵开发了一个名为 “Kgotobed” 的内核模块，它迫使你在特定的时间上床睡觉。也就是说它会强制关闭你的系统。

![](/data/attachment/album/201805/12/084852hiwel0b0jqzkjk9w.png)

我知道熬夜对健康不利。但谁在乎？多年来我一直是一只夜猫子。我通常在 12 点以后睡觉，有时在凌晨 1 点以后睡觉。第二天早上，我至少推迟三次闹钟，醒来后又累又有脾气。每天，我向自己保证早点睡觉，但最终会像平常一样晚睡。而且，这个循环还在继续！如果你和我一样，这有一个好消息。一个同学通宵开发了一个名为 **“Kgotobed”** 的内核模块，它迫使你在特定的时间上床睡觉。也就是说它会强制关闭你的系统。

你可能会问！我为什么要用这个？我有很多其他的选择。我可以设置一个 cron 作业来安排在特定时间关闭系统。我可以设置提醒或闹钟。我可以使用浏览器插件或软件。但是，它们都可以轻易忽略或绕过。Kgotobed 是你不能忽视的东西。**即使您是 root 用户也无法禁用**。是的，它会在指定的时间强制关闭你的系统。没有推迟选项。你不能推迟关机过程，也不能取消它。无论如何，系统都会在指定的时间停止运行。你被警告了！！

### 安装 Kgotobed

确保你已经安装了 `dkms`。它在大多数 Linux 发行版的默认仓库中都有。

例如在 Fedora 上，你可以使用以下命令安装它：

```
$ sudo dnf install kernel-devel-$(uname -r) dkms

```

在 Debian、Ubuntu、linux Mint 上：

```
$ sudo apt install dkms

```

安装完成后，`git clone` Kgotobed 项目。

```
$ git clone https://github.com/nikital/kgotobed.git

```

该命令会在当前工作目录中将所有 Kgotobed 仓库的内容克隆到名为 `kgotobed` 的文件夹中。进入到该目录：

```
$ cd kgotobed/

```

接着，使用命令安装 Kgotobed 驱动：

```
$ sudo make install

```

上面的命令将 `kgotobed.ko` 模块注册到 **DKMS**（这样它会为每个你运行的内核重建）并在 `/usr/local/bin/` 目录下安装 `gotobed`，然后注册、启用并启动 kgotobed 服务。

### 如何运行

默认情况下，Kgotobed 将睡前时间设置为 **1:00 AM**。也就是说，无论你在做什么，你的电脑都会在凌晨 1 点关机。

要查看当前的睡前时间，请运行：

```
$ gotobed
Current bedtime is 2018-04-10 01:00:00

```

要提前睡眠时间，例如 22:00（晚上 10 点），请运行：

```
$ sudo gotobed 22:00
[sudo] password for sk:
Current bedtime is 2018-04-10 00:58:00
Setting bedtime to 2018-04-09 22:00:00
Bedtime will be in 2 hours 16 minutes

```

当你想早点睡觉时，这会很有帮助！

但是，你不能设置更晚的时间也就是凌晨 1 点以后。你无法卸载模块，并且调整系统时钟也无济于事。唯一的出路是重启！

要设置不同的默认时间，您需要自定义 `kgotobed.service`（通过编辑或使用 systemd 工具）。

### 卸载 Kgotobed

对 Kgotobed 不满意？别担心！进入我们先前克隆的 `kgotobed` 文件夹，然后运行以下命令将其卸载。

```
$ sudo make uninstall

```

再一次，我警告你，即使你是 root 用户，也没有办法推迟或取消关机过程。你的系统将在指定的时间强制关闭。这并不适合每个人！当你在做一项重要任务时，它可能会让你疯狂。在这种情况下，请确保你已经不时地保存工作，或使用下面链接中的一些高级工具来帮助你在特定时间自动关闭、重启、暂停和休眠系统。

* [在特定时间自动关闭、重启、暂停和休眠系统](https://www.ostechnix.com/auto-shutdown-reboot-suspend-hibernate-linux-system-specific-time/)

就是这些了。希望你觉得这个指南有帮助。还有更好的东西。敬请关注！

干杯!

### 资源

* [Kgotobed GitHub 仓库](https://github.com/nikital/kgotobed)

---

via: <https://www.ostechnix.com/kgotobed-a-kernel-module-that-forcibly-shutdown-your-system/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[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：全局、局部和非局部变量（带示例）

Summary: 在 Python 中，在函数之外或在全局范围内声明的变量被称为全局变量。

在 Python 中，在函数之外或在全局范围内声明的变量被称为全局变量。

![](/data/attachment/album/201805/12/104634hn44z9dxolr4idcn.jpg)

### 全局变量

在 Python 中，在函数之外或在全局范围内声明的变量被称为全局变量。 这意味着，全局变量可以在函数内部或外部访问。

我们来看一个关于如何在 Python 中创建一个全局变量的示例。

#### 示例 1：创建全局变量

```
x = "global"

def foo():
    print("x inside :", x)

foo()
    print("x outside:", x)

```

当我们运行代码时，将会输出：

```
x inside : global
x outside: global

```

在上面的代码中，我们创建了 `x` 作为全局变量，并定义了一个 `foo()` 来打印全局变量 `x`。 最后，我们调用 `foo()` 来打印x的值。

倘若你想改变一个函数内的 `x` 的值该怎么办？

```
x = "global"

def foo():
    x = x * 2
    print(x)
foo()

```

当我们运行代码时，将会输出：

```
UnboundLocalError: local variable 'x' referenced before assignment

```

输出显示一个错误，因为 Python 将 `x` 视为局部变量，而 `x` 没有在 `foo()` 内部定义。

为了运行正常，我们使用 `global` 关键字，查看 [PythonGlobal 关键字](https://www.programiz.com/python-programming/global-keyword)以便了解更多。

### 局部变量

在函数体内或局部作用域内声明的变量称为局部变量。

#### 示例 2：访问作用域外的局部变量

```
def foo():
    y = "local"

foo()
print(y)

```

当我们运行代码时，将会输出：

```
NameError: name 'y' is not defined

```

输出显示了一个错误，因为我们试图在全局范围内访问局部变量 `y`，而局部变量只能在 `foo()` 函数内部或局部作用域内有效。

我们来看一个关于如何在 Python 中创建一个局部变量的例子。

#### 示例 3：创建一个局部变量

通常，我们在函数内声明一个变量来创建一个局部变量。

```
def foo():
    y = "local"
    print(y)

foo()

```

当我们运行代码时，将会输出：

```
local

```

让我们来看看前面的问题，其中x是一个全局变量，我们想修改 `foo()` 内部的 `x`。

### 全局变量和局部变量

在这里，我们将展示如何在同一份代码中使用全局变量和局部变量。

#### 示例 4：在同一份代码中使用全局变量和局部变量

```
x = "global"

def foo():
    global x
    y = "local"
    x = x * 2
    print(x)
    print(y)

foo()

```

当我们运行代码时，将会输出（LCTT 译注：原文中输出结果的两个 `global` 有空格，正确的是没有空格）：

```
globalglobal
local

```

在上面的代码中，我们将 `x` 声明为全局变量，将 `y` 声明为 `foo()` 中的局部变量。 然后，我们使用乘法运算符 `*` 来修改全局变量 `x`，并打印 `x` 和 `y`。

在调用 `foo()` 之后，`x` 的值变成 `globalglobal`了（LCTT 译注：原文同样有空格，正确的是没有空格），因为我们使用 `x * 2` 打印两次 `global`。 之后，我们打印局部变量y的值，即 `local` 。

#### 示例 5：具有相同名称的全局变量和局部变量

```
x = 5

def foo():
    x = 10
    print("local x:", x)

foo()
print("global x:", x)

```

当我们运行代码时，将会输出：

```
local x: 10
global x: 5

```

在上面的代码中，我们对全局变量和局部变量使用了相同的名称 `x`。 当我们打印相同的变量时却得到了不同的结果，因为这两个作用域内都声明了变量，即 `foo()` 内部的局部作用域和 `foo()` 外面的全局作用域。

当我们在 `foo()` 内部打印变量时，它输出 `local x: 10`，这被称为变量的局部作用域。

同样，当我们在 `foo()` 外部打印变量时，它输出 `global x: 5`，这被称为变量的全局作用域。

### 非局部变量

非局部变量用于局部作用域未定义的嵌套函数。 这意味着，变量既不能在局部也不能在全局范围内。

我们来看一个关于如何在 Python 中创建一个非局部变量的例子。（LCTT 译者注：原文为创建全局变量，疑为笔误）

我们使用 `nonlocal` 关键字来创建非局部变量。

#### 示例 6：创建一个非局部变量

```
def outer():
    x = "local"

    def inner():
        nonlocal x
        x = "nonlocal"
        print("inner:", x)

    inner()
    print("outer:", x)

outer()

```

当我们运行代码时，将会输出：

```
inner: nonlocal
outer: nonlocal

```

在上面的代码中有一个嵌套函数 `inner()`。 我们使用 `nonlocal` 关键字来创建非局部变量。`inner()` 函数是在另一个函数 `outer()` 的作用域中定义的。

注意：如果我们改变非局部变量的值，那么变化就会出现在局部变量中。

---

via: <https://www.programiz.com/python-programming/global-local-nonlocal-variables>

作者：[programiz](https://www.programiz.com/) 译者：[Flowsnow](https://github.com/Flowsnow) 校对：[wxy](https://github.com/wxy)

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


放慢速度如何使我变成更好的领导者

Summary: 开放式领导和耐心、倾听一样重要，它们都是关于执行的。

开放式领导和耐心、倾听一样重要，它们都是关于执行的。

>
> 开放式领导和耐心、倾听一样重要，它们都是关于执行的。
>
>
>

![](/data/attachment/album/201805/12/114919hq2v2508r0588v4l.png)

在我职业生涯的早期，我认为我能做的最重要的事情就是行动。如果我的老板说跳，我的回答是“跳多高？”

但是当我成长为一个领导者和管理者时，我意识到了我能提供的最重要的品质是 [耐心](https://opensource.com/open-organization/16/3/my-most-difficult-leadership-lesson) 和倾听。耐心和倾听意味着我关注于真正重要的东西。我很果断，所以我会毫不犹豫地行动。然而我了解到，当我考虑来自多个来源的意见，并就我们应该做什么提供建议，而不仅仅是对眼前的请求做出反应时，我的行动更具影响力。

实行开放式领导需要培养耐心和倾听技能，我需要在[最佳行动计划上进行合作，而不仅仅是最快的计划](https://opensource.com/open-organization/16/3/fastest-result-isnt-always-best-result)。它还为我提供了一些工具，以解释 [为什么我会对某人说“不”](https://opensource.com/open-organization/17/5/saying-no-open-organization) （或者，也许是“不是现在”），这样我就能以透明和自信的方式领导。

如果你正在进行软件开发和实践 scrum 中，那么下面的观点可能会引起你的共鸣：在 sprint 计划和 sprint 演示中，耐心和倾听经理的表现和它的技能一样重要。（LCTT 译注： scrum 是迭代式增量软件开发过程，通常用于敏捷软件开发。 sprint 计划和 sprint 演示是其中的两个术语。）忘掉它们，你会减少你能够产生的影响。

### 专注于耐心

专注和耐心并不总是容易的。通常，我发现自己正坐在会议上，用行动项目填满我的笔记本时，我一般会思考：“我们只要做了某事，另外一件事就会得到改善”。然后我记得事物不是那么线性发展的。

我需要考虑可能影响情况的其他因素。暂停下来从多个人和资源中获取数据可以帮我充实策略，以确保组织长期成功。它还帮助我确定那些短期的里程碑，这些里程碑应该可以让我负责生产的业务完成交付。

这里有一个很好的例子，以前耐心不是我认为应该拥有、以及影响我的表现的东西。当我在北卡罗来纳州工作时，我与一个在亚利桑那州的人共事。我们没有使用视频会议技术，所以当我们交谈时我没有看到她的肢体语言。然而当我负责为我领导的项目交付结果时，她是确保我获得足够支持的两个人之一。

无论出于何种原因，当我与她交谈时，当她要求我做某件事时，我做了。她会为我的绩效评估提供意见，所以我想确保她高兴。那时，我还不够成熟不懂得其实没必要非要讨她开心；我的重点应该放在其他绩效指标上。我本应该花更多的时间倾听并与她合作，而不是在她还在说话的时候拿起第一个“行动项目”并开始工作。

在工作六个月后，她给了我一些负面的反馈。 我很生气，很伤心。 我没有做她所要求的一切吗？ 我工作了很长时间，每周工作近七天，为期六个月。 她怎么敢批评我的表现？

然后，在我经历了愤怒和悲伤之后，我想到了她说的话，她的反馈很重要。

在 sprint 计划和 sprint 演示中，耐心和倾听经理的表现和它的技能一样重要。

她对这个项目感到担忧，她继续让我负责是因为我是项目的负责人。我们解决了问题，并且我学到了关于如何领导的重要课程：领导力并不意味着“现在就完成”。 领导力意味着制定战略，然后制定沟通和实施支持战略的计划。这也意味着犯错和从这些问题中学习。

### 经验教训

事后看来，我意识到我可以提出更多的问题来更好地理解她的反馈意图。如果她的指导不符合我收到的其他意见，我也可能会推迟。通过耐心倾听给我的关于项目的各种信息来源，综合我所学到的知识，并创建一个连贯的行动计划，我会成为一个更好的领导者。我也会有更多的目的来推动我正在做的工作。 我不会对单个数据点做出反应，而是会实施一项战略计划。 这样我也会有一个更好的绩效评估。

我最终对她有一些反馈。 下次我们一起工作时，我不想在六个月后听到反馈意见。 我想早些时候和更频繁地听到反馈意见，以便我能够尽早从错误中学习。 关于这项工作的持续讨论是任何团队都应该发生的事情。

当我成为一名管理者和领导者时，我坚持要求我的团队达到相同的标准：计划，执行计划并反思。 重复。 不要让外力造成的麻烦让你偏离你需要实施的计划。 将工作分成小的增量，以便反思和调整计划。 正如 Daniel Goleman 写道：“把注意力放在需要的地方是领导力的一个主要任务。” 不要害怕面对这个挑战。

---

via: <https://opensource.com/open-organization/18/2/open-leadership-patience-listening>

作者：[Angela Robertson](https://opensource.com/users/arobertson98) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

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


5 个最佳实践开始你的 DevOps 之旅

>
> 想要实现 DevOps 但是不知道如何开始吗？试试这 5 个最佳实践吧。
>
>
>

![5 best practices for getting started with DevOps](/data/attachment/album/201805/13/073759q00kz56ze1eiqe1p.png "5 best practices for getting started with DevOps")

想要采用 DevOps 的人通常会过早的被它的歧义性给吓跑，更不要说更加深入的使用了。当一些人开始使用 DevOps 的时候都会问：“如何开始使用呢？”，”怎么才算使用了呢？“。这 5 个最佳实践是指导你的 DevOps 之旅的很好的路线图。

### 1、 衡量所有的事情

除非你能够量化输出结果，否则你并不能确认你的努力能否使事情变得更好。新功能能否快速的输出给客户？带给他们的缺陷更少吗？出错了能快速应对和恢复吗？

在你开始做任何修改之前，思考一下你切换到 DevOps 之后想要一些什么样的输出。随着你的 DevOps 之旅，将享受到服务的所有内容的丰富的实时报告，从这两个指标考虑一下：

* **上架时间** 衡量端到端，通常是面向客户的业务经验。这通常从一个功能被正式提出而开始，客户在产品中开始使用这个功能而结束。上架时间不是工程团队的主要指标；更加重要的是，当开发出一个有价值的新功能时，它表明了你完成业务的效率，为系统改进提供了一个机会。
* **时间周期** 衡量工程团队的进度。从开始开发一个新功能开始，到在产品环境中运行需要多久？这个指标对于你了解团队的效率是非常有用的，为团队层面的提升提供了一个机会。

### 2、 放飞你的流程

DevOps 的成功需要团队布置一个定期（但愿有效）流程并且持续提升它。这不总是有效的，但是必须是一个定期的流程。通常它有一些敏捷开发的味道，就像 Scrum 或者 Scrumban 一样；一些时候它也像精益开发。不论你用的什么方法，挑选一个正式的流程，开始使用它，并且做好这些基础。

定期检查和调整流程是 DevOps 成功的关键，抓住相关演示、团队回顾、每日会议的机会来提升你的流程。

DevOps 的成功取决于大家一起有效的工作。团队的成员需要在一个有权改进的公共流程中工作。他们也需要定期找机会分享从这个流程中上游或下游的其他人那里学到的东西。

随着你构建成功，好的流程规范能帮助你的团队以很快的速度体会到 DevOps 其他的好处

尽管更多面向开发的团队采用 Scrum 是常见的，但是以运营为中心的团队（或者其他中断驱动的团队）可能选用一个更短期的流程，例如 Kanban。

### 3、 可视化工作流程

这是很强大的，能够看到哪个人在给定的时间做哪一部分工作，可视化你的工作流程能帮助大家知道接下来应该做什么，流程中有多少工作以及流程中的瓶颈在哪里。

在你看到和衡量之前你并不能有效的限制流程中的工作。同样的，你也不能有效的排除瓶颈直到你清楚的看到它。

全部工作可视化能帮助团队中的成员了解他们在整个工作中的贡献。这样可以促进跨组织边界的关系建设，帮助您的团队更有效地协作，实现共同的成就感。

### 4、 持续化所有的事情

DevOps 应该是强制自动化的。然而罗马不是一日建成的。你应该注意的第一个事情应该是努力的[持续集成（CI）](https://martinfowler.com/articles/continuousIntegration.html)，但是不要停留到这里；紧接着的是[持续交付（CD）](https://martinfowler.com/bliki/ContinuousDelivery.html)以及最终的持续部署。

持续部署的过程中是个注入自动测试的好时机。这个时候新代码刚被提交，你的持续部署应该运行测试代码来测试你的代码和构建成功的加工品。这个加工品经受流程的考验被产出，直到最终被客户看到。

另一个“持续”是不太引人注意的持续改进。一个简单的场景是每天询问你旁边的同事：“今天做些什么能使工作变得更好？”，随着时间的推移，这些日常的小改进融合到一起会带来很大的结果，你将很惊喜！但是这也会让人一直思考着如何改进。

### 5、 Gherkinize

促进组织间更有效的沟通对于成功的 DevOps 的系统思想至关重要。在程序员和业务员之间直接使用共享语言来描述新功能的需求文档对于沟通是个好办法。一个好的产品经理能在一天内学会 [Gherkin](https://cucumber.io/docs/reference) 然后使用它以平实的英语构造出明确的描述需求文档，工程师会使用 Gherkin 描述的需求文档来写功能测试，之后开发功能代码直到代码通过测试。这是一个简化的 [验收测试驱动开发](https://en.wikipedia.org/wiki/Acceptance_test%E2%80%93driven_development)(ATDD)，能够帮助你开始你的 DevOps 文化和开发实践。

### 开始你旅程

不要自馁哦。希望这五个想法给你坚实的入门方法。

### 关于作者

Magnus Hedemark - Magnus 在 IT 行业已有 20 多年，并且一直热衷于技术。他目前是 nitedHealth Group 的 DevOps 工程师。在业余时间，Magnus 喜欢摄影和划独木舟。

---

via: <https://opensource.com/article/17/11/5-keys-get-started-devops>

作者：[Magnus Hedemark](https://opensource.com/users/magnus919) 译者：[aiwhj](https://github.com/aiwhj) 校对：[wxy](https://github.com/wxy)

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


给初学者看的 shuf 命令教程

Summary: 使用 shuf 命令，我们可以随机打乱给定输入文件的行。

使用 shuf 命令，我们可以随机打乱给定输入文件的行。

![](/data/attachment/album/201805/13/074840tw9rfrjwmzrmm9jb.png)

`shuf` 命令用于在类 Unix 操作系统中生成随机排列。使用 `shuf` 命令，我们可以随机打乱给定输入文件的行。`shuf` 命令是 GNU Coreutils 的一部分，因此你不必担心安装问题。在这个简短的教程中，让我向你展示一些 `shuf` 命令的例子。

### 带例子的 shuf 命令教程

我有一个名为 `ostechnix.txt` 的文件，内容如下：

```
$ cat ostechnix.txt
line1
line2
line3
line4
line5
line6
line7
line8
line9
line10

```

现在让我们以随机顺序显示上面的行。为此，请运行：

```
$ shuf ostechnix.txt
line2
line8
line5
line10
line7
line1
line4
line6
line9
line3

```

看到了吗？上面的命令将名为 `ostechnix.txt` 中的行随机排列并输出了结果。

你可能想将输出写入另一个文件。例如，我想将输出保存到 `output.txt` 中。为此，请先创建 `output.txt`：

```
$ touch output.txt

```

然后，像下面使用 `-o` 标志将输出写入该文件：

```
$ shuf ostechnix.txt -o output.txt

```

上面的命令将随机随机打乱 `ostechnix.txt` 的内容并将输出写入 `output.txt`。你可以使用命令查看 `output.txt` 的内容：

```
$ cat output.txt

line2
line8
line9
line10
line1
line3
line7
line6
line4
line5

```

我只想显示文件中的任意一行。我该怎么做？很简单！

```
$ shuf -n 1 ostechnix.txt
line6

```

同样，我们可以选择前 “n” 个随机条目。以下命令将只显示前五个随机条目：

```
$ shuf -n 5 ostechnix.txt
line10
line4
line5
line9
line3

```

如下所示，我们可以直接使用 `-e` 标志传入输入，而不是从文件中读取行：

```
$ shuf -e line1 line2 line3 line4 line5
line1
line3
line5
line4
line2

```

你也可以传入数字：

```
$ shuf -e 1 2 3 4 5
3
5
1
4
2

```

要快速在给定范围选择一个，请改用此命令：

```
$ shuf -n 1 -e 1 2 3 4 5

```

或者，选择下面的任意三个随机数字：

```
$ shuf -n 3 -e 1 2 3 4 5
3
5
1

```

我们也可以在特定范围内生成随机数。例如，要显示 1 到 10 之间的随机数，只需使用：

```
$ shuf -i 1-10
1
9
8
2
4
7
6
3
10
5

```

有关更多详细信息，请参阅手册页。

```
$ man shuf

```

今天就是这些。还有更多更好的东西。敬请关注！

干杯!

---

via: <https://www.ostechnix.com/the-shuf-command-tutorial-with-examples-for-beginners/>

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

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


如何在 Fedora 上开始 Java 开发

Summary: Java 是世界上最流行的编程语言之一。它广泛用于开发物联网设备、Android 程序、Web 和企业应用。本文将提供使用 OpenJDK 安装和配置工作站的指南。

![](/data/attachment/album/201805/13/075645epzn1bt0y1pn8huu.jpg)

Java 是世界上最流行的编程语言之一。它广泛用于开发物联网设备、Android 程序、Web 和企业应用。本文将提供使用 [OpenJDK](http://openjdk.java.net/) 安装和配置工作站的指南。

### 安装编译器和工具

在 Fedora 中安装编译器或 Java Development Kit（JDK）很容易。在写这篇文章时，可以用 v8 和 v9 版本。只需打开一个终端并输入：

```
sudo dnf install java-1.8.0-openjdk-devel

```

这安装 JDK v8。对于 v9，请输入：

```
sudo dnf install java-9-openjdk-devel

```

对于需要其他工具和库（如 Ant 和 Maven）的开发人员，可以使用 **Java Development** 组。要安装套件，请输入：

```
sudo dnf group install "Java Development"

```

要验证编译器是否已安装，请运行：

```
javac -version

```

输出显示编译器版本，如下所示：

```
javac 1.8.0_162

```

### 编译程序

你可以使用任何基本的文本编辑器（如 nano、vim 或 gedit）编写程序。这个例子提供了一个简单的 “Hello Fedora” 程序。

打开你最喜欢的文本编辑器并输入以下内容：

```
public class HelloFedora {

      public static void main (String[] args) {
              System.out.println("Hello Fedora!");
      }
}

```

将文件保存为 `HelloFedora.java`。在终端切换到包含该文件的目录并执行以下操作：

```
javac HelloFedora.java

```

如果编译器遇到任何语法错误，它会发出错误。否则，它只会在下面显示 shell 提示符。

你现在应该有一个名为 `HelloFedora` 的文件，它是编译好的程序。使用以下命令运行它：

```
java HelloFedora

```

输出将显示：

```
Hello Fedora!

```

### 安装集成开发环境（IDE）

有些程序可能更复杂，IDE 可以帮助顺利进行。Java 程序员有很多可用的 IDE，其中包括：

* Geany，一个快速加载的基本 IDE，并提供内置模板
* Anjuta
* GNOME Builder，已经在 [Builder - 这是一个专门面向 GNOME 程序开发人员的新 IDE](https://fedoramagazine.org/builder-a-new-ide-specifically-for-gnome-app-developers-2/) 的文章中介绍过

然而，主要用 Java 编写的最流行的开源 IDE 之一是 [Eclipse](https://www.eclipse.org/)。 Eclipse 在官方仓库中有。要安装它，请运行以下命令：

```
sudo dnf install eclipse-jdt

```

安装完成后，Eclipse 的快捷方式会出现在桌面菜单中。

有关如何使用 Eclipse 的更多信息，请参阅其网站上的[用户指南](http://help.eclipse.org/oxygen/nav/0)。

### 浏览器插件

如果你正在开发 Web 小程序并需要一个用于浏览器的插件，则可以使用 [IcedTea-Web](https://icedtea.classpath.org/wiki/IcedTea-Web)。像 OpenJDK 一样，它是开源的并易于在 Fedora 中安装。运行这个命令：

```
sudo dnf install icedtea-web

```

从 Firefox 52 开始，Web 插件不再有效。有关详细信息，请访问 Mozilla 支持网站 <https://support.mozilla.org/en-US/kb/npapi-plugins?as=u&utm_source=inproduct>。

恭喜，你的 Java 开发环境已准备完毕。

---

via: <https://fedoramagazine.org/start-developing-java-fedora/>

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


如何在任何地方使用 Vim 编辑器输入文本

![](/data/attachment/album/201805/14/111701l0i5s4i2fis595mo.png)

各位 Vim 使用者大家好！今天，我这里有个好消息告诉大家。我会向大家介绍 **Vim-anywhere**，这是一个简单的脚本，它允许你使用 Vim 编辑器在 Linux 中的任何地方输入文本。这意味着你能简单地调用自己最爱的 Vim 编辑器，输入任何你所想的，并将这些文本粘贴到任意的应用和网站中。这些文本将在剪贴板可用，直到你重启了系统。这个工具对那些喜欢在非 Vim 环境中使用 Vim 键位绑定的人来说十分有用。

### 在 Linux 中安装 Vim-anywhere

Vim-anywhere 工具可以运行在任何基于 GNOME（或其他衍生品）的 Linux 发行版上。另外，确保你已经安装了下面的依赖。

* Curl
* Git
* gVim
* xclip

比如，你可以用下面的命令在 Ubuntu 中安装这些工具：

```
$ sudo apt install curl git vim-gnome xclip

```

然后运行如下的命令来安装 Vim-anywhere：

```
$ curl -fsSL https://raw.github.com/cknadler/vim-anywhere/master/install | bash

```

Vim-anywhere 到此已经安装完成。现在我们来看看如何使用它。

### 在任何地方使用 Vim 编辑器输入文本

假如你需要创建一个 word 文档。但是你更愿意使用 Vim 编辑器，而不是 LibreOffice。没问题，这里 Vim-anywhere 就派上用场了。Vim-anywhere 自动化了整个流程。它仅仅简单地调用 Vim 编辑器，所以你能写任何你所想的，然后将之粘贴到 .doc 文件中。

让我给你展示一个用例。打开 LibreOffice 或者你选的任何图形文本编辑器。然后打开 Vim-anywhere。你只需要按下 `CTRL+ALT+V` 即可。它将会打开 gVim 编辑器。按下 `i` 切换到交互模式然后输入文本。完成之后，键入 `:wq` 关闭并保存文件。

![](/data/attachment/album/201805/14/111703pir6tdrzfpfjdhpz.png)

这些文本会在剪贴板中可用，直到你重启了系统。在你关闭编辑器之后，你之前的应用会重新占据主界面。你只需按下 `CTRL+P` 将文本粘贴进去。

![](/data/attachment/album/201805/14/111705qz7bkx6ix7ooxpox.png)

这仅仅只是一个例子。你甚至可以使用 Vim-anywhere 在烦人的 web 表单或者其他应用上进行输入。一旦 Vim-anywhere 被调用，它将会打开一个缓冲区。关闭 Vim-anywhere 之后，缓冲器内的内容会自动复制到你的剪贴板中，之前的应用会重新占据主界面。

Vim-anywhere 在被调用的时候会在 `/tmp/vim-anywhere` 中创建一个临时文件。这些临时文件会一致保存着，直到你重启了系统，并为你提供临时的历史记录。

```
$ ls /tmp/vim-anywhere

```

你可以用下面的命令重新打开最近的文件：

```
$ vim $( ls /tmp/vim-anywhere | sort -r | head -n 1 )

```

#### 更新 Vim-anywhere

运行下面的命令来更新 Vim-anywhere：

```
$ ~/.vim-anywhere/update

```

#### 更改快捷键

默认调用 Vim-anywhere 的键位是 `CTRL+ALT+V`。你可以用 `gconf` 工具将其更改为任何自定义的键位绑定。

```
$ gconftool -t str --set /desktop/gnome/keybindings/vim-anywhere/binding <custom binding>

```

#### 卸载 Vim-anywhere

可能有些人觉得每次打开 Vim 编辑器，输入一些文本，然后将文本复制到其他应用中是没有意义也毫无必要的。

如果你不觉得这个工具有用，只需使用下面的命令来卸载它：

```
$ ~/.vim-anywhere/uninstall

```

---

via: <https://www.ostechnix.com/how-to-use-vim-editor-to-input-text-anywhere/>

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

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


如何在终端中使用 Instagram

Summary: 现在你可以在任何类 Unix 操作系统上的终端中使用 Instagram

之前尝试很多相关教程,很多都不靠谱,而且f.cp46.cn/tfr2计数方式一直没摸透,这个播放量计数真的很诡异.今天刚找到个新的工具,比较干净

现在你可以在任何类 Unix 操作系统上的终端中使用 Instagram

![](/data/attachment/album/201805/14/120659m79qf4m98899th4j.png)

Instagram 不需要介绍。它是像 Facebook 和 Twitter 之类的流行社交网络平台之一，它可以公开或私下分享照片和视频给确认过的粉丝。它是由两位企业家 **Kevin Systrom** 和 **Mike Krieger**于 2010 年发起的。2012 年，社交网络巨头 Facebook 收购了 Instagram。Android 和 iOS 设备上可以免费下载 Instagram。我们也可以通过网络浏览器在桌面系统中使用它。而且，最酷的是现在你可以在任何类 Unix 操作系统上的终端中使用 Instagram。你兴奋了吗？那么，请阅读以下内容了解如何在终端上查看你的 Instagram feed。

### 终端中的 Instagram

首先，按照以下链接中的说明安装 `pip3`。

然后，git clone 它的脚本仓库。

```
$ git clone https://github.com/billcccheng/instagram-terminal-news-feed.git

```

以上命令会将 instagram 脚本的内容克隆到当前工作目录中名为 `instagram-terminal-news-feed` 的目录中。cd 到该目录：

```
$ cd instagram-terminal-news-feed/

```

然后，运行以下命令安装它：

```
$ pip3 install -r requirements.txt

```

现在，运行以下命令在 Linux 终端中启动 instagram。

```
$ python3 start.py

```

输入你的 Instagram 用户名和密码，并直接从终端中浏览你的 Instagram feed。你的 instragram 用户名和密码将仅本地存储在名为 `credential.json` 的文件中。所以，你不必担心它。你也可以选择不保存默认保存的凭证。

下面是[我的 Instagram 页面](https://www.instagram.com/ostechnix/)的一些截图。

![](/data/attachment/album/201805/14/120701saigkglgc2k68s88.png)

![](/data/attachment/album/201805/14/120703mnmafga9ma8nfv3n.png)

![](/data/attachment/album/201805/14/120704fze72c35kc2c5o02.png)

请注意，你只能查看你的 feed。你不能关注任何人，喜欢或评论帖子。这只是一个 instagram feed 阅读器。

该项目可在 GitHub 上免费获得，因此你可以查看源代码，改进它，添加更多功能，修复任何 bug。

玩得开心！干杯！！

---

via: <https://www.ostechnix.com/how-to-use-instagram-in-terminal/>

作者：[SK](https://www.ostechnix.com/author/sk/) 选题：[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/) 荣誉推出


“Exit Trap” 让你的 Bash 脚本更稳固可靠

Summary: 要做到这一点，秘诀就是 bash 提供的一个叫做 EXIT 的伪信号，你可以 trap 它，当脚本因为任何原因退出时，相应的命令或函数就会执行。

![](/data/attachment/album/201805/14/150056qniv8u75vo7qmouz.jpg)

有个简单实用的技巧可以让你的 bash 脚本更稳健 -- 确保总是执行必要的收尾工作，哪怕是在发生异常的时候。要做到这一点，秘诀就是 bash 提供的一个叫做 EXIT 的伪信号，你可以 [trap](http://www.gnu.org/software/bash/manual/bashref.html#index-trap) 它，当脚本因为任何原因退出时，相应的命令或函数就会执行。我们来看看它是如何工作的。

基本的代码结构看起来像这样：

```
#!/bin/bash
function finish {
  # 你的收尾代码
}
trap finish EXIT

```

你可以把任何你觉得务必要运行的代码放在这个 `finish` 函数里。一个很好的例子是：创建一个临时目录，事后再删除它。

```
#!/bin/bash
scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
function finish {
  rm -rf "$scratch"
}
trap finish EXIT

```

这样，在你的核心代码中，你就可以在这个 `$scratch` 目录里下载、生成、操作中间或临时数据了。   注1

```
# 下载所有版本的 linux 内核…… 为了科学研究！
for major in {1..4}; do
  for minor in {0..99}; do
    for patchlevel in {0..99}; do
      tarball="linux-${major}-${minor}-${patchlevel}.tar.bz2"
      curl -q "http://kernel.org/path/to/$tarball" -o "$scratch/$tarball" || true
      if [ -f "$scratch/$tarball" ]; then
        tar jxf "$scratch/$tarball"
      fi
    done
  done
done
# 整合成单个文件
# 复制到目标位置
cp "$scratch/frankenstein-linux.tar.bz2" "$1"
# 脚本结束， scratch 目录自动被删除

```

比较一下如果不用 `trap` ，你是怎么删除 `scratch` 目录的：

```
#!/bin/bash
# 别这样做！

scratch=$(mktemp -d -t tmp.XXXXXXXXXX)

# 在这里插入你的几十上百行代码

# 都搞定了，退出之前把目录删除
rm -rf "$scratch"

```

这有什么问题么？很多：

* 如果运行出错导致脚本提前退出， `scratch` 目录及里面的内容不会被删除。这会导致资料泄漏，可能引发安全问题。
* 如果这个脚本的设计初衷就是在脚本末尾以前退出，那么你必须手动复制粘贴 `rm` 命令到每一个出口。
* 这也给维护带来了麻烦。如果今后在脚本某处添加了一个 `exit` ，你很可能就忘了加上删除操作 -- 从而制造潜在的安全漏洞。

### 无论如何，服务要在线

另外一个场景： 想象一下你正在运行一些自动化系统运维任务，要临时关闭一项服务，最后这项服务需要重启，而且要万无一失，即使脚本运行出错。那么你可以这样做：

```
function finish {
    # 重启服务
    sudo /etc/init.d/something start
}
trap finish EXIT
sudo /etc/init.d/something stop
# 主要任务代码

# 脚本结束，执行 finish 函数重启服务

```

一个具体的实例：比如 Ubuntu 服务器上运行着 MongoDB ，你要为 crond 写一个脚本来临时关闭服务并做一些日常维护工作。你应该这样写：

```
function finish {
    # 重启服务
    sudo service mongdb start
}
trap finish EXIT
# 关闭 mongod 服务
sudo service mongdb stop
# （如果 mongod 配置了 fork ，比如 replica set ，你可能需要执行 “sudo killall --wait /usr/bin/mongod”）

```

### 控制开销

有一种情况特别能体现 EXIT `trap` 的价值：如果你的脚本运行过程中需要初始化一下成本高昂的资源，结束时要确保把它们释放掉。比如你在 AWS (Amazon Web Services) 上工作，要在脚本中创建一个镜像。

（名词解释: 在亚马逊云上的运行的服务器叫“[实例](http://aws.amazon.com/ec2/)”。实例从<ruby> 亚马逊机器镜像 <rt>  Amazon Machine Image </rt></ruby>创建而来，通常被称为 “AMI” 或 “镜像” 。AMI 相当于某个特殊时间点的服务器快照。）

我们可以这样创建一个自定义的 AMI ：

1. 基于一个基准 AMI 运行一个实例（例如，启动一个服务器）。
2. 在实例中手动或运行脚本来做一些修改。
3. 用修改后的实例创建一个镜像。
4. 如果不再需要这个实例，可以将其删除。

最后一步**相当重要**。如果你的脚本没有把实例删除掉，它会一直运行并计费。（到月底你的账单让你大跌眼镜时，恐怕哭都来不及了！）

如果把 AMI 的创建封装在脚本里，我们就可以利用 `trap` EXIT 来删除实例了。我们还可以用上 EC2 的命令行工具：

```
#!/bin/bash
# 定义基准 AMI 的 ID
ami=$1
# 保存临时实例的 ID
instance=''
# 作为 IT 人，让我们看看 scratch 目录的另类用法
scratch=$(mktemp -d -t tmp.XXXXXXXXXX)
function finish {
    if [ -n "$instance" ]; then
        ec2-terminate-instances "$instance"
    fi
    rm -rf "$scratch"
}
trap finish EXIT
# 创建实例，将输出(包含实例 ID )保存到 scratch 目录下的文件里
ec2-run-instances "$ami" > "$scratch/run-instance"
# 提取实例 ID
instance=$(grep '^INSTANCE' "$scratch/run-instance" | cut -f 2)

```

脚本执行到这里，实例（EC2 服务器）已经开始运行    注2  。接下来你可以做任何事情：在实例中安装软件，修改配置文件等，然后为最终版本创建一个镜像。实例会在脚本结束时被删除 -- 即使脚本因错误而提前退出。（请确保实例创建成功后再运行业务代码。）

### 更多应用

这篇文章只讲了些皮毛。我已经使用这个 bash 技巧很多年了，现在还能不时发现一些有趣的用法。你也可以把这个方法应用到你自己的场景中，从而提升你的 bash 脚本的可靠性。

### 尾注

* 注1. `mktemp` 的选项 `-t` 在 Linux 上是可选的，在 OS X 上是必需的。带上此选项可以让你的脚本有更好的可移植性。
* 注2. 如果只是为了获取实例 ID ，我们不用创建文件，直接写成 `instance=$(ec2-run-instances "$ami" | grep '^INSTANCE' | cut -f 2)` 就可以。但把输出写入文件可以记录更多有用信息，便于调试 ，代码可读性也更强。

作者简介：美国加利福尼亚旧金山的作家，软件工程师，企业家。[Powerful Python](https://www.amazon.com/d/0692878971) 的作者，他的 [blog](https://powerfulpython.com/blog/)。

---

via: <http://redsymbol.net/articles/bash-exit-traps/>

作者：[aaron maxwell](http://redsymbol.net/) 译者：[Dotcra](https://github.com/Dotcra) 校对：[wxy](https://github.com/wxy)

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


Linux 命令行下的数学运算

Summary: 有几个有趣的命令可以在 Linux 系统下做数学运算： expr、factor、jot 和 bc 命令。

>
> 有几个有趣的命令可以在 Linux 系统下做数学运算： `expr`、`factor`、`jot` 和 `bc` 命令。
>
>
>

![](/data/attachment/album/201805/14/190605btc11bot16tiv2u8.jpg)

可以在 Linux 命令行下做数学运算吗？当然可以！事实上，有不少命令可以轻松完成这些操作，其中一些甚至让你大吃一惊。让我们来学习这些有用的数学运算命令或命令语法吧。

### expr

首先，对于在命令行使用命令进行数学运算，可能最容易想到、最常用的命令就是 `expr` （<ruby> 表达式 <rt>  expression </rt></ruby>。它可以完成四则运算，也可以用于比较大小。下面是几个例子：

#### 变量递增

```
$ count=0
$ count=`expr $count + 1`
$ echo $count
1

```

#### 完成简单运算

```
$ expr 11 + 123
134
$ expr 134 / 11
12
$ expr 134 - 11
123
$ expr 11 * 123
expr: syntax error      <== oops!
$ expr 11 \* 123
1353
$ expr 20 % 3
2

```

注意，你需要在 `*` 运算符之前增加 `\` 符号，避免语法错误（注：`*` 是 bash 的通配符，因此需要用 `\` 转义，下面的 `>` 也是由于是 bash 的管道符而需要转义）。`%` 运算符用于取余运算。

下面是一个稍微复杂的例子：

```
participants=11
total=156
share=`expr $total / $participants`
remaining=`expr $total - $participants \* $share`
echo $share
14
echo $remaining
2

```

假设某个活动中有 11 位参与者，需要颁发的奖项总数为 156，那么平均每个参与者获得 14 项奖项，额外剩余 2 个奖项。

#### 比较

下面让我们看一下比较的操作。从第一印象来看，语句看似有些怪异；这里并不是**设置**数值，而是进行数字比较。在本例中 `expr` 判断表达式是否为真：如果结果是 1，那么表达式为真；反之，表达式为假。

```
$ expr 11 = 11
1
$ expr 11 = 12
0

```

请读作“11 是否等于 11？”及“11 是否等于 12？”，你很快就会习惯这种写法。当然，我们不会在命令行上执行上述比较，可能的比较是 `$age` 是否等于 `11`。

```
$ age=11
$ expr $age = 11
1

```

在本例中，我们判断 10 是否大于 5，以及是否大于 99。

```
$ expr 10 \> 5
1
$ expr 10 \> 99
0

```

的确，返回 1 和 0 分别代表比较的结果为真和假，我们一般预期在 Linux 上得到这个结果。在下面的例子中，按照上述逻辑使用 `expr` 并不正确，因为 `if` 的工作原理刚好相反，即 0 代表真。

```
#!/bin/bash

echo -n "Cost to us> "
read cost
echo -n "Price we're asking> "
read price

if [ `expr $price \> $cost` ]; then
 echo "We make money"
else
 echo "Don't sell it"
fi

```

下面，我们运行这个脚本：

```
$ ./checkPrice
Cost to us> 11.50
Price we're asking> 6
We make money

```

这显然与我们预期不符！我们稍微修改一下，以便使其按我们预期工作：

```
#!/bin/bash

echo -n "Cost to us> "
read cost
echo -n "Price we're asking> "
read price

if [ `expr $price \> $cost` == 1 ]; then
 echo "We make money"
else
 echo "Don't sell it"
fi

```

### factor

`factor` 命令的功能基本与你预期相符。你给出一个数字，该命令会给出对应数字的因子。

```
$ factor 111
111: 3 37
$ factor 134
134: 2 67
$ factor 17894
17894: 2 23 389
$ factor 1987
1987: 1987

```

注：`factor` 命令对于最后一个数字没有返回更多因子，这是因为 1987 是一个**质数**。

### jot

`jot` 命令可以创建一系列数字。给定数字总数及起始数字即可。

```
$ jot 8 10
10
11
12
13
14
15
16
17

```

你也可以用如下方式使用 `jot`，这里我们要求递减至数字 2。

```
$ jot 8 10 2
10
9
8
7
5
4
3
2

```

`jot` 可以帮你构造一系列数字组成的列表，该列表可以用于其它任务。

```
$ for i in `jot 7 17`; do echo April $i; done
April 17
April 18
April 19
April 20
April 21
April 22
April 23

```

### bc

`bc` 基本上是命令行数学运算最佳工具之一。输入你想执行的运算，使用管道发送至该命令即可：

```
$ echo "123.4+5/6-(7.89*1.234)" | bc
113.664

```

可见 `bc` 并没有忽略精度，而且输入的字符串也相当直截了当。它还可以进行大小比较、处理布尔值、计算平方根、正弦、余弦和正切等。

```
$ echo "sqrt(256)" | bc
16
$ echo "s(90)" | bc -l
.89399666360055789051

```

事实上，`bc` 甚至可以计算 pi。你需要指定需要的精度。

```
$ echo "scale=5; 4*a(1)" | bc -l
3.14156
$ echo "scale=10; 4*a(1)" | bc -l
3.1415926532
$ echo "scale=20; 4*a(1)" | bc -l
3.14159265358979323844
$ echo "scale=40; 4*a(1)" | bc -l
3.1415926535897932384626433832795028841968

```

除了通过管道接收数据并返回结果，`bc`还可以交互式运行，输入你想执行的运算即可。本例中提到的 `scale` 设置可以指定有效数字的个数。

```
$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=2
3/4
.75
2/3
.66
quit

```

你还可以使用 `bc` 完成数字进制转换。`obase` 用于设置输出的数字进制。

```
$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
obase=16
16      <=== entered
10      <=== response
256     <=== entered
100     <=== response
quit

```

按如下方式使用 `bc` 也是完成十六进制与十进制转换的最简单方式之一：

```
$ echo "ibase=16; F2" | bc
242
$ echo "obase=16; 242" | bc
F2

```

在上面第一个例子中，我们将输入进制（`ibase`）设置为十六进制（`hex`），完成十六进制到为十进制的转换。在第二个例子中，我们执行相反的操作，即将输出进制（`obase`）设置为十六进制。

### 简单的 bash 数学运算

通过使用双括号，我们可以在 bash 中完成简单的数学运算。在下面的例子中，我们创建一个变量，为变量赋值，然后依次执行加法、自减和平方。

```
$ (( e = 11 ))
$ (( e = e + 7 ))
$ echo $e
18

$ (( e-- ))
$ echo $e
17

$ (( e = e ** 2 ))
$ echo $e
289

```

允许使用的运算符包括：

```
+ -     加法及减法
++ --   自增与自减
* / %   乘法、除法及求余数
**      指数运算（bash 中）
^       指数运算（bc 中）
```

你还可以使用逻辑运算符和布尔运算符：

```
$ ((x=11)); ((y=7))
$ if (( x > y )); then
> echo "x > y"
> fi
x > y

$ ((x=11)); ((y=7)); ((z=3))
$ if (( x > y )) >> (( y > z )); then
> echo "letters roll downhill"
> fi
letters roll downhill

```

或者如下方式：

```
$ if [ x > y ] << [ y > z ]; then echo "letters roll downhill"; fi
letters roll downhill

```

下面计算 2 的 3 次幂：

```
$ echo "2 ^ 3"
2 ^ 3
$ echo "2 ^ 3" | bc
8

```

### 总结

在 Linux 系统中，有很多不同的命令行工具可以完成数字运算。希望你在读完本文之后，能掌握一两个新工具。

感谢 @[no1xsyzy](https://github.com/no1xsyzy) [提出的修改意见](https://github.com/LCTT/TranslateProject/issues/8841)。

---

via: <https://www.networkworld.com/article/3268964/linux/how-to-do-math-on-the-linux-command-line.html>

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

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


两款 Linux 桌面端可用的科学计算器

Summary: 如果你想找个高级的桌面计算器的话，你可以看看开源软件，以及一些其它有趣的工具。

如果你想找个高级的桌面计算器的话，你可以看看开源软件，以及一些其它有趣的工具。

>
> 如果你想找个高级的桌面计算器的话，你可以看看开源软件，以及一些其它有趣的工具。
>
>
>

![](/data/attachment/album/201805/15/102710qilkuv3eaiysdfyg.jpg)

每个 Linux 桌面环境都至少带有一个功能简单的桌面计算器，但大多数计算器只能进行一些简单的计算。

幸运的是，还是有例外的：不仅可以做得比开平方根和一些三角函数还多，而且还很简单。这里将介绍两款强大的计算器，外加一大堆额外的功能。

### SpeedCrunch

[SpeedCrunch](http://speedcrunch.org/index.html) 是一款高精度科学计算器，有着简明的 Qt5 图像界面，并且强烈依赖键盘。

![SpeedCrunch graphical interface](/data/attachment/album/201805/15/102725rxsac00x8y1so2oz.png "SpeedCrunch graphical interface")

*SpeedCrunch 运行中*

它支持单位，并且可用在所有函数中。

例如，

```
2 * 10^6 newton / (meter^2)

```

你可以得到：

```
= 2000000 pascal

```

SpeedCrunch 会默认地将结果转化为国际标准单位，但还是可以用 `in` 命令转换：

例如：

```
3*10^8 meter / second in kilo meter / hour

```

结果是：

```
= 1080000000 kilo meter / hour

```

`F5` 键可以将所有结果转为科学计数法（`1.08e9 kilo meter / hour`），`F2` 键可以只将那些很大的数或很小的数转为科学计数法。更多选项可以在配置页面找到。

可用的函数的列表看上去非常壮观。它可以用在 Linux 、 Windows、macOS。许可证是 GPLv2，你可以在 [Bitbucket](https://bitbucket.org/heldercorreia/speedcrunch) 上得到它的源码。

### Qalculate!

[Qalculate!](https://qalculate.github.io/)（有感叹号）有一段长而复杂的历史。

这个项目给了我们一个强大的库，而这个库可以被其它程序使用（在 Plasma 桌面中，krunner 可以用它来计算），以及一个用 GTK3 搭建的图形界面。它允许你转换单位，处理物理常量，创建图像，使用复数，矩阵以及向量，选择任意精度，等等。

![Qalculate! Interface](/data/attachment/album/201805/15/102726moffos25nibeii0p.png "Qalculate! Interface")

*在 Qalculate! 中查看物理常量*

在单位的使用方面，Qalculate! 会比 SppedCrunch 更加直观，而且可以识别一些常用前缀。你有听说过 exapascal 压力吗？反正我没有（太阳的中心大概在 `~26 PPa`），但 Qalculate! ，可以准确 `1 EPa` 的意思。同时，Qalculate! 可以更加灵活地处理语法错误，所以你不需要担心打括号：如果没有歧义，Qalculate! 会直接给出正确答案。

一段时间之后这个项目看上去被遗弃了。但在 2016 年，它又变得强大了，在一年里更新了 10 个版本。它的许可证是 GPLv2 （源码在 [GitHub](https://github.com/Qalculate) 上），提供Linux 、Windows 、macOS的版本。

### 更多计算器

#### ConvertAll

好吧，这不是“计算器”，但这个程序非常好用。

大部分单位转换器只是一个大的基本单位列表以及一大堆基本组合，但 [ConvertAll](http://convertall.bellz.org/) 与它们不一样。有试过把“天文单位每年”转换为“英尺每秒”吗？不管它们说不说得通，只要你想转换任何种类的单位，ConvertAll 就是你要的工具。

只需要在相应的输入框内输入转换前和转换后的单位：如果单位相容，你会直接得到答案。

主程序是在 PyQt5 上搭建的，但也有 [JavaScript 的在线版本](http://convertall.bellz.org/js/)。

#### 带有单位包的 (wx)Maxima

有时候（好吧，很多时候）一款桌面计算器时候不够你用的，然后你需要更多的原力。

[Maxima](http://maxima.sourceforge.net/) 是一款计算机代数系统（LCTT 译注：进行符号运算的软件。这种系统的要件是数学表示式的符号运算），你可以用它计算导数、积分、方程、特征值和特征向量、泰勒级数、拉普拉斯变换与傅立叶变换，以及任意精度的数字计算、二维或三维图像··· ···列出这些都够我们写几页纸的了。

[wxMaxima](https://andrejv.github.io/wxmaxima/) 是一个设计精湛的 Maxima 的图形前端，它简化了许多 Maxima 的选项，但并不会影响其它。在 Maxima 的基础上，wxMaxima 还允许你创建 “笔记本”，你可以在上面写一些笔记，保存你的图像等。其中一项 (wx)Maxima 最惊艳的功能是它可以处理尺寸单位。

在提示符只需要输入：

```
load("unit")

```

按 `Shift+Enter`，等几秒钟的时间，然后你就可以开始了。

默认地，单位包可以用基本的 MKS 单位，但如果你喜欢，例如，你可以用 `N` 为单位而不是 `kg*m/s2`，你只需要输入：`setunits(N)`。

Maxima 的帮助（也可以在 wxMaxima 的帮助菜单中找到）会给你更多信息。

你使用这些程序吗？你知道还有其它好的科学、工程用途的桌面计算器或者其它相关的计算器吗？在评论区里告诉我们吧！

---

via: <https://opensource.com/article/18/1/scientific-calculators-linux>

作者：[Ricardo Berlasso](https://opensource.com/users/rgb-es) 译者：[zyk2290](https://github.com/zyk2290) 校对：[wxy](https://github.com/wxy)

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


基于命令行的任务管理器 Taskwarrior

![](/data/attachment/album/201805/15/104609d5en8uesea8gepn8.jpg)

Taskwarrior 是一个灵活的[命令行任务管理程序](https://taskwarrior.org/)，用他们[自己的话说](https://taskwarrior.org/docs/start.html)：

>
> Taskwarrior 在命令行里管理你的 TODO 列表。它灵活，快速，高效，不显眼，它默默做自己的事情让你避免自己管理。
>
>
>

Taskwarrior 是高度可定制的，但也可以“立即使用”。在本文中，我们将向你展示添加和完成任务的基本命令，然后我们将介绍几个更高级的命令。最后，我们将向你展示一些基本的配置设置，以开始自定义你的设置。

### 安装 Taskwarrior

Taskwarrior 在 Fedora 仓库中是可用的，所有安装它很容易：

```
sudo dnf install task

```

一旦完成安装，运行 `task` 命令。第一次运行将会创建一个 `~/.taskrc` 文件。

```
$ task
A configuration file could not be found in ~

Would you like a sample /home/link/.taskrc created, so Taskwarrior can proceed? (yes/no) yes
[task next]
No matches.

```

### 添加任务

添加任务快速而不显眼。

```
$ task add Plant the wheat
Created task 1.

```

运行 `task` 或者 `task list` 来显示即将来临的任务。

```
$ task list

ID Age Description Urg
 1 8s Plant the wheat 0

1 task

```

让我们添加一些任务来完成这个示例。

```
$ task add Tend the wheat
Created task 2.
$ task add Cut the wheat
Created task 3.
$ task add Take the wheat to the mill to be ground into flour
Created task 4.
$ task add Bake a cake
Created task 5.

```

再次运行 `task` 来查看列表。

```
[task next]

ID Age Description Urg
 1 3min Plant the wheat 0
 2 22s Tend the wheat 0
 3 16s Cut the wheat 0
 4 8s Take the wheat to the mill to be ground into flour 0
 5 2s Bake a cake 0

5 tasks

```

### 完成任务

将一个任务标记为完成， 查找其 ID 并运行：

```
$ task 1 done
Completed task 1 'Plant the wheat'.
Completed 1 task.

```

你也可以用它的描述来标记一个任务已完成。

```
$ task 'Tend the wheat' done
Completed task 1 'Tend the wheat'.
Completed 1 task.

```

通过使用 `add`、`list` 和 `done`，你可以说已经入门了。

### 设定截止日期

很多任务不需要一个截止日期：

```
task add Finish the article on Taskwarrior

```

但是有时候，设定一个截止日期正是你需要提高效率的动力。在添加任务时使用 `due` 修饰符来设置特定的截止日期。

```
task add Finish the article on Taskwarrior due:tomorrow

```

`due` 非常灵活。它接受特定日期 (`2017-02-02`) 或 ISO-8601 (`2017-02-02T20:53:00Z`)，甚至相对时间 (`8hrs`)。可以查看所有示例的 [Date & Time](https://taskwarrior.org/docs/dates.html) 文档。

日期也不只有截止日期，Taskwarrior 有 `scheduled`, `wait` 和 `until` 选项。

```
task add Proof the article on Taskwarrior scheduled:thurs

```

一旦日期（本例中的星期四）通过，该任务就会被标记为 `READY` 虚拟标记。它会显示在 `ready` 报告中。

```
$ task ready

ID Age S Description Urg
 1 2s 1d Proof the article on Taskwarrior 5

```

要移除一个日期，使用空白值来 `modify` 任务：

```
$ task 1 modify scheduled:

```

### 查找任务

如果没有使用正则表达式搜索的能力，任务列表是不完整的，对吧？

```
$ task '/.* the wheat/' list

ID Age Project Description Urg
 2 42min Take the wheat to the mill to be ground into flour 0
 1 42min Home Cut the wheat 1

2 tasks

```

### 自定义 Taskwarrior

记得我们在开头创建的文件 (`~/.taskrc`)吗？让我们来看看默认设置：

```
# [Created by task 2.5.1 2/9/2017 16:39:14]
# Taskwarrior program configuration file.
# For more documentation, see http://taskwarrior.org or try 'man task', 'man task-color',
# 'man task-sync' or 'man taskrc'

# Here is an example of entries that use the default, override and blank values
# variable=foo -- By specifying a value, this overrides the default
# variable= -- By specifying no value, this means no default
# #variable=foo -- By commenting out the line, or deleting it, this uses the default

# Use the command 'task show' to see all defaults and overrides

# Files
data.location=~/.task

# Color theme (uncomment one to use)
#include /usr//usr/share/task/light-16.theme
#include /usr//usr/share/task/light-256.theme
#include /usr//usr/share/task/dark-16.theme
#include /usr//usr/share/task/dark-256.theme
#include /usr//usr/share/task/dark-red-256.theme
#include /usr//usr/share/task/dark-green-256.theme
#include /usr//usr/share/task/dark-blue-256.theme
#include /usr//usr/share/task/dark-violets-256.theme
#include /usr//usr/share/task/dark-yellow-green.theme
#include /usr//usr/share/task/dark-gray-256.theme
#include /usr//usr/share/task/dark-gray-blue-256.theme
#include /usr//usr/share/task/solarized-dark-256.theme
#include /usr//usr/share/task/solarized-light-256.theme
#include /usr//usr/share/task/no-color.theme

```

现在唯一生效的选项是 `data.location=~/.task`。要查看活动配置设置（包括内置的默认设置），运行 `show`。

```
task show

```

要改变设置，使用 `config`。

```
$ task config displayweeknumber no
Are you sure you want to add 'displayweeknumber' with a value of 'no'? (yes/no) yes
Config file /home/link/.taskrc modified.

```

### 示例

这些只是你可以用 Taskwarrior 做的一部分事情。

将你的任务分配到一个项目：

```
task 'Fix leak in the roof' modify project:Home

```

使用 `start` 来标记你正在做的事情，这可以帮助你回忆起你周末后在做什么：

```
task 'Fix bug #141291' start

```

使用相关的标签：

```
task add 'Clean gutters' +weekend +house

```

务必阅读[完整文档](https://taskwarrior.org/docs/)以了解你可以编目和组织任务的所有方式。

---

via: <https://fedoramagazine.org/getting-started-taskwarrior/>

作者：[Link Dupont](https://fedoramagazine.org/author/linkdupont/) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

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


探秘“栈”之旅

Summary: 栈非常重要，因为它追踪着一个程序中运行的函数，而函数又是一个软件的重要组成部分。

![](/data/attachment/album/201805/15/182842wn8zd9pnfynzfh4v.jpg)

早些时候，我们探索了 [“内存中的程序之秘”](/article-9255-1.html)，我们欣赏了在一台电脑中是如何运行我们的程序的。今天，我们去探索*栈的调用*，它在大多数编程语言和虚拟机中都默默地存在。在此过程中，我们将接触到一些平时很难见到的东西，像<ruby> 闭包 <rt>  closure </rt></ruby>、递归、以及缓冲溢出等等。但是，我们首先要作的事情是，描绘出栈是如何运作的。

栈非常重要，因为它追踪着一个程序中运行的*函数*，而函数又是一个软件的重要组成部分。事实上，程序的内部操作都是非常简单的。它大部分是由函数向栈中推入数据或者从栈中弹出数据的相互调用组成的，而在堆上为数据分配内存才能在跨函数的调用中保持数据。不论是低级的 C 软件还是像 JavaScript 和 C# 这样的基于虚拟机的语言，它们都是这样的。而对这些行为的深刻理解，对排错、性能调优以及大概了解究竟发生了什么是非常重要的。

当一个函数被调用时，将会创建一个<ruby> 栈帧 <rt>  stack frame </rt></ruby>去支持函数的运行。这个栈帧包含函数的*局部变量*和调用者传递给它的*参数*。这个栈帧也包含了允许被调用的函数（*callee*）安全返回给其调用者的内部事务信息。栈帧的精确内容和结构因处理器架构和函数调用规则而不同。在本文中我们以 Intel x86 架构和使用 C 风格的函数调用（`cdecl`）的栈为例。下图是一个处于栈顶部的一个单个栈帧：

![](/data/attachment/album/201805/15/183135uglyl5cwdxxwizzs.png)

在图上的场景中，有三个 CPU 寄存器进入栈。<ruby> 栈指针 <rt>  stack pointer </rt></ruby> `esp`（LCTT 译注：扩展栈指针寄存器） 指向到栈的顶部。栈的顶部总是被最*后一个推入到栈且还没有弹出*的东西所占据，就像现实世界中堆在一起的一叠盘子或者 100 美元大钞一样。

保存在 `esp` 中的地址始终在变化着，因为栈中的东西不停被推入和弹出，而它总是指向栈中的最后一个推入的东西。许多 CPU 指令的一个副作用就是自动更新 `esp`，离开寄存器而使用栈是行不通的。

在 Intel 的架构中，绝大多数情况下，栈的增长是向着*低位内存地址*的方向。因此，这个“顶部” 在包含数据的栈中是处于低位的内存地址（在这种情况下，包含的数据是 `local_buffer`）。注意，关于从 `esp` 到 `local_buffer` 的箭头不是随意连接的。这个箭头代表着事务：它*专门*指向到由 `local_buffer` 所拥有的*第一个字节*，因为，那是一个保存在 `esp` 中的精确地址。

第二个寄存器跟踪的栈是 `ebp`（LCTT 译注：扩展基址指针寄存器），它包含一个<ruby> 基指针 <rt>  base pointer </rt></ruby>或者称为<ruby> 帧指针 <rt>  frame pointer </rt></ruby>。它指向到一个*当前运行*的函数的栈帧内的固定位置，并且它为参数和局部变量的访问提供一个稳定的参考点（基址）。仅当开始或者结束调用一个函数时，`ebp` 的内容才会发生变化。因此，我们可以很容易地处理在栈中的从 `ebp` 开始偏移后的每个东西。如图所示。

不像 `esp`， `ebp` 大多数情况下是在程序代码中通过花费很少的 CPU 来进行维护的。有时候，完成抛弃 `ebp` 有一些性能优势，可以通过 [编译标志](http://stackoverflow.com/questions/14666665/trying-to-understand-gcc-option-fomit-frame-pointer) 来做到这一点。Linux 内核就是一个这样做的示例。

最后，`eax`（LCTT 译注：扩展的 32 位通用数据寄存器）寄存器惯例被用来转换大多数 C 数据类型返回值给调用者。

现在，我们来看一下在我们的栈帧中的数据。下图清晰地按字节展示了字节的内容，就像你在一个调试器中所看到的内容一样，内存是从左到右、从顶部至底部增长的，如下图所示：

![](/data/attachment/album/201805/15/183138nz4ogo2hlsa4oihg.png)

局部变量 `local_buffer` 是一个字节数组，包含一个由 null 终止的 ASCII 字符串，这是 C 程序中的一个基本元素。这个字符串可以读取自任意地方，例如，从键盘输入或者来自一个文件，它只有 7 个字节的长度。因为，`local_buffer` 只能保存 8 字节，所以还剩下 1 个未使用的字节。*这个字节的内容是未知的*，因为栈不断地推入和弹出，*除了你写入的之外*，你根本不会知道内存中保存了什么。这是因为 C 编译器并不为栈帧初始化内存，所以它的内容是未知的并且是随机的 —— 除非是你自己写入。这使得一些人对此很困惑。

再往上走，`local1` 是一个 4 字节的整数，并且你可以看到每个字节的内容。它似乎是一个很大的数字，在8 后面跟着的都是零，在这里可能会误导你。

Intel 处理器是<ruby> 小端 <rt>  little endian </rt></ruby>机器，这表示在内存中的数字也是首先从小的一端开始的。因此，在一个多字节数字中，较小的部分在内存中处于最低端的地址。因为一般情况下是从左边开始显示的，这背离了我们通常的数字表示方式。我们讨论的这种从小到大的机制，使我想起《格里佛游记》：就像小人国的人们吃鸡蛋是从小头开始的一样，Intel 处理器处理它们的数字也是从字节的小端开始的。

因此，`local1` 事实上只保存了一个数字 8，和章鱼的腿数量一样。然而，`param1` 在第二个字节的位置有一个值 2，因此，它的数学上的值是 `2 * 256 = 512`（我们与 256 相乘是因为，每个位置值的范围都是从 0 到 255）。同时，`param2` 承载的数量是 `1 * 256 * 256 = 65536`。

这个栈帧的内部数据是由两个重要的部分组成：*前一个*栈帧的地址（保存的 `ebp` 值）和函数退出才会运行的指令的地址（返回地址）。它们一起确保了函数能够正常返回，从而使程序可以继续正常运行。

现在，我们来看一下栈帧是如何产生的，以及去建立一个它们如何共同工作的内部蓝图。首先，栈的增长是非常令人困惑的，因为它与你你预期的方式相反。例如，在栈上分配一个 8 字节，就要从 `esp` 减去 8，去，而减法是与增长不同的奇怪方式。

我们来看一个简单的 C 程序：

```
Simple Add Program - add.c

int add(int a, int b)
{
    int result = a + b;
    return result;
}

int main(int argc)
{
    int answer;
    answer = add(40, 2);
}

```

*简单的加法程序 - add.c*

假设我们在 Linux 中不使用命令行参数去运行它。当你运行一个 C 程序时，实际运行的第一行代码是在 C 运行时库里，由它来调用我们的 `main` 函数。下图展示了程序运行时每一步都发生了什么。每个图链接的 GDB 输出展示了内存和寄存器的状态。你也可以看到所使用的 [GDB 命令](https://github.com/gduarte/blog/blob/master/code/x86-stack/add-gdb-commands.txt)，以及整个 [GDB 输出](https://github.com/gduarte/blog/blob/master/code/x86-stack/add-gdb-output.txt)。如下：

![](/data/attachment/album/201805/15/183143nubun1kk11f6kuh7.png)

第 2 步和第 3 步，以及下面的第 4 步，都只是函数的<ruby> 序言 <rt>  prologue </rt></ruby>，几乎所有的函数都是这样的：`ebp` 的当前值被保存到了栈的顶部，然后，将 `esp` 的内容拷贝到 `ebp`，以建立一个新的栈帧。`main` 的序言和其它函数一样，但是，不同之处在于，当程序启动时 `ebp` 被清零。

如果你去检查栈下方（右边）的整形变量（`argc`），你将找到更多的数据，包括指向到程序名和命令行参数（传统的 C 的 `argv`）、以及指向 Unix 环境变量以及它们真实的内容的指针。但是，在这里这些并不是重点，因此，继续向前调用 `add()`：

![](/data/attachment/album/201805/15/183153s1whezj3xxrs14wx.png)

在 `main` 从 `esp` 减去 12 之后得到它所需的栈空间，它为 `a` 和 `b` 设置值。在内存中的值展示为十六进制，并且是小端格式，与你从调试器中看到的一样。一旦设置了参数值，`main` 将调用 `add`，并且开始运行：

![](/data/attachment/album/201805/15/183201abvr2pppvhdv8per.png)

现在，有一点小激动！我们进入了另一个函数序言，但这次你可以明确看到栈帧是如何从 `ebp` 到栈建立一个链表。这就是调试器和高级语言中的 `Exception` 对象如何对它们的栈进行跟踪的。当一个新帧产生时，你也可以看到更多这种典型的从 `ebp` 到 `esp` 的捕获。我们再次从 `esp` 中做减法得到更多的栈空间。

当 `ebp` 寄存器的值拷贝到内存时，这里也有一个稍微有些怪异的字节逆转。在这里发生的奇怪事情是，寄存器其实并没有字节顺序：因为对于内存，没有像寄存器那样的“增长的地址”。因此，惯例上调试器以对人类来说最自然的格式展示了寄存器的值：数位从最重要的到最不重要。因此，这个在小端机器中的副本的结果，与内存中常用的从左到右的标记法正好相反。我想用图去展示你将会看到的东西，因此有了下面的图。

在比较难懂的部分，我们增加了注释：

![](/data/attachment/album/201805/15/183206o5k7eaatkiztcevw.png)

这是一个临时寄存器，用于帮你做加法，因此没有什么警报或者惊喜。对于加法这样的作业，栈的动作正好相反，我们留到下次再讲。

对于任何读到这里的人都应该有一个小礼物，因此，我做了一个大的图表展示了 [组合到一起的所有步骤](https://manybutfinite.com/img/stack/callSequence.png)。

一旦把它们全部布置好了，看上起似乎很乏味。这些小方框给我们提供了很多帮助。事实上，在计算机科学中，这些小方框是主要的展示工具。我希望这些图片和寄存器的移动能够提供一种更直观的构想图，将栈的增长和内存的内容整合到一起。从软件的底层运作来看，我们的软件与一个简单的图灵机器差不多。

这就是我们栈探秘的第一部分，再讲一些内容之后，我们将看到构建在这个基础上的高级编程的概念。下周见！

---

via:<https://manybutfinite.com/post/journey-to-the-stack/>

作者：[Gustavo Duarte](http://duartes.org/gustavo/blog/about/) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


从专有到开源的十个简单步骤

Summary: 这个共同福利并不适用于专有软件：保持隐藏的东西是不能照亮或丰富这个世界的。

这个共同福利并不适用于专有软件：保持隐藏的东西是不能照亮或丰富这个世界的。

>
> 这个共同福利并不适用于专有软件：保持隐藏的东西是不能照亮或丰富这个世界的。
>
>
>

![](/data/attachment/album/201805/16/081220tpmrm9gptf75m5u9.jpg)

“开源软件肯定不太安全，因为每个人都能看到它的源代码，而且他们能重新编译它，用他们自己写的不好的东西进行替换。”举手示意：谁之前听说过这个说法？ 注1

当我和客户讨论的时候（是的，他们有时候会让我和客户交谈），对于这个领域 注2 的人来说种问题是很常见的。在前一篇文章中，“[许多只眼睛的审查并不一定能防止错误代码]”，我谈论的是开源软件（尤其是安全软件）并不能神奇地比专有软件更安全，但是和专有软件比起来，我每次还是比较青睐开源软件。但我听到“关于开源软件不是很安全”这种问题表明了有时候只是说“开源需要参与”是不够的，我们也需要积极的参与辩护 注3 。

我并不期望能够达到牛顿或者维特根斯坦的逻辑水平，但是我会尽我所能，而且我会在结尾做个总结，如果你感兴趣的话可以去快速的浏览一下。

### 关键因素

首先，我们必须明白没有任何软件是完美的 注6 。无论是专有软件还是开源软件。第二，我们应该承认确实还是存在一些很不错的专有软件的，以及第三，也存在一些糟糕的开源软件。第四，有很多非常聪明的，很有天赋的，专业的架构师、设计师和软件工程师设计开发了专有软件。

但也有些问题：第五，从事专有软件的人员是有限的，而且你不可能总是能够雇佣到最好的员工。即使在政府部门或者公共组织 —— 他们拥有丰富的人才资源池，但在安全应用这块，他们的人才也是有限的。第六，可以查看、测试、改进、拆解、再次改进和发布开源软件的人总是无限的，而且还包含最好的人才。第七（也是我最喜欢的一条），这群人也包含很多编写专有软件的人才。第八，许多政府或者公共组织开发的软件也都逐渐开源了。

第九，如果你在担心你在运行的软件的不被支持或者来源不明，好消息是：有一批组织 注7 会来检查软件代码的来源，提供支持、维护和补丁更新。他们会按照专利软件模式那样去运行开源软件，你也可以确保你从他们那里得到的软件是正确的软件：他们的技术标准就是对软件包进行签名，以便你可以验证你正在运行的开源软件不是来源不明或者是恶意的软件。

第十（也是这篇文章的重点），当你运行开源软件，测试它，对问题进行反馈，发现问题并且报告的时候，你就是在为<ruby> 共同福利 <rt>  commonwealth </rt></ruby>贡献知识、专业技能以及经验，这就是开源，其因为你的所做的这些而变得更好。如果你是通过个人或者提供支持开源软件的商业组织之一 注8 参与的，你已经成为了这个共同福利的一部分了。开源让软件变得越来越好，你可以看到它们的变化。没有什么是隐藏封闭的，它是完全开放的。事情会变坏吗？是的，但是我们能够及时发现问题并且修复。

这个共同福利并不适用于专有软件：保持隐藏的东西是不能照亮或丰富这个世界的。

我知道作为一个英国人在使用<ruby> 共同福利 <rt>  commonwealth </rt></ruby>这个词的时候要小心谨慎的；它和帝国连接着的，但我所表达的不是这个意思。它不是克伦威尔 注9 在对这个词所表述的意思，无论如何，他是一个有争议的历史人物。我所表达的意思是这个词有“共同”和“福利”连接，福利不是指钱而是全人类都能拥有的福利。

我真的很相信这点的。如果i想从这篇文章中得到一些虔诚信息的话，那应该是第十条 注10 ：共同福利是我们的遗产，我们的经验，我们的知识，我们的责任。共同福利是全人类都能拥有的。我们共同拥有它而且它是一笔无法估量的财富。

### 便利贴

1. （几乎）没有一款软件是完美无缺的。
2. 有很好的专有软件。
3. 有不好的专有软件。
4. 有聪明，有才能，专注的人开发专有软件。
5. 从事开发完善专有软件的人是有限的，即使在政府或者公共组织也是如此。
6. 相对来说从事开源软件的人是无限的。
7. …而且包括很多从事专有软件的人才。
8. 政府和公共组织的人经常开源它们的软件。
9. 有商业组织会为你的开源软件提供支持。
10. 贡献--即使是使用--为开源软件贡献。

### 脚注

* 注1： 好的--你现在可以放下手了
* 注2：这应该大写吗？有特定的领域吗？或者它是如何工作的？我不确定。
* 注3：我有一个英国文学和神学的学位--这可能不会惊讶到我的文章的普通读者 注4 。
* 注4： 我希望不是，因为我说的太多神学了 注5 。但是它经常充满了冗余的，无关紧要的人文科学引用。
* 注5： Emacs，每一次。
* 注6： 甚至是 Emacs。而且我知道有技术能够去证明一些软件的正确性。（我怀疑 Emacs 不能全部通过它们...）
* 注7： 注意这里：我被他们其中之一 [Red Hat](https://www.redhat.com/) 所雇佣，去查看一下--它是一个有趣的工作地方，而且[我们经常在招聘](https://www.redhat.com/en/jobs)。
* 注8： 假设他们完全遵守他们正在使用的开源软件许可证。
* 注9： 昔日的“英格兰、苏格兰、爱尔兰的上帝守护者”--比克伦威尔。
* 注10： 很明显，我选择 Emacs 而不是 Vi 变体。

这篇文章原载于 [Alice, Eve, and Bob - a security blog] 而且已经被授权重新发布。

---

via: <https://opensource.com/article/17/11/commonwealth-open-source>

作者：[Mike Bursell](https://opensource.com/users/mikecamel) 译者：[FelixYFZ](https://github.com/FelixYFZ) 校对：[wxy](https://github.com/wxy)

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


如何在 Linux 终端下检查笔记本电池状态

![](/data/attachment/album/201805/16/082358p32gn2ouvqs5uriu.png)

在图形界面下查看你的笔记本电池状态是很容易的，只需将鼠标指向任务栏中的电池图标上，你便可以很容易地知道电池的电量。但如果我们想要从命令行中获得这些信息呢？并不是所有人都知道如何做到这点。前几天我的一个朋友询问我如何从他的 Ubuntu 系统里，在终端中查看他的笔记本电池的电量。这便是我写这篇文章的起因。在本文中我概括了三种简单的方法来让你在任何 Linux 发行版本中从终端查看笔记本电池的状态。

### 在终端下检查笔记本电池状态

我们可以使用下面的三种方法来从命令行中查找到笔记本电池状态。

#### 方法一 – 使用 upower 命令

`upower` 命令预装在大多数的 Linux 发行版本中。为了使用 `upower` 命令来展示电池的状态，打开终端并运行如下命令：

```
$ upower -i /org/freedesktop/UPower/devices/battery_BAT0

```

示例输出：

```
native-path: BAT0
vendor: Samsung SDI
model: DELL 7XFJJA2
serial: 4448
power supply: yes
updated: Sat 12 May 2018 06:48:48 PM IST (41 seconds ago)
has history: yes
has statistics: yes
battery
present: yes
rechargeable: yes
state: charging
warning-level: none
energy: 43.3011 Wh
energy-empty: 0 Wh
energy-full: 44.5443 Wh
energy-full-design: 48.84 Wh
energy-rate: 9.8679 W
voltage: 12.548 V
time to full: 7.6 minutes
percentage: 97%
capacity: 91.2045%
technology: lithium-ion
icon-name: 'battery-full-charging-symbolic'
History (charge):
1526131128 97.000 charging
History (rate):
1526131128 9.868 charging

```

正如你所看到的那样，我的电池正处于充电状态，并且它的电量百分比是 97%。

假如上面的命令因为某些未知原因不起作用，可以尝试使用下面的命令：

```
$ upower -i `upower -e | grep 'BAT'`

```

示例输出：

```
native-path: BAT0
vendor: Samsung SDI
model: DELL 7XFJJA2
serial: 4448
power supply: yes
updated: Sat 12 May 2018 06:50:49 PM IST (22 seconds ago)
has history: yes
has statistics: yes
battery
present: yes
rechargeable: yes
state: charging
warning-level: none
energy: 43.6119 Wh
energy-empty: 0 Wh
energy-full: 44.5443 Wh
energy-full-design: 48.84 Wh
energy-rate: 8.88 W
voltage: 12.552 V
time to full: 6.3 minutes
percentage: 97%
capacity: 91.2045%
technology: lithium-ion
icon-name: 'battery-full-charging-symbolic'
History (rate):
1526131249 8.880 charging

```

`upower` 不仅可以显示出电池的状态，它还可以显示出已安装电池的其他完整信息，例如电池型号，供应商名称，电池的序列号，电池的状态，电池的电压等信息。

当然，如果你只想显示电池的状态，你可以可以结合使用 `upower` 命令和[grep](https://www.ostechnix.com/the-grep-command-tutorial-with-examples-for-beginners/) 命令，具体命令如下：

```
$ upower -i $(upower -e | grep BAT) | grep --color=never -E "state|to\ full|to\ empty|percentage"

```

示例输出：

```
state: fully-charged
percentage: 100%

```

![](/data/attachment/album/201805/16/082359jln0iht9l99tt07i.png)

从上面的输出中可以看到我的笔记本电池已经完全充满了。

想知晓更多的细节，可以参看 man 页：

```
$ man upower

```

#### 方法二 – 使用 acpi 命令

`acpi` 命令可以用来显示你的 Linux 发行版本中电池的状态以及其他 ACPI 信息。

在某些 Linux 发行版本中，你可能需要安装 `acpi` 命令。

要在 Debian、 Ubuntu 及其衍生版本中安装它，可以使用如下命令：

```
$ sudo apt-get install acpi

```

在 RHEL、 CentOS、 Fedora 等系统中使用：

```
$ sudo yum install acpi

```

或者使用如下命令：

```
$ sudo dnf install acpi

```

在 Arch Linux 及其衍生版本中使用：

```
$ sudo pacman -S acpi

```

一旦 `acpi` 安装好后，运行下面的命令：

```
$ acpi -V

```

注意： 在上面的命令中， `V` 是大写字母。

示例输出：

```
Battery 0: Charging, 99%, 00:02:09 until charged
Battery 0: design capacity 4400 mAh, last full capacity 4013 mAh = 91%
Battery 1: Discharging, 0%, rate information unavailable
Adapter 0: on-line
Thermal 0: ok, 77.5 degrees C
Thermal 0: trip point 0 switches to mode critical at temperature 84.0 degrees C
Cooling 0: Processor 0 of 3
Cooling 1: Processor 0 of 3
Cooling 2: LCD 0 of 15
Cooling 3: Processor 0 of 3
Cooling 4: Processor 0 of 3
Cooling 5: intel_powerclamp no state information available
Cooling 6: x86_pkg_temp no state information available

```

首先让我们来检查电池的电量，可以运行：

```
$ acpi

```

示例输出：

```
Battery 0: Charging, 99%, 00:01:41 until charged
Battery 1: Discharging, 0%, rate information unavailable

```

下面，让我们来查看电池的温度：

```
$ acpi -t

```

示例输出：

```
Thermal 0: ok, 63.5 degrees C

```

如果需要将温度以华氏温标显示，可以使用：

```
$ acpi -t -f

```

示例输出：

```
Thermal 0: ok, 144.5 degrees F

```

如果想看看交流电适配器是否连接上了没有，可以运行：

```
$ acpi -a

```

示例输出：

```
Adapter 0: on-line

```

假如交流电适配器没有连接上，则你将看到如下的输出：

```
Adapter 0: off-line

```

想获取更多的信息，可以查看 man 页：

```
$ man acpi

```

#### 方法三 - 使用 batstat 程序

`batstat` 是一个基于 ncurses 的命令行小工具，使用它可以在类 Unix 系统中展示笔记本电池状态。它可以展示如下具体信息：

* 当前电池电量
* 当前电池所存能量
* 充满时所存能量
* 从程序启动开始经历的时间，它不会追踪记录机器休眠的时间
* 电池电量消耗历史数据

安装 `batstat` 轻而易举。使用下面的命令来克隆该程序的最新版本：

```
$ git clone https://github.com/Juve45/batstat.git

```

上面的命令将拉取 `batstat` 的最新版本并将它的内容保存在一个名为 `batstat` 的文件夹中。

首先将目录切换到 `batstat/bin/` 中：

```
$ cd batstat/bin/

```

接着将 `batstat` 二进制文件复制到 `PATH` 环境变量中的某个目录中，例如 `/usr/local/bin/` 目录：

```
$ sudo cp batstat /usr/local/bin/

```

使用下面的命令来让它可被执行：

```
$ sudo chmod +x /usr/local/bin/batstat

```

最后，使用下面的命令来查看你的电池状态。

```
$ batstat

```

示例输出：

![](/data/attachment/album/201805/16/082401molzolooflqrm3mo.png)

从上面的截图中可以看到我的笔记本电池正处于充电状态。

这个小工具还有某些小的限制。在书写本文之时，`batstat` 仅支持显示一个电池的相关信息。而且它只从 `/sys/class/power_supply/` 目录搜集相关的信息。假如你的电池信息被存放在另外的目录中，则这个小工具就不会起作用了。

想知晓更多信息，可以查看 `batstat` 的 [GitHub 主页](https://github.com/Juve45/batstat)。

上面就是今天我要分享的所有内容。当然，可能还有很多其他的命令或者程序来从 Linux 终端检查笔记本的电池状态。据我所知，上面给出的命令都运行良好。假如你知道其他命令来查看电池的状态，请在下面的评论框中让我们知晓。假如你所给出的方法能够起作用，我将对我的这篇文章进行更新。

最后，上面便是今天的全部内容了。更多的优质内容敬请期待，敬请关注！

欢呼吧!

---

via: <https://www.ostechnix.com/how-to-check-laptop-battery-status-in-terminal-in-linux/>

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

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


如何在 Linux 中使用 find

Summary: 使用正确的参数，find 命令是在你的系统上找到数据的强大而灵活的方式。

使用正确的参数，find 命令是在你的系统上找到数据的强大而灵活的方式。

>
> 使用正确的参数，`find` 命令是在你的系统上找到数据的强大而灵活的方式。
>
>
>

![](/data/attachment/album/201805/16/083712gelll7esoold7o7l.png)

在[最近的一篇文章](/article-9585-1.html)中，Lewis Cowles 介绍了 `find` 命令。

`find` 是日常工具箱中功能更强大、更灵活的命令行工具之一，因此值得花费更多的时间。

最简单的，`find` 跟上路径寻找一些东西。例如：

```
find /

```

它将找到（并打印出）系统中的每个文件。而且由于一切都是文件，你会得到很多需要整理的输出。这可能不能帮助你找到你要找的东西。你可以改变路径参数来缩小范围，但它不会比使用 `ls` 命令更有帮助。所以你需要考虑你想要找的东西。

也许你想在主目录中找到所有的 JPEG 文件。 `-name` 参数允许你将结果限制为与给定模式匹配的文件。

```
find ~ -name '*jpg'

```

可是等等！如果它们中的一些是大写的扩展名会怎么样？`-iname` 就像 `-name`，但是不区分大小写。

```
find ~ -iname '*jpg'

```

很好！但是 8.3 名称方案是如此的老。一些图片可能是 .jpeg 扩展名。幸运的是，我们可以将模式用“或”（表示为 `-o`）来组合。

```
find ~ ( -iname 'jpeg' -o -iname 'jpg' )

```

我们正在接近目标。但是如果你有一些以 jpg 结尾的目录呢？ （为什么你要命名一个 `bucketofjpg` 而不是 `pictures` 的目录就超出了本文的范围。）我们使用 `-type` 参数修改我们的命令来查找文件。

```
find ~ \( -iname '*jpeg' -o -iname '*jpg' \) -type f

```

或者，也许你想找到那些命名奇怪的目录，以便稍后重命名它们：

```
find ~ \( -iname '*jpeg' -o -iname '*jpg' \) -type d

```

你最近拍了很多照片，所以让我们把它缩小到上周更改的文件。

```
find ~ \( -iname '*jpeg' -o -iname '*jpg' \) -type f -mtime -7

```

你可以根据文件状态更改时间 （`ctime`）、修改时间 （`mtime`） 或访问时间 （`atime`） 来执行时间过滤。 这些是在几天内，所以如果你想要更细粒度的控制，你可以表示为在几分钟内（分别是 `cmin`、`mmin` 和 `amin`）。 除非你确切地知道你想要的时间，否则你可能会在 `+` （大于）或 `-` （小于）的后面加上数字。

但也许你不关心你的照片。也许你的磁盘空间不够用，所以你想在 `log` 目录下找到所有巨大的（让我们定义为“大于 1GB”）文件：

```
find /var/log -size +1G

```

或者，也许你想在 `/data` 中找到 bcotton 拥有的所有文件：

```
find /data -owner bcotton

```

你还可以根据权限查找文件。也许你想在你的主目录中找到对所有人可读的文件，以确保你不会过度分享。

```
find ~ -perm -o=r

```

这篇文章只说了 `find` 能做什么的表面。将测试条件与布尔逻辑相结合可以为你提供难以置信的灵活性，以便准确找到要查找的文件。并且像 `-exec` 或 `-delete` 这样的参数，你可以让 `find` 对它发现的内容采取行动。你有任何最喜欢的 `find` 表达式么？在评论中分享它们！

---

via: <https://opensource.com/article/18/4/how-use-find-linux>

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


在 5 分钟内重置丢失的 root 密码

>
> 如何快速简单地在 Fedora 、 CentOS 及类似的 Linux 发行版上重置 root 密码。
>
>
>

![](/data/attachment/album/201805/17/090716ijbddjjptmudu9de.jpg)

系统管理员可以轻松地为忘记密码的用户重置密码。但是如果系统管理员忘记 root 密码或他从公司离职了，会发生什么情况？本指南将向你介绍如何在不到 5 分钟的时间内在 Red Hat 兼容系统（包括 Fedora 和 CentOS）上重置丢失或忘记的 root 密码。

请注意，如果整个系统硬盘已用 LUKS 加密，则需要在出现提示时提供 LUKS 密码。此外，此过程适用于运行 systemd 的系统，该系统自 Fedora 15、CentOS 7.14.04 和 Red Hat Enterprise Linux 7.0 以来一直是缺省的初始系统。

首先你需要中断启动的过程，因此你需要启动或者如果已经启动就重启它。第一步可能有点棘手因为 GRUB 菜单会在屏幕上快速地闪烁过去。你可能需要尝试几次，直到你能够做到这一点。

当你看到这个屏幕时，按下键盘上的 `e` 键：

![](/data/attachment/album/201805/17/090246xolkqql77l88aky8.png)

如果你正确地做了这点，你应该看到一个类似于这个的屏幕：

![](/data/attachment/album/201805/17/090247kgmghcn1jtmmlgd6.png)

使用箭头键移动到 `Linux16` 这行：

![](/data/attachment/album/201805/17/090247nwoy8mkbq7qb7hdh.png)

使用你的 `del` 键或你的 `backspace` 键，删除 `rhgb quiet` 并替换为以下内容：

```
rd.break enforcing=0

```

![](/data/attachment/album/201805/17/090247z3lrrglyur7373ui.png)

设置 `enforcing=0` 可以避免执行完整的系统 SELinux 重标记。一旦系统重新启动，你只需要为 `/etc/shadow` 恢复正确的 SELinux 上下文。我会告诉你如何做到这一点。

按下 `Ctrl-x` 启动。

**系统现在将处于紧急模式。**

以读写权限重新挂载硬盘驱动器：

```
# mount –o remount,rw /sysroot

```

运行 `chroot` 来访问系统：

```
# chroot /sysroot

```

你现在可以更改 root 密码：

```
# passwd

```

出现提示时，输入新的 root 密码两次。如果成功，你应该看到一条消息显示 “all authentication tokens updated successfully”。

输入 `exit` 两次以重新启动系统。

以 root 身份登录并恢复 `/etc/shadow` 的 SELinux 标签。

```
# restorecon -v /etc/shadow

```

将 SELinux 回到 enforce 模式：

```
# setenforce 1

```

---

via: <https://opensource.com/article/18/4/reset-lost-root-password>

作者：[Curt Warfield](https://opensource.com/users/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/) 荣誉推出


使用 syslog-ng 可靠地记录物联网事件

Summary: 用增强的日志守护进程 syslog-ng 来监控你的物联网设备。

用增强的日志守护进程 syslog-ng 来监控你的物联网设备。

>
> 用增强的日志守护进程 syslog-ng 来监控你的物联网设备。
>
>
>

![](/data/attachment/album/201805/17/094849iinnwxitxxn6tbtw.jpg)

现在，物联网设备和嵌入式系统越来越多。对于许多连接到因特网或者一个网络的设备来说，记录事件很有必要，因为你需要知道这些设备都做了些什么事情，这样你才能够解决可能出现的问题。

可以考虑去使用的一个监视工具是开源的 [syslog-ng](https://syslog-ng.com/open-source-log-management) 应用程序，它是一个强化的、致力于可移植的、中心化的日志收集守护程序。它可以从许多不同种类的来源、进程来收集日志，并且可以对这些日志进行处理和过滤，也可以存储或者路由它们，以便于做进一步的分析。syslog-ng 的大多数代码是用高效率的、高可移植的 C 代码写成的。它能够适用于各种场景，无论你是将它运行在一个处理能力很弱的设备上做一些简单的事情，还是运行在数据中心从成千上万的机器中收集日志的强大应用，它都能够胜任。

你可能注意到在这个段落中，我使用了大量的溢美词汇。为了让你更清晰地了解它，我们来复习一下，但这将花费更多的时间，也了解的更深入一些。

### 日志

首先解释一下日志。<ruby> 日志 <rt>  logging </rt></ruby>是记录一台计算机上事件的东西。在一个典型的 Linux 机器上，你可以在 `/var/log` 目录中找到这些信息。例如，如果你通过 SSH 登录到机器中，你将可以在其中一个日志文件中找到类似于如下内容的信息：

```
Jan 14 11:38:48 linux-0jbu sshd[7716]: Accepted publickey for root from 127.0.0.1 port 48806 ssh2

```

日志的内容可能是关于你的 CPU 过热、通过 HTTP 下载了一个文档，或者你的应用程序认为重要的任何东西。

### syslog-ng

正如我在上面所写的那样，syslog-ng 应用程序是一个强化的、致力于可移植性、和中心化的日志收集守护程序。守护程序的意思是，syslog-ng 是一个持续运行在后台的应用程序，在这里，它用于收集日志信息。

虽然现在大多数应用程序的 Linux 测试是限制在 x86\_64 的机器上，但是，syslog-ng 也可以运行在大多数 BSD 和商业 UNIX 变种版本上的。从嵌入式/物联网的角度来看，这种能够运行在不同的 CPU 架构（包括 32 位和 64 位的 ARM、PowerPC、MIPS 等等）的能力甚至更为重要。（有时候，我通过阅读关于 syslog-ng 是如何使用它们的来学习新架构）

为什么中心化的日志收集如此重要？其中一个很重要的原因是易于使用，因为它放在一个地方，不用到成百上千的机器上挨个去检查它们的日志。另一个原因是可用性 —— 即使一个设备不论是什么原因导致了它不可用，你都可以检查这个设备的日志信息。第三个原因是安全性；当你的设备被黑，检查设备日志可以发现攻击的踪迹。

### syslog-ng 的四种用法

syslog-ng 有四种主要的用法：收集、处理、过滤、和保存日志信息。

**收集信息：** syslog-ng 能够从各种各样的 [特定平台源](https://syslog-ng.com/documents/html/syslog-ng-ose-latest-guides/en/syslog-ng-ose-guide-admin/html/sources.html) 上收集信息，比如 `/dev/log`，`journal`，或者 `sun-streams`。作为一个中心化的日志收集器，传统的（`rfc3164`）和最新的（`rfc5424`）系统日志协议、以及它们基于 UDP、TCP 和加密连接的各种变种，它都是支持的。你也可以从管道、套接字、文件、甚至应用程序输出来收集日志信息（或者各种文本数据）。

**处理日志信息：** 它的处理能力几乎是无限的。你可以用它内置的解析器来分类、规范，以及结构化日志信息。如果它没有为你提供在你的应用场景中所需要的解析器，你甚至可以用 Python 来自己写一个解析器。你也可以使用地理数据来丰富信息，或者基于信息内容来附加一些字段。日志信息可以按处理它的应用程序所要求的格式进行重新格式化。你也可以重写日志信息 —— 当然了，不是篡改日志内容 —— 比如在某些情况下，需要满足匿名要求的信息。

**过滤日志：** 过滤日志的用法主要有两种：丢弃不需要保存的日志信息 —— 像调试级别的信息；和路由日志信息—— 确保正确的日志到达正确的目的地。后一种用法的一个例子是，转发所有的认证相关的信息到一个安全信息与事件管理系统（SIEM）。

**保存信息：** 传统的做法是，将文件保存在本地或者发送到中心化日志服务器；不论是哪种方式，它们都被发送到一个[普通文件](https://en.wikipedia.org/wiki/Flat_file_database)。经过这些年的改进，syslog-ng 已经开始支持 SQL 数据库，并且在过去的几年里，包括 HDFS、Kafka、MongoDB、和 Elasticsearch 在内的大数据存储，都被加入到 syslog-ng 的支持中。

### 消息格式

当在你的 `/var/log` 目录中查看消息时，你将看到（如上面的 SSH 信息）大量的消息都是如下格式的内容：

```
日期 + 主机名 + 应用名 + 一句几乎完整的英文信息

```

在这里的每个应用程序事件都是用不同的语法描述的，基于这些数据去创建一个报告是个痛苦的任务。

解决这种混乱信息的一个方案是使用结构化日志。在这种情况下，事件被表示为键-值对，而不是随意的日志信息。比如，一个 SSH 日志能够按应用程序名字、源 IP 地址、用户名、认证方法等等来描述。

你可以从一开始就对你的日志信息按合适的格式进行结构化处理。当处理传统的日志信息时，你可以在 syslog-ng 中使用不同的解析器，转换非结构化（和部分结构化）的信息为键-值对格式。一旦你的日志信息表示为键-值对，那么，报告、报警、以及简单查找信息将变得很容易。

### 物联网日志

我们从一个棘手的问题开始：哪个版本的 syslog-ng 最流行？在你回答之前，想想如下这些事实：这个项目启动于 20 年以前，Red Hat 企业版 Linux EPEL 已经有了 3.5 版，而当前版本是 3.14。当我在我的演讲中问到这个问题时，观众通常回答是他们用的 Linux 发行版中自带的那个。你们绝对想不到的是，正确答案竟然是 1.6 版最流行，这个版本已经有 15 年的历史的。这什么这个版本是最为流行的，因为它是包含在亚马逊 Kindle 阅读器中的版本，它是电子书阅读器，因为它运行在全球范围内超过 1 亿台的设备上。另外一个在消费类设备上运行 syslog-ng 的例子是 BMW i3 电动汽车。

Kindle 使用 syslog-ng 去收集关于用户在这台设备上都做了些什么事情等所有可能的信息。在 BMW 电动汽车上，syslog-ng 所做的事情更复杂，基于内容过滤日志信息，并且在大多数情况下，只记录最重要的日志。

使用 syslog-ng 的其它类别设备还有网络和存储。一些比较知名的例子有，Turris Omnia 开源 Linux 路由器和群晖 NAS 设备。在大多数案例中，syslog-ng 是在设备上作为一个日志客户端来运行，但是在有些案例中，它运行为一个有丰富 Web 界面的中心日志服务器。

你还可以在一些行业服务中找到 syslog-ng 的身影。它运行在来自美国国家仪器有限公司（NI）的实时 Linux 设备上，执行测量和自动化任务。它也被用于从定制开发的应用程序中收集日志。从命令行就可以做配置，但是一个漂亮的 GUI 可用于浏览日志。

最后，还有大量的项目，比如，汽车和飞机，syslog-ng 在它们上面既可以运行为客户端，也可以运行为服务端。在这种使用案例中，syslog-ng 一般用来收集所有的日志和测量数据，然后发送它们到处理这些日志的中心化服务器集群上，然后保存它们到支持大数据的目的地，以备进一步分析。

### 对物联网的整体益处

在物联网环境中使用 syslog-ng 有几个好处。第一，它的分发性能很高，并且是一个可靠的日志收集器。第二，它的架构也很简单，因此，系统、应用程序日志、以及测量数据可以被一起收集。第三，它使数据易于使用，因为，数据可以被解析和表示为易于使用的格式。最后，通过 syslog-ng 的高效路由和过滤功能，可以显著降低处理程序的负载水平。

---

via: <https://opensource.com/article/18/3/logging-iot-events-syslog-ng>

作者：[Peter Czanik](https://opensource.com/users/czanik) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


在 KVM 中测试 IPv6 网络：第 2 部分

![](/data/attachment/album/201805/17/215300wph170t9ltmgmt93.png)

我们又见面了，在上一篇 [在 KVM 中测试 IPv6 网络：第 1 部分](/article-9594-1.html) 中，我们学习了有关 IPv6 私有地址的内容。今天，我们将使用 KVM 创建一个网络，去测试上一星期学习的 IPv6 的内容。

如果你想重新温习如何使用 KVM，可以查看 [在 KVM 中创建虚拟机：第 1 部分](https://www.linux.com/learn/intro-to-linux/2017/5/creating-virtual-machines-kvm-part-1) 和 [在 KVM 中创建虚拟机：第 2 部分— 网络](https://www.linux.com/learn/intro-to-linux/2017/5/creating-virtual-machines-kvm-part-2-networking)。

### 在 KVM 中创建网络

在 KVM 中你至少需要两个虚拟机。当然了，如果你愿意，也可以创建更多的虚拟机。在我的系统中有 Fedora、Ubuntu、以及 openSUSE。去创建一个新的 IPv6 网络，在主虚拟机管理窗口中打开 “Edit > Connection Details > Virtual Networks”。点击左下角的绿色十字按钮去创建一个新的网络（图 1）。

![](/data/attachment/album/201805/17/215302kxj4ehu2xx41dmy1.png)

*图 1：创建一个网络*

给新网络输入一个名字，然后，点击 “Forward” 按钮。如果你愿意，也可以不创建 IPv4 网络。当你创建一个新的 IPv4 网络时，虚拟机管理器将不让你创建重复网络，或者是使用了一个无效地址。在我的宿主机 Ubuntu 系统上，有效的地址是以绿色高亮显示的，而无效地址是使用高亮的玫瑰红色调。在我的 openSUSE 机器上没有高亮颜色。启用或不启用 DHCP，以及创建或不创建一个静态路由，然后进入下一个窗口。

选中 “Enable IPv6 network address space definition”，然后输入你的私有地址范围。你可以使用任何你希望的 IPv6 地址类，但是要注意，不能将你的实验网络泄漏到公网上去。我们将使用非常好用的 IPv6 唯一本地地址（ULA），并且使用在 [Simple DNS Plus](http://simpledns.com/private-ipv6.aspx) 上的在线地址生成器，去创建我们的网络地址。拷贝 “Combined/CID” 地址到网络框中（图 2）。

![network address](/data/attachment/album/201805/17/215303egnh1euqueh5t9s1.png "network address")

*图 2：拷贝 "Combined/CID" 地址到网络框中*

虚拟机认为我的地址是无效的，因为，它显示了高亮的玫瑰红色。它做的对吗？我们使用 `ipv6calc` 去验证一下：

```
$ ipv6calc -qi fd7d:844d:3e17:f3ae::/64
Address type: unicast, unique-local-unicast, iid, iid-local
Registry for address: reserved(RFC4193#3.1)
Address type has SLA: f3ae
Interface identifier: 0000:0000:0000:0000
Interface identifier is probably manual set

```

`ipv6calc` 认为没有问题。如果感兴趣，你可以改变其中一个数字为无效的东西，比如字母 `g`，然后再试一次。（问 “如果…？”，试验和错误是最好的学习方法）。

我们继续进行，启用 DHCPv6（图 3）。你可以接受缺省值，或者输入一个你自己的设置值。

![](/data/attachment/album/201805/17/215304ly6uy27d06mez1e8.png)

*图 3： 启用 DHCPv6*

我们将跳过缺省路由定义这一步，继续进入下一屏，在那里我们将启用 “Isolated Virtual Network” 和 “Enable IPv6 internal routing/networking”。

### 虚拟机网络选择

现在，你可以配置你的虚拟机去使用新的网络。打开你的虚拟机，然后点击顶部左侧的 “i” 按钮去打开 “Show virtual hardware details” 屏幕。在 “Add Hardware” 列点击 “NIC” 按钮去打开网络选择器，然后选择你喜欢的新的 IPv6 网络。点击 “Apply”，然后重新启动。（或者使用你喜欢的方法去重新启动网络，或者更新你的 DHCP 租期。）

### 测试

`ifconfig` 告诉我们它做了什么？

```
$ ifconfig
ens3: flags=4163 UP,BROADCAST,RUNNING,MULTICAST  mtu 1500
 inet 192.168.30.207  netmask 255.255.255.0
   broadcast 192.168.30.255
 inet6 fd7d:844d:3e17:f3ae::6314
   prefixlen 128  scopeid 0x0
 inet6 fe80::4821:5ecb:e4b4:d5fc
   prefixlen 64  scopeid 0x20

```

这是我们新的 ULA，`fd7d:844d:3e17:f3ae::6314`，它是自动生成的本地链路地址。如果你有兴趣，可以 ping 一下，ping 网络上的其它虚拟机：

```
vm1 ~$ ping6 -c2 fd7d:844d:3e17:f3ae::2c9f
PING fd7d:844d:3e17:f3ae::2c9f(fd7d:844d:3e17:f3ae::2c9f) 56 data bytes
64 bytes from fd7d:844d:3e17:f3ae::2c9f: icmp_seq=1 ttl=64 time=0.635 ms
64 bytes from fd7d:844d:3e17:f3ae::2c9f: icmp_seq=2 ttl=64 time=0.365 ms

vm2 ~$ ping6 -c2 fd7d:844d:3e17:f3ae:a:b:c:6314
PING fd7d:844d:3e17:f3ae:a:b:c:6314(fd7d:844d:3e17:f3ae:a:b:c:6314) 56 data bytes
64 bytes from fd7d:844d:3e17:f3ae:a:b:c:6314: icmp_seq=1 ttl=64 time=0.744 ms
64 bytes from fd7d:844d:3e17:f3ae:a:b:c:6314: icmp_seq=2 ttl=64 time=0.364 ms

```

当你努力去理解子网时，这是一个可以让你尝试不同地址是否可以正常工作的快速易用的方法。你可以给单个接口分配多个 IP 地址，然后 ping 它们去看一下会发生什么。在一个 ULA 中，接口，或者主机是 IP 地址的最后四部分，因此，你可以在那里做任何事情，只要它们在同一个子网中即可，在那个例子中是 `f3ae`。在我的其中一个虚拟机上，我只改变了这个示例的接口 ID，以展示使用这四个部分，你可以做任何你想做的事情：

```
vm1 ~$ sudo /sbin/ip -6 addr add fd7d:844d:3e17:f3ae:a:b:c:6314 dev ens3

vm2 ~$ ping6 -c2 fd7d:844d:3e17:f3ae:a:b:c:6314
PING fd7d:844d:3e17:f3ae:a:b:c:6314(fd7d:844d:3e17:f3ae:a:b:c:6314) 56 data bytes
64 bytes from fd7d:844d:3e17:f3ae:a:b:c:6314: icmp_seq=1 ttl=64 time=0.744 ms
64 bytes from fd7d:844d:3e17:f3ae:a:b:c:6314: icmp_seq=2 ttl=64 time=0.364 ms

```

现在，尝试使用不同的子网，在下面的示例中使用了 `f4ae` 代替 `f3ae`：

```
$ ping6 -c2 fd7d:844d:3e17:f4ae:a:b:c:6314
PING fd7d:844d:3e17:f4ae:a:b:c:6314(fd7d:844d:3e17:f4ae:a:b:c:6314) 56 data bytes
From fd7d:844d:3e17:f3ae::1 icmp_seq=1 Destination unreachable: No route
From fd7d:844d:3e17:f3ae::1 icmp_seq=2 Destination unreachable: No route

```

这也是练习路由的好机会，以后，我们将专门做一期，如何在不使用 DHCP 情况下实现自动寻址。

---

via: <https://www.linux.com/learn/intro-to-linux/2017/11/testing-ipv6-networking-kvm-part-2>

作者：[CARLA SCHRODER](https://www.linux.com/users/cschroder) 选题：[lujun9972](https://github.com/lujun9972) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


成为你所在社区的美好力量

Summary: 明白如何传递美好，了解积极意愿的力量，以及更多。

明白如何传递美好，了解积极意愿的力量，以及更多。

>
> 明白如何传递美好，了解积极意愿的力量，以及更多。
>
>
>

![Be a force for good in your community](/data/attachment/album/201805/17/224122lcp16v5ipkgfuvs1.png)

激烈的争论是开源社区和开放组织的标志特征之一。在好的时候，这些争论充满活力和建设性。他们面红耳赤的背后其实是幽默和善意。各方实事求是，共同解决问题，推动持续改进。对我们中的许多人来说，他们只是单纯的喜欢而已。

然而在那些不好的日子里，这些争论演变成了对旧话题的反复争吵。或者我们用各种方式来传递伤害和相互攻击，或是使用卑劣的手段，而这些侵蚀着我们社区的激情、信任和生产力。

我们茫然四顾，束手无策，因为社区的对话开始变得有毒。然而，正如 [DeLisa Alexander 最近的分享](https://opensource.com/business/15/5/5-ways-promote-inclusive-environment)，我们每个人都有很多方法可以成为我们社区的一种力量。

在这个“开源文化”系列的第一篇文章中，我将分享一些策略，教你如何在这个关键时刻进行干预，引导每个人走向更积极、更有效率的方向。

### 不要将人推开，而是将人推向前方

最近，我和我的朋友和同事 [Mark Rumbles](https://twitter.com/leadership_365) 一起吃午饭。多年来，我们在许多支持开源文化和引领 Red Hat 的项目中合作。在这一天，Mark 问我，他看到我最近介入了一个邮件列表的对话，当其中的辩论越来越过分时我是怎么坚持的。

幸运的是，这事早已尘埃落定，事实上我几乎忘记了谈话的内容。然而，它让我们开始讨论如何在一个拥有数千名成员的社区里，公开和坦率的辩论。

Mark 说了一些让我印象深刻的话。他说:“你知道，作为一个社区，我们真的很擅长将人推开。但我想看到的是，我们更多的是互相扶持 *向前* 。”

Mark 是绝对正确的。在我们的社区里，我们成为一种美好力量的最好的方法之一就是：以一种迫使每个人提升他们的行为的方式回应冲突，而不是使冲突升级的方式。

### 积极意愿假想

我们可以从一个简单的假想开始，当我们在一个激烈的对话中观察到不良行为时：完全有可能该不良行为其实有着积极意愿。

诚然，这不是一件容易的事情。当我看到一场辩论正在变得肮脏的迹象时，我停下来问自己，史蒂芬·科维（Steven Covey）所说的人性化问题是什么：

>
> “为什么一个理性、正直的人会做这样的事情？”
>
>
>

现在，如果他是你的一个“普通的观察对象”—— 一个有消极行为倾向的社区成员——也许你的第一个想法是，“嗯，也许这个人是个不靠谱，不理智的人”

回过头来说。我并不是说你让你自欺欺人。这其实就是人性化的问题，不仅是因为它让你理解别人的立场，它还让你变得人性化。

而这反过来又能帮助你做出反应，或者从最有效率的地方进行干预。

### 寻求了解社区异议的原因

当我再一次问自己为什么一个理性的、正直的人可能会做这样的事情时，归结为几个原因:

* 他认为没人聆听他
* 他认为没人尊重他
* 他认为没人理解他

一个简单的积极意愿假想，我们可以适用于几乎所有的不良行为，其实就是那个人想要被聆听，被尊重，或被理解。我想这是相当合理的。

通过站在这个更客观、更有同情心的角度，我们可以看到他们的行为几乎肯定 ***不会*** 帮助他们得到他们想要的东西，而社区也会因此而受到影响。如果没有我们的帮助的话。

对我来说，这激发了一个愿望：帮助每个人从我们所处的这个丑陋的地方“摆脱困境”。

在我介入之前，我问自己一个后续的问题：是否有其他积极的意图可能会驱使这种行为

容易想到的例子包括:

* 他们担心我们错过了一些重要的东西，或者我们犯了一个错误，没有人能看到它。
* 他们想感受到自己的贡献的价值。
* 他们精疲力竭，因为在社区里工作过度或者在他们的个人生活中发生了一些事情。
* 他们讨厌一些东西被破坏，并感到沮丧，因为没有人能看到造成的伤害或不便。
* ……诸如此类。

有了这些，我就有了丰富的积极的意图假想，我可以为他们的行为找到原因。我准备伸出援助之手，向他们提供一些帮助。

### 传递美好，挣脱泥潭

什么是 an out？（LCTT 译注：类似与佛家“解脱法门”的意思）把它想象成一个逃跑的门。这是一种退出对话的方式，或者放弃不良的行为，恢复表现得像一个体面的人，而不是丢面子。是叫某人振作向上，而不是叫他走开。

你可能经历过这样的事情，在你的生活中，当 *你* 在一次谈话中表现不佳时，咆哮着，大喊大叫，对某事大惊小怪，而有人慷慨地给 *你* 提供了一个台阶下。也许他们选择不去和你“抬杠”，相反，他们说了一些表明他们相信你是一个理性、正直的人，他们采用积极意愿假想，比如:

>
> 所以，嗯，我听到的是你真的很担心，你很沮丧，因为似乎没有人在听。或者你担心我们忽略了它的重要性。是这样对吧？
>
>
>

于是乎：即使这不是完全正确的（也许你的意图不那么高尚），在那一刻，你可能抓住了他们提供给你的台阶，并欣然接受了重新定义你的不良行为的机会。你几乎可以肯定地转向一个更富有成效的角度，甚至你自己可能都没有意识到。

也许你这样说，“哦，虽然不完全是这样，但我只是担心，我们这样会走向歧途，我明白你说的，作为社区，我们不能同时解决所有问题，但如果我们不尽快解决这个问题，会有更多不好的事情要发生……”

最后，谈话几乎可以肯定地开始转移到一个更有效率的方向。

我们都有机会让一个沮丧的人挣脱泥潭，而这就是方法。

### 坏行为还是坏人？

如果这个人特别激动，他们可能不会听到或者接受你给出的第一个台阶。没关系。最可能的是，他们迟钝的大脑已经被史前曾经对人类生存至关重要的杏仁体接管了，他们需要更多的时间来认识到你并不是一个威胁。只是需要你保持温和的态度，坚定地对待他们，就好像他们 *曾经是* 一个理性、正直的人，看看会发生什么。

根据我的经验，这些社区干预以三种方式结束:

大多数情况下，这个人实际上 *是* 一个理性的人，很快，他们就感激地接受了这个事实。在这个过程中，每个人都跳出了“黑与白”，“赢或输”的心态。人们开始思考创造性的选择和“双赢”的结果，每个人都将受益。

>
> 为什么一个理性、正直的人会做这样的事呢？
>
>
>

有时候，这个人天生不是特别理性或正直的，但当他被你以如此一致的、不知疲倦的、耐心的慷慨和善良的对待的时候，他们就会羞愧地从谈话中撤退。这听起来像是，“嗯，我想我已经说了所有要说的了。谢谢你听我的意见”。或者，对于不那么开明的人来说，“嗯，我厌倦了这种谈话。让我们结束吧。”（好的，谢谢）。

更少的情况是，这个人是一个“*坏人*”，或者在社区管理圈子里，是一个“搅屎棍”。这些人确实存在，而且他们在演戏方面很有发展。你猜怎么着？通过持续地以一种友善、慷慨、以社区为中心的方式，完全无视所有试图使局势升级的尝试，你有效地将谈话变成了一个对他们没有兴趣的领域。他们别无选择，只能放弃它。你成为赢家。

这就是积极意愿假想的力量。通过对愤怒和充满敌意的言辞做出回应，优雅而有尊严地回应，你就能化解一场战争，理清混乱，解决棘手的问题，而且在这个过程中很有可能会交到一个新朋友。

我每次应用这个原则都成功吗？见鬼，不会。但我从不后悔选择了积极意愿。但是我能生动的回想起，当我采用消极意愿假想时，将问题变得更糟糕的场景。

现在轮到你了。我很乐意听到你提出的一些策略和原则，当你的社区里的对话变得激烈的时候，要成为一股好力量。在下面的评论中分享你的想法。

下次，我们将探索更多的方法，在你的社区里成为一个美好力量，我将分享一些处理“坏脾气先生”的技巧。

---

作者简介：

<ruby> 丽贝卡·费尔南德斯 <rp>  （ </rp> <rt>  Rebecca Fernandez </rt> <rp>  ） </rp></ruby>是红帽公司的首席就业品牌 + 通讯专家，是《开放组织》书籍的贡献者，也是开源决策框架的维护者。她的兴趣是开源和业务管理模型的开源方式。Twitter：@ruhbehka

---

via: <https://opensource.com/open-organization/17/1/force-for-good-community>

作者：[Rebecca Fernandez](https://opensource.com/users/rebecca) 译者：[chao-zhi](https://github.com/chao-zhi) 校对：[wxy](https://github.com/wxy)

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


使用树莓派和 projectx/os 托管你自己的电子邮件

Summary: 这个开源项目可以通过低成本的服务器设施帮助你保护你的数据隐私和所有权。

这个开源项目可以通过低成本的服务器设施帮助你保护你的数据隐私和所有权。

>
> 这个开源项目可以通过低成本的服务器设施帮助你保护你的数据隐私和所有权。
>
>
>

![](/data/attachment/album/201805/18/120617zeoe2re6jo8eozt2.jpg)

现在有大量的理由，不能再将存储你的数据的任务委以他人之手，也不能在第三方公司运行你的服务；隐私、所有权，以及防范任何人拿你的数据去“赚钱”。但是对于大多数人来说，自己去运行一个服务器，是件即费时间又需要太多的专业知识的事情。不得已，我们只能妥协。抛开这些顾虑，使用某些公司的云服务，随之而来的就是广告、数据挖掘和售卖、以及其它可能的任何东西。

[projectx/os](https://git.sigbus.net/projectx/os) 项目就是要去除这种顾虑，它可以在家里毫不费力地做服务托管，并且可以很容易地创建一个类似于 Gmail 的帐户。实现上述目标，你只需一个 $35 的树莓派 3 和一个基于 Debian 的操作系统镜像 —— 并且不需要很多的专业知识。仅需要四步就可以实现：

1. 解压缩一个 ZIP 文件到 SD 存储卡中。
2. 编辑 SD 卡上的一个文本文件以便于它连接你的 WiFi（如果你不使用有线网络的话）。
3. 将这个 SD 卡插到树莓派 3 中。
4. 使用你的智能手机在树莓派 3 上安装 “email 服务器” 应用并选择一个二级域。

服务器应用程序（比如电子邮件服务器）被分解到多个容器中，它们中的每个都只能够使用指定的方式与外界通讯，它们使用了管理粒度非常细的隔离措施以提高安全性。例如，入站 SMTP、[SpamAssassin](http://spamassassin.apache.org/)（反垃圾邮件平台）、[Dovecot](https://www.dovecot.org/) （安全的 IMAP 服务器），以及 webmail 都使用了独立的容器，它们之间相互不能看到对方的数据，因此，单个守护进程出现问题不会波及其它的进程。

另外，它们都是无状态容器，比如 SpamAssassin 和入站 SMTP，每次收到电子邮件之后，它们的容器都会被销毁并重建，因此，即便是有人找到了 bug 并利用了它，他们也不能访问以前的电子邮件或者接下来的电子邮件；他们只能访问他们自己挖掘出漏洞的那封电子邮件。幸运的是，大多数对外发布的、最容易受到攻击的服务都是隔离的和无状态的。

所有存储的数据都使用 [dm-crypt](https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt) 进行加密。非公开的服务，比如 Dovecot（IMAP）或者 webmail，都是在内部监听，并使用 [ZeroTier One](https://www.zerotier.com/download.shtml) 所提供的私有的加密层叠网络，因此只有你的设备（智能手机、笔记本电脑、平板等等）才能访问它们。

虽然电子邮件并不是端到端加密的（除非你使用了 [PGP](https://en.wikipedia.org/wiki/Pretty_Good_Privacy)），但是非加密的电子邮件绝不会跨越网络，并且也不会存储在磁盘上。现在明文的电子邮件只存在于双方的私有邮件服务器上，它们都在他们的家中受到很好的安全保护并且只能通过他们的客户端访问（智能手机、笔记本电脑、平板等等）。

另一个好处就是，个人设备都使用一个密码保护（不是指纹或者其它生物识别技术），而且在你家中的设备都受到美国的 [第四宪法修正案](https://simple.wikipedia.org/wiki/Fourth_Amendment_to_the_United_States_Constitution) 的保护，比起由公司所有的第三方数据中心，它们受到更强的法律保护。当然，如果你的电子邮件使用的是 Gmail，Google 还保存着你的电子邮件的拷贝。

### 展望

电子邮件是我使用 project/os 项目打包的第一个应用程序。想像一下，一个应用程序商店有全部的服务器软件，打包起来易于安装和使用。想要一个博客？添加一个 WordPress 应用程序！想替换安全的 Dropbox ？添加一个 [Seafile](https://www.seafile.com/en/home/) 应用程序或者一个 [Syncthing](https://syncthing.net/) 后端应用程序。 [IPFS](https://ipfs.io/) 节点？ [Mastodon](https://github.com/tootsuite/mastodon) 实例？GitLab 服务器？各种家庭自动化/物联网后端服务？这里有大量的非常好的开源服务器软件 ，它们都非常易于安装，并且可以使用它们来替换那些有专利的云服务。

---

via: <https://opensource.com/article/18/3/host-your-own-email>

作者：[Nolan Leake](https://opensource.com/users/nolan) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


使用 AppImageLauncher 轻松运行和集成 AppImage 文件

你有没有下载过 AppImage 文件，而你不知道如何使用它？或许你可能知道如何使用它，但是你每次要运行它时必须要进入到下载了该 .AppImage 的文件夹中来运行它，或者手动为其创建启动程序。

使用 AppImageLauncher，这些就都是过去的问题。该程序可让你轻松运行 AppImage 文件，而无需使其可执行。但它最有趣的特点是可以轻松地将 AppImage 与你的系统进行整合：AppImageLauncher 可以自动将 AppImage 程序快捷方式添加到桌面环境的程序启动器/菜单（包括程序图标和合适的说明）中。

这 里有个例子，我想在 Ubuntu 上使用 [Kdenlive](https://kdenlive.org/download/)，但我不想从仓库中安装它，因为它有大量的 KDE 依赖，我不想把它们弄到我的 Gnome 系统中。因为没有它的 Flatpak 或 Snap 镜像，我只能去下载了 Kdenlive 的 AppImage。

在没有把下载的 [Kdenline](https://kdenlive.org/download/) AppImage 变成可执行的情况下，我第一次双击它时（安装好了 AppImageLauncher），AppImageLauncher 提供了两个选项：

“Run once”或者“Integrate and run”。

![](/data/attachment/album/201805/18/122930e3crdimggjmmgi03.png)

点击 “Integrate and run”，这个 AppImage 就被复制到 `~/.bin/` （家目录中的隐藏文件夹）并添加到菜单中，然后启动该程序。

要删除它也很简单，只要您使用的桌面环境支持桌面动作就行。例如，在 Gnome Shell 中，只需右键单击“活动概览”中的应用程序图标，然后选择“Remove from system”：

![](/data/attachment/album/201805/18/122945kbbh7om7w09u857v.png)

更新：该应用只初步为 Ubuntu 和 Mint 做了开发，但它最近会提供 Debian、 Netrunner 和 openSUSE 支持。本文首次发布后添加的另一个功能是支持 AppImage 的更新；你在启动器中可以找到 “Update AppImage”。

### 下载 AppImageLauncher

AppImageLauncher 支持 Ubuntu、 Debian、Netrunner 和 openSUSE。如果你使用 Ubuntu 18.04，请确保你下载的 deb 包的名字中有“bionic”，而其它的 deb 是用于旧一些的 Ubuntu 版本的。

* [下载 AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher/releases)

---

via: <https://www.linuxuprising.com/2018/04/easily-run-and-integrate-appimage-files.html>

作者：[Logix](https://plus.google.com/118280394805678839070) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy) 选题：[lujun9972](https://github.com/lujun9972)

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


如何创建适合移动设备的文档

Summary: 帮助用户在智能手机或平板上快速轻松地找到他们所需的信息。

帮助用户在智能手机或平板上快速轻松地找到他们所需的信息。

>
> 帮助用户在智能手机或平板上快速轻松地找到他们所需的信息。
>
>
>

![](/data/attachment/album/201805/18/170635a6e756r5evz033sv.jpg)

我并不是完全相信[移动为先](https://www.uxmatters.com/mt/archives/2012/03/mobile-first-what-does-it-mean.php)的理念，但是我确实发现更多的人使用智能手机和平板电脑等移动设备来获取信息。这包括在线的软件和硬件文档，但它们大部分都是冗长的，不适合小屏幕。通常情况下，它的伸缩性不太好，而且很难导航。

当用户使用移动设备访问文档时，他们通常需要迅速获取信息以了解如何执行任务或解决问题，他们不想通过看似无尽的页面来寻找他们需要的特定信息。幸运的是，解决这个问题并不难。以下是一些技巧，可以帮助你构建文档以满足移动阅读器的需求。

### 简短一点

这意味着简短的句子，简短的段落和简短的流程。你不是在写一部长篇小说或一段长新闻。使你的文档简洁。尽可能使用少量的语言来获得想法和信息。

以广播新闻报道为示范：关注关键要素，用简单直接的语言对其进行解释。不要让你的读者在屏幕上看到冗长的文字。

另外，直接切入重点。关注读者需要的信息。在线发布的文档不应该像以前厚厚的手册一样。不要把所有东西都放在一个页面上，把你的信息分成更小的块。接下来是怎样做到这一点：

### 主题

在技术写作的世界里，主题是独立的，独立的信息块。每个主题都由你网站上的单个页面组成。读者应该能从特定的主题中获取他们需要的信息 -- 并且只是那些信息。要做到这一点，选择哪些主题要包含在文档中并决定如何组织它们：

### DITA

<ruby> <a href="https://en.wikipedia.org/wiki/Darwin_Information_Typing_Architecture">  达尔文信息类型化体系结构 </a> <rt>  Darwin Information Typing Architecture </rt></ruby> （DITA） 是用于编写和发布的一个 XML 模型。它[广泛采用](http://dita.xml.org/book/list-of-organizations-using-dita)在技术写作中，特别是作为较长的文档集中。

我并不是建议你将文档转换为 XML（除非你真的想）。相反，考虑将 DITA 的不同类型主题的概念应用到你的文档中：

* 一般：概述信息
* 任务：分步骤的流程
* 概念：背景或概念信息
* 参考：API 参考或数据字典等专用信息
* 术语表：定义术语
* 故障排除：有关用户可能遇到的问题以及如何解决问题的信息

你会得到很多单独的页面。要连接这些页面：

### 链接

许多内容管理系统、维基和发布框架都包含某种形式的导航 —— 通常是目录或[面包屑导航](https://en.wikipedia.org/wiki/Breadcrumb_(navigation))，这是一种在移动设备上逐渐消失的导航。

为了加强导航，在主题之间添加明确的链接。将这些链接放在每个主题末尾的“另请参阅”或“相关主题”的标题处。每个部分应包含两到五个链接，指向与当前主题相关的概述、概念和参考主题。

如果你需要指向文档集之外的信息，请确保链接在浏览器新的选项卡中打开。这将把读者送到另一个网站，同时也将读者继续留你的网站上。

这解决了文本问题，那么图片呢？

### 不使用图片

除少数情况之外，不应该加太多图片到文档中。仔细查看文档中的每个图片，然后问自己：

* 它有用吗？
* 它是否增强了文档？
* 如果删除它，读者会错过这张图片吗？

如果回答否，那么移除图片。

另一方面，如果你绝对不能没有图片，就让它变成[响应式的](https://en.wikipedia.org/wiki/Responsive_web_design)。这样，图片就会自动调整以适应更小的屏幕。

如果你仍然不确定图片是否应该出现，Opensource.com 社区版主 Ben Cotton 提供了一个关于在文档中使用屏幕截图的[极好的解释](https://opensource.com/business/15/9/when-does-your-documentation-need-screenshots)。

### 最后的想法

通过少量努力，你就可以构建适合移动设备用户的文档。此外，这些更改也改进了桌面计算机和笔记本电脑用户的文档体验。

---

via: <https://opensource.com/article/17/12/think-mobile>

作者：[Scott Nesbitt](https://opensource.com/users/chrisshort) 译者：[MjSeven](https://github.com/MjSeven) 校对：[wxy](https://github.com/wxy)

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


Linux 局域网路由新手指南：第 1 部分

Summary: 现在我们继续深入学习 Linux 中的 IPv4 路由的基础知识。

现在我们继续深入学习 Linux 中的 IPv4 路由的基础知识。

![](/data/attachment/album/201805/19/104432ydrvfz6cqdr7q28d.jpg)

前面我们学习了 [IPv6 路由](https://www.linux.com/learn/intro-to-linux/2017/7/practical-networking-linux-admins-ipv6-routing)。现在我们继续深入学习 Linux 中的 IPv4 路由的基础知识。我们从硬件概述、操作系统和 IPv4 地址的基础知识开始，下周我们将继续学习它们如何配置，以及测试路由。

### 局域网路由器硬件

Linux 实际上是一个网络操作系统，一直都是，从一开始它就有内置的网络功能。要将你的局域网连入因特网，构建一个局域网路由器比起构建网关路由器要简单的多。你不要太过于执念安全或者防火墙规则，对于处理网络地址转换（NAT）它还是比较复杂的，NAT是 IPv4 的一个痛点。我们为什么不放弃 IPv4 去转到 IPv6 呢？这样将使网络管理员的工作更加简单。

有点跑题了。从理论上讲，你的 Linux 路由器是一个至少有两个网络接口的小型机器。Linux Gizmos 有一个很大的单板机名单：[98 个开放规格、适于黑客的 SBC 的目录](http://linuxgizmos.com/catalog-of-98-open-spec-hacker-friendly-sbcs/#catalog)。你能够使用一个很老的笔记本电脑或者台式计算机。你也可以使用一个紧凑型计算机，像 ZaReason Zini 或者 System76 Meerkat 一样，虽然这些有点贵，差不多要 $600。但是它们又结实又可靠，并且你不用在 Windows 许可证上浪费钱。

如果对路由器的要求不高，使用树莓派 3 Model B 作为路由器是一个非常好的选择。它有一个 10/100 以太网端口，板载 2.4GHz 的 802.11n 无线网卡，并且它还有四个 USB 端口，因此你可以插入多个 USB 网卡。USB 2.0 和低速板载网卡可能会让树莓派变成你的网络上的瓶颈，但是，你不能对它期望太高（毕竟它只有 $35，既没有存储也没有电源）。它支持很多种风格的 Linux，因此你可以选择使用你喜欢的版本。基于 Debian 的树莓派是我的最爱。

### 操作系统

你可以在你选择的硬件上安装将你喜欢的 Linux 的简化版，因为定制的路由器操作系统，比如 OpenWRT、 Tomato、DD-WRT、Smoothwall、Pfsense 等等，都有它们自己的非标准界面。我的观点是，没有必要这么麻烦，它们对你并没有什么帮助。尽量使用标准的 Linux 工具，因为你只需要学习它们一次就够了。

Debian 的网络安装镜像大约有 300MB 大小，并且支持多种架构，包括 ARM、i386、amd64 和 armhf。Ubuntu 的服务器网络安装镜像也小于 50MB，这样你就可以控制你要安装哪些包。Fedora、Mageia、和 openSUSE 都提供精简的网络安装镜像。如果你需要创意，你可以浏览 [Distrowatch](http://distrowatch.org/)。

### 路由器能做什么

我们需要网络路由器做什么？一个路由器连接不同的网络。如果没有路由，那么每个网络都是相互隔离的，所有的悲伤和孤独都没有人与你分享，所有节点只能孤独终老。假设你有一个 192.168.1.0/24 和一个 192.168.2.0/24 网络。如果没有路由器，你的两个网络之间不能相互沟通。这些都是 C 类的私有地址，它们每个都有 254 个可用网络地址。使用 `ipcalc` 可以非常容易地得到它们的这些信息：

```
$ ipcalc 192.168.1.0/24
Address:   192.168.1.0          11000000.10101000.00000001. 00000000
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Wildcard:  0.0.0.255            00000000.00000000.00000000. 11111111
=>
Network:   192.168.1.0/24       11000000.10101000.00000001. 00000000
HostMin:   192.168.1.1          11000000.10101000.00000001. 00000001
HostMax:   192.168.1.254        11000000.10101000.00000001. 11111110
Broadcast: 192.168.1.255        11000000.10101000.00000001. 11111111
Hosts/Net: 254                   Class C, Private Internet

```

我喜欢 `ipcalc` 的二进制输出信息，它更加可视地表示了掩码是如何工作的。前三个八位组表示了网络地址，第四个八位组是主机地址，因此，当你分配主机地址时，你将 “掩盖” 掉网络地址部分，只使用剩余的主机部分。你的两个网络有不同的网络地址，而这就是如果两个网络之间没有路由器它们就不能互相通讯的原因。

每个八位组一共有 256 字节，但是它们并不能提供 256 个主机地址，因为第一个和最后一个值 ，也就是 0 和 255，是被保留的。0 是网络标识，而 255 是广播地址，因此，只有 254 个主机地址。`ipcalc` 可以帮助你很容易地计算出这些。

当然，这并不意味着你不能有一个结尾是 0 或者 255 的主机地址。假设你有一个 16 位的前缀：

```
$ ipcalc 192.168.0.0/16
Address:   192.168.0.0          11000000.10101000. 00000000.00000000
Netmask:   255.255.0.0 = 16     11111111.11111111. 00000000.00000000
Wildcard:  0.0.255.255          00000000.00000000. 11111111.11111111
=>
Network:   192.168.0.0/16       11000000.10101000. 00000000.00000000
HostMin:   192.168.0.1          11000000.10101000. 00000000.00000001
HostMax:   192.168.255.254      11000000.10101000. 11111111.11111110
Broadcast: 192.168.255.255      11000000.10101000. 11111111.11111111
Hosts/Net: 65534                 Class C, Private Internet

```

`ipcalc` 列出了你的第一个和最后一个主机地址，它们是 192.168.0.1 和 192.168.255.254。你是可以有以 0 或者 255 结尾的主机地址的，例如，192.168.1.0 和 192.168.0.255，因为它们都在最小主机地址和最大主机地址之间。

不论你的地址块是私有的还是公共的，这个原则同样都是适用的。不要羞于使用 `ipcalc` 来帮你计算地址。

### CIDR

CIDR（无类域间路由）就是通过可变长度的子网掩码来扩展 IPv4 的。CIDR 允许对网络空间进行更精细地分割。我们使用 `ipcalc` 来演示一下：

```
$ ipcalc 192.168.1.0/22
Address:   192.168.1.0          11000000.10101000.000000 01.00000000
Netmask:   255.255.252.0 = 22   11111111.11111111.111111 00.00000000
Wildcard:  0.0.3.255            00000000.00000000.000000 11.11111111
=>
Network:   192.168.0.0/22       11000000.10101000.000000 00.00000000
HostMin:   192.168.0.1          11000000.10101000.000000 00.00000001
HostMax:   192.168.3.254        11000000.10101000.000000 11.11111110
Broadcast: 192.168.3.255        11000000.10101000.000000 11.11111111
Hosts/Net: 1022                  Class C, Private Internet

```

网络掩码并不局限于整个八位组，它可以跨越第三和第四个八位组，并且子网部分的范围可以是从 0 到 3，而不是非得从 0 到 255。可用主机地址的数量并不一定是 8 的倍数，因为它是由整个八位组定义的。

给你留一个家庭作业，复习 CIDR 和 IPv4 地址空间是如何在公共、私有和保留块之间分配的，这个作业有助你更好地理解路由。一旦你掌握了地址的相关知识，配置路由器将不再是件复杂的事情了。

从 [理解 IP 地址和 CIDR 图表](https://www.ripe.net/about-us/press-centre/understanding-ip-addressing)、[IPv4 私有地址空间和过滤](https://www.arin.net/knowledge/address_filters.html)、以及 [IANA IPv4 地址空间注册](https://www.iana.org/assignments/ipv4-address-space/ipv4-address-space.xhtml) 开始。接下来的我们将学习如何创建和管理路由器。

通过来自 Linux 基金会和 edX 的免费课程 [“Linux 入门”](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux)学习更多 Linux 知识。

---

via: <https://www.linux.com/learn/intro-to-linux/2018/2/linux-lan-routing-beginners-part-1>

作者：[Carla Schroder](https://www.linux.com/users/cschroder) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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