24 个必知必会的系统管理员面试问题

# 24 个必知必会的系统管理员面试问题

>
> 即将进行系统管理员工作面试吗？阅读本文，了解你可能会遇到的一些问题以及可能的答案。
>
>
>

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

作为一个经常与计算机打交道的极客，在硕士毕业后在 IT 行业选择我的职业是很自然的选择。因此，我认为走上系统管理员之路是正确的路径。在我的职业生涯中，我对求职面试过程非常熟悉。现在来看一下对该职位的预期、职业发展道路，以及一系列常见面试问题及我的回答。

### 系统管理员的典型任务和职责

组织需要了解系统工作原理的人员，以确保数据安全并保持服务平稳运行。你可能会问：“等等，是不是系统管理员还能做更多的事情？”

你是对的。现在，一般来说，让我们看一下典型的系统管理员的日常任务。根据公司的需求和人员的技能水平，系统管理员的任务从管理台式机、笔记本电脑、网络和服务器到设计组织的 IT 策略不等。有时，系统管理员甚至负责购买和订购新的 IT 设备。

那些寻求系统管理工作以作为其职业发展道路的人可能会发现，由于 IT 领域的快速变化是不可避免的，因此难以保持其技能和知识的最新状态。所有人都会想到的下一个自然而然的问题是 IT 专业人员如何掌握最新的更新和技能。

### 简单的问题

这是你将遇到的一些最基本的问题，以及我的答案：

**1、你在 \*nix 服务器上登录后键入的前五个命令是什么？**

>
> * `lsblk` 以查看所有的块设备信息
> * `who` 查看谁登录到服务器
> * `top`，以了解服务器上正在运行的进程
> * `df -khT` 以查看服务器上可用的磁盘容量
> * `netstat` 以查看哪些 TCP 网络连接处于活动状态
>
>
>

**2、如何使进程在后台运行，这样做的好处是什么？**

