树莓派 3 新手指南

Summary: 这个教程将帮助你入门树莓派 3。

mark一下

这个教程将帮助你入门树莓派 3。

>
> 这个教程将帮助你入门<ruby> 树莓派 3 <rt>  Raspberry Pi 3 </rt></ruby>。
>
>
>

![](/data/attachment/album/201801/17/213214csl1u9bxkyb9e09e.jpg)

这篇文章是我的使用树莓派 3 创建新项目的每周系列文章的一部分。该系列的这个第一篇文章专注于入门，它主要讲安装 Raspbian 和 PIXEL 桌面，以及设置网络和其它的基本组件。

### 你需要：

* 一台树莓派 3
* 一个 5v 2mAh 带 USB 接口的电源适配器
* 至少 8GB 容量的 Micro SD 卡
* Wi-Fi 或者以太网线
* 散热片
* 键盘和鼠标
* 一台 PC 显示器
* 一台用于准备 microSD 卡的 Mac 或者 PC

现在有很多基于 Linux 操作系统可用于树莓派，你可以直接安装它，但是，如果你是第一次接触树莓派，我推荐使用 NOOBS，它是树莓派官方的操作系统安装器，它安装操作系统到该设备的过程非常简单。

在你的电脑上从 [这个链接](https://www.raspberrypi.org/downloads/noobs/) 下载 NOOBS。它是一个 zip 压缩文件。如果你使用的是 MacOS，可以直接双击它，MacOS 会自动解压这个文件。如果你使用的是 Windows，右键单击它，选择“解压到这里”。

如果你运行的是 Linux 桌面，如何去解压 zip 文件取决于你的桌面环境，因为，不同的桌面环境下解压文件的方法不一样，但是，使用命令行可以很容易地完成解压工作。

```
$ unzip NOOBS.zip

```

不管它是什么操作系统，打开解压后的文件，你看到的应该是如下图所示的样子：

![content](/data/attachment/album/201801/17/213216vqvblu6pzb4b46kt.jpg)

现在，在你的 PC 上插入 Micro SD 卡，将它格式化成 FAT32 格式的文件系统。在 MacOS 上，使用磁盘实用工具去格式化 Micro SD 卡：

![format](/data/attachment/album/201801/17/213218sz8ii818igx88858.jpg)

在 Windows 上，只需要右键单击这个卡，然后选择“格式化”选项。如果是在 Linux 上，不同的桌面环境使用不同的工具，就不一一去讲解了。在这里我写了一个教程，[在 Linux 上使用命令行界面](http://www.cio.com/article/3176034/linux/how-to-format-an-sd-card-in-linux.html) 去格式化 SD 卡为 Fat32 文件系统。

在你的卡格式成了 FAT32 格式的文件系统后，就可以去拷贝下载的 NOOBS 目录的内容到这个卡的根目录下。如果你使用的是 MacOS 或者 Linux，可以使用 `rsync` 将 NOOBS 的内容传到 SD 卡的根目录中。在 MacOS 或者 Linux 中打开终端应用，然后运行如下的 rsync 命令：

```
rsync -avzP /path_of_NOOBS /path_of_sdcard

```

一定要确保选择了 SD 卡的根目录，在我的案例中（在 MacOS 上），它是：

```
rsync -avzP /Users/swapnil/Downloads/NOOBS_v2_2_0/ /Volumes/U/

```

或者你也可以拷贝粘贴 NOOBS 目录中的内容。一定要确保将 NOOBS 目录中的内容全部拷贝到 Micro SD 卡的根目录下，千万不能放到任何的子目录中。

现在可以插入这张 MicroSD 卡到树莓派 3 中，连接好显示器、键盘鼠标和电源适配器。如果你拥有有线网络，我建议你使用它，因为有线网络下载和安装操作系统更快。树莓派将引导到 NOOBS，它将提供一个供你去选择安装的分发版列表。从第一个选项中选择 Raspbian，紧接着会出现如下图的画面。

![raspi config](/data/attachment/album/201801/17/213219fkpdee1481k13u5v.jpg)

在你安装完成后，树莓派将重新启动，你将会看到一个欢迎使用树莓派的画面。现在可以去配置它，并且去运行系统更新。大多数情况下，我们都是在没有外设的情况下使用树莓派的，都是使用 SSH 基于网络远程去管理它。这意味着你不需要为了管理树莓派而去为它接上鼠标、键盘和显示器。

开始使用它的第一步是，配置网络（假如你使用的是 Wi-Fi）。点击顶部面板上的网络图标，然后在出现的网络列表中，选择你要配置的网络并为它输入正确的密码。

![wireless](/data/attachment/album/201801/17/213225qbb3zgia3ivs9b3r.jpg)

恭喜您，无线网络的连接配置完成了。在进入下一步的配置之前，你需要找到你的网络为树莓派分配的 IP 地址，因为远程管理会用到它。

打开一个终端，运行如下的命令：

```
ifconfig

```

现在，记下这个设备的 `wlan0` 部分的 IP 地址。它一般显示为 “inet addr”。

现在，可以去启用 SSH 了，在树莓派上打开一个终端，然后打开 `raspi-config` 工具。

```
sudo raspi-config

```

树莓派的默认用户名和密码分别是 “pi” 和 “raspberry”。在上面的命令中你会被要求输入密码。树莓派配置工具的第一个选项是去修改默认密码，我强烈推荐你修改默认密码，尤其是你基于网络去使用它的时候。

第二个选项是去修改主机名，如果在你的网络中有多个树莓派时，主机名用于区分它们。一个有意义的主机名可以很容易在网络上识别每个设备。

然后进入到接口选项，去启用摄像头、SSH、以及 VNC。如果你在树莓派上使用了一个涉及到多媒体的应用程序，比如，家庭影院系统或者 PC，你也可以去改变音频输出选项。缺省情况下，它的默认输出到 HDMI 接口，但是，如果你使用外部音响，你需要去改变音频输出设置。转到树莓派配置工具的高级配置选项，选择音频，然后选择 “3.5mm” 作为默认输出。

[小提示：使用箭头键去导航，使用回车键去选择]

一旦应用了所有的改变， 树莓派将要求重新启动。你可以从树莓派上拔出显示器、鼠标键盘，以后可以通过网络来管理它。现在可以在你的本地电脑上打开终端。如果你使用的是 Windows，你可以使用 Putty 或者去读我的文章 - 怎么在 Windows 10 上安装 Ubuntu Bash。

在你的本地电脑上输入如下的 SSH 命令：

```
ssh pi@IP_ADDRESS_OF_Pi

```

在我的电脑上，这个命令是这样的：

```
ssh pi@10.0.0.161

```

输入它的密码，你登入到树莓派了！现在你可以从一台远程电脑上去管理你的树莓派。如果你希望通过因特网去管理树莓派，可以去阅读我的文章 - [如何在你的计算机上启用 RealVNC](http://www.infoworld.com/article/3171682/internet-of-things/how-to-access-your-raspberry-pi-remotely-over-the-internet.html)。

在该系列的下一篇文章中，我将讲解使用你的树莓派去远程管理你的 3D 打印机。

---

via: <https://www.infoworld.com/article/3176488/linux/a-beginner-s-guide-to-raspberry-pi-3.html>

作者：[Swapnil Bhartiya](https://www.infoworld.com/author/Swapnil-Bhartiya/) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


在 RHEL/CentOS 系统上使用 YUM history 命令回滚升级操作

Summary: yum history 命令允许系统管理员将系统回滚到上一个状态，但由于某些限制，回滚不是在所有情况下都能成功，有时 yum 命令可能什么都不做，有时可能会删掉一些其他的包。

![](/data/attachment/album/201801/18/094229orftygtv7zdnlkmf.png)

为服务器打补丁是 Linux 系统管理员的一项重要任务，为的是让系统更加稳定，性能更加优化。厂商经常会发布一些安全/高危的补丁包，相关软件需要升级以防范潜在的安全风险。

Yum （Yellowdog Update Modified） 是 CentOS 和 RedHat 系统上用的 RPM 包管理工具，`yum history` 命令允许系统管理员将系统回滚到上一个状态，但由于某些限制，回滚不是在所有情况下都能成功，有时 `yum` 命令可能什么都不做，有时可能会删掉一些其他的包。

我建议你在升级之前还是要做一个完整的系统备份，而 `yum history` 并不能用来替代系统备份的。系统备份能让你将系统还原到任意时候的节点状态。

**推荐阅读：**

* [在 RHEL/CentOS 系统上使用 YUM 命令管理软件包](https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/)
* [在 Fedora 系统上使用 DNF （YUM 的一个分支）命令管理软件包](https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/)
* [如何让 history 命令显示日期和时间](https://www.2daygeek.com/display-date-time-linux-bash-history-command/)

某些情况下，安装的应用程序在升级了补丁之后不能正常工作或者出现一些错误（可能是由于库不兼容或者软件包升级导致的），那该怎么办呢？

与应用开发团队沟通，并找出导致库和软件包的问题所在，然后使用 `yum history` 命令进行回滚。

**注意：**

* 它不支持回滚 selinux，selinux-policy-\*，kernel，glibc （以及依赖 glibc 的包，比如 gcc）。
* 不建议将系统降级到更低的版本（比如 CentOS 6.9 降到 CentOS 6.8），这会导致系统处于不稳定的状态

让我们先来看看系统上有哪些包可以升级，然后挑选出一些包来做实验。

```
# yum update
Loaded plugins: fastestmirror, security
Setting up Update Process
Loading mirror speeds from cached hostfile
epel/metalink | 12 kB 00:00
 * epel: mirror.csclub.uwaterloo.ca
base | 3.7 kB 00:00
dockerrepo | 2.9 kB 00:00
draios | 2.9 kB 00:00
draios/primary_db | 13 kB 00:00
epel | 4.3 kB 00:00
epel/primary_db | 5.9 MB 00:00
extras | 3.4 kB 00:00
updates | 3.4 kB 00:00
updates/primary_db | 2.5 MB 00:00
Resolving Dependencies
--> Running transaction check
---> Package git.x86_64 0:1.7.1-8.el6 will be updated
---> Package git.x86_64 0:1.7.1-9.el6_9 will be an update
---> Package httpd.x86_64 0:2.2.15-60.el6.centos.4 will be updated
---> Package httpd.x86_64 0:2.2.15-60.el6.centos.5 will be an update
---> Package httpd-tools.x86_64 0:2.2.15-60.el6.centos.4 will be updated
---> Package httpd-tools.x86_64 0:2.2.15-60.el6.centos.5 will be an update
---> Package perl-Git.noarch 0:1.7.1-8.el6 will be updated
---> Package perl-Git.noarch 0:1.7.1-9.el6_9 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

=================================================================================================
 Package Arch Version Repository Size
=================================================================================================
Updating:
 git x86_64 1.7.1-9.el6_9 updates 4.6 M
 httpd x86_64 2.2.15-60.el6.centos.5 updates 836 k
 httpd-tools x86_64 2.2.15-60.el6.centos.5 updates 80 k
 perl-Git noarch 1.7.1-9.el6_9 updates 29 k

Transaction Summary
=================================================================================================
Upgrade 4 Package(s)

Total download size: 5.5 M
Is this ok [y/N]: n

```

你会发现 `git` 包可以被升级，那我们就用它来实验吧。运行下面命令获得软件包的版本信息（当前安装的版本和可以升级的版本）。

```
# yum list git
Loaded plugins: fastestmirror, security
Setting up Update Process
Loading mirror speeds from cached hostfile
 * epel: mirror.csclub.uwaterloo.ca
Installed Packages
git.x86_64 1.7.1-8.el6 @base
Available Packages
git.x86_64 1.7.1-9.el6_9 updates

```

运行下面命令来将 `git` 从 `1.7.1-8` 升级到 `1.7.1-9`。

```
# yum update git
Loaded plugins: fastestmirror, presto
Setting up Update Process
Loading mirror speeds from cached hostfile
 * base: repos.lax.quadranet.com
 * epel: fedora.mirrors.pair.com
 * extras: mirrors.seas.harvard.edu
 * updates: mirror.sesp.northwestern.edu
Resolving Dependencies
--> Running transaction check
---> Package git.x86_64 0:1.7.1-8.el6 will be updated
--> Processing Dependency: git = 1.7.1-8.el6 for package: perl-Git-1.7.1-8.el6.noarch
---> Package git.x86_64 0:1.7.1-9.el6_9 will be an update
--> Running transaction check
---> Package perl-Git.noarch 0:1.7.1-8.el6 will be updated
---> Package perl-Git.noarch 0:1.7.1-9.el6_9 will be an update
--> Finished Dependency Resolution

Dependencies Resolved

=================================================================================================
 Package Arch Version Repository Size
=================================================================================================
Updating:
 git x86_64 1.7.1-9.el6_9 updates 4.6 M
Updating for dependencies:
 perl-Git noarch 1.7.1-9.el6_9 updates 29 k

Transaction Summary
=================================================================================================
Upgrade 2 Package(s)

Total download size: 4.6 M
Is this ok [y/N]: y
Downloading Packages:
Setting up and reading Presto delta metadata
Processing delta metadata
Package(s) data still to download: 4.6 M
(1/2): git-1.7.1-9.el6_9.x86_64.rpm | 4.6 MB 00:00
(2/2): perl-Git-1.7.1-9.el6_9.noarch.rpm | 29 kB 00:00
-------------------------------------------------------------------------------------------------
Total 5.8 MB/s | 4.6 MB 00:00
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
 Updating : perl-Git-1.7.1-9.el6_9.noarch 1/4
 Updating : git-1.7.1-9.el6_9.x86_64 2/4
 Cleanup : perl-Git-1.7.1-8.el6.noarch 3/4
 Cleanup : git-1.7.1-8.el6.x86_64 4/4
 Verifying : git-1.7.1-9.el6_9.x86_64 1/4
 Verifying : perl-Git-1.7.1-9.el6_9.noarch 2/4
 Verifying : git-1.7.1-8.el6.x86_64 3/4
 Verifying : perl-Git-1.7.1-8.el6.noarch 4/4

Updated:
 git.x86_64 0:1.7.1-9.el6_9

Dependency Updated:
 perl-Git.noarch 0:1.7.1-9.el6_9

Complete!

```

验证升级后的 `git` 版本.

```
# yum list git
Installed Packages
git.x86_64 1.7.1-9.el6_9 @updates

或
# rpm -q git
git-1.7.1-9.el6_9.x86_64

```

现在我们成功升级这个软件包，可以对它进行回滚了。步骤如下。

### 使用 YUM history 命令回滚升级操作

首先，使用下面命令获取 yum 操作的 id。下面的输出很清晰地列出了所有需要的信息，例如操作 id、谁做的这个操作（用户名）、操作日期和时间、操作的动作（安装还是升级）、操作影响的包数量。

```
# yum history
或
# yum history list all
Loaded plugins: fastestmirror, presto
ID | Login user | Date and time | Action(s) | Altered
-------------------------------------------------------------------------------
 13 | root | 2017-08-18 13:30 | Update | 2
 12 | root | 2017-08-10 07:46 | Install | 1
 11 | root | 2017-07-28 17:10 | E, I, U | 28 EE
 10 | root | 2017-04-21 09:16 | E, I, U | 162 EE
 9 | root | 2017-02-09 17:09 | E, I, U | 20 EE
 8 | root | 2017-02-02 10:45 | Install | 1
 7 | root | 2016-12-15 06:48 | Update | 1
 6 | root | 2016-12-15 06:43 | Install | 1
 5 | root | 2016-12-02 10:28 | E, I, U | 23 EE
 4 | root | 2016-10-28 05:37 | E, I, U | 13 EE
 3 | root | 2016-10-18 12:53 | Install | 1
 2 | root | 2016-09-30 10:28 | E, I, U | 31 EE
 1 | root | 2016-07-26 11:40 | E, I, U | 160 EE

```

上面命令显示有两个包受到了影响，因为 `git` 还升级了它的依赖包 `perl-Git`。 运行下面命令来查看关于操作的详细信息。

```
# yum history info 13
Loaded plugins: fastestmirror, presto
Transaction ID : 13
Begin time : Fri Aug 18 13:30:52 2017
Begin rpmdb : 420:f5c5f9184f44cf317de64d3a35199e894ad71188
End time : 13:30:54 2017 (2 seconds)
End rpmdb : 420:d04a95c25d4526ef87598f0dcaec66d3f99b98d4
User : root
Return-Code : Success
Command Line : update git
Transaction performed with:
 Installed rpm-4.8.0-55.el6.x86_64 @base
 Installed yum-3.2.29-81.el6.centos.noarch @base
 Installed yum-plugin-fastestmirror-1.1.30-40.el6.noarch @base
 Installed yum-presto-0.6.2-1.el6.noarch @anaconda-CentOS-201207061011.x86_64/6.3
Packages Altered:
 Updated git-1.7.1-8.el6.x86_64 @base
 Update 1.7.1-9.el6_9.x86_64 @updates
 Updated perl-Git-1.7.1-8.el6.noarch @base
 Update 1.7.1-9.el6_9.noarch @updates
history info

```

运行下面命令来回滚 `git` 包到上一个版本。

```
# yum history undo 13
Loaded plugins: fastestmirror, presto
Undoing transaction 53, from Fri Aug 18 13:30:52 2017
 Updated git-1.7.1-8.el6.x86_64 @base
 Update 1.7.1-9.el6_9.x86_64 @updates
 Updated perl-Git-1.7.1-8.el6.noarch @base
 Update 1.7.1-9.el6_9.noarch @updates
Loading mirror speeds from cached hostfile
 * base: repos.lax.quadranet.com
 * epel: fedora.mirrors.pair.com
 * extras: repo1.dal.innoscale.net
 * updates: mirror.vtti.vt.edu
Resolving Dependencies
--> Running transaction check
---> Package git.x86_64 0:1.7.1-8.el6 will be a downgrade
---> Package git.x86_64 0:1.7.1-9.el6_9 will be erased
---> Package perl-Git.noarch 0:1.7.1-8.el6 will be a downgrade
---> Package perl-Git.noarch 0:1.7.1-9.el6_9 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

=================================================================================================
 Package Arch Version Repository Size
=================================================================================================
Downgrading:
 git x86_64 1.7.1-8.el6 base 4.6 M
 perl-Git noarch 1.7.1-8.el6 base 29 k

Transaction Summary
=================================================================================================
Downgrade 2 Package(s)

Total download size: 4.6 M
Is this ok [y/N]: y
Downloading Packages:
Setting up and reading Presto delta metadata
Processing delta metadata
Package(s) data still to download: 4.6 M
(1/2): git-1.7.1-8.el6.x86_64.rpm | 4.6 MB 00:00
(2/2): perl-Git-1.7.1-8.el6.noarch.rpm | 29 kB 00:00
-------------------------------------------------------------------------------------------------
Total 3.4 MB/s | 4.6 MB 00:01
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
 Installing : perl-Git-1.7.1-8.el6.noarch 1/4
 Installing : git-1.7.1-8.el6.x86_64 2/4
 Cleanup : perl-Git-1.7.1-9.el6_9.noarch 3/4
 Cleanup : git-1.7.1-9.el6_9.x86_64 4/4
 Verifying : git-1.7.1-8.el6.x86_64 1/4
 Verifying : perl-Git-1.7.1-8.el6.noarch 2/4
 Verifying : git-1.7.1-9.el6_9.x86_64 3/4
 Verifying : perl-Git-1.7.1-9.el6_9.noarch 4/4

Removed:
 git.x86_64 0:1.7.1-9.el6_9 perl-Git.noarch 0:1.7.1-9.el6_9

Installed:
 git.x86_64 0:1.7.1-8.el6 perl-Git.noarch 0:1.7.1-8.el6

Complete!

```

回滚后，使用下面命令来检查降级包的版本。

```
# yum list git
或
# rpm -q git
git-1.7.1-8.el6.x86_64

```

### 使用YUM downgrade 命令回滚升级

此外，我们也可以使用 YUM `downgrade` 命令回滚升级。

```
# yum downgrade git-1.7.1-8.el6 perl-Git-1.7.1-8.el6
Loaded plugins: search-disabled-repos, security, ulninfo
Setting up Downgrade Process
Resolving Dependencies
--> Running transaction check
---> Package git.x86_64 0:1.7.1-8.el6 will be a downgrade
---> Package git.x86_64 0:1.7.1-9.el6_9 will be erased
---> Package perl-Git.noarch 0:1.7.1-8.el6 will be a downgrade
---> Package perl-Git.noarch 0:1.7.1-9.el6_9 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

=================================================================================================
 Package Arch Version Repository Size
=================================================================================================
Downgrading:
 git x86_64 1.7.1-8.el6 base 4.6 M
 perl-Git noarch 1.7.1-8.el6 base 29 k

Transaction Summary
=================================================================================================
Downgrade 2 Package(s)

Total download size: 4.6 M
Is this ok [y/N]: y
Downloading Packages:
(1/2): git-1.7.1-8.el6.x86_64.rpm | 4.6 MB 00:00
(2/2): perl-Git-1.7.1-8.el6.noarch.rpm | 28 kB 00:00
-------------------------------------------------------------------------------------------------
Total 3.7 MB/s | 4.6 MB 00:01
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
 Installing : perl-Git-1.7.1-8.el6.noarch 1/4
 Installing : git-1.7.1-8.el6.x86_64 2/4
 Cleanup : perl-Git-1.7.1-9.el6_9.noarch 3/4
 Cleanup : git-1.7.1-9.el6_9.x86_64 4/4
 Verifying : git-1.7.1-8.el6.x86_64 1/4
 Verifying : perl-Git-1.7.1-8.el6.noarch 2/4
 Verifying : git-1.7.1-9.el6_9.x86_64 3/4
 Verifying : perl-Git-1.7.1-9.el6_9.noarch 4/4

Removed:
 git.x86_64 0:1.7.1-9.el6_9 perl-Git.noarch 0:1.7.1-9.el6_9

Installed:
 git.x86_64 0:1.7.1-8.el6 perl-Git.noarch 0:1.7.1-8.el6

Complete!

```

注意： 你也需要降级依赖包，否则它会删掉当前版本的依赖包而不是对依赖包做降级，因为 `downgrade` 命令无法处理依赖关系。

### 至于 Fedora 用户

命令是一样的，只需要将包管理器名称从 `yum` 改成 `dnf` 就行了。

```
# dnf list git
# dnf history
# dnf history info
# dnf history undo
# dnf list git
# dnf downgrade git-1.7.1-8.el6 perl-Git-1.7.1-8.el6

```

---

via: <https://www.2daygeek.com/rollback-fallback-updates-downgrade-packages-centos-rhel-fedora/>

作者：[2daygeek](https://www.2daygeek.com/author/2daygeek/) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


解决 Linux 和 Windows 双启动带来的时间同步问题

![](/data/attachment/album/201801/17/215458ygiiiifpowyp9o4y.jpg)

想在保留 Windows 系统的前提下尝试其他 Linux 发行版，双启动是个常用的做法。这种方法如此风行是因为实现双启动是一件很容易的事情。然而这也带来了一个大问题，那就是 **时间**。

是的，你没有看错。若你只是用一个操作系统，时间同步不会有什么问题。但若有 Windows 和 Linux 两个系统，则可能出现时间同步上的问题。Linux 使用的是格林威治时间而 Windows 使用的是本地时间。当你从 Linux 切换到 Windows 或者从 Windows 切换到 Linux 时，就可能显示错误的时间了。

不过不要担心，这个问题很好解决。

点击 Windows 系统中的开始菜单，然后搜索 regedit。

[![open regedit in windows 10](/data/attachment/album/201801/17/215459ybu7ca3uu9zi39xq.jpg)](http://www.theitstuff.com/wp-content/uploads/2017/12/syncdualbootime1-e1512732558530.jpg)

点击打开，然后你会看到类型下面的内容。这就是注册表编辑器。

[![windows 10 registry editor](/data/attachment/album/201801/17/215500mz2f7oc7r5lrc7pl.jpg)](http://www.theitstuff.com/wp-content/uploads/2017/12/syncdualbootime2.jpg)

在左边的导航菜单，导航到 `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation`。

在右边窗口，右键点击空白位置，然后选择 `New >> DWORD(32 bit) Value`。

[![change time format utc from windows registry](/data/attachment/album/201801/17/215500o0nyyry9hlylhpmy.jpg)](http://www.theitstuff.com/wp-content/uploads/2017/12/syncdualbootime3.jpg)

之后，你会新生成一个条目，而且这个条目默认是高亮的。将这个条目重命名为 `RealTimeIsUniversal` 并设置值为 `1`。

[![set universal time utc in windows](/data/attachment/album/201801/17/215501yj57uqqtbsv7avbj.jpg)](http://www.theitstuff.com/wp-content/uploads/2017/12/syncdualbootime4.jpg)

所有的配置就完成了，下次重启，就不会再有时间同步问题了。

---

via: <http://www.theitstuff.com/how-to-sync-time-between-linux-and-windows-dual-boot-2>

作者：[Rishabh Kandari](http://www.theitstuff.com) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


手把手教你构建开放式文化

Summary: 这本开放式组织的最新著作是大规模体验开放的手册。

这本开放式组织的最新著作是大规模体验开放的手册。

>
> 这本开放式组织的最新著作是大规模体验开放的手册。
>
>
>

![](/data/attachment/album/201801/17/221605r1pqjj7t4431iunp.jpg)

我们于 2015 年发表<ruby> 开放组织 <rt>  Open Organization </rt></ruby> 后，很多各种类型、各种规模的公司都对“开放式”文化究竟意味着什么感到好奇。甚至当我跟别的公司谈论我们产品和服务的优势时，也总是很快就从谈论技术转移到人和文化上去了。几乎所有对推动创新和保持行业竞争优势有兴趣的人都在思考这个问题。

不是只有<ruby> 高层领导团队 <rt>  senior leadership teams </rt> <rt> </rt></ruby>才对开放式工作感兴趣。[红帽公司最近一次调查](https://www.redhat.com/en/blog/red-hat-releases-2017-open-source-culture-survey-results)  发现 [81% 的受访者](https://www.techvalidate.com/tvid/923-06D-74C)  同意这样一种说法：“拥有开放式的组织文化对我们公司非常重要。”

然而要注意的是。同时只有 [67% 的受访者](https://www.techvalidate.com/tvid/D30-09E-B52)  认为：“我们的组织有足够的资源来构建开放式文化。”

这个结果与我从其他公司那交流所听到的相吻合：人们希望在开放式文化中工作，他们只是不知道该怎么做。对此我表示同情，因为组织的行事风格是很难捕捉、评估和理解的。在 [Catalyst-In-Chief](https://opensource.com/open-organization/resources/catalyst-in-chief) 中，我将其称之为“组织中最神秘莫测的部分。”

《开放式组织》认为， 在数字转型有望改变我们工作的许多传统方式的时代，拥抱开放文化是创造持续创新的最可靠途径。当我们在书写这本书的时候，我们所关注的是描述在红帽公司中兴起的那种文化--而不是编写一本如何操作的书。我们并不会制定出一步步的流程来让其他组织采用。

这也是为什么与其他领导者和高管谈论他们是如何开始构建开放式文化的会那么有趣。在创建开放组织时，很多高管会说我们要“改变我们的文化”。但是文化并不是一项输入。它是一项输出——它是人们互动和日常行为的副产品。

告诉组织成员“更加透明地工作”，“更多地合作”，以及“更加包容地行动”并没有什么作用。因为像“透明”，“合作”和“包容”这一类的文化特质并不是行动。他们只是组织内指导行为的价值观而已。

要如何才能构建开放式文化呢？

在过去的两年里，Opensource.com 社区收集了各种以开放的精神来进行工作、管理和领导的最佳实践方法。现在我们在新书 《[The Open Organization Workbook](https://opensource.com/open-organization/resources/workbook)》 中将之分享出来，这是一本更加规范的引发文化变革的指引。

要记住，任何改变，尤其是巨大的改变，都需要承诺、耐心，以及努力的工作。我推荐你在通往伟大成功的大道上先使用这本工作手册来实现一些微小的，有意义的成果。

通过阅读这本书，你将能够构建一个开放而又富有创新的文化氛围，使你们的人能够茁壮成长。我已經迫不及待想听听你的故事了。

本文摘自 《[Open Organization Workbook project](https://opensource.com/open-organization/17/8/workbook-project-announcement)》。

---

via: <https://opensource.com/open-organization/17/12/whitehurst-workbook-introduction>

作者：[Jim Whitehurst](https://opensource.com/users/jwhitehurst) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


让 history 命令显示日期和时间

Summary: 默认情况下 history 命令直接显示用户执行的命令而不会输出运行命令时的日期和时间，即使 history 命令记录了这个时间。

很有用，感谢

![](/data/attachment/album/201801/18/111938vf1fnfzfrofnsrfs.jpg)

我们都对 `history` 命令很熟悉。它将终端上 bash 执行过的所有命令存储到 `.bash_history` 文件中，来帮助我们复查用户之前执行过的命令。

默认情况下 `history` 命令直接显示用户执行的命令而不会输出运行命令时的日期和时间，即使 `history` 命令记录了这个时间。

运行 `history` 命令时，它会检查一个叫做 `HISTTIMEFORMAT` 的环境变量，这个环境变量指明了如何格式化输出 `history` 命令中记录的这个时间。

若该值为 null 或者根本没有设置，则它跟大多数系统默认显示的一样，不会显示日期和时间。

`HISTTIMEFORMAT` 使用 `strftime` 来格式化显示时间（`strftime` - 将日期和时间转换为字符串）。`history` 命令输出日期和时间能够帮你更容易地追踪问题。

* `%T`： 替换为时间（`%H:%M:%S`）。
* `%F`： 等同于 `%Y-%m-%d` （ISO 8601:2000 标准日期格式）。

下面是 `history` 命令默认的输出。

```
# history
 1 yum install -y mysql-server mysql-client
 2 service mysqld start
 3 sysdig proc.name=sshd
 4 sysdig -c topprocs_net
 5 sysdig proc.name=sshd
 6 sysdig proc.name=sshd | more
 7 sysdig fd.name=/var/log/auth.log | more
 8 sysdig fd.name=/var/log/mysqld.log
 9 sysdig -cl
 10 sysdig -i httplog
 11 sysdig -i proc_exec_time
 12 sysdig -i topprocs_cpu
 13 sysdig -c topprocs_cpu
 14 sysdig -c tracers_2_statsd
 15 sysdig -c topfiles_bytes
 16 sysdig -c topprocs_cpu
 17 sysdig -c topprocs_cpu "fd.name contains sshd"
 18 sysdig -c topprocs_cpu "proc.name contains sshd"
 19 csysdig
 20 sysdig -c topprocs_cpu
 21 rpm --import https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public
 22 curl -s -o /etc/yum.repos.d/draios.repo http://download.draios.com/stable/rpm/draios.repo
 23 yum install -y epel-release
 24 yum update
 25 yum makecache
 26 yum -y install kernel-devel-$(uname -r)
 27 yum -y install sysdig
 28 sysdig
 29 yum install httpd mysql
 30 service httpd start

```

根据需求，有三种不同的设置环境变量的方法。

* 临时设置当前用户的环境变量
* 永久设置当前/其他用户的环境变量
* 永久设置所有用户的环境变量

**注意：** 不要忘了在最后那个单引号前加上空格，否则输出会很混乱的。

### 方法 1：

运行下面命令为为当前用户临时设置 `HISTTIMEFORMAT` 变量。这会一直生效到下次重启。

```
# export HISTTIMEFORMAT='%F %T '

```

### 方法 2：

将 `HISTTIMEFORMAT` 变量加到 `.bashrc` 或 `.bash_profile` 文件中，让它永久生效。

```
# echo 'HISTTIMEFORMAT="%F %T "' >> ~/.bashrc
或
# echo 'HISTTIMEFORMAT="%F %T "' >> ~/.bash_profile

```

运行下面命令来让文件中的修改生效。

```
# source ~/.bashrc
或
# source ~/.bash_profile

```

### 方法 3：

将 `HISTTIMEFORMAT` 变量加入 `/etc/profile` 文件中，让它对所有用户永久生效。

```
# echo 'HISTTIMEFORMAT="%F %T "' >> /etc/profile

```

运行下面命令来让文件中的修改生效。

```
# source /etc/profile

```

输出结果为：

```
# history
 1 2017-08-16 15:30:15 yum install -y mysql-server mysql-client
 2 2017-08-16 15:30:15 service mysqld start
 3 2017-08-16 15:30:15 sysdig proc.name=sshd
 4 2017-08-16 15:30:15 sysdig -c topprocs_net
 5 2017-08-16 15:30:15 sysdig proc.name=sshd
 6 2017-08-16 15:30:15 sysdig proc.name=sshd | more
 7 2017-08-16 15:30:15 sysdig fd.name=/var/log/auth.log | more
 8 2017-08-16 15:30:15 sysdig fd.name=/var/log/mysqld.log
 9 2017-08-16 15:30:15 sysdig -cl
 10 2017-08-16 15:30:15 sysdig -i httplog
 11 2017-08-16 15:30:15 sysdig -i proc_exec_time
 12 2017-08-16 15:30:15 sysdig -i topprocs_cpu
 13 2017-08-16 15:30:15 sysdig -c topprocs_cpu
 14 2017-08-16 15:30:15 sysdig -c tracers_2_statsd
 15 2017-08-16 15:30:15 sysdig -c topfiles_bytes
 16 2017-08-16 15:30:15 sysdig -c topprocs_cpu
 17 2017-08-16 15:30:15 sysdig -c topprocs_cpu "fd.name contains sshd"
 18 2017-08-16 15:30:15 sysdig -c topprocs_cpu "proc.name contains sshd"
 19 2017-08-16 15:30:15 csysdig
 20 2017-08-16 15:30:15 sysdig -c topprocs_cpu
 21 2017-08-16 15:30:15 rpm --import https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public
 22 2017-08-16 15:30:15 curl -s -o /etc/yum.repos.d/draios.repo http://download.draios.com/stable/rpm/draios.repo
 23 2017-08-16 15:30:15 yum install -y epel-release
 24 2017-08-16 15:30:15 yum update
 25 2017-08-16 15:30:15 yum makecache
 26 2017-08-16 15:30:15 yum -y install kernel-devel-$(uname -r)
 27 2017-08-16 15:30:15 yum -y install sysdig
 28 2017-08-16 15:30:15 sysdig
 29 2017-08-16 15:30:15 yum install httpd mysql
 30 2017-08-16 15:30:15 service httpd start

```

---

via: <https://www.2daygeek.com/display-date-time-linux-bash-history-command/>

作者：[2daygeek](https://www.2daygeek.com/author/2daygeek/) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


在 Ubuntu 上体验 LXD 容器

![](/data/attachment/album/201801/18/113902apgo7es2ocs2fgtz.jpg)

本文的主角是容器，一种类似虚拟机但更轻量级的构造。你可以轻易地在你的 Ubuntu 桌面系统中创建一堆容器！

虚拟机会虚拟出整个电脑让你来安装客户机操作系统。**相比之下**，容器**复用**了主机的 Linux 内核，只是简单地 **包容** 了我们选择的根文件系统（也就是运行时环境）。Linux 内核有很多功能可以将运行的 Linux 容器与我们的主机分割开（也就是我们的 Ubuntu 桌面）。

Linux 本身需要一些手工操作来直接管理他们。好在，有 LXD（读音为 Lex-deeh），这是一款为我们管理 Linux 容器的服务。

我们将会看到如何：

1. 在我们的 Ubuntu 桌面上配置容器，
2. 创建容器，
3. 安装一台 web 服务器，
4. 测试一下这台 web 服务器，以及
5. 清理所有的东西。

### 设置 Ubuntu 容器

如果你安装的是 Ubuntu 16.04，那么你什么都不用做。只要安装下面所列出的一些额外的包就行了。若你安装的是 Ubuntu 14.04.x 或 Ubuntu 15.10，那么按照 [LXD 2.0 系列（二）：安装与配置](/article-7687-1.html) 来进行一些操作，然后再回来。

确保已经更新了包列表：

```
sudo apt update
sudo apt upgrade

```

安装 `lxd` 包：

```
sudo apt install lxd

```

若你安装的是 Ubuntu 16.04，那么还可以让你的容器文件以 ZFS 文件系统的格式进行存储。Ubuntu 16.04 的 Linux kernel 包含了支持 ZFS 必要的内核模块。若要让 LXD 使用 ZFS 进行存储，我们只需要安装 ZFS 工具包。没有 ZFS，容器会在主机文件系统中以单独的文件形式进行存储。通过 ZFS，我们就有了写入时拷贝等功能，可以让任务完成更快一些。

安装 `zfsutils-linux` 包（若你安装的是 Ubuntu 16.04.x）：

```
sudo apt install zfsutils-linux

```

安装好 LXD 后，包安装脚本应该会将你加入 `lxd` 组。该组成员可以使你无需通过 `sudo` 就能直接使用 LXD 管理容器。根据 Linux 的习惯，**你需要先登出桌面会话然后再登录** 才能应用 `lxd` 的组成员关系。（若你是高手，也可以通过在当前 shell 中执行 `newgrp lxd` 命令，就不用重登录了）。

在开始使用前，LXD 需要初始化存储和网络参数。

运行下面命令：

```
$ sudo lxd init
Name of the storage backend to use (dir or zfs): zfs
Create a new ZFS pool (yes/no)? yes
Name of the new ZFS pool: lxd-pool
Would you like to use an existing block device (yes/no)? no
Size in GB of the new loop device (1GB minimum): 30
Would you like LXD to be available over the network (yes/no)? no
Do you want to configure the LXD bridge (yes/no)? yes
> You will be asked about the network bridge configuration. Accept all defaults and continue.
Warning: Stopping lxd.service, but it can still be activated by:
 lxd.socket
 LXD has been successfully configured.
$ _

```

我们在一个（单独）的文件而不是块设备（即分区）中构建了一个文件系统来作为 ZFS 池，因此我们无需进行额外的分区操作。在本例中我指定了 30GB 大小，这个空间取之于根（`/`） 文件系统中。这个文件就是 `/var/lib/lxd/zfs.img`。

行了！最初的配置完成了。若有问题，或者想了解其他信息，请阅读 <https://www.stgraber.org/2016/03/15/lxd-2-0-installing-and-configuring-lxd-212/> 。

### 创建第一个容器

所有 LXD 的管理操作都可以通过 `lxc` 命令来进行。我们通过给 `lxc` 不同参数来管理容器。

```
lxc list

```

可以列出所有已经安装的容器。很明显，这个列表现在是空的，但这表示我们的安装是没问题的。

```
lxc image list

```

列出可以用来启动容器的（已经缓存的）镜像列表。很明显这个列表也是空的，但这也说明我们的安装是没问题的。

```
lxc image list ubuntu：

```

列出可以下载并启动容器的远程镜像。而且指定了显示 Ubuntu 镜像。

```
lxc image list images：

```

列出可以用来启动容器的（已经缓存的）各种发行版的镜像列表。这会列出各种发行版的镜像比如 Alpine、Debian、Gentoo、Opensuse 以及 Fedora。

让我们启动一个 Ubuntu 16.04 容器，并称之为 `c1`：

```
$ lxc launch ubuntu：x c1
Creating c1
Starting c1
$

```

我们使用 `launch` 动作，然后选择镜像 `ubuntu：x` （`x` 表示 Xenial/16.04 镜像），最后我们使用名字 `c1` 作为容器的名称。

让我们来看看安装好的首个容器，

```
$ lxc list

+---------|---------|----------------------|------|------------|-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------|---------|----------------------|------|------------|-----------+
| c1 | RUNNING | 10.173.82.158 (eth0) | | PERSISTENT | 0 |
+---------|---------|----------------------|------|------------|-----------+

```

我们的首个容器 c1 已经运行起来了，它还有自己的 IP 地址（可以本地访问）。我们可以开始用它了！

### 安装 web 服务器

我们可以在容器中运行命令。运行命令的动作为 `exec`。

```
$ lxc exec c1 -- uptime
 11：47：25 up 2 min，0 users，load average：0.07，0.05，0.04
$ _

```

在 `exec` 后面，我们指定容器、最后输入要在容器中运行的命令。该容器的运行时间只有 2 分钟，这是个新出炉的容器：-)。

命令行中的 `--` 跟我们 shell 的参数处理过程有关。若我们的命令没有任何参数，则完全可以省略 `-`。

```
$ lxc exec c1 -- df -h

```

这是一个必须要 `-` 的例子，由于我们的命令使用了参数 `-h`。若省略了 `-`，会报错。

然后我们运行容器中的 shell 来更新包列表。

```
$ lxc exec c1 bash
root@c1:~# apt update
Ign http://archive.ubuntu.com trusty InRelease
Get:1 http://archive.ubuntu.com trusty-updates InRelease [65.9 kB]
Get:2 http://security.ubuntu.com trusty-security InRelease [65.9 kB]
...
Hit http://archive.ubuntu.com trusty/universe Translation-en
Fetched 11.2 MB in 9s (1228 kB/s)
Reading package lists... Done
root@c1:~# apt upgrade
Reading package lists... Done
Building dependency tree
...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
Setting up dpkg (1.17.5ubuntu5.7) ...
root@c1:~# _

```

我们使用 nginx 来做 web 服务器。nginx 在某些方面要比 Apache web 服务器更酷一些。

```
root@c1:~# apt install nginx
Reading package lists... Done
Building dependency tree
...
Setting up nginx-core (1.4.6-1ubuntu3.5) ...
Setting up nginx (1.4.6-1ubuntu3.5) ...
Processing triggers for libc-bin (2.19-0ubuntu6.9) ...
root@c1:~# _

```

让我们用浏览器访问一下这个 web 服务器。记住 IP 地址为 10.173.82.158，因此你需要在浏览器中输入这个 IP。

[![lxd-nginx](/data/attachment/album/201801/18/113912hc9pa3agdypmc0cg.png)](https://i2.wp.com/blog.simos.info/wp-content/uploads/2016/06/lxd-nginx.png?ssl=1)

让我们对页面文字做一些小改动。回到容器中，进入默认 HTML 页面的目录中。

```
root@c1:~# cd /var/www/html/
root@c1:/var/www/html# ls -l
total 2
-rw-r--r-- 1 root root 612 Jun 25 12:15 index.nginx-debian.html
root@c1:/var/www/html#

```

使用 nano 编辑文件，然后保存：

[![lxd-nginx-nano](/data/attachment/album/201801/18/113915j4awrpi4yxgvdew4.png)](https://i2.wp.com/blog.simos.info/wp-content/uploads/2016/06/lxd-nginx-nano.png?ssl=1)

之后，再刷一下页面看看，

[![lxd-nginx-modified](/data/attachment/album/201801/18/113920uoxiic6zluz6vofo.png)](https://i1.wp.com/blog.simos.info/wp-content/uploads/2016/06/lxd-nginx-modified.png?ssl=1)

### 清理

让我们清理一下这个容器，也就是删掉它。当需要的时候我们可以很方便地创建一个新容器出来。

```
$ lxc list
+---------+---------+----------------------+------+------------+-----------+
| NAME | STATE   | IPV4                 | IPV6 | TYPE       | SNAPSHOTS    |
+---------+---------+----------------------+------+------------+-----------+
| c1   | RUNNING | 10.173.82.169 (eth0) |      | PERSISTENT | 0            |
+---------+---------+----------------------+------+------------+-----------+
$ lxc stop c1
$ lxc delete c1
$ lxc list
+---------+---------+----------------------+------+------------+-----------+
| NAME | STATE   | IPV4                 | IPV6 | TYPE       | SNAPSHOTS    |
+---------+---------+----------------------+------+------------+-----------+
+---------+---------+----------------------+------+------------+-----------+

```

我们停止（关闭）这个容器，然后删掉它了。

本文至此就结束了。关于容器有很多玩法。而这只是配置 Ubuntu 并尝试使用容器的第一步而已。

---

via: <https://blog.simos.info/trying-out-lxd-containers-on-our-ubuntu/>

作者：[Simos Xenitellis](https://blog.simos.info/author/simos/) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


剖析内存中的程序之秘

![](/data/attachment/album/201801/18/184936hk1nkta39t714jt1.jpg)

内存管理是操作系统的核心任务；它对程序员和系统管理员来说也是至关重要的。在接下来的几篇文章中，我将从实践出发着眼于内存管理，并深入到它的内部结构。虽然这些概念很通用，但示例大都来自于 32 位 x86 架构的 Linux 和 Windows 上。这第一篇文章描述了在内存中程序如何分布。

在一个多任务操作系统中的每个进程都运行在它自己的内存“沙箱”中。这个沙箱是一个<ruby> 虚拟地址空间 <rt>  virtual address space </rt></ruby>，在 32 位的模式中它总共有 4GB 的内存地址块。这些虚拟地址是通过内核<ruby> 页表 <rt>  page table </rt></ruby>映射到物理地址的，并且这些虚拟地址是由操作系统内核来维护，进而被进程所消费的。每个进程都有它自己的一组页表，但是这里有点玄机。一旦虚拟地址被启用，这些虚拟地址将被应用到这台电脑上的 *所有软件*，*包括内核本身*。因此，一部分虚拟地址空间必须保留给内核使用：

![Kernel/User Memory Split](/data/attachment/album/201801/18/184944wdn8i2oofzzyynh3.png)

但是，这并**不是**说内核就使用了很多的物理内存，恰恰相反，它只使用了很少一部分可用的地址空间映射到其所需要的物理内存。内核空间在内核页表中被标记为独占使用于 [特权代码](http://duartes.org/gustavo/blog/post/cpu-rings-privilege-and-protection) （ring 2 或更低），因此，如果一个用户模式的程序尝试去访问它，将触发一个页面故障错误。在 Linux 中，内核空间是始终存在的，并且在所有进程中都映射相同的物理内存。内核代码和数据总是可寻址的，准备随时去处理中断或者系统调用。相比之下，用户模式中的地址空间，在每次进程切换时都会发生变化：

![Process Switch Effects on Virtual Memory](/data/attachment/album/201801/18/184944hapz2flzafgd29pg.png)

蓝色的区域代表映射到物理地址的虚拟地址空间，白色的区域是尚未映射的部分。在上面的示例中，众所周知的内存“饕餮” Firefox 使用了大量的虚拟内存空间。在地址空间中不同的条带对应了不同的内存段，像<ruby> 堆 <rt>  heap </rt></ruby>、<ruby> 栈 <rt>  stack </rt></ruby>等等。请注意，这些段只是一系列内存地址的简化表示，它与 [Intel 类型的段](http://duartes.org/gustavo/blog/post/memory-translation-and-segmentation) *并没有任何关系* 。不过，这是一个在 Linux 进程的标准段布局：

![Flexible Process Address Space Layout In Linux](/data/attachment/album/201801/18/184944xpqp2n00ee25pmqm.png)

当计算机还是快乐、安全的时代时，在机器中的几乎每个进程上，那些段的起始虚拟地址都是**完全相同**的。这将使远程挖掘安全漏洞变得容易。漏洞利用经常需要去引用绝对内存位置：比如在栈中的一个地址，一个库函数的地址，等等。远程攻击可以闭着眼睛选择这个地址，因为地址空间都是相同的。当攻击者们这样做的时候，人们就会受到伤害。因此，地址空间随机化开始流行起来。Linux 会通过在其起始地址上增加偏移量来随机化[栈](http://lxr.linux.no/linux+v2.6.28.1/fs/binfmt_elf.c#L542)、[内存映射段](http://lxr.linux.no/linux+v2.6.28.1/arch/x86/mm/mmap.c#L84)、以及[堆](http://lxr.linux.no/linux+v2.6.28.1/arch/x86/kernel/process_32.c#L729)。不幸的是，32 位的地址空间是非常拥挤的，为地址空间随机化留下的空间不多，因此 [妨碍了地址空间随机化的效果](http://www.stanford.edu/%7Eblp/papers/asrandom.pdf)。

在进程地址空间中最高的段是栈，在大多数编程语言中它存储本地变量和函数参数。调用一个方法或者函数将推送一个新的<ruby> 栈帧 <rt>  stack frame </rt></ruby>到这个栈。当函数返回时这个栈帧被删除。这个简单的设计，可能是因为数据严格遵循 [后进先出（LIFO）](http://en.wikipedia.org/wiki/Lifo) 的次序，这意味着跟踪栈内容时不需要复杂的数据结构 —— 一个指向栈顶的简单指针就可以做到。推入和弹出也因此而非常快且准确。也可能是，持续的栈区重用往往会在 [CPU 缓存](http://duartes.org/gustavo/blog/post/intel-cpu-caches) 中保持活跃的栈内存，这样可以加快访问速度。进程中的每个线程都有它自己的栈。

向栈中推送更多的而不是刚合适的数据可能会耗尽栈的映射区域。这将触发一个页面故障，在 Linux 中它是通过 [`expand_stack()`](http://lxr.linux.no/linux+v2.6.28/mm/mmap.c#L1716) 来处理的，它会去调用 [`acct_stack_growth()`](http://lxr.linux.no/linux+v2.6.28/mm/mmap.c#L1544) 来检查栈的增长是否正常。如果栈的大小低于 `RLIMIT_STACK` 的值（一般是 8MB 大小），那么这是一个正常的栈增长和程序的合理使用，否则可能是发生了未知问题。这是一个栈大小按需调节的常见机制。但是，栈的大小达到了上述限制，将会发生一个栈溢出，并且，程序将会收到一个<ruby> 段故障 <rt>  Segmentation Fault </rt></ruby>错误。当映射的栈区为满足需要而扩展后，在栈缩小时，映射区域并不会收缩。就像美国联邦政府的预算一样，它只会扩张。

动态栈增长是 [唯一例外的情况](http://lxr.linux.no/linux+v2.6.28.1/arch/x86/mm/fault.c#L692) ，当它去访问一个未映射的内存区域，如上图中白色部分，是允许的。除此之外的任何其它访问未映射的内存区域将触发一个页面故障，导致段故障。一些映射区域是只读的，因此，尝试去写入到这些区域也将触发一个段故障。

在栈的下面，有内存映射段。在这里，内核将文件内容直接映射到内存。任何应用程序都可以通过 Linux 的 [`mmap()`](http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html) 系统调用（ [代码实现](http://lxr.linux.no/linux+v2.6.28.1/arch/x86/kernel/sys_i386_32.c#L27)）或者 Windows 的 [`CreateFileMapping()`](http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx) / [`MapViewOfFile()`](http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx) 来请求一个映射。内存映射是实现文件 I/O 的方便高效的方式。因此，它经常被用于加载动态库。有时候，也被用于去创建一个并不匹配任何文件的匿名内存映射，这种映射经常被用做程序数据的替代。在 Linux 中，如果你通过 [`malloc()`](http://www.kernel.org/doc/man-pages/online/pages/man3/malloc.3.html) 去请求一个大的内存块，C 库将会创建这样一个匿名映射而不是使用堆内存。这里所谓的“大”表示是超过了`MMAP_THRESHOLD` 设置的字节数，它的缺省值是 128 kB，可以通过 [`mallopt()`](http://www.kernel.org/doc/man-pages/online/pages/man3/undocumented.3.html) 去调整这个设置值。

接下来讲的是“堆”，就在我们接下来的地址空间中，堆提供运行时内存分配，像栈一样，但又不同于栈的是，它分配的数据生存期要长于分配它的函数。大多数编程语言都为程序提供了堆管理支持。因此，满足内存需要是编程语言运行时和内核共同来做的事情。在 C 中，堆分配的接口是 [`malloc()`](http://www.kernel.org/doc/man-pages/online/pages/man3/malloc.3.html) 一族，然而在支持垃圾回收的编程语言中，像 C#，这个接口使用 `new` 关键字。

如果在堆中有足够的空间可以满足内存请求，它可以由编程语言运行时来处理内存分配请求，而无需内核参与。否则将通过 [`brk()`](http://www.kernel.org/doc/man-pages/online/pages/man2/brk.2.html) 系统调用（[代码实现](http://lxr.linux.no/linux+v2.6.28.1/mm/mmap.c#L248)）来扩大堆以满足内存请求所需的大小。堆管理是比较 [复杂的](http://g.oswego.edu/dl/html/malloc.html)，在面对我们程序的混乱分配模式时，它通过复杂的算法，努力在速度和内存使用效率之间取得一种平衡。服务一个堆请求所需要的时间可能是非常可观的。实时系统有一个 [特定用途的分配器](http://rtportal.upv.es/rtmalloc/) 去处理这个问题。堆也会出现 *碎片化* ，如下图所示：

![Fragmented Heap](/data/attachment/album/201801/18/184945m4kwgkkowwk4uobu.png)

最后，我们抵达了内存的低位段：BSS、数据、以及程序文本。在 C 中，静态（全局）变量的内容都保存在 BSS 和数据中。它们之间的不同之处在于，BSS 保存 *未初始化的* 静态变量的内容，它的值在源代码中并没有被程序员设置。BSS 内存区域是 *匿名* 的：它没有映射到任何文件上。如果你在程序中写这样的语句 `static int cntActiveUsers`，`cntActiveUsers` 的内容就保存在 BSS 中。

反过来，数据段，用于保存在源代码中静态变量 *初始化后* 的内容。这个内存区域是 *非匿名* 的。它映射了程序的二进值镜像上的一部分，包含了在源代码中给定初始化值的静态变量内容。因此，如果你在程序中写这样的语句 `static int cntWorkerBees = 10`，那么，`cntWorkerBees` 的内容就保存在数据段中，并且初始值为 `10`。尽管可以通过数据段映射到一个文件，但是这是一个私有内存映射，意味着，如果改变内存，它并不会将这种变化反映到底层的文件上。必须是这样的，否则，分配的全局变量将会改变你磁盘上的二进制文件镜像，这种做法就太不可思议了！

用图去展示一个数据段是很困难的，因为它使用一个指针。在那种情况下，指针 `gonzo` 的*内容*（一个 4 字节的内存地址）保存在数据段上。然而，它并没有指向一个真实的字符串。而这个字符串存在于文本段中，文本段是只读的，它用于保存你的代码中的类似于字符串常量这样的内容。文本段也会在内存中映射你的二进制文件，但是，如果你的程序写入到这个区域，将会触发一个段故障错误。尽管在 C 中，它比不上从一开始就避免这种指针错误那么有效，但是，这种机制也有助于避免指针错误。这里有一个展示这些段和示例变量的图：

![ELF Binary Image Mapped Into Memory](/data/attachment/album/201801/18/184945caxqy3s235isbqdt.png)

你可以通过读取 `/proc/pid_of_process/maps` 文件来检查 Linux 进程中的内存区域。请记住，一个段可以包含很多的区域。例如，每个内存映射的文件一般都在 mmap 段中的它自己的区域中，而动态库有类似于 BSS 和数据一样的额外的区域。下一篇文章中我们将详细说明“<ruby> 区域 <rt>  area </rt></ruby>”的真正含义是什么。此外，有时候人们所说的“<ruby> 数据段 <rt>  data segment </rt></ruby>”是指“<ruby> 数据 <rt>  data </rt></ruby> + BSS + 堆”。

你可以使用 [nm](http://manpages.ubuntu.com/manpages/intrepid/en/man1/nm.1.html) 和 [objdump](http://manpages.ubuntu.com/manpages/intrepid/en/man1/objdump.1.html) 命令去检查二进制镜像，去显示它们的符号、地址、段等等。最终，在 Linux 中上面描述的虚拟地址布局是一个“弹性的”布局，这就是这几年来的缺省情况。它假设 `RLIMIT_STACK` 有一个值。如果没有值的话，Linux 将恢复到如下所示的“经典” 布局：

![Classic Process Address Space Layout In Linux](/data/attachment/album/201801/18/184945j66hejd0e48b5ub6.png)

这就是虚拟地址空间布局。接下来的文章将讨论内核如何对这些内存区域保持跟踪、内存映射、文件如何读取和写入、以及内存使用数据的意义。

---

via: <http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/>

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


当你在 Linux 上启动一个进程时会发生什么？

![](/data/attachment/album/201801/19/113216ou3o0ouab9z01lxx.jpg)

本文是关于 fork 和 exec 是如何在 Unix 上工作的。你或许已经知道，也有人还不知道。几年前当我了解到这些时，我惊叹不已。

我们要做的是启动一个进程。我们已经在博客上讨论了很多关于**系统调用**的问题，每当你启动一个进程或者打开一个文件，这都是一个系统调用。所以你可能会认为有这样的系统调用：

```
start_process(["ls", "-l", "my_cool_directory"])

```

这是一个合理的想法，显然这是它在 DOS 或 Windows 中的工作原理。我想说的是，这并不是 Linux 上的工作原理。但是，我查阅了文档，确实有一个 [posix\_spawn](http://man7.org/linux/man-pages/man3/posix_spawn.3.html) 的系统调用基本上是这样做的，不过这不在本文的讨论范围内。

### fork 和 exec

Linux 上的 `posix_spawn` 是通过两个系统调用实现的，分别是 `fork` 和 `exec`（实际上是 `execve`），这些都是人们常常使用的。尽管在 OS X 上，人们使用 `posix_spawn`，而 `fork` 和 `exec` 是不提倡的，但我们将讨论的是 Linux。

Linux 中的每个进程都存在于“进程树”中。你可以通过运行 `pstree` 命令查看进程树。树的根是 `init`，进程号是 1。每个进程（`init` 除外）都有一个父进程，一个进程都可以有很多子进程。

所以，假设我要启动一个名为 `ls` 的进程来列出一个目录。我是不是只要发起一个进程 `ls` 就好了呢？不是的。

我要做的是，创建一个子进程，这个子进程是我（`me`）本身的一个克隆，然后这个子进程的“脑子”被吃掉了，变成 `ls`。

开始是这样的：

```
my parent
    |- me

```

然后运行 `fork()`，生成一个子进程，是我（`me`）自己的一份克隆：

```
my parent
    |- me
       |-- clone of me

```

然后我让该子进程运行 `exec("ls")`，变成这样：

```
my parent
    |- me
       |-- ls

```

当 ls 命令结束后，我几乎又变回了我自己：

```
my parent
    |- me
       |-- ls (zombie)

```

在这时 `ls` 其实是一个僵尸进程。这意味着它已经死了，但它还在等我，以防我需要检查它的返回值（使用 `wait` 系统调用）。一旦我获得了它的返回值，我将再次恢复独自一人的状态。

```
my parent
    |- me

```

### fork 和 exec 的代码实现

如果你要编写一个 shell，这是你必须做的一个练习（这是一个非常有趣和有启发性的项目。Kamal 在 Github 上有一个很棒的研讨会：<https://github.com/kamalmarhubi/shell-workshop>）。

事实证明，有了 C 或 Python 的技能，你可以在几个小时内编写一个非常简单的 shell，像 bash 一样。（至少如果你旁边能有个人多少懂一点，如果没有的话用时会久一点。）我已经完成啦，真的很棒。

这就是 `fork` 和 `exec` 在程序中的实现。我写了一段 C 的伪代码。请记住，[fork 也可能会失败哦。](https://rachelbythebay.com/w/2014/08/19/fork/)

```
int pid = fork();
// 我要分身啦
// “我”是谁呢？可能是子进程也可能是父进程
if (pid == 0) {
    // 我现在是子进程
    // “ls” 吃掉了我脑子，然后变成一个完全不一样的进程
    exec(["ls"])
} else if (pid == -1) {
    // 天啊，fork 失败了，简直是灾难！
} else {
    // 我是父进程耶
    // 继续做一个酷酷的美男子吧
    // 需要的话，我可以等待子进程结束
}

```

### 上文提到的“脑子被吃掉”是什么意思呢？

进程有很多属性：

* 打开的文件（包括打开的网络连接）
* 环境变量
* 信号处理程序（在程序上运行 Ctrl + C 时会发生什么？）
* 内存（你的“地址空间”）
* 寄存器
* 可执行文件（`/proc/$pid/exe`）
* cgroups 和命名空间（与 Linux 容器相关）
* 当前的工作目录
* 运行程序的用户
* 其他我还没想到的

当你运行 `execve` 并让另一个程序吃掉你的脑子的时候，实际上几乎所有东西都是相同的！ 你们有相同的环境变量、信号处理程序和打开的文件等等。

唯一改变的是，内存、寄存器以及正在运行的程序，这可是件大事。

### 为何 fork 并非那么耗费资源（写入时复制）

你可能会问：“如果我有一个使用了 2GB 内存的进程，这是否意味着每次我启动一个子进程，所有 2 GB 的内存都要被复制一次？这听起来要耗费很多资源！”

事实上，Linux 为 `fork()` 调用实现了<ruby> 写时复制 <rt>  copy on write </rt></ruby>，对于新进程的 2GB 内存来说，就像是“看看旧的进程就好了，是一样的！”。然后，当如果任一进程试图写入内存，此时系统才真正地复制一个内存的副本给该进程。如果两个进程的内存是相同的，就不需要复制了。

### 为什么你需要知道这么多

你可能会说，好吧，这些细节听起来很厉害，但为什么这么重要？关于信号处理程序或环境变量的细节会被继承吗？这对我的日常编程有什么实际影响呢？

有可能哦！比如说，在 Kamal 的博客上有一个很有意思的 [bug](http://kamalmarhubi.com/blog/2015/06/30/my-favourite-bug-so-far-at-the-recurse-center/)。它讨论了 Python 如何使信号处理程序忽略了 `SIGPIPE`。也就是说，如果你从 Python 里运行一个程序，默认情况下它会忽略 `SIGPIPE`！这意味着，程序从 Python 脚本和从 shell 启动的表现会**有所不同**。在这种情况下，它会造成一个奇怪的问题。

所以，你的程序的环境（环境变量、信号处理程序等）可能很重要，都是从父进程继承来的。知道这些，在调试时是很有用的。

---

via: <https://jvns.ca/blog/2016/10/04/exec-will-eat-your-brain/>

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

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


如何轻松地寻找 GitHub 上超棒的项目和资源

![](/data/attachment/album/201801/19/114622kjzue1r60un59qo6.png)

在 GitHub 网站上每天都会新增上百个项目。由于 GitHub 上有成千上万的项目，要在上面搜索好的项目简直要累死人。好在，有那么一伙人已经创建了一些这样的列表。其中包含的类别五花八门，如编程、数据库、编辑器、游戏、娱乐等。这使得我们寻找在 GitHub 上托管的项目、软件、资源、库、书籍等其他东西变得容易了很多。有一个 GitHub 用户更进了一步，创建了一个名叫 `Awesome-finder` 的命令行工具，用来在 awesome 系列的仓库中寻找超棒的项目和资源。该工具可以让我们不需要离开终端（当然也就不需要使用浏览器了）的情况下浏览 awesome 列表。

在这篇简单的说明中，我会向你演示如何方便地在类 Unix 系统中浏览 awesome 列表。

### Awesome-finder - 方便地寻找 GitHub 上超棒的项目和资源

#### 安装 Awesome-finder

使用 `pip` 可以很方便地安装该工具，`pip` 是一个用来安装使用 Python 编程语言开发的程序的包管理器。

在 Arch Linux 及其衍生发行版中（比如 Antergos，Manjaro Linux），你可以使用下面命令安装 `pip`：

```
sudo pacman -S python-pip

```

在 RHEL，CentOS 中：

```
sudo yum install epel-release

```

```
sudo yum install python-pip

```

在 Fedora 上：

```
sudo dnf install epel-release
sudo dnf install python-pip

```

在 Debian，Ubuntu，Linux Mint 上：

```
sudo apt-get install python-pip

```

在 SUSE，openSUSE 上：

```
sudo zypper install python-pip

```

`pip` 安装好后，用下面命令来安装 'Awesome-finder'。

```
sudo pip install awesome-finder

```

#### 用法

Awesome-finder 会列出 GitHub 网站中如下这些主题（其实就是仓库）的内容：

* awesome
* awesome-android
* awesome-elixir
* awesome-go
* awesome-ios
* awesome-java
* awesome-javascript
* awesome-php
* awesome-python
* awesome-ruby
* awesome-rust
* awesome-scala
* awesome-swift

该列表会定期更新。

比如，要查看 `awesome-go` 仓库中的列表，只需要输入：

```
awesome go

```

你就能看到用 “Go” 写的所有流行的东西了，而且这些东西按字母顺序进行了排列。

![](/data/attachment/album/201801/19/114624u2i6n2i3iiztl7zi.png)

你可以通过 上/下 箭头在列表中导航。一旦找到所需要的东西，只需要选中它，然后按下回车键就会用你默认的 web 浏览器打开相应的链接了。

类似的，

* `awesome android` 命令会搜索 awesome-android 仓库。
* `awesome awesome` 命令会搜索 awesome 仓库。
* `awesome elixir` 命令会搜索 awesome-elixir。
* `awesome go` 命令会搜索 awesome-go。
* `awesome ios` 命令会搜索 awesome-ios。
* `awesome java` 命令会搜索 awesome-java。
* `awesome javascript` 命令会搜索 awesome-javascript。
* `awesome php` 命令会搜索 awesome-php。
* `awesome python` 命令会搜索 awesome-python。
* `awesome ruby` 命令会搜索 awesome-ruby。
* `awesome rust` 命令会搜索 awesome-rust。
* `awesome scala` 命令会搜索 awesome-scala。
* `awesome swift` 命令会搜索 awesome-swift。

而且，它还会随着你在提示符中输入的内容而自动进行筛选。比如，当我输入 `dj` 后，他会显示与 Django 相关的内容。

![](/data/attachment/album/201801/19/114625xku4ko00birk09o1.png)

若你想从最新的 `awesome-<topic>`( 而不是用缓存中的数据) 中搜索，使用 `-f` 或 `-force` 标志：

```
awesome <topic> -f (--force)

```

像这样：

```
awesome python -f

```

或，

```
awesome python --force

```

上面命令会显示 awesome-python GitHub 仓库中的列表。

很棒，对吧？

要退出这个工具的话，按下 ESC 键。要显示帮助信息，输入：

```
awesome -h

```

本文至此就结束了。希望本文能对你产生帮助。如果你觉得我们的文章对你有帮助，请将他们分享到你的社交网络中去，造福大众。我们马上还有其他好东西要来了。敬请期待！

---

via: <https://www.ostechnix.com/easily-find-awesome-projects-resources-hosted-github/>

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

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


微服务和容器：需要去防范的 5 个“坑”

Summary: 因为微服务和容器是 天生的“一对”，所以一起来使用它们，似乎也就不会有什么问题。当我们将这对“天作之合”投入到生产系统后，你就会发现，随着你的 IT 基础的提升，等待你的将是大幅上升的成本。是不是这样的？

>
> 微服务与容器天生匹配，但是你需要避开一些常见的陷阱。
>
>
>

![](/data/attachment/album/201801/19/153328uzw2zrg4k1ntrwgg.png)

因为微服务和容器是 [天生的“一对”](https://enterprisersproject.com/article/2017/8/5-advantages-containers-writing-applications)，所以一起来使用它们，似乎也就不会有什么问题。当我们将这对“天作之合”投入到生产系统后，你就会发现，随着你的 IT 基础的提升，等待你的将是大幅上升的成本。是不是这样的？

（让我们等一下，等人们笑声过去）

是的，很遗憾，这并不是你所希望的结果。虽然这两种技术的组合是非常强大的，但是，如果没有很好的规划和适配，它们并不能发挥出强大的性能来。在前面的文章中，我们整理了如果你想 [使用它们你应该掌握的知识](https://enterprisersproject.com/article/2017/9/microservices-and-containers-6-things-know-start-time)。但是，那些都是组织在容器中使用微服务时所遇到的常见问题。

事先了解这些可能出现的问题，能够帮你避免这些问题，为你的成功奠定更坚实的基础。

微服务和容器技术的出现是基于组织的需要、知识、资源等等更多的现实的要求。Mac Browning 说，“他们最常犯的一个 [错误] 是试图一次就想‘搞定’一切”，他是 [DigitalOcean](https://www.digitalocean.com/) 的工程部经理。“而真正需要面对的问题是，你的公司应该采用什么样的容器和微服务。”

**[ 努力向你的老板和同事去解释什么是微服务？阅读我们的入门读本[如何简单明了地解释微服务](https://enterprisersproject.com/article/2017/8/how-explain-microservices-plain-english?sc_cid=70160000000h0aXAAQ)。]**

Browning 和其他的 IT 专业人员分享了他们遇到的，在组织中使用容器化微服务时的五个陷阱，特别是在他们的生产系统生命周期的早期时候。在你的组织中需要去部署微服务和容器时，了解这些知识，将有助于你去评估微服务和容器化的部署策略。

### 1、 在部署微服务和容器化上，试图同时从零开始

如果你刚开始从完全的单例应用开始改变，或者如果你的组织在微服务和容器化上还没有足够的知识储备，那么，请记住：微服务和容器化并不是拴在一起、不可分别部署的。这就意味着，你可以发挥你公司内部专家的技术特长，先从部署其中的一个开始。Sungard Availability Services][5](https://www.sungardas.com/) 的资深 CTO 架构师 Kevin McGrath 建议，通过首先使用容器化来为你的团队建立知识和技能储备，通过对现有应用或者新应用进行容器化部署，接着再将它们迁移到微服务架构，这样才能最终感受到它们的优势所在。

McGrath 说，“微服务要想运行的很好，需要公司经过多年的反复迭代，这样才能实现快速部署和迁移”，“如果组织不能实现快速迁移，那么支持微服务将很困难。实现快速迁移，容器化可以帮助你，这样就不用担心业务整体停机”。

### 2、 从一个面向客户的或者关键的业务应用开始

对组织来说，一个相关陷阱恰恰就是从容器、微服务、或者两者同时起步：在尝试征服一片丛林中的雄狮之前，你应该先去征服处于食物链底端的一些小动物，以取得一些实践经验。

在你的学习过程中可以预期会有一些错误出现 —— 你是希望这些错误发生在面向客户的关键业务应用上，还是，仅对 IT 或者其他内部团队可见的低风险应用上？

DigitalOcean 的 Browning 说，“如果整个生态系统都是新的，为了获取一些微服务和容器方面的操作经验，那么，将它们先应用到影响面较低的区域，比如像你的持续集成系统或者内部工具，可能是一个低风险的做法。”你获得这方面的经验以后，当然会将这些技术应用到为客户提供服务的生产系统上。而现实情况是，不论你准备的如何周全，都不可避免会遇到问题，因此，需要提前为可能出现的问题制定应对之策。

### 3、 在没有合适的团队之前引入了太多的复杂性

由于微服务架构的弹性，它可能会产生复杂的管理需求。

作为 [Red Hat](https://www.redhat.com/en) 技术的狂热拥护者，[Gordon Haff](https://enterprisersproject.com/user/gordon-haff) 最近写道，“一个符合 OCI 标准的容器运行时本身管理单个容器是很擅长的，但是，当你开始使用多个容器和容器化应用时，并将它们分解为成百上千个节点后，管理和编配它们将变得极为复杂。最终，你将需要回过头来将容器分组来提供服务 —— 比如，跨容器的网络、安全、测控”。

Haff 提示说，“幸运的是，由于容器是可移植的，并且，与之相关的管理栈也是可移植的”。“这时出现的编配技术，比如像 [Kubernetes](https://www.redhat.com/en/containers/what-is-kubernetes) ，使得这种 IT 需求变得简单化了”（更多内容请查阅 Haff 的文章：[容器化为编写应用带来的 5 个优势](https://enterprisersproject.com/article/2017/8/5-advantages-containers-writing-applications)）。

另外，你需要合适的团队去做这些事情。如果你已经有 [DevOps shop](https://enterprisersproject.com/article/2017/8/devops-jobs-how-spot-great-devops-shop)，那么，你可能比较适合做这种转换。因为，从一开始你已经聚集了相关技能的人才。

Mike Kavis 说，“随着时间的推移，部署了越来越多的服务，管理起来会变得很不方便”，他是 [Cloud Technology Partners](https://www.cloudtp.com/) 的副总裁兼首席云架构设计师。他说，“在 DevOps 的关键过程中，确保各个领域的专家 —— 开发、测试、安全、运营等等 —— 全部都参与进来，并且在基于容器的微服务中，在构建、部署、运行、安全方面实现协作。”

### 4、 忽视重要的需求：自动化

除了具有一个合适的团队之外，那些在基于容器化的微服务部署比较成功的组织都倾向于以“实现尽可能多的自动化”来解决固有的复杂性。

Carlos Sanchez 说，“实现分布式架构并不容易，一些常见的挑战，像数据持久性、日志、排错等等，在微服务架构中都会变得很复杂”，他是 [CloudBees](https://www.cloudbees.com/) 的资深软件工程师。根据定义，Sanchez 提到的分布式架构，随着业务的增长，将变成一个巨大无比的繁重的运营任务。“服务和组件的增殖，将使得运营自动化变成一项非常强烈的需求”。Sanchez 警告说。“手动管理将限制服务的规模”。

### 5、 随着时间的推移，微服务变得越来越臃肿

在一个容器中运行一个服务或者软件组件并不神奇。但是，这样做并不能证明你就一定在使用微服务。Manual Nedbal， [ShieldX Networks](https://www.shieldx.com/) 的 CTO，他警告说，IT 专业人员要确保，随着时间的推移，微服务仍然是微服务。

Nedbal 说，“随着时间的推移，一些软件组件积累了大量的代码和特性，将它们放在一个容器中将会产生并不需要的微服务，也不会带来相同的优势”，也就是说，“随着组件的变大，工程师需要找到合适的时机将它们再次分解”。

---

via: <https://enterprisersproject.com/article/2017/9/using-microservices-containers-wisely-5-pitfalls-avoid>

作者：[Kevin Casey](https://enterprisersproject.com/user/kevin-casey) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


让我们使用 PC 键盘在终端演奏钢琴

![](/data/attachment/album/201801/20/151908e9pj06ce0a9va6pv.jpg)

厌倦了工作？那么来吧，让我们弹弹钢琴！是的，你没有看错，根本不需要真的钢琴。我们可以用 PC 键盘在命令行下就能弹钢琴。向你们介绍一下 `piano-rs` —— 这是一款用 Rust 语言编写的，可以让你用 PC 键盘在终端弹钢琴的简单工具。它自由开源，基于 MIT 协议。你可以在任何支持 Rust 的操作系统中使用它。

### piano-rs：使用 PC 键盘在终端弹钢琴

#### 安装

确保系统已经安装了 Rust 编程语言。若还未安装，运行下面命令来安装它。

```
curl https://sh.rustup.rs -sSf | sh

```

（LCTT 译注：这种直接通过 curl 执行远程 shell 脚本是一种非常危险和不成熟的做法。）

安装程序会问你是否默认安装还是自定义安装还是取消安装。我希望默认安装，因此输入 `1` （数字一）。

```
info: downloading installer

Welcome to Rust!

This will download and install the official compiler for the Rust programming
language, and its package manager, Cargo.

It will add the cargo, rustc, rustup and other commands to Cargo's bin
directory, located at:

/home/sk/.cargo/bin

This path will then be added to your PATH environment variable by modifying the
profile files located at:

/home/sk/.profile
/home/sk/.bash_profile

You can uninstall at any time with rustup self uninstall and these changes will
be reverted.

Current installation options:

default host triple: x86_64-unknown-linux-gnu
 default toolchain: stable
 modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
1

info: syncing channel updates for 'stable-x86_64-unknown-linux-gnu'
223.6 KiB / 223.6 KiB (100 %) 215.1 KiB/s ETA: 0 s
info: latest update on 2017-10-12, rust version 1.21.0 (3b72af97e 2017-10-09)
info: downloading component 'rustc'
 38.5 MiB / 38.5 MiB (100 %) 459.3 KiB/s ETA: 0 s
info: downloading component 'rust-std'
 56.7 MiB / 56.7 MiB (100 %) 220.6 KiB/s ETA: 0 s
info: downloading component 'cargo'
 3.7 MiB / 3.7 MiB (100 %) 173.5 KiB/s ETA: 0 s
info: downloading component 'rust-docs'
 4.1 MiB / 4.1 MiB (100 %) 224.0 KiB/s ETA: 0 s
info: installing component 'rustc'
info: installing component 'rust-std'
info: installing component 'cargo'
info: installing component 'rust-docs'
info: default toolchain set to 'stable'

stable installed - rustc 1.21.0 (3b72af97e 2017-10-09)

Rust is installed now. Great!

To get started you need Cargo's bin directory ($HOME/.cargo/bin) in your PATH
environment variable. Next time you log in this will be done automatically.

To configure your current shell run source $HOME/.cargo/env

```

登出然后重启系统来将 cargo 的 bin 目录纳入 `PATH` 变量中。

校验 Rust 是否正确安装：

```
$ rustc --version
rustc 1.21.0 (3b72af97e 2017-10-09)

```

太棒了！Rust 成功安装了。是时候构建 piano-rs 应用了。

使用下面命令克隆 Piano-rs 仓库：

```
git clone https://github.com/ritiek/piano-rs

```

上面命令会在当前工作目录创建一个名为 `piano-rs` 的目录并下载所有内容到其中。进入该目录：

```
cd piano-rs

```

最后，运行下面命令来构建 Piano-rs：

```
cargo build --release

```

编译过程要花上一阵子。

#### 用法

编译完成后，在 `piano-rs` 目录中运行下面命令：

```
./target/release/piano-rs

```

这就是我们在终端上的钢琴键盘了！可以开始弹指一些音符了。按下按键可以弹奏相应音符。使用 **左/右** 方向键可以在弹奏时调整音频。而，使用 **上/下** 方向键可以在弹奏时调整音长。

![](/data/attachment/album/201801/20/151909oqjxlqgf6lbi2qi5.png)

Piano-rs 使用与 [multiplayerpiano.com](http://www.multiplayerpiano.com/) 一样的音符和按键。另外，你可以使用[这些音符](https://pastebin.com/CX1ew0uB)来学习弹指各种流行歌曲。

要查看帮助。输入：

```
$ ./target/release/piano-rs -h

piano-rs 0.1.0
Ritiek Malhotra <ritiekmalhotra123@gmail.com>
Play piano in the terminal using PC keyboard.

USAGE:
 piano-rs [OPTIONS]

FLAGS:
 -h, --help Prints help information
 -V, --version Prints version information

OPTIONS:
 -c, --color <COLOR> Color of block to generate when a note is played (Default: "red")
 -d, --duration <DURATION> Duration to play each note for, where 0 means till the end of note (Default: 0)
 -s, --sequence <SEQUENCE> Frequency sequence from 0 to 5 to begin with (Default: 2)

```

我必须承认这是个超级酷的项目。对于那些买不起钢琴的人，很推荐使用这款应用。

祝你周末愉快！！

此致敬礼！

---

via: <https://www.ostechnix.com/let-us-play-piano-terminal-using-pc-keyboard/>

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

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


autorandr：自动调整屏幕布局

Summary: 像许多笔记本用户一样，我经常将笔记本插入到不同的显示器上（桌面上有多台显示器，演示时有投影机等）。运行 xrandr 命令或点击界面非常繁琐，编写脚本也不是很好。

![](/data/attachment/album/201801/20/153223rhk5n2irohakh8oq.jpg)

像许多笔记本用户一样，我经常将笔记本插入到不同的显示器上（桌面上有多台显示器，演示时有投影机等）。运行 `xrandr` 命令或点击界面非常繁琐，编写脚本也不是很好。

最近，我遇到了 [autorandr](https://github.com/phillipberndt/autorandr)，它使用 EDID（和其他设置）检测连接的显示器，保存 `xrandr` 配置并恢复它们。它也可以在加载特定配置时运行任意脚本。我已经打包了它，目前仍在 NEW 状态。如果你不能等待，[这是 deb](https://www.donarmstrong.com/autorandr_1.2-1_all.deb)，[这是 git 仓库](https://git.donarmstrong.com/deb_pkgs/autorandr.git)。

要使用它，只需安装软件包，并创建你的初始配置（我这里用的名字是 `undocked`）：

```
autorandr --save undocked

```

然后，连接你的笔记本（或者插入你的外部显示器），使用 `xrandr`（或其他任何）更改配置，然后保存你的新配置（我这里用的名字是 workstation）：

```
autorandr --save workstation

```

对你额外的配置（或当你有新的配置）进行重复操作。

`autorandr` 有 `udev`、`systemd` 和 `pm-utils` 钩子，当新的显示器出现时 `autorandr --change` 应该会立即运行。如果需要，也可以手动运行 `autorandr --change` 或 `autorandr - load workstation`。你也可以在加载配置后在 `~/.config/autorandr/$PROFILE/postswitch` 添加自己的脚本来运行。由于我运行 i3，我的工作站配置如下所示：

```
#!/bin/bash

xrandr --dpi 92
xrandr --output DP2-2 --primary
i3-msg '[workspace="^(1|4|6)"] move workspace to output DP2-2;'
i3-msg '[workspace="^(2|5|9)"] move workspace to output DP2-3;'
i3-msg '[workspace="^(3|8)"] move workspace to output DP2-1;'

```

它适当地修正了 dpi，设置主屏幕（可能不需要？），并移动 i3 工作区。你可以通过在配置文件目录中添加一个 `block` 钩子来安排配置永远不会运行。

如果你定期更换显示器，请看一下！

---

via: <https://www.donarmstrong.com/posts/autorandr/>

作者：[Don Armstrong](https://www.donarmstrong.com) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


如何配置一个小朋友使用的 Linux

![](/data/attachment/album/201801/20/225319qudbrl0w2h07nr2x.jpg)

如果你接触电脑有一段时间了，提到 Linux，你应该会联想到一些特定的人群。你觉得哪些人在使用 Linux？别担心，这就告诉你。

Linux 是一个可以深度定制的操作系统。这就赋予了用户高度控制权。事实上，家长们可以针对小朋友设置出一个专门的 Linux 发行版，确保让孩子不会在不经意间接触那些高危地带。但是相比 Windows，这些设置显得更费时，但是一劳永逸。Linux 的开源免费，让教室或计算机实验室系统部署变得容易。

### 小朋友的 Linux 发行版

这些为儿童而简化的 Linux 发行版，界面对儿童十分友好。家长只需要先安装和设置，孩子就可以完全独立地使用计算机了。你将看见多彩的图形界面，丰富的图画，简明的语言。

不过，不幸的是，这类发行版不会经常更新，甚至有些已经不再积极开发了。但也不意味着不能使用，只是故障发生率可能会高一点。

![qimo-gcompris](/data/attachment/album/201801/20/225320mpuj4eifuefzwufo.jpg "qimo-gcompris")

#### 1. Edubuntu

[Edubuntu](http://www.edubuntu.org) 是 Ubuntu 的一个分支版本，专用于教育事业。它拥有丰富的图形环境和大量教育软件，易于更新维护。它被设计成初高中学生专用的操作系统。

#### 2. Ubermix

[Ubermix](http://www.ubermix.org/) 是根据教育需求而被设计出来的。Ubermix 将学生从复杂的计算机设备中解脱出来，就像手机一样简单易用，而不会牺牲性能和操作系统的全部能力。一键开机、五分钟安装、二十秒钟快速还原机制，以及超过 60 个的免费预装软件，ubermix 就可以让你的硬件变成功能强大的学习设备。

#### 3. Sugar

[Sugar](http://wiki.sugarlabs.org/go/Downloads) 是为“每个孩子一台笔记本（OLPC）计划”而设计的操作系统。Sugar 和普通桌面 Linux 大不相同，它更专注于学生课堂使用和教授编程能力。

**注意** ：很多为儿童开发的 Linux 发行版我并没有列举，因为它们大都不再积极维护或是被长时间遗弃。

### 为小朋友过筛选内容的 Linux

只有你，最能保护孩子拒绝访问少儿不宜的内容，但是你不可能每分每秒都在孩子身边。但是你可以设置“限制访问”的 URL 到内容过滤代理服务器（通过软件）。这里有两个主要的软件可以帮助你。

![儿童内容过滤 Linux](/data/attachment/album/201801/20/225324wympvvudb9xvvh5i.png "linux-for-children-content-filtering")

#### 1、 DansGuardian

[DansGuardian](https://help.ubuntu.com/community/DansGuardian)，一个开源内容过滤软件，几乎可以工作在任何 Linux 发行版上，灵活而强大，需要你通过命令行设置你的代理。如果你不深究代理服务器的设置，这可能是最强力的选择。

配置 DansGuardian 可不是轻松活儿，但是你可以跟着安装说明按步骤完成。一旦设置完成，它将是过滤不良内容的高效工具。

#### 2、 Parental Control: Family Friendly Filter

[Parental Control: Family Friendly Filter](https://addons.mozilla.org/en-US/firefox/addon/family-friendly-filter/) 是 Firefox 的插件，允许家长屏蔽包含色情内容在内的任何少儿不宜的网站。你也可以设置不良网站黑名单，将其一直屏蔽。

![firefox 内容过滤插件](/data/attachment/album/201801/20/225325kuixuaq3hs8uau33.png "firefox-content-filter-addon")

你使用的老版本的 Firefox 可能不支持 [网页插件](https://www.maketecheasier.com/best-firefox-web-extensions/)，那么你可以使用 [ProCon Latte 内容过滤器](https://addons.mozilla.org/en-US/firefox/addon/procon-latte/)。家长们添加网址到预设的黑名单内，然后设置密码，防止设置被篡改。

#### 3、 Blocksi 网页过滤

[Blocksi 网页过滤](https://chrome.google.com/webstore/detail/blocksi-web-filter/pgmjaihnmedpcdkjcgigocogcbffgkbn?hl=en) 是 Chrome 浏览器插件，能有效过滤网页和 Youtube。它也提供限时服务，这样你可以限制家里小朋友的上网时间。

### 闲趣

![Linux 儿童游戏：tux kart](/data/attachment/album/201801/20/225326icz2o11215lxlzt2.jpg "linux-for-children-tux-kart")

给孩子们使用的计算机，不管是否是用作教育，最好都要有一些游戏。虽然 Linux 没有 Windows 那么好的游戏性，但也在奋力追赶。这有建议几个有益的游戏，你可以安装到孩子们的计算机上。

* [Super Tux Kart](http://supertuxkart.sourceforge.net/)（竞速卡丁车）
* [GCompris](http://gcompris.net/)（适合教育的游戏）
* [Secret Maryo Chronicles](http://www.secretmaryo.org/)（超级马里奥）
* [Childsplay](http://www.schoolsplay.org/)（教育/记忆力游戏）
* [EToys](http://www.squeakland.org/about/intro/)（儿童编程）
* [TuxTyping](http://tux4kids.alioth.debian.org/tuxtype/index.php)（打字游戏）
* [Kalzium](http://edu.kde.org/kalzium/)（元素周期表）
* [Tux of Math Command](http://tux4kids.alioth.debian.org/tuxmath/index.php)（数学游戏）
* [Pink Pony](http://code.google.com/p/pink-pony/)（Tron 风格竞速游戏）
* [KTuberling](http://games.kde.org/game.php?game=ktuberling)（创造游戏）
* [TuxPaint](http://www.tuxpaint.org/)（绘画）
* [Blinken](https://www.kde.org/applications/education/blinken/)（[记忆力](https://www.ebay.com/sch/i.html?_nkw=memory) 游戏）
* [KTurtle](https://www.kde.org/applications/education/kturtle/)（编程指导环境）
* [KStars](https://www.kde.org/applications/education/kstars/)（天文馆）
* [Marble](https://www.kde.org/applications/education/marble/)（虚拟地球）
* [KHangman](https://www.kde.org/applications/education/khangman/)（猜单词）

### 结论：为什么给孩子使用 Linux？

Linux 以复杂著称。那为什么给孩子使用 Linux？这是为了让孩子适应 Linux。在 Linux 上工作给了解系统运行提供了很多机会。当孩子长大，他们就有随自己兴趣探索的机会。得益于 Linux 如此开放的平台，孩子们才能得到这么一个极佳的场所发现自己对计算机的毕生之恋。

本文于 2010 年 7 月首发，2017 年 12 月更新。

图片来自 [在校学生](https://www.flickr.com/photos/lupuca/8720604364)

---

via: <https://www.maketecheasier.com/configure-linux-for-children/>

作者：[Alexander Fox](https://www.maketecheasier.com/author/alexfox/) 译者：[CYLeft](https://github.com/CYLeft) 校对：[wxy](https://github.com/wxy)

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


如何找出并打包文件成 tar 包

Summary: 我想找出所有的 *.doc 文件并将它们创建成一个 tar 包，然后存储在 /nfs/backups/docs/file.tar 中。

【find $HOME -type f -name "*.sh" | xargs tar cfvz /nfs/x230/my-shell-scripts.tgz】这种管道符方式，有时会不起作用，导致如果是时间条件的话，会不按条件，而将所有结果都输出到包中！<br />
【find /dir/to/search/ -name "*.doc" -exec tar -rvf out.tar {} \;】或【tar cvf - `find . -mtime -1 -type f -print` > updatefiles.tar】是我首选的两种方式！！目前还没有出过错！！！

有同事问我：“{}”到底要不要加引号？

这个问题我这里也特地提出来讨论一下，怎么说呢，应该是：默认不加引号！

引号在Linux中，【单引号，作为字符转义符，即单引号里的为字符】，【双引号，保留变量的字符转义符，即默认情况下引号中为字符】，这里默认不加引号，不过建议大家习惯性使用【双引号】呢！！！

Q：我想找出所有的 \*.doc 文件并将它们创建成一个 tar 包，然后存储在 `/nfs/backups/docs/file.tar` 中。是否可以在 Linux 或者类 Unix 系统上查找并 tar 打包文件？

`find` 命令用于按照给定条件在目录层次结构中搜索文件。`tar` 命令是用于 Linux 和类 Unix 系统创建 tar 包的归档工具。

[![How to find and tar files on linux unix](/data/attachment/album/201801/20/230406vgfvzg7g777t7ztp.jpg)](https://www.cyberciti.biz/media/new/faq/2017/12/How-to-find-and-tar-files-on-linux-unix.jpg)

让我们看看如何将 `tar` 命令与 `find` 命令结合在一个命令行中创建一个 tar 包。

### Find 命令

语法是：

```
find /path/to/search -name "file-to-search" -options
## 找出所有 Perl（*.pl）文件 ##
find $HOME -name "*.pl" -print
## 找出所有 *.doc 文件 ##
find $HOME -name "*.doc" -print
## 找出所有 *.sh（shell 脚本）并运行 ls -l 命令 ##
find . -iname "*.sh" -exec ls -l {} +

```

最后一个命令的输出示例：

```
-rw-r--r-- 1 vivek vivek 1169 Apr  4  2017 ./backups/ansible/cluster/nginx.build.sh
-rwxr-xr-x 1 vivek vivek 1500 Dec  6 14:36 ./bin/cloudflare.pure.url.sh
lrwxrwxrwx 1 vivek vivek   13 Dec 31  2013 ./bin/cmspostupload.sh -> postupload.sh
lrwxrwxrwx 1 vivek vivek   12 Dec 31  2013 ./bin/cmspreupload.sh -> preupload.sh
lrwxrwxrwx 1 vivek vivek   14 Dec 31  2013 ./bin/cmssuploadimage.sh -> uploadimage.sh
lrwxrwxrwx 1 vivek vivek   13 Dec 31  2013 ./bin/faqpostupload.sh -> postupload.sh
lrwxrwxrwx 1 vivek vivek   12 Dec 31  2013 ./bin/faqpreupload.sh -> preupload.sh
lrwxrwxrwx 1 vivek vivek   14 Dec 31  2013 ./bin/faquploadimage.sh -> uploadimage.sh
-rw-r--r-- 1 vivek vivek  778 Nov  6 14:44 ./bin/mirror.sh
-rwxr-xr-x 1 vivek vivek  136 Apr 25  2015 ./bin/nixcraft.com.301.sh
-rwxr-xr-x 1 vivek vivek  547 Jan 30  2017 ./bin/paypal.sh
-rwxr-xr-x 1 vivek vivek  531 Dec 31  2013 ./bin/postupload.sh
-rwxr-xr-x 1 vivek vivek  437 Dec 31  2013 ./bin/preupload.sh
-rwxr-xr-x 1 vivek vivek 1046 May 18  2017 ./bin/purge.all.cloudflare.domain.sh
lrwxrwxrwx 1 vivek vivek   13 Dec 31  2013 ./bin/tipspostupload.sh -> postupload.sh
lrwxrwxrwx 1 vivek vivek   12 Dec 31  2013 ./bin/tipspreupload.sh -> preupload.sh
lrwxrwxrwx 1 vivek vivek   14 Dec 31  2013 ./bin/tipsuploadimage.sh -> uploadimage.sh
-rwxr-xr-x 1 vivek vivek 1193 Oct 18  2013 ./bin/uploadimage.sh
-rwxr-xr-x 1 vivek vivek   29 Nov  6 14:33 ./.vim/plugged/neomake/tests/fixtures/errors.sh
-rwxr-xr-x 1 vivek vivek  215 Nov  6 14:33 ./.vim/plugged/neomake/tests/helpers/trap.sh

```

### Tar 命令

要[创建 /home/vivek/projects 目录的 tar 包](https://www.cyberciti.biz/faq/creating-a-tar-file-linux-command-line/)，运行：

```
$ tar -cvf /home/vivek/projects.tar /home/vivek/projects

```

### 结合 find 和 tar 命令

语法是：

```
find /dir/to/search/ -name "*.doc" -exec tar -rvf out.tar {} \;

```

或者

```
find /dir/to/search/ -name "*.doc" -exec tar -rvf out.tar {} +

```

例子：

```
find $HOME -name "*.doc" -exec tar -rvf /tmp/all-doc-files.tar "{}" \;

```

或者

```
find $HOME -name "*.doc" -exec tar -rvf /tmp/all-doc-files.tar "{}" +

```

这里，find 命令的选项：

* `-name "*.doc"`：按照给定的模式/标准查找文件。在这里，在 $HOME 中查找所有 \*.doc 文件。
* `-exec tar ...` ：对 `find` 命令找到的所有文件执行 `tar` 命令。

这里，`tar` 命令的选项：

* `-r`：将文件追加到归档末尾。参数与 `-c` 选项具有相同的含义。
* `-v`：详细输出。
* `-f out.tar` : 将所有文件追加到 out.tar 中。

也可以像下面这样将 `find` 命令的输出通过管道输入到 `tar` 命令中：

```
find $HOME -name "*.doc" -print0 | tar -cvf /tmp/file.tar --null -T -

```

传递给 `find` 命令的 `-print0` 选项处理特殊的文件名。`--null` 和 `-T` 选项告诉 `tar` 命令从标准输入/管道读取输入。也可以使用 `xargs` 命令：

```
find $HOME -type f -name "*.sh" | xargs tar cfvz /nfs/x230/my-shell-scripts.tgz

```

有关更多信息，请参阅下面的 man 页面：

```
$ man tar
$ man find
$ man xargs
$ man bash

```

---

作者简介：

作者是 nixCraft 的创造者，是一名经验丰富的系统管理员，也是 Linux 操作系统/Unix shell 脚本培训师。他曾与全球客户以及 IT、教育、国防和太空研究以及非营利部门等多个行业合作。在 Twitter、Facebook 和 Google+ 上关注他。

---

via: <https://www.cyberciti.biz/faq/linux-unix-find-tar-files-into-tarball-command/>

作者：[Vivek Gite](https://www.cyberciti.biz) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


通过 ssh 会话执行 bash 别名

Summary: 我在远程主机上上设置过一个叫做 file_repl 的 bash 别名 。当我使用 ssh 命令登录远程主机后，可以很正常的使用这个别名。然而这个 bash 别名却无法通过 ssh 来运行

![](/data/attachment/album/201801/21/193337r4ufopgmuf6oomk6.png)

我在远程主机上[上设置过一个叫做 file\_repl 的 bash 别名](https://bash.cyberciti.biz/guide/Alias_command#How_to_define_alias) 。当我使用 ssh 命令登录远程主机后，可以很正常的使用这个别名。然而这个 bash 别名却无法通过 ssh 来运行，像这样：

```
$ ssh vivek@server1.cyberciti.biz file_repl
bash：file_repl：command not found

```

我要怎样做才能通过 ssh 命令运行 bash 别名呢？

SSH 客户端 (ssh) 是一个登录远程服务器并在远程系统上执行 shell 命令的 Linux/Unix 命令。它被设计用来在两个非信任的机器上通过不安全的网络（比如互联网）提供安全的加密通讯。

### 如何用 ssh 客户端执行命令

通过 ssh 运行 `free` 命令或 [date 命令](https://www.cyberciti.biz/faq/unix-date-command-howto-see-set-date-time/ "See Linux/Unix date command examples for more info") 可以这样做：

```
$ ssh vivek@server1.cyberciti.biz date

```

结果为：

```
Tue Dec 26 09：02：50 UTC 2017

```

或者：

```
$ ssh vivek@server1.cyberciti.biz free -h

```

结果为：

```
 total used free shared buff/cache available
Mem：2.0G 428M 138M 145M 1.4G 1.1G
Swap：0B 0B 0B

```

### 理解 bash shell 以及命令的类型

[bash shell](https://bash.cyberciti.biz/guide/Shell_commands) 共有下面几类命令：

1. 别名，比如 `ll`
2. 关键字，比如 `if`
3. 函数 （用户自定义函数，比如 `genpasswd`）
4. 内置命令，比如 `pwd`
5. 外部文件，比如 `/bin/date`

[type 命令](https://bash.cyberciti.biz/guide/Type_command) 和 [command 命令](https://bash.cyberciti.biz/guide/Command) 可以用来查看命令类型：

```
$ type -a date
date is /bin/date
$ type -a free
free is /usr/bin/free
$ command -V pwd
pwd is a shell builtin
$ type -a file_repl
is aliased to `sudo -i /shared/takes/master.replication'

```

`date` 和 `free` 都是外部命令，而 `file_repl` 是 `sudo -i /shared/takes/master.replication` 的别名。你不能直接执行像 `file_repl` 这样的别名：

```
$ ssh user@remote file_repl

```

### 在 Unix 系统上无法直接通过 ssh 客户端执行 bash 别名

要解决这个问题可以用下面方法运行 ssh 命令：

```
$ ssh -t user@remote /bin/bash -ic 'your-alias-here'
$ ssh -t user@remote /bin/bash -ic 'file_repl'

```

`ssh` 命令选项：

* `-t`：[强制分配伪终端。可以用来在远程机器上执行任意的](https://www.cyberciti.biz/faq/linux-unix-bsd-sudo-sorry-you-must-haveattytorun/) 基于屏幕的程序，有时这非常有用。当使用 `-t` 时你可能会收到一个类似 “bash: cannot set terminal process group (-1): Inappropriate ioctl for device. bash: no job control in this shell .” 的错误。

bash shell 的选项：

* `-i`：运行交互 shell，这样 shell 才能运行 bash 别名。
* `-c`：要执行的命令取之于第一个非选项参数的命令字符串。若在命令字符串后面还有其他参数，这些参数会作为位置参数传递给命令，参数从 `$0` 开始。

总之，要运行一个名叫 `ll` 的 bash 别名，可以运行下面命令：

```
$ ssh -t vivek@server1.cyberciti.biz -ic 'll'

```

结果为：

[![Running bash aliases over ssh based session when using Unix or Linux ssh cli](/data/attachment/album/201801/21/193409r4mfvaqbgv9q4xww.jpg)](https://www.cyberciti.biz/media/new/faq/2017/12/Bash-shell-aliase-not-found-when-run-over-ssh-on-linux-unix.jpg)

下面是我的一个 shell 脚本的例子：

```
#！/bin/bash
I="tags.deleted.410"
O="/tmp/https.www.cyberciti.biz.410.url.conf"
box="vivek@server1.cyberciti.biz"
[！-f "$I" ] && { echo "$I file not found。"; exit 10; }
>$O
cat "$I" | sort | uniq | while read -r u
do
    uu="${u##https：//www.cyberciti.biz}"
    echo "~^$uu 1;" >>"${O}"
done
echo "Config file created at ${O} and now updating remote nginx config file"
scp "${O}" ${box}：/tmp/
ssh ${box} /usr/bin/lxc file push /tmp/https.www.cyberciti.biz.410.url.conf nginx-container/etc/nginx/
ssh -t ${box} /bin/bash -ic 'push_config_job'

```

### 相关资料

更多信息请输入下面命令查看 [OpenSSH 客户端](https://man.openbsd.org/ssh) 和 [bash 的 man 帮助](https://www.gnu.org/software/bash/manual/bash.html) ：

```
$ man ssh
$ man bash
$ help type
$ help command

```

---

via: <https://www.cyberciti.biz/faq/use-bash-aliases-ssh-based-session/>

作者：[Vivek Gite](https://www.cyberciti.biz) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


如何创建定制的 Ubuntu Live CD 镜像

Summary: 我找到了另一种创建 Ubuntu Live CD 镜像的工具。使用 Cubic，这是一个用来创建定制的可启动的 Ubuntu Live CD（ISO）镜像的 GUI 应用程序。

![](/data/attachment/album/201801/21/223622aq923y3rroz2lpqq.png)

今天让我们来讨论一下如何创建 Ubuntu Live CD 的定制镜像（ISO）。我们以前可以使用 [Pinguy Builder](https://www.ostechnix.com/pinguy-builder-build-custom-ubuntu-os/) 完成这项工作。但是，现在它似乎停止维护了。最近 Pinguy Builder 的官方网站似乎没有任何更新。幸运的是，我找到了另一种创建 Ubuntu Live CD 镜像的工具。使用 Cubic （即 **C**ustom **Ub**untu **I**SO **C**reator 的首字母缩写），这是一个用来创建定制的可启动的 Ubuntu Live CD（ISO）镜像的 GUI 应用程序。

Cubic 正在积极开发，它提供了许多选项来轻松地创建一个定制的 Ubuntu Live CD ，它有一个集成的 chroot 命令行环境（LCTT 译注：chroot —— Change Root，也就是改变程序执行时所参考的根目录位置），在那里你可以定制各种方面，比如安装新的软件包、内核，添加更多的背景壁纸，添加更多的文件和文件夹。它有一个直观的 GUI 界面，在 live 镜像创建过程中可以轻松的利用导航（可以利用点击鼠标来回切换）。您可以创建一个新的自定义镜像或修改现有的项目。因为它可以用来制作 Ubuntu live 镜像，所以我相信它可以用在制作其他 Ubuntu 的发行版和衍生版镜像中，比如 Linux Mint。

### 安装 Cubic

Cubic 的开发人员已经做出了一个 PPA 来简化安装过程。要在 Ubuntu 系统上安装 Cubic ，在你的终端上运行以下命令:

```
sudo apt-add-repository ppa:cubic-wizard/release
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6494C6D6997C215E
sudo apt update
sudo apt install cubic

```

### 利用 Cubic 创建 Ubuntu Live CD 的定制镜像

安装完成后，从应用程序菜单或 dock 启动 Cubic。这是在我在 Ubuntu 16.04 LTS 桌面系统中 Cubic 的样子。

为新项目选择一个目录。它是保存镜像文件的目录。

![](/data/attachment/album/201801/21/223624gi626h0lns2565ln.png)

请注意，Cubic 不是创建您当前系统的 Live CD 镜像，而是利用 Ubuntu 的安装 CD 来创建一个定制的 Live CD，因此，你应该有一个最新的 ISO 镜像。

选择您存储 Ubuntu 安装 ISO 镜像的路径。Cubic 将自动填写您定制操作系统的所有细节。如果你愿意，你可以改变细节。单击 Next 继续。

![](/data/attachment/album/201801/21/223625hf5w8ttmvt0otf82.png)

接下来，来自源安装介质中的压缩的 Linux 文件系统将被提取到项目的目录（在我们的例子中目录的位置是 `/home/ostechnix/custom_ubuntu`)。

![](/data/attachment/album/201801/21/223627lo39rrwr974t42u3.png)

一旦文件系统被提取出来，将自动加载到 chroot 环境。如果你没有看到终端提示符，请按几次回车键。

![](/data/attachment/album/201801/21/223629bpirbweefpwbft8i.png)

在这里可以安装任何额外的软件包，添加背景图片，添加软件源列表，添加最新的 Linux 内核和所有其他定制到你的 Live CD 。

例如，我希望 `vim` 安装在我的 Live CD 中，所以现在就要安装它。

![](/data/attachment/album/201801/21/223630l38u8e955399udus.png)

我们不需要使用 `sudo`，因为我们已经在具有最高权限（root）的环境中了。

类似地，如果需要，可以安装更多的任何版本 Linux 内核。

```
apt install linux-image-extra-4.10.0-24-generic

```

此外，您还可以更新软件源列表（添加或删除软件存储库列表）：

![](/data/attachment/album/201801/21/223632nurjwwlyux64xhhr.png)

修改源列表后，不要忘记运行 `apt update` 命令来更新源列表：

```
apt update

```

另外，您还可以向 Live CD 中添加文件或文件夹。复制文件或文件夹（右击它们并选择复制或者利用 `CTRL+C`），在终端右键单击（在 Cubic 窗口内)，选择 “Paste file(s)”，最后点击 Cubic 向导底部的 “Copy”。

![](/data/attachment/album/201801/21/223633tox1z5kvwo35g35o.png)

**Ubuntu 17.10 用户注意事项**

>
> 在 Ubuntu 17.10 系统中，DNS 查询可能无法在 chroot 环境中工作。如果您正在制作一个定制的 Ubuntu 17.10 Live 镜像，您需要指向正确的 `resolve.conf` 配置文件：
>
>
>
> ```
> ln -sr /run/systemd/resolve/resolv.conf /run/systemd/resolve/stub-resolv.conf
>
> ```
>
> 要验证 DNS 解析工作，运行:
>
>
>
> ```
> cat /etc/resolv.conf
> ping google.com
>
> ```
>
>

如果你想的话，可以添加你自己的壁纸。要做到这一点，请切换到 `/usr/share/backgrounds/` 目录，

```
cd /usr/share/backgrounds

```

并将图像拖放到 Cubic 窗口中。或复制图像，右键单击 Cubic 终端窗口并选择 “Paste file(s)” 选项。此外，确保你在 `/usr/share/gnome-backproperties` 的XML文件中添加了新的壁纸，这样你可以在桌面上右键单击新添加的图像选择 “Change Desktop Background” 进行交互。完成所有更改后，在 Cubic 向导中单击 “Next”。

接下来，选择引导到新的 Live ISO 镜像时使用的 Linux 内核版本。如果已经安装了其他版本内核，它们也将在这部分中被列出。然后选择您想在 Live CD 中使用的内核。

![](/data/attachment/album/201801/21/223634aqkt9pf3jr0a30j3.png)

在下一节中，选择要从您的 Live 映像中删除的软件包。在使用定制的 Live 映像安装完 Ubuntu 操作系统后，所选的软件包将自动删除。在选择要删除的软件包时，要格外小心，您可能在不知不觉中删除了一个软件包，而此软件包又是另外一个软件包的依赖包。

![](/data/attachment/album/201801/21/223636rv3t3vrozb2zmzof.png)

接下来， Live 镜像创建过程将开始。这里所要花费的时间取决于你定制的系统规格。

![](/data/attachment/album/201801/21/223637d70ghbf0tyo30083.png)

镜像创建完成后后，单击 “Finish”。Cubic 将显示新创建的自定义镜像的细节。

如果你想在将来修改刚刚创建的自定义 Live 镜像，不要选择“ Delete all project files, except the generated disk image and the corresponding MD5 checksum file”（除了生成的磁盘映像和相应的 MD5 校验和文件之外，删除所有的项目文件\*\*） ，Cubic 将在项目的工作目录中保留自定义图像，您可以在将来进行任何更改。而不用从头再来一遍。

要为不同的 Ubuntu 版本创建新的 Live 镜像，最好使用不同的项目目录。

### 利用 Cubic 修改 Ubuntu Live CD 的定制镜像

从菜单中启动 Cubic ，并选择一个现有的项目目录。单击 “Next” 按钮，您将看到以下三个选项：

1. Create a disk image from the existing project. （从现有项目创建一个磁盘映像。）
2. Continue customizing the existing project.（继续定制现有项目。）
3. Delete the existing project.（删除当前项目。）

![](/data/attachment/album/201801/21/223639lrz88u781ooggl78.png)

第一个选项将允许您从现有项目中使用之前所做的自定义设置创建一个新的 Live ISO 镜像。如果您丢失了 ISO 镜像，您可以使用第一个选项来创建一个新的。

第二个选项允许您在现有项目中进行任何其他更改。如果您选择此选项，您将再次进入 chroot 环境。您可以添加新的文件或文件夹，安装任何新的软件，删除任何软件，添加其他的 Linux 内核，添加桌面背景等等。

第三个选项将删除现有的项目，所以您可以从头开始。选择此选项将删除所有文件，包括新生成的 ISO 镜像文件。

我用 Cubic 做了一个定制的 Ubuntu 16.04 LTS 桌面 Live CD 。就像这篇文章里描述的一样。如果你想创建一个 Ubuntu Live CD， Cubic 可能是一个不错的选择。

就这些了，再会！

---

via: <https://www.ostechnix.com/create-custom-ubuntu-live-cd-image/>

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

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


Debian 取代 Ubuntu 成为 Google 内部 Linux 发行版的新选择

>
> 摘要：Google 多年来一直使用基于 Ubuntu 的内部操作系统 Goobuntu。如今，Goobuntu 正在被基于 Debian Testing 的 gLinux 所取代。
>
>
>

如果你读过那篇《[Ubuntu 十个令人惊奇的事实](https://itsfoss.com/facts-about-ubuntu/)》，你可能知道 Google 使用了一个名为 [Goobuntu](https://en.wikipedia.org/wiki/Goobuntu) 的 Linux 发行版作为开发平台。这是一个定制化的 Linux 发行版，不难猜到，它是基于 Ubuntu 的。

Goobuntu 基本上是一个 [采用轻量级的界面的 Ubuntu](http://www.zdnet.com/article/the-truth-about-goobuntu-googles-in-house-desktop-ubuntu-linux/)，它是基于 Ubuntu LTS 版本的。如果你认为 Google 对 Ubuntu 的测试或开发做出了贡献，那么你就错了。Google 只是 Canonical 公司的 [Ubuntu Advantage Program](https://www.ubuntu.com/support) 计划的付费客户而已。[Canonical](https://www.canonical.com/) 是 Ubuntu 的母公司。

### 遇见 gLinux：Google 基于 Debian Buster 的新 Linux 发行版

![gLinux from Goobuntu](/data/attachment/album/201801/22/094039koc97zz7uiipj77i.jpg)

在使用 Ubuntu 五年多以后，Google 正在用一个基于 Debian Testing 版本的 Linux 发行版 —— gLinux 取代 Goobuntu。

正如 [MuyLinux](https://www.muylinux.com/2018/01/15/goobuntu-glinux-google/) 所报道的，gLinux 是从软件包的源代码中构建出来的，然后 Google 对其进行了修改，这些改动也将为上游做出贡献。

这个“新闻”并不是什么新鲜事，它早在去年八月就在 Debconf'17 开发者大会上宣布了。但不知为何，这件事并没有引起应有的关注。

请点击 [这里](https://debconf17.debconf.org/talks/44/) 观看 Debconf 视频中的演示。gLinux 的演示从 12:00 开始。

[推荐阅读：微软出局，巴塞罗那青睐 Linux 系统和开源软件](/article-9236-1.html)

### 从 Ubuntu 14.04 LTS 转移到 Debian 10 Buster

Google 曾经看重 Ubuntu LTS 的稳定性，现在为了及时测试软件而转移到 Debian Testing 上。但目前尚不清楚 Google 为什么决定从 Ubuntu 切换到 Debian。

Google 计划如何转移到 Debian Testing？目前的 Debian Testing 版本是即将发布的 Debian 10 Buster。Google 开发了一个内部工具，用于将现有系统从 Ubuntu 14.04 LTS 迁移到 Debian 10 Buster。项目负责人 Margarita 在 Debconf 中声称，经过测试，该工具工作正常。

Google 还计划将这些改动发到 Debian 的上游项目中，从而为其发展做出贡献。

![gLinux testing plan from Google](/data/attachment/album/201801/22/094039og5f939ic2156fi9.jpg)

*gLinux 的开发计划*

### Ubuntu 丢失了一个大客户！

回溯到 2012 年，Canonical 公司澄清说 Google 不是他们最大的商业桌面客户。但至少可以说，Google 是他们的大客户。当 Google 准备切换到 Debian 时，必然会使 Canonical 蒙受损失。

### 你怎么看？

请记住，Google 不会限制其开发者使用任何操作系统，但鼓励使用 Linux。

如果你想使用 Goobuntu 或 gLinux，那得成为 Google 公司的雇员才行。因为这是 Google 的内部项目，不对公众开放。

总的来说，这对 Debian 来说是一个好消息，尤其是他们成为了上游发行版的话。对 Ubuntu 来说可就不同了。我已经联系了 Canonical 公司征求意见，但至今没有回应。

更新：Canonical 公司回应称，他们“不共享与单个客户关系的细节”，因此他们不能提供有关收入和任何其他的细节。

你对 Google 抛弃 Ubuntu 而选择 Debian 有什么看法？

---

#### 关于作者 Abhishek Prakash

我是一名专业的软件开发人员，也是 FOSS 的创始人。我是一个狂热的 Linux 爱好者和开源爱好者。我使用 Ubuntu 并相信知识共享。除了 Linux 之外，我还喜欢经典的侦探推理故事。我是阿加莎·克里斯蒂（Agatha Christie）作品的忠实粉丝。

---

via: <https://itsfoss.com/goobuntu-glinux-google/>

作者：[Abhishek Prakash](https://itsfoss.com/author/abhishek/) 译者：[jessie-pang](https://github.com/jessie-pang) 校对：[wxy](https://github.com/wxy)

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


Wine 3.0 发布，支持 Android 图形驱动、Direct3D 11

![](/data/attachment/album/201801/23/094921iojmp0ymjdb0wmwb.jpg)

2018 年伊始，Wine（Wine Is Not an Emulator） 项目发布了年度更新，释出了最新的 3.0 稳定版本。 Wine 是一个在 Linux 和 Unix 类操作系统上运行 Windows 应用及游戏的开源兼容层。

经过近一年的开发，Wine 3.0 发布了许多神奇的功能，如 Android 图形驱动可以使用户在基于 Android 的机器上运行 Windows 应用和游戏，对 AMD Radeon 和 Intel GPU 默认启用 Direct3D 11 支持，在 macOS 上支持 AES 加密支持，程序管理器的 DDE 支持以及任务调度器。

此外，Wine 3.0 通过 reg.exe 引入了输出注册表项的功能，对中继调试和 OLE 数据缓存增加了各种增强，以及在 MSHTML 中增加了另外一层事件支持，这是微软专有的 HTML 布局引擎，用于 Windows 版本的 IE 浏览器。

更多更新细节可以参考[发布公告](https://www.winehq.org/announce/3.0)。

其中还提到：“再一次，因为是年度发布，一些功能还在开发当中，会被延迟到下一个开发周期当中。这包括 Direct3D 12 和 Vulkan 支持，以及在 Android 上启用 Direct3D 的 OpenGL ES 支持。”。

### 下载 Wine 3.0

如果你不想等待你的 Linux 发行版更新，你可以直接下载源代码构建或者从官方网站下载二进制包。

源代码：

* <https://dl.winehq.org/wine/source/3.0/wine-3.0.tar.xz>
* <http://mirrors.ibiblio.org/wine/source/3.0/wine-3.0.tar.xz>

二进制包：

* <https://www.winehq.org/download>

据其发布公告，Wine 3.0 作为一个主要更新，其包含了 6000 处以上的单独改进。对于那些需要在 GNU/Linux 发行版上运行 Windows 应用及游戏的人们来说，相信这是一个重要的里程碑；同样，这对于要在 Android 系统上运行 Windows 应用的人来说也是如此。


与 C 语言长别离

Summary: 我意识到了一个让我震惊的事实 —— 我有着 35 年的 C 语言经验。每周我都要写很多 C 代码，但是我已经记不清楚上一次我 创建一个新的 C 语言项目 是在什么时候了。

![](/data/attachment/album/201801/23/173840hqcqbhto0kbtwpxn.jpg)

这几天来，我在思考那些正在挑战 C 语言的系统编程语言领袖地位的新潮语言，尤其是 Go 和 Rust。思考的过程中，我意识到了一个让我震惊的事实 —— 我有着 35 年的 C 语言经验。每周我都要写很多 C 代码，但是我已经记不清楚上一次我 *创建一个新的 C 语言项目* 是在什么时候了。

如果你完全不认为这种情况令人震惊，那你很可能不是一个系统程序员。我知道有很多程序员使用更高级的语言工作。但是我把大部分时间都花在了深入打磨像 NTPsec、 GPSD 以及 giflib 这些东西上。熟练使用 C 语言在这几十年里一直就是我的专长。但是，现在我不仅是不再使用 C 语言写新的项目，甚至我都记不清我是什么时候开始这样做的了，而且……回头想想，我觉得这都不是本世纪发生的事情。

这个对于我来说是件大事，因为如果你问我，我的五个最核心软件开发技能是什么，“C 语言专家” 一定是你最有可能听到的之一。这也激起了我的思考。C 语言的未来会怎样 ？C 语言是否正像当年的 COBOL 语言一样，在辉煌之后，走向落幕？

我恰好是在 C 语言迅猛发展，并把汇编语言以及其它许多编译型语言挤出主流存在的前几年开始编程的。那场过渡大约是在 1982 到 1985 年之间。在那之前，有很多编译型语言争相吸引程序员的注意力，那些语言中还没有明确的领导者；但是在那之后，小众的语言就直接毫无声息的退出了舞台。主流的语言（FORTRAN、Pascal、COBOL）则要么只限于老代码，要么就是固守单一领域，再就是在 C 语言的边缘领域顶着愈来愈大的压力苟延残喘。

而在那以后，这种情形持续了近 30 年。尽管在应用程序开发上出现了新的动向： Java、 Perl、 Python， 以及许许多多不是很成功的竞争者。起初我很少关注这些语言，这很大一部分是因为在它们的运行时的开销对于当时的实际硬件来说太大。因此，这就使得 C 的成功无可撼动；为了使用和对接大量已有的 C 语言代码，你得使用 C 语言写新代码（一部分脚本语言尝试过打破这种壁垒，但是只有 Python 有可能取得成功）。

回想起来，我在 1997 年使用脚本语言写应用时本应该注意到这些语言的更重要的意义的。当时我写的是一个名为 SunSITE 的帮助图书管理员做源码分发的辅助软件，当时使用的是 Perl 语言。

这个应用完全是用来处理文本输入的，而且只需要能够应对人类的反应速度即可（大概 0.1 秒），因此使用 C 或者别的没有动态内存分配以及字符串类型的语言来写就会显得很傻。但是在当时，我仅仅是把其视为一个试验，而完全没有想到我几乎再也不会在一个新项目的第一个文件里敲下 `int main(int argc, char **argv)` 这样的 C 语言代码了。

我说“几乎”，主要是因为 1999 年的 [SNG](http://sng.sourceforge.net/)。 我想那是我最后一个用 C 从头开始写的项目了。

在那之后我写的所有的 C 代码都是在为那些上世纪已经存在的老项目添砖加瓦，或者是在维护诸如 GPSD 以及 NTPsec 一类的项目。

当年我本不应该使用 C 语言写 SNG 的。因为在那个年代，摩尔定律的快速迭代使得硬件愈加便宜，使得像 Perl 这样的语言的执行效率也不再是问题。仅仅三年以后，我可能就会毫不犹豫地使用 Python 而不是 C 语言来写 SNG。

在 1997 年我学习了 Python， 这对我来说是一道分水岭。这个语言很美妙 —— 就像我早年使用的 Lisp 一样，而且 Python 还有很酷的库！甚至还完全遵循了 POSIX！还有一个蛮好用的对象系统！Python 没有把 C 语言挤出我的工具箱，但是我很快就习惯了在只要能用 Python 时就写 Python ，而只在必须使用 C 语言时写 C。

（在此之后，我开始在我的访谈中指出我所谓的 “Perl 的教训” ，也就是任何一个没能实现和 C 语言语义等价的遵循 POSIX 的语言*都注定要失败*。在计算机科学的发展史上，很多学术语言的骨骸俯拾皆是，原因是这些语言的设计者没有意识到这个重要的问题。）

显然，对我来说，Python 的主要优势之一就是它很简单，当我写 Python 时，我不再需要担心内存管理问题或者会导致核心转储的程序崩溃 —— 对于 C 程序员来说，处理这些问题烦的要命。而不那么明显的优势恰好在我更改语言时显现，我在 90 年代末写应用程序和非核心系统服务的代码时，为了平衡成本与风险都会倾向于选择具有自动内存管理但是开销更大的语言，以抵消之前提到的 C 语言的缺陷。而在仅仅几年之前（甚至是 1990 年），那些语言的开销还是大到无法承受的；那时硬件产业的发展还在早期阶段，没有给摩尔定律足够的时间来发挥威力。

尽量地在 C 语言和 Python 之间选择 C —— 只要是能的话我就会从 C 语言转移到 Python 。这是一种降低工程复杂程度的有效策略。我将这种策略应用在了 GPSD 中，而针对 NTPsec , 我对这个策略的采用则更加系统化。这就是我们能把 NTP 的代码库大小削减四分之一的原因。

但是今天我不是来讲 Python 的。尽管我觉得它在竞争中脱颖而出，Python 也未必真的是在 2000 年之前彻底结束我在新项目上使用 C 语言的原因，因为在当时任何一个新的学院派的动态语言都可以让我不再选择使用 C 语言。也有可能是在某段时间里在我写了很多 Java 之后，我才慢慢远离了 C 语言。

我写这个回忆录是因为我觉得我并非特例，在世纪之交，同样的发展和转变也改变了不少 C 语言老手的编码习惯。像我一样，他们在当时也并没有意识到这种转变正在发生。

在 2000 年以后，尽管我还在使用 C/C++ 写之前的项目，比如 GPSD ，游戏韦诺之战以及 NTPsec，但是我的所有新项目都是使用 Python 的。

有很多程序是在完全无法在 C 语言下写出来的，尤其是 [reposurgeon](http://www.catb.org/esr/reposurgeon/) 以及 [doclifter](http://www.catb.org/esr/doclifter/) 这样的项目。由于 C 语言受限的数据类型本体论以及其脆弱的底层数据管理问题，尝试用 C 写的话可能会很恐怖，并注定失败。

甚至是对于更小的项目 —— 那些可以在 C 中实现的东西 —— 我也使用 Python 写，因为我不想花不必要的时间以及精力去处理内核转储问题。这种情况一直持续到去年年底，持续到我创建我的第一个 Rust 项目，以及成功写出第一个[使用 Go 语言的项目](http://www.catb.org/esr/loccount/)。

如前文所述，尽管我是在讨论我的个人经历，但是我想我的经历体现了时代的趋势。我期待新潮流的出现，而不是仅仅跟随潮流。在 98 年的时候，我就是 Python 的早期使用者。来自 [TIOBE](https://www.tiobe.com/tiobe-index/) 的数据则表明，在 Go 语言脱胎于公司的实验项目并刚刚从小众语言中脱颖而出的几个月内，我就开始实现自己的第一个 Go 语言项目了。

总而言之：直到现在第一批有可能挑战 C 语言的传统地位的语言才出现。我判断这个的标准很简单 —— 只要这个语言能让我等 C 语言老手接受不再写 C 的事实，这个语言才 “有可能” 挑战到 C 语言的地位 —— 来看啊，这有个新编译器，能把 C 转换到新语言，现在你可以让他完成你的*全部工作*了 —— 这样 C 语言的老手就会开心起来。

Python 以及和其类似的语言对此做的并不够好。使用 Python 实现 NTPsec（以此举例）可能是个灾难，最终会由于过高的运行时开销以及由于垃圾回收机制导致的延迟变化而烂尾。如果需求是针对单个用户且只需要以人类能接受的速度运行，使用 Python 当然是很好的，但是对于以 *机器的速度* 运行的程序来说就不总是如此了 —— 尤其是在很高的多用户负载之下。这不只是我自己的判断 —— 因为拿 Go 语言来说，它的存在主要就是因为当时作为 Python 语言主要支持者的 Google 在使用 Python 实现一些工程的时候也遭遇了同样的效能痛点。

Go 语言就是为了解决 Python 搞不定的那些大多由 C 语言来实现的任务而设计的。尽管没有一个全自动语言转换软件让我很是不爽，但是使用 Go 语言来写系统程序对我来说不算麻烦，我发现我写 Go 写的还挺开心的。我的很多 C 编码技能还可以继续使用，我还收获了垃圾回收机制以及并发编程机制，这何乐而不为？

（[这里](https://blog.ntpsec.org/2017/02/07/grappling-with-go.html)有关于我第一次写 Go 的经验的更多信息）

本来我想把 Rust 也视为 “C 语言要过时了” 的例证，但是在学习并尝试使用了这门语言编程之后，我觉得[这种语言现在还没有做好准备](http://esr.ibiblio.org/?p=7303)。也许 5 年以后，它才会成为 C 语言的对手。

随着 2017 的尾声来临，我们已经发现了一个相对成熟的语言，其和 C 类似，能够胜任 C 语言的大部分工作场景（我在下面会准确描述），在几年以后，这个语言界的新星可能就会取得成功。

这件事意义重大。如果你不长远地回顾历史，你可能看不出来这件事情的伟大性。*三十年了* —— 这几乎就是我作为一个程序员的全部生涯，我们都没有等到一个 C 语言的继任者，也无法遥望 C 之后的系统编程会是什么样子的。而现在，我们面前突然有了后 C 时代的两种不同的展望和未来……

……另一种展望则是下面这个语言留给我们的。我的一个朋友正在开发一个他称之为 “Cx” 的语言，这个语言在 C 语言上做了很少的改动，使得其能够支持类型安全；他的项目的目的就是要创建一个能够在最少人力参与的情况下把古典 C 语言修改为新语言的程序。我不会指出这位朋友的名字，免得给他太多压力，让他做出太多不切实际的保证。但是他的实现方法真的很是有意思，我会尽量给他募集资金。

现在，我们看到了可以替代 C 语言实现系统编程的三种不同的可能的道路。而就在两年之前，我们的眼前还是一片漆黑。我重复一遍：这件事情意义重大。

我是在说 C 语言将要灭绝吗？不是这样的，在可预见的未来里，C 语言还会是操作系统的内核编程以及设备固件编程的主流语言，在这些场景下，尽力压榨硬件性能的古老规则还在奏效，尽管它可能不是那么安全。

现在那些将要被 C 的继任者攻破的领域就是我之前提到的我经常涉及的领域 —— 比如 GPSD 以及 NTPsec、系统服务以及那些因为历史原因而使用 C 语言写的进程。还有就是以 DNS 服务器以及邮件传输代理 —— 那些需要以机器速度而不是人类的速度运行的系统程序。

现在我们可以对后 C 时代的未来窥见一斑，即上述这类领域的代码都可以使用那些具有强大内存安全特性的 C 语言的替代者实现。Go 、Rust 或者 Cx ，无论是哪个，都可能使 C 的存在被弱化。比如，如果我现在再来重新实现一遍 NTP ，我可能就会毫不犹豫的使用 Go 语言去完成。

---

via: <http://esr.ibiblio.org/?p=7711>

作者：[Eric Raymond](http://esr.ibiblio.org/?author=2) 译者：[name1e5s](https://github.com/name1e5s) 校对：[yunfengHe](https://github.com/yunfengHe), [wxy](https://github.com/wxy)

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


通过 Linux 命令行连接 Wifi

![](/data/attachment/album/201801/23/224506dhwwhqwgjblq76ui.jpg)

目标：仅使用命令行工具来配置 WiFi

发行版：适用主流的那些发行版

要求：安装了无线网卡的 Linux 并且拥有 root 权限。

难度：简单

约定：

* `#` - 需要使用 root 权限来执行指定命令，可以直接使用 root 用户来执行，也可以使用 `sudo` 命令
* `$` - 可以使用普通用户来执行指定命令

### 简介

许多人喜欢用图形化的工具来管理电脑，但也有很多人不喜欢这样做。如果你比较喜欢命令行工具，管理 WiFi 会是件很痛苦的事情。然而，事情本不该如此。

wpa\_supplicant 可以作为命令行工具来用。使用一个简单的配置文件就可以很容易设置号 WiFi。

### 扫描网络

若你已经知道了网络的信息，就可以跳过这一步。如果不了解的话，则这是一个找出网络信息的好方法。

wpa\_supplicant 中有一个工具叫做 `wpa_cli`，它提供了一个命令行接口来管理你的 WiFi 连接。事实上你可以用它来设置任何东西，但是设置一个配置文件看起来要更容易一些。

使用 root 权限运行 `wpa_cli`，然后扫描网络。

```
# wpa_cli
> scan

```

扫描过程要花上一点时间，并且会显示所在区域的那些网络。记住你想要连接的那个网络。然后输入 `quit` 退出。

### 生成配置块并且加密你的密码

还有更方便的工具可以用来设置配置文件。它接受网络名称和密码作为参数，然后生成一个包含该网路配置块（其中的密码被加密处理了）的配置文件。

```
# wpa_passphrase networkname password > /etc/wpa_supplicant/wpa_supplicant.conf

```

### 裁剪你的配置

现在你已经有了一个配置文件了，这个配置文件就是 `/etc/wpa_supplicant/wpa_supplicant.conf`。其中的内容并不多，只有一个网络块，其中有网络名称和密码，不过你可以在此基础上对它进行修改。

用喜欢的编辑器打开该文件，首先删掉说明密码的那行注释。然后，将下面行加到配置最上方。

```
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel

```

这一行只是让 `wheel` 组中的用户可以管理 wpa\_supplicant。这会方便很多。

其他的内容则添加到网络块中。

如果你要连接到一个隐藏网络，你可以添加下面行来通知 wpa\_supplicant 先扫描该网络。

```
scan_ssid=1

```

下一步，设置协议以及密钥管理方面的配置。下面这些是 WPA2 相关的配置。

```
proto=RSN
key_mgmt=WPA-PSK

```

`group` 和 `pairwise` 配置告诉 wpa\_supplicant 你是否使用了 CCMP、TKIP，或者两者都用到了。为了安全考虑，你应该只用 CCMP。

```
group=CCMP
pairwise=CCMP

```

最后，设置网络优先级。越高的值越会优先连接。

```
priority=10

```

![Complete WPA_Supplicant Settings](/data/attachment/album/201801/23/224513ubg3zg5t0gjzb2n0.jpg)

保存配置然后重启 wpa\_supplicant 来让改动生效。

### 结语

当然，该方法并不是用于即时配置无线网络的最好方法，但对于定期连接的网络来说，这种方法非常有效。

---

via: <https://linuxconfig.org/connect-to-wifi-from-the-linux-command-line>

作者：[Nick Congleton](https://linuxconfig.org) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


十大 Linux 命令行游戏

Summary: Linux 有一个超过 Windows 的优势。它拥有一个强大的 Linux 终端。在 Linux 终端上，你可以做很多事情，包括玩 命令行游戏。

>
> 概要： 本文列举了 Linux 中最好的命令行游戏。
>
>
>

![](/data/attachment/album/201801/23/231932sljm5xwlevsrfa8z.jpg)

Linux 从来都不是游戏的首选操作系统，尽管近日来 [Linux 的游戏](/article-7316-1.html)提供了很多，你也可以从许多资源[下载到 Linux 游戏](https://itsfoss.com/download-linux-games/)。

也有专门的 [游戏版 Linux](https://itsfoss.com/manjaro-gaming-linux/)。没错，确实有。但是今天，我们并不是要欣赏游戏版 Linux。

Linux 有一个超过 Windows 的优势。它拥有一个强大的 Linux 终端。在 Linux 终端上，你可以做很多事情，包括玩 **命令行游戏**。

当然，我们都是 Linux 终端的骨灰粉。终端游戏轻便、快速、有地狱般的魔力。而这最有意思的事情是，你可以在 Linux 终端上重温大量经典游戏。

### 最好的 Linux 终端游戏

来揭秘这张榜单，找出 Linux 终端最好的游戏。

#### 1. Bastet

谁还没花上几个小时玩[俄罗斯方块](https://en.wikipedia.org/wiki/Tetris)？它简单而且容易上瘾。 Bastet 就是 Linux 版的俄罗斯方块。

![Linux 终端游戏 Bastet](/data/attachment/album/201801/23/231939o0ll5a3ahq35q3hz.jpg)

使用下面的命令获取 Bastet：

```
sudo apt install bastet

```

运行下列命令，在终端上开始这个游戏：

```
bastet

```

使用空格键旋转方块，方向键控制方块移动。

#### 2. Ninvaders

Space Invaders（太空侵略者）。我仍记得这个游戏里，和我兄弟为了最高分而比拼。这是最好的街机游戏之一。

![Linux 终端游戏 nInvaders](/data/attachment/album/201801/23/231940pk0fcl00cf80stzs.jpg)

复制粘贴这段代码安装 Ninvaders。

```
sudo apt-get install ninvaders

```

使用下面的命令开始游戏：

```
ninvaders

```

方向键移动太空飞船。空格键射击外星人。

[推荐阅读：2016 你可以开始的 Linux 游戏 Top 10](https://itsfoss.com/best-linux-games/)

#### 3. Pacman4console

是的，这个就是街机之王。Pacman4console 是最受欢迎的街机游戏 Pacman（吃豆人）的终端版。

![Linux 命令行吃豆豆游戏 Pacman4console](/data/attachment/album/201801/23/231941sbqvnnod65udqmum.jpg)

使用以下命令获取 pacman4console：

```
sudo apt-get install pacman4console

```

打开终端，建议使用最大的终端界面。键入以下命令启动游戏：

```
pacman4console

```

使用方向键控制移动。

#### 4. nSnake

记得在老式诺基亚手机里玩的贪吃蛇游戏吗？

这个游戏让我在很长时间内着迷于手机。我曾经设计过各种姿态去获得更长的蛇身。

![nsnake : Linux 终端上的贪吃蛇游戏](/data/attachment/album/201801/23/231942rx3l5lxzpy21l4y2.jpg)

我们拥有 [Linux 终端上的贪吃蛇游戏](https://itsfoss.com/nsnake-play-classic-snake-game-linux-terminal/) 得感谢 [nSnake](https://itsfoss.com/nsnake-play-classic-snake-game-linux-terminal/)。使用下面的命令安装它：

```
sudo apt-get install nsnake

```

键入下面的命令开始游戏：

```
nsnake

```

使用方向键控制蛇身并喂它。

#### 5. Greed

Greed 有点像 Tron（类似贪吃蛇的进化版），但是减少了速度，也没那么刺激。

你当前的位置由闪烁的 ‘@’ 表示。你被数字所环绕，你可以在四个方向任意移动。

你选择的移动方向上标识的数字，就是你能移动的步数。你将重复这个步骤。走过的路不能再走，如果你无路可走，游戏结束。

似乎我让它听起来变得更复杂了。

![Greed : 命令行上的 Tron](/data/attachment/album/201801/23/231944eszk777q3bdpqq83.jpg)

通过下列命令获取 Greed：

```
sudo apt-get install greed

```

通过下列命令启动游戏，使用方向键控制游戏。

```
greed

```

#### 6. Air Traffic Controller

还有什么比做飞行员更有意思的？那就是空中交通管制员。在你的终端中，你可以模拟一个空中交通系统。说实话，在终端里管理空中交通蛮有意思的。

![Linux 空中交通管理员](/data/attachment/album/201801/23/231946z2begppnz94fne7g.jpg)

使用下列命令安装游戏：

```
sudo apt-get install bsdgames

```

键入下列命令启动游戏：

```
atc

```

ATC 不是孩子玩的游戏。建议查看官方文档。

#### 7. Backgammon（双陆棋）

无论之前你有没有玩过 [双陆棋](https://en.wikipedia.org/wiki/Backgammon)，你都应该看看这个。 它的说明书和控制手册都非常友好。如果你喜欢，可以挑战你的电脑或者你的朋友。

![Linux 终端上的双陆棋](/data/attachment/album/201801/23/231947ct4qz40b0ti84zyc.jpg)

使用下列命令安装双陆棋：

```
sudo apt-get install bsdgames

```

键入下列命令启动游戏:

```
backgammon

```

当你提示游戏规则时，回复 ‘y’ 即可。

#### 8. Moon Buggy

跳跃、开火。欢乐时光不必多言。

![Moon buggy](/data/attachment/album/201801/23/231948u0qk59kj5ws006yy.jpg)

使用下列命令安装游戏：

```
sudo apt-get install moon-buggy

```

使用下列命令启动游戏：

```
moon-buggy

```

空格跳跃，‘a’ 或者 ‘l’射击。尽情享受吧。

#### 9. 2048

2048 可以活跃你的大脑。[2048](https://itsfoss.com/2048-offline-play-ubuntu/) 是一个策咯游戏，很容易上瘾。以获取 2048 分为目标。

![Linux 终端上的 2048](/data/attachment/album/201801/23/231949k6dui5detu2ctqqq.jpg)

复制粘贴下面的命令安装游戏：

```
wget https://raw.githubusercontent.com/mevdschee/2048.c/master/2048.c

gcc -o 2048 2048.c

```

键入下列命令启动游戏：

```
./2048

```

#### 10. Tron

没有动作类游戏，这张榜单怎么可能结束？

![Linux 终端游戏 Tron](/data/attachment/album/201801/23/231950rp6jbphmkxip1zri.jpg)

是的，Linux 终端可以实现这种精力充沛的游戏 Tron。为接下来迅捷的反应做准备吧。无需被下载和安装困扰。一个命令即可启动游戏，你只需要一个网络连接：

```
ssh sshtron.zachlatta.com

```

如果有别的在线游戏者，你可以多人游戏。了解更多：[Linux 终端游戏 Tron](https://itsfoss.com/play-tron-game-linux-terminal/)。

### 你看上了哪一款?

伙计，十大 Linux 终端游戏都分享给你了。我猜你现在正准备键入 `ctrl+alt+T`（终端快捷键） 了。榜单中那个是你最喜欢的游戏？或者你有其它的终端游戏么？尽情分享吧！

---

via: <https://itsfoss.com/best-command-line-games-linux/>

作者：[Aquil Roshan](https://itsfoss.com/author/aquil/) 译者：[CYLeft](https://github.com/CYleft) 校对：[wxy](https://github.com/wxy)

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


修复 Debian 中的 vim 奇怪行为

Summary: 我一直在想，为什么我服务器上 vim 为什么在鼠标方面表现得如此愚蠢：不能像平时那样跳转、复制、粘贴。尽管在 /etc/vim/vimrc.local 中已经设置了。

我一直在想，为什么我服务器上 vim 为什么在鼠标方面表现得如此愚蠢：不能像平时那样跳转、复制、粘贴。尽管在 `/etc/vim/vimrc.local` 中已经设置了。

```
set mouse=

```

最后我终于知道为什么了，多谢 bug [#864074](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864074) 并且修复了它。

![](/data/attachment/album/201801/23/232925po4bjtppxoooceoe.jpg)

原因是，当没有 `~/.vimrc` 的时候，vim 在 `vimrc.local` **之后**加载 `defaults.vim`，从而覆盖了几个设置。

在 `/etc/vim/vimrc` 中有一个注释（虽然我没有看到）解释了这一点：

```
" Vim will load $VIMRUNTIME/defaults.vim if the user does not have a vimrc.
" This happens after /etc/vim/vimrc(.local) are loaded, so it will override
" any settings in these files.
" If you don't want that to happen, uncomment the below line to prevent
" defaults.vim from being loaded.
" let g:skip_defaults_vim = 1

```

我同意这是在正常安装 vim 后设置 vim 的好方法，但 Debian 包可以做得更好。在错误报告中清楚地说明了这个问题：如果没有 `~/.vimrc`，`/etc/vim/vimrc.local` 中的设置被覆盖。

这在Debian中是违反直觉的 - 而且我也不知道其他包中是否采用类似的方法。

由于 `defaults.vim` 中的设置非常合理，所以我希望使用它，但只修改了一些我不同意的项目，比如鼠标。最后，我在 `/etc/vim/vimrc.local` 中做了以下操作：

```
if filereadable("/usr/share/vim/vim80/defaults.vim")
  source /usr/share/vim/vim80/defaults.vim
endif
" now set the line that the defaults file is not reloaded afterwards!
let g:skip_defaults_vim = 1

" turn of mouse
set mouse=
" other override settings go here

```

可能有更好的方式来获得一个不依赖于 vim 版本的通用加载语句, 但现在我对此很满意。

---

via: <https://www.preining.info/blog/2017/10/fixing-vim-in-debian/>

作者：[Norbert Preining](https://www.preining.info/blog/author/norbert/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


最重要的 Firefox 命令行选项

![](/data/attachment/album/201801/23/234142oi23zlyukzxej22z.jpg)

Firefox web 浏览器支持很多命令行选项，可以定制它启动的方式。

你可能已经接触过一些了，比如 `-P "配置文件名"` 指定浏览器启动加载时的配置文件，`-private` 开启一个私有会话。

本指南会列出对 FIrefox 来说比较重要的那些命令行选项。它并不包含所有的可选项，因为很多选项只用于特定的目的，对一般用户来说没什么价值。

你可以在 Firefox 开发者网站上看到[完整](https://developer.mozilla.org/en-US/docs/Mozilla/Command_Line_Options) 的命令行选项列表。需要注意的是，很多命令行选项对其它基于 Mozilla 的产品一样有效，甚至对某些第三方的程序也有效。

### 重要的 Firefox 命令行选项

![firefox command line](/data/attachment/album/201801/23/234211r6dajkmar5ia1dm6.png)

#### 配置文件相关选项

* `-CreateProfile 配置文件名` -- 创建新的用户配置信息，但并不立即使用它。
* `-CreateProfile "配置文件名 存放配置文件的目录"` -- 跟上面一样，只是指定了存放配置文件的目录。
* `-ProfileManager`，或 `-P` -- 打开内置的配置文件管理器。
* `-P "配置文件名"` -- 使用指定的配置文件启动 Firefox。若指定的配置文件不存在则会打开配置文件管理器。只有在没有其他 Firefox 实例运行时才有用。
* `-no-remote` -- 与 `-P` 连用来创建新的浏览器实例。它允许你在同一时间运行多个配置文件。

#### 浏览器相关选项

* `-headless` -- 以无头模式（LCTT 译注：无显示界面）启动 Firefox。Linux 上需要 Firefox 55 才支持，Windows 和 Mac OS X 上需要 Firefox 56 才支持。
* `-new-tab URL` -- 在 Firefox 的新标签页中加载指定 URL。
* `-new-window URL` -- 在 Firefox 的新窗口中加载指定 URL。
* `-private` -- 以隐私浏览模式启动 Firefox。可以用来让 Firefox 始终运行在隐私浏览模式下。
* `-private-window` -- 打开一个隐私窗口。
* `-private-window URL` -- 在新的隐私窗口中打开 URL。若已经打开了一个隐私浏览窗口，则在那个窗口中打开 URL。
* `-search 单词` -- 使用 FIrefox 默认的搜索引擎进行搜索。
* - `url URL` -- 在新的标签页或窗口中加载 URL。可以省略这里的 `-url`，而且支持打开多个 URL，每个 URL 之间用空格分离。

#### 其他选项

* `-safe-mode` -- 在安全模式下启动 Firefox。在启动 Firefox 时一直按住 Shift 键也能进入安全模式。
* `-devtools` -- 启动 Firefox，同时加载并打开开发者工具。
* `-inspector URL` -- 使用 DOM Inspector 查看指定的 URL
* `-jsconsole` -- 启动 Firefox，同时打开浏览器终端。
* `-tray` -- 启动 Firefox，但保持最小化。

---

via: <https://www.ghacks.net/2017/10/08/the-most-important-firefox-command-line-options/>

作者：[Martin Brinkmann](https://www.ghacks.net/author/martin/) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


ftrace：跟踪你的内核函数！

受益匪浅

![](/data/attachment/album/201801/24/114629wxzw91rhxshvr1h2.jpg)

大家好！今天我们将去讨论一个调试工具：ftrace，之前我的博客上还没有讨论过它。还有什么能比一个新的调试工具更让人激动呢？

这个非常棒的 ftrace 并不是个新的工具！它大约在 Linux 的 2.6 内核版本中就有了，时间大约是在 2008 年。[这一篇是我用谷歌能找到的最早的文档](https://lwn.net/Articles/290277/)。因此，如果你是一个调试系统的“老手”，可能早就已经使用它了！

我知道，ftrace 已经存在了大约 2.5 年了（LCTT 译注：距本文初次写作时），但是还没有真正的去学习它。假设我明天要召开一个专题研究会，那么，关于 ftrace 应该讨论些什么？因此，今天是时间去讨论一下它了！

### 什么是 ftrace？

ftrace 是一个 Linux 内核特性，它可以让你去跟踪 Linux 内核的函数调用。为什么要这么做呢？好吧，假设你调试一个奇怪的问题，而你已经得到了你的内核版本中这个问题在源代码中的开始的位置，而你想知道这里到底发生了什么？

每次在调试的时候，我并不会经常去读内核源代码，但是，极个别的情况下会去读它！例如，本周在工作中，我有一个程序在内核中卡死了。查看到底是调用了什么函数，能够帮我更好的理解在内核中发生了什么，哪些系统涉及其中！（在我的那个案例中，它是虚拟内存系统）。

我认为 ftrace 是一个十分好用的工具（它肯定没有 `strace` 那样使用广泛，也比它难以使用），但是它还是值得你去学习。因此，让我们开始吧！

### 使用 ftrace 的第一步

不像 `strace` 和 `perf`，ftrace 并不是真正的 **程序** – 你不能只运行 `ftrace my_cool_function`。那样太容易了！

如果你去读 [使用 ftrace 调试内核](https://lwn.net/Articles/365835/)，它会告诉你从 `cd /sys/kernel/debug/tracing` 开始，然后做很多文件系统的操作。

对于我来说，这种办法太麻烦——一个使用 ftrace 的简单例子像是这样：

```
cd /sys/kernel/debug/tracing
echo function > current_tracer
echo do_page_fault > set_ftrace_filter
cat trace

```

这个文件系统是跟踪系统的接口（“给这些神奇的文件赋值，然后该发生的事情就会发生”）理论上看起来似乎可用，但是它不是我的首选方式。

幸运的是，ftrace 团队也考虑到这个并不友好的用户界面，因此，它有了一个更易于使用的界面，它就是 `trace-cmd`！！！`trace-cmd` 是一个带命令行参数的普通程序。我们后面将使用它！我在 LWN 上找到了一个 `trace-cmd` 的使用介绍：[trace-cmd: Ftrace 的一个前端](https://lwn.net/Articles/410200/)。

### 开始使用 trace-cmd：让我们仅跟踪一个函数

首先，我需要去使用 `sudo apt-get install trace-cmd` 安装 `trace-cmd`，这一步很容易。

对于第一个 ftrace 的演示，我决定去了解我的内核如何去处理一个页面故障。当 Linux 分配内存时，它经常偷懒，（“你并不是*真的*计划去使用内存，对吗？”）。这意味着，当一个应用程序尝试去对分配给它的内存进行写入时，就会发生一个页面故障，而这个时候，内核才会真正的为应用程序去分配物理内存。

我们开始使用 `trace-cmd` 并让它跟踪 `do_page_fault` 函数！

```
$ sudo trace-cmd record -p function -l do_page_fault
  plugin 'function'
Hit Ctrl^C to stop recording

```

我将它运行了几秒钟，然后按下了 `Ctrl+C`。 让我大吃一惊的是，它竟然产生了一个 2.5MB 大小的名为 `trace.dat` 的跟踪文件。我们来看一下这个文件的内容！

```
$ sudo trace-cmd report
          chrome-15144 [000] 11446.466121: function:             do_page_fault
          chrome-15144 [000] 11446.467910: function:             do_page_fault
          chrome-15144 [000] 11446.469174: function:             do_page_fault
          chrome-15144 [000] 11446.474225: function:             do_page_fault
          chrome-15144 [000] 11446.474386: function:             do_page_fault
          chrome-15144 [000] 11446.478768: function:             do_page_fault
 CompositorTileW-15154 [001] 11446.480172: function:             do_page_fault
          chrome-1830  [003] 11446.486696: function:             do_page_fault
 CompositorTileW-15154 [001] 11446.488983: function:             do_page_fault
 CompositorTileW-15154 [001] 11446.489034: function:             do_page_fault
 CompositorTileW-15154 [001] 11446.489045: function:             do_page_fault

```

看起来很整洁 – 它展示了进程名（chrome）、进程 ID（15144）、CPU ID（000），以及它跟踪的函数。

通过察看整个文件，（`sudo trace-cmd report | grep chrome`）可以看到，我们跟踪了大约 1.5 秒，在这 1.5 秒的时间段内，Chrome 发生了大约 500 个页面故障。真是太酷了！这就是我们做的第一个 ftrace！

### 下一个 ftrace 技巧：我们来跟踪一个进程！

好吧，只看一个函数是有点无聊！假如我想知道一个程序中都发生了什么事情。我使用一个名为 Hugo 的静态站点生成器。看看内核为 Hugo 都做了些什么事情？

在我的电脑上 Hugo 的 PID 现在是 25314，因此，我使用如下的命令去记录所有的内核函数：

```
sudo trace-cmd record --help # I read the help!
sudo trace-cmd record -p function -P 25314 # record for PID 25314

```

`sudo trace-cmd report` 输出了 18,000 行。如果你对这些感兴趣，你可以看 [这里是所有的 18,000 行的输出](https://gist.githubusercontent.com/jvns/e5c2d640f7ec76ed9ed579be1de3312e/raw/78b8425436dc4bb5bb4fa76a4f85d5809f7d1ef2/trace-cmd-report.txt)。

18,000 行太多了，因此，在这里仅摘录其中几行。

当系统调用 `clock_gettime` 运行的时候，都发生了什么：

```
 compat_SyS_clock_gettime
    SyS_clock_gettime
       clockid_to_kclock
       posix_clock_realtime_get
          getnstimeofday64
             __getnstimeofday64
                arch_counter_read
    __compat_put_timespec

```

这是与进程调试相关的一些东西：

```
 cpufreq_sched_irq_work
    wake_up_process
       try_to_wake_up
          _raw_spin_lock_irqsave
             do_raw_spin_lock
          _raw_spin_lock
             do_raw_spin_lock
          walt_ktime_clock
             ktime_get
                arch_counter_read
          walt_update_task_ravg
             exiting_task

```

虽然你可能还不理解它们是做什么的，但是，能够看到所有的这些函数调用也是件很酷的事情。

### “function graph” 跟踪

这里有另外一个模式，称为 `function_graph`。除了它既可以进入也可以退出一个函数外，其它的功能和函数跟踪器是一样的。[这里是那个跟踪器的输出](https://gist.githubusercontent.com/jvns/f32e9b06bcd2f1f30998afdd93e4aaa5/raw/8154d9828bb895fd6c9b0ee062275055b3775101/function_graph.txt)

```
sudo trace-cmd record -p function_graph -P 25314

```

同样，这里只是一个片断（这次来自 futex 代码）：

```
             |      futex_wake() {
             |        get_futex_key() {
             |          get_user_pages_fast() {
  1.458 us   |            __get_user_pages_fast();
  4.375 us   |          }
             |          __might_sleep() {
  0.292 us   |            ___might_sleep();
  2.333 us   |          }
  0.584 us   |          get_futex_key_refs();
             |          unlock_page() {
  0.291 us   |            page_waitqueue();
  0.583 us   |            __wake_up_bit();
  5.250 us   |          }
  0.583 us   |          put_page();
+ 24.208 us  |        }

```

我们看到在这个示例中，在 `futex_wake` 后面调用了 `get_futex_key`。这是在源代码中真实发生的事情吗？我们可以检查一下！！[这里是在 Linux 4.4 中 futex\_wake 的定义](https://github.com/torvalds/linux/blob/v4.4/kernel/futex.c#L1313-L1324) (我的内核版本是 4.4）。

为节省时间我直接贴出来，它的内容如下：

```
static int
futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
{
    struct futex_hash_bucket *hb;
    struct futex_q *this, *next;
    union futex_key key = FUTEX_KEY_INIT;
    int ret;
    WAKE_Q(wake_q);

    if (!bitset)
        return -EINVAL;

    ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);

```

如你所见，在 `futex_wake` 中的第一个函数调用真的是 `get_futex_key`！ 太棒了！相比阅读内核代码，阅读函数跟踪肯定是更容易的找到结果的办法，并且让人高兴的是，还能看到所有的函数用了多长时间。

### 如何知道哪些函数可以被跟踪

如果你去运行 `sudo trace-cmd list -f`，你将得到一个你可以跟踪的函数的列表。它很简单但是也很重要。

### 最后一件事：事件！

现在，我们已经知道了怎么去跟踪内核中的函数，真是太酷了！

还有一类我们可以跟踪的东西！有些事件与我们的函数调用并不相符。例如，你可能想知道当一个程序被调度进入或者离开 CPU 时，都发生了什么事件！你可能想通过“盯着”函数调用计算出来，但是，我告诉你，不可行！

由于函数也为你提供了几种事件，因此，你可以看到当重要的事件发生时，都发生了什么事情。你可以使用 `sudo cat /sys/kernel/debug/tracing/available_events` 来查看这些事件的一个列表。

我查看了全部的 sched*switch 事件。我并不完全知道 sched*switch 是什么，但是，我猜测它与调度有关。

```
sudo cat /sys/kernel/debug/tracing/available_events
sudo trace-cmd record -e sched:sched_switch
sudo trace-cmd report

```

输出如下：

```
 16169.624862:   Chrome_ChildIOT:24817 [112] S ==> chrome:15144 [120]
 16169.624992:   chrome:15144 [120] S ==> swapper/3:0 [120]
 16169.625202:   swapper/3:0 [120] R ==> Chrome_ChildIOT:24817 [112]
 16169.625251:   Chrome_ChildIOT:24817 [112] R ==> chrome:1561 [112]
 16169.625437:   chrome:1561 [112] S ==> chrome:15144 [120]

```

现在，可以很清楚地看到这些切换，从 PID 24817 -> 15144 -> kernel -> 24817 -> 1561 -> 15114。(所有的这些事件都发生在同一个 CPU 上）。

### ftrace 是如何工作的？

ftrace 是一个动态跟踪系统。当我们开始 ftrace 内核函数时，**函数的代码会被改变**。让我们假设去跟踪 `do_page_fault` 函数。内核将在那个函数的汇编代码中插入一些额外的指令，以便每次该函数被调用时去提示跟踪系统。内核之所以能够添加额外的指令的原因是，Linux 将额外的几个 NOP 指令编译进每个函数中，因此，当需要的时候，这里有添加跟踪代码的地方。

这是一个十分复杂的问题，因为，当不需要使用 ftrace 去跟踪我的内核时，它根本就不影响性能。而当我需要跟踪时，跟踪的函数越多，产生的开销就越大。

（或许有些是不对的，但是，我认为的 ftrace 就是这样工作的）

### 更容易地使用 ftrace：brendan gregg 的工具及 kernelshark

正如我们在文件中所讨论的，你需要去考虑很多的关于单个的内核函数/事件直接使用 ftrace 都做了些什么。能够做到这一点很酷！但是也需要做大量的工作！

Brendan Gregg （我们的 Linux 调试工具“大神”）有个工具仓库，它使用 ftrace 去提供关于像 I/O 延迟这样的各种事情的信息。这是它在 GitHub 上全部的 [perf-tools](https://github.com/brendangregg/perf-tools) 仓库。

这里有一个权衡，那就是这些工具易于使用，但是你被限制仅能用于 Brendan Gregg 认可并做到工具里面的方面。它包括了很多方面！:)

另一个工具是将 ftrace 的输出可视化，做的比较好的是 [kernelshark](https://lwn.net/Articles/425583/)。我还没有用过它，但是看起来似乎很有用。你可以使用 `sudo apt-get install kernelshark` 来安装它。

### 一个新的超能力

我很高兴能够花一些时间去学习 ftrace！对于任何内核工具，不同的内核版本有不同的功效，我希望有一天你能发现它很有用！

### ftrace 系列文章的一个索引

最后，这里是我找到的一些 ftrace 方面的文章。它们大部分在 LWN （Linux 新闻周刊）上，它是 Linux 的一个极好的资源（你可以购买一个 [订阅](https://lwn.net/subscribe/Info)！）

* [使用 Ftrace 调试内核 - part 1](https://lwn.net/Articles/365835/) (Dec 2009, Steven Rostedt)
* [使用 Ftrace 调试内核 - part 2](https://lwn.net/Articles/366796/) (Dec 2009, Steven Rostedt)
* [Linux 函数跟踪器的秘密](https://lwn.net/Articles/370423/) (Jan 2010, Steven Rostedt)
* [trace-cmd：Ftrace 的一个前端](https://lwn.net/Articles/410200/) (Oct 2010, Steven Rostedt)
* [使用 KernelShark 去分析实时调试器](https://lwn.net/Articles/425583/) (2011, Steven Rostedt)
* [Ftrace: 神秘的开关](https://lwn.net/Articles/608497/) (2014, Brendan Gregg)
* 内核文档：（它十分有用） [Documentation/ftrace.txt](https://raw.githubusercontent.com/torvalds/linux/v4.4/Documentation/trace/ftrace.txt)
* 你能跟踪的事件的文档 [Documentation/events.txt](https://raw.githubusercontent.com/torvalds/linux/v4.4/Documentation/trace/events.txt)
* linux 内核开发上的一些 ftrace 设计文档 （不是有用，而是有趣！) [Documentation/ftrace-design.txt](https://raw.githubusercontent.com/torvalds/linux/v4.4/Documentation/trace/ftrace-design.txt)

---

via: <https://jvns.ca/blog/2017/03/19/getting-started-with-ftrace/>

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


使用 Vi/Vim 编辑器：高级概念

![](/data/attachment/album/201801/25/130618obscga8bc0sr01sg.png)

早些时候我们已经讨论了一些关于 VI/VIM 编辑器的基础知识，但是 VI 和 VIM 都是非常强大的编辑器，还有很多其他的功能可以和编辑器一起使用。在本教程中，我们将学习 VI/VIM 编辑器的一些高级用法。

（**推荐阅读**：[使用 VI 编辑器：基础知识](http://linuxtechlab.com/working-vi-editor-basics/)）

### 使用 VI/VIM 编辑器打开多个文件

要打开多个文件，命令将与打开单个文件相同。我们只要添加第二个文件的名称。

```
 $ vi file1 file2 file 3

```

要浏览到下一个文件，我们可以（在 vim 命令模式中）使用：

```
:n

```

或者我们也可以使用

```
:e filename

```

### 在编辑器中运行外部命令

我们可以在 vi 编辑器内部运行外部的 Linux/Unix 命令，也就是说不需要退出编辑器。要在编辑器中运行命令，如果在插入模式下，先返回到命令模式，我们使用 BANG 也就是 `!` 接着是需要使用的命令。运行命令的语法是：

```
:! command

```

这是一个例子：

```
:! df -H

```

### 根据模板搜索

要在文本文件中搜索一个单词或模板，我们在命令模式下使用以下两个命令：

* 命令 `/` 代表正向搜索模板
* 命令 `?` 代表反向搜索模板

这两个命令都用于相同的目的，唯一不同的是它们搜索的方向。一个例子是：

如果在文件的开头向前搜索，

```
:/ search pattern

```

如果在文件末尾向后搜索，

```
:? search pattern

```

### 搜索并替换一个模式

我们可能需要搜索和替换我们的文本中的单词或模式。我们不是从整个文本中找到单词的出现的地方并替换它，我们可以在命令模式中使用命令来自动替换单词。使用搜索和替换的语法是：

```
:s/pattern_to_be_found/New_pattern/g

```

假设我们想要将单词 “alpha” 用单词 “beta” 代替，命令就是这样：

```
:s/alpha/beta/g

```

如果我们只想替换第一个出现的 “alpha”，那么命令就是：

```
$ :s/alpha/beta/

```

### 使用 set 命令

我们也可以使用 set 命令自定义 vi/vim 编辑器的行为和外观。下面是一些可以使用 set 命令修改 vi/vim 编辑器行为的选项列表：

```
:set ic  ' 在搜索时忽略大小写

:set smartcase ' 搜索强制区分大小写

:set nu ' 在每行开始显示行号

:set hlsearch ' 高亮显示匹配的单词

:set ro ' 将文件类型更改为只读

:set term ' 打印终端类型

:set ai ' 设置自动缩进

:set noai ' 取消自动缩进

```

其他一些修改 vi 编辑器的命令是：

```
:colorscheme ' 用来改变编辑器的配色方案 。（仅适用于 VIM 编辑器）

:syntax on ' 为 .xml、.html 等文件打开颜色方案。（仅适用于VIM编辑器）

```

这篇结束了本系列教程，请在下面的评论栏中提出你的疑问/问题或建议。

---

via: <http://linuxtechlab.com/working-vivim-editor-advanced-concepts/>

作者：[Shusain](http://linuxtechlab.com/author/shsuain/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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