>
> 你可以通过在命令末尾添加特殊字符 `＆` 来使进程在后台运行。通常，执行时间太长并且不需要用户交互的应用程序可以放到后台，以便我们可以在终端中继续工作。（[引文](https://github.com/trimstray/test-your-sysadmin-skills)）
>
>
>

**3、以 root 用户身份运行这些命令是好事还是坏事？**

>
> 由于两个主要问题，以 root 身份运行（任何命令）是不好的。第一个是*风险*。当你以 **root** 身份登录时，无法避免你由于粗心大意而犯错。如果你尝试以带有潜在危害的方式更改系统，则需要使用 `sudo`，它会引入一个暂停（在你输入密码时），以确保你不会犯错。
>
>
> 第二个原因是*安全*。如果你不知道管理员用户的登录信息，则系统更难被攻击。拥有 root 的访问权限意味着你已经能够进行管理员身份下的一半工作任务。
>
>
>

**4、`rm` 和 `rm -rf` 有什么区别？**

>
> `rm` 命令本身仅删除指明的文件（而不删除目录）。使用 `-rf` 标志，你添加了两个附加功能：`-r`（或等价的 `-R`、`--recursive`）标志可以递归删除目录的内容，包括隐藏的文件和子目录；而 `-f`（或 `--force`）标志使 `rm` 忽略不存在的文件，并且从不提示你进行确认。
>
>
>

**5、有一个大小约为 15GB 的 `Compress.tgz` 文件。你如何列出其内容，以及如何仅提取出特定文件？**

>
> 要列出文件的内容：
>
>
> `tar tf archive.tgz`
>
>
> 要提取特定文件：
>
>
> `tar xf archive.tgz filename`
>
>
>

### 有点难度的问题

这是你可能会遇到的一些较难的问题，以及我的答案：

**6、什么是 RAID？什么是 RAID 0、RAID 1、RAID 5、RAID 6 和 RAID 10？**

>
> RAID（<ruby> 廉价磁盘冗余阵列 <rt>  Redundant Array of Inexpensive Disks </rt></ruby>）是一种用于提高数据存储性能和/或可靠性的技术。RAID 级别为：
>
>
> * RAID 0：也称为磁盘条带化，这是一种分解文件并将数据分布在 RAID 组中所有磁盘驱动器上的技术。它没有防止磁盘失败的保障。（[引文](https://www.waytoeasylearn.com/2016/05/netapp-filer-tutorial.html)）
> * RAID 1：一种流行的磁盘子系统，通过在两个驱动器上写入相同的数据来提高安全性。RAID 1 被称为*镜像*，它不会提高写入性能，但读取性能可能会提高到每个磁盘性能的总和。另外，如果一个驱动器发生故障，则会使用第二个驱动器，发生故障的驱动器需要手动更换。更换后，RAID 控制器会将可工作的驱动器的内容复制到新驱动器上。
> * RAID 5：一种磁盘子系统，可通过计算奇偶校验数据来提高安全性和提高速度。RAID 5 通过跨三个或更多驱动器交错数据（条带化）来实现此目的。在单个驱动器发生故障时，后续读取可以从分布式奇偶校验计算出，从而不会丢失任何数据。
> * RAID 6：通过添加另一个奇偶校验块来扩展 RAID 5。此级别至少需要四个磁盘，并且可以在任何两个并发磁盘故障的情况下继续执行读/写操作。RAID 6 不会对读取操作造成性能损失，但由于与奇偶校验计算相关的开销，因此确实会对写入操作造成性能损失。
> * RAID 10：RAID 10 也称为 RAID 1 + 0，它结合了磁盘镜像和磁盘条带化功能来保护数据。它至少需要四个磁盘，并且跨镜像对对数据进行条带化。只要每个镜像对中的一个磁盘起作用，就可以检索数据。如果同一镜像对中的两个磁盘发生故障，则所有数据将丢失，因为带区集中没有奇偶校验。（[引文](https://searchstorage.techtarget.com/definition/RAID-10-redundant-array-of-independent-disks)）
>
>
>

**7、`ping` 命令使用哪个端口？**

>
> `ping` 命令使用 ICMP。具体来说，它使用 ICMP 回显请求和应答包。
>
>
> ICMP 不使用 UDP 或 TCP 通信服务：相反，它使用原始的 IP 通信服务。这意味着，ICMP 消息直接承载在 IP 数据报数据字段中。
>
>
>

**8、路由器和网关之间有什么区别？什么是默认网关？**

>
> *路由器*描述的是一种通用技术功能（第 3 层转发）或用于该目的的硬件设备，而*网关*描述的是本地网段的功能（提供到其他地方的连接性）。你还可以说“将路由器设置为网关”。另一个术语是“跳”，它描述了子网之间的转发。
>
>
> 术语*默认网关*表示局域网上的路由器，它的责任是作为对局域网外部的计算机通信的第一个联系点。
>
>
>

**9、解释一下 Linux 的引导过程。**

>
> BIOS -> 主引导记录（MBR） -> GRUB -> 内核 -> 初始化 -> 运行级
>
>
>

**10、服务器启动时如何检查错误消息？**

>
> 内核消息始终存储在 kmsg 缓冲区中，可通过 `dmesg` 命令查看。
>
>
> 引导出现的问题和错误要求系统管理员结合某些特定命令来查看某些重要文件，这些文件不同版本的 Linux 处理方式不同：
>
>
> * `/var/log/boot.log` 是系统引导日志，其中包含系统引导过程中展开的所有内容。
> * `/var/log/messages` 存储全局系统消息，包括系统引导期间记录的消息。
> * `/var/log/dmesg` 包含内核环形缓冲区信息。
>
>
>

**11、符号链接和硬链接有什么区别？**

>
> *符号链接*（*软链接*）实际是到原始文件的链接，而*硬链接*是原始文件的镜像副本。如果删除原始文件，则该软链接就没有用了，因为它指向的文件不存在了。如果是硬链接，则完全相反。如果删除原始文件，则硬链接仍然包含原始文件中的数据。（[引文](https://www.answers.com/Q/What_is_hard_link_and_soft_link_in_Linux)）
>
>
>

**12、如何更改内核参数？你可能需要调整哪些内核选项？**

>
> 要在类 Unix 系统中设置内核参数，请首先编辑文件 `/etc/sysctl.conf`。进行更改后，保存文件并运行 `sysctl -p` 命令。此命令使更改永久生效，而无需重新启动计算机
>
>
>

**13、解释一下 `/proc` 文件系统。**

>
> `/proc` 文件系统是虚拟的，并提供有关内核、硬件和正在运行的进程的详细信息。由于 `/proc` 包含虚拟文件，因此称为“虚拟文件系统”。这些虚拟文件具有独特性。其中大多数显示为零字节。
>
>
> 虚拟文件，例如 `/proc/interrupts`、`/proc/meminfo`、`/proc/mounts` 和 `/proc/partitions`，提供了系统硬件的最新信息。其他诸如 `/proc/filesystems` 和 `/proc/sys` 目录提供系统配置信息和接口。
>
>
>

**14、如何在没有密码的情况下以其他用户身份运行脚本？**

>
> 例如，如果你可以编辑 sudoers 文件（例如 `/private/etc/sudoers`），则可以使用 `visudo` 添加以下[内容](https://github.com/trimstray/test-your-sysadmin-skills)：
>
>
> `user1 ALL =（user2）NOPASSWD：/opt/scripts/bin/generate.sh`
>
>
>

**15、什么是 UID 0 toor 帐户？是被入侵了么？**

>
> `toor` 用户是备用的超级用户帐户，其中 `toor` 是 `root` 反向拼写。它预期与非标准 shell 一起使用，因此 `root` 的默认 shell 不需要更改。
>
>
> 此用途很重要。这些 shell 不是基本发行版的一部分，而是从 ports 或软件包安装的，它们安装在 `/usr/local/bin` 中，默认情况下，位于其他文件系统上。如果 root 的 shell 位于 `/usr/local/bin` 中，并且未挂载包含 `/usr/local/bin` 的文件系统，则 root 无法登录以解决问题，并且系统管理员必须重新启动进入单用户模式来输入 shell 程序的路径。
>
>
>

### 更难的问题

这是你可能会遇到的甚至更困难的问题：

**16、`tracert` 如何工作，使用什么协议？**

>
> 命令 `tracert`（或 `traceroute`，具体取决于操作系统）使你可以准确地看到在连接到最终目的地的连接链条中所触及的路由器。如果你遇到无法连接或无法 `ping` 通最终目的地的问题，则可以使用 `tracert` 来帮助你确定连接链在何处停止。（[引文](https://www.wisdomjobs.com/e-university/network-administrator-interview-questions.html)）
>
>
> 通过此信息，你可以联系正确的人；无论是你自己的防火墙、ISP、目的地的 ISP 还是中间的某个位置。 `tracert` 命令像 `ping` 一样使用 ICMP 协议，但也可以使用 TCP 三步握手的第一步来发送 SYN 请求以进行响应。
>
>
>

**17、使用 `chroot` 的主要优点是什么？我们何时以及为什么使用它？在 chroot 环境中，`mount /dev`、`mount /proc` 和 `mount /sys` 命令的作用是什么？**

>
> chroot 环境的优点是文件系统与物理主机是隔离的，因为 chroot 在文件系统内部有一个单独的文件系统。区别在于 `chroot` 使用新创建的根目录（`/`）作为其根目录。
>
>
> chroot 监狱可让你将进程及其子进程与系统其余部分隔离。它仅应用于不以 root 身份运行的进程，因为 root 用户可以轻松地脱离监狱。
>
>
> 该思路是创建一个目录树，在其中复制或链接运行该进程所需的所有系统文件。然后，你可以使用 `chroot()` 系统调用来告诉它根目录现在位于此新树的基点上，然后启动在该 chroot 环境中运行的进程。由于该命令因此而无法引用修改后的根目录之外的路径，因此它无法在这些位置上执行恶意操作（读取、写入等）。（[引文](https://unix.stackexchange.com/questions/105/chroot-jail-what-is-it-and-how-do-i-use-it)）
>
>
>

**18、如何保护你的系统免遭黑客攻击？**

>
> 遵循最低特权原则和这些做法：
>
>
> * 使用公钥加密，它可提供出色的安全性。
> * 增强密码复杂性。
> * 了解为什么要对上述规则设置例外。
> * 定期检查你的例外情况。
> * 让具体的人对失败负责。（它使你保持警惕。）（[引文](https://serverfault.com/questions/391370/how-to-prevent-zero-day-attacks)）
>
>
>

**19、什么是 LVM，使用 LVM 有什么好处？**

>
> LVM（逻辑卷管理）是一种存储设备管理技术，该技术使用户能够合并和抽象化组件存储设备的物理布局，从而可以更轻松、灵活地进行管理。使用设备映射器的 Linux 内核框架，当前迭代（LVM2）可用于将现有存储设备收集到组中，并根据需要从组合的空间分配逻辑单元。
>
>
>

**20、什么是粘性端口？**

>
> 粘性端口是网络管理员最好的朋友，也是最头痛的事情之一。它们允许你设置网络，以便通过将交换机上的每个端口锁定到特定的 MAC 地址，仅允许一台（或你指定的数字）计算机在该端口上进行连接。
>
>
>

**21、解释一下端口转发？**

>
> 尝试与安全的网络内部的系统进行通信时，从外部进行通信可能非常困难，这是很显然的。因此，在路由器本身或其他连接管理设备中使用端口转发表可以使特定流量自动转发到特定目的地。例如，如果你的网络上运行着一台 Web 服务器，并且想从外部授予对该服务器的访问权限，则可以将端口转发设置为该服务器上的端口 80。这意味着在 Web 浏览器中输入你的（外网）IP 地址的任何人都将立即连接到该服务器的网站。
>
>
> 请注意，通常不建议允许从你的网络外部直接访问服务器。
>
>
>

**22、对于 IDS，误报和漏报是什么？**

>
> 当入侵检测系统（IDS）设备为实际上没有发生的入侵生成警报时，这是<ruby> 误报（假阳性） <rt>  false positive </rt></ruby>。如果设备未生成任何警报，而入侵实际上已发生，则为<ruby> 漏报（假阴性）</ruby>。
>
>
>

**23、解释一下 `:(){ :|:& };:`，如果已经登录系统，如何停止此代码？**

>
> 这是一枚复刻炸弹。它分解如下：
>
>
> * `:()` 定义了函数，以 `:` 作为函数名，并且空括号表示它不接受任何参数。
> * `{}` 是函数定义的开始和结束。
> * `:|:` 将函数 `:` 的副本加载到内存中，并将其输出通过管道传递给函数 `:` 的另一个副本，该副本也必须加载到内存中。
> * `＆` 使前一个命令行成为后台进程，因此即使父进程被自动杀死，子进程也不会被杀死。
> * `:` 执行该函数，因此连锁反应开始。
>
>
> 保护多用户系统的最佳方法是使用特权访问管理（PAM）来限制用户可以使用的进程数。
>
>
> 复刻炸弹的最大问题是它发起了太多进程。因此，如果你已经登录系统，我们有两种尝试解决此问题的方法。一种选择是执行一个 `SIGSTOP` 命令来停止进程，例如：
>
>
> `killall -STOP -u user1`
>
>
> 如果由于占用了所有进程而无法使用命令行，则必须使用 `exec` 强制其运行：
>
>
> `exec killall -STOP -u user1`
>
>
> 对于复刻炸弹，最好的选择是防患于未然。
>
>
>

**24、什么是 OOM 杀手，它如何决定首先杀死哪个进程？**

>
> 如果内存被进程彻底耗尽，可能会威胁到系统的稳定性，那么<ruby> 内存不足 <rt>  out of memory </rt></ruby>（OOM）杀手就登场了。
>
>
> OOM 杀手首先必须选择要杀死的最佳进程。*最佳*在这里指的是在被杀死时将释放最大内存的进程，并且对系统来说最不重要。主要目标是杀死最少数量的进程，以最大程度地减少造成的损害，同时最大化释放的内存量。
>
>
> 为了实现此目标，内核为每个进程维护一个 `oom_score`。你可以在 `/proc` 文件系统中的 `pid` 目录下的看到每个进程的 `oom_score`：
>
>
> `$ cat /proc/10292/oom_score`
>
>
> 任何进程的 `oom_score` 值越高，在内存不足的情况下被 OOM 杀手杀死的可能性就越高。（[引文](https://unix.stackexchange.com/a/153586/8369)）
>
>
>

### 总结

系统管理人员的薪水[差别很大](https://blog.netwrix.com/2018/07/23/systems-administrator-salary-in-2018-how-much-can-you-earn/)，有些网站上说年薪在 70,000 到 100,000 美元之间，具体取决于地点、组织的规模以及你的教育水平以及多年的工作经验。系统管理的职业道路最终归结为你对使用服务器和解决那些酷问题的兴趣。现在，我要说，继续前进，实现你的梦想之路吧！

---

via: <https://opensource.com/article/19/7/sysadmin-job-interview-questions>

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

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


GNOME Linux 桌面入门

作为GNOME的忠实用户，从2003年的Redhat 9开始使用GNOME, 不过比较习惯GNOME 2. 对3 开始很不习惯。感谢dash to dock 插件，让我适应了GNOME3，比较类似Mac的界面吧。

# GNOME Linux 桌面入门

>
> 本文是 24 天 Linux 桌面特别系列的一部分。GNOME 是大多数现代 Linux 发行版的默认桌面，它干净、简单、组织良好。
>
>
>

[GNOME](https://www.gnome.org/) 项目理所应当是 Linux 桌面的宠儿。它起初是专有桌面（当时包括 KDE）的自由开源的桌面替代品，此后一直发展强劲。GNOME 采用了[由 GIMP 项目开发](https://www.gtk.org/overview.php)的 GTK+，并将其开发为强大的通用 GTK 框架。该项目开创了用户界面的先声，挑战了桌面“应有”外观的先入之见，并为用户提供了新的范例和选项。

在大多数主流现代 Linux 发行版（包括 RHEL、Fedora、Debian 和 Ubuntu）中，GNOME 作为默认桌面而广泛使用。如果你的发行版不提供它的某个版本，那么你可以从软件仓库中安装 GNOME。但是，在执行此操作之前，请注意，为了提供完整的桌面体验，这会随桌面一起安装许多 GNOME 应用。如果你在用其他桌面，那么你可能会发现有冗余的应用（两个 PDF 阅读器、两个媒体播放器、两个文件管理器，等等）。如果你只想尝试 GNOME 桌面，请考虑在虚拟机，如 [GNOME Boxes](https://opensource.com/article/19/5/getting-started-gnome-boxes-virtualization)，中安装 GNOME 发行版。

### GNOME 功能

GNOME 桌面很干净，顶部有一个简单的任务栏，右上角的系统托盘中只有很少的图标。GNOME 上没有桌面图标，这是设计使然。如果你是喜欢在桌面上保存*任何东西*的用户，那么你可能会意识到桌面会定期地变得混乱，而且，更糟糕的是，由于你的应用掩盖了桌面，因此桌面永远不会显示出来。

GNOME 解决了两个问题：（在功能上）没有桌面，并且动态生成新的虚拟工作区，因此你可以在全屏模式下运行应用。如果你常把屏幕弄乱，那么可能需要一些时间来习惯，但实际上，从各个方面来说，这都是一种改进的工作流程。你将学习如何使文件井井有条（或者将它们分散在家目录中），并且可以像在手机上一样快速地在屏幕之间切换。

当然，并非所有应用都设计为在全屏模式下运行，因此，如果你更喜欢单击切换窗口，也可以这样做。

GNOME 哲学褒扬了 Canonical 对常见任务的解决方案。在 GNOME 中，你通常不会发现“回字有四种写法”。你会找到一种或两种官方方法来完成一项任务，你了解了这些方法后，便只需记住这些即可。它非常简单，但由于它在 Linux 上运行，因此在技术上也很灵活（毕竟，你不必因为运行 GNOME 桌面而必须要使用 GNOME 应用）。

### 应用菜单

要访问名为“活动”的应用菜单，请在桌面的左上角单击。此菜单将占满整个屏幕，屏幕最左侧有一栏常见应用的 dock，或可以在网格中浏览应用的图标。你可以通过浏览已安装的应用，或输入软件的头几个字母来过滤列表，然后来启动应用。

### GNOME 应用

GNOME 不仅是桌面。它是一个桌面以及一组丰富的集成应用，例如 Gedit 文本编辑器、Evince PDF 查看器、Web 浏览器、图像查看器、Nautilus 文件管理器等等。GNOME 应用（例如桌面本身）遵循 [GNOME 人机界面指南](https://developer.gnome.org/hig/stable/)，因此用户体验既愉悦又一致。无论你是否使用 GNOME 桌面，都可能使用 GTK 应用，也可能会使用 GNOME 应用。

### GNOME 3 及更高版本

GNOME 项目进展顺利，还有几个令人兴奋的项目（例如 MATE 和 [Cinnamon](https://opensource.com/article/19/11/advent-2019-cinnamon)）。它流行、令人舒适，被视为 Linux 桌面的代表。

---

via: <https://opensource.com/article/19/12/gnome-linux-desktop>

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

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


5 个最酷的终端分页器

Summary: 分页器提供了许多使文本文件导航更加简单的功能，包括滚动、搜索功能，以及作为命令管道的一部分而具有的功能。

# 5 个最酷的终端分页器

像日志或源代码这样的大文件可能会多达成千上万行，这使得在文件内导航非常困难，尤其是在终端上。此外，大多数终端仿真器的回滚缓冲区只有几百行。这可能使得无法使用打印到标准输出的实用程序（例如 `cat`、`head` 和 `tail`）在终端中浏览大型文件。在计算时代的早期，程序员通过开发用于以虚拟“页面”形式显示文本的实用程序来解决这些问题，该实用程序被形象地描述为<ruby> 分页器 <rt>  pager </rt></ruby>。

*分页器*提供了许多使文本文件导航更加简单的功能，包括滚动、搜索功能，以及作为命令[管道](https://fedoramagazine.org/command-line-quick-tips-using-pipes-to-connect-tools/)的一部分而具有的功能。与大多数文本编辑器相比，某些终端分页器不需要加载整个文件即可查看，这使得它们更快，特别是对于非常大的文件。

在现代 Linux 计算时代，终端仿真器比以往更加复杂。它们提供了对缤纷的色彩、终端尺寸调整以及许多其它功能的支持，这些功能使得辨析屏幕上的文本变得更加轻松和高效。从诸如 `pg` 和 `more` 这样极其简单的 UNIX 实用程序，到涵盖各种使用场景的、功能广泛的复杂程序，终端分页器也经历了类似的演变。考虑到这一点，我们或“多”或“少”地汇总了一些最受欢迎的终端分页实用程序的列表。

### more

`more` 是最早的分页器之一，最初在 3.0 BSD 版本中出现。`more` 的第一个实现由 [Daniel Halbert](https://danhalbert.org/more.html) 编写于 1978 年。从那时起，`more` 已成为许多操作系统的普遍功能，包括 Windows、OS/2，MacOS 和大多数 Linux 发行版。

`more` 是一个非常轻量级的实用程序。util-linux 软件包中提供的版本只有不到 2100 行的 C 语言代码。但是，这种较小的代码大小是有代价的。大多数版本的 `more` 的功能相对有限，不支持向后滚动或搜索。命令也同样精简：按回车键可滚动一行，或按空格键滚动一页。其他一些有用的命令包括：

* 在阅读时按 `v` 键以在默认的终端编辑器中打开当前文件。
* `/模式` 可以让你搜索下一个出现的“模式”。
* 以多个文件作为参数调用 `more` 时，`:n` 和 `:p` 将分别打开下一个和上一个文件 ### less

`less` 最初被认为是 `more` 的继承者，解决了它的一些局限性。`less` 以 `more` 的功能为基础，增加了许多有用的功能，包括向后滚动、向后搜索。它也更适合窗口大小调整。

`less` 中的导航方式与 `more` 类似，尽管 `less` 也从 `vi` 编辑器借用了一些有用的命令。用户可以使用熟悉的<ruby> 主行导航键 <rt>  home row navigational keys </rt></ruby>（LCTT 译注：指 左手的 `A`、`S`、`D`、`F` 和右手的 `J`、`K`、`L`、`;`，及大拇指所在的空格键）浏览文档。看一眼 `less` 的手册页，就会发现相当多的可用命令。一些特别有用的示例包括：

* `?模式` 可让你在文件中向后搜索“模式”。
* `＆模式` 仅显示具有“模式”特征的行。这对于发现自己经常要使用 `$ grep 模式 | less` 的人特别有用。
* 使用 `-s`（或 `–sqeueeze-blank-lines`）标志来调用 `less`，使你可以查看空白较大的文本文件。 多个换行符被简化为单个中断行。
* 在该程序中调用的 `s 文件名` 将输入保存到 `文件名`中（如果输入来自管道）。
* 或者，使用 `-o 文件名` 标志来调用 `less` 将把 `less` 的输入保存到 `文件名` 中。 随着这些增强的功能也带来了体积的略微增大。在写作本文时，Fedora 随附的 `less` 版本大约有 25000 行源代码。当然，除非是受存储限制最大的系统，在所有其它的系统上这都不是问题。`less` 比 `more` 功能更多。

### most

`less` 旨在扩展 `more` 的现有功能，而 `most` 采用另一种方法。`most` 不是在传统的单个文件视图上进行扩展，而是使用户能够将其视图拆分为“窗口”。每个窗口以不同的查看模式包含不同的文件。

重要的是，`most` 考虑了其输入文本的宽度。默认的查看模式是不换行的（`less` 中的 `-S` 参数），此功能在处理“宽”文件时特别有用。尽管对于某些用户来说，这些设计决策可能代表着与传统的重大偏离，但最终结果却非常强大。

除了 `more` 提供的导航命令外，`most` 使用直观的助记符进行文件导航。例如，`t` 移至文件的顶部（Top），而 `b` 移至底部（Bottom）。这样，不熟悉 `vi` 及其衍生品的用户会发现 `most` 非常简单好用。

`most` 的与众不同之处在于它能够快速轻松地拆分窗口和上下文。例如，可以使用以下命令打开两个不同的文本文件：

```
$ most textFile1.txt textFile2.txt
```

为了水平拆分屏幕，请使用组合键 `Ctrl+x, 2` 或 `Ctrl+w, 2`。 `:n` 命令将在给定窗口中打开下一个文件参数，提供两个文件的分屏视图：

如果在一个窗口中关闭自动换行，它不会影响其他窗口的行为。（行末的）`\` 字符表示换行或折叠，而 `$` 字符表示文件超出了当前窗口的限制。

### pspg

使用 SQL 数据库的人员通常需要能够一目了然地检查数据库的内容。许多流行的开源 DBMS（例如 MySQL 和 PostGreSQL）的命令行界面都使用系统默认的分页器来查看无法显示在单个屏幕上的输出。诸如 `more` 和 `less` 之类的实用程序是围绕呈现文本文件的想法而设计的，但是对于更结构化的数据，还有一些不足之处。天真的文本分页程序没有宽的表格数据的概念，当处理大型查询时，这可能会令人感到沮丧。

[pspg](https://github.com/okbob/pspg) 试图通过为用户提供在查看时冻结列、*原位*排序数据并为输出着色的功能来解决此问题。尽管`pspg` 最初是专门用作 `psql` 的分页器的替代品，但该程序还支持查看 CSV 数据，并且是 `mysql` 和 `pgcli` 的合适的直接替代品。

### Vim

在现代的颜色鲜明的终端中，无休止的黑色页面上的灰色文字感觉太过时了。强大的文本编辑器（如 `vim`）提供的语法高亮显示选项对于浏览源代码很有用。此外，`vim` 提供的搜索功能远远超过了竞争对手。考虑到这一点，`vim` 附带了一个 shell 脚本 `less.sh`，该脚本可以使 `vim` 替代传统的分页器。

要将 `vim` 设置为手册页的[默认分页器](https://zameermanji.com/blog/2012/12/30/using-vim-as-manpager/)，请将以下内容添加到 shell 的配置中（如果使用默认的bash shell 的话是 `~/.bashrc`）：

```
export MANPAGER="/bin/sh -c \"col -b | vim -c 'set ft=man ts=8 nomod nolist nonu noma' -\""
```

或者，要将 `vim` 设置为系统范围内的默认分页器，请找到 `less.sh` 脚本。（你可以在当前 Fedora 系统上的 `/usr/share/vim/vim81/macros/` 找到它。）将此位置导出为变量 `PAGER` 以将其设置为默认值，或者将其设置为别名以显式调用它。

---

via: <https://fedoramagazine.org/5-cool-terminal-pagers-in-fedora/>

作者：[Jacob Burns](https://fedoramagazine.org/author/jaek/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[wxy](https://github.com/wxy) 校对：[wxy](https://github.com/wxy)

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


如何在 Linux 中找出 CPU 占用高的进程

Summary: 在之前的文章中我们已经讨论过 如何在 Linux 中找出内存消耗最大的进程。你可能也会遇到在 Linux 系统中找出 CPU 占用高的进程的情形。

# 如何在 Linux 中找出 CPU 占用高的进程

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

在之前的文章中我们已经讨论过 [如何在 Linux 中找出内存消耗最大的进程](/article-11542-1.html)。你可能也会遇到在 Linux 系统中找出 CPU 占用高的进程的情形。如果是这样，那么你需要列出系统中 CPU 占用高的进程列表来确定。我认为只有两种方法能实现：使用 [top 命令](https://www.2daygeek.com/linux-top-command-linux-system-performance-monitoring-tool/) 和 [ps 命令](https://www.2daygeek.com/linux-ps-command-find-running-process-monitoring/)。出于一些理由，我更倾向于用 `top` 命令而不是 `ps` 命令。但是两个工具都能达到你要的目的，所以你可以根据需求决定使用哪个。这两个工具都被 Linux 系统管理员广泛使用。

### 1) 怎样使用 top 命令找出 Linux 中 CPU 占用高的进程

在所有监控 Linux 系统性能的工具中，Linux 的 `top` 命令是最好的也是最知名的一个。`top` 命令提供了 Linux 系统运行中的进程的动态实时视图。它能显示系统的概览信息和 Linux 内核当前管理的进程列表。它显示了大量的系统信息，如 CPU 使用、内存使用、交换内存、运行的进程数、目前系统开机时间、系统负载、缓冲区大小、缓存大小、进程 PID 等等。默认情况下，`top` 命令的输出结果按 CPU 占用进行排序，每 5 秒中更新一次结果。如果你想要一个更清晰的视图来更深入的分析结果，[以批处理模式运行 top 命令](https://www.2daygeek.com/linux-run-execute-top-command-in-batch-mode/) 是最好的方法。同时，你需要 [理解 top 命令输出结果的含义](https://www.2daygeek.com/understanding-linux-top-command-output-usage/) ，这样才能解决系统的性能问题。

```
# top -b | head -50

top - 00:19:17 up 14:23,  1 user,  load average: 2.46, 2.18, 1.97
Tasks: 306 total,   1 running, 305 sleeping,   0 stopped,   0 zombie
%Cpu0  : 10.4 us,  3.0 sy,  0.0 ni, 83.9 id,  0.0 wa,  1.3 hi,  1.3 si,  0.0 st
%Cpu1  : 17.0 us,  3.0 sy,  0.0 ni, 78.7 id,  0.0 wa,  0.3 hi,  1.0 si,  0.0 st
%Cpu2  : 13.0 us,  4.0 sy,  0.0 ni, 81.3 id,  0.0 wa,  0.3 hi,  1.3 si,  0.0 st
%Cpu3  : 12.3 us,  3.3 sy,  0.0 ni, 82.5 id,  0.3 wa,  0.7 hi,  1.0 si,  0.0 st
%Cpu4  : 12.2 us,  3.0 sy,  0.0 ni, 82.8 id,  0.7 wa,  0.3 hi,  1.0 si,  0.0 st
%Cpu5  :  6.4 us,  2.7 sy,  0.0 ni, 89.2 id,  0.0 wa,  0.7 hi,  1.0 si,  0.0 st
%Cpu6  : 26.7 us,  3.4 sy,  0.0 ni, 68.6 id,  0.0 wa,  0.7 hi,  0.7 si,  0.0 st
%Cpu7  : 15.6 us,  4.0 sy,  0.0 ni, 78.8 id,  0.0 wa,  0.7 hi,  1.0 si,  0.0 st
KiB Mem : 16248556 total,  1448920 free,  8571484 used,  6228152 buff/cache
KiB Swap: 17873388 total, 17873388 free,        0 used.  4596044 avail Mem
PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 2179 daygeek   20     3106324 613584 327564 S  79.5   3.8  14:19.76 Web Content
 1714 daygeek   20     4603372 974600 403504 S  20.2   6.0  65:18.91 firefox
 1227 daygeek   20     4192012 376332 180348 S  13.9   2.3  20:43.26 gnome-shell
18324 daygeek   20     3296192 766040 127948 S   6.3   4.7   9:18.12 Web Content
 1170 daygeek   20     1008264 572036 546180 S   6.0   3.5  18:07.85 Xorg
 4684 daygeek   20     3363708   1.1g   1.0g S   3.6   7.2  13:49.92 VirtualBoxVM
 4607 daygeek   20     4591040   1.7g   1.6g S   3.0  11.0  14:09.65 VirtualBoxVM
 1211 daygeek    9 -11 2865268  21032  16588 S   2.0   0.1  10:46.37 pulseaudio
 4562 daygeek   20     1096888  28812  21044 S   1.7   0.2   4:42.93 VBoxSVC
 1783 daygeek   20     3123888 376896 134788 S   1.3   2.3  39:32.56 Web Content
 3286 daygeek   20     3089736 404088 184968 S   1.0   2.5  41:57.44 Web Content
```

上面的命令的各部分解释：

* `top`：命令
* `-b`：批次档模式
* `head -50`：显示输出结果的前 50 个
* `PID`：进程的 ID
* `USER`：进程的归属者
* `PR`：进程的等级
* `NI`：进程的 NICE 值
* `VIRT`：进程使用的虚拟内存
* `RES`：进程使用的物理内存
* `SHR`：进程使用的共享内存
* `S`：这个值表示进程的状态: `S` = 睡眠，`R` = 运行，`Z` = 僵尸进程
* `%CPU`：进程占用的 CPU 比例
* `%MEM`：进程使用的 RAM 比例
* `TIME+`：进程运行了多长时间
* `COMMAND`：进程名字

如果你想看命令的完整路径而不是命令名字，以运行下面的格式 `top` 命令：

```
# top -c -b | head -50

top - 00:28:49 up 14:33,  1 user,  load average: 2.43, 2.49, 2.23
Tasks: 305 total,   1 running, 304 sleeping,   0 stopped,   0 zombie
%Cpu0  : 11.7 us,  3.7 sy,  0.0 ni, 82.3 id,  0.0 wa,  1.0 hi,  1.3 si,  0.0 st
%Cpu1  : 13.6 us,  3.3 sy,  0.0 ni, 81.1 id,  0.7 wa,  0.3 hi,  1.0 si,  0.0 st
%Cpu2  : 10.9 us,  2.6 sy,  0.0 ni, 85.1 id,  0.0 wa,  0.3 hi,  1.0 si,  0.0 st
%Cpu3  : 16.0 us,  2.6 sy,  0.0 ni, 80.1 id,  0.0 wa,  0.3 hi,  1.0 si,  0.0 st
%Cpu4  :  9.2 us,  3.6 sy,  0.0 ni, 85.9 id,  0.0 wa,  0.3 hi,  1.0 si,  0.0 st
%Cpu5  : 15.6 us,  2.9 sy,  0.0 ni, 80.5 id,  0.0 wa,  0.3 hi,  0.7 si,  0.0 st
%Cpu6  : 11.6 us,  4.3 sy,  0.0 ni, 82.7 id,  0.0 wa,  0.3 hi,  1.0 si,  0.0 st
%Cpu7  :  8.0 us,  3.0 sy,  0.0 ni, 87.3 id,  0.0 wa,  0.7 hi,  1.0 si,  0.0 st
KiB Mem : 16248556 total,  1022456 free,  8778508 used,  6447592 buff/cache
KiB Swap: 17873388 total, 17873388 free,        0 used.  4201560 avail Mem
PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
18527 daygeek   20     3151820 624808 325748 S  52.8   3.8  59:26.72 /usr/lib/firefox/firefox -contentproc -childID 18 -isForBrowser -prefsLen 10002 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /+
 1714 daygeek   20     4764668 910940 443228 S  21.5   5.6  68:59.33 /usr/lib/firefox/firefox --new-window
 1227 daygeek   20     4193108 377344 181404 S  11.6   2.3  21:47.36 /usr/bin/gnome-shell
 1170 daygeek   20     1008820 572700 546844 S   5.6   3.5  19:05.10 /usr/lib/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -nolisten tcp -background none -noreset -keeptty -verbose 3
18324 daygeek   20     3300288 789344 127948 S   5.0   4.9   9:46.89 /usr/lib/firefox/firefox -contentproc -childID 16 -isForBrowser -prefsLen 10002 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /+
 4684 daygeek   20     3363708   1.1g   1.0g S   3.6   7.2  14:10.18 /usr/lib/virtualbox/VirtualBoxVM --comment CentOS7 --startvm 002f47b8-2af2-48f5-be1d-67b67e03514c --no-startvm-errormsgbox
 4607 daygeek   20     4591040   1.7g   1.6g S   3.0  11.0  14:28.86 /usr/lib/virtualbox/VirtualBoxVM --comment Ubuntu-18.04 --startvm e8c32dbb-8b01-41b0-977a-bf28b9db1117 --no-startvm-errormsgbox
 1783 daygeek   20     3132640 451924 132168 S   2.6   2.8  39:49.66 /usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -prefsLen 1 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /usr/l+
 1211 daygeek    9 -11 2865268  21272  16828 S   2.0   0.1  11:01.29 /usr/bin/pulseaudio --daemonize=no
 4562 daygeek   20     1096888  28812  21044 S   1.7   0.2   4:49.33 /usr/lib/virtualbox/VBoxSVC --auto-shutdown
16865 daygeek   20     3073364 430596 124652 S   1.3   2.7   8:04.02 /usr/lib/firefox/firefox -contentproc -childID 15 -isForBrowser -prefsLen 10002 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /+
 2179 daygeek   20     2945348 429644 172940 S   1.0   2.6  15:20.90 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -prefsLen 7821 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /us+
```

### 2) 怎样使用 ps 命令找出 Linux 中 CPU 占用高的进程

`ps` 是<ruby> 进程状态 <rt>  process status </rt></ruby>的缩写，它能显示系统中活跃的/运行中的进程的信息。它提供了当前进程及其详细信息，诸如用户名、用户 ID、CPU 使用率、内存使用、进程启动日期时间、命令名等等的快照。

```
# ps -eo pid,ppid,%mem,%cpu,cmd --sort=-%cpu | head

  PID  PPID %MEM %CPU CMD
18527  1714  4.2 40.3 /usr/lib/firefox/firefox -contentproc -childID 18 -isForBrowser -prefsLen 10002 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 1714 true tab
 1714  1152  5.6  8.0 /usr/lib/firefox/firefox --new-window
18324  1714  4.9  6.3 /usr/lib/firefox/firefox -contentproc -childID 16 -isForBrowser -prefsLen 10002 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 1714 true tab
 3286  1714  2.0  5.1 /usr/lib/firefox/firefox -contentproc -childID 14 -isForBrowser -prefsLen 8078 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 1714 true tab
 1783  1714  3.0  4.5 /usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -prefsLen 1 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 1714 true tab
 1227  1152  2.3  2.5 /usr/bin/gnome-shell
 1170  1168  3.5  2.2 /usr/lib/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -nolisten tcp -background none -noreset -keeptty -verbose 3
16865  1714  2.5  2.1 /usr/lib/firefox/firefox -contentproc -childID 15 -isForBrowser -prefsLen 10002 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 1714 true tab
 2179  1714  2.7  1.8 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -prefsLen 7821 -prefMapSize 213431 -parentBuildID 20191031132559 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 1714 true tab
```

上面的命令的各部分解释：

* `ps`：命令名字
* `-e`：选择所有进程
* `-o`：自定义输出格式
* `–sort=-%cpu`：基于 CPU 使用率对输出结果排序
* `head`：显示结果的前 10 行
* `PID`：进程的 ID
* `PPID`：父进程的 ID
* `%MEM`：进程使用的 RAM 比例
* `%CPU`：进程占用的 CPU 比例
* `Command`：进程名字

如果你只想看命令名字而不是命令的绝对路径，以运行下面的格式 `ps` 命令：

```
# ps -eo pid,ppid,%mem,%cpu,comm --sort=-%cpu | head

  PID  PPID %MEM %CPU COMMAND
18527  1714  4.1 40.4 Web Content
 1714  1152  5.7  8.0 firefox
18324  1714  4.9  6.3 Web Content
 3286  1714  2.0  5.1 Web Content
 1783  1714  3.0  4.5 Web Content
 1227  1152  2.3  2.5 gnome-shell
 1170  1168  3.5  2.2 Xorg
16865  1714  2.4  2.1 Web Content
 2179  1714  2.7  1.8 Web Content
```

---

via: <https://www.2daygeek.com/how-to-find-high-cpu-consumption-processes-in-linux/>

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

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


Java 与 Python：你应该选择哪个？

Summary: 比较世界上最流行的两种编程语言，并在投票中让我们知道你喜欢哪一个。

this is a hello-world

比较世界上最流行的两种编程语言，并在投票中让我们知道你喜欢哪一个。

# Java 与 Python：你应该选择哪个？

>
> 比较世界上最流行的两种编程语言，并在投票中让我们知道你喜欢哪一个。
>
>
>

让我们比较一下世界上两种最受欢迎、最强大的编程语言：Java 和 Python！这两种语言有巨大的社区支持和库来执行几乎任何编程任务，尽管选择编程语言通常取决于开发人员的场景。在比较和对比之后，请投票分享你的观点。

### 是什么？

* **Java** 是一门通用面向对象的编程语言，主要用于开发从移动端到 Web 到企业级应用的各种应用。
* **Python** 是一门高级面向对象的编程语言，主要用于 Web 开发、人工智能、机器学习、自动化和其他数据科学应用。

### 创建者

* **Java** 是由 James Gosling（Sun Microsystems）创造的。
* **Python** 是由 Guido van Rossum 创造的。

### 开源状态

* **Java** 是免费的，（大部分）开源，但商业用途除外。
* **Python** 对于所有场景都是免费、开源的。

### 平台依赖

* **Java** 根据它的 WORA (“<ruby> 一次编写，到处运行 <rt>  write once, run anywhere </rt></ruby>”)哲学，它是平台无关的。
* **Python** 依赖于平台。

### 编译或解释

* **Java** 是一门编译语言。Java 程序在编译时转换为字节码，而不是运行时。
* **Python** 是一门解释性语言。Python 程序在运行时进行解释。

### 文件创建

* **Java**：编译后生成 `<filename>.class` 文件。
* **Python**：在运行期，创建 `<filename>.pyc` 文件。

### 错误类型

* **Java** 有 2 种错误类型：编译和运行时错误。
* **Python** 有 1 种错误类型：回溯（或运行时）错误。

### 静态或动态类型

* **Java** 是静态类型。当初始化变量时，需要在程序中指定变量的类型，因为类型检查是在编译时完成的。
* **Python** 是动态类型。变量不需要在初始化时指定类型，因为类型检查是在运行时完成的。

### 语法

* **Java**：每个语句都需要以分号（`;` ）结尾，并且代码块由大括号（ `{}` ）分隔。
* **Python**：代码块通过缩进分隔（用户可以选择要使用的空格数，但在整个块中应保持一致）。

### 类的数量

* **Java**：在 Java 中的单个文件中只能存在一个公有顶级类。
* **Python**：Python 中的单个文件中可以存在任意数量的类。

### 代码多少？

* **Java** 通常比 Python 要写更多代码行。
* **Python**通常比 Java 要写更少代码行。

### 多重继承

* **Java** 不支持多重继承（从两个或多个基类继承）。
* **Python** 支持多重继承，但由于继承复杂性、层次结构、依赖等各种问题，它很少实现。

### 多线程

* **Java** 多线程可以支持同时运行的两个或多个并发线程。
* **Python** 使用全局解释器锁 （GIL），一次只允许运行单个线程（一个 CPU 核）。

### 执行速度

* **Java** 的执行时间通常比 Python 快。
* **Python** 的执行时间通常比 Java 慢。

### Hello world

Java 的：

```
public class Hello {
   public static void main([String][3][] args) {
      [System][4].out.println("Hello Opensource.com from Java!");
   }
}
```

Python 的：

```
print("Hello Opensource.com from Java!")
```

### 运行程序

要运行 java 程序 `Hello.java`，你需要先编译它，这将创建一个 `Hello.class` 文件。只需运行类名 `java Hello`。对于 Python，只需运行文件 `python3 helloworld.py`。

---

via: <https://opensource.com/article/19/12/java-vs-python>

作者：[Archit Modi](https://opensource.com/users/architmodi) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


每周开源点评：Kubernetes 傻瓜指南、低代码开发人员和其他行业趋势

Summary: 每周开源社区、市场和行业趋势。

每周开源社区、市场和行业趋势。

# 每周开源点评：Kubernetes 傻瓜指南、低代码开发人员和其他行业趋势

>
> 每周开源社区、市场和行业趋势。
>
>
>

<img src="content_image/album_201912_16_105530ocd5715c1jjj75ea.png" alt="Person standing in front of a giant computer screen with numbers, data" title="Person standing in front of a giant computer screen with numbers, data">

作为我在具有开源开发模型的企业软件公司担任高级产品营销经理的角色的一部分，我为产品营销人员、经理和其他影响者定期发布有关开源社区，市场和行业趋势的定期更新。这里有该更新中我和他们最喜欢的四篇文章。

### Kubernetes 傻瓜指南

* [文章链接](https://www.cbronline.com/feature/an-idiots-guide-to-kubernetes)

>
> Kubernetes 已经发展出了新的特性，这使其成为企业软件的更好的容器平台。安全性和高级网络等元素已被纳入 Kubernetes 上游代码的主体，并且现在可供所有人使用。
>
>
> 然而，企业解决方案的其他方面总会有补充需求；比如日志记录和性能监控。这就是像 Istio 等辅助包发挥作用的地方，它带来了额外的功能，但是仍使 Kubernetes 的核心保持了合理的大小和特性集。
>
>
>

**影响**: 我总是发现，人们很容易把对技术发展的认识视为理所当然。当与你打交道的每个人都处于“最前沿”时，你的观点就会歪曲到这样的程度：你甚至可能会认为对最新的（*此处插入首选技术*）一无所知的人跟不上潮流，而实际上这并没有开始影响他们做自己需要做的事情的能力。那些人不是白痴；他们是我们的朋友、客户、合作伙伴、合作者和社区。

### Gartner: 采用低代码开发之前应该考虑什么

* [文章链接](https://www.computerweekly.com/feature/Gartner-What-to-consider-before-adopting-low-code-development)

>
> 尽管专注于商业 IT 团队，但 Gartner 发现，一个日益重要的开发人员社区是需要快速开发简单应用程序或构建最低可行产品或多体验功能的核心 IT 专业开发人员。当应用程序领导者在传统的应用程序项目中使用低代码时，他们可能希望使用标准的 IT DevOps 自动化方法和低代码工具。
>
>
>

**影响**: 越来越多的用例和用户体验可以通过需要更少时间和技能来创建的应用程序来处理和交互。而低代码开发人员也可能会结合成一个具有他们自己的规范和亚文化的独特群体。

### 诺基亚认为云原生对 5G 核心至关重要

* [文章链接](https://www.sdxcentral.com/articles/news/nokia-argues-cloud-native-is-essential-to-5g-core/2019/11/)

>
> 诺基亚概述了 5G 的五个关键业务目标，这些目标只能通过云原生环境来实现。其中包括：更好的带宽、延迟和密度；通过网络切片将服务扩展到新的企业、行业和[物联网](https://www.sdxcentral.com/5g/iot/ "IoT")市场；根据敏捷性和效率定义的快速服务部署；超越传统带宽、语音和信息传递的新服务；以及利用端到端网络获取更多收入的数字服务的出现。
>
>
>

**影响**: 在越来越多的事物连接到网络的情况下，这是最有意义的。4G 主要与越来越多的手机有关；只有当你开始连接其他所有东西时，5G 才是真正必要的。4G 意味着我们的手机上有更丰富的应用程序，而 5G 几乎与手机无关。

### API：隐藏的业务加速器

* [文章链接](https://www.cbronline.com/opinion/digital-transformation-3)

>
> 要想让组织成功地进行数字化转型，API 策略至关重要。从解锁有价值的数据到加快开发时间，API 都是数字时代的幕后英雄。那些已经尝试过 API 的人已经感受到了好处。例如，研究表明，使用 API 的企业中，有 53% 认为它们提高了生产力，而 29% 声称它们的收入增长是使用 API 的直接结果。当 API 被视为存在于一个项目之外的可发现和可重用的产品时，它有助于为持续的变更奠定灵活的基础。
>
>
>

**影响**: 隐藏的业务加速器实际上是这样一种思想，即功能应该以一种方式进行打包，使其能够在原始提供者没有预料到的环境中进行重新利用和组合。

我希望你喜欢这份上周给我留下深刻印象的列表，并于下周一回来了解更多开源社区、市场和行业的趋势。

---

via: <https://opensource.com/article/19/12/technology-advice-and-other-industry-trends>

作者：[Tim Hildred](https://opensource.com/users/thildred) 选题：[lujun9972](https://github.com/lujun9972) 译者：[algzjh](https://github.com/algzjh) 校对：[wxy](https://github.com/wxy)

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


使用 split 命令分割 Linux 文件

# 使用 split 命令分割 Linux 文件

>
> 一些简单的 Linux 命令能让你根据需要分割以及重新组合文件，来适应存储或电子邮件附件大小的限制。
>
>
>

<img src="content_image/album_201912_16_111204d5pznhjqi7nxbhzw.jpg" alt="Marco Verch" title="Marco Verch">

Linux 系统提供了一个非常易于使用的命令来分割文件。在将文件上传到限制大小的存储网站或者作为邮件附件之前，你可能需要执行此操作。要将文件分割为多个文件块，只需使用 `split` 命令。

```
$ split bigfile
```

默认情况下，`split` 命令使用非常简单的命名方案。文件块将被命名为 `xaa`、`xab`、`xac` 等，并且，大概地，如果你将足够大的文件分割，你甚至可能会得到名为 `xza` 和 `xzz` 的块。

除非你要求，否则该命令将无任何反馈地运行。但是，如果你想在创建文件块时看到反馈，可以使用 `--verbose` 选项。

```
$ split –-verbose bigfile
creating file 'xaa'
creating file 'xab'
creating file 'xac'
```

你还可以给文件命名前缀。例如，要将你原始文件分割并命名为 `bigfile.aa`、`bigfile.ab` 等，你可以将前缀添加到 `split` 命令的末尾，如下所示：

```
$ split –-verbose bigfile bigfile.
creating file 'bigfile.aa'
creating file 'bigfile.ab'
creating file 'bigfile.ac'
```

请注意，上述命令中显示的前缀的末尾会添加一个点。否则，文件将是 `bigfileaa` 之类的名称，而不是 `bigfile.aa`。

请注意，`split` 命令*不会*删除你的原始文件，只是创建了文件块。如果要指定文件块的大小，可以使用 `-b` 选项将其添加到命令中。例如：

```
$ split -b100M bigfile
```

文件大小可以是 KB、MB，GB，最大可以是 YB！只需使 K、M、G、T、P、E、Z 和 Y 这些合适的字母。

如果要基于每个块中的行数而不是字节数来拆分文件，那么可以使用 `-l`（行）选项。在此示例中，每个文件将有 1000 行，当然，最后一个文件可能有较少的行。

```
$ split --verbose -l1000 logfile log.
creating file 'log.aa'
creating file 'log.ab'
creating file 'log.ac'
creating file 'log.ad'
creating file 'log.ae'
creating file 'log.af'
creating file 'log.ag'
creating file 'log.ah'
creating file 'log.ai'
creating file 'log.aj'
```

如果你需要在远程站点上重新组合文件，那么可以使用如下所示的 `cat` 命令轻松地完成此操作：

```
$ cat x?? > original.file
$ cat log.?? > original.file
```

上面所示的分割和组合命令适合于二进制和文本文件。在此示例中，我们将 zip 二进制文件分割为 50KB 的块，之后使用 `cat` 重新组合了它们，然后比较了组合后的文件和原始文件。`diff` 命令验证文件是否相同。

```
$ split --verbose -b50K zip zip.
creating file 'zip.aa'
creating file 'zip.ab'
creating file 'zip.ac'
creating file 'zip.ad'
creating file 'zip.ae'
$ cat zip.a? > zip.new
$ diff zip zip.new
$                    <== 无输出 = 无差别
```

我唯一要提醒的一点的是，如果你经常使用 `split` 并使用默认命名，那么某些文件块可能会覆盖其他的文件块，甚至会比你预期的更多，因为有些是更早之前分割的。

---

via: <https://www.networkworld.com/article/3489256/breaking-linux-files-into-pieces-with-the-split-command.html>

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

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


中国 GPL 诉讼第一案：关于 GPL 问题的探讨

# 中国 GPL 诉讼第一案：关于 GPL 问题的探讨

2019 年 11 月初，数字天堂（北京）网络技术有限公司（下称：数字天堂）诉柚子（北京）科技有限公司、柚子（北京）移动技术有限公司（下称：两柚子）侵犯计算机软件著作权纠纷案，由北京高级人民法院二审作出终审判决。笔者曾密切关注该案，终审判决生效前，囿于关联代理关系的利益冲突，不便多谈。现将本案相关若干问题梳理成文，愿与各位探讨之。

本案之所以受关注，是因为本次计算机软件著作权侵权案涉及开源软件和 GPL 许可证，本案的判决对未来开源软件诉讼实践有重要意义。本案一审法院对 GPL 相关条款作了阐述，二审法院回避了 GPL 问题。本文，笔者基于本案事实和法院判决做些思考，分享给大家讨论。本文将仅对涉及开源软件及 GPL 许可证的内容进行论述，其他法律问题不作探讨。

### 案情简介

为节省篇幅，以下对案情进行摘要和总结，详细案情可见[一审链接](https://mp.weixin.qq.com/s/SQGKVDimdwfK1bzKF3RrCA)和[二审链接](https://mp.weixin.qq.com/s/7EIUcrMg3vrJ1owYe01jnQ)。

经过一审和二审对事实的调查和确认，两柚子认可：

1. 数字天堂是 HBuilder 软件的著作权人；
2. 数字天堂拥有 HBuilder 软件中的代码输入法功能插件、真机运行功能插件、边改边看功能插件源代码著作权；
3. 两柚子的 APICloud 软件中对应插件源代码部分与涉案的三个插件具有同一性。

基于此，针对本著作权侵权控诉，两柚子抗辩理由只有 GPL 开源许可协议这一个突破口。而二审中对涉案代码量、侵权产品数量的认定，以及基于此对赔偿额的认定，只是量的维度问题。

### 开源许可证是法律文件

一审法院虽未明确 GPL 许可证的法律效力，但在论述涉案三个插件是否受 GPL 协议限制时，默认了 GPL 许可证具有法律约束力。这一点虽然是意料之中，但毕竟开源理念和大部分开源协议来源于国外，且应用于开源社区特定人群，这一认定给未来涉及开源软件的诉讼消除了部分不确定性。为了强调协议内容，下文涉及 GPL 许可证的除特指许可证本身外，都以 GPL 协议指代。

法院虽然默认了 GPL 协议具有约束力，即类似于协议或合同的法律效果，但并未进一步将 GPL 协议条款基于我国著作权法进行解释。社区内关于 GPL 协议的解释，特别是关于 GPL 传染性的解释是基于美国版权法，其能否为国内法院认可，依然存在不确定性。

随着开源理念的深入以及开源软件在世界范围内的普及，本案作为中国 GPL 第一案，对未来开源软件相关的诉讼意义重大。稍有遗憾的是，两审法院并未就开源软件以及 GPL 协议的关键问题进行阐述。当然，也不可能期待 GPL 问题通过一次诉讼案件完全解决，未来还需要更多的法律、学术、技术等人士贡献智慧。

### 关于一审认定的思考

既然法院确认了 GPL 协议的法律约束力，那么对 GPL 协议的解释要么采取社区通说解释，要么基于我国著作权法作独立解释。否则很容易出现矛盾或模糊，以至于增加企业开源实践中的法律不确定性。

关于 GPL 协议约束力范围（传染性），一审法院以涉案的三个插件可以独立运行，分别存放在三个独立的文件夹中且三个独立文件夹中无 GPL 许可证，**据此认为涉案三个插件不属于 GPL 协议中所指应被开源的衍生产品或修改版本**。

GPL 许可证中有关的原文如下：

>
> The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".)——[GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.html)
>
>
>

>
> To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
>
>
> A “covered work” means either the unmodified Program or a work based on the Program.——[GPL 2.0](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
>
>
>

结合 GPL 协议条款和 GNU 官网对于 GPL 传染性的解释，一审法院这一认定是值得商榷的，就像你不能认为总部在西城的 A 公司与其在昌平拥有独立办公场所的分公司 B 是完全独立的，这需要从 A 和 B 之间的财务、人事、业务等是否独立为基础判断。

同理，GPL 模块 A 与模块 B 之间是否独立，绝对不能以A和B是否位于独立的文件夹中来判断，还是需要从 A 和 B 之间的功能关系、通信关系、调用关系、依赖关系等来判断。

插件相对于主程序是否独立，需要看：

1. 插件的使命，是否为该主程序而存在；
2. 插件与主程序的交互方式，如管道、队列、函数调用；
3. <ruby> 交换消息的密切性 <rp>  （ </rp> <rt>  intimate communication </rt> <rp>  ） </rp></ruby>；
4. 是否有例外声明等。

一审法院在确定赔偿额的时候又一次指出三个涉案插件是三个独立软件作品。一审法院从审判认定到赔偿衡量是一致的。这里，两柚子并没有就涉案三个插件的独立性进行抗辩，而这一点对 GPL 是否构成传染非常关键，在一审中被告代理律师对 GPL 许可证条款的理解也存在局限。

### 关于二审认定的思考

首先，二审中两柚子再次提出司法鉴定来否定涉案三个插件独立性，可能是准备利用GPL传染性中关于独立作品的认定来抗辩。不过，法院认为二审诉讼中再次提出第三次鉴定申请，有违司法程序公正和司法程序效率，即二审法院基于程序公正的角度考量不予准许。同时，二审法院认为两柚子提出的新的司法鉴定申请内容与本案待证事实之间无直接关联性，这一点是值得商榷的，因为 GPL 中作品是否独立直接影响作品是否受GPL约束，进而直接影响本案关于侵权的认定。二审法院的否决理由，直接回避了可能对 GPL 传染性问题的讨论。

其次，二审法院认定数字天堂现有证据不足以证明涉案三个插件可以独立于 HBuilder 开发工具软件中的其他程序独立运行，但针对不独立的插件却没有进一步讨论这种不独立是否能够进行 GPL 开源抗辩。也就是说，一审法院基于作品的独立认定 GPL 抗辩无效，二审法院采取了一审对 GPL 抗辩的意见，但却否定了作品的独立性这一前提。

是否为独立作品的认定直接决定作品是否属于<ruby> 衍生作品 <rp>  （ </rp> <rt>  derivative work </rt> <rp>  ） </rp></ruby>或<ruby> 修改作品 <rp>  （ </rp> <rt>  modified version </rt> <rp>  ） </rp></ruby>，进而直接影响是否受 GPL 约束。

当然，我们可以这样解读二审法院对于作品独立的认定，即 GPL 许可证里所说的作品的独立性，和一审、二审法院判决赔偿额对插件独立的认定是不同维度/层次，这是说的通的。但仔细阅读一审判决可知，**法院在否决 GPL 抗辩中和赔偿额判定中对独立的认定是一致的，二审认可了一审对 GPL 抗辩部分的认定，却否决了赔偿额中对独立作品的认定，本身前后有矛盾嫌疑**。

笔者认为，如果按照上述：GPL 传染性中独立性判定和对侵权作品数量中独立性判定是不同维度的独立性判定的假设，至少二审中需要重新认定 GPL 传染性的问题，从而将两个维度的独立性认定区分开来。

### 关于两柚子诉求理由的思考

两柚子在二审中再次申请司法鉴定：

1. 涉案三个插件是否可以脱离 Eclipse 主体软件在 Windows 环境中独立运行；
2. 将涉案三个插件源代码编译为插件以验证插件能否在 Eclipse 主体软件中独立运行；
3. 任意删除 Hbuilder 软件目录下的一个或多个以“org．eclipse”、“org．apache”、“com．aptana”为前缀的文件或目录 JAR 文件以验证涉案三个插件能否正常运行……

关于这三个补充鉴定事项，首先，笔者认为两柚子或者其律师在开源上做足了工作，但其中依然存在问题。首先，插件独立于 Eclipse 主程序，并不一定需要插件可以脱离 Eclipse 主程序在 Windows 中独立运行。插件的独立性在于：插件有明确的功能，可用于特定的主程序，但不依赖于特定的主程序。最后，主程序脱离插件，应当且必须可以独立运行，并且不损失主程序本身的所有功能。

### 再看诉讼本身

基于以上认识，我们再回头看看案件本身。首先说明，因本案需要进行多处技术鉴定，笔者无法也没有精力一一取证，仅仅基于几个假设，再捋一下 GPL 相关的问题。笔者认为，关于本案 GPL 传染性的认定需要从 3 个方面来看：

1. Eclipse 主程本身；
2. 基于 Eclipse 主程序的 GPL 插件；
3. 涉案插件与主程序，以及涉案插件与上述 GPL 插件的关系。

为方便读者理解，引用数字天堂代理律所对一审结果评述的一张图。

#### （1）从 Eclipse 主程序看

APICloud 和 HBuilder 都是基于主程序 Eclipse 平台，包含第三方开源插件+各自自研插件组成的集成开发环境 IDE。

首先，主程序 Eclipse 是采用 EPL（Eclipse Public License）许可证公开，EPL 与 GPL 不兼容。即便是 2017 年 8 月发布的 [EPL-2.0](https://www.eclipse.org/legal/epl-2.0) 版本虽然添加了次级许可证选项，但其与 GPL 依然是不兼容的。因此，HBuilder 作为下游产品，其[对 Eclipse 的包装分发不能变更 Eclipse 许可证](https://www.eclipse.org/legal/epl-2.0/faq.php)。

其次，针对插件来说，无非是拓展 Eclipse 某一特定的功能，任何非 Eclipse 本身的第三方插件，可以说对于 Eclipse 主程序来说都是非必须的。其第三方公司开发的 Eclipse 主程序的插件，按照 EPL 传染性的规定，一般不视为 EPL 的衍生作品，不受 EPL 约束。

最后，需要强调的是 EPL 虽然是弱 Copyleft 许可证，但其依然是类似于 GPL 的具有“传染性”的许可证，其在给予用户更大使用方便的同时，对自身软件的 Copyleft 保护依然很强。因此，下游软件开发者在处理 EPL 软件和 GPL 软件时，需要认真对待它们的兼容性问题。

#### （2）从 Aptana 插件看

Aptana 在 2006 年推出时，以 EPL 1.0 发布，并于 2017 年 9 月 21 日修改为 GPL3.0 和 APL（Aptana Public License ）双许可。APL 不是开源/自由软件许可证，可以认为是商业许可，但对于非分发的内部使用是免费的。

Aptana 作为主程序 Eclipse 的插件，由于 EPL 和 GPL 不兼容，Aptana 中的 GPL 插件要和以 EPL 许可的 Eclipse 主程序连接，必须在 GPL 许可证里作例外声明。毫无疑问，笔者在 Aptana 官网找到了例外声明，即关于独立作品的 GPL 传染性例外声明，以及[聚合程序的 GPL 传染性例外声明](http://www.aptana.com/legal/gpl.html)。部分内容如下：

>
> GPL Section 7 Exception
>
>
> ……which are conveyed to you by Appcelerator, Inc. and licensed under one or more of the licenses identified in the Excepted License List below (each an "Excepted License"), as long as:
>
>
> 1. you obey the GPL in all respects for the Program and the modified version, except for Excepted Works which are identifiable sections of the modified version, which are not derived from the Program, and which can reasonably be considered independent and separate works in themselves,
> 2. all Excepted Works which are identifiable sections of the modified version, which are not derived from the Program, and which can reasonably be considered independent and separate works in themselves,
> 3. are distributed subject to the Excepted License under which they were originally licensed, and
> 4. are not themselves modified from the form in which they are conveyed to you by Appcelerator, and
> 5. the object code or executable form of those sections are accompanied by the complete corresponding machine-readable source code for those sections, on the same medium as the corresponding object code or executable forms of those sections, and are licensed under the applicable Excepted License as the corresponding object code or executable forms of those sections, and
> 6. any works which are aggregated with the Program, or with a modified version on a volume of a storage or distribution medium in accordance with the GPL, are aggregates (as defined in Section 5 of the GPL) which can reasonably be considered independent and separate works in themselves and which are not modified versions of either the Program, a modified version, or an Excepted Work.
>
>
> If the above conditions are not met, then the Program may only be copied, modified, distributed or used under the terms and conditions of the GPL or another valid licensing option from Appcelerator, Inc. Terms used but not defined in the foregoing paragraph have the meanings given in the GPL
>
>
>

从以上 GPL 例外中可以看出，Aptana 只是部分限定了“衍生作品”解释，也就是运行采用 GPL 许可证的 Aptana 与像 Eclipse 这样独立的程序交互不会发生传染，仅此而已。而如果修改 Aptana，将其他程序并入 Aptana Studio，或者将 Aptana 与其他程序进行整合的作品依然受到 GPL 协议约束。简单的说，加入 GPL 例外的 GPL 程序依然是 GPL 程序，这一点必须强调。关于这一点，[Aptana 官网还专门有问题解答](http://www.aptana.com/legal.html)：

> **Can I add EPL'd plugins to Aptana Studio package and redistribute it?**
> No. You can only redistribute the unmodified binary versions of the EPL'd plugins that are part of Aptana Studio when distributing any of the GPL'd code. Adding any files to Aptana Studio package creates a derivative work, and since all derivative works need to be made GPL'd, you will not be able to add EPL'd (or any other license) plugins without contacting us for a commercial license.
>
>
> **What if I want to make changes to some of Aptana Studio's EPL'd plugins?**
> You are free to make changes to any of Aptana Studio EPL'd code under the terms of the EPL. To get those redistributed as part of Aptana Studio, we encourage you to contribute those back to Aptana so that we may evaluate your changes for inclusion back into the product.
>
>
> **Can I take unmodified Aptana Studio binaries and combine them with an Eclipse distribution?**
> No. Combining our GPL'd licensed code with any other product requires that the entire product be GPL'd, and therefore you cannot include any Eclipse distribution.
>
>
>

数字天堂认为，其 HBuilder 是包含 Eclipse 平台框架和众多插件的聚合体软件包，但其基于 Eclipse 开发且打包了 Aptana 中的 GPL 插件。从 GPL 协议对独立程序和聚合程序的规定来看，HBuilder 不被感染很难成立。一旦这种潜在传染可能性成立，数字天堂的 HBuilder 发行版就不满足合规性，其内部 EPL 和 GPL 软件不兼容。直白的说，就是整个发行版都可能受到 GPL 的约束。同时，这对于 Eclipse 是不可接受的，哪怕 EPL 是弱 Copyleft 许可证。这些问题，多是对 EPL 和 GPL 的 Copyleft 性质认识不到位导致。

#### （3）涉案插件与主程序及 Aptana 插件的关系

其实，以上两步分析一旦得出受 GPL 约束的结论，就不需要下面的分析了。为了完整，同时供未来类似案例参考，简单介绍。

进一步分析 Aptana 与数字天堂的涉案三个插件之间的关系，若涉案三个插件与 Aptana 有调用、通信、依赖关系，那么涉案三个插件必然会被 GPL 传染，也即是受 GPL 约束。

从以上三步的分析可见，**在 GPL 传染性判断时，是否为独立作品是非常关键的。**这也是我在前面法院判决部分要强调一审法院对独立的认定虽未必符合 GPL 本身解释，但至少前后一致。而二审法院对作品独立的认定甚至前后矛盾。

当然，笔者没太多精力去调查技术细节，点到为止，有兴趣的读者可以进行深入研究。

以上分析，是基于 Eclipse 作为中立主程序（即 Eclipse 主程序著作权人非诉讼参与人），GPL 插件与非 GPL 插件判定的情况，换一种场景以上判断完全或者大部分不成立。关于开源软件和 GPL 的问题还有很多需要注意的，限于篇幅不再进一步说明，对本案或对开源感兴趣的朋友可以找我单独讨论。

*付钦伟，集慧智佳高级咨询师、专利代理人，擅长专利分析布局、FTO 调查与风险应对、专利信息应用、开源软件风险与合规指导。*


帮助你排序文本文件的 Awk 命令行或脚本

Summary: Awk 是一个强大的工具，可以执行某些可能由其它常见实用程序（包括 sort）来完成的任务。

@wxy 翻译能不能走点心

# 帮助你排序文本文件的 Awk 命令行或脚本

>
> Awk 是一个强大的工具，可以执行某些可能由其它常见实用程序（包括 `sort`）来完成的任务。
>
>
>

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

Awk 是个普遍存在的 Unix 命令，用于扫描和处理包含可预测模式的文本。但是，由于它具有函数功能，因此也可以合理地称之为编程语言。

令人困惑的是，有不止一个 awk。（或者，如果你认为只有一个，那么其它几个就是克隆。）有 `awk`（由Aho、Weinberger 和 Kernighan 编写的原始程序），然后有 `nawk` 、`mawk` 和 GNU 版本的 `gawk`。GNU 版本的 awk 是该实用程序的一个高度可移植的自由软件版本，具有几个独特的功能，因此本文是关于 GNU awk 的。

虽然它的正式名称是 `gawk`，但在 GNU+Linux 系统上，它的别名是 `awk`，并用作该命令的默认版本。 在其他没有带有 GNU awk 的系统上，你必须先安装它并将其称为 `gawk`，而不是 `awk`。本文互换使用术语 `awk` 和 `gawk`。

`awk` 既是命令语言又是编程语言，这使其成为一个强大的工具，可以处理原本留给 `sort`、`cut`、`uniq` 和其他常见实用程序的任务。幸运的是，开源中有很多冗余空间，因此，如果你面临是否使用 `awk` 的问题，答案可能是肯定的“随便”。

`awk` 的灵活之美在于，如果你已经确定使用 `awk` 来完成一项任务，那么无论接下来发生什么，你都可以继续使用 `awk`。这包括对数据排序而不是按交付给你的顺序的永恒需求。

### 样本数据集

在探索 `awk` 的排序方法之前，请生成要使用的样本数据集。保持简单，这样你就不会为极端情况和意想不到的复杂性所困扰。这是本文使用的样本集：

```
Aptenodytes;forsteri;Miller,JF;1778;Emperor
Pygoscelis;papua;Wagler;1832;Gentoo
Eudyptula;minor;Bonaparte;1867;Little Blue
Spheniscus;demersus;Brisson;1760;African
Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Torvaldis;linux;Ewing,L;1996;Tux
```

这是一个很小的数据集，但它提供了多种数据类型：

* 属名和种名，彼此相关但又是分开的
* 姓，有时是以逗号开头的首字母缩写
* 代表日期的整数
* 任意术语
* 所有字段均以分号分隔

根据你的教育背景，你可能会认为这是二维数组或表格，或者只是行分隔的数据集合。你如何看待它只是你的问题，而 `awk` 只认识文本。由你决定告诉 `awk` 你想如何解析它。

### 只想排序

如果你只想按特定的可定义字段（例如电子表格中的“单元格”）对文本数据集进行排序，则可以使用 [sort 命令](https://opensource.com/article/19/10/get-sorted-sort)。

### 字段和记录

无论输入的格式如何，都必须在其中找到模式才可以专注于对你重要的数据部分。在此示例中，数据由两个因素定界：行和字段。每行都代表一个新的*记录*，就如你在电子表格或数据库转储中看到的一样。在每一行中，都有用分号（`;`）分隔的不同的*字段*（将其视为电子表格中的单元格）。

`awk` 一次只处理一条记录，因此，当你在构造发给 `awk` 的这指令时，你可以只关注一行记录。写下你想对一行数据执行的操作，然后在下一行进行测试（无论是心理上还是用 `awk` 进行测试），然后再进行其它的一些测试。最后，你要对你的 `awk` 脚本要处理的数据做好假设，以便可以按你要的数据结构提供给你数据。

在这个例子中，很容易看到每个字段都用分号隔开。为简单起见，假设你要按每行的第一字段对列表进行排序。

在进行排序之前，你必须能够让 `awk` 只关注在每行的第一个字段上，因此这是第一步。终端中 awk 命令的语法为 `awk`，后跟相关选项，最后是要处理的数据文件。

```
$ awk --field-separator=";" '{print $1;}' penguins.list
Aptenodytes
Pygoscelis
Eudyptula
Spheniscus
Megadyptes
Eudyptes
Torvaldis
```

因为字段分隔符是对 Bash shell 具有特殊含义的字符，所以必须将分号括在引号中或在其前面加上反斜杠。此命令仅用于证明你可以专注于特定字段。你可以使用另一个字段的编号尝试相同的命令，以查看数据的另一个“列”的内容：

```
$ awk --field-separator=";" '{print $3;}' penguins.list
Miller,JF
Wagler
Bonaparte
Brisson
Milne-Edwards
Viellot
Ewing,L
```

我们尚未进行任何排序，但这是良好的基础。

### 脚本编程

`awk` 不仅仅是命令，它是一种具有索引、数组和函数的编程语言。这很重要，因为这意味着你可以获取要排序的字段列表，将列表存储在内存中，进行处理，然后打印结果数据。对于诸如此类的一系列复杂操作，在文本文件中进行操作会更容易，因此请创建一个名为 `sort.awk` 的新文件并输入以下文本：

```
#!/bin/gawk -f

BEGIN {
        FS=";";
}
```

这会将该文件建立为 `awk` 脚本，该脚本中包含执行的行。

`BEGIN` 语句是 `awk` 提供的特殊设置功能，用于只需要执行一次的任务。定义内置变量 `FS`，它代表<ruby> 字段分隔符 <rt>  field separator </rt></ruby>，并且与你在 `awk` 命令中使用 `--field-separator` 设置的值相同，它只需执行一次，因此它包含在 `BEGIN` 语句中。

#### awk 中的数组

你已经知道如何通过使用 `$` 符号和字段编号来收集特定字段的值，但是在这种情况下，你需要将其存储在数组中而不是将其打印到终端。这是通过 `awk` 数组完成的。`awk` 数组的重要之处在于它包含键和值。 想象一下有关本文的内容；它看起来像这样：`author:"seth",title:"How to sort with awk",length:1200`。诸如作者、标题和长度之类的元素是键，跟着的内容为值。

在排序的上下文中这样做的好处是，你可以将任何字段分配为键，将任何记录分配为值，然后使用内置的 `awk` 函数 `asorti()`（按索引排序）按键进行排序。现在，随便假设你*只*想按第二个字段排序。

*没有*被特殊关键字 `BEGIN` 或 `END` 引起来的 `awk` 语句是在每个记录都要执行的循环。这是脚本的一部分，该脚本扫描数据中的模式并进行相应的处理。每次 `awk` 将注意力转移到一条记录上时，都会执行 `{}` 中的语句（除非以 `BEGIN` 或 `END` 开头）。

要将键和值添加到数组，请创建一个包含数组的变量（在本示例脚本中，我将其称为 `ARRAY`，虽然不是很原汁原味，但很清楚），然后在方括号中分配给它键，用等号（`=`）连接值。

```
{   # dump each field into an array
    ARRAY[$2] = $R;
}
```

在此语句中，第二个字段的内容（`$2`）用作关键字，而当前记录（`$R`）用作值。

### asorti() 函数

除了数组之外，`awk` 还具有一些基本函数，你可以将它们用作常见任务的快速简便的解决方案。GNU awk中引入的函数之一 `asorti()` 提供了按键（*索引*）或值对数组进行排序的功能。

你只能在对数组进行填充后对其进行排序，这意味着此操作不能对每个新记录都触发，而只能在脚本的最后阶段进行。为此，`awk` 提供了特殊的 `END` 关键字。与 `BEGIN` 相反，`END` 语句仅在扫描了所有记录之后才触发一次。

将这些添加到你的脚本：

```
END {
    asorti(ARRAY,SARRAY);
    # get length
    j = length(SARRAY);

    for (i = 1; i <= j; i++) {
        printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
    }
}
```

`asorti()` 函数获取 `ARRAY` 的内容，按索引对其进行排序，然后将结果放入名为 `SARRAY` 的新数组（我在本文中发明的任意名称，表示“排序的 ARRAY”）。

接下来，将变量 `j`（另一个任意名称）分配给 `length()` 函数的结果，该函数计算 `SARRAY` 中的项数。

最后，使用 `for` 循环使用 `printf()` 函数遍历 `SARRAY` 中的每一项，以打印每个键，然后在 `ARRAY` 中打印该键的相应值。

### 运行该脚本

要运行你的 `awk` 脚本，先使其可执行：

```
$ chmod +x sorter.awk
```

然后针对 `penguin.list` 示例数据运行它：

```
$ ./sorter.awk penguins.list
antipodes Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
chrysocome Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
demersus Spheniscus;demersus;Brisson;1760;African
forsteri Aptenodytes;forsteri;Miller,JF;1778;Emperor
linux Torvaldis;linux;Ewing,L;1996;Tux
minor Eudyptula;minor;Bonaparte;1867;Little Blue
papua Pygoscelis;papua;Wagler;1832;Gentoo
```

如你所见，数据按第二个字段排序。

这有点限制。最好可以在运行时灵活选择要用作排序键的字段，以便可以在任何数据集上使用此脚本并获得有意义的结果。

### 添加命令选项

你可以通过在脚本中使用字面值 `var` 将命令变量添加到 `awk` 脚本中。更改脚本，以使迭代子句在创建数组时使用 `var`：

```
{ # dump each field into an array
    ARRAY[$var] = $R;
}
```

尝试运行该脚本，以便在执行脚本时使用 `-v var` 选项将其按第三字段排序：

```
$ ./sorter.awk -v var=3 penguins.list
Bonaparte Eudyptula;minor;Bonaparte;1867;Little Blue
Brisson Spheniscus;demersus;Brisson;1760;African
Ewing,L Torvaldis;linux;Ewing,L;1996;Tux
Miller,JF Aptenodytes;forsteri;Miller,JF;1778;Emperor
Milne-Edwards Megadyptes;antipodes;Milne-Edwards;1880;Yellow-eyed
Viellot Eudyptes;chrysocome;Viellot;1816;Sothern Rockhopper
Wagler Pygoscelis;papua;Wagler;1832;Gentoo
```

### 修正

本文演示了如何在纯 GNU awk 中对数据进行排序。你可以对脚本进行改进，以便对你有用，花一些时间在`gawk` 的手册页上研究 [awk 函数](https://www.gnu.org/software/gawk/manual/html_node/Built_002din.html#Built_002din)并自定义脚本以获得更好的输出。

这是到目前为止的完整脚本：

```
#!/usr/bin/awk -f
# GPLv3 appears here
# usage: ./sorter.awk -v var=NUM FILE

BEGIN { FS=";"; }

{ # dump each field into an array
    ARRAY[$var] = $R;
}

END {
    asorti(ARRAY,SARRAY);
    # get length
    j = length(SARRAY);

    for (i = 1; i <= j; i++) {
        printf("%s %s\n", SARRAY[i],ARRAY[SARRAY[i]])
    }
}
```

---

via: <https://opensource.com/article/19/11/how-sort-awk>

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

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


专访徐亮：解密 UCloud 的工程能力

# 专访徐亮：解密 UCloud 的工程能力

似乎每一家互联网公司都有一种属于自己的气质，我接触过很多知名互联网公司的技术专家，其中有一家公司技术专家给了非常深的印象，那就是 UCloud。在和 UCloud 技术专家的沟通中，我深深感受到这是一支极为自信、动手能力很强的技术团队。

近期，我在UCloud上海办公室采访了 UCloud 虚拟网络负责人徐亮，就如同我采访过的很多一线技术领军人物一样，徐亮给我带来的直接印象就是执着、朴实和认真。

*说到自己擅长的网络技术领域，徐亮神采飞扬*

在和他的谈话中，我听到了不少 UCloud 有趣的研发故事，让我对 UCloud 技术团队的动手能力有了更深的认识。尤其是， 当UCloud 所倡行的**“客户为先”、“客户的需求就是我们的下一个产品”**等理念从一个专注于前沿技术的技术领军人物的谈吐中汩汩冒出时，印象更深刻了。

### 转化：实验室技术能力 ➡➡➡ 生产能力

我为什么认为 UCloud 的技术团队是一支动手能力极强，这得从他们的 25G 智能网卡项目说起。

众所周知，如何将实验室形成的技术能力转化成生产能力，需要很好的工程能力，25G 智能网卡从实验室到生产环境恰恰体现了这样的工程能力。

“去年我们将 25G 智能网卡产品投入到生产环境，实际上，UCloud 从 2016 年就开始跟踪这项技术。这期间我们测试了很多厂商的智能网卡，有的智能网卡的性能相当不错。但是阻碍我们将其投入生产环境的一个重要原因是，它和公有云所要求的热迁移的能力不兼容。所以，虽然这些智能网卡的性能很好，但是没有办法应用到公有云环境。”徐亮介绍道。

其实，业界一些公有云厂商很早就在借助这些智能网卡做加速，但是在处理热迁移的时候做不到用户的无感迁移，必须要用户手动修改虚机里面网络的配置。这虽然能够达到目的，但是对用户并不友好。对此，UCloud 秉持一向的态度：**“我们一定要做到用户没有额外的负担，这样对用户来说才是最佳的方案，才是成熟的、用户友好的方案。”**

据徐亮回忆，情况在 2017 年底出现了一个转机。彼时，Linux 内核社区开始讨论智能网卡如何能够无感的支持热迁移，UCloud 技术团队第一时间进行了深入的技术追踪和研究。从社区开始讨论和开发，最后到 2018 年 5 月份时该功能趋于稳定，才被接受到 Linux 的内核主线里。

“在发现该功能已经基本成熟后，我们马上就把这个补丁应用回 UCloud 的定制内核当中，跟智能网卡厂商一起研究，很快就在实验室完成了该产品。”徐亮接着谈到，“然后我们就开始在线上做公测。这个时候就非常体现我们的工程能力。”

在徐亮的团队将智能网卡投入生产环境时，虽然也发生了一些问题，但是就算在连固件都升级过两次的情况下、对用户的业务并没有产生太大的影响，我想这就是 UCloud 技术团队的工程能力一个重要体现——**“我的固件都升级了，而用户业务不受影响。”**

### 驱动：客户为先 ➡➡➡ 工程能力

在我采访的 UCloud 技术人员中，徐亮并不是第一个提到“客户为先”、“客户的需求就是我们下一个产品”等理念的，在与 UCloud 技术副总裁[杨镭](/article-10744-1.html)、私有云和容器产品线负责人[叶理灯](/article-10971-1.html)等人的采访沟通中他们都曾提及这一贯彻于 UCloud 所有技术、产品研发中的理念。他们对于“客户为先”以及在产品的研发、技术专研中的践行，让我深信他们从骨子里认可这样一个价值观。可以说，“用户为先”的理念驱动着其工程能力的形成。

谈到他们的经典网络升级至 VPC 2.0 项目，也许你会理解我说的。

#### 以“客户为先”为出发点

据我了解，**UCloud 应该是全球唯一一家把经典网络升级到 VPC 2.0 网络的公有云厂商。**在我和多位 UCloud 技术人员的接触中，这个项目被多次提及，它的实施可谓是历经周折，遇到的困难很多。

“**我们的出发点是‘客户是不是有这个诉求？这件事情对客户来说是不是有好处？’如果是的话，那我们为什么不做呢？**“。当问及项目出发点时，徐亮谈到。显然，如果能够透明的将经典网络升级至 VPC 网络，对于用户来说无疑是有诉求和好处，不需要自行迁移或是同时维护两个架构。但，UCloud 一开始低估了这个项目的难度。

徐亮说，“为什么这么难？因为一个默认的前提条件出现了变化——我们以前假设用户的 IP 是唯一的，这不光体现在网络产品上，还包括数据库产品、存储产品等，都会假设用户的 IP 是唯一的——在之前的经典网络时，该前提条件似乎是显而易见的。但在我们要升级到 VPC 2.0 时，我们突然发现这个 IP 变得不再唯一，由于不同的租户网络是完全隔离的，IP 完全是可以重复的。”

因此，这个项目不再是一个纯粹的网络项目，意味着 UCloud 平台上的所有产品都需要升级，都要支持这个重要变化，所以在工程上存在非常多的协调工作。这是一件非常、非常难的事，是一个涉及到全公司协调的能力。

#### “客户为先”驱动产品创新

VPC 2.0 项目过程中，徐亮团队还推出了许多创新产品，如 IPv6 地址转换。

公有云里面会有一些公共服务，比如说，像镜像服务、DNS 服务等，所有的客户都可能会访问这些公共服务，而有些客户的 IP 是彼此重叠的，只是 VPC 不同而已。传统上都是采用 NAT 的方式去做的，因为地址是相同的，肯定需要通过 NAT 翻译成不同的地址，然后再去访问公共服务。

但是，NAT 方式有两个问题，一个是公共服务在获取原地址时变得很复杂，它要用 TOA 或其它手段才能够提取出原地址。另外是这是一个有状态的网关，可扩展性会存在一定的问题，有状态的部分容易成为瓶颈，维护状态代价很大。

UCloud 在这方面做了一个创新——徐亮的团队把用户的地址和用户的 VPC 这两个部分信息组合起来，形成一个 128 位的 IPv6 地址，把用户的 IPv4 的请求无状态地转换成了 IPv6 请求，然后发送给这些公共服务。徐亮说，“**我们这个无状态转换的思路，是非常创新的。对用户来说，得到的性能很好，同时不需要为此额外增加成本。**”

就这样在“用户为先”的驱动下，UCloud 技术团队一点一点的完成了经典网络到 VPC 网络的升级，历时三年。

**“我们的初衷就是从客户为先的角度出发，用我们的技术给客户带去价值，在这个基础上我们就认为这件事情值得就去做。”**

### 自省：关于工程能力的三句话

关于对工程能力的理解，徐亮谈到了几句话： **“先于客户发现问题”、 “先扛住再优化”、“这件事情能不能做到24小时止血”、“一周之内能不能拿出一个中期解决方案？**”… 让我印象深刻，这也是 UCloud 技术团队的实践路线。

>
> “先于客户发现问题”
>
>
>

据徐亮介绍，其团队做可编程交换机的过程中遇到一个非常隐晦的交换机芯片编译器的 BUG，它会发生哈希冲突，从而导致行为不可预期，但是这个问题在实验室是没办法复现出来。历时一个月时间，UCloud 通过在工程上引入全量测试的环节，提前发现了问题。

这件事情之后，徐亮的团队开发了一个新系统，对所有用户虚机点对点通信的信息进行统计，在做变更时就会针对通信过的场景做全量验证。通过这种方式来发现一些因为软件架构变化导致的问题，能够“**先于客户发现问题**”，在对客户业务没有产生影响的情况下去解决它。

>
> “先扛住再优化”
>
>
>

发现问题第一时间不是去分析根本原因是什么，而要考虑怎样降低对客户的影响，这就是 UCloud 团队常说的“**先扛住再优化**”。比如说，智能网卡出现故障了，不会先修复智能网卡，肯定是先把用户的业务切走，让用户的业务正常，然后再想办法解决智能网卡的问题。

>
> “这件事情能不能做 24 小时止血”
>
>
>

一旦发生故障就会做复盘，这时候UCloud技术团队最常说的一句话就是“**这件事情能不能做24小时止血**”。故障对客户是有影响的，我们要在24小时之内先推出一个方案，这个的方案能够让客户降低损失。不光是出现问题的客户，甚至是其他没有出现问题的客户，我们也要在24小时之内拿出一个方案，让这些问题不会影响到客户。

然后，再问‘一周之内能不能拿出一个中期解决方案？’，最后再考虑长期解决方案，长期方案有的时候就真的很长，比如说体系架构设计的不合理、需要进行重构。

### 结语

在和包括徐亮在内的多位 UCloud 技术领头人在深入沟通后，深切感受到这是一支极为自信、工程能力极强的技术团队，他们敢于尝试新技术，同时其工程能力能在给用户提高价值的同时，保证不出现问题，我相信这是 UCloud 技术团队自信的底气。

>
>
>
>
> “穿山甲专访”栏目是 Linux 中国社区推出的面向开源界、互联网技术圈的重要领军人物的系列采访，将为大家介绍中国开源领域中一些积极推动开源，谙熟开源思想的技术人，并辨析其思考、挖掘其动因，揭示其背后所发生的事情，为关注开源、有志于开源的企业和技术人标出一条路径。
>
>
> 取名为“穿山甲”寓意有二：取穿山甲挖掘、深入之意来象征技术进步和表征技术领袖的作用；穿山甲是珍稀保护动物，宣传公益。
>
>
>


怎样用 Bash 编程：逻辑操作符和 shell 扩展

Summary: 学习逻辑操作符和 shell 扩展，本文是三篇 Bash 编程系列的第二篇。

学习逻辑操作符和 shell 扩展，本文是三篇 Bash 编程系列的第二篇。

# 怎样用 Bash 编程：逻辑操作符和 shell 扩展

>
> 学习逻辑操作符和 shell 扩展，本文是三篇 Bash 编程系列的第二篇。
>
>
>

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

Bash 是一种强大的编程语言，完美契合命令行和 shell 脚本。本系列（三篇文章，基于我的 [三集 Linux 自学课程](http://www.both.org/?page_id=1183)）讲解如何在 CLI 使用 Bash 编程。

[第一篇文章](/article-11552-1.html) 讲解了 Bash 的一些简单命令行操作，包括如何使用变量和控制操作符。第二篇文章探讨文件、字符串、数字等类型和各种各样在执行流中提供控制逻辑的的逻辑运算符，还有 Bash 中的各类 shell 扩展。本系列第三篇也是最后一篇文章，将会探索能重复执行操作的 `for` 、`while` 和 `until` 循环。

逻辑操作符是程序中进行判断的根本要素，也是执行不同的语句组合的依据。有时这也被称为流控制。

### 逻辑操作符

Bash 中有大量的用于不同条件表达式的逻辑操作符。最基本的是 `if` 控制结构，它判断一个条件，如果条件为真，就执行一些程序语句。操作符共有三类：文件、数字和非数字操作符。如果条件为真，所有的操作符返回真值（`0`），如果条件为假，返回假值（`1`）。

这些比较操作符的函数语法是，一个操作符加一个或两个参数放在中括号内，后面跟一系列程序语句，如果条件为真，程序语句执行，可能会有另一个程序语句列表，该列表在条件为假时执行：

```
if [ arg1 operator arg2 ] ; then list
或
if [ arg1 operator arg2 ] ; then list ; else list ; fi
```

像例子中那样，在比较表达式中，空格不能省略。中括号的每部分，`[` 和 `]`，是跟 `test` 命令一样的传统的 Bash 符号：

```
if test arg1 operator arg2 ; then list
```

还有一个更新的语法能提供一点点便利，一些系统管理员比较喜欢用。这种格式对于不同版本的 Bash 和一些 shell 如 ksh（Korn shell）兼容性稍差。格式如下：

```
if [[ arg1 operator arg2 ]] ; then list
```

#### 文件操作符

文件操作符是 Bash 中一系列强大的逻辑操作符。图表 1 列出了 20 多种不同的 Bash 处理文件的操作符。在我的脚本中使用频率很高。

| 操作符 | 描述 |
| --- | --- |
| `-a filename` | 如果文件存在，返回真值；文件可以为空也可以有内容，但是只要它存在，就返回真值 |
| `-b filename` | 如果文件存在且是一个块设备，如 `/dev/sda` 或 `/dev/sda1`，则返回真值 |
| `-c filename` | 如果文件存在且是一个字符设备，如 `/dev/TTY1`，则返回真值 |
| `-d filename` | 如果文件存在且是一个目录，返回真值 |
| `-e filename` | 如果文件存在，返回真值；与上面的 `-a` 相同 |
| `-f filename` | 如果文件存在且是一个一般文件，不是目录、设备文件或链接等的其他的文件，则返回 真值 |
| `-g filename` | 如果文件存在且 `SETGID` 标记被设置在其上，返回真值 |
| `-h filename` | 如果文件存在且是一个符号链接，则返回真值 |
| `-k filename` | 如果文件存在且粘滞位已设置，则返回真值 |
| `-p filename` | 如果文件存在且是一个命名的管道（FIFO），返回真值 |
| `-r filename` | 如果文件存在且有可读权限（它的可读位被设置），返回真值 |
| `-s filename` | 如果文件存在且大小大于 0，返回真值；如果一个文件存在但大小为 0，则返回假值 |
| `-t fd` | 如果文件描述符 `fd` 被打开且被关联到一个终端设备上，返回真值 |
| `-u filename` | 如果文件存在且它的 `SETUID` 位被设置，返回真值 |
| `-w filename` | 如果文件存在且有可写权限，返回真值 |
| `-x filename` | 如果文件存在且有可执行权限，返回真值 |
| `-G filename` | 如果文件存在且文件的组 ID 与当前用户相同，返回真值 |
| `-L filename` | 如果文件存在且是一个符号链接，返回真值（同 `-h`） |
| `-N filename` | 如果文件存在且从文件上一次被读取后文件被修改过，返回真值 |
| `-O filename` | 如果文件存在且你是文件的拥有者，返回真值 |
| `-S filename` | 如果文件存在且文件是套接字，返回真值 |
| `file1 -ef file2` | 如果文件 `file1` 和文件 `file2` 指向同一设备的同一 INODE 号，返回真值（即硬链接） |
| `file1 -nt file2` | 如果文件 `file1` 比 `file2` 新（根据修改日期），或 `file1` 存在而 `file2` 不存在，返回真值 |
| `file1 -ot file2` | 如果文件 `file1` 比 `file2` 旧（根据修改日期），或 `file1` 不存在而 `file2` 存在 |

*图表 1：Bash 文件操作符*

以测试一个文件存在与否来举例：

```
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] ; then echo "The file $File exists." ; else echo "The file $File does not exist." ; fi
The file TestFile1 does not exist.
[student@studentvm1 testdir]$
```

创建一个用来测试的文件，命名为 `TestFile1`。目前它不需要包含任何数据：

```
[student@studentvm1 testdir]$ touch TestFile1
```

在这个简短的 CLI 程序中，修改 `$File` 变量的值相比于在多个地方修改表示文件名的字符串的值要容易：

```
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] ; then echo "The file $File exists." ; else echo "The file $File does not exist." ; fi
The file TestFile1 exists.
[student@studentvm1 testdir]$
```

现在，运行一个测试来判断一个文件是否存在且长度不为 0（表示它包含数据）。假设你想判断三种情况：

1. 文件不存在；
2. 文件存在且为空；
3. 文件存在且包含数据。

因此，你需要一组更复杂的测试代码 — 为了测试所有的情况，使用 `if-elif-else` 结构中的 `elif` 语句：

```
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -s $File ] ; then echo "$File exists and contains data." ; fi
[student@studentvm1 testdir]$
```

在这个情况中，文件存在但不包含任何数据。向文件添加一些数据再运行一次：

```
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is file $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; fi
TestFile1 exists and contains data.
[student@studentvm1 testdir]$
```

这组语句能返回正常的结果，但是仅仅是在我们已知三种可能的情况下测试某种确切的条件。添加一段 `else` 语句，这样你就可以更精确地测试。把文件删掉，你就可以完整地测试这段新代码：

```
[student@studentvm1 testdir]$ File="TestFile1" ; rm $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
TestFile1 does not exist or is empty.
```

现在创建一个空文件用来测试：

```
[student@studentvm1 testdir]$ File="TestFile1" ; touch $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
TestFile1 does not exist or is empty.
```

向文件添加一些内容，然后再测试一次：

```
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is file $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
TestFile1 exists and contains data.
```

现在加入 `elif` 语句来辨别是文件不存在还是文件为空：

```
[student@studentvm1 testdir]$ File="TestFile1" ; touch $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; elif [ -e $File ] ; then echo "$File exists and is empty." ; else echo "$File does not exist." ; fi
TestFile1 exists and is empty.
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; elif [ -e $File ] ; then echo "$File exists and is empty." ; else echo "$File does not exist." ; fi
TestFile1 exists and contains data.
[student@studentvm1 testdir]$
```

现在你有一个可以测试这三种情况的 Bash CLI 程序，但是可能的情况是无限的。

如果你能像保存在文件中的脚本那样组织程序语句，那么即使对于更复杂的命令组合也会很容易看出它们的逻辑结构。图表 2 就是一个示例。 `if-elif-else` 结构中每一部分的程序语句的缩进让逻辑更变得清晰。

```
File="TestFile1"
echo "This is $File" > $File
if [ -s $File ]
   then
   echo "$File exists and contains data."
elif [ -e $File ]
   then
   echo "$File exists and is empty."
else
   echo "$File does not exist."
fi
```

*图表 2: 像在脚本里一样重写书写命令行程序*

对于大多数 CLI 程序来说，让这些复杂的命令变得有逻辑需要写很长的代码。虽然 CLI 可能是用 Linux 或 Bash 内置的命令，但是当 CLI 程序很长或很复杂时，创建一个保存在文件中的脚本将更有效，保存到文件中后，可以随时运行。

#### 字符串比较操作符

字符串比较操作符使我们可以对字符串中的字符按字母顺序进行比较。图表 3 列出了仅有的几个字符串比较操作符。

| 操作符 | 描述 |
| --- | --- |
| `-z string` | 如果字符串的长度为 0 ，返回真值 |
| `-n string` | 如果字符串的长度不为 0 ，返回真值 |
| `string1 == string2` 或 `string1 = string2` | 如果两个字符串相等，返回真值。处于遵从 POSIX 一致性，在测试命令中应使用一个等号 `=`。与命令 `[[` 一起使用时，会进行如上描述的模式匹配（混合命令）。 |
| `string1 != string2` | 两个字符串不相等，返回真值 |
| `string1 < string2` | 如果对 `string1` 和 `string2` 按字母顺序进行排序，`string1` 排在 `string2` 前面（即基于地区设定的对所有字母和特殊字符的排列顺序） |
| `string1 > string2` | 如果对 `string1` 和 `string2` 按字母顺序进行排序，`string1` 排在 `string2` 后面 |

*图表 3: Bash 字符串逻辑操作符*

首先，检查字符串长度。比较表达式中 `$MyVar` 两边的双引号不能省略（你仍应该在目录 `~/testdir` 下 ）。

```
[student@studentvm1 testdir]$ MyVar="" ; if [ -z "" ] ; then echo "MyVar is zero length." ; else echo "MyVar contains data" ; fi
MyVar is zero length.
[student@studentvm1 testdir]$ MyVar="Random text" ; if [ -z "" ] ; then echo "MyVar is zero length." ; else echo "MyVar contains data" ; fi
MyVar is zero length.
```

你也可以这样做：

```
[student@studentvm1 testdir]$ MyVar="Random text" ; if [ -n "$MyVar" ] ; then echo "MyVar contains data." ; else echo "MyVar is zero length" ; fi
MyVar contains data.
[student@studentvm1 testdir]$ MyVar="" ; if [ -n "$MyVar" ] ; then echo "MyVar contains data." ; else echo "MyVar is zero length" ; fi
MyVar is zero length
```

有时候你需要知道一个字符串确切的长度。这虽然不是比较，但是也与比较相关。不幸的是，计算字符串的长度没有简单的方法。有很多种方法可以计算，但是我认为使用 `expr`（求值表达式）命令是相对最简单的一种。阅读 `expr` 的手册页可以了解更多相关知识。注意表达式中你检测的字符串或变量两边的引号不要省略。

```
[student@studentvm1 testdir]$ MyVar="" ; expr length "$MyVar"
0
[student@studentvm1 testdir]$ MyVar="How long is this?" ; expr length "$MyVar"
17
[student@studentvm1 testdir]$ expr length "We can also find the length of a literal string as well as a variable."
70
```

关于比较操作符，在我们的脚本中使用了大量的检测两个字符串是否相等（例如，两个字符串是否实际上是同一个字符串）的操作。我使用的是非 POSIX 版本的比较表达式：

```
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello World" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches Var2" ; else echo "Var1 and Var2 do not match." ; fi
Var1 matches Var2
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello world" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches Var2" ; else echo "Var1 and Var2 do not match." ; fi
Var1 and Var2 do not match.
```

在你自己的脚本中去试一下这些操作符。

#### 数字比较操作符

数字操作符用于两个数字参数之间的比较。像其他类操作符一样，大部分都很容易理解。

| 操作符 | 描述 |
| --- | --- |
| `arg1 -eq arg2` | 如果 `arg1` 等于 `arg2`，返回真值 |
| `arg1 -ne arg2` | 如果 `arg1` 不等于 `arg2`，返回真值 |
| `arg1 -lt arg2` | 如果 `arg1` 小于 `arg2`，返回真值 |
| `arg1 -le arg2` | 如果 `arg1` 小于或等于 `arg2`，返回真值 |
| `arg1 -gt arg2` | 如果 `arg1` 大于 `arg2`，返回真值 |
| `arg1 -ge arg2` | 如果 `arg1` 大于或等于 `arg2`，返回真值 |

*图表 4: Bash 数字比较逻辑操作符*

来看几个简单的例子。第一个示例设置变量 `$X` 的值为 1，然后检测 `$X` 是否等于 1。第二个示例中，`$X` 被设置为 0，所以比较表达式返回结果不为真值。

```
[student@studentvm1 testdir]$ X=1 ; if [ $X -eq 1 ] ; then echo "X equals 1" ; else echo "X does not equal 1" ; fi
X equals 1
[student@studentvm1 testdir]$ X=0 ; if [ $X -eq 1 ] ; then echo "X equals 1" ; else echo "X does not equal 1" ; fi
X does not equal 1
[student@studentvm1 testdir]$
```

自己来多尝试一下其他的。

#### 杂项操作符

这些杂项操作符展示一个 shell 选项是否被设置，或一个 shell 变量是否有值，但是它不显示变量的值，只显示它是否有值。

| 操作符 | 描述 |
| --- | --- |
| `-o optname` | 如果一个 shell 选项 `optname` 是启用的（查看内建在 Bash 手册页中的 set `-o` 选项描述下面的选项列表），则返回真值 |
| `-v varname` | 如果 shell 变量 `varname` 被设置了值（被赋予了值），则返回真值 |
| `-R varname` | 如果一个 shell 变量 `varname` 被设置了值且是一个名字引用，则返回真值 |

*图表 5: 杂项 Bash 逻辑操作符*

自己来使用这些操作符实践下。

### 扩展

Bash 支持非常有用的几种类型的扩展和命令替换。根据 Bash 手册页，Bash 有七种扩展格式。本文只介绍其中五种：`~` 扩展、算术扩展、路径名称扩展、大括号扩展和命令替换。

#### 大括号扩展

大括号扩展是生成任意字符串的一种方法。（下面的例子是用特定模式的字符创建大量的文件。）大括号扩展可以用于产生任意字符串的列表，并把它们插入一个用静态字符串包围的特定位置或静态字符串的两端。这可能不太好想象，所以还是来实践一下。

首先，看一下大括号扩展的作用：

```
[student@studentvm1 testdir]$ echo {string1,string2,string3}
string1 string2 string3
```

看起来不是很有用，对吧？但是用其他方式使用它，再来看看：

```
[student@studentvm1 testdir]$ echo "Hello "{David,Jen,Rikki,Jason}.
Hello David. Hello Jen. Hello Rikki. Hello Jason.
```

这看起来貌似有点用了 — 我们可以少打很多字。现在试一下这个：

```
[student@studentvm1 testdir]$ echo b{ed,olt,ar}s
beds bolts bars
```

我可以继续举例，但是你应该已经理解了它的用处。

#### ~ 扩展

资料显示，使用最多的扩展是波浪字符（`~`）扩展。当你在命令中使用它（如 `cd ~/Documents`）时，Bash shell 把这个快捷方式展开成用户的完整的家目录。

使用这个 Bash 程序观察 `~` 扩展的作用：

```
[student@studentvm1 testdir]$ echo ~
/home/student
[student@studentvm1 testdir]$ echo ~/Documents
/home/student/Documents
[student@studentvm1 testdir]$ Var1=~/Documents ; echo $Var1 ; cd $Var1
/home/student/Documents
[student@studentvm1 Documents]$
```

#### 路径名称扩展

路径名称扩展是展开文件通配模式为匹配该模式的完整路径名称的另一种说法，匹配字符使用 `?` 和 `*`。文件通配指的是在大量操作中匹配文件名、路径和其他字符串时用特定的模式字符产生极大的灵活性。这些特定的模式字符允许匹配字符串中的一个、多个或特定字符。

* `?` — 匹配字符串中特定位置的一个任意字符
* `*` — 匹配字符串中特定位置的 0 个或多个任意字符

这个扩展用于匹配路径名称。为了弄清它的用法，请确保 `testdir` 是当前工作目录（`PWD`），先执行基本的列出清单命令 `ls`（我家目录下的内容跟你的不一样）。

```
[student@studentvm1 testdir]$ ls
chapter6  cpuHog.dos    dmesg1.txt  Documents  Music       softlink1  testdir6    Videos
chapter7  cpuHog.Linux  dmesg2.txt  Downloads  Pictures    Templates  testdir
testdir  cpuHog.mac    dmesg3.txt  file005    Public      testdir    tmp
cpuHog     Desktop       dmesg.txt   link3      random.txt  testdir1   umask.test
[student@studentvm1 testdir]$
```

现在列出以 `Do`、`testdir/Documents` 和 `testdir/Downloads` 开头的目录：

```
Documents:
Directory01  file07  file15        test02  test10  test20      testfile13  TextFiles
Directory02  file08  file16        test03  test11  testfile01  testfile14
file01       file09  file17        test04  test12  testfile04  testfile15
file02       file10  file18        test05  test13  testfile05  testfile16
file03       file11  file19        test06  test14  testfile09  testfile17
file04       file12  file20        test07  test15  testfile10  testfile18
file05       file13  Student1.txt  test08  test16  testfile11  testfile19
file06       file14  test01        test09  test18  testfile12  testfile20

Downloads:
[student@studentvm1 testdir]$
```

然而，并没有得到你期望的结果。它列出了以 `Do` 开头的目录下的内容。使用 `-d` 选项，仅列出目录而不列出它们的内容。

```
[student@studentvm1 testdir]$ ls -d Do*
Documents  Downloads
[student@studentvm1 testdir]$
```

在两个例子中，Bash shell 都把 `Do*` 模式展开成了匹配该模式的目录名称。但是如果有文件也匹配这个模式，会发生什么？

```
[student@studentvm1 testdir]$ touch Downtown ; ls -d Do*
Documents  Downloads  Downtown
[student@studentvm1 testdir]$
```

因此所有匹配这个模式的文件也被展开成了完整名字。

#### 命令替换

命令替换是让一个命令的标准输出数据流被当做参数传给另一个命令的扩展形式，例如，在一个循环中作为一系列被处理的项目。Bash 手册页显示：“命令替换可以让你用一个命令的输出替换为命令的名字。”这可能不太好理解。

命令替换有两种格式：``command`` 和 `$(command)`。在更早的格式中使用反引号（```），在命令中使用反斜杠（`\`）来保持它转义之前的文本含义。然而，当用在新版本的括号格式中时，反斜杠被当做一个特殊字符处理。也请注意带括号的格式打开个关闭命令语句都是用一个括号。

我经常在命令行程序和脚本中使用这种能力，一个命令的结果能被用作另一个命令的参数。

来看一个非常简单的示例，这个示例使用了这个扩展的两种格式（再一次提醒，确保 `testdir` 是当前工作目录）：

```
[student@studentvm1 testdir]$ echo "Todays date is `date`"
Todays date is Sun Apr  7 14:42:46 EDT 2019
[student@studentvm1 testdir]$ echo "Todays date is $(date)"
Todays date is Sun Apr  7 14:42:59 EDT 2019
[student@studentvm1 testdir]$
```

`-seq` 工具用于一个数字序列：

```
[student@studentvm1 testdir]$ seq 5
1
2
3
4
5
[student@studentvm1 testdir]$ echo `seq 5`
1 2 3 4 5
[student@studentvm1 testdir]$
```

现在你可以做一些更有用处的操作，比如创建大量用于测试的空文件。

```
[student@studentvm1 testdir]$ for I in $(seq -w 5000) ; do touch file-$I ; done
```

`seq` 工具加上 `-w` 选项后，在生成的数字前面会用 0 补全，这样所有的结果都等宽，例如，忽略数字的值，它们的位数一样。这样在对它们按数字顺序进行排列时很容易。

`seq -w 5000` 语句生成了 1 到 5000 的数字序列。通过把命令替换用于 `for` 语句，`for` 语句就可以使用该数字序列来生成文件名的数字部分。

#### 算术扩展

Bash 可以进行整型的数学计算，但是比较繁琐（你一会儿将看到）。数字扩展的语法是 `$((arithmetic-expression))` ，分别用两个括号来打开和关闭表达式。算术扩展在 shell 程序或脚本中类似命令替换；表达式结算后的结果替换了表达式，用于 shell 后续的计算。

我们再用一个简单的用法来开始：

```
[student@studentvm1 testdir]$ echo $((1+1))
2
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; Var3=$((Var1*Var2)) ; echo "Var 3 = $Var3"
Var 3 = 35
```

下面的除法结果是 0，因为表达式的结果是一个小于 1 的整型数字：

```
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; Var3=$((Var1/Var2)) ; echo "Var 3 = $Var3"
Var 3 = 0
```

这是一个我经常在脚本或 CLI 程序中使用的一个简单的计算，用来查看在 Linux 主机中使用了多少虚拟内存。 `free` 不提供我需要的数据：

```
[student@studentvm1 testdir]$ RAM=`free | grep ^Mem | awk '{print $2}'` ; Swap=`free | grep ^Swap | awk '{print $2}'` ; echo "RAM = $RAM and Swap = $Swap" ; echo "Total Virtual memory is $((RAM+Swap))" ;
RAM = 4037080 and Swap = 6291452
Total Virtual memory is 10328532
```

我使用 ``` 字符来划定用作命令替换的界限。

我用 Bash 算术扩展的场景主要是用脚本检查系统资源用量后基于返回的结果选择一个程序运行的路径。

### 总结

本文是 Bash 编程语言系列的第二篇，探讨了 Bash 中文件、字符串、数字和各种提供流程控制逻辑的逻辑操作符还有不同种类的 shell 扩展。

---

via: <https://opensource.com/article/19/10/programming-bash-logical-operators-shell-expansions>

作者：[David Both](https://opensource.com/users/dboth) 选题：[lujun9972](https://github.com/lujun9972) 译者：[lxbwolf](https://github.com/lxbwolf) 校对：[wxy](https://github.com/wxy)

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


开源软件名称中的故事

# 开源软件名称中的故事

>
> 有没有想过你喜欢的开源项目或编程语言的名称来自何处？让我们按字母顺序了解一下流行的技术术语背后的起源故事。
>
>
>

GNOME、Java、Jupyter、Python……如果你的朋友或家人曾留意过你的工作对话，他们可能会认为你从事文艺复兴时期的民间文学艺术、咖啡烘焙、天文学或动物学工作。这些开源技术的名称从何而来？我们请我们的作者社区提供意见，并汇总了一些我们最喜欢的技术名称的起源故事。

### Ansible

“Ansible”这个名称直接来自科幻小说。Ursula Le Guin 的《Rocannon's World》一书中能进行即时（比光速更快）通信的设备被称为 ansibles（显然来自 “answerable” 一词）。Ansibles 开始流行于科幻小说之中，Orson Scott Card 的《Ender's Game》（后来成为受欢迎的电影）中，该设备控制了许多远程太空飞船。对于控制分布式机器的软件来说，这似乎是一个很好的模型，因此 Michael DeHaan（Ansible 的创建者和创始人）借用了这个名称。

### Apache

[Apache](https://httpd.apache.org/) 是最初于 1995 年发布的开源 Web 服务器。它的名称与著名的美国原住民部落无关；相反，它是指对原始软件代码的重复补丁。因此称之为，“<ruby> 一个修补的 <rt>  A-patchy </rt></ruby>服务器”。

### awk

“awk(1) 代表着 Aho、Weinberger、Kernighan（作者）”—— Michael Greenberg

### Bash

“最初的 Unix shell，即 Bourne shell，是以其创造者的名字命名的。在开发出来 Bash 时，csh（发音为 ‘seashell’）实际上更受交互登录用户的欢迎。Bash 项目旨在赋予 Bourne shell 新的生命，使其更适合于交互式使用，因此它被命名为 ‘Bourne again shell’，是‘<ruby> 重生 <rt>  born again </rt></ruby>’的双关语。”——Ken Gaillot

### C

在早期，AT&T 的 Ken Thompson 和 Dennis Ritchie 发现可以使用更高级的编程语言（而不是低级的、可移植性更低的汇编编程）来编写操作系统和工具。早期有一个叫做 BCPL（<ruby> 基本组合编程语言 <rt>  Basic Combined programming Language </rt></ruby>）的编程系统，Thompson 创建了一个名为 B 的简化版 BCPL，但 B 的灵活性和速度都不高。然后，Ritchie 把 B 的思想扩展成一种叫做 C 的编译语言。”——Jim Hall

### dd

“我想你发表这样一篇文章不能不提到 dd。我的外号叫 Didi。发音正确的话听起来像 ‘dd’。我开始学的是 Unix，然后是 Linux，那是在 1993 年，当时我还是个学生。然后我去了军队，来到了我的部队中少数几个使用 Unix（Ultrix）的部门之一（其它部门主要是 VMS），那里的一个人说：‘这么说，你是一个黑客，对吗？你以为你了解 Unix 吗？好的，那么 dd 这个名字的是怎么来的呢？’我不知道，试着猜道：‘<ruby> 数据复印机 <rt>  Data duplicator </rt></ruby>？’所以他说，‘我要告诉你 dd 的故事。dd 是<ruby> 转换 <rt>  convert </rt></ruby>和<ruby> 复制 <rt>  copy </rt></ruby>的缩写（如今人们仍然可以在手册页中看到），但由于 cc 这个缩写已经被 C 编译器占用，所以它被命名为 dd。’就在几年后，我听闻了关于 JCL 的数据定义和 Unix dd 命令不统一的、半开玩笑的语法的真实故事，某种程度是基于此的。”——Yedidyah Bar David

### Emacs

经典的<ruby> 反 vi <rt>  anti-vi </rt></ruby>编辑器，其名称的真正词源并不明显，因为它源自“<ruby> 编辑宏 <rt>  Editing MACroS </rt></ruby>”。但是，它作为一个伟大的宗教亵渎和崇拜的对象，吸引了许多恶作剧般的缩写，例如“Escape Meta Alt Control Shift”（以调侃其对键盘的大量依赖），“<ruby> 8MB 并经常发生内存交换 <rt>  Eight Megabytes And Constantly Swapping </rt></ruby>”（从那时起就很吃内存了），“<ruby> 最终分配了所有的计算机存储空间 <rt>  Eventually malloc()s All Computer Storage </rt></ruby>”和 “<ruby> EMACS 使一台计算机慢 <rt>  EMACS Makes A Computer Slow </rt></ruby>”——改编自 Jargon File/Hacker's Dictionary

### Enarx

[Enarx](https://enarx.io) 是机密计算领域的一个新项目。该项目的设计原则之一是它应该是“可替代的”。因此最初的名字是“psilocybin”（著名的魔术蘑菇）。一般情况下，经理级别的人可能会对这个名称有所抵触，因此考虑使用新名称。该项目的两位创始人 Mike Bursell 和 Nathaniel McCallum 都是古老语言极客，因此他们考虑了许多不同的想法，包括 тайна（Tayna——俄语中代表秘密或神秘——虽然俄语并不是一门古老的语言，但你就不要在乎这些细节了），crypticon（希腊语的意思是完全私生的），cryptidion（希腊中表示小密室），arconus（拉丁语中表示秘密的褒义形容词），arcanum（拉丁语中表示秘密的中性形容词）和 ærn（盎格鲁撒克逊人表示地方、秘密的地方、壁橱、住所、房子，或小屋的词汇）。最后，由于各种原因，包括域名和 GitHub 项目名称的可用性，他们选择了 enarx，这是两个拉丁词根的组合：en-（表示内部）和 -arx（表示城堡、要塞或堡垒）。

### GIMP

没有 [GIMP](https://www.gimp.org/) 我们会怎么样？<ruby> GNU 图像处理项目 <rt>  GNU Image Manipulation Project </rt></ruby>多年来一直是开源的重要基础。[维基百科](https://en.wikipedia.org/wiki/GIMP)指出，“1995 年，[Spencer Kimball](https://en.wikipedia.org/wiki/Spencer_Kimball_(computer_programmer)) 和 [Peter Mattis](https://en.wikipedia.org/wiki/Peter_Mattis) 在加州大学伯克利分校开始为<ruby> 实验计算设施 <rt>  eXperimental Computing Facility </rt></ruby>开发 GIMP，这是一个为期一个学期的项目。”

### GNOME

你有没有想过为什么 GNOME 被称为 GNOME？根据[维基百科](https://en.wikipedia.org/wiki/GNOME)，GNOME 最初是一个表示“<ruby> GNU 网络对象模型环境 <rt>  GNU Network Object Model Environment </rt></ruby>”的缩写词。现在，该名称不再表示该项目，并且该项目已被放弃，但这个名称仍然保留了下来。[GNOME 3](https://www.gnome.org/gnome-3/) 是 Fedora、红帽企业版、Ubuntu、Debian、SUSE Linux 企业版等发行版的默认桌面环境。

### Java

你能想象这种编程语言还有其它名称吗？Java 最初被称为 Oak，但是遗憾的是，Sun Microsystems 的法律团队由于已有该商标而否决了它。所以开发团队又重新给它命名。[据说](https://www.javaworld.com/article/2077265/so-why-did-they-decide-to-call-it-java-.html)该语言的工作组在 1995 年 1 月举行了一次大规模的头脑风暴。许多其它名称也被扔掉了，包括 Silk、DNA、WebDancer 等。该团队不希望新名称与过度使用的术语“web”或“net”有任何关系。取而代之的是，他们在寻找更有活力、更有趣、更容易记住的东西。Java 满足了这些要求，并且奇迹般地，团队同意通过了！

### Jupyter

现在许多数据科学家和学生在工作中使用 [Jupyter](https://jupyter.org/) 笔记本。“Jupyter”这个名字是三种开源计算机语言的融合，这三种语言在这个笔记本中都有使用，在数据科学中也很突出：[Julia](https://julialang.org/)、[Python](https://www.python.org/) 和 [R](https://www.r-project.org/)。

### Kubernetes

Kubernetes 源自希腊语中的舵手。Kubernetes 项目创始人 Craig McLuckie 在 [2015 Hacker News](https://news.ycombinator.com/item?id=9653797) 回应中证实了这种词源。他坚持航海主题，解释说，这项技术可以驱动集装箱，就像舵手或驾驶员驾驶集装箱船一样，因此，他选择了 Kubernetes 这个名字。我们中的许多人仍然在尝试正确的发音（koo-bur-NET-eez），因此 替代使用 K8s 也是可以接受的。有趣的是，它与英语单词“<ruby> 行政长官 <rp>  （ </rp> <rt>  governor </rt> <rp>  ） </rp></ruby>”具有相同的词源，也与蒸汽机上的机械负反馈装置相同。

### KDE

那 K 桌面呢？KDE 最初代表“<ruby> 酷桌面环境 <rt>  Kool Desktop Environment </rt></ruby>”。 它由 [Matthias Ettrich](https://en.wikipedia.org/wiki/Matthias_Ettrich) 于 1996 年创立。根据[维基百科](https://en.wikipedia.org/wiki/KDE)上的说法，该名称是对 Unix 上 <ruby>   通用桌面环境  <rt>  Common Desktop Environment </rt></ruby>（CDE）一词的调侃。

### Linux

[Linux](https://en.wikipedia.org/wiki/Linux) 因其发明者 Linus Torvalds 的名字命名的。Linus 最初想将他的作品命名为“Freax”，因为他认为以他自己的名字命名太自负了。根据[维基百科](https://en.wikipedia.org/wiki/Linux)的说法，“赫尔辛基科技大学 Torvalds 的同事 Ari Lemmke 当时是 FTP 服务器的志愿管理员之一，他并不认为‘Freax’是个好名字。因此，他没有征询 Torvalds 就将服务器上的这个项目命名为‘Linux’。”

以下是一些最受欢迎的 Linux 发行版。

#### CentOS

[CentOS](https://www.centos.org/) 是<ruby> 社区企业操作系统 <rt>  Community Enterprise Operating System </rt></ruby>的缩写。它包含来自 Red Hat Enterprise Linux 的上游软件包。

#### Debian

[Debian](https://www.debian.org/) Linux 创建于 1993 年 9 月，是其创始人 Ian Murdock 和他当时的女友 Debra Lynn 的名字的混成词。

#### RHEL

[Red Hat Linux](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux) 得名于它的创始人 Marc Ewing，他戴着一顶祖父送给他的康奈尔大学红色<ruby> 软呢帽 <rt>  fedora </rt></ruby>。红帽公司成立于 1993 年 3 月 26 日。[Fedora Linux](https://getfedora.org/) 最初是一个志愿者项目，旨在为红帽发行版提供额外的软件，它的名字来自红帽的“Shadowman”徽标。

#### Ubuntu

[Ubuntu](https://ubuntu.com/about) 旨在广泛分享开源软件，它以非洲哲学“<ruby> 人的本质 <rt>  ubuntu </rt></ruby>”命名，可以翻译为“对他人的人道主义”或“我之所以是我，是因为我们都是这样的人”。

### Moodle

开源学习平台 [Moodle](https://moodle.org/) 是“<ruby> 模块化面向对象动态学习环境 <rt>  modular object-oriented dynamic learning environment </rt></ruby>”的首字母缩写。Moodle 仍然是领先的线上学习平台。全球有近 10.4 万个注册的 Moodle 网站。

另外两个流行的开源内容管理系统是 Drupal 和 Joomla。Drupal 的名字来自荷兰语 “druppel”，意思是“掉落”。根据维基百科，Joomla 是斯瓦希里语单词“jumla”的[英式拼写](https://en.wikipedia.org/wiki/Joomla#Historical_background)，在阿拉伯语、乌尔都语和其他语言中是“在一起”的意思。

### Mozilla

[Mozilla](https://www.mozilla.org/en-US/) 是一个成立于 1998 年的开源软件社区。根据其网站，“Mozilla 项目创建于 1998 年，发布了 Netscape 浏览器套件源代码。其旨在利用互联网上成千上万的程序员的创造力，并推动浏览器市场上前所未有的创新水平。” 这个名字是 [Mosaic](https://en.wikipedia.org/wiki/Mosaic_(web_browser)) 和 Godzilla 的混成词。

### Nginx

“许多技术人员都试图装酷，并将它念成‘n’‘g’‘n’‘x’。实际上，很少的一些人做点基本的调查工作，就可以很快发现该名称实际上应该被念成是“EngineX”，指的是功能强大的 web 服务器，像个引擎。”——Jean Sebastien Tougne

### Perl

Perl 的创始人 Larry Wall 最初将他的项目命名为“Pearl”。根据维基百科，Wall 想给这种语言起一个有积极含义的简短名字。在 Perl 正式发布之前，Wall 发现了已有 [PEARL](https://en.wikipedia.org/wiki/PEARL_(programming_language)) 编程语言，于是更改了名称的拼写。

### Piet 和 Mondrian

“有两种编程语言以艺术家 Piet Mondrian 命名。一种叫做‘Piet’，另一种叫做‘Mondrian’。（David Morgan-Mar [写道](http://www.dangermouse.net/esoteric/piet.html)）：‘Piet 是一种编程语言，其中的程序看起来像抽象绘画。该语言以几何抽象艺术的开创者 Piet Mondrian 的名字命名。我曾想将这种语言命名为 Mondrian，但是有人告诉我这会让它看起来像一种很普通的脚本语言。哦，好吧，我想我们不能都是深奥的语言作家。’”——Yuval Lifshitz

### Python

Python 编程语言的独特名称来自其创建者 Guido Van Rossum，他是英国六人喜剧团体 Monty Python 的粉丝。

### Raspberry Pi

Raspberry Pi 以其微小但强大的功能和对低廉的价格而闻名，在开源社区中是最受欢迎的。但是它可爱（和好吃）的名字是从哪里来的呢？在 70 年代和 80 年代，以水果命名的计算机是一种流行的趋势。苹果、橘子、杏……有人饿了吗？根据创始人 Eben Upton 的 [2012 采访](https://www.techspot.com/article/531-eben-upton-interview/)，“<ruby> 树莓派 <rt>  Raspberry Pi </rt></ruby>”这个名称是对这种趋势的致敬。树莓也很小，但却很有味道。名称中的“Pi”暗示着这样的事实：最初，该计算机只能运行 Python。

### Samba

[Server Message Block](https://www.samba.org/) 用于在 Linux 上共享 Windows 文件。

### ScummVM

[ScummVM](https://www.scummvm.org/)（《疯狂大楼》虚拟机的脚本创建实用程序）是一个程序，可以在现代计算机上运行一些经典的计算机冒险游戏。最初，它旨在玩用 SCUMM 构建的 LucasArts 的冒险游戏，该游戏最初用于开发《疯狂大楼》，后来又被用来开发 LucasArts 的其它大多数冒险游戏。目前，ScummVM 支持大量游戏引擎，包括 Sierra Online 的 AGI 和 SCI，但仍保留着名称 ScummVM。

有一个相关的项目 [ResidualVM](https://www.residualvm.org/) 之所以得名，是因为它涵盖了 ScummVM 未涵盖的“<ruby> 剩余的 <rt>  residual </rt></ruby>” LucasArts 冒险游戏。 ResidualVM 涵盖的 LucasArts 游戏是使用 GrimE（Grim Engine）开发的，该引擎最初用于开发 Grim Fandango，因此 ResidualVM 的名称是双关语。

### SQL

“你可能知道 SQL 代表<ruby> 结构化查询语言 <rt>  Structured Query Language </rt></ruby>，但你知道为什么它经常被读作‘sequel’吗？它是作为原本的‘QUEL’（<ruby> 查询语言 <rt>  QUEry Language </rt></ruby>）的后续（如<ruby> 结局 <rt>  sequel </rt></ruby>）而创建的。”——Ken Gaillot

### XFCE

[XFCE](https://www.xfce.org/) 是由 [Olivier Fourdan](https://en.wikipedia.org/wiki/Olivier_Fourdan) 创建的一个流行的桌面。它在 1996 年作为 CDE 的替代品出现，最初是 <ruby> XForms 公共环境 <rt>  XForms Common Environment </rt></ruby>的缩写。

### Zsh

Zsh 是一个交互式登录 shell。1990 年，普林斯顿大学的学生 Paul Falstad 写了该 shell 的第一个版本。他在看到当时在普林斯顿大学担任助教的 Zhong Sha 的登录 ID（zsh）后，觉得这个名字听起来像 [shell 的好名字](http://www.zsh.org/mla/users/2005/msg00951.html)，给它起了这个名字。

还有更多的项目和名称还没有包括在这个列表中。请一定要在评论中分享你的收藏。

---

via: <https://opensource.com/article/19/10/open-source-name-origins>

作者：[Joshua Allen Holm](https://opensource.com/users/holmja) 选题：[lujun9972](https://github.com/lujun9972) 译者：[laingke](https://github.com/laingke) 校对：[wxy](https://github.com/wxy)

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


新人必读：区块链实用型技能树

非常清晰的知识地图！

# 新人必读：区块链实用型技能树

随着新一波的区块链热潮，许多同学怀着巨大的热情进入了这个领域，同时也会遇到不少疑惑，区块链开发需要哪些知识？怎么学习？从哪里学习？遇到问题怎么办？本文将试图给区块链领域新人一个快速实用的指引。

### 一、基本 IT 技能

区块链堪称“黑科技”，本身具有大量的技术元素，有志于从技术角度切入区块链的人，应该具备或掌握基本的 IT 技能，达到至少是常规级别“程序员”或“系统管理员”的技能水平。

#### 首先需要熟练的 Linux 操作系统知识

大多数区块链系统是可以跑在 Linux 上的，包括 CentOS 和 Ubuntu 等，你至少要会一些基本的 Linux 操作指令，比如 `ls` 查看目录、`ps` 或 `top` 查看进程、`find` 查找文件、`netstat` 查看网络、`ulimit` 检查系统参数限制、`df`/`du` 查看磁盘空间、用 `apt`/`yum` 安装软件等等，如果这些基本命令都不掌握，在 Linux 上操作肯定是举步维艰的。

这方面的书和资料都很多，相信一星期就能上手。另外，善于 Linux 的 `man` 指令，可以获得每个命令的详细帮助。如果学会写 shell 脚本，那更如虎添翼，可以把大量的繁琐操作给自动化了。

#### 要有清晰的网络概念

区块链本来是分布式系统，节点之间一定是通过网络相连的，只是跑起来的话，不需要多高深的网络知识，只需要了解什么是 TCP/IP；公网、内网、本地地址的区别；端口如何配置；节点和节点、SDK 和节点之间的互联是否会被防火墙和网络策略挡住；采用 `ifconfig`、`telnet`、`ping`、`netstat` 等命令检查网络信息和进行探测、定位网络问题。一般来说，Linux 书籍也都会介绍这部分内容。

区块链周边的支持，如浏览器、中间件、业务应用，会依赖一些第三方基础软件，如 MySQL/MariaDB 数据库、Nginx 服务、Tomcat 服务等，至少懂得怎么去安装指定版本的软件，掌握修改这些软件的配置文件并使之生效的基本操作，了解各款软件的密码、权限配置和网络安全策略，以保护自身安全。

如果是基于云、Docker 或者 k8s 等容器环境构建，需要了解使用的服务商或容器的功能、性能、配置方式，包括对资源的分配：CPU、内存、带宽、存储等，以及安全和权限的配置、网络策略配置、运维方式，达到轻松分发构建的同时，还能保持其稳定性和可用性。

各种云服务商和容器解决方案都有周全的文档和客服服务渠道，可以帮助用户顺畅地使用。

#### 到编程语言阶段，可以根据自己的学习路径，选择不同的语言

如果是使用 Java 语言，那就应该熟练掌握 Eclipse、IntelliJ IDEA 等集成 IDE，熟悉 Gradle 为主的工程管理软件，熟悉 Spring、Springboot 等 Java 的基础开发组件，熟悉在 IDE 或命令行下对资源路径如 ApplicationContext 等路径的定义，或许还有 myBatis 等流行的组件，这些都可以在 Java 相关的社区和网站找到资料和书籍。

在熟练使用 Java 语言的情况下，采用 Java SDK 接入到区块链，跑起一个演示示例，将是非常轻松写意的事情。

如果是采用其他语言，我们也提供了 Python、Node.js、Golang 等语言的区块链 SDK。

不同的语言，其安装包有不同的稳定版本，会采用不同的环境和依赖安装配置方法，会有不同的 IDE 和调试方法，就不在本文一一罗列，相信学习和使用语言这件事本身，于程序员已经是最基本的技能了。

#### 最后，作为在开源世界里冲浪的玩家，“全球最大同性交友网站”——GitHub 一定是要上的了

注册 GitHub 账号，掌握 Git 版本管理工具的基本操作，克隆和拉取开源软件代码，提交议题，提交自己的修改，给开源项目提交拉取请求，再顺手点个星标，激情而有范儿，在开源世界里留下你的姓名。

### 二、区块链领域的基础知识栈

以下部分的知识和区块链或区块链某一个平台更加相关，从底到上依次是：

#### HASH（哈希算法）、签名、证书

严格来说，这并不是区块链领域的专有知识，只是必须具备的基础知识，包括 SHA3/SHA256/RIPEMD160 等摘要算法，以及这些算法和“区块链地址”的关系，基于公私钥的数字签名和验证方法，数字证书的概念和格式，比如 X.509 证书，以及保存证书/公私钥的文件格式，如 PEM 文件、keystore文件等。

#### 基础应用密码学

基础应用密码学其实范围很广，作为入门者，至少要了解对称和非对称加密的常见算法，如 AES 对称加密，RSA、ECDSA 椭圆曲线等非对称加密算法，以及这些算法在签名验签、数据加密、通信协商和保护方面的作用。如果要使用国密，那么需要了解 SM2~SM9 一系列算法的概念和使用。

#### 分布式网络结构

区块链是先天的“分布式网络系统”，节点和节点通过网络的 P2P 端口互连，客户端、SDK 通过 RPC/通道端口互连，首先要保证网络之间是互通的，监听的地址和端口是对的，端口是开放的，防火墙和网络策略是正确的，用于安全连接的证书已经到位，才能保证区块链的“通则不痛”。

这也要求使用者具备基本的网络知识、网络工具，同时了解区块链特有的节点类型（共识节点、观察节点、轻节点等）、互连方式（点对点双向连接、JSON RPC 的 HTTP 短连接、通道长连接等）。详情点击参考[《FISCO BCOS 网络端口讲解》](http://mp.weixin.qq.com/s?__biz=MzU5NTg0MjA4MA==&mid=2247484395&idx=1&sn=fb2c47ca54c986484bc935d1904d6b65&chksm=fe6a86a4c91d0fb2067ccde86a5da9f9e4b78bc876b2fd5dc26cabd5f3006586bcc90abdd3c1&scene=21#wechat_redirect)。

#### 智能合约

智能合约可说是应用开发者直面区块链的一道大门，入得此门，精彩无穷。流行的智能合约语言是 Solidity 语言，这门源自以太坊，从诞生开始就是为区块链而来的。

Solidity 语言更新活跃、文档完备，具有良好的一致性和事务性，功能足够实现中型的商业应用。

当然，它在实时调试、第三库支持、运行速度等方面还比不上成熟的语言，如果开发者想要用 C++ 等语言编写智能合约，那就要对区块链上的计算范式进行深入了解，避免写出无法共识的智能合约来，一般是建议有深入的了解后再采用 Solidity 之外的其他语言编写合约。

要掌握 Solidity 合约，当然是通读文档，并动手尝试。具体参考[该文档](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/smart_contract.html)。

#### ABI 接口原理

在采用 EVM 作为虚拟机的区块链上，EVM 执行的是 Solidity 语言的合约。合约编译会生成后缀名为 ABI 的文件，其实里面就是该合约接口定义的 JSON 文本，可以用文本查看器查阅，了解你写的合约如何翻译成 ABI 里的接口，接口返回类型，参数列表，参数类型等，只要有合约的 ABI 文件，就可以调用区块链 SDK 的接口，解析这个合约相关的交易、返回值、回执等。

#### 区块数据结构

<ruby> 区块 <rp>  （ </rp> <rt>  Block </rt> <rp>  ） </rp></ruby>有区块头和区块体。区块体有交易列表，交易列表里的每个<ruby> 交易 <rp>  （ </rp> <rt>  Transaction </rt> <rp>  ） </rp></ruby>（Tx）有发起方、目标地址、调用方法和参数，以及发送者签名。交易的结果会生成一个“<ruby> 回执 <rp>  （ </rp> <rt>  Receipt </rt> <rp>  ） </rp></ruby>”，回执里包含被调用方法的返回值、运行过程生成的 EventLog 等……

了解这些，基本上就掌握了区块链数据的脉络，还可以继续深究数据结构里的梅克尔根以及对应的梅克尔树是如何生成的，有什么作用（如用于 SPV：Simplified PaymentVerification）。具体参考[该文档](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/design/protocol_description.html)。

#### RPC 接口

这里把区块链节点暴露的功能接口统称为“RPC 接口”。查看链上数据，包括区块、交易、回执、系统信息、配置信息，向链上发起交易，以调用智能合约、修改系统配置等，或者通过 AMOP 协议发送消息、监听事件，都是通过 RPC 接口。

几十个 RPC 接口建议一一走读，或善用搜索，以发现自己想要的接口。

接口通信采用的协议可能是 JSON RPC，或者是 FISCO BCOS 独创的通道协议，SDK 基本上已经对接口和协议进行了良好的包装，也可以在深入理解 ABI 和 RLP 等编码模式前提下自行开发接口客户端。具体参考[该文档](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/api.html)。

#### 准入和权限模型

联盟链强调安全可控，节点准入是第一步，在链初始化后，其他节点或者 SDK 配置了相应的证书，才能接入到既有的联盟链上。

链上的角色用权限模型控制，包括管理员权限、发布合约的权限、创建表的权限、参数配置权限等，以避免角色之间操作混淆，某些角色既当运动员又当裁判员。

初学者需要仔细阅读区块链平台提供的技术文档了解原理，遵循操作手册的步骤进行操作。具体参考[该文档](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/permission_control.html)。

#### 数据存储模型

区块链节点会采用文件数据库（LevelDB 或 RocksDB），或者关系型数据库如 MySQL 保存数据，所以，链上是真的有“数据库”的。

写入数据库的数据包括区块、交易、回执、合约产生的状态数据等，是否写入“调用合约产生的历史数据”根据不同的平台而定， FISCO BCOS 默认只保存最新的状态值，可以选择性地将修改记录写入“回执”或“历史表”里进行追踪。

FISCO BCOS 还提供方案，将历史数据导出到链下数据库进行关联分析。具体参考[该文档](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/design/storage/index.html)。

#### 共识机制原理

联盟链通常采用插件化共识机制实现，FISCO BCOS 提供 PBFT 和 RAFT 两种高效共识算法，而不会采用“挖矿”这些高耗能低效率的共识。

共识机制是区块链的灵魂，对共识机制进行深入学习，才可以深入理解区块链通过多方协作、达成高度一致性、支持交易事务性、防篡改防作恶的功效。具体参考[该文档](https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/design/consensus/index.html)。

区块链的知识包罗万象，更深层次的知识还有分布式系统理论、博弈论、前沿密码学、经济学、社会学等，掌握以上的基础知识，再深入学习，举一反三，用场景去验证和探索创新式应用，方可发挥技术的潜力，感受分布式商业的魅力。

### 三、做一个怎样的学习者

在这个过程中，希望学习者做到：

#### 读文档的耐心

我们的开源项目文档足有 20 万字以上的篇幅，公众号里还有大量的技术解析和科普文章，这都是程序员们在编码之外，用尽自己仅有的语文储备，码出的海量文字，是一笔巨大的技术财富，涵盖了相关开源项目的方方面面。如果能通读，或者记住文档结构和标题，需要时快速打开，足以解惑且深入。

#### 搜资料的能力

文档、公众号都有搜索功能，当想起和开源社区有关的问题时，可以随手用关键字搜索，一般都能找到答案。如果有语言不详之处，可以向开源项目团队提出，或者根据自己的理解进行补充。通用的知识点，如操作系统、网络等，通过公网搜索引擎，一般都能找到答案。

#### 排查环境和依赖问题的能力

开源软件牵涉的系统环境、第三方软件、软件的版本等常常有错综复杂的依赖关系，太高或太低的版本都可能会有一些问题，请注意阅读项目文档对软硬件环境和依赖的描述，保证自己的环境符合要求，并善用配置管理工具、软件安装工具获取和设置合适的版本。

#### 调试能力

如上所述，Solidity 语言的调试工具完善程度尚未达到完美，但可以善用合约的返回值、EventLog 等方式，通过 WeBASE、控制台等趁手的工具进行调试，并查阅 Solidity 文档，了解问题可能出在哪里。

区块链节点的日志开启 debug 级别后，也会打印详细的信息，可以查阅运行日志，获取运行信息和可能的错误信息，将这些信息与自己所做的操作比如发交易的流程结合起来进行分析，提高调试效率。

同时，目前的开源软件通常会在屏幕上打印错误原因和解决问题的提示，仔细查看操作反馈，大概率能了解错误原因和解决方案。

#### 代码阅读能力

开源软件的最大效能是把代码毫无遗漏的摊到了开发者和学习者面前，了解代码结构，查阅代码里的关键流程，用关键字去搜索代码里的对应实现，都可以深入系统细节，挖掘设计思想，定位问题，寻找优化方法。一个好学且硬核的程序员，足可通过代码，和世界对话。

#### 问问题的方式方法

“一个好问题，比答案还重要”。我们的社区非常活跃，大家都很热情地答复和解决问题。我们鼓励在社区里公开提出问题，一方面使大家都可以分享问题，找到解决方案，另一方面提问者也可以得到更多人的帮助。同时，希望提问者提出问题时，一次性描述详尽，把相关的操作步骤、系统环境、软件版本、出错提示以及希望得到的解决方案都提出来。

如果是通用性的问题，可以先搜索再提问，有利于培养独立解决问题的能力。希望提问者能向社区反馈更深层次的问题，以帮助社区快速优化。对很多典型问题，社区也积累了一些行之有效的解决方案，我们会整理和公布出来，以便查阅。

从新人到老鸟的路也许漫漫，如果能参考这篇小文的一些方法，可以少踩许多坑，多写一些应用。Enjoy blockchain，社区与你共同进步。

### 资源链接

* 各项开源组件索引： <https://fintech.webank.com/>
* FISCO BCOS 开源文档： <https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/>
* 关键概念：<https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/tutorial/key_concepts.html>
* 以及使用手册：<https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/index.html>


从命令行轻松将文本片段上传到类似 Pastebin 的服务中

# 从命令行轻松将文本片段上传到类似 Pastebin 的服务中

每当需要在线共享代码片段时，我们想到的第一个便是 Pastebin.com，这是 Paul Dixon 于 2002 年推出的在线文本共享网站。现在，有几种可供选择的文本共享服务可以上传和共享文本片段、错误日志、配置文件、命令输出或任何类型的文本文件。如果你碰巧经常使用各种类似于 Pastebin 的服务来共享代码，那么这对你来说确实是个好消息。向 Wgetpaste 打个招呼吧，它是一个命令行 BASH 实用程序，可轻松地将文本摘要上传到类似 Pastebin 的服务中。使用 Wgetpaste 脚本，任何人都可以与自己的朋友、同事或想在类似 Unix 的系统中的命令行中查看/使用/审查代码的人快速共享文本片段。

### 安装 Wgetpaste

Wgetpaste 在 Arch Linux [Community] 存储库中可用。要将其安装在 Arch Linux 及其变体（如 Antergos 和 Manjaro Linux）上，只需运行以下命令：

```
$ sudo pacman -S wgetpaste
```

对于其他发行版，请从 [Wgetpaste 网站](http://wgetpaste.zlin.dk/) 获取源代码，并按如下所述手动安装。

首先下载最新的 Wgetpaste tar 文件：

```
$ wget http://wgetpaste.zlin.dk/wgetpaste-2.28.tar.bz2
```

提取它：

```
$ tar -xvjf wgetpaste-2.28.tar.bz2
```

它将 tar 文件的内容提取到名为 `wgetpaste-2.28` 的文件夹中。

转到该目录：

```
$ cd wgetpaste-2.28/
```

将 `wgetpaste` 二进制文件复制到 `$PATH` 中，例如 `/usr/local/bin/`。

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

最后，使用命令使其可执行：

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

### 将文本片段上传到类似 Pastebin 的服务中

使用 Wgetpaste 上传文本片段很简单。让我向你展示一些示例。

#### 1、上传文本文件

要使用 Wgetpaste 上传任何文本文件，只需运行：

```
$ wgetpaste mytext.txt
```

此命令将上传 `mytext.txt` 文件的内容。

示例输出：

```
Your paste can be seen here: https://paste.pound-python.org/show/eO0aQjTgExP0wT5uWyX7/
```

你可以通过邮件、短信、whatsapp 或 IRC 等任何媒体共享 pastebin 的 URL。拥有此 URL 的人都可以访问它，并在他们选择的 Web 浏览器中查看文本文件的内容。

这是 Web 浏览器中 `mytext.txt` 文件的内容：

你也可以使用 `tee` 命令显示粘贴的内容，而不是盲目地上传它们。

为此，请使用如下的 `-t` 选项。

```
$ wgetpaste -t mytext.txt
```

#### 2、将文字片段上传到其他服务

默认情况下，Wgetpaste 会将文本片段上传到 poundpython（<https://paste.pound-python.org/>）服务。

要查看支持的服务列表，请运行：

```
$ wgetpaste -S
```

示例输出：

```
Services supported: (case sensitive):
Name: | Url:
=============|=================
bpaste | https://bpaste.net/
codepad | http://codepad.org/
dpaste | http://dpaste.com/
gists | https://api.github.com/gists
*poundpython | https://paste.pound-python.org/
```

在这里，`*` 表示默认服务。

如你所见，Wgetpaste 当前支持五种文本共享服务。我并没有全部尝试，但是我相信所有服务都可以使用。

要将内容上传到其他服务，例如 bpaste.net，请使用如下所示的 `-s` 选项。

```
$ wgetpaste -s bpaste mytext.txt
Your paste can be seen here: https://bpaste.net/show/5199e127e733
```

#### 3、从标准输入读取输入

Wgetpaste 也可以从标准输入读取。

```
$ uname -a | wgetpaste
```

此命令将上传 `uname -a` 命令的输出。

#### 4、上传命令及命令的输出

有时，你可能需要粘贴命令及其输出。为此，请在如下所示的引号内指定命令的内容。

```
$ wgetpaste -c 'ls -l'
```

这会将命令 `ls -l` 及其输出上传到 pastebin 服务。

当你想让其他人清楚地知道你刚运行的确切命令及其输出时，此功能很有用。

如你在输出中看到的，我运行了 `ls -l` 命令。

#### 5、上载系统日志文件、配置文件

就像我已经说过的，我们可以上载你的系统中任何类型的文本文件，而不仅仅是普通的文本文件，例如日志文件、特定命令的输出等。例如，你刚刚更新了 Arch Linux 机器，最后系统损坏了。你问你的同事该如何解决此问题，他（她）想阅读 `pacman.log` 文件。 这是上传 `pacman.log` 文件内容的命令：

```
$ wgetpaste /var/log/pacman.log
```

与你的同事共享 pastebin URL，以便他/她可以查看 `pacman.log`，并通过查看日志文件来帮助你解决问题。

通常，日志文件的内容可能太长，你不希望全部共享它们。在这种情况下，只需使用 `cat` 命令读取输出，然后使用 `tail -n` 命令定义要共享的行数，最后将输出通过管道传递到 Wgetpaste，如下所示。

```
$ cat /var/log/pacman.log | tail -n 50 | wgetpaste
```

上面的命令将仅上传 `pacman.log` 文件的“最后 50 行”。

#### 6、将输入网址转换为短链接

默认情况下，Wgetpaste 将在输出中显示完整的 pastebin URL。如果要将输入 URL 转换为短链接，只需使用 `-u` 选项。

```
$ wgetpaste -u mytext.txt
Your paste can be seen here: http://tinyurl.com/y85d8gtz
```

#### 7、设定语言

默认情况下，Wgetpaste 将上传“纯文本”中的文本片段。

要列出指定服务支持的语言，请使用 `-L` 选项。

```
$ wgetpaste -L
```

该命令将列出默认服务（poundpython <https://paste.pound-python.org/>）支持的所有语言。

我们可以使用 `-l` 选项来改变它。

```
$ wgetpaste -l Bash mytext.txt
```

#### 8、在输出中禁用语法突出显示或 html

如上所述，文本片段将以特定的语言格式（纯文本、Bash 等）显示。

但是，你可以更改此行为，以使用 `-r` 选项显示原始文本摘要。

```
$ wgetpaste -r mytext.txt
Your raw paste can be seen here: https://paste.pound-python.org/raw/CUJhQ3jEmr2UvfmD2xCL/
```

如你在上面的输出中看到的，没有语法突出显示，没有 html 格式。只是原始输出。

#### 9、更改 Wgetpaste 默认值

所有默认值（`DEFAULT_{NICK,LANGUAGE,EXPIRATION}[_${SERVICE}]` 和 `DEFAULT_SERVICE`）都可以在 `/etc/wgetpaste.conf` 中全局更改，也可以在 `~/.wgetpaste.conf` 文件中针对每个用户更改。但是，这些文件在我的系统中默认情况下并不存在。我想我们需要手动创建它们。开发人员已经在[这里](http://wgetpaste.zlin.dk/zlin.conf)和[这里](http://wgetpaste.zlin.dk/wgetpaste.example)为这两个文件提供了示例内容。只需使用给定的样本内容手动创建这些文件，并相应地修改参数即可更改 Wgetpaste 的默认设置。

#### 10、获得帮助

要显示帮助部分，请运行：

```
$ wgetpaste -h
```

---

via: <https://www.ostechnix.com/how-to-easily-upload-text-snippets-to-pastebin-like-services-from-commandline/>

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

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


简单就是易于调试

Summary: 对于框架、库或者工具来说，怎样做才算是“简单”？也许有很多的定义，但我的理解通常是易于调试。

# 简单就是易于调试

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

对于框架、库或者工具来说，怎样做才算是“简单”？也许有很多的定义，但我的理解通常是**易于调试**。我经常见到人们宣传某个特定的程序、框架、库、文件格式或者其它什么东西是简单的，因为他们会说“看，我只需要这么一点工作量就能够完成某项工作，这太简单了”。非常好，但并不完善。

你可能只编写一次软件，但几乎总要经历好几个调试周期。注意我说的调试周期并不意味着“代码里面有 bug 你需要修复”，而是说“我需要再看一下这份代码来修复 bug”。为了调试代码，你需要理解它，因此“易于调试”延伸来讲就是“易于理解”。

抽象使得程序易于编写，但往往是以难以理解为代价。有时候这是一个很好的折中，但通常不是。大体上，如果能使程序在日后易于理解和调试，我很乐意花更多的时间来写一些东西，因为这样实际上更省时间。

简洁并不是让程序易于调试的**唯一**方法，但它也许是最重要的。良好的文档也是，但不幸的是好的文档太少了。（注意，质量并**不**取决于字数！）

这种影响是真是存在的。难以调试的程序会有更多的 bug，即使最初的 bug 数量与易于调试的程序完全相同，而是因为修复 bug 更加困难、更花时间。

在公司的环境中，把时间花在难以修复的 bug 上通常被认为是不划算的投资。而在开源的环境下，人们花的时间会更少。（大多数项目都有一个或多个定期的维护者，但成百上千的贡献者提交的仅只是几个补丁）

---

这并不全是 1974 年由 Brian W. Kernighan 和 P. J. Plauger 合著的《<ruby> 编程风格的元素 <rt>  The Elements of Programming Style </rt></ruby>》中的观点：

>
> 每个人都知道调试比起编写程序困难两倍。当你写程序的时候耍小聪明，那么将来应该怎么去调试？
>
>
>

我见过许多看起来写起来“极尽精妙”，但却导致难以调试的代码。我会在下面列出几种样例。争论这些东西本身有多坏并不是我的本意，我仅想强调对于“易于使用”和“易于调试”之间的折中。

* <ruby> ORM <rt>  对象关系映射 </rt></ruby> 库可以让数据库查询变得简单，代价是一旦你想解决某个问题，事情就变得难以理解。
* 许多测试框架让调试变得困难。Ruby 的 rspec 就是一个很好的例子。有一次我不小心使用错了，结果花了很长时间搞清楚**究竟**哪里出了问题（因为它给出错误提示非常含糊）。

我在《[测试并非万能](https://www.arp242.net/testing.html)》这篇文章中写了更多关于以上的例子。
* 我用过的许多 JavaScript 框架都很难完全理解。Clever（LCTT 译注：一种 JS 框架）的语句一向很有逻辑，直到某条语句不能如你预期的工作，这时你就只能指望 Stack Overflow 上的某篇文章或 GitHub 上的某个回帖来帮助你了。

这些函数库**确实**让任务变得非常简单，使用它们也没有什么错。但通常人们都过于关注“易于使用”而忽视了“易于调试”这一点。
* Docker 非常棒，并且让许多事情变得非常简单，直到你看到了这条提示：

```
ERROR: for elasticsearch Cannot start service elasticsearch:
oci runtime error: container_linux.go:247: starting container process caused "process_linux.go:258:
applying cgroup configuration for process caused \"failed to write 898 to cgroup.procs: write
/sys/fs/cgroup/cpu,cpuacct/docker/b13312efc203e518e3864fc3f9d00b4561168ebd4d9aad590cc56da610b8dd0e/cgroup.procs:
invalid argument\""
```

或者这条：

```
ERROR: for elasticsearch Cannot start service elasticsearch: EOF
```

那么…你怎么看？
* `Systemd` 比起 `SysV`、`init.d` 脚本更加简单，因为编写 `systemd` 单元文件比起编写 `shell` 脚本更加方便。这也是 Lennart Poetterin 在他的 [systemd 神话](http://0pointer.de/blog/projects/the-biggest-myths.html) 中解释 `systemd` 为何简单时使用的论点。

我非常赞同 Poettering 的观点——也可以看 [shell 脚本陷阱](https://www.arp242.net/shell-scripting-trap.html) 这篇文章。但是这种角度并不全面。单元文件简单的背后意味着 `systemd` 作为一个整体要复杂的多，并且用户确实会受到它的影响。看看我遇到的这个[问题](https://unix.stackexchange.com/q/185495/33645)和为它所做的[修复](https://cgit.freedesktop.org/systemd/systemd/commit/?id=6e392c9c45643d106673c6643ac8bf4e65da13c1)。看起来很简单吗？

---

via: <https://arp242.net/weblog/easy.html>

作者：[Martin Tournoij](https://arp242.net/) 选题：[lujun9972](https://github.com/lujun9972) 译者：[LuuMing](https://github.com/LuuMing) 校对：[wxy](https://github.com/wxy)

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


在 Linux 上使用 Ksnip 注释截图

Summary: Ksnip 让你能轻松地在 Linux 中创建和标记截图。

看起来不错。一直希望 Linux 上能有个类似于 Snipaste 的工具。

不支持中文输入法

Ksnip 让你能轻松地在 Linux 中创建和标记截图。

# 在 Linux 上使用 Ksnip 注释截图

>
> Ksnip 让你能轻松地在 Linux 中创建和标记截图。
>
>
>

我最近从 MacOS 切换到了 [Elementary OS](https://elementary.io/)，这是一个专注于易用性和隐私性的 Linux 发行版。作为用户体验设计师和自由软件支持者，我会经常截图并进行注释。在尝试了几种不同的工具之后，到目前为止，我最喜欢的工具是 [Ksnip](https://github.com/damirporobic/ksnip)，它是 GPLv2 许可下的一种开源工具。

### 安装

使用你首选的包管理器安装 Ksnip。我通过 Apt 安装了它：

```
sudo apt-get install ksnip
```

### 配置

Ksnip 有许多配置选项，包括：

* 保存截图的地方
* 默认截图的文件名
* 图像采集器行为
* 光标颜色和宽度
* 文字字体

你也可以将其与你的 Imgur 帐户集成。

### 用法

Ksnip 提供了大量的[功能](https://github.com/DamirPorobic/ksnip#features)。我最喜欢的 Ksnip 部分是它拥有我需要的所有注释工具（还有一个我没想到的工具！）。

你可以使用以下注释：

* 钢笔
* 记号笔
* 矩形
* 椭圆
* 文字

你还可以模糊区域来移除敏感信息。还有使用我最喜欢的新工具：用于在界面上表示步骤的带数字的点。

### 关于作者

我非常喜欢 Ksnip，因此我联系了作者 [Damir Porobic](https://github.com/damirporobic/) 来了解有关该项目的更多信息。

当我问到是什么启发了他编写 Ksnip 时，他说：

>
> “几年前我从 Windows 切换到 Linux，却没有了在 Windows 中常用的 Windows Snipping Tool。当时的所有其他截图工具要么很大（很多按钮和复杂功能），要么缺少诸如注释等关键功能，所以我决定编写一个简单的 Windows Snipping Tool 克隆版，但是随着时间的流逝，它开始有越来越多的功能。“
>
>
>

这正是我在评估截图工具时发现的。他花时间构建解决方案并免费共享给他人使用，这真是太好了。

至于 Ksnip 的未来，Damir 希望添加全局快捷方式（至少对于 Windows 是这样）和用于新截图的选项卡，并允许该应用在后台运行。GitHub 上的功能请求列表也越来越多。

### 帮助的方式

Damir 最需要的是帮助开发 Ksnip。他和他的妻子很快就会有孩子了，所以他将没有太多的时间放在这个项目上。不过，他可以检查和接受拉取请求。

此外，此项目还可以通过 Snap 、Flatpak 以及 MacOS 安装包、Windows 安装包等其他安装方式安装。如果你想提供帮助，请查看 Ksnip 的 README 的 [Contribution](https://github.com/DamirPorobic/ksnip/blob/master/README.md#contribution) 部分。

---

>
> 此文章最初发表在 [Agaric Tech Cooperative 的博客](https://agaric.coop/blog/annotate-screenshots-linux-ksnip)上，并经允许重新发布。
>
>
>

---

via: <https://opensource.com/article/19/12/annotate-screenshots-linux-ksnip>

作者：[Clayton Dewey](https://opensource.com/users/cedewey) 选题：[lujun9972](https://github.com/lujun9972) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


将你的应用迁移到 Python 3 的三个步骤

# 将你的应用迁移到 Python 3 的三个步骤

>
> Python 2 气数将尽，是时候将你的项目从 Python 2 迁移到 Python 3 了。
>
>
>

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

Python 2.x 很快就要[失去官方支持](/article-11629-1.html)了，尽管如此，从 Python 2 迁移到 Python 3 却并没有想象中那么难。我在上周用了一个晚上的时间将一个 3D 渲染器的前端代码及其对应的 [PySide](https://pypi.org/project/PySide/) 迁移到 Python 3，回想起来，尽管在迁移过程中无可避免地会遇到一些牵一发而动全身的修改，但整个过程相比起痛苦的重构来说简直是出奇地简单。

每个人都别无选择地有各种必须迁移的原因：或许是觉得已经拖延太久了，或许是依赖了某个在 Python 2 下不再维护的模块。但如果你仅仅是想通过做一些事情来对开源做贡献，那么把一个 Python 2 应用迁移到 Python 3 就是一个简单而又有意义的做法。

无论你从 Python 2 迁移到 Python 3 的原因是什么，这都是一项重要的任务。按照以下三个步骤，可以让你把任务完成得更加清晰。

### 1、使用 2to3

从几年前开始，Python 在你或许还不知道的情况下就已经自带了一个名叫 [2to3](https://docs.python.org/3.1/library/2to3.html) 的脚本，它可以帮助你实现大部分代码从 Python 2 到 Python 3 的自动转换。

下面是一段使用 Python 2.6 编写的代码：

```
#!/usr/bin/env python
# -*- coding: utf-8 -*-
mystring = u'abcdé'
print ord(mystring[-1])
```

对其执行 2to3 脚本：

```
$ 2to3 example.py
RefactoringTool: Refactored example.py
--- example.py     (original)
+++ example.py     (refactored)
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-

-mystring = u'abcdé'
-print ord(mystring[-1])
+mystring = 'abcdé'
+print(ord(mystring[-1]))
RefactoringTool: Files that need to be modified:
RefactoringTool: example.py
```

在默认情况下，`2to3` 只会对迁移到 Python 3 时必须作出修改的代码进行标示，在输出结果中显示的 Python 3 代码是直接可用的，但你可以在 2to3 加上 `-w` 或者 `--write` 参数，这样它就可以直接按照给出的方案修改你的 Python 2 代码文件了。

```
$ 2to3 -w example.py
[...]
RefactoringTool: Files that were modified:
RefactoringTool: example.py
```

`2to3` 脚本不仅仅对单个文件有效，你还可以把它用于一个目录下的所有 Python 文件，同时它也会递归地对所有子目录下的 Python 文件都生效。

### 2、使用 Pylint 或 Pyflakes

有一些不良的代码在 Python 2 下运行是没有异常的，在 Python 3 下运行则会或多或少报出错误，这种情况并不鲜见。因为这些不良代码无法通过语法转换来修复，所以 `2to3` 对它们没有效果，但一旦使用 Python 3 来运行就会产生报错。

要找出这种问题，你需要使用 [Pylint](https://opensource.com/article/19/10/python-pylint-introduction)、[Pyflakes](https://pypi.org/project/pyflakes/)（或 [flake8](https://opensource.com/article/19/5/python-flake8) 封装器）这类工具。其中我更喜欢 Pyflakes，它会忽略代码风格上的差异，在这一点上它和 Pylint 不同。尽管代码优美是 Python 的一大特点，但在代码迁移的层面上，“让代码功能保持一致”无疑比“让代码风格保持一致”重要得多。

以下是 Pyflakes 的输出样例：

```
$ pyflakes example/maths
example/maths/enum.py:19: undefined name 'cmp'
example/maths/enum.py:105: local variable 'e' is assigned to but never used
example/maths/enum.py:109: undefined name 'basestring'
example/maths/enum.py:208: undefined name 'EnumValueCompareError'
example/maths/enum.py:208: local variable 'e' is assigned to but never used
```

上面这些由 Pyflakes 输出的内容清晰地给出了代码中需要修改的问题。相比之下，Pylint 会输出多达 143 行的内容，而且多数是诸如代码缩进这样无关紧要的问题。

值得注意的是第 19 行这个容易产生误导的错误。从输出来看你可能会以为 `cmp` 是一个在使用前未定义的变量，实际上 `cmp` 是 Python 2 的一个内置函数，而它在 Python 3 中被移除了。而且这段代码被放在了 `try` 语句块中，除非认真检查这段代码的输出值，否则这个问题很容易被忽略掉。

```
    try:
        result = cmp(self.index, other.index)
    except:
        result = 42

    return result
```

在代码迁移过程中，你会发现很多原本在 Python 2 中能正常运行的函数都发生了变化，甚至直接在 Python 3 中被移除了。例如 PySide 的绑定方式发生了变化、`importlib` 取代了 `imp` 等等。这样的问题只能见到一个解决一个，而涉及到的功能需要重构还是直接放弃，则需要你自己权衡。但目前来说，大多数问题都是已知的，并且有[完善的文档记录](https://docs.python.org/3.0/whatsnew/3.0.html)。所以难的不是修复问题，而是找到问题，从这个角度来说，使用 Pyflake 是很有必要的。

### 3、修复被破坏的 Python 2 代码

尽管 `2to3` 脚本能够帮助你把代码修改成兼容 Python 3 的形式，但对于一个完整的代码库，它就显得有点无能为力了，因为一些老旧的代码在 Python 3 中可能需要不同的结构来表示。在这样的情况下，只能人工进行修改。

例如以下代码在 Python 2.6 中可以正常运行：

```
class CLOCK_SPEED:
        TICKS_PER_SECOND = 16
        TICK_RATES = [int(i * TICKS_PER_SECOND)
                      for i in (0.5, 1, 2, 3, 4, 6, 8, 11, 20)]

class FPS:
        STATS_UPDATE_FREQUENCY = CLOCK_SPEED.TICKS_PER_SECOND
```

类似 `2to3` 和 Pyflakes 这些自动化工具并不能发现其中的问题，但如果上述代码使用 Python 3 来运行，解释器会认为 `CLOCK_SPEED.TICKS_PER_SECOND` 是未被明确定义的。因此就需要把代码改成面向对象的结构：

```
class CLOCK_SPEED:
        def TICKS_PER_SECOND():
                TICKS_PER_SECOND = 16
                TICK_RATES = [int(i * TICKS_PER_SECOND)
                        for i in (0.5, 1, 2, 3, 4, 6, 8, 11, 20)]
                return TICKS_PER_SECOND

class FPS:
        STATS_UPDATE_FREQUENCY = CLOCK_SPEED.TICKS_PER_SECOND()
```

你也许会认为如果把 `TICKS_PER_SECOND()` 改写为一个构造函数（用 `__init__` 函数设置默认值）能让代码看起来更加简洁，但这样就需要把这个方法的调用形式从 `CLOCK_SPEED.TICKS_PER_SECOND()` 改为 `CLOCK_SPEED()` 了，这样的改动或多或少会对整个库造成一些未知的影响。如果你对整个代码库的结构烂熟于心，那么你确实可以随心所欲地作出这样的修改。但我通常认为，只要我做出了修改，都可能会影响到其它代码中的至少三处地方，因此我更倾向于不使代码的结构发生改变。

### 坚持信念

如果你正在尝试将一个大项目从 Python 2 迁移到 Python 3，也许你会觉得这是一个漫长的过程。你可能会费尽心思也找不到一条有用的报错信息，这种情况下甚至会有将代码推倒重建的冲动。但从另一个角度想，代码原本在 Python 2 中就可以运行，要让它能在 Python 3 中继续运行，你需要做的只是对它稍加转换而已。

但只要你完成了迁移，你就得到了这个模块或者整个应用程序的 Python 3 版本，外加 Python 官方的长期支持。

---

via: <https://opensource.com/article/19/12/update-apps-python-3>

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

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


如何为 Linux 桌面配置 Openbox

# 如何为 Linux 桌面配置 Openbox

>
> 本文是 24 天 Linux 桌面特别系列的一部分。Openbox 窗口管理器占用很小的系统资源、易于配置、使用愉快。
>
>
>

你可能不知道你使用过 [Openbox](http://openbox.org) 桌面：尽管 Openbox 本身是一个出色的窗口管理器，但它还是 LXDE 和 LXQT 等桌面环境的窗口管理器“引擎”，它甚至可以管理 KDE 和 GNOME。除了作为多个桌面的基础之外，Openbox 可以说是最简单的窗口管理器之一，可以为那些不想学习那么多配置选项的人配置。通过使用基于菜单的 obconf 的配置应用，可以像在 GNOME 或 KDE 这样的完整桌面中一样轻松地设置所有常用首选项。

### 安装 Openbox

你可能会在 Linux 发行版的软件仓库中找到 Openbox，也可以在 [Openbox.org](http://openbox.org/wiki/Openbox:Download) 中找到它。如果你已经在运行其他桌面，那么可以安全地在同一系统上安装 Openbox，因为 Openbox 除了几个配置面板之外，不包括任何捆绑的应用。

安装后，退出当前桌面会话，以便你可以登录 Openbox 桌面。默认情况下，会话管理器（KDM、GDM、LightDM 或 XDM，这取决于你的设置）将继续登录到以前的桌面，因此你必须在登录之前覆盖该选择。

要使用 GDM 覆盖它：

要使用 SDDM 覆盖它：

### 配置 Openbox 桌面

默认情况下，Openbox 包含 obconf 应用，你可以使用它来选择和安装主题、修改鼠标行为、设置桌面首选项等。你可能会在仓库中发现其他配置应用，如 obmenu，用于配置窗口管理器的其他部分。

构建你自己的桌面环境相对容易。它有一些所有常见的桌面组件，例如系统托盘 [stalonetray](https://sourceforge.net/projects/stalonetray/)、任务栏 [Tint2](https://opensource.com/article/19/1/productivity-tool-tint2) 或 [Xfce4-panel](http://xfce.org) 等几乎你能想到的。任意组合应用，直到拥有梦想的开源桌面为止。

### 为何使用 Openbox

Openbox 占用的系统资源很小、易于配置、使用起来很愉悦。它基本不会让你感觉到阻碍，会是一个容易熟悉的系统。你永远不会知道你面前的桌面环境秘密使用了 Openbox 作为窗口管理器（知道如何自定义它会不会很高兴？）。如果开源吸引你，那么试试看 Openbox。

---

via: <https://opensource.com/article/19/12/openbox-linux-desktop>

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

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