mirror of
https://github.com/LCTT/TranslateProject.git
synced 2026-08-20 03:53:30 +08:00
归档 201901
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10429-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 0 Introduction)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/introduction.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 0 简介
|
||||
======
|
||||
|
||||
这个课程简介不包含实践内容,但它解释了一个操作系统的基本概念、汇编代码、和其它很重要的一些基本原理。如果你想直接进入实践环节,跳过本课程并不会有什么问题。
|
||||
|
||||
### 1、操作系统
|
||||
|
||||
操作系统就是一个非常复杂的程序。它的任务就是组织安排计算机上的其它程序,包括共享计算机的时间、内存、硬件和其它资源。你可能听说过的一些比较大的桌面操作系统家族有 GNU/Linux、Mac OS X 和 Microsoft Windows。其它的设备比如电话,也需要操作系统,它可能使用的操作系统是 Android、iOS 和 Windows Phone。 [^1]
|
||||
|
||||
由于操作系统是用来与计算机系统上的硬件进行交互的,所以它必须了解系统上硬件专有的信息。为了能让操作系统适用于各种类型的计算机,发明了 **驱动程序** 的概念。驱动程序是为了能够让操作系统与特定的硬件进行交互而添加(并可删除)到操作系统上的一小部分代码。在本课程中,我们并不涉及如何创建可删除的驱动程序,而是专注于特定的一个硬件:树莓派。
|
||||
|
||||
操作系统有各种不同的设计方式,在本课程中,我们只触及操作系统设计的皮毛。本课程中,我们主要专注于操作系统与各种硬件的交互部分,因为这经常是比较棘手的部分,并且也是在网络上文档和帮助最少的部分。
|
||||
|
||||
### 2、汇编代码
|
||||
|
||||
> 处理器每秒可以执行上百万的指令,但是这些指令必须要简单。
|
||||
|
||||
本课程几乎要完全靠汇编代码来写。汇编代码非常接近计算机的底层。计算机其实是靠一个叫处理器的设备来工作的,处理器能够执行像加法这样的简单任务,还有一组叫做 RAM 的芯片,它能够用来保存数字。当计算机通电后,处理器执行程序员给定的一系列指令,这将导致内存中的数字发生变化,以及与连接的硬件进行交互。汇编代码只是将这些机器命令转换为人类可读的文本。
|
||||
|
||||
常规的编程就是,程序员使用编程语言,比如 C++、Java、C#、Basic 等等来写代码,然后一个叫编译器的程序将程序员写的代码转换成汇编代码,然后进一步转换为二进制代码。[^2] 二进制代码才是计算机真正能够理解的东西,但它是人类无法读取的东西。汇编代码比二进制代码好一点,至少它的命令是人类可读的,但它仍然让人很沮丧。请记住,你用汇编代码写的每个命令都是处理器可以直接认识的,因此这些命令设计的很简单,因为物理电路必须能够处理每个命令。
|
||||
|
||||
![Compiler process][1]
|
||||
|
||||
和普通编程一样,也有很多不同的汇编代码编程语言,但与普通编程不一样的是,每个汇编编程语言是面对不同的处理器的,每种处理器设计为去理解不同的语言。因此,用一个针对某种机器设计的汇编语言所写的汇编代码,是不能在其它种类的机器上运行的。很多情况下,这都是一个大灾难,因此每个程序都必须在使用它的不同种类的机器上重写一遍,但对于操作系统,这不是个问题,因为在不同的硬件上它必须得重写。尽管如此,大多数操作系统都是用 C++ 或 C 来写的,这样它们就可以很容易地在不同种类的硬件上使用,只需要重写那些必须用汇编代码来实现的部分即可。
|
||||
|
||||
现在,你已经准备好进入第一节课了,它是 [课程 1 OK01][2]
|
||||
|
||||
[^1]: 要查看更完整的操作系统列表,请参照:[操作系统列表 - Wikipedia](http://en.wikipedia.org/wiki/List_of_operating_systems)
|
||||
[^2]: 当然,我简化了普通编程的这种解释,实际上它在很大程度上取决于语言和机器。感兴趣的话,参见 [编译器 - Wikipedia](http://en.wikipedia.org/wiki/Compiler)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/introduction.html
|
||||
|
||||
作者:[Robert Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.cl.cam.ac.uk/~rdm34
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/compiling.png
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html
|
||||
@@ -0,0 +1,233 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10458-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 1 OK01)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 1 OK01
|
||||
======
|
||||
|
||||
OK01 课程讲解了树莓派如何入门,以及在树莓派上如何启用靠近 RCA 和 USB 端口的 OK 或 ACT 的 LED 指示灯。这个指示灯最初是为了指示 OK 状态的,但它在第二版的树莓派上被改名为 ACT。
|
||||
|
||||
### 1、入门
|
||||
|
||||
我们假设你已经访问了[下载][1]页面,并且已经获得了必需的 GNU 工具链。也下载了一个称为操作系统模板的文件。请下载这个文件并在一个新目录中解开它。
|
||||
|
||||
### 2、开始
|
||||
|
||||
现在,你已经展开了这个模板文件,在 `source` 目录中创建一个名为 `main.s` 的文件。这个文件包含了这个操作系统的代码。具体来看,这个文件夹的结构应该像下面这样:
|
||||
|
||||
```
|
||||
build/
|
||||
(empty)
|
||||
source/
|
||||
main.s
|
||||
kernel.ld
|
||||
LICENSE
|
||||
Makefile
|
||||
```
|
||||
|
||||
用文本编辑器打开 `main.s` 文件,这样我们就可以输入汇编代码了。树莓派使用了称为 ARMv6 的汇编代码变体,这就是我们即将要写的汇编代码类型。
|
||||
|
||||
> 扩展名为 `.s` 的文件一般是汇编代码,需要记住的是,在这里它是 ARMv6 的汇编代码。
|
||||
|
||||
首先,我们复制下面的这些命令。
|
||||
|
||||
```
|
||||
.section .init
|
||||
.globl _start
|
||||
_start:
|
||||
```
|
||||
|
||||
实际上,上面这些指令并没有在树莓派上做任何事情,它们是提供给汇编器的指令。汇编器是一个转换程序,它将我们能够理解的汇编代码转换成树莓派能够理解的机器代码。在汇编代码中,每个行都是一个新的命令。上面的第一行告诉汇编器 [^1] 在哪里放我们的代码。我们提供的模板中将它放到一个名为 `.init` 的节中的原因是,它是输出的起始点。这很重要,因为我们希望确保我们能够控制哪个代码首先运行。如果不这样做,首先运行的代码将是按字母顺序排在前面的代码!`.section` 命令简单地告诉汇编器,哪个节中放置代码,从这个点开始,直到下一个 `.section` 或文件结束为止。
|
||||
|
||||
```
|
||||
在汇编代码中,你可以跳行、在命令前或后放置空格去提升可读性。
|
||||
```
|
||||
|
||||
接下来两行是停止一个警告消息,它们并不重要。[^2]
|
||||
|
||||
### 3、第一行代码
|
||||
|
||||
现在,我们正式开始写代码。计算机执行汇编代码时,是简单地一行一行按顺序执行每个指令,除非明确告诉它不这样做。每个指令都是开始于一个新行。
|
||||
|
||||
复制下列指令。
|
||||
|
||||
```
|
||||
ldr r0,=0x20200000
|
||||
```
|
||||
|
||||
> `ldr reg,=val` 将数字 `val` 加载到名为 `reg` 的寄存器中。
|
||||
|
||||
那是我们的第一个命令。它告诉处理器将数字 `0x20200000` 保存到寄存器 `r0` 中。在这里我需要去回答两个问题,<ruby>寄存器<rt>register</rt></ruby>是什么?`0x20200000` 是一个什么样的数字?
|
||||
|
||||
寄存器在处理器中就是一个极小的内存块,它是处理器保存正在处理的数字的地方。处理器中有很多寄存器,很多都有专门的用途,我们在后面会一一接触到它们。最重要的有十三个(命名为 `r0`、`r1`、`r2`、…、`r9`、`r10`、`r11`、`r12`),它们被称为通用寄存器,你可以使用它们做任何计算。由于是写我们的第一行代码,我们在示例中使用了 `r0`,当然你可以使用它们中的任何一个。只要后面始终如一就没有问题。
|
||||
|
||||
> 树莓派上的一个单独的寄存器能够保存任何介于 `0` 到 `4,294,967,295`(含)之间的任意整数,它可能看起来像一个很大的内存,实际上它仅有 32 个二进制比特。
|
||||
|
||||
`0x20200000` 确实是一个数字。只不过它是以十六进制表示的。下面的内容详细解释了十六进制的相关信息:
|
||||
|
||||
> 延伸阅读:十六进制解释
|
||||
|
||||
> 十六进制是另一种表示数字的方式。你或许只知道十进制的数字表示方法,十进制共有十个数字:`0`、`1`、`2`、`3`、`4`、`5`、`6`、`7`、`8` 和 `9`。十六进制共有十六个数字:`0`、`1`、`2`、`3`、`4`、`5`、`6`、`7`、`8`、`9`、`a`、`b`、`c`、`d`、`e` 和 `f`。
|
||||
|
||||
> 你可能还记得十进制是如何用位制来表示的。即最右侧的数字是个位,紧接着的左边一位是十位,再接着的左边一位是百位,依此类推。也就是说,它的值是 100 × 百位的数字,再加上 10 × 十位的数字,再加上 1 × 个位的数字。
|
||||
|
||||
> ![567 is 5 hundreds, 6 tens and 7 units.][2]
|
||||
|
||||
> 从数学的角度来看,我们可以发现规律,最右侧的数字是 10<sup>0</sup> = 1s,紧接着的左边一位是 10<sup>1</sup> = 10s,再接着是 10<sup>2</sup> = 100s,依此类推。我们设定在系统中,0 是最低位,紧接着是 1,依此类推。但如果我们使用一个不同于 10 的数字为幂底会是什么样呢?我们在系统中使用的十六进制就是这样的一个数字。
|
||||
|
||||
> ![567 is 5x10^2+6x10^1+7x10^0][3]
|
||||
|
||||
> ![567 = 5x10^2+6x10^1+7x10^0 = 2x16^2+3x16^1+7x16^0][4]
|
||||
|
||||
> 上面的数学等式表明,十进制的数字 567 等于十六进制的数字 237。通常我们需要在系统中明确它们,我们使用下标 <sub>10</sub> 表示它是十进制数字,用下标 <sub>16</sub> 表示它是十六进制数字。由于在汇编代码中写上下标的小数字很困难,因此我们使用 0x 来表示它是一个十六进制的数字,因此 0x237 的意思就是 237<sub>16</sub> 。
|
||||
|
||||
> 那么,后面的 `a`、`b`、`c`、`d`、`e` 和 `f` 又是什么呢?好问题!在十六进制中为了能够写每个数字,我们就需要额外的东西。例如 9<sub>16</sub> = 9×16<sup>0</sup> = 9<sub>10</sub> ,但是 10<sub>16</sub> = 1×16<sup>1</sup> + 1×16<sup>0</sup> = 16<sub>10</sub> 。因此,如果我们只使用 0、1、2、3、4、5、6、7、8 和 9,我们就无法写出 10<sub>10</sub> 、11<sub>10</sub> 、12<sub>10</sub> 、13<sub>10</sub> 、14<sub>10</sub> 、15<sub>10</sub> 。因此我们引入了 6 个新的数字,这样 a<sub>16</sub> = 10<sub>10</sub> 、b<sub>16</sub> = 11<sub>10</sub> 、c<sub>16</sub> = 12<sub>10</sub> 、d<sub>16</sub> = 13<sub>10</sub> 、e<sub>16</sub> = 14<sub>10</sub> 、f<sub>16</sub> = 15<sub>10</sub> 。
|
||||
|
||||
> 所以,我们就有了另一种写数字的方式。但是我们为什么要这么麻烦呢?好问题!由于计算机总是工作在二进制中,事实证明,十六进制是非常有用的,因为每个十六进制数字正好是四个二进制数字的长度。这种方法还有另外一个好处,那就是许多计算机的数字都是十六进制的整数倍,而不是十进制的整数倍。比如,我在上面的汇编代码中使用的一个数字 20200000<sub>16</sub> 。如果我们用十进制来写,它就是一个不太好记住的数字 538968064<sub>10</sub> 。
|
||||
|
||||
> 我们可以用下面的简单方法将十进制转换成十六进制:
|
||||
|
||||
> ![Conversion example][5]
|
||||
|
||||
> 1. 我们以十进制数字 567 为例来说明。
|
||||
> 2. 将十进制数字 567 除以 16 并计算其余数。例如 567 ÷ 16 = 35 余数为 7。
|
||||
> 3. 在十六进制中余数就是答案中的最后一位数字,在我们的例子中它是 7。
|
||||
> 4. 重复第 2 步和第 3 步,直到除法结果的整数部分为 0。例如 35 ÷ 16 = 2 余数为 3,因此 3 就是答案中的下一位。2 ÷ 16 = 0 余数为 2,因此 2 就是答案的接下来一位。
|
||||
> 5. 一旦除法结果的整数部分为 0 就结束了。答案就是反序的余数,因此 567<sub>10</sub> = 237<sub>16</sub>。
|
||||
|
||||
> 转换十六进制数字为十进制,也很容易,将数字展开即可,因此 237<sub>16</sub> = 2×16<sup>2</sup> + 3×16<sup>1</sup> +7 ×16<sup>0</sup> = 2×256 + 3×16 + 7×1 = 512 + 48 + 7 = 567。
|
||||
|
||||
因此,我们所写的第一个汇编命令是将数字 20200000<sub>16</sub> 加载到寄存器 `r0` 中。那个命令看起来似乎没有什么用,但事实并非如此。在计算机中,有大量的内存块和设备。为了能够访问它们,我们给每个内存块和设备指定了一个地址。就像邮政地址或网站地址一样,它用于标识我们想去访问的内存块或设备的位置。计算机中的地址就是一串数字,因此上面的数字 20200000<sub>16</sub> 就是 GPIO 控制器的地址。这个地址是由制造商的设计所决定的,他们也可以使用其它地址(只要不与其它的冲突即可)。我之所以知道这个地址是 GPIO 控制器的地址是因为我看了它的手册,[^3] 地址的使用没有专门的规范(除了它们都是以十六进制表示的大数以外)。
|
||||
|
||||
### 4、启用输出
|
||||
|
||||
![A diagram showing key parts of the GPIO controller.][6]
|
||||
|
||||
阅读了手册可以得知,我们需要给 GPIO 控制器发送两个消息。我们必须用它的语言告诉它,如果我们这样做了,它将非常乐意实现我们的意图,去打开 OK 的 LED 指示灯。幸运的是,它是一个非常简单的芯片,为了让它能够理解我们要做什么,只需要给它设定几个数字即可。
|
||||
|
||||
```
|
||||
mov r1,#1
|
||||
lsl r1,#18
|
||||
str r1,[r0,#4]
|
||||
```
|
||||
|
||||
> `mov reg,#val` 将数字 `val` 放到名为 `reg` 的寄存器中。
|
||||
|
||||
> `lsl reg,#val` 将寄存器 `reg` 中的二进制操作数左移 `val` 位。
|
||||
|
||||
> `str reg,[dest,#val]` 将寄存器 `reg` 中的数字保存到地址 `dest + val` 上。
|
||||
|
||||
这些命令的作用是在 GPIO 的第 16 号插针上启用输出。首先我们在寄存器 `r1` 中获取一个必需的值,接着将这个值发送到 GPIO 控制器。因此,前两个命令是尝试取值到寄存器 `r1` 中,我们可以像前面一样使用另一个命令 `ldr` 来实现,但 `lsl` 命令对我们后面能够设置任何给定的 GPIO 针比较有用,因此从一个公式中推导出值要比直接写入来好一些。表示 OK 的 LED 灯是直接连线到 GPIO 的第 16 号针脚上的,因此我们需要发送一个命令去启用第 16 号针脚。
|
||||
|
||||
寄存器 `r1` 中的值是启用 LED 针所需要的。第一行命令将数字 1<sub>10</sub> 放到 `r1` 中。在这个操作中 `mov` 命令要比 `ldr` 命令快很多,因为它不需要与内存交互,而 `ldr` 命令是将需要的值从内存中加载到寄存器中。尽管如此,`mov` 命令仅能用于加载某些值。[^4] 在 ARM 汇编代码中,基本上每个指令都使用一个三字母代码表示。它们被称为助记词,用于表示操作的用途。`mov` 是 “move” 的简写,而 `ldr` 是 “load register” 的简写。`mov` 是将第二个参数 `#1` 移动到前面的 `r1` 寄存器中。一般情况下,`#` 肯定是表示一个数字,但我们已经看到了不符合这种情况的一个反例。
|
||||
|
||||
第二个指令是 `lsl`(逻辑左移)。它的意思是将第一个参数的二进制操作数向左移第二个参数所表示的位数。在这个案例中,将 1<sub>10</sub> (即 1<sub>2</sub> )向左移 18 位(将它变成 1000000000000000000<sub>2</sub>=262144<sub>10</sub> )。
|
||||
|
||||
如果你不熟悉二进制表示法,可以看下面的内容:
|
||||
|
||||
> 延伸阅读: 二进制解释
|
||||
|
||||
> 与十六进制一样,二进制是写数字的另一种方法。在二进制中只有两个数字,即 `0` 和 `1`。它在计算机中非常有用,因为我们可以用电路来实现它,即电流能够通过电路表示为 `1`,而电流不能通过电路表示为 `0`。这就是计算机能够完成真实工作和做数学运算的原理。尽管二进制只有两个数字,但它却能够表示任何一个数字,只是写起来有点长而已。
|
||||
|
||||
> ![567 in decimal = 1000110111 in binary][7]
|
||||
|
||||
> 这个图片展示了 567<sub>10</sub> 的二进制表示是 1000110111<sub>2</sub> 。我们使用下标 2 来表示这个数字是用二进制写的。
|
||||
|
||||
> 我们在汇编代码中大量使用二进制的其中一个巧合之处是,数字可以很容易地被 `2` 的幂(即 `1`、`2`、`4`、`8`、`16`)乘或除。通常乘法和除法都是非常难的,而在某些特殊情况下却变得非常容易,所以二进制非常重要。
|
||||
|
||||
> ![13*4 = 52, 1101*100=110100][8]
|
||||
|
||||
> 将一个二进制数字左移 `n` 位就相当于将这个数字乘以 2<sup>n</sup>。因此,如果我们想将一个数乘以 4,我们只需要将这个数字左移 2 位。如果我们想将它乘以 256,我们只需要将它左移 8 位。如果我们想将一个数乘以 12 这样的数字,我们可以有一个替代做法,就是先将这个数乘以 8,然后再将那个数乘以 4,最后将两次相乘的结果相加即可得到最终结果(N × 12 = N × (8 + 4) = N × 8 + N × 4)。
|
||||
|
||||
> ![53/16 = 3, 110100/10000=11][9]
|
||||
|
||||
> 右移一个二进制数 `n` 位就相当于这个数除以 2<sup>n</sup> 。在右移操作中,除法的余数位将被丢弃。不幸的是,如果对一个不能被 2 的幂次方除尽的二进制数字做除法是非常难的,这将在 [课程 9 Screen04][10] 中讲到。
|
||||
|
||||
> ![Binary Terminology][11]
|
||||
|
||||
> 这个图展示了二进制常用的术语。一个<ruby>比特<rt>bit</rt></ruby>就是一个单独的二进制位。一个“<ruby>半字节<rt>nibble</rt></ruby>“ 是 4 个二进制位。一个<ruby>字节<rt>byte</rt></ruby>是 2 个半字节,也就是 8 个比特。<ruby>半字<rt>half</rt></ruby>是指一个字长度的一半,这里是 2 个字节。<ruby>字<rt>word</rt></ruby>是指处理器上寄存器的大小,因此,树莓派的字长是 4 字节。按惯例,将一个字最高有效位标识为 31,而将最低有效位标识为 0。顶部或最高位表示最高有效位,而底部或最低位表示最低有效位。一个 kilobyte(KB)就是 1000 字节,一个 megabyte 就是 1000 KB。这样表示会导致一些困惑,到底应该是 1000 还是 1024(二进制中的整数)。鉴于这种情况,新的国际标准规定,一个 KB 等于 1000 字节,而一个 Kibibyte(KiB)是 1024 字节。一个 Kb 是 1000 比特,而一个 Kib 是 1024 比特。
|
||||
|
||||
> 树莓派默认采用小端法,也就是说,从你刚才写的地址上加载一个字节时,是从一个字的低位字节开始加载的。
|
||||
|
||||
再强调一次,我们只有去阅读手册才能知道我们所需要的值。手册上说,GPIO 控制器中有一个 24 字节的集合,由它来决定 GPIO 针脚的设置。第一个 4 字节与前 10 个 GPIO 针脚有关,第二个 4 字节与接下来的 10 个针脚有关,依此类推。总共有 54 个 GPIO 针脚,因此,我们需要 6 个 4 字节的一个集合,总共是 24 个字节。在每个 4 字节中,每 3 个比特与一个特定的 GPIO 针脚有关。我们想去启用的是第 16 号 GPIO 针脚,因此我们需要去设置第二组 4 字节,因为第二组的 4 字节用于处理 GPIO 针脚的第 10-19 号,而我们需要第 6 组 3 比特,它在上面的代码中的编号是 18(6×3)。
|
||||
|
||||
最后的 `str`(“store register”)命令去保存第一个参数中的值,将寄存器 `r1` 中的值保存到后面的表达式计算出来的地址上。这个表达式可以是一个寄存器,在上面的例子中是 `r0`,我们知道 `r0` 中保存了 GPIO 控制器的地址,而另一个值是加到它上面的,在这个例子中是 `#4`。它的意思是将 GPIO 控制器地址加上 `4` 得到一个新的地址,并将寄存器 `r1` 中的值写到那个地址上。那个地址就是我们前面提到的第二组 4 字节的位置,因此,我们发送我们的第一个消息到 GPIO 控制器上,告诉它准备启用 GPIO 第 16 号针脚的输出。
|
||||
|
||||
### 5、生命的信号
|
||||
|
||||
现在,LED 已经做好了打开准备,我们还需要实际去打开它。意味着需要给 GPIO 控制器发送一个消息去关闭 16 号针脚。是的,你没有看错,就是要发送一个关闭的消息。芯片制造商认为,在 GPIO 针脚关闭时打开 LED 更有意义。[^5] 硬件工程师经常做这种反常理的决策,似乎是为了让操作系统开发者保持警觉。可以认为是给自己的一个警告。
|
||||
|
||||
```
|
||||
mov r1,#1
|
||||
lsl r1,#16
|
||||
str r1,[r0,#40]
|
||||
```
|
||||
|
||||
希望你能够认识上面全部的命令,先不要管它的值。第一个命令和前面一样,是将值 `1` 推入到寄存器 `r1` 中。第二个命令是将二进制的 `1` 左移 16 位。由于我们是希望关闭 GPIO 的 16 号针脚,我们需要在下一个消息中将第 16 比特设置为 1(想设置其它针脚只需要改变相应的比特位即可)。最后,我们写这个值到 GPIO 控制器地址加上 40<sub>10</sub> 的地址上,这将使那个针脚关闭(加上 28 将打开针脚)。
|
||||
|
||||
### 6、永远幸福快乐
|
||||
|
||||
似乎我们现在就可以结束了,但不幸的是,处理器并不知道我们做了什么。事实上,处理器只要通电,它就永不停止地运转。因此,我们需要给它一个任务,让它一直运转下去,否则,树莓派将进入休眠(本示例中不会,LED 灯会一直亮着)。
|
||||
|
||||
```
|
||||
loop$:
|
||||
b loop$
|
||||
|
||||
```
|
||||
|
||||
> `name:` 下一行的名字。
|
||||
|
||||
> `b label` 下一行将去标签 `label` 处运行。
|
||||
|
||||
第一行不是一个命令,而是一个标签。它给下一行命名为 `loop$`,这意味着我们能够通过名字来指向到该行。这就称为一个标签。当代码被转换成二进制后,标签将被丢弃,但这对我们通过名字而不是数字(地址)找到行比较有用。按惯例,我们使用一个 `$` 表示这个标签只对这个代码块中的代码起作用,让其它人知道,它不对整个程序起作用。`b`(“branch”)命令将去运行指定的标签中的命令,而不是去运行它后面的下一个命令。因此,下一行将再次去运行这个 `b` 命令,这将导致永远循环下去。因此处理器将进入一个无限循环中,直到它安全关闭为止。
|
||||
|
||||
代码块结尾的一个空行是有意这样写的。GNU 工具链要求所有的汇编代码文件都是以空行结束的,因此,这就可以你确实是要结束了,并且文件没有被截断。如果你不这样处理,在汇编器运行时,你将收到烦人的警告。
|
||||
|
||||
### 7、树莓派上场
|
||||
|
||||
由于我们已经写完了代码,现在,我们可以将它上传到树莓派中了。在你的计算机上打开一个终端,改变当前工作目录为 `source` 文件夹的父级目录。输入 `make` 然后回车。如果报错,请参考排错章节。如果没有报错,你将生成三个文件。 `kernel.img` 是你的编译后的操作系统镜像。`kernel.list` 是你写的汇编代码的一个清单,它实际上是生成的。这在将来检查程序是否正确时非常有用。`kernel.map` 文件包含所有标签结束位置的一个映射,这对于跟踪值非常有用。
|
||||
|
||||
为安装你的操作系统,需要先有一个已经安装了树莓派操作系统的 SD 卡。如果你浏览 SD 卡中的文件,你应该能看到一个名为 `kernel.img` 的文件。将这个文件重命名为其它名字,比如 `kernel_linux.img`。然后,复制你编译的 `kernel.img` 文件到 SD 卡中原来的位置,这将用你的操作系统镜像文件替换现在的树莓派操作系统镜像。想切换回来时,只需要简单地删除你自己的 `kernel.img` 文件,然后将前面重命名的文件改回 `kernel.img` 即可。我发现,保留一个原始的树莓派操作系统的备份是非常有用的,万一你要用到它呢。
|
||||
|
||||
将这个 SD 卡插入到树莓派,并打开它的电源。这个 OK 的 LED 灯将亮起来。如果不是这样,请查看故障排除页面。如果一切如愿,恭喜你,你已经写出了你的第一个操作系统。[课程 2 OK02][12] 将指导你让 LED 灯闪烁和关闭闪烁。
|
||||
|
||||
[^1]: 是的,我说错了,它告诉的是链接器,它是另一个程序,用于将汇编器转换过的几个代码文件链接到一起。直接说是汇编器也没有大问题。
|
||||
[^2]: 其实它们对你很重要。由于 GNU 工具链主要用于开发操作系统,它要求入口点必须是名为 `_start` 的地方。由于我们是开发一个操作系统,无论什么时候,它总是从 `_start` 开时的,而我们可以使用 `.section .init` 命令去设置它。因此,如果我们没有告诉它入口点在哪里,就会使工具链困惑而产生警告消息。所以,我们先定义一个名为 `_start` 的符号,它是所有人可见的(全局的),紧接着在下一行生成符号 `_start` 的地址。我们很快就讲到这个地址了。
|
||||
[^3]: 本教程的设计减少了你阅读树莓派开发手册的难度,但是,如果你必须要阅读它,你可以在这里 [SoC-Peripherals.pdf](https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads/SoC-Peripherals.pdf) 找到它。由于添加了混淆,手册中 GPIO 使用了不同的地址系统。我们的操作系统中的地址 0x20200000 对应到手册中是 0x7E200000。
|
||||
[^4]: `mov` 能够加载的值只有前 8 位是 `1` 的二进制表示的值。换句话说就是一个 0 后面紧跟着 8 个 `1` 或 `0`。
|
||||
[^5]: 一个很友好的硬件工程师是这样向我解释这个问题的:
|
||||
|
||||
原因是现在的芯片都是用一种称为 CMOS 的技术来制成的,它是互补金属氧化物半导体的简称。互补的意思是每个信号都连接到两个晶体管上,一个是使用 N 型半导体的材料制成,它用于将电压拉低,而另一个使用 P 型半导体材料制成,它用于将电压升高。在任何时刻,仅有一个半导体是打开的,否则将会短路。P 型材料的导电性能不如 N 型材料。这意味着三倍大的 P 型半导体材料才能提供与 N 型半导体材料相同的电流。这就是为什么 LED 总是通过降低为低电压来打开它,因为 N 型半导体拉低电压比 P 型半导体拉高电压的性能更强。
|
||||
|
||||
还有一个原因。早在上世纪七十年代,芯片完全是由 N 型材料制成的(NMOS),P 型材料部分使用了一个电阻来代替。这意味着当信号为低电压时,即便它什么事都没有做,芯片仍然在消耗能量(并发热)。你的电话装在口袋里什么事都不做,它仍然会发热并消耗你的电池电量,这不是好的设计。因此,信号设计成 “活动时低”,而不活动时为高电压,这样就不会消耗能源了。虽然我们现在已经不使用 NMOS 了,但由于 N 型材料的低电压信号比 P 型材料的高电压信号要快,所以仍然使用了这种设计。通常在一个 “活动时低” 信号名字上方会有一个条型标记,或者写作 `SIGNAL_n` 或 `/SIGNAL`。但是即便这样,仍然很让人困惑,那怕是硬件工程师,也不可避免这种困惑!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html
|
||||
|
||||
作者:[Robert Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.cl.cam.ac.uk/~rdm34
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal1.png
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal2.png
|
||||
[4]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal3.png
|
||||
[5]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/hexadecimal4.png
|
||||
[6]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/gpioController.png
|
||||
[7]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary1.png
|
||||
[8]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary2.png
|
||||
[9]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary3.png
|
||||
[10]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen04.html
|
||||
[11]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary4.png
|
||||
[12]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok02.html
|
||||
@@ -0,0 +1,68 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10478-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 2 OK02)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok02.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 2 OK02
|
||||
======
|
||||
|
||||
OK02 课程构建于 OK01 课程的基础上,通过不停地打开和关闭 OK 或 ACT LED 指示灯来实现闪烁。假设你已经有了 [课程 1:OK01][1] 操作系统的代码,它将是这一节课的基础。
|
||||
|
||||
### 1、等待
|
||||
|
||||
等待是操作系统开发中非常有用的部分。操作系统经常发现自己无事可做,以及必须要延迟。在这个例子中,我们希望通过等待,让 LED 灯打开、关闭的闪烁可以看到。如果你只是打开和关闭它,你将看到这个视觉效果,因为计算机每秒种可以打开和关闭它好几千次(LCTT 译注:视觉暂留效应会使你难以发觉它的闪烁)。在后面的课程中,我们将看到精确的等待,但是现在,我们只要简单地去消耗时间就足够了。
|
||||
|
||||
```
|
||||
mov r2,#0x3F0000
|
||||
wait1$:
|
||||
sub r2,#1
|
||||
cmp r2,#0
|
||||
bne wait1$
|
||||
```
|
||||
|
||||
> `sub reg,#val` 从寄存器 `reg` 中的值上减去数字 `val`
|
||||
>
|
||||
> `cmp reg,#val` 将寄存器中的值与数字 `val` 进行比较。
|
||||
>
|
||||
> 如果最后的比较结果是不相等,那么执行后缀了 `ne` 的 `b` 命令。
|
||||
|
||||
上面是一个很常见的产生延迟的代码片段,由于每个树莓派基本上是相同的,所以产生的延迟大致也是相同的。它的工作原理是,使用一个 `mov` 命令将值 3F0000<sub>16</sub> 推入到寄存器 `r2` 中,然后将这个值减 1,直到这个值减到 0 为止。在这里使用了三个新命令 `sub`、 `cmp` 和 `bne`。
|
||||
|
||||
`sub` 是减法命令,它只是简单地从第一个参数中的值减去第二个参数中的值。
|
||||
|
||||
`cmp` 是个很有趣的命令。它将第一个参数与第二个参数进行比较,然后将比较结果记录到一个称为当前处理器状态寄存器的专用寄存器中。你其实不用担心它,它记住的只是两个数谁大或谁小,或是相等而已。[^1]
|
||||
|
||||
`bne` 其实是一个伪装的分支命令。在 ARM 汇编语言家族中,任何指令都可以有条件地运行。这意味着如果上一个比较结果是某个确定的结果,那个指令才会运行。这是个非常有意思的技巧,我们在后面将大量使用到它,但在本案例中,我们在 `b` 命令后面的 `ne` 后缀意思是 “只有在上一个比较的结果是值不相等,才去运行该分支”。`ne` 后缀可以使用在任何命令上,其它几个(总共 16 个)条件也是如此,比如 `eq` 表示等于,而 `lt` 表示小于。
|
||||
|
||||
### 2、组合到一起
|
||||
|
||||
上一节讲我提到过,通过将 GPIO 地址偏移量设置为 28(即:`str r1,[r0,#28]`)而不是 40 即可实现 LED 的关闭。因此,你需要去修改课程 OK01 的代码,在打开 LED 后,运行等待代码,然后再关闭 LED,再次运行等待代码,并包含一个回到开始位置的分支。注意,不需要重新启用 GPIO 的 16 号针脚的输出功能,这个操作只需要做一次就可以了。如果你想更高效,我建议你复用 `r1` 寄存器的值。所有课程都一样,你可以在 [下载页面][2] 找到所有的解决方案。需要注意的是,必须保证你的所有标签都是唯一的。当你写了 `wait1$:` 你其它行上的标签就不能再使用 `wait1$` 了。
|
||||
|
||||
在我的树莓派上,它大约是每秒闪两次。通过改变我们所设置的 `r2` 寄存器中的值,可以很轻松地修改它。但是,不幸的是,我不能够精确地预测它的运行速度。如果你的树莓派未按预期正常工作,请查看我们的故障排除页面,如果它正常工作,恭喜你。
|
||||
|
||||
在这个课程中,我们学习了另外两个汇编命令:`sub` 和 `cmp`,同时学习了 ARM 中如何实现有条件运行。
|
||||
|
||||
在下一个课程,[课程 3:OK03][3] 中我们将学习如何编写代码,以及建立一些代码复用的标准,并且如果需要的话,可能会使用 C 或 C++ 来写代码。
|
||||
|
||||
[^1]: 如果你点了这个链接,说明你一定想知道它的具体内容。CPSR 是一个由许多独立的比特位组成的 32 比特寄存器。它有一个位用于表示正数、零和负数。当一个 `cmp` 指令运行后,它从第一个参数上减去第二个参数,然后用这个位记下它的结果是正数、零还是负数。如果是零意味着它们相等(`a-b=0` 暗示着 `a=b`)如果为正数意味着 a 大于 b(`a-b>0` 暗示着 `a>b`),如果为负数意味着小于。还有其它比较指令,但 `cmp` 指令最直观。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok02.html
|
||||
|
||||
作者:[Robert Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.cl.cam.ac.uk/~rdm34
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linux.cn/article-10458-1.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/downloads.html
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok03.html
|
||||
144
published/201901/20150717 The History of Hello World.md
Normal file
144
published/201901/20150717 The History of Hello World.md
Normal file
@@ -0,0 +1,144 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "zzzzzzmj"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-10485-1.html"
|
||||
[#]: subject: "The History of Hello World"
|
||||
[#]: via: "https://www.thesoftwareguild.com/blog/the-history-of-hello-world/"
|
||||
[#]: author: "thussong https://www.thesoftwareguild.com/blog/author/thussong/"
|
||||
|
||||
Hello World 的由来
|
||||
=========
|
||||
|
||||
资深软件开发人员都知道 [Hello World][2] 程序,这是一个能在设备显示器上输出某种变体的 “Hello, World!” 的程序,是学习编程的第一步。在这个编程中只涉及到一些最基本语法的程序,可以用大多数编程语言了来编写。事实上,路易斯安纳理工学院计算机协会(ACM)在最近统计[发现][3]这个程序至少有 204 个版本。
|
||||
|
||||
传统意义上,Hello World 程序是用于说明编码过程是如何工作的,以及确保编程语言或系统能正常运行。它们经常是新手程序员学习的第一个程序,因为即使是经验很少或者没有经验的人也能轻松正确的执行 Hello World。
|
||||
|
||||
首先,Hello World 简单,这就是为什么它经常被用做程序执行成功的晴雨表。如果 Hello World 在该框架中无法有效执行,那么其它更复杂的程序中也可能会失败。正如 [Win-Vector][4] 的一位专家所说,Hello World 实际上是一个对抗性程序。“该作者还说道,‘你的计算机系统能不能工作并不是一目了然,除非我能看到它至少能打印一行文字,否则我不会在上面浪费太多时间。’” Win-Vector 博主 John Mount 说。
|
||||
|
||||
但是这个两词短语在计算机科学领域有着重大的影响。以 Hello World 为基础,新手程序员可以轻松的理解计算机科学原理或元素,而拥有多年编码经验的程序员可以用它来学习编程语言的工作原理,特别是在结构与语法方面。这样的一个小程序,在任何难度的应用程序和几乎所有语言中都有着悠久的历史。
|
||||
|
||||
### 用途
|
||||
|
||||
以上概括了 Hello World 程序的主要用途:这是新手程序员熟悉新语言的一种方式。然而,这些程序不仅仅是对编码世界的介绍。例如,Hello World 可以作为测试,以确保语言的组件(编译器、开发和运行环境)安装正确。因为配置完整的编程工具链的过程复杂而漫长,所以像 Hello World 这样简单的程序通常用作新工具链的首次运行测试。
|
||||
|
||||
根据 Cunningham & Cunningham(C2)的编程顾问所说,在系统设计人员并不预期可以执行代码的地方,黑客经常使用 Hello World 程序作为一个可以通过漏洞执行任意代码的概念验证(POC)。事实上,它是在设备上使用自制内容或者“自酿”的第一步,当[有经验的编码人员][5]正在配置环境或在学习新事物时,他们会通过 Hello World 来验证其行为是否正确。
|
||||
|
||||
它也作为调试过程的一部分,允许程序员检查他们是否正确地编辑了可在运行时修改的程序并重新加载。
|
||||
|
||||
Hello World 的一个更常用的用途是作为基础比较。根据 C2 的 wiki 所讲,程序员可以“比较语言生成的可执行文件的大小,以及程序背后必须存在多少支持的基础设施才能执行。”
|
||||
|
||||
### 开端
|
||||
|
||||
虽然 Hello World 的起源还有些不太明了,不过人们普遍认为它作为测试用语,最早出现在 Brian Kernigham 在 1972 年发布的《<ruby>B 语言简介教程<rt>A Tutorial Introduction to the Language B</rt></ruby>》中。在此文中,该程序的第一个已知版本用于说明外部变量。因为该教程中的前一个例子在终端上打印了 “hi!”,而需要更多的字符常量来表达相对复杂的 “hello,world!”,这是学习过程的下一步。
|
||||
|
||||
在那以后,它还被用于 1974 年的贝尔实验室备忘录,以及 1987 年的《<ruby>C 语言程序设计<rt>The C Programming Language</rt></ruby>》。这两篇著名的文字是让 Hello World 闻名于世的主要原因。在书中的一个例子(第一个,也是最著名的例子)打印了没有大写字母和感叹号的 “hello,world”。此时的 Hello World 几乎只是用于说明语言的一些功能,而不是测试系统是否正常运行。
|
||||
|
||||
在 Kernigham 的关于 B 语言和 C 语言的开创性文章之前,没有真正意义上的第一个程序,甚至直到 1974 年,它也没被广泛使用。著名的 BASIC 教程 “<ruby>我的电脑喜欢我用 BASIC 跟它讲话<rt>My Computer Likes Me,When I Speak BASIC</rt></ruby>”,从一个写一行文本的简单程序开始,不过那句话是 “MY HUMAN UNDERSTANDS ME”,跟如今程序员侃侃而谈的这个双词问候语差的有点远。不过,当 Hello World 被发明后,它就迅速传播,并在 20 世纪 70 年代后变成了众所周知。直到今天它也依然受欢迎。
|
||||
|
||||
### 一个声明,多种语言
|
||||
|
||||
以下是目前正在被使用的一些流行的编程语言中的 Hello World 代码。
|
||||
|
||||
#### Java
|
||||
|
||||
```
|
||||
class HelloWorld {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, world!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### C#
|
||||
|
||||
```
|
||||
using System;
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello, world!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Python
|
||||
|
||||
```
|
||||
print("Hello, world!")
|
||||
```
|
||||
|
||||
#### Ruby
|
||||
|
||||
```
|
||||
puts "Hello, world!"
|
||||
```
|
||||
|
||||
#### Scala
|
||||
|
||||
```
|
||||
object HelloWorld extends App {
|
||||
println("Hello, world!")
|
||||
}
|
||||
```
|
||||
|
||||
#### ASP.NET
|
||||
|
||||
```
|
||||
Response.Write("Hello World!");
|
||||
```
|
||||
|
||||
#### Lisp
|
||||
|
||||
```
|
||||
(princ "Hello, world!")
|
||||
```
|
||||
|
||||
#### Haskell
|
||||
|
||||
```
|
||||
main = putStrLn "Hello, world!"
|
||||
```
|
||||
|
||||
#### Malbolge
|
||||
|
||||
```
|
||||
('&%:9]!~}|z2Vxwv-,POqponl$Hjig%eB@@>}=<M:9wv6WsU2T|nm-,jcL(I&%$#"
|
||||
`CB]V?Tx<uVtT`Rpo3NlF.Jh++FdbCBA@?]!~|4XzyTT43Qsqq(Lnmkj"Fhg${z@>
|
||||
```
|
||||
|
||||
#### Go
|
||||
|
||||
```
|
||||
package main
|
||||
import "fmt"
|
||||
func main() {
|
||||
fmt.Println("Hello, world!")
|
||||
}
|
||||
```
|
||||
|
||||
### 如今的 Hello world:各种形式下的标准实践
|
||||
|
||||
在现在的编程语言中,Hello World 有着不同的复杂程度。例如,Go 语言中引入一个多语言版的 Hello World 程序,XL 则会提供一个具有图形、可旋转的 3D 版本。一些编程语言,像 Ruby、Python,仅仅需要一个语句去打印“Hello World”,但是低级汇编语言则需要几个命令才能做到这样。现在的编程语言还引入对标点符号和大小写的变化,包括是否有逗号或者感叹号,以及两个词的大写形式。举个例子,当系统只支持大写字母,会呈现像“HELLO WORLD”的短语。值得纪念的第一个 Malbolge 程序打印出了“HEllO WORld”(LCTT 译注:Malbolge 是最难的编程语言之一。事实上,在它诞生后,花了 2 年时间才完成第一个 Malbolge 程序)。它的变体跨越了原本的字面意思。像 Lisp、Haskell 这样函数语言,用阶乘程序替代了 Hello World,从而注重递归技术。这与原来的示例不同,后者更强调 I/O 以及产生的副作用。
|
||||
|
||||
随着现在的编程语言越来越复杂,Hello World 比以往显得更加重要。作为测试和教学工具,它已经成为程序员测试配置的编程环境的标准方法。没有人能确切说出为什么 Hello World 能在快速创新著称的行业中经受住时间的考验,但是它又确实留下来了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.thesoftwareguild.com/blog/the-history-of-hello-world/
|
||||
|
||||
作者:[thussong][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zzzzzzmj](https://github.com/zzzzzzmj)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.thesoftwareguild.com/blog/author/thussong/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.thesoftwareguild.com%2Fblog%2Fthe-history-of-hello-world%2F&title=The%20History%20of%20Hello%20World
|
||||
[2]: http://en.wikipedia.org/wiki/%22Hello,_World!%22_program
|
||||
[3]: http://whatis.techtarget.com/definition/Hello-World
|
||||
[4]: http://www.win-vector.com/blog/2008/02/hello-world-an-instance-rhetoric-in-computer-science/
|
||||
[5]: http://c2.com/cgi/wiki?HelloWorld
|
||||
@@ -0,0 +1,136 @@
|
||||
下载 Linux 游戏的最佳网站
|
||||
======
|
||||
|
||||
> 新接触 Linux 游戏并想知道从哪里来 **下载 Linux 游戏**?我们列出了最好的资源,在这里你既能 **下载免费的 Linux 游戏** ,也能购买优质的 Linux 游戏。
|
||||
|
||||
Linux 和游戏?从前,很难想象这两者走到一起。然而随着时间流逝,很多事情都在变化。到如今,有成千上万在 Linux 上可以玩的游戏,而大公司和独立开发者们正在开发更多的游戏。
|
||||
|
||||
[在 Linux 上玩游戏][1] 现在已经是现实。今天我们将去看看,你在哪里可以找到 Linux 平台游戏、搜索到你喜欢的游戏。
|
||||
|
||||
### 在哪里来下载 Linux 游戏?
|
||||
|
||||
![下载 Linux 游戏的网站][2]
|
||||
|
||||
首先,看看你的 Linux 发行版的软件中心(如果有的话)。在这里你也能找到大量的游戏。
|
||||
|
||||
但是,这不意味着你应该将自己的视野局限于软件中心上。让我们来为你列出一些可以下载 Linux 游戏网站。
|
||||
|
||||
#### 1. Steam
|
||||
|
||||
如果你是老练的玩家,你应该听过 Steam。如果你还不知道的话,没错,Steam 在 Linux 上也是可用的。Steam 推荐运行在 Ubuntu 上,但是它也能运行在其它主要的发行版上。如果你真的对 Steam 很狂热,这里甚至还有一个玩 Steam 游戏的专用操作系统:[SteamOS][3]。我们在上一年 [最佳的 Linux 游戏发行版][4] 文章中提及了它。
|
||||
|
||||
![Steam 商店][5]
|
||||
|
||||
Steam 有最大的 Linux 游戏商店。当写这篇文章的时候,在 Linux 平台上,确切地说有 3487 款游戏,这真的是很多了。你可以从宽广的类型中寻找游戏。至于 [数字版权管理(DRM)][6],大多数的 Steam 游戏都有某种 DRM 。
|
||||
|
||||
对于使用 Steam ,要么你必须在你的 Linux 系统上安装 [Steam 客户端][7],要么使用 SteamOS。Steam 的一个优势是,在初始化安装后,对于大多数的游戏,你不需要担心依赖关系和复杂的安装过程。 Steam 客户端将为你做这些繁重的任务。
|
||||
|
||||
- [Steam 商店][8]
|
||||
|
||||
#### 2. GOG
|
||||
|
||||
如果你只对免 DRM 的游戏感兴趣,GOG 收集了相当多的这种游戏。此刻,GOG 在它们的库中有 1978 种免 DRM 游戏。GOG 因它大量收集了免 DRM 游戏而闻名。
|
||||
|
||||
![GOG 商店][9]
|
||||
|
||||
GOG 游戏官方支持 Ubuntu LTS 版本和 Linux Mint。所以,Ubuntu 和它的衍生版在安装它们时将没有问题。在其他发行版上安装它们时可能需要一些额外的工作,例如,你需要安装正确的依赖关系。
|
||||
|
||||
从 GOG 中下载游戏,你不需要额外的客户端。所有购买的游戏都可在你的账户区内找到。你可以使用你最爱的下载管理器直接下载它们。
|
||||
|
||||
- [GOG 商店][10]
|
||||
|
||||
#### 3. Humble 商店
|
||||
|
||||
Humble 商店是另一个你可以查找各种各样 Linux 游戏的地方。在 Humble 商店中有免 DRM 和非免 DRM 的游戏。非免 DRM 游戏通常来自 Steam。在 Humble 商店中,当前有超过 1826 款 Linux 游戏。
|
||||
|
||||
![Humble 商店][11]
|
||||
|
||||
Humble 商店因另一个原因而著名。它们有一个被称为 [Humble 独立包][12]的活动,其中打包提供了一批游戏,带有令人不可抗拒的限时优惠。关于 Humble 的另一件事是,当你购买时,你的购买金额的 10% 将捐给慈善机构。
|
||||
|
||||
Humble 不需要额外的客户端来下载它们的游戏。
|
||||
|
||||
- [Humble 商店][13]
|
||||
|
||||
#### 4. itch.io 商店
|
||||
|
||||
itch.io 是给独立数字创作者的一个开放市场,其致力于独立视频游戏。itch.io 有一些你能找到的最有趣、最独特的游戏。在 itch.io 的大多数游戏是免 DRM 的。
|
||||
|
||||
![itch.io 商店][14]
|
||||
|
||||
现今,itch.io 在它的商店中有 9514 款 Linux 平台的游戏。
|
||||
|
||||
itch.io 有它自己的 [客户端][15],可以轻松地下载、安装、更新和玩它们的游戏。
|
||||
|
||||
- [itch.io 商店][16]
|
||||
|
||||
#### 5. LGDB
|
||||
|
||||
LGDB 是 <ruby>Linux 游戏数据库<rt>Linux Game DataBase</rt></ruby>的缩写。虽然从技术上说它不是一个游戏商店,它收集有大量的 Linux 游戏,以及关于它们的各种各样的信息。每一款游戏都有你可以在哪里找到它们的链接。
|
||||
|
||||
![Linux 游戏数据库][17]
|
||||
|
||||
如今,在该数据库中有 2046 款游戏。它们也有很长的关于 [模拟器][18]、[工具][19] 和 [游戏引擎][20] 的列表。
|
||||
|
||||
- [LGDB][21]
|
||||
|
||||
#### 6. Game Jolt 商店
|
||||
|
||||
Game Jolt 有一个非常可观的集合,在它的库藏中大约有 5000 个 Linux 独立游戏。
|
||||
|
||||
![Game Jolt 商店][22]
|
||||
|
||||
Game Jolt 有一个(预览版)[客户端][23],可用于轻松地下载、安装、更新和玩游戏。
|
||||
|
||||
- [Game Jolt 商店][24]
|
||||
|
||||
### 其他
|
||||
|
||||
有很多其他的销售 Linux 游戏的商店。也有很多你能找到免费游戏的地方。这是它们中的两个:
|
||||
|
||||
* [Bundle Stars][25]:当前有 814 个 Linux 游戏和 31 个游戏包。
|
||||
* [GamersGate][26]:现在有 595 个 Linux 游戏。既有免 DRM 的,也有非免 DRM 的。
|
||||
|
||||
#### 应用商店、软件中心 & 软件库
|
||||
|
||||
Linux 发行版有它们自己的应用商店或软件库。尽管不是很多,但是在这里你也能找到各种各样的游戏。
|
||||
|
||||
今天到此为止。你知道这里有这么多 Linux 上可玩的游戏吗?你使用一些其他的网站来下载 Linux 游戏吗?与我们分享你的收藏。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/download-linux-games/
|
||||
|
||||
作者:[Munif Tanjim][a]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/munif/
|
||||
[1]:https://linux.cn/article-7316-1.html
|
||||
[2]:https://itsfoss.com/wp-content/uploads/2017/05/download-linux-games-800x450.jpg
|
||||
[3]:http://store.steampowered.com/steamos/
|
||||
[4]:https://itsfoss.com/linux-gaming-distributions/
|
||||
[5]:https://itsfoss.com/wp-content/uploads/2017/05/Steam-Store-800x382.jpg
|
||||
[6]:https://www.wikiwand.com/en/Digital_rights_management
|
||||
[7]:http://store.steampowered.com/about/
|
||||
[8]:http://store.steampowered.com/linux
|
||||
[9]:https://itsfoss.com/wp-content/uploads/2017/05/GOG-Store-800x366.jpg
|
||||
[10]:https://www.gog.com/games?system=lin_mint,lin_ubuntu
|
||||
[11]:https://itsfoss.com/wp-content/uploads/2017/05/The-Humble-Store-800x393.jpg
|
||||
[12]:https://www.humblebundle.com/?partner=itsfoss
|
||||
[13]:https://www.humblebundle.com/store?partner=itsfoss
|
||||
[14]:https://itsfoss.com/wp-content/uploads/2017/05/itch.io-Store-800x485.jpg
|
||||
[15]:https://itch.io/app
|
||||
[16]:https://itch.io/games/platform-linux
|
||||
[17]:https://itsfoss.com/wp-content/uploads/2017/05/LGDB-800x304.jpg
|
||||
[18]:https://lgdb.org/emulators
|
||||
[19]:https://lgdb.org/tools
|
||||
[20]:https://lgdb.org/engines
|
||||
[21]:https://lgdb.org/games
|
||||
[22]:https://itsfoss.com/wp-content/uploads/2017/05/GameJolt-Store-800x357.jpg
|
||||
[23]:http://gamejolt.com/client
|
||||
[24]:http://gamejolt.com/games/best?os=linux
|
||||
[25]:https://www.bundlestars.com/en/games?page=1&platforms=Linux
|
||||
[26]:https://www.gamersgate.com/games?state=available
|
||||
[27]:https://itsfoss.com/linux-gaming-problems/
|
||||
115
published/201901/20170921 The Rise and Rise of JSON.md
Normal file
115
published/201901/20170921 The Rise and Rise of JSON.md
Normal file
@@ -0,0 +1,115 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (runningwater)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (The Rise and Rise of JSON)
|
||||
[#]: via: (https://twobithistory.org/2017/09/21/the-rise-and-rise-of-json.html)
|
||||
[#]: author: (https://twobithistory.org)
|
||||
[#]: url: (https://linux.cn/article-10440-1.html)
|
||||
|
||||
JSON 的兴起与崛起
|
||||
======
|
||||
|
||||
JSON 已经占领了全世界。当今,任何两个应用程序彼此通过互联网通信时,可以打赌它们在使用 JSON。它已被所有大型企业所采用:十大最受欢迎的 web API 接口列表中(主要由 Google、Facebook 和 Twitter 提供),仅仅只有一个 API 接口是以 XML 的格式开放数据的。[^1] 这个列表中的 Twitter API 为此做了一个鲜活的注脚:其对 XML 格式的支持到 2013 年结束,其时发布的新版本的 API 取消 XML 格式,转而仅使用 JSON。JSON 也在程序编码级别和文件存储上被广泛采用:在 Stack Overflow(LCTT 译注:一个面向程序员的问答网站)上,现在更多的是关于 JSON 的问题,而不是其他的数据交换格式。[^2]
|
||||
|
||||
![][1]
|
||||
|
||||
XML 仍然在很多地方存在。网络上它被用于 SVG 和 RSS / Atom 信息流。Android 开发者想要获得用户权限许可时,需要在其 APP 的 `manifest` 文件中声明 —— 此文件是 XML 格式的。XML 的替代品也不仅仅只有 JSON,现在有很多人在使用 YAML 或 Google 的 Protocol Buffers 等技术,但这些技术的受欢迎程度远不如 JSON。目前来看,JSON 是应用程序在网络之间通信的首选协议格式。
|
||||
|
||||
考虑到自 2005 年来 Web 编程世界就垂涎于 “异步 JavaScript 和 XML” 而非 “异步 JavaScript 和 JSON” 的技术潜力,你可以发现 JSON 的主导地位是如此的让人惊讶。当然了,这可能与这两种通信格式的受欢迎程度无关,而仅反映出缩写 “AJAX” 似乎比 “AJAJ” 更具吸引力。但是,即使在 2005 年有些人(实际上没有太多人)已经用 JSON 来取代 XML 了,我们不禁要问为什么 XML 的噩运来的如此之快,以至于短短十来年,“异步 JavaScript 和 XML” 这个名称就成为一个很讽刺的误称。那这十来年发生了什么?JSON 怎么会在那么多应用程序中取代了 XML?现在被全世界工程师和系统所使用、依赖的这种数据格式是谁提出的?
|
||||
|
||||
### JSON 之诞生
|
||||
|
||||
2001 年 4 月,首个 JSON 格式的消息被发送出来。此消息是从旧金山湾区某车库的一台计算机发出的,这是计算机历史上重要的的时刻。Douglas Crockford 和 Chip Morningstar 是一家名为 State Software 的技术咨询公司的联合创始人,他们当时聚集在 Morningstar 的车库里测试某个想法,发出了此消息。
|
||||
|
||||
在 “AJAX” 这个术语被创造之前,Crockford 和 Morningstar 就已经在尝试构建好用的 AJAX 应用程序了,可是浏览器对其兼容性不好。他们想要在初始页面加载后就将数据传递给应用程序,但其目标要针对所有的浏览器,这就实现不了。
|
||||
|
||||
这在今天看来不太可信,但是要记得 2001 年的时候 Internet Explorer(IE)代表了网页浏览器的最前沿技术产品。早在 1999 年的时候,Internet Explorer 5 就支持了原始形式的 `XMLHttpRequest`,开发者可以使用名为 ActiveX 的框架来访问此对象。Crockford 和 Morningstar 能够使用此技术(在 IE 中)来获取数据,但是在 Netscape 4 中(这是他们想要支持的另一种浏览器)就无法使用这种解决方案。为此 Crockford 和 Morningstar 只得使用一套不同的系统以兼容不同的浏览器。
|
||||
|
||||
第一条 JSON 消息如下所示:
|
||||
|
||||
```
|
||||
<html><head><script>
|
||||
document.domain = 'fudco';
|
||||
parent.session.receive(
|
||||
{ to: "session", do: "test",
|
||||
text: "Hello world" }
|
||||
)
|
||||
</script></head></html>
|
||||
```
|
||||
|
||||
消息中只有一小部分类似于今天我们所知的 JSON,本身其实是一个包含有一些 JavaScript 的 HTML 文档。类似于 JSON 的部分只是传递给名为 `receive()` 的函数的 JavaScript 对象字面量。
|
||||
|
||||
Crockford 和 Morningstar 决定滥用 HTML 的帧(`<frame>`)以发送数据。他们可以让一个帧指向一个返回的上述 HTML 文档的 URL。当接收到 HTML 时,JavaScript 代码段就会运行,就可以把数据对象字面量如实地传递回应用程序。只要小心的回避浏览器保护策略(即子窗口不允许访问父窗口),这种技术就可以正常运行无误。可以看到 Crockford 和 Mornginstar 通过明确地设置文档域这种方法来达到其目的。(这种基于帧的技术,有时称为隐藏帧技术,通常在 90 年代后期,即在广泛使用 XMLHttpRequest 技术之前使用。[^3] )
|
||||
|
||||
第一个 JSON 消息的惊人之处在于,它显然不是一种新的数据格式的首次使用。它就是 JavaScript!实际上,以此方式使用 JavaScript 的想法如此简单,Crockford 自己也说过他不是第一个这样做的人。他说 Netscape 公司的某人早在 1996 年就使用 JavaScript 数组字面量来交换信息。[^4] 因为消息就是 JavaScript,其不需要任何特殊解析工作,JavaScript 解释器就可搞定一切。
|
||||
|
||||
最初的 JSON 信息实际上与 JavaScript 解释器发生了冲突。JavaScript 保留了大量的关键字(ECMAScript 6 版本就有 64 个保留字),Crockford 和 Morningstar 无意中在其 JSON 中使用了一个保留字。他们使用了 `do` 作为了键名,但 `do` 是解释器中的保留字。因为 JavaScript 使用的保留字太多了,Crockford 做了决定:既然不可避免的要使用到这些保留字,那就要求所有的 JSON 键名都加上引号。被引起来的键名会被 JavaScript 解释器识别成字符串,其意味着那些保留字也可以放心安全的使用。这就为什么今天 JSON 键名都要用引号引起来的原因。
|
||||
|
||||
Crockford 和 Morningstar 意识到这技术可以应用于各类应用系统。想给其命名为 “JSML”,即 <ruby>JavaScript 标记语言<rt>JavaScript Markup Language</rt></ruby>的意思,但发现这个缩写已经被一个名为 Java Speech 标记语言的东西所使用了。因此他们决定采用 “JavaScript Object Notation”,缩写为 JSON。他们开始向客户推销,但很快发现客户不愿意冒险使用缺乏官方规范的未知技术。所以 Crockford 决定写一个规范。
|
||||
|
||||
2002 年,Crockford 买下了 [JSON.org][2] 域名,放上了 JSON 语法及一个解释器的实例例子。该网站仍然在运行,现在已经包含有 2013 年正式批准的 JSON ECMA 标准的显著链接。在该网站建立后,Crockford 并没有过多的推广,但很快发现很多人都在提交各种不同编程语言的 JSON 解析器实现。JSON 的血统显然与 JavaScript 相关联,但很明显 JSON 非常适合于不同语言之间的数据交换。
|
||||
|
||||
### AJAX 导致的误会
|
||||
|
||||
2005 年,JSON 有了一次大爆发。那一年,一位名叫 Jesse James Garrett 的网页设计师和开发者在博客文章中创造了 “AJAX” 一词。他很谨慎地强调:AJAX 并不是新技术,而是 “好几种蓬勃发展的技术以某种强大的新方式汇集在一起。[^5] ” AJAX 是 Garrett 给这种正受到青睐的 Web 应用程序的新开发方法的命名。他的博客文章接着描述了开发人员如何利用 JavaScript 和 XMLHttpRequest 构建新型应用程序,这些应用程序比传统的网页更具响应性和状态性。他还以 Gmail 和 Flickr 网站已经使用 AJAX 技术作为了例子。
|
||||
|
||||
当然了,“AJAX” 中的 “X” 代表 XML。但在随后的问答帖子中,Garrett 指出,JSON 可以完全替代 XML。他写道:“虽然 XML 是 AJAX 客户端进行数据输入、输出的最完善的技术,但要实现同样的效果,也可以使用像 JavaScript Object Notation(JSON)或任何类似的结构数据方法等技术。 ”[^6]
|
||||
|
||||
开发者确实发现在构建 AJAX 应用程序时可以很容易的使用 JSON,许多人更喜欢它而不是 XML。具有讽刺意味的是,对 AJAX 的兴趣逐渐的导致了 JSON 的普及。大约在这个时候,JSON 引起了博客圈的注意。
|
||||
|
||||
2006 年,Dave Winer,一位高产的博主,他也是许多基于 XML 的技术(如 RSS 和 XML-RPC)背后的开发工程师,他抱怨到 JSON 毫无疑问的正在重新发明 XML。尽管人们认为数据交换格式之间的竞争不会导致某一技术的消亡。其写到:
|
||||
|
||||
> 毫无疑问,我可以编写一个例程来解析 JSON,但来看看他们要重新发明一个东西有多大的意义,出于某种原因 XML 本身对他们来说还不够好(我很想听听原因)。谁想干这荒谬之事?查找一棵树然后把节点串起来。可以立马试试。[^7]
|
||||
|
||||
我很理解 Winer 的挫败感。事实上并没有太多人喜欢 XML。甚至 Winer 也说过他不喜欢 XML。[^8] 但 XML 已被设计成一个可供任何人使用,并且可以用于几乎能想象到的所有事情。归根到底,XML 实际上是一门元语言,允许你为特定应用程序自定义该领域特定的语言。如 Web 信息流技术 RSS 和 SOAP(简单对象访问协议)就是例子。Winer 认为由于通用交换格式所带来的好处,努力达成共识非常重要。XML 的灵活性应该能满足任何人的需求,然而 JSON 格式呢,其并没有比 XML 提供更多东西,除了它抛弃了使 XML 更灵活的那些繁琐的东西。
|
||||
|
||||
Crockford 阅读了 Winer 的这篇文章并留下了评论。为了回应 JSON 重新发明 XML 的指责,Crockford 写到:“重造轮子的好处是可以得到一个更好的轮子。”[^9]
|
||||
|
||||
### JSON 与 XML 对比
|
||||
|
||||
到 2014 年,JSON 已经由 ECMA 标准和 RFC 官方正式认可。它有了自己的 MIME 类型。JSON 已经进入了大联盟时代。
|
||||
|
||||
为什么 JSON 比 XML 更受欢迎?
|
||||
|
||||
在 [JSON.org][2] 网站上,Crockford 总结了一些 JSON 的优势。他写到,JSON 的语法极少,其结构可预测,因此 JSON 更容易被人类和机器理解。[^10] 其他博主一直关注 XML 的冗长啰嗦及“尖括号负担”。[^11] XML 中每个开始标记都必须与结束标记匹配,这意味着 XML 文档包含大量的冗余信息。在未压缩时,XML 文档的体积比同等信息量 JSON 文档的体积大很多,但是,更重要的,这也使 XML 文档更难以阅读。
|
||||
|
||||
Crockford 还声称 JSON 的另一个巨大优势是其被设计为数据交换格式。[^12] 从一开始,它的目的就是在应用程序间传递结构化信息的。而 XML 呢,虽然也可以使用来传递数据,但其最初被设计为文档标记语言。它演变自 SGML(通用标准标记语言),而它又是从被称为 Scribe 的标记语言演变而来,其旨在发展成类似于 LaTeX 一样的文字处理系统。XML 中,一个标签可以包含有所谓的“混合内容”,即带有围绕单词、短语的内嵌标签的文本。这会让人浮现出一副用红蓝笔记录的手稿画面,这是标记语言核心思想的形象比喻。另一方面,JSON 不支持对混合内容模型的清晰构建,但这也意味着它的结构足够简单。一份文档最好的建模就是一棵树,但 JSON 抛弃了这种文档的思想,Crockford 将 JSON 抽象限制为字典和数组,这是所有程序员构建程序时都会使用的最基本的、也最熟悉的元素。
|
||||
|
||||
最后,我认为人们不喜欢 XML 是因为它让人困惑。它让人迷惑的地方就是有很多不同的风格。乍一看,XML 本身及其子语言(如 RSS、ATOM、SOAP 或 SVG)之间的界限并不明显。典型的 XML 文档的第一行标识了该 XML 的版本,然后该 XML 文档应该符合特定的子语言。这就有变化需要考虑了,特别是跟 JSON 做比较,JSON 是如此简单,以至于永远不需要编写新版本的 JSON 规范。XML 的设计者试图将 XML 做为唯一的数据交换格式以支配所有格式,就会掉入那个经典的程序员陷阱:过度工程化。XML 非常笼统及概念化,所以很难于简单的使用。
|
||||
|
||||
在 2000 年的时候,发起了一场使 HTML 符合 XML 标准的活动,发布了一份符合 XML 标准的 HTML 开发规范,这就此后很出名的 XHTML。虽然一些浏览器厂商立即开始支持这个新标准,但也很明显,大部分基于 HTML 技术的开发者不愿意改变他们的习惯。新标准要求对 XHTML 文档进行严格的验证,而不是基于 HTML 的基准。但大多的网站都是依赖于 HTML 的宽容规则的。到 2009 年的时候,试图编写第二版本的 XHTML 标准的努力已经流产,因为未来已清晰可见,HTML 将会发展为 HTML5(一种不强制要求接受 XML 规则的标准)。
|
||||
|
||||
如果 XHTML 的努力取得了成功,那么 XML 可能会成为其设计者所希望的通用数据格式。想象一下,一个 HTML 文档和 API 响应具有完全相同结构的世界。在这样的世界中,JSON 可能不会像现在一样普遍存在。但我把 HTML 的失败看做是 XML 阵营的一种道义上的失败。如果 XML 不是 HTML 的最佳工具,那么对于其他应用程序,也许会有更好的工具出现。在这个世界,我们的世界,很容易看到像 JSON 格式这样的足够简单、量体裁衣的才能获得更大的成功。
|
||||
|
||||
如果你喜欢这博文,每两周会更新一次! 请在 Twitter 上关注 [@TwoBitHistory][3] 或订阅 [RSS feed][4],以确保得到更新的通知。
|
||||
|
||||
[^1]: http://www.cs.tufts.edu/comp/150IDS/final_papers/tstras01.1/FinalReport/FinalReport.html#software
|
||||
[^2]: https://insights.stackoverflow.com/trends?tags=json%2Cxml%2Cprotocol-buffers%2Cyaml%2Ccsv
|
||||
[^3]: Zakas, Nicholas C., et al. “What Is Ajax?” Professional Ajax, 2nd ed., Wiley, 2007.
|
||||
[^4]: https://youtu.be/-C-JoyNuQJs?t=32s
|
||||
[^5]: http://adaptivepath.org/ideas/ajax-new-approach-web-applications/
|
||||
[^6]: 同上
|
||||
[^7]: http://scripting.com/2006/12/20.html
|
||||
[^8]: http://blogoscoped.com/archive/2009-03-05-n15.html
|
||||
[^9]: https://scripting.wordpress.com/2006/12/20/scripting-news-for-12202006/#comment-26383
|
||||
[^10]: http://www.json.org/xml.html
|
||||
[^11]: https://blog.codinghorror.com/xml-the-angle-bracket-tax
|
||||
[^12]: https://youtu.be/-C-JoyNuQJs?t=33m50sgg
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://twobithistory.org/2017/09/21/the-rise-and-rise-of-json.html
|
||||
|
||||
作者:[Two-Bit History][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[runningwater](https://github.com/runningwater)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://twobithistory.org
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://twobithistory.org/images/json.svg
|
||||
[2]: http://JSON.org
|
||||
[3]: https://twitter.com/TwoBitHistory
|
||||
@@ -0,0 +1,112 @@
|
||||
如何用 Gonimo 创建一个免费的婴儿监视系统
|
||||
======
|
||||
> 当你可以用两个设备、浏览器和网络连接就能免费搭建一个婴儿监视器时,谁还会花钱去买呢?
|
||||
|
||||

|
||||
|
||||
新父母和准父母很快就会知道将会有一个既长且昂贵的新生儿所需设备的清单,清单中的首位是一个婴儿监视器,借此他们可以在做其他事情时照看自己的婴儿,但这儿有一件不必消耗你的婴儿经费的设备,Gonimo 是一个可以将现有的设备转换成婴儿监控系统的自由开源解决方案,附近大型婴儿用品商店的过道中有数以千计的其他必备或时尚物品,就可以为其中某一个腾出一些婴儿的预算。
|
||||
|
||||
Gonimo 诞生时,它的开发者,一个有双胞胎的开源粉丝,发现现有选择存在问题:
|
||||
|
||||
* 现有硬件婴儿监视器价格昂贵,使用范围有限,需要您带着额外的设备。
|
||||
* 虽然有移动监控应用程序,但大多数现有的 iOS / Android 婴儿监控应用程序都不可靠且不安全,不太容易找到开源产品。
|
||||
* 如果您有两个小孩(例如双胞胎),您将需要两台监视器,使您的成本翻倍。
|
||||
|
||||
Gonimo 是作为一个解决典型的监视器的缺点的开源解决方案而创建的:
|
||||
|
||||
* 昂贵?不,它是免费的!
|
||||
* 使用范围有限?不,它适用于互联网 / WiFi,无论您身在何处。
|
||||
* 下载并安装应用程序?噢不,它适用于您现有的网络浏览器。
|
||||
* 购买新设备?不用,你可以使用任何笔记本电脑、手机或平板电脑与网络浏览器和麦克风和/或相机。
|
||||
|
||||
(注意:遗憾的是,Apple iOS 设备尚不支持,但预计很快就会发生变化 —— 请继续阅读,了解如何帮实现这一目标。)
|
||||
|
||||
### 开始
|
||||
|
||||
将您的设备转换为婴儿监视器很容易。从您设备的浏览器(理想情况下为 Chrome),访问 [gonimo.com][1] 并单击 “Start baby monitor” 以访问该 Web 应用程序。
|
||||
|
||||
1、创建家庭:在首次启动的屏幕上,你会看到一只可爱的兔子在地球上奔跑。这是您创建新家庭的地方。单击 “+” 按钮并接受随机生成的姓氏或键入您自己的选择。
|
||||
|
||||
![Start screen][3]
|
||||
|
||||
*从开始屏幕创建一个新家庭*
|
||||
|
||||
2、邀请设备:建立完家庭以后,下个屏幕将指示您邀请其他设备加入你的 Gonimo 家庭。您可以通过电子邮件直接发送一次性邀请链接,也可以将其复制并粘贴到消息中。对其他设备,只需打开该链接并接受邀请。对您要邀请的任何其他设备重复此过程。您的设备现在属于同一家庭,可以作为一个完全正常工作的婴儿监视器系统进行配合。
|
||||
|
||||
![Invite screen][5]
|
||||
|
||||
*邀请家庭成员*
|
||||
|
||||
3、启动婴儿站流:接下来,通过转到 [Gonimo 主屏][6],点击带有奶嘴的按钮,并允许网络浏览器访问设备的麦克风和摄像头,选择将婴儿的音频和视频流式传输到父母的设备。调整相机以指向宝宝的床,或关闭它以节省设备电池(音频仍将流式传输)。点击“Start”。该流现在处于活动状态。
|
||||
|
||||
![Select baby station][8]
|
||||
|
||||
*选择婴儿站*
|
||||
|
||||
![Press Start][10]
|
||||
|
||||
*按“Start”开始以流式传输视频*
|
||||
|
||||
4、连接到父母站流:要查看婴儿站流,请转到 Gonimo 家族中的另外的设备 —— 即父母站。点击 Gonimo 主屏幕上的 “Parent” 按钮。您将看到该系列中所有设备的列表;旁边有一个闪动的“Connect”按钮的是活跃的婴儿站。选择“Connect”,您可以通过点对点音频/视频流看到和听到您的宝宝。音量条为传输的音频流提供可视化。
|
||||
|
||||
![Select parent station][12]
|
||||
|
||||
*选择父母站*
|
||||
|
||||
![Press Connect][14]
|
||||
|
||||
*按下“Connect”开始观看婴儿流。*
|
||||
|
||||
5、恭喜!您已成功将设备直接通过网络浏览器转换为婴儿监视器,无需下载或安装任何应用程序!
|
||||
|
||||
有关重命名设备,从系列中删除设备或删除系列的详细信息和详细说明,请查看 gonimo.com 的[视频教程][15]。
|
||||
|
||||
### 家庭系统的灵活性
|
||||
|
||||
Gonimo 的优势之一是其基于家庭的系统,它为即使在商业 Android 或 iOS 应用中也无法提供的各种情况提供了极大的灵活性。要深入了解这些功能,我们假设您创建了一个由三个设备组成的家庭系统。
|
||||
|
||||
* 多婴儿:如果你想留意你在两个不同房间睡觉的两个小孩怎么办?在每个孩子的房间放一个设备,并将其设置为婴儿站。第三个设备将充当父母站,您可以在其上连接到两个流并通过分屏查看您的幼儿。您甚至可以通过向该家庭系统提供更多设备,并将其设置为婴儿站来将此用例扩展到两个以上的婴儿站。只要您的父母站连接到第一个婴儿站,请单击左上角的后退箭头返回“设备概述”屏幕。现在您可以连接到第二个(以及依次为第三个、第四个、第五个和第五个等)设备,并自动建立分屏。酷!
|
||||
* 多父母:如果爸爸想在他上班的时候看孩子怎么办?只需邀请第四个设备(例如,他的办公室 PC )到家庭并将其设置为父母站。父母双方都可以通过他们自己的设备同时检查他们的孩子,甚至可以独立地选择他们希望连接的孩子。
|
||||
* 多家庭:单个设备也可以是几个家庭系统的一部分。当您的婴儿站与您一起时,如平板电脑,您经常访问亲戚或朋友时,这非常有用。为“奶奶的房子”或“约翰叔叔的房子”创建另一个家庭,其中包括您的婴儿站设备与奶奶或约翰叔叔的设备配对。您可以随时通过婴儿站设备的 Gonimo 主屏幕在这些家庭中切换婴儿站设备。
|
||||
|
||||
### 想要参加吗?
|
||||
|
||||
Gonimo 团队喜欢开源。代码来自社区,代码用于社区。Gonimo 的用户对我们非常重要,但它们只是 Gonimo 故事的一部分。幕后有创意的大脑是创造出色婴儿监视器体验的关键。
|
||||
|
||||
目前我们特别需要那些愿意成为 iOS 11 测试者的人的帮助,因为 Apple 在 iOS 11 中对 WebRTC 的支持意味着我们最终将能够支持 iOS 设备。如果可以,请帮助我们实现这个令人赞叹的里程碑。
|
||||
|
||||
如果您了解 Haskell 或想要了解它,您可以查看 [GitHub 上我们的代码][16]。欢迎发起拉取请求、审查代码以及提出问题。
|
||||
|
||||
最后,请通过向新父母和开源世界宣传 Gonimo 婴儿监视器是易于使用并且便携的。
|
||||
|
||||
### 关于作者
|
||||
|
||||
Robert Klotzner:我是双胞胎的父亲,一个程序员。当我听到普通人可以给计算机编程时,我买了一本 1200 页的关于 C++ 的书开始学习,我当时才十五岁。我坚持用 C++ 相当长的一段时间,学习了 Java 又回归到 C++,学习了 D、Python 等等,最终学习了 Haskell。我喜欢 Haskell 是因为它丰富的类型系统,这几乎可以避免我书写错误的代码。强壮的静态类型和性能让我爱上了 C++……
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/17/9/gonimo
|
||||
|
||||
作者:[Robert Klotzner][a]
|
||||
译者:[lintaov587](https://github.com/lintaov587)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/robert-klotzner
|
||||
[1]:https://gonimo.com/
|
||||
[2]:/file/371256
|
||||
[3]:https://opensource.com/sites/default/files/u128651/start-screen.png (Start screen)
|
||||
[4]:/file/371236
|
||||
[5]:https://opensource.com/sites/default/files/u128651/invite-screen.png (Invite screen)
|
||||
[6]:https://app.gonimo.com/
|
||||
[7]:/file/371231
|
||||
[8]:https://opensource.com/sites/default/files/u128651/baby-select.png (Select baby station)
|
||||
[9]:/file/371226
|
||||
[10]:https://opensource.com/sites/default/files/u128651/baby-screen.png (Press Start)
|
||||
[11]:/file/371251
|
||||
[12]:https://opensource.com/sites/default/files/u128651/parent-select.png (Select parent station)
|
||||
[13]:/file/371241
|
||||
[14]:https://opensource.com/sites/default/files/u128651/parent-screen.png (Press Connect)
|
||||
[15]:https://gonimo.com/index.php#intro
|
||||
[16]:https://github.com/gonimo/gonimo
|
||||
89
published/201901/20171119 The Ruby Story.md
Normal file
89
published/201901/20171119 The Ruby Story.md
Normal file
@@ -0,0 +1,89 @@
|
||||
红宝石(Ruby)史话
|
||||
======
|
||||
|
||||
尽管我很难说清楚为什么,但 Ruby 一直是我最喜爱的一门编程语言。如果用音乐来类比的话,Python 给我的感觉像是<ruby>朋克摇滚<rt>punk rock</rt></ruby>,简单、直接,但略显单调,而 Ruby 则像是爵士乐,从根本上赋予了程序员表达自我的自由,虽然这可能会让代码变复杂,编写出来的程序对其他人来说不直观。
|
||||
|
||||
Ruby 社区一直将<ruby>灵活表达<rt>freedom of expression</rt></ruby>视为其核心价值。可我不认同这对于 Ruby 的开发和普及是最重要的。创建一门编程语言也许是为了更高的性能,也许是为了在抽象上节省更多的时间,可 Ruby 就有趣在它并不关心这些,从它诞生之初,它的目标就是让程序员更快乐。
|
||||
|
||||
### 松本·行弘
|
||||
|
||||
<ruby>松本·行弘<rt>Yukihiro Matsumoto</rt></ruby>,亦称为 “Matz”,于 1990 年毕业于筑波大学。筑波是东京东北方向上的一个小城市,是科学研究与技术开发的中心之一。筑波大学以其 STEM 计划广为流传。松本·行弘在筑波大学的信息科学专业学习过,且专攻编程语言。他也在 Ikuo Nakata 的编程语言实验室工作过。(LCTT 译注:STEM 是<ruby>科学<rt>Science</rt></ruby>、<ruby>技术<rt>Technology</rt></ruby>、<ruby>工程<rt>Engineering</rt></ruby>、<ruby>数学<rt>Mathematics</rt></ruby>四门学科英文首字母的缩写。)
|
||||
|
||||
松本从 1993 年开始制作 Ruby,那时他才刚毕业几年。他制作 Ruby 的起因是觉得那时的脚本语言缺乏一些特性。他在使用 Perl 的时候觉得这门语言过于“玩具”,此外 Python 也有点弱,用他自己的话说:
|
||||
|
||||
> 我那时就知道 Python 了,但我不喜欢它,因为我认为它不是一门真正的面向对象的语言。面向对象就像是 Python 的一个附件。作为一个编程语言狂热者,我在 15 年里一直是面向对象的忠实粉丝。我真的想要一门生来就面向对象而且易用的脚本语言。我为此特地寻找过,可事实并不如愿。[^1]
|
||||
|
||||
所以一种解释松本创造 Ruby 的动机就是他想要创造一门更好,且面向对象的 Perl。
|
||||
|
||||
但在其他场合,松本说他创造 Ruby 主要是为了让他自己和别人更快乐。2008 年,松本在谷歌技术讲座结束时放映了这张幻灯片:
|
||||
|
||||
![][1]
|
||||
|
||||
他对听众说到,
|
||||
|
||||
> 我希望 Ruby 能帮助世界上的每一个程序员更有效率地工作,享受编程并感到快乐。这也是制作 Ruby 语言的主要意图。[^2]
|
||||
|
||||
松本开玩笑的说他制作 Ruby 的原因很自私,因为他觉得其它的语言乏味,所以需要创造一点让自己开心的东西。
|
||||
|
||||
这张幻灯片展现了松本谦虚的一面。其实,松本是一位摩门教践行者,因此我很好奇他传奇般的友善有多少归功于他的宗教信仰。无论如何,他的友善在 Ruby 社区广为流传,甚至有一条称为 MINASWAN 的原则,即“<ruby>松本人很好,我们也一样<rt>Matz Is Nice And So We Are Nice</rt></ruby>”。我想那张幻灯片一定震惊了来自 Google 的观众。我想谷歌技术讲座上的每张幻灯片都充满着代码和运行效率的指标,来说明一个方案比另一个更快更有效,可仅仅放映崇高的目标的幻灯片却寥寥无几。
|
||||
|
||||
Ruby 主要受到 Perl 的影响。Perl 则是由 Larry Wall 于 20 世纪 80 年代晚期创造的语言,主要用于处理和转换基于文本的数据。Perl 因其文本处理和正则表达式而闻名于世。对于 Ruby 程序员,Perl 程序中的很多语法元素都不陌生,例如符号 `$`、符号 `@`、`elsif` 等等。虽然我觉得,这些不是 Ruby 应该具有的特征。除了这些符号外,Ruby 还借鉴了 Perl 中的正则表达式的处理和标准库。
|
||||
|
||||
但影响了 Ruby 的不仅仅只有 Perl 。在 Ruby 之前,松本制作过一个仅用 Emacs Lisp 编写的邮件客户端。这一经历让他对 Emacs 和 Lisp 语言运行的内部原理有了更多的认识。松本说 Ruby 底层的对象模型也受其启发。在那之上,松本添加了一个 Smalltalk 风格的信息传递系统,这一系统随后成为了 Ruby 中任何依赖 `#method_missing` 的操作的基石。松本也表示过 Ada 和 Eiffel 也影响了 Ruby 的设计。
|
||||
|
||||
当时间来到了给这门新语言命名的时候,松本和他的同事 Keiju Ishitsuka 挑选了很多个名字。他们希望名字能够体现新语言和 Perl、shell 脚本间的联系。在[这一段非常值得一读的即时消息记录][2]中,Ishitsuka 和 松本也许花了太多的时间来思考 <ruby>shell<rt>贝壳</rt></ruby>、<ruby>clam<rt>蛤蛎</rt></ruby>、<ruby>oyster<rt>牡蛎</rt></ruby>和<ruby>pearl<rt>珍珠</rt></ruby>之间的关系了,以至于差点把 Ruby 命名为“<ruby>Coral<rt>珊瑚虫</rt></ruby>”或“<ruby>Bisque<rt>贝类浓汤</rt></ruby>”。幸好,他们决定使用 Ruby,因为它就像 pearl 一样,是一种珍贵的宝石。此外,<ruby>Ruby<rt>红宝石</rt></ruby> 还是 7 月的生辰石,而 <ruby>Pearl<rt>珍珠</rt></ruby> 则是 6 月的生辰石,采用了类似 C++ 和 C# 的隐喻,暗示着她们是改进自前辈的编程语言。(LCTT 译注:Perl 和 Pearl 发音相同,所以也常以“珍珠”来借喻 Perl;shell 是操作系统提供的用户界面,这里指的是命令行界面;更多有关生辰石的[信息](https://zh.wikipedia.org/zh-hans/%E8%AA%95%E7%94%9F%E7%9F%B3)。)
|
||||
|
||||
### Ruby 西渐
|
||||
|
||||
Ruby 在日本的普及很快。1995 年 Ruby 刚刚发布后不久后,松本就被一家名为 Netlab 的日本软件咨询财团(全名 Network Applied Communication Laboratory)雇用,并全职为 Ruby 工作。到 2000 年时,在 Ruby 发布仅仅 5 年后,Ruby 在日本的流行度就超过了 Python。可这时的 Ruby 才刚刚进入英语国家。虽然从 Ruby 的诞生之初就存在讨论它的日语邮件列表,但是英语的邮件列表直到 1998 年才建立起来。起初,在英语的邮件列表中交流的大多是日本的 Ruby 狂热者,可随着 Ruby 在西方的逐渐普及而得以改变。
|
||||
|
||||
在 2000 年,Dave Thomas 出版了第一本涵盖 Ruby 的英文书籍《Programming Ruby》。因为它的封面上画着一把锄头,所以这本书也被称为锄头书。这是第一次向身处西方的程序员们介绍了 Ruby。就像在日本那样,Ruby 的普及很快,到 2002 年时,英语的 Ruby 邮件列表的通信量就超过了日语邮件列表。
|
||||
|
||||
时间来到了 2005 年,Ruby 更流行了,但它仍然不是主流的编程语言。然而,Ruby on Rails 的发布让一切都不一样了。Ruby on Rails 是 Ruby 的“杀手级应用”,没有别的什么项目能比它更推动 Ruby 的普及了。在 Ruby on Rails 发布后,人们对 Ruby 的兴趣爆发式的增长,看看 TIOBE 监测的语言排行:
|
||||
|
||||
![][3]
|
||||
|
||||
有时人们开玩笑的说,Ruby 程序全是基于 Ruby-on-Rails 的网站。虽然这听起来就像是 Ruby on Rails 占领了整个 Ruby 社区,但在一定程度上,这是事实。因为编写 Rails 应用时使用的语言正是 Ruby。Rails 欠 Ruby 的和 Ruby 欠 Rails 的一样多。
|
||||
|
||||
Ruby 的设计哲学也深深地影响了 Rails 的设计与开发。Rails 之父 David Heinemeier Hansson 常常提起他第一次与 Ruby 的接触的情形,那简直就是一次传教。他说,那种经历简直太有感召力了,让他感受到要为松本的杰作(指 Ruby)“传教”的使命。[^3] 对于 Hansson 来说,Ruby 的灵活性简直就是对 Python 或 Java 语言中自上而下的设计哲学的反抗。他很欣赏 Ruby 这门能够信任自己的语言,Ruby 赋予了他自由选择<ruby>程序表达方式<rt>express his programs</rt></ruby>的权力。
|
||||
|
||||
就像松本那样,Hansson 声称他创造 Rails 时因为对现状的不满并想让自己能更开心。他也认同让程序员更快乐高于一切的观点,所以检验 Rails 是否需要添加一项新特性的标准是“<ruby>更灿烂的笑容标准<rt>The Principle of The Bigger Smile</rt></ruby>”。什么功能能让 Hansson 更开心就给 Rails 添加什么。因此,Rails 中包括了很多非正统的功能,例如 “Inflector” 类和 `Time` 扩展(“Inflector”类试图将单个类的名字映射到多个数据库表的名字;`Time` 扩展允许程序员使用 `2.days.ago` 这样的表达式)。可能会有人觉得这些功能太奇怪了,但 Rails 的成功表明它的确能让很多人的生活得更快乐。
|
||||
|
||||
因此,虽然 Rails 的火热带动了 Ruby 的普及看起来是一个偶然,但事实上 Rails 体现了 Ruby 的很多核心准则。此外,很难看到使用其他语言开发的 Rails,正是因为 Rails 的实现依赖于 Ruby 中<ruby>类似于宏的类方法调用<rt>macro-like class method calls</rt></ruby>来实现模型关联这样的功能。一些人认为这么多的 Ruby 开发需要基于 Ruby on Rails 是 Ruby 生态不健康的表现,但 Ruby 和 Ruby on Rails 结合的如此紧密并不是没有道理的。
|
||||
|
||||
### Ruby 之未来
|
||||
|
||||
人们似乎对 Ruby(及 Ruby on Rails)是否正在消亡有着异常的兴趣。早在 2011 年,Stack Overflow 和 Quora 上就充斥着程序员在咨询“如果几年后不再使用 Ruby 那么现在是否有必要学它”的话题。这些担忧对 Ruby 并非没有道理,根据 TIOBE 指数和 Stack Overflow 趋势,Ruby 和 Ruby on Rails 的人气一直在萎缩,虽然它也曾是热门新事物,但在更新更热的框架面前它已经黯然失色。
|
||||
|
||||
一种解释这种趋势的理论是程序员们正在舍弃动态类型的语言转而选择静态类型的。TIOBE 指数的趋势中可以看出对软件质量的需求在上升,这意味着出现在运行时的异常变得难以接受。他们引用 TypeScript 来说明这一趋势,TypeScript 是 JavaScript 的全新版本,而创造它的目的正是为了保证客户端运行的代码能受益于编译所提供的安全保障。
|
||||
|
||||
我认为另一个更可能的原因是比起 Ruby on Rails 推出的时候,现在存在着更多有竞争力的框架。2005 年它刚刚发布的时候,还没有那么多用于创建 Web 程序的框架,其主要的替代者还是 Java。可在今天,你可以使用为 Go、Javascript 或者 Python 开发的各种优秀的框架,而这还仅仅是主流的选择。Web 的世界似乎正走向更加分布式的结构,与其使用一块代码来完成从数据库读取到页面渲染所有事务,不如将事务拆分到多个组件,其中每个组件专注于一项事务并将其做到最好。在这种趋势下,Rails 相较于那些专攻于 JavaScript 前端通信的 JSON API 就显得过于宽泛和臃肿。
|
||||
|
||||
总而言之,我们有理由对 Ruby 的未来持乐观态度。因为不管是 Ruby 还是 Rails 的开发都还很活跃。松本和其他的贡献者们都在努力开发 Ruby 的第三个主要版本。新的版本将比现在的版本快上 3 倍,以减轻制约着 Ruby 发展的性能问题。虽然从 2005 年起,越来越多的 Web 框架被开发出来,但这并不意味着 Ruby on Rails 就失去了其生存空间。Rails 是一个富有大量功能的成熟的工具,对于一些特定类型的应用开发一直是非常好的选择。
|
||||
|
||||
但就算 Ruby 和 Rails 走上了消亡的道路,Ruby 让程序员更快乐的信条一定会存活下来。Ruby 已经深远的影响了许多新的编程语言的设计,这些语言的设计中能够看到来自 Ruby 的很多理念。而其他的新生语言则试着变成 Ruby 更现代的实现,例如 Elixir 是一个强调函数式编程范例的语言,仍在开发中的 Crystal 目标是成为使用静态类型的 Ruby 。世界上许多程序员都喜欢上了 Ruby 及其语法,因此它的影响必将会在未来持续很长一段时间。
|
||||
|
||||
喜欢这篇文章吗?这里每两周都会发表一篇这样的文章。请在推特上关注我们 [@TwoBitHistory][4] 或者订阅我们的 [RSS][5],这样新文章发布的第一时间你就能得到通知。
|
||||
|
||||
[^1]: http://ruby-doc.org/docs/ruby-doc-bundle/FAQ/FAQ.html
|
||||
[^2]: https://www.youtube.com/watch?v=oEkJvvGEtB4?t=30m55s
|
||||
[^3]: http://rubyonrails.org/doctrine/
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://twobithistory.org/2017/11/19/the-ruby-story.html
|
||||
|
||||
作者:[Two-Bit History][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wwhio](https://github.com/wwhio)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://twobithistory.org
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://twobithistory.org/images/matz.png
|
||||
[2]: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/88819
|
||||
[3]: https://twobithistory.org/images/tiobe_ruby.png
|
||||
[4]: https://twitter.com/TwoBitHistory
|
||||
[5]: https://twobithistory.org/feed.xml
|
||||
@@ -0,0 +1,84 @@
|
||||
Turtl:Evernote 的开源替代品
|
||||
======
|
||||
> 如果你正在寻找一个 Evernote 和 Google Keep 的替代品,那么 Turtl 是一个可靠的记笔记工具。
|
||||
|
||||

|
||||
|
||||
我认识的每个人都会记笔记,许多人使用在线笔记应用,如 Evernote、Simplenote 或 Google Keep。这些都是很好的工具,但你不得不担忧信息的安全性和隐私性 —— 特别是考虑到 [Evernote 2016 年的隐私策略变更][1]。如果你想要更好地控制笔记和数据,你需要转向开源工具。
|
||||
|
||||
无论你离开 Evernote 的原因是什么,都有开源替代品。让我们来看看其中一个选择:Turtl。
|
||||
|
||||
### 入门
|
||||
|
||||
[Turtl][2] 背后的开发人员希望你将其视为“具有绝对隐私的 Evernote”。说实话,我不能保证 Turtl 提供的隐私级别,但它是一个非常好的笔记工具。
|
||||
|
||||
要开始使用 Turtl,[下载][3]适用于 Linux、Mac OS 或 Windows 的桌面客户端,或者获取它的 [Android 应用][4]。安装它,然后启动客户端或应用。系统会要求你输入用户名和密码。Turtl 使用密码来生成加密密钥,根据开发人员的说法,加密密钥会在将笔记存储在设备或服务器上之前对其进行加密。
|
||||
|
||||
### 使用 Turtl
|
||||
|
||||
你可以使用 Turtl 创建以下类型的笔记:
|
||||
|
||||
* 密码
|
||||
* 档案
|
||||
* 图片
|
||||
* 书签
|
||||
* 文字笔记
|
||||
|
||||
无论你选择何种类型的笔记,你都可以在类似的窗口中创建:
|
||||
|
||||

|
||||
|
||||
*在 Turtl 中创建新笔记*
|
||||
|
||||
添加笔记标题、文字并(如果你正在创建文件或图像笔记)附加文件或图像等信息。然后单击“保存”。
|
||||
|
||||
你可以通过 [Markdown][6] 为你的笔记添加格式。因为没有工具栏快捷方式,所以你需要手动添加格式。
|
||||
|
||||
如果你需要整理笔记,可以将它们添加到“白板”中。白板就像 Evernote 中的笔记本。要创建新的白板,请单击 “Board” 选项卡,然后单击“创建”按钮。输入白板的标题,然后单击“创建”。
|
||||
|
||||

|
||||
|
||||
*在 Turtl 中创建新的白板*
|
||||
|
||||
要向白板中添加笔记,请创建或编辑笔记,然后单击笔记底部的“此笔记不在任何白板”的链接。选择一个或多个白板,然后单击“完成”。
|
||||
|
||||
要为笔记添加标记,请单击记事本底部的“标记”图标,输入一个或多个以逗号分隔的关键字,然后单击“完成”。
|
||||
|
||||
### 跨设备同步你的笔记
|
||||
|
||||
例如,如果你在多台计算机和 Android 设备上使用 Turtl,Turtl 会在你上线时同步你的笔记。但是,我在同步时遇到了一个小问题:我手机上创建的笔记经常不会同步到我的笔记本电脑上。我尝试通过单击窗口左上角的图标手动同步,然后单击立即同步,但这并不总是有效。我发现偶尔需要单击“设置”图标,然后单击“清除本地数据”。然后我需要重新登录 Turtl,但所有数据都能正确同步了。
|
||||
|
||||
### 一个疑问和一些问题
|
||||
|
||||
当我开始使用 Turtl 时,我被一个疑问所困扰:我的笔记保存在哪里?事实证明,Turtl 背后的开发人员位于美国,这也是他们服务器的所在地。虽然 Turtl 使用的加密[非常强大][8]并且你的笔记在服务器上加密,但我偏执地认为你不应该在 Turtl 中保存任何敏感内容(或在任何类似的在线笔记中)。
|
||||
|
||||
Turtl 以平铺视图显示笔记,让人想起 Google Keep:
|
||||
|
||||

|
||||
|
||||
*Turtl 中的一系列笔记*
|
||||
|
||||
无法在桌面或 Android 应用上将其更改为列表视图。这对我来说不是问题,但我听说有些人因为它没有列表视图而不喜欢 Turtl。
|
||||
|
||||
说到 Android 应用,它并不差。但是,它没有与 Android 共享菜单集成。如果你想把在其他应用中看到或阅读的内容添加到 Turtl 笔记中,则需要手动复制并粘贴。
|
||||
|
||||
我已经在我的 Linux 笔记本,[运行 GalliumOS 的 Chromebook][10],还有一台 Android 手机上使用 Turtl 几个月了。对所有这些设备来说这都是一种非常无缝的体验。虽然它不是我最喜欢的开源笔记工具,但 Turtl 做得非常好。试试看它,它可能是你正在寻找的简单的笔记工具。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/17/12/using-turtl-open-source-alternative-evernote
|
||||
|
||||
作者:[Scott Nesbitt][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/scottnesbitt
|
||||
[1]:https://blog.evernote.com/blog/2016/12/15/evernote-revisits-privacy-policy/
|
||||
[2]:https://turtlapp.com/
|
||||
[3]:https://turtlapp.com/download/
|
||||
[4]:https://turtlapp.com/download/
|
||||
[6]:https://en.wikipedia.org/wiki/Markdown
|
||||
[8]:https://turtlapp.com/docs/security/encryption-specifics/
|
||||
[10]:https://opensource.com/article/17/4/linux-chromebook-gallium-os
|
||||
100
published/201901/20171222 10 keys to quick game development.md
Normal file
100
published/201901/20171222 10 keys to quick game development.md
Normal file
@@ -0,0 +1,100 @@
|
||||
快速开发游戏的十个关键
|
||||
======
|
||||
|
||||

|
||||
|
||||
十月初,由 Opensource.com 赞助的首届 [Open Jam][1] 吸引了来自世界各地的团队的 45 个参赛项目。这些队伍只用了三天时间就用开源软件制作出一个游戏来参与角逐,[有三支队伍取得了胜利][2]。
|
||||
|
||||
我们在我们的大学为每一位愿意参与的人举办了我们自己的 Open Jam 活动。我们预留了周末的计算机实验室,并教大家使用开源软件来创建游戏和游戏素材:游戏引擎:[Godot][3]、音乐:[LMMS][4]、2D 素材:[GIMP][5]、3D 素材:[Blender][6]。我们的活动产出了三个游戏:[Loathsome][7]、[Lost Artist][8] 和 [Paint Rider][9](我做的)。
|
||||
|
||||
根据我在游戏开发和游戏开发方面的经验,这里有 10 条关于游戏引擎、编码和快速游戏开发的经验教训。
|
||||
|
||||
### 1、限定规模
|
||||
|
||||
很容易想要去做一个规模宏大的冒险游戏或者可以比拟你最喜欢的游戏的东西。如果你有一些经验,追求超乎游戏 Jam 活动的东西可能很酷,但不要高估自己拥有的时间。我欣赏游戏 Jam 活动的一点是它强制你快速将一个游戏从概念阶段变成最终产品,因为你的时间非常有限。这也就是限定规模如此重要的原因。
|
||||
|
||||
这个 Open Jam 的主题是“留下痕迹”,题目一出来,我和朋友就开始讨论什么样的游戏适合该主题。一个想法就是做玩家能在敌人身上留下伤痕的 3D 拳击游戏。我几乎没有做 3D 游戏的经验,我想做好的话,在我甚至还没发掘出可玩性之前,就得花太多时间在学习如何让痕迹合理和打击有效。
|
||||
|
||||
### 2、尽早可玩
|
||||
|
||||
这是我对游戏 Jam 活动最中肯的建议。试着做出核心机制,快速写出代码,这样你就可以测试并决定它是否值得做成一个完整的游戏。不应该只剩几个小时截止了,你的游戏才可玩。像 Open Jam 这样的三天的活动,不应该花费几个小时以上来做一个可以运行的演示。
|
||||
|
||||
### 3、保持简单
|
||||
|
||||
你想加入的每个特性都会延长整个开发时间。因为你不能迅速使之运行,所以无从得知提交一个新特性是否会消耗大量时间。街机风格的高分作品往往会在游戏 Jam 活动中表现良好,它们天生就很简单。一旦核心部分完成,你可以开始加入特性并润色,无需担心最后游戏是否功能正常。
|
||||
|
||||
### 4、从其他游戏获取灵感
|
||||
|
||||
可能你想做出完全原创的作品,但有个可以基于它开发的原型极其有用。这将节省重复劳动的时间,因为你已经知道什么有趣。告诉自己实践的经验越多,越容易做出包含自己想法的大型游戏,所以你也能从再创作其他人的作品中得到很好地练习。
|
||||
|
||||
考虑到 Open Jam 的“留下痕迹”主题,我觉得创作一个玩的时候可以留下颜料痕迹的游戏会很有趣,这样也可以看到你留下的标记。我记得有款老式动画游戏 [Line Rider 2 Beta][10] (后来叫 Paint Rider),而且知道玩的时候按住 Control 键可以画出痕迹的彩蛋。我简化了这个概念,甚至只需要一个按键来垂直移动。(更像老式飞机游戏)。进入到 Jam 活动大概一两个小时后,我就有了基本模型,可以用一个按钮上下移动和留下小黑圈的痕迹。
|
||||
|
||||
### 5、不要忽视可得性
|
||||
|
||||
确保尽可能多的人能玩你的游戏。某个提交到 Open Jam 的游戏是虚拟现实游戏。尽管那很酷,但几乎没有人可以玩,因为拥有 VR 设备的人不多。所幸它的开发者并不期望取得好名次,只是想练手。但如果你想和人们分享你的游戏(或者赢得游戏 Jam 活动),注意可得性是很重要的。
|
||||
|
||||
Godot (和其他大多数游戏引擎)允许你在所有主流平台发布游戏。提交游戏时,特别是在 [Itch.io][11],有个浏览器版本就可以支持大多数人玩。但尽你所能去发布在更多的平台和操作系统上。我甚至试着在移动端发布 Paint Rider,但技术有限。
|
||||
|
||||
### 6、不要做得太难
|
||||
|
||||
如果游戏需要花费过多精力去学或者玩,你将失去一部分玩家。要保持简单和限定规模,这在游戏计划阶段非常重要。再次重申,想出一个需要花上十天半个月开发的宏大的游戏创意很容易;难的是做出好玩、简单的游戏。
|
||||
|
||||
给我的妈妈介绍了 Paint Rider 之后,她很快开始玩起来,我认为不需要跟她说明更多。
|
||||
|
||||
### 7、不用太整洁
|
||||
|
||||
如果你习惯于花时间在设计模式上和确保代码可复用、可适应,试着放松一点。如果你花太多时间考虑设计,当你最后到了可以玩游戏的时候,你可能发现游戏不是很有趣,那时候就来不及修改了。
|
||||
|
||||
这过程也适用于简化更严格的游戏:快速码出验证概念性展示模型,直到找出值得做成完整游戏的,然后你可以潜心建立完美的代码来支持它。为游戏 Jame 活动创作的游戏就像是个快速开发一个可验证的模型一样。
|
||||
|
||||
### 8、但也不要太随意
|
||||
|
||||
另一方面, [意大利面式代码][12] 容易失控,即使游戏开发没有大量代码。还好大多是游戏引擎都考虑到了设计模式。就拿 Godot 的[信号][13] 功能来说,节点可以发送数据信息给它们“连上了”的节点 —— 这是你的设计自动成型的[观察者模式][14]。只要你知道如何利用这种游戏引擎的特性的优势,就可以快速写代码,你的代码也不会特别难读。
|
||||
|
||||
### 9、取得反馈
|
||||
|
||||
向人们展示你正在做的。让他们试一试并看看他们说些啥。看看他们如何玩你的游戏,找找他们有没有发现你预料之外的事。如果游戏 Jam 活动有 [Discord][15] 频道或者类似的,把你的游戏放上去,人们会反馈给你想法。Paint Rider 的一个确定的功能是画布循环,所以你可以看到之前留下来的画。在有人问我为什么这个游戏没有之前,我甚至没有考虑那个机制。
|
||||
|
||||
团队协作的话,确保有可以传递周围反馈的人参与这个开发。
|
||||
|
||||
而且不要忘了用相同的方式帮助其他人;如果你在玩其他人游戏的时候发现了有助于你游戏的东西,这就是双赢。
|
||||
|
||||
### 10、哪里找资源
|
||||
|
||||
做出所有你自己的资源真的会拖你后腿。Open Jam 期间,当我忙于组装新特性和修漏洞时,我注意到 Loathsome 的开发者花了大量时间在绘制主要角色上。你可以简化游戏的艺术风格创作并且用一些视听效果尚可的东西,但这里还有其他选择。试着寻找 [Creative Commons][16] 许可的或免费音乐站点(比如 [Anttis Instrumentals][17])的资源。或者,可行的话,组建一个有专门艺术家、作家或者音乐家的团队。
|
||||
|
||||
其他你可能觉得有用的软件有 [Krita][18],这是一款适合数字绘画的开源 2D 图像生成软件,特别是如果你有一块绘图板的话;还有 [sfxr][19],这是一款游戏音效生成软件,很多参数可以调,但正如它的开发者所说:“它的基本用法包括了按下随机按钮。”(Paint Rider 的所有音效都是用 Sfxr 做的。)你也可以试试 [Calinou][20] 的众多但有序的开源游戏开发软件列表。
|
||||
|
||||
你参加 Open Jam 或者其他游戏 Jam 并有别的建议吗?对我未提及的有问题吗?有的话,请在评论中分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/17/12/10-keys-rapid-open-source-game-development
|
||||
|
||||
作者:[Ryan Estes][a]
|
||||
译者:[XYenChi](https://github.com/XYenChi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/figytuna
|
||||
[1]:https://itch.io/jam/open-jam-1
|
||||
[2]:https://opensource.com/article/17/11/open-jam
|
||||
[3]:https://godotengine.org/
|
||||
[4]:https://lmms.io/
|
||||
[5]:https://www.gimp.org/
|
||||
[6]:https://www.blender.org/
|
||||
[7]:https://astropippin.itch.io/loathsome
|
||||
[8]:https://masonraus.itch.io/lost-artist
|
||||
[9]:https://figytuna.itch.io/paint-rider
|
||||
[10]:http://www.andkon.com/arcade/racing/lineriderbeta2/
|
||||
[11]:https://itch.io/
|
||||
[12]:https://en.wikipedia.org/wiki/Spaghetti_code
|
||||
[13]:http://kidscancode.org/blog/2017/03/godot_101_07/
|
||||
[14]:https://en.wikipedia.org/wiki/Observer_pattern
|
||||
[15]:https://discordapp.com/
|
||||
[16]:https://creativecommons.org/
|
||||
[17]:http://www.soundclick.com/bands/default.cfm?bandID=1277008
|
||||
[18]:https://krita.org/en/
|
||||
[19]:http://www.drpetter.se/project_sfxr.html
|
||||
[20]:https://notabug.org/Calinou/awesome-gamedev/src/master/README.md
|
||||
@@ -0,0 +1,316 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10423-1.html)
|
||||
[#]: subject: (YAML: probably not so great after all)
|
||||
[#]: via: (https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html)
|
||||
[#]: author: (Martin Tournoij https://arp242.net/)
|
||||
|
||||
YAML:可能并不是那么完美
|
||||
======
|
||||
|
||||
我之前写过[为什么将 JSON 用于人类可编辑的配置文件是一个坏主意][1],今天我们将讨论 YAML 格式的一些常见问题。
|
||||
|
||||
### 默认情况下不安全
|
||||
|
||||
YAML 默认是不安全的。加载用户提供的(不可信的)YAML 字符串需要仔细考虑。
|
||||
|
||||
```
|
||||
!!python/object/apply:os.system
|
||||
args: ['ls /']
|
||||
```
|
||||
|
||||
用 `print(yaml.load(open('a.yaml')))` 运行它,应该给你这样的东西:
|
||||
|
||||
```
|
||||
bin etc lib lost+found opt root sbin tmp var sys
|
||||
boot dev efi home lib64 mnt proc run srv usr
|
||||
0
|
||||
```
|
||||
|
||||
许多其他语言(包括 Ruby 和 PHP [^1] )默认情况下也不安全(LCTT 译注:这里应该说的是解析 yaml)。[在 GitHub 上搜索 yaml.load][2] 会得到惊人的 280 万个结果,而 [yaml.safe_load][3] 只能得到 26000 个结果。
|
||||
|
||||
提个醒,很多这样的 `yaml.load()` 都工作的很好,在配置文件中加载 `yaml.load()` 通常没问题,因为它通常(虽然并不总是!)来自“可靠源”,而且很多都来自静态的 YAML 测试文件。但是,人们还是不禁怀疑在这 280 万个结果中隐藏了多少漏洞。
|
||||
|
||||
这不是一个理论问题。在 2013 年,[正是由于这个问题,所有的 Ruby on Rails 应用程序都被发现易受][4]远程代码执行攻击。
|
||||
|
||||
有人可能会反驳说这不是 YAML 格式的错误,而是那些库实现错误的的问题,但似乎大多数库默认不是安全的(特别是动态语言),所以事实上这是 YAML 的一个问题。
|
||||
|
||||
有些人可能会反驳认为修复它就像用 `safe_load()` 替换 `load()` 一样容易,但是很多人都没有意识到这个问题,即使你知道它,它也是很容易忘记的事情之一。这是非常糟糕的 API 设计。
|
||||
|
||||
### 可能很难编辑,特别是对于大文件
|
||||
|
||||
YAML 文件可能很难编辑,随着文件变大,这个难度会快速增大。
|
||||
|
||||
一个很好的例子是 Ruby on Rails 的本地化翻译文件。例如:
|
||||
|
||||
```
|
||||
en:
|
||||
formtastic:
|
||||
labels:
|
||||
title: "Title" # Default global value
|
||||
article:
|
||||
body: "Article content"
|
||||
post:
|
||||
new:
|
||||
title: "Choose a title..."
|
||||
body: "Write something..."
|
||||
edit:
|
||||
title: "Edit title"
|
||||
body: "Edit body"
|
||||
```
|
||||
|
||||
看起来不错,对吧?但是如果这个文件有 100 行怎么办?或者 1,000 行?在文件中很难看到 “where”,因为它可能在屏幕外。你需要向上滚动,但是你需要跟踪缩进,即使遵循缩进指南也很难,特别是因为 2 个空格缩进是常态而且 [制表符缩进被禁止][5] [^2] 。
|
||||
|
||||
不小心缩进出错通常不算错误,它通常只是反序列化为你不想要的东西。这样只能祝你调试快乐!
|
||||
|
||||
我已经愉快地编写 Python 长达十多年,所以我已经习惯了显眼的空白,但有时候我仍在和 YAML 抗争。在 Python 中,虽然没有那种长达几页的函数,但数据或配置文件的长度没有这种自然限制,这就带来了缺点和损失了清晰度。
|
||||
|
||||
对于小文件,这不是问题,但它确实无法很好地扩展到较大的文件,特别是如果你以后想编辑它们的话。
|
||||
|
||||
### 这非常复杂
|
||||
|
||||
在浏览一个基本的例子时,YAML 看似“简单”和“显而易见”,但事实证明并非如此。[YAML 规范][6]有 23449 个单词,为了比较,[TOML][7] 有 3339 个单词,[Json][8] 有 1969 个单词,[XML][9] 有 20603 个单词。
|
||||
|
||||
我们中有谁读过全部规范吗?有谁读过并理解了全部?谁阅读过,理解进而**记住**所有这些?
|
||||
|
||||
例如,你知道[在 YAML 中编写多行字符串有 9 种方法][10]吗?并且它们具有细微的不同行为。
|
||||
|
||||
是的 :-/
|
||||
|
||||
如果你看一下[那篇文章的修订历史][11],它就会变得更加有趣,因为文章的作者发现了越来越多的方法可以实现这一点,以及更多的细微之处。
|
||||
|
||||
它从预览开始告诉我们 YAML 规范,它表明(强调我的):
|
||||
|
||||
> 本节简要介绍了 YAML 的表达能力。**预计初次阅读的人不可能理解所有的例子**。相反,这些选择用作该规范其余部分的动机。
|
||||
|
||||
#### 令人惊讶的行为
|
||||
|
||||
以下会解析成什么([Colm O’Connor][12] 提供的例子):
|
||||
|
||||
```
|
||||
- Don Corleone: Do you have faith in my judgment?
|
||||
- Clemenza: Yes
|
||||
- Don Corleone: Do I have your loyalty?
|
||||
```
|
||||
|
||||
结果为:
|
||||
|
||||
```
|
||||
[
|
||||
{'Don Corleone': 'Do you have faith in my judgment?'},
|
||||
{'Clemenza': True},
|
||||
{'Don Corleone': 'Do I have your loyalty?'}
|
||||
]
|
||||
```
|
||||
|
||||
那么这个呢:
|
||||
|
||||
```
|
||||
python: 3.5.3
|
||||
postgres: 9.3
|
||||
```
|
||||
|
||||
`3.5.3` 被识别为字符串,但 `9.3` 被识别为数字而不是字符串:
|
||||
|
||||
```
|
||||
{'python': '3.5.3', 'postgres': 9.3}
|
||||
```
|
||||
|
||||
这个呢:
|
||||
|
||||
```
|
||||
Effenaar: Eindhoven
|
||||
013: Tilburg
|
||||
```
|
||||
|
||||
`013` 是<ruby>蒂尔堡<rt>Tilburg<rt></ruby>的一个流行音乐场地,但 YAML 会告诉你错误答案,因为它被解析为八进制数字:
|
||||
|
||||
```
|
||||
{11: 'Tilburg', 'Effenaar': 'Eindhoven'}
|
||||
```
|
||||
|
||||
所有这一切,以及更多,就是为什么许多经验丰富的 YAMLer 经常会将所有字符串用引号引起来的原因,即使它不是严格要求。许多人不使用引号,而且很容易忘记,特别是如果文件的其余部分(可能由其他人编写)不使用引号。
|
||||
|
||||
### 它不方便
|
||||
|
||||
因为它太复杂了,它所声称的可移植性被夸大了。例如,考虑以下这个从 YAML 规范中获取的示例:
|
||||
|
||||
```
|
||||
? - Detroit Tigers
|
||||
- Chicago cubs
|
||||
:
|
||||
- 2001-07-23
|
||||
|
||||
? [ New York Yankees,
|
||||
Atlanta Braves ]
|
||||
: [ 2001-07-02, 2001-08-12,
|
||||
2001-08-14 ]
|
||||
```
|
||||
|
||||
抛开大多数读者可能甚至不知道这是在做什么之外,请尝试使用 PyYAML 在 Python 中解析它:
|
||||
|
||||
```
|
||||
yaml.constructor.ConstructorError: while constructing a mapping
|
||||
in "a.yaml", line 1, column 1
|
||||
found unhashable key
|
||||
in "a.yaml", line 1, column 3
|
||||
```
|
||||
|
||||
在 Ruby 中,它可以工作:
|
||||
|
||||
```
|
||||
{
|
||||
["Detroit Tigers", "Chicago cubs"] => [
|
||||
#<Date: 2001-07-23 ((2452114j,0s,0n),+0s,2299161j)>
|
||||
],
|
||||
["New York Yankees", "Atlanta Braves"] => [
|
||||
#<Date: 2001-07-02 ((2452093j,0s,0n),+0s,2299161j)>,
|
||||
#<Date: 2001-08-12 ((2452134j,0s,0n),+0s,2299161j)>,
|
||||
#<Date: 2001-08-14 ((2452136j,0s,0n),+0s,2299161j)>
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
这个原因是你不能在 Python 中使用列表作为一个字典的键:
|
||||
|
||||
```
|
||||
>>> {['a']: 'zxc'}
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
TypeError: unhashable type: 'list'
|
||||
```
|
||||
|
||||
而这种限制并不是 Python 特有的,PHP、JavaScript 和 Go 等常用语言都有此限制。
|
||||
|
||||
因此,在 YAML 文件中使用这种语法,你将无法在大多数语言中解析它。
|
||||
|
||||
这是另一个从 YAML 规范的示例部分中获取的:
|
||||
|
||||
```
|
||||
# Ranking of 1998 home runs
|
||||
---
|
||||
- Mark McGwire
|
||||
- Sammy Sosa
|
||||
- Ken Griffey
|
||||
|
||||
# Team ranking
|
||||
---
|
||||
- Chicago Cubs
|
||||
- St Louis Cardinals
|
||||
```
|
||||
|
||||
Python 会输出:
|
||||
|
||||
```
|
||||
yaml.composer.ComposerError: expected a single document in the stream
|
||||
in "a.yaml", line 3, column 1
|
||||
but found another document
|
||||
in "a.yaml", line 8, column 1
|
||||
```
|
||||
|
||||
然而 Ruby 输出:
|
||||
|
||||
```
|
||||
["Mark McGwire", "Sammy Sosa", "Ken Griffey"]
|
||||
```
|
||||
|
||||
原因是单个文件中有多个 YAML 文档(`---` 意味开始一个新文档)。在 Python 中,有一个 `load_all` 函数来解析所有文档,而 Ruby 的 `load()` 只是加载第一个文档,据我所知,它没有办法加载多个文档。
|
||||
|
||||
[在实现之间存在很多不兼容][13]。
|
||||
|
||||
### 目标实现了吗?
|
||||
|
||||
规范说明:
|
||||
|
||||
> YAML 的设计目标是降低优先级:
|
||||
>
|
||||
> 1. YAML 很容易被人类阅读。
|
||||
> 2. YAML 数据在编程语言之间是可移植的。
|
||||
> 3. YAML 匹配敏捷语言的原生数据结构。
|
||||
> 4. YAML 有一个一致的模型来支持通用工具。
|
||||
> 5. YAML 支持一次性处理。
|
||||
> 6. YAML 具有表现力和可扩展性。
|
||||
> 7. YAML 易于实现和使用。
|
||||
|
||||
那么它做的如何呢?
|
||||
|
||||
> YAML 很容易被人类阅读。
|
||||
|
||||
只有坚持一小部分子集时才有效。完整的规则集很复杂 —— 远远超过 XML 或 JSON。
|
||||
|
||||
> YAML 数据在编程语言之间是可移植的。
|
||||
|
||||
事实并非如此,因为创建常见语言不支持的结构太容易了。
|
||||
|
||||
> YAML 匹配敏捷语言的原生数据结构。
|
||||
|
||||
参见上面。另外,为什么只支持敏捷(或动态)语言?其他语言呢?
|
||||
|
||||
> YAML 有一个一致的模型来支持通用工具。
|
||||
|
||||
我甚至不确定这意味着什么,我找不到任何详细说明。
|
||||
|
||||
> YAML 支持一次性处理。
|
||||
|
||||
这点我接受。
|
||||
|
||||
> YAML 具有表现力和可扩展性。
|
||||
|
||||
嗯,是的,但它太富有表现力(例如太复杂)。
|
||||
|
||||
> YAML 易于实现和使用。
|
||||
|
||||
```
|
||||
$ cat `ls -1 ~/gocode/src/github.com/go-yaml/yaml/*.go | grep -v _test` | wc -l
|
||||
9247
|
||||
|
||||
$ cat /usr/lib/python3.5/site-packages/yaml/*.py | wc -l
|
||||
5713
|
||||
```
|
||||
|
||||
### 结论
|
||||
|
||||
不要误解我的意思,并不是说 YAML 很糟糕 —— 它肯定不像[使用 JSON 那么多的问题][1] —— 但它也不是非常好。有一些一开始并不明显的缺点和惊喜,还有许多更好的替代品,如 [TOML][7] 和其他更专业的格式。
|
||||
|
||||
就个人而言,当我有选择时,我不太可能再次使用它。
|
||||
|
||||
如果你必须使用 YAML,那么我建议你使用 [StrictYAML][14],它会删除一些(虽然不是全部)比较麻烦的部分。
|
||||
|
||||
### 反馈
|
||||
|
||||
你可以发送电子邮件至 [martin@arp242.net][15] 或[创建 GitHub issue][16] 以获取反馈、问题等。
|
||||
|
||||
[^1]: 在 PHP 中你需要修改一个 INI 设置来获得安全的行为,不能只是调用像 `yaml_safe()` 这样的东西。PHP 想尽办法让愚蠢的东西越发愚蠢。干得漂亮!
|
||||
[^2]: 不要在这里做空格与制表符之争,如果这里可以用制表符的话,我可以(临时)增加制表符宽度来使它更易读——这是制表符的一种用途。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html
|
||||
|
||||
作者:[Martin Tournoij][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://arp242.net/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://arp242.net/weblog/JSON_as_configuration_files-_please_dont.html
|
||||
[2]: https://github.com/search?q=yaml.load&type=Code&utf8=%E2%9C%93
|
||||
[3]: https://github.com/search?q=yaml.safe_load&type=Code&utf8=%E2%9C%93
|
||||
[4]: https://www.sitepoint.com/anatomy-of-an-exploit-an-in-depth-look-at-the-rails-yaml-vulnerability/
|
||||
[5]: http://www.yaml.org/faq.html
|
||||
[6]: http://yaml.org/spec/1.2/spec.pdf
|
||||
[7]: https://github.com/toml-lang/toml
|
||||
[8]: http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
|
||||
[9]: https://www.w3.org/TR/REC-xml/
|
||||
[10]: http://stackoverflow.com/a/21699210/660921
|
||||
[11]: http://stackoverflow.com/posts/21699210/revisions
|
||||
[12]: https://github.com/crdoconnor/strictyaml/blob/master/FAQ.rst#what-is-wrong-with-implicit-typing
|
||||
[13]: https://github.com/cblp/yaml-sucks
|
||||
[14]: https://github.com/crdoconnor/strictyaml
|
||||
[15]: mailto:martin@arp242.net
|
||||
[16]: https://github.com/Carpetsmoker/arp242.net/issues/new
|
||||
@@ -0,0 +1,90 @@
|
||||
5 款 Linux 街机游戏
|
||||
================
|
||||
|
||||

|
||||
|
||||
长久以来,游戏都是 Linux 的软肋。近些年,Steam、GOG 等游戏发布平台上不少商业游戏都开始支持 Linux,这对于 Linux 的游戏生态来说是件好事,但是我们能在这些平台上玩到的游戏通常是不开源的商业作品。当然,这些游戏在一个开源的操作系统上运行,但对于一个开源提倡者来说这似乎还不够纯粹。
|
||||
|
||||
那么,我们能找到既自由开源又能给玩家带来完整游戏体验的优质游戏吗?当然!虽然绝大多数的开源游戏很难和 3A 商业游戏大作竞争,但仍然有不少各种类型的开源游戏,不仅内容有趣而且直接可以通过几大 Linux 发行版本库中直接安装。
|
||||
|
||||
本文首先介绍 Linux 开源游戏中的街机类型游戏,在之后的文章中,我将介绍桌面和卡牌游戏,解谜游戏,竞速游戏,以及策略模拟游戏。
|
||||
|
||||
### <ruby>太空危机<rt>AstroMenace</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[太空危机][3] 是一个近现代太空背景下的滚动页面射击游戏。开发初期它是一个闭源游戏,但它的代码和素材而后以开源许可证发布了。游戏玩法和大多数此类游戏大同小异,但它有质量极高的 3D 画面。飞船和武器升级可以通过击杀敌人所获得的点数购买。游戏的难度可以选择,因此适合新手以及想要追求挑战的硬核玩家。
|
||||
|
||||
安装太空危机,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户: `dnf install astromenace`
|
||||
- Debian/Ubuntu 用户: `apt install astromenace`
|
||||
|
||||
### <ruby>坦克战役<rt>Battle Tanks</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[坦克战役][4] 是一个俯瞰式视角的快节奏坦克战斗游戏。玩家可以选择三种不同的陆地坦克,操纵其在地图上前行,收集道具并且尝试炸飞敌军。它有四种游戏模式,死亡竞赛(又称“死斗”)、团队死斗、夺旗模式和合作模式。死斗和夺旗模式下,分别有 9 张地图可供玩家选择,合作模式则有 4 张。该游戏支持分屏本地双人游戏,以及在线多人竞技。游戏节奏很快,默认一次战役仅 5 分钟,因此,坦克战役十分适合想要利用零碎时间快速来一局的玩家。
|
||||
|
||||
安装坦克战役,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户: `dnf install btanks`
|
||||
- Debian/Ubuntu 用户: `apt install btanks`
|
||||
|
||||
### <ruby>火星<rt>M.A.R.S.</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[火星][5] 是一个自上而下的太空射击游戏,游戏机制类似传统街机游戏 “<ruby>爆破彗星<rt>Asteroids</rt></ruby>”。玩家在操控一个太空船的同时向敌方射击并躲避敌军的弹幕射击。游戏有标准的死斗和团体死斗模式,除此之外也有更新鲜的比赛形式 —— 例如在一个模式下,玩家需要控制一个球使其进入敌方母星。该游戏支持本地多人游戏,但遗憾的是不支持多人联机。该游戏的开发更新似乎已经停止,所以该游戏之后增加联机模式的几率很小,但就算没有联机支持,这个游戏仍然值得一试。
|
||||
|
||||
安装火星,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户: `dnf install marsshooter`
|
||||
- Debian/Ubuntu 用户: `apt install marsshooter`
|
||||
|
||||
### <ruby>不存在之球<rt>Neverball</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[不存在之球][6] 的游戏灵感来源自世嘉的 “<ruby>超级猴子球<rt>Super Monkey Ball</rt></ruby>” ,玩家需要将一个球在 3D 球场上运动起来,但是玩家控制的不是球,而是球场。游戏任务是在规定的时限内,收集足够多的金币从而打开该关卡的出口并且将小球落进该洞中。游戏可以调整难度,从休闲到难以超乎想象,可以适应不同的玩家需求。该游戏支持键盘/鼠标以及控制杆操作。
|
||||
|
||||
安装不存在之球,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户:`dnf install neverball`
|
||||
- Debian/Ubuntu 用户:`apt install neverball`
|
||||
|
||||
### <ruby>超级 Tux<rt>SuperTux</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[超级 Tux][7] 是继任天堂超级马里奥后的一款 2D 的平台跳跃游戏。Linux 的吉祥物企鹅 Tux 代替了马里奥,而鸡蛋对应着马里奥系列中的蘑菇能力提升。当 Tux 获得了鸡蛋得到了能力提升,它便可以收集花朵,而花朵可以带来新的附加特殊能力。火焰花在关卡中最为常见,收集了火焰花的 Tux 可以掷出火球。除此之外,冰冻花/空气花/土地花也在游戏的程序中。收集星星的能力提升能使 Tux 暂时变得隐形,就如同马里奥系列游戏。该游戏最基础的一组关卡,冰之岛也有 30 关之多,因此游戏的内容和流程和超级马里奥系列一般长。SuperTux 还有一些附加关卡,例如三个额外奖励小岛、一个森林之岛、一个万圣节岛、一个孵化处,以及很多测试关卡。SuperTux 有一个自带的关卡编辑器,所以玩家可以创建他们的原创关卡。
|
||||
|
||||
安装超级 Tux,你只需要在终端下运行以下指令:
|
||||
|
||||
- Fedora 用户:`dnf install supertux`
|
||||
- Debian/Ubuntu 用户: `apt install supertux`
|
||||
|
||||
如果我没有在上文中提及你最喜欢的开源街机游戏,欢迎在评论中分享。
|
||||
|
||||
### 有关作者
|
||||
|
||||
Joshua Allen Holm - 是 Opensource.com 的社区协调者之一。他的主要兴趣有数字人文、学术开放以及公开教育资源。你可以在 GitHub、GitLab、LinkedIn 和 Zotero 上找到他。可以通过 holmja@opensource.com 联系到他。
|
||||
|
||||
------
|
||||
|
||||
via: https://opensource.com/article/18/1/arcade-games-linux
|
||||
|
||||
作者:[Joshua Allen Holm][a]
|
||||
译者:[Scoutydren](https://github.com/Scoutydren)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/holmja
|
||||
[1]: http://store.steampowered.com/
|
||||
[2]: https://www.gog.com/
|
||||
[3]: http://www.viewizard.com/
|
||||
[4]: http://btanks.sourceforge.net/blog/about-game
|
||||
[5]: http://mars-game.sourceforge.net/?page_id=10
|
||||
[6]: https://neverball.org/index.php
|
||||
[7]: http://supertux.org/
|
||||
@@ -0,0 +1,261 @@
|
||||
tmux:适用于重度命令行 Linux 用户的终端复用器
|
||||
======
|
||||
|
||||
tmux 是<ruby>终端复用器<rt>terminal multiplexer</rt></ruby>的缩写,它允许用户在单个窗口中创建或启用多个终端(垂直或水平),当你处理不同的问题时,可以在单个窗口中轻松访问和控制它们。
|
||||
|
||||
它使用客户端-服务器模型,允许在用户之间共享会话,也可以将终端连接到 tmux 会话。我们可以根据需要轻松移动或重新排列虚拟控制台。终端会话可以从一个虚拟控制台自由切换到另一个。
|
||||
|
||||
tmux 依赖于 `libevent` 和 `ncurses` 库。tmux 在屏幕底部提供了一个状态行,它显示当前 tmux 会话的有关信息,例如当前窗口编号、窗口名称、用户名、主机名、当前时间和日期。
|
||||
|
||||
启动 tmux 时,它会在一个单独窗口上创建一个新的会话,并将其显示在屏幕上。它允许用户在同一个会话中创建任意数量的窗口。
|
||||
|
||||
许多人说它类似于 `screen`,但我不这么认为,因为它提供了许多配置选项。
|
||||
|
||||
**注意:** `Ctrl+b` 是 tmux 中的默认命令前缀,因此,要在 tmux 中执行任何操作,你必须先输入该前缀然后输入所需的选项。
|
||||
|
||||
### tmux 特性
|
||||
|
||||
* 创建任意数量的窗口
|
||||
* 在一个窗口中创建任意数量的窗格
|
||||
* 它允许垂直和水平分割
|
||||
* 分离并重新连接窗口
|
||||
* 客户端-服务器架构,这允许用户之间共享会话
|
||||
* tmux 提供许多配置技巧
|
||||
|
||||
**建议阅读:**
|
||||
|
||||
- [tmate - 马上与其他人分享你的终端会话][2]
|
||||
- [Teleconsole - 一个与其他人分享终端会话的工具][3]
|
||||
|
||||
### 如何安装 tmux 命令
|
||||
|
||||
大多数 Linux 系统默认预安装 tmux 命令。如果没有,按照以下步骤安装。
|
||||
|
||||
对于 Debian/Ubuntu,使用 [APT-GET 命令][4]或 [APT 命令][5]来安装:
|
||||
|
||||
```
|
||||
$ sudo apt install tmux
|
||||
```
|
||||
|
||||
对于 RHEL/CentOS,使用 [YUM 命令][6]来安装:
|
||||
|
||||
```
|
||||
$ sudo yum install tmux
|
||||
```
|
||||
|
||||
对于 Fedora,使用 [DNF 命令][7]来安装:
|
||||
|
||||
```
|
||||
$ sudo dnf install tmux
|
||||
```
|
||||
|
||||
对于 Arch Linux,使用 [Pacman 命令][8]来安装:
|
||||
|
||||
```
|
||||
$ sudo pacman -S tmux
|
||||
```
|
||||
|
||||
对于 openSUSE,使用 [Zypper 命令][9]来安装:
|
||||
|
||||
```
|
||||
$ sudo zypper in tmux
|
||||
```
|
||||
|
||||
### 如何使用 tmux
|
||||
|
||||
在终端上运行以下命令来启动 tmux 会话。启动 tmux 后,它会在一个新窗口中创建新会话,并将使用你的用户账户自动登录到你的默认 shell。
|
||||
|
||||
```
|
||||
$ tmux
|
||||
```
|
||||
|
||||
![][11]
|
||||
|
||||
你会得到类似于我们上面的截图。tmux 附带状态栏,显示有关当前会话详细信息、日期、时间等。
|
||||
|
||||
状态栏信息如下:
|
||||
|
||||
* `[0]`:它表示由 tmux 服务器创建的会话号。默认情况下,它从 0 开始。
|
||||
* `0:bash`:表示会话号、命令行提示符(这里的 `bash` 表示 shell 名称)。
|
||||
* `*`:这表示该窗口现在处于活动状态。
|
||||
* 主机名:显示服务器的完全主机名。
|
||||
* 日期与时间:显示当前日期和时间。
|
||||
|
||||
(LCTT 译注:tmux 的状态可以根据需要定制,也会因环境、版本的不同而不同。)
|
||||
|
||||
### 如何拆分窗口
|
||||
|
||||
tmux 允许用户垂直或水平分割窗口,称为窗格。每个窗格都包含自己独立运行的终端实例。我们来看看如何做到这一点。
|
||||
|
||||
按下 `Ctrl+b, %` 来垂直分割窗格。
|
||||
|
||||
![][13]
|
||||
|
||||
按下 `Ctrl+b, "` 来水平分割窗格。
|
||||
|
||||
![][14]
|
||||
|
||||
### 如何在窗格之间移动
|
||||
|
||||
假设,我们创建了一些窗格,希望在它们之间移动,这该怎么做?如果你不知道怎么做,那么使用 tmux 就没有意义了。使用以下控制键执行操作。在窗格之间移动有许多方法。
|
||||
|
||||
- 按 `Ctrl+b, ←` - 选择左边的窗格
|
||||
- 按 `Ctrl+b, →` - 选择右边的窗格
|
||||
- 按 `Ctrl+b, ↑` - 选择上边的窗格
|
||||
- 按 `Ctrl+b, ↓` - 选择下边的窗格
|
||||
- 按 `Ctrl+b, {` - 来向左交换窗格
|
||||
- 按 `Ctrl+b, }` - 来向右交换窗格
|
||||
- 按 `Ctrl+b, o` - 切换到下一个窗格(从左到右,从上到下)
|
||||
- 按 `Ctrl+b, ;` - 移动到先前活动的窗格
|
||||
|
||||
出于测试目的,我们将在窗格之间移动。现在我们在 `pane2` 中,它展示了 `lsb_release -a` 命令的输出。
|
||||
|
||||
![][15]
|
||||
|
||||
我们将移动到 `pane0`,它显示 `uname -a` 命令的输出。
|
||||
|
||||
![][16]
|
||||
|
||||
### 如何打开/创建新窗口
|
||||
|
||||
你可以在一个终端内打开任意数量的窗口。
|
||||
|
||||
- 按 `Ctrl+b, c` 来创建一个新窗口。
|
||||
- 按 `Ctrl+b, n` 移动到下一个窗口。
|
||||
- 按 `Ctrl+b, p` 移动到上一个窗口。
|
||||
- 按 `Ctrl+b, 0` ~ `Ctrl+b, 9` 立即移动到特定窗口。
|
||||
- 按 `Ctrl+b, l` 移动到先前选择的窗口。
|
||||
|
||||
我有两个窗口,第一个窗口有三个窗格,其中包含操作系统版本信息,`top` 命令输出和内核信息。
|
||||
|
||||
![][17]
|
||||
|
||||
第二个窗口有两个窗格,其中包含 Linux 发行版 logo 信息。使用以下命令执行操作:
|
||||
|
||||
![][18]
|
||||
|
||||
按 `Ctrl+b, w` 以交互方式选择当前窗口。
|
||||
|
||||
![][19]
|
||||
|
||||
### 如何缩放窗格
|
||||
|
||||
你正在一些非常小的窗格中工作,并且你希望将其缩小以进行进一步的工作。要做到这一点,使用以下键绑定。
|
||||
|
||||
目前我们有三个窗格,我在 `pane1` 工作,它使用 `top` 命令显示系统活动信息,我将缩放它。
|
||||
|
||||
![][17]
|
||||
|
||||
缩放窗格时,它将隐藏所有其它窗格,并只显示窗口中的缩放窗格。
|
||||
|
||||
![][20]
|
||||
|
||||
按 `Ctrl+b, z` 缩放窗格,并再次按下它使缩放窗格恢复原状。
|
||||
|
||||
### 显示窗格信息
|
||||
|
||||
要了解窗格编号及其大小,运行以下命令。
|
||||
|
||||
按 `Ctrl+b, q` 可简单显示窗格索引。
|
||||
|
||||
![][21]
|
||||
|
||||
### 显示窗口信息
|
||||
|
||||
要知道窗口编号、布局大小,与窗口关联的窗格数量及其大小等,运行以下命令。
|
||||
|
||||
只需运行 `tmux list-windows` 即可查看窗口信息。
|
||||
|
||||
![][22]
|
||||
|
||||
### 如何调整窗格大小
|
||||
|
||||
你可能需要调整窗格大小来满足你的要求。你必须按下 `Ctrl+b, :`,然后在页面底部的黄色颜色条上输入以下详细信息。
|
||||
|
||||
![][23]
|
||||
|
||||
在上一部分中,我们打印了窗格索引,它同时也显示了窗格大小。为了测试,我们要向增加 `10` 个单元。参考以下输出,该窗格将 pane1 和 pane2 的大小从 `55x21` 增加到 `55x31`。
|
||||
|
||||
![][24]
|
||||
|
||||
**语法:** `Ctrl+b, :` 然后输入 `resize-pane [options] [cells size]`
|
||||
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -D 10` 将当前窗格大小向下调整 10 个单元。
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -U 10` 将当前窗格大小向上调整 10 个单元。
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -L 10` 将当前窗格大小向左调整 10 个单元。
|
||||
- `Ctrl+b, :` 然后输入 `resize-pane -R 10` 将当前窗格大小向右调整 10 个单元。
|
||||
|
||||
### 分离并重新连接 tmux 会话
|
||||
|
||||
tmux 最强大的功能之一是能够在需要时分离和重新连接会话。
|
||||
|
||||
运行一个长时间运行的进程,然后按下 `Ctrl+b`,接着按 `d`,通过离开正在运行的进程安全地分离你的 tmux 会话。
|
||||
|
||||
**建议阅读:** [如何在断开 SSH 会话后保持进程/命令继续运行][25]
|
||||
|
||||
现在,运行一个长时间运行的进程。出于演示目的,我们将把此服务器备份移动到另一个远程服务器以进行灾难恢复(DR)。
|
||||
|
||||
```
|
||||
$ rsync -avzhe ssh /backup root@192.168.0.161:/backups/week-1/
|
||||
```
|
||||
|
||||
在分离 tmux 会话之后,你将获得类似下面的输出。
|
||||
|
||||
```
|
||||
[detached (from session 0)]
|
||||
```
|
||||
|
||||
运行以下命令以列出可用的 tmux 会话。
|
||||
|
||||
```
|
||||
$ tmux ls
|
||||
0: 3 windows (created Tue Jan 30 06:17:47 2018) [109x45]
|
||||
```
|
||||
|
||||
现在,使用适当的会话 ID 重新连接 tmux 会话,如下所示:
|
||||
|
||||
```
|
||||
$ tmux attach -t 0
|
||||
```
|
||||
|
||||
### 如何关闭窗格和窗口
|
||||
|
||||
只需在相应的窗格中输入 `exit` 或按下 `Ctrl-d` 即可关闭它,和终端关闭类似。要关闭窗口,按下 `Ctrl+b, &`。
|
||||
|
||||
好了,就到这里了,希望你喜欢上它。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/tmux-a-powerful-terminal-multiplexer-emulator-for-linux/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.2daygeek.com/author/magesh/
|
||||
[1]:https://www.2daygeek.com/category/terminal-emulator/
|
||||
[2]:https://www.2daygeek.com/tmate-instantly-share-your-terminal-session-to-anyone-in-seconds/
|
||||
[3]:https://www.2daygeek.com/teleconsole-share-terminal-session-instantly-to-anyone-in-seconds/
|
||||
[4]:https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[5]:https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[6]:https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[7]:https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
|
||||
[8]:https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/
|
||||
[9]:https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
|
||||
[10]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[11]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-1.png
|
||||
[13]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-2.png
|
||||
[14]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-3.png
|
||||
[15]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-4.png
|
||||
[16]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-5.png
|
||||
[17]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-8.png
|
||||
[18]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-6.png
|
||||
[19]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-7.png
|
||||
[20]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-9.png
|
||||
[21]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-10.png
|
||||
[22]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-14.png
|
||||
[23]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-11.png
|
||||
[24]:https://www.2daygeek.com/wp-content/uploads/2018/01/tmux-a-powerful-terminal-multiplexer-emulator-for-linux-13.png
|
||||
[25]:https://www.2daygeek.com/how-to-keep-a-process-command-running-after-disconnecting-ssh-session/
|
||||
@@ -0,0 +1,144 @@
|
||||
如何使用 Ansible 管理你的工作站配置
|
||||
======
|
||||
|
||||
> 在这个系列的第一篇中,学习一下管理笔记本电脑和台式机配置的基础内容。
|
||||
|
||||

|
||||
|
||||
配置管理是服务器管理和 DevOps 的一个非常重要的方面。“<ruby>基础架构即代码<rt>infrastructure as code</rt></ruby>”方法可以轻松地以各种配置部署服务器,并动态扩展组织的资源以满足用户需求。但是,对于希望自动设置自己的笔记本电脑和台式机(工作站)的个人管理员的关注较少。
|
||||
|
||||
在本系列中,我将向你展示如何通过 [Ansible][1] 自动化你的工作站设置,如果你想要或需要重新安装你的机器,这可以让你轻松恢复整个配置。此外,如果你有多个工作站,则可以使用相同的方法在每个工作站上进行相同的配置。在第一篇文章中,我们将为个人或工作计算机设置基本的配置管理,并为本系列的其余部分奠定基础。到本文结束时,你将会因此得到一个可以工作的环境。本系列之后的每篇文章都会自动化更多内容并增加复杂性。
|
||||
|
||||
### 为什么用 Ansible?
|
||||
|
||||
有许多配置管理解决方案,包括 Salt Stack、Chef 和 Puppet。我更喜欢 Ansible,因为它在资源利用方面更轻量级,语法更容易阅读,并且如果正确使用它可以彻底改变你的配置管理。Ansible 的轻量级特性与这个主题特别相关,因为我们可能不希望运行一整台服务器而只是为了自动化我们的笔记本电脑和台式机的设置。一般我们总是想要快一些;我们可以使用某些东西来快速启动和运行,以在我们需要恢复的工作站或在多台机器之间同步我们的配置。我使用 Ansible 的具体方法(我将在本文中演示)非常适用于此,而不需要维护服务器。你只需下载配置并运行它。
|
||||
|
||||
### 我的方法
|
||||
|
||||
通常,Ansible 运行于中央服务器。它使用一个<ruby>库存清单<rt>inventory</rt></ruby>文件,该文件是一个文本文件,其中包含我们希望 Ansible 管理的所有主机及其 IP 地址或域名的列表。这对于静态环境非常有用,但对于工作站来说并不理想。原因是我们真的不知道我们的工作站在某一时刻的状态。也许我关闭了台式电脑,或者笔记本电脑可能会被挂起并放在我的包里。在任何一种情况下,Ansible 服务器都会抱怨,因为如果它们处于脱机状态,Ansible 就无法联系到我的机器。我们更需要的是按需方式,我们通过利用 `ansible-pull` 来实现这一目标。`ansible-pull` 命令是 Ansible 的一个命令,允许你从 Git 仓库下载配置并立即应用它。你不需要维护服务器或库存清单;你只需运行 `ansible-pull` 命令,给它一个 Git 仓库 URL,它将为你完成剩下的工作。
|
||||
|
||||
### 起步
|
||||
|
||||
首先,在要管理的计算机上安装 Ansible。有一个问题是许多发行版都附带了旧版本的 Ansible。根据经验,你肯定希望获得最新版本。Ansible 中经常引入新功能,如果你运行的是旧版本,则你在网上找到的示例语法可能无法正常运行,因为它使用的功能未在你安装的版本中实现。甚至发布的小版本都有很多新功能。其中一个例子是 `dconf` 模块,它是从 Ansible 2.4 开始的新功能。如果你尝试使用使用此模块的语法,除非你使用 2.4 或更新版本,否则会失败。在 Ubuntu 及其衍生产品中,我们可以使用官方个人包存档([PPA][2])轻松安装最新版本的 Ansible。以下命令可以解决这个问题:
|
||||
|
||||
```
|
||||
sudo apt-get install software-properties-common
|
||||
sudo apt-add-repository ppa:ansible/ansible
|
||||
sudo apt-get update
|
||||
sudo apt-get install ansible
|
||||
```
|
||||
|
||||
如果你没有使用 Ubuntu,请参阅 [Ansible 的文档][3] 了解如何为你的平台获取它。
|
||||
|
||||
接下来,我们需要一个 Git 仓库来保存我们的配置。满足此要求的最简单方法是在 GitHub 上创建一个空的仓库,或者如果有的话,也可以使用自己的 Git 服务器。为了简单起见,我假设你正在使用 GitHub,因此如果你正在使用其他仓库,请相应调整命令。在 GitHub 中创建一个仓库;你最终会得到一个与此类似的仓库 URL:
|
||||
|
||||
```
|
||||
git@github.com:<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
将该仓库克隆到你的本地工作目录(忽略任何抱怨仓库为空的消息):
|
||||
|
||||
```
|
||||
git clone git@github.com:<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
现在我们有了一个可以使用的空仓库。将你的工作目录切换到仓库(例如 `cd ./ansible`),并在你喜欢的文本编辑器中创建名为 `local.yml` 的文件。将以下配置放在该文件中:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install htop
|
||||
apt: name=htop
|
||||
```
|
||||
|
||||
你刚刚创建的文件被称为<ruby>剧本<rt>playbook</rt></ruby>,安装 `htop` 的指令(我任意选择的一个包作为例子)被称为<ruby>动作<rt>play</rt></ruby>。剧本本身是一个 YAML 格式的文件,它是一种易于阅读的标记语言。对 YAML 的完整讲述超出了本文的范围,但你无需专业理解即可熟练使用 Ansible。该配置易于阅读;只需查看此文件,你就可以轻松理解我们正在安装的 `htop` 软件包。要注意一下最后一行的 `apt` 模块,它只适用于基于 Debian 的系统。如果你使用的是 Red Hat 平台,你可以将其更改为 `yum` 而不是 `apt`,或者如果你正在使用 Fedora,则将其更改为 `dnf`。`name` 行只是提供有关我们任务的信息,并将显示在输出中。因此,你需要确保名称具有描述性,以便在需要对多个动作进行故障排除时很容易找到。
|
||||
|
||||
接下来,让我们将新文件提交到我们的仓库:
|
||||
|
||||
```
|
||||
git add local.yml
|
||||
git commit -m "initial commit"
|
||||
git push origin master
|
||||
```
|
||||
|
||||
现在我们的新剧本应该出现在我们的 GitHub 上的仓库中。我们可以使用以下命令应用我们创建的剧本:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
如果执行正确,`htop`包应该会安装在你的系统上。你可能会在开头附近看到一些警告,抱怨缺少库存清单文件。这很好,因为我们没有使用库存清单文件(我们也不需要这样做)。在输出结束时,它将概述它做的内容。如果 `htop` 安装正确,你应该在输出的最后一行看到 `changed = 1`。
|
||||
|
||||
它是如何工作的呢?`ansible-pull` 命令使用了 `-U` 选项,它需要一个仓库 URL。出于安全考虑,我给它提供了仓库 URL 的 https 版本,因为我不希望任何主机对仓库具有写访问权限(默认情况下 https 是只读的)。`local.yml` 是预设的剧本名称,因此我们不需要为剧本提供文件名:如果它在仓库的根目录中找到名为 `local.yml` 的剧本,它将自动运行它。接下来,我们在命令前面使用了 `sudo`,因为我们正在修改系统。
|
||||
|
||||
让我们继续为我们的剧本添加更多的包。我将添加两个包,使它看起来像这样:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install htop
|
||||
apt: name=htop
|
||||
|
||||
- name: Install mc
|
||||
apt: name=mc
|
||||
|
||||
- name: Install tmux
|
||||
apt: name=tmux
|
||||
```
|
||||
|
||||
我添加了更多的动作(任务)来安装另外两个包,`mc` 和 `tmux`。在此剧本中选择安装的哪些软件包并不重要;我只是随意挑选这些。你应该安装你希望所有的系统都具有的软件包。唯一需要注意的是,在你分发前,你必须知道那个包存在于软件仓库中。
|
||||
|
||||
在我们提交并应用这个更新的剧本之前,我们应该整理一下它。它可以很好地工作,但(说实话)它看起来有点混乱。让我们尝试在一个动作中安装所有三个包。用下面这个替换你的 `local.yml` 的内容:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install packages
|
||||
apt: name={{item}}
|
||||
with_items:
|
||||
- htop
|
||||
- mc
|
||||
- tmux
|
||||
```
|
||||
|
||||
现在看起来更干净、更有效率了。我们使用 `with_items` 将我们的包列表合并为一个动作。如果我们想要添加其他包,我们只需添加另一个带有连字符和包名称的行。可以把 `with_items` 看做类似于 `for` 循环。我们列出的每个包都将安装。
|
||||
|
||||
将我们的新更改提交回仓库:
|
||||
|
||||
```
|
||||
git add local.yml
|
||||
git commit -m "added additional packages, cleaned up formatting"
|
||||
git push origin master
|
||||
```
|
||||
|
||||
现在我们可以运行我们的剧本以接受新的新配置:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<your_user_name>/ansible.git
|
||||
```
|
||||
|
||||
不可否认,这个例子还没有做多少事情;它所做的就是安装一些软件包。你可以使用包管理器更快地安装这些包。然而,随着这个系列的继续,这些例子将变得更加复杂,我们将自动化更多的东西。最后,你创建的 Ansible 配置将自动执行越来越多的任务。例如,我自己使用的那个配置可以自动安装数百个软件包、设置cron 作业、处理桌面配置等等。
|
||||
|
||||
从我们迄今为止所取得的成就来看,你可能已经有了大概了解。我们所要做的就是创建一个仓库,在该仓库中放置一个剧本,然后利用 `ansible-pull` 命令拉取该仓库并将其应用到我们的机器上。我们不需要设置服务器。将来,如果我们想要更改配置,我们可以拉取该仓库、更新它,然后将其推回到我们的仓库并应用它。如果我们要设置新机器,我们只需要安装 Ansible 并应用配置。
|
||||
|
||||
在下一篇文章中,我们将通过 cron 和一些其他项目进一步自动化。与此同时,我已将本文的代码复制到
|
||||
[我的 GitHub 仓库][4] 中,以便你可以用你的语法对比一下我的。随着我们的进展,我会不断更新代码。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/manage-workstation-ansible
|
||||
|
||||
作者:[Jay LaCroix][a]
|
||||
译者:[wxy](https://github.com/)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/jlacroix
|
||||
[1]:https://www.ansible.com/
|
||||
[2]:https://launchpad.net/ubuntu/+ppas
|
||||
[3]:http://docs.ansible.com/ansible/latest/intro_installation.html
|
||||
[4]:https://github.com/jlacroix82/ansible_article
|
||||
@@ -0,0 +1,154 @@
|
||||
用 PGP 保护代码完整性(四):将主密钥移到离线存储中
|
||||
======
|
||||
> 如果开发者的 PGP 密钥被偷了,危害非常大。了解一下如何更安全。
|
||||
|
||||

|
||||
|
||||
在本系列教程中,我们为使用 PGP 提供了一个实用指南。你可以从下面的链接中查看前面的文章:
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
|
||||
这是本系列教程的第四部分,我们继续本教程,我们将谈一谈如何及为什么要将主密钥从你的家目录移到离线存储中。现在开始我们的教程。
|
||||
|
||||
#### 清单
|
||||
|
||||
* 准备一个加密的可移除的存储(必要)
|
||||
* 备份你的 GnuPG 目录(必要)
|
||||
* 从你的家目录中删除主密钥(推荐)
|
||||
* 从你的家目录中删除吊销证书(推荐)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
为什么要从你的家目录中删除你的主 [C] 密钥 ?这样做的主要原因是防止你的主密钥失窃或意外泄露。对于心怀不轨的人来说,私钥对他们具有很大的诱惑力 —— 我们知道有几个恶意软件成功地实现了扫描用户的家目录并将发现的私钥内容上传。
|
||||
|
||||
对于开发者来说,私钥失窃是非常危险的事情 —— 在自由软件的世界中,这无疑是身份证明失窃。从你的家目录中删除私钥将帮你防范这类事件的发生。
|
||||
|
||||
#### 备份你的 GnuPG 目录
|
||||
|
||||
**!!!绝对不要跳过这一步!!!**
|
||||
|
||||
备份你的 PGP 密钥将让你在需要的时候很容易地恢复它们,这很重要!(这与我们做的使用 paperkey 的灾难级备份是不一样的)。
|
||||
|
||||
#### 准备可移除的加密存储
|
||||
|
||||
我们从取得一个(最好是两个)小型的 USB “拇指“ 驱动器(可加密 U 盘)开始,我们将用它来做备份。你首先需要去加密它们:
|
||||
|
||||
加密密码可以使用与主密钥相同的密码。
|
||||
|
||||
#### 备份你的 GnuPG 目录
|
||||
|
||||
加密过程结束之后,重新插入 USB 驱动器并确保它能够正常挂载。你可以通过运行 `mount` 命令去找到设备挂载点的完全路径。(在 Linux 下,外置介质一般挂载在 `/media/disk` 下,Mac 一般在它的 `/Volumes` 下)
|
||||
|
||||
你知道了挂载点的全路径后,将你的整个 GnuPG 的目录复制进去:
|
||||
|
||||
```
|
||||
$ cp -rp ~/.gnupg [/media/disk/name]/gnupg-backup
|
||||
```
|
||||
|
||||
(注意:如果出现任何套接字不支持的错误,没有关系,直接忽略它们。)
|
||||
|
||||
现在,用如下的命令去测试一下,确保它们能够正常地工作:
|
||||
|
||||
```
|
||||
$ gpg --homedir=[/media/disk/name]/gnupg-backup --list-key [fpr]
|
||||
```
|
||||
|
||||
如果没有出现任何错误,说明一切正常。弹出这个 USB 驱动器并给它粘上一个明确的标签,以便于你下次需要它时能够很快找到它。接着,将它放到一个安全的 —— 但不要太远 —— 的地方,因为从现在起,你需要偶尔使用它来做一些像编辑身份信息、添加或吊销子证书、或签署其它人的密钥这样的事情。
|
||||
|
||||
#### 删除主密钥
|
||||
|
||||
我们家目录中的文件并没有像我们所想像的那样受到保护。它们可能会通过许多不同的方式被泄露或失窃:
|
||||
|
||||
* 通过快速复制来配置一个新工作站时的偶尔事故
|
||||
* 通过系统管理员的疏忽或恶意操作
|
||||
* 通过安全性欠佳的备份
|
||||
* 通过桌面应用中的恶意软件(浏览器、pdf 查看器等等)
|
||||
* 通过跨境胁迫
|
||||
|
||||
使用一个很好的密码来保护你的密钥是降低上述风险的一个很好方法,但是密码能够通过键盘记录器、背后窥视、或其它方式被发现。基于以上原因,我们建议去配置一个从你的家目录上可移除的主密钥,将它保存在一个离线存储中。
|
||||
|
||||
##### 删除你的主密钥
|
||||
|
||||
**请查看前面的节,确保你有完整的你的 GnuPG 目录的一个备份。如果你没有一个可用的备份,下面所做的操作将会使你的主密钥失效!!!**
|
||||
|
||||
首先,识别你的主密钥的 keygrip:
|
||||
|
||||
```
|
||||
$ gpg --with-keygrip --list-key [fpr]
|
||||
```
|
||||
|
||||
它的输出应该像下面这样:
|
||||
|
||||
```
|
||||
pub rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
||||
111122223333444455556666AAAABBBBCCCCDDDD
|
||||
Keygrip = AAAA999988887777666655554444333322221111
|
||||
uid [ultimate] Alice Engineer <alice@example.org>
|
||||
uid [ultimate] Alice Engineer <allie@example.net>
|
||||
sub rsa2048 2017-12-06 [E]
|
||||
Keygrip = BBBB999988887777666655554444333322221111
|
||||
sub rsa2048 2017-12-06 [S]
|
||||
Keygrip = CCCC999988887777666655554444333322221111
|
||||
```
|
||||
|
||||
找到 `pub` 行下方的 `Keygrip` 条目(就在主密钥指纹的下方)。它与你的家目录下 `.gnupg` 目录下的一个文件是一致的:
|
||||
|
||||
```
|
||||
$ cd ~/.gnupg/private-keys-v1.d
|
||||
$ ls
|
||||
AAAA999988887777666655554444333322221111.key
|
||||
BBBB999988887777666655554444333322221111.key
|
||||
CCCC999988887777666655554444333322221111.key
|
||||
```
|
||||
|
||||
现在你做的全部操作就是简单地删除与主密钥 keygrip 一致的 `.key` 文件:
|
||||
|
||||
```
|
||||
$ cd ~/.gnupg/private-keys-v1.d
|
||||
$ rm AAAA999988887777666655554444333322221111.key
|
||||
```
|
||||
|
||||
现在,如果运行 `--list-secret-keys` 命令将出现问题,它将显示主密钥丢失(`#` 表示不可用):
|
||||
|
||||
```
|
||||
$ gpg --list-secret-keys
|
||||
sec# rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
||||
111122223333444455556666AAAABBBBCCCCDDDD
|
||||
uid [ultimate] Alice Engineer <alice@example.org>
|
||||
uid [ultimate] Alice Engineer <allie@example.net>
|
||||
ssb rsa2048 2017-12-06 [E]
|
||||
ssb rsa2048 2017-12-06 [S]
|
||||
```
|
||||
|
||||
#### 删除吊销证书
|
||||
|
||||
你应该去删除的另一个文件是吊销证书(**删除之前,确保你的备份中有它**),它是使用你的主密钥自动创建的。吊销证书允许一些人去永久标记你的证书为吊销状态,这意味着它无论在任何用途中将不再被使用或信任。一般是使用它来吊销由于某些原因不再受控的一个密钥 —— 比如,你丢失了密钥密码。
|
||||
|
||||
与使用主密钥一样,如果一个吊销证书泄露到恶意者手中,他们能够使用它去破坏你的开发者数字身份,因此,最好是从你的家目录中删除它。
|
||||
|
||||
```
|
||||
cd ~/.gnupg/openpgp-revocs.d
|
||||
rm [fpr].rev
|
||||
```
|
||||
|
||||
在下一篇文章中,你将学习如何保护你的子密钥。敬请期待。
|
||||
|
||||
从来自 Linux 基金会和 edX 的免费课程 [“Linux 入门”][4] 中学习更多 Linux 知识。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-4-moving-your-master-key-offline-storage
|
||||
|
||||
作者:[Konstantin Ryabitsev][a]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
||||
@@ -0,0 +1,285 @@
|
||||
用 PGP 保护代码完整性(五):将子密钥移到一个硬件设备中
|
||||
======
|
||||
|
||||
> 在这个系列教材中,将为你提供使用 PGP 和保护你的私钥的最佳体验。
|
||||
|
||||

|
||||
|
||||
在本系列教程中,我们将提供一个使用 PGP 的实用指南。如果你没有看过前面的文章,你可以通过下面的链接去查看。在这篇文章中,我们将继续讨论如何保护你的密钥,谈一谈将你的子密钥移到一个专门的硬件设备中的一些技巧。
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
- [第四部分:将主密钥移到离线存储中][4]
|
||||
|
||||
#### 清单
|
||||
|
||||
* 取得一个 GnuPG 兼容的硬件设备(必要)
|
||||
* 配置 GnuPG 在设备上工作(必要)
|
||||
* 设置用户和管理员的 PIN(必要)
|
||||
* 移动子密钥到设备中(必要)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
虽然现在主密钥已经不用担心泄露或失窃了,但子密钥仍然在你的家目录中。任何得到它的人都能够解密你的通讯或假冒你的签名(如果他们知道密钥的密码)。并且,每次执行一个 GnuPG 操作都要将密钥加载到操作系统内存中,这将使一些更高级的恶意软件有机会得到你的密钥(想想 Meltdown 和 Spectre)。
|
||||
|
||||
完全保护密钥的最好方式就是,将它移到一个专门的硬件设备中,这种硬件设备是一个可操作的智能卡。
|
||||
|
||||
##### 智能卡的好处
|
||||
|
||||
一个智能卡包含一个加密芯片,它能够存储私钥,并且直接在智能卡内部执行秘密操作。因为密钥内容从来没有离开过智能卡,计算机操作系统并不能检索你插入的智能卡上的私钥。这与前面用于备份目的的加密 USB 存储是不同的 —— 虽然 USB 设备也是插入并解密的,但操作系统是能够去访问私钥内容的。使用外置的加密 USB 介质并不能代替智能卡设备的功能。
|
||||
|
||||
智能卡的一些其它好处:
|
||||
|
||||
* 它们很便宜且易于获得
|
||||
* 它们小巧且易于携带
|
||||
* 它们可以用于多种设备上
|
||||
* 它们中的很多都具有防篡改功能(取决于制造商)
|
||||
|
||||
#### 可用的智能卡设备
|
||||
|
||||
智能卡最初是嵌入到真实钱包大小的卡中,故而得名智能卡。你肯定可以买到并使用 GnuPG 功能的智能卡,并且它们是你能得到的最便宜的可用设备之一。但是,事实上智能卡有一个很重要的缺点:它们需要一个智能卡读卡器,只有极小数的笔记本电脑上有这种读卡器。
|
||||
|
||||
由于这个原因,制造商开始推出小型 USB 设备,它的大小和 U 盘类似,内置有微型智能卡,并且在芯片上简单地实现了智能卡协议特性。下面推荐几个这样的设备:
|
||||
|
||||
* [Nitrokey Start][5]:开源硬件和自由软件,可用于 GnuPG 的最便宜的选择之一,但是额外的安全特性很少。
|
||||
* [Nitrokey Pro][6]:类似于 Nitrokey Start,它提供防篡改及更多的安全特性(但没有 U2F,具体查看指南的 U2F 节)。
|
||||
* [Yubikey 4][7]:专利硬件和软件,但比 Nitrokey Pro 便宜,并且可以用在最新的笔记本电脑上的 USB-C 接口;也提供像 U2F 这样的额外的安全特性。
|
||||
|
||||
我们推荐选一个同时具备智能卡功能和 U2F 的设备,在写这篇文章时,只能选择 Yubikey 4。
|
||||
|
||||
#### 配置智能卡设备
|
||||
|
||||
你的智能卡设备插入任何一台现代的 Linux 或 Mac 工作站上都应该能正常工作。你可以通过运行如下的命令去验证它:
|
||||
|
||||
```
|
||||
$ gpg --card-status
|
||||
```
|
||||
|
||||
如果你没有收到错误,有一个完整的卡列表,就表示一切正常。不幸的是,排除为什么设备不能正常工作的所有可能原因,已经超出了本指南的范围。如果你的智能卡使用 GnuPG 时有问题,请通过你的操作系统的常见支持通道寻求支持。
|
||||
|
||||
##### PIN 不一定是数字
|
||||
|
||||
注意,尽管名为 “PIN”(暗示你它必须是一个“数字”),不论是用户 PIN 还是管理员 PIN 都不必非要是数字。
|
||||
|
||||
当你收到一个新设备时,它可能设置有一个默认的用户和管理员 PIN,对于 Yubikey,它分别是 `123456` 和 `12345678`。如果它们的 PIN 不是默认的,请查看设备附带的说明书。
|
||||
|
||||
##### 快速设置
|
||||
|
||||
为配置你的智能卡,你需要使用 GnuPG 菜单系统,因此这里并没有更方便的命令行开关:
|
||||
|
||||
```
|
||||
$ gpg --card-edit
|
||||
[...omitted...]
|
||||
gpg/card> admin
|
||||
Admin commands are allowed
|
||||
gpg/card> passwd
|
||||
```
|
||||
|
||||
你应该去设置用户 PIN (1)、管理员 PIN (3)、和重置码 (4)。请确保把它们记录并保存到一个安全的地方 —— 尤其是管理员 PIN 和重置码(它允许你去擦除整个智能卡内容)。你很少使用到管理员 PIN,因此如果你不记录下来,很可能会忘掉它。
|
||||
|
||||
返回到智能卡主菜单,你也可以设置其它值(比如名字、性别、登入日期、等等),但是这些都不是必需的,一旦你的智能卡丢失了,将导致额外的信息泄露。
|
||||
|
||||
#### 将子密钥移到你的智能卡中
|
||||
|
||||
退出卡菜单(使用 `q` 命令)保存所有更改。接下来,我们将你的子密钥移到智能卡中。将需要用到你的 PGP 密钥的密码,在大多数的智能卡操作中都将用到管理员 PIN。记住,那个 `[fpr]` 表示你的密钥的完整的 40 个字符的指纹。
|
||||
|
||||
```
|
||||
$ gpg --edit-key [fpr]
|
||||
|
||||
Secret subkeys are available.
|
||||
|
||||
pub rsa4096/AAAABBBBCCCCDDDD
|
||||
created: 2017-12-07 expires: 2019-12-07 usage: C
|
||||
trust: ultimate validity: ultimate
|
||||
ssb rsa2048/1111222233334444
|
||||
created: 2017-12-07 expires: never usage: E
|
||||
ssb rsa2048/5555666677778888
|
||||
created: 2017-12-07 expires: never usage: S
|
||||
[ultimate] (1). Alice Engineer <alice@example.org>
|
||||
[ultimate] (2) Alice Engineer <allie@example.net>
|
||||
|
||||
gpg>
|
||||
```
|
||||
|
||||
使用 `--edit-key` 再次进入到菜单模式,你将注意到那个密钥清单有一点小差别。从现在开始,所有的命令都是在这个菜单模式下运行,它用 `gpg>` 提示符来表示。
|
||||
|
||||
首先,我们来选择移到智能卡中的密钥 —— 你可以通过键入 `key 1`(它表示选择清单中的第一个密钥)来实现:
|
||||
|
||||
```
|
||||
gpg> key 1
|
||||
```
|
||||
|
||||
这个输出会有一点细微的差别:
|
||||
|
||||
```
|
||||
pub rsa4096/AAAABBBBCCCCDDDD
|
||||
created: 2017-12-07 expires: 2019-12-07 usage: C
|
||||
trust: ultimate validity: ultimate
|
||||
ssb* rsa2048/1111222233334444
|
||||
created: 2017-12-07 expires: never usage: E
|
||||
ssb rsa2048/5555666677778888
|
||||
created: 2017-12-07 expires: never usage: S
|
||||
[ultimate] (1). Alice Engineer <alice@example.org>
|
||||
[ultimate] (2) Alice Engineer <allie@example.net>
|
||||
```
|
||||
|
||||
注意与密钥对应的 `ssb` 行旁边的 `*` —— 它表示这是当前选定的密钥。它是可切换的,意味着如果你再次输入 `key 1`,这个 `*` 将消失,这个密钥将不再被选中。
|
||||
|
||||
现在,我们来将密钥移到智能卡中:
|
||||
|
||||
```
|
||||
gpg> keytocard
|
||||
Please select where to store the key:
|
||||
(2) Encryption key
|
||||
Your selection? 2
|
||||
```
|
||||
|
||||
由于它是我们的 [E] 密钥,把它移到加密区中是有很有意义的。当你提交了你的选择之后,将会被提示输入你的 PGP 密钥的保护密码,接下来输入智能卡的管理员 PIN。如果命令没有返回错误,表示你的密钥已经被移到智能卡中了。
|
||||
|
||||
**重要:** 现在再次输入 `key 1` 去取消选中第一个密钥,并输入 `key 2` 去选择 [S] 密钥:
|
||||
|
||||
```
|
||||
gpg> key 1
|
||||
gpg> key 2
|
||||
gpg> keytocard
|
||||
Please select where to store the key:
|
||||
(1) Signature key
|
||||
(3) Authentication key
|
||||
Your selection? 1
|
||||
```
|
||||
|
||||
你可以使用 [S] 密钥同时做签名和验证,但是我们希望确保它在签名区,因此,我们选择 (`1`)。完成后,如果你的命令没有返回错误,表示操作已成功。
|
||||
|
||||
最后,如果你创建了一个 [A] 密钥,你也可以将它移到智能卡中,但是你需要先取消选中 `key 2`。完成后,选择 `q`:
|
||||
|
||||
```
|
||||
gpg> q
|
||||
Save changes? (y/N) y
|
||||
```
|
||||
|
||||
保存变更将把你的子密钥移到智能卡后,把你的家目录中的相应子密钥删除(没有关系,因为我们的备份中还有,如果更换了智能卡,你需要再做一遍)。
|
||||
|
||||
##### 验证移动后的密钥
|
||||
|
||||
现在,如果你执行一个` --list-secret-keys` 操作,你将看到一个稍有不同的输出:
|
||||
|
||||
```
|
||||
$ gpg --list-secret-keys
|
||||
sec# rsa4096 2017-12-06 [C] [expires: 2019-12-06]
|
||||
111122223333444455556666AAAABBBBCCCCDDDD
|
||||
uid [ultimate] Alice Engineer <alice@example.org>
|
||||
uid [ultimate] Alice Engineer <allie@example.net>
|
||||
ssb> rsa2048 2017-12-06 [E]
|
||||
ssb> rsa2048 2017-12-06 [S]
|
||||
```
|
||||
|
||||
在 `ssb>` 的输出中的 `>` 表示子密钥仅在智能卡上有效。如果你进入到你的密钥目录中,查看目录的内容,你将会看到那个 `.key` 文件已经被存根替换:
|
||||
|
||||
```
|
||||
$ cd ~/.gnupg/private-keys-v1.d
|
||||
$ strings *.key
|
||||
```
|
||||
|
||||
这个输出将包含一个影子私钥,它表示那个文件仅是个存根,真正的内容在智能卡中。
|
||||
|
||||
#### 验证智能卡的功能
|
||||
|
||||
验证智能卡能否如期正常运行,你可以通过创建一个签名来验证:
|
||||
|
||||
```
|
||||
$ echo "Hello world" | gpg --clearsign > /tmp/test.asc
|
||||
$ gpg --verify /tmp/test.asc
|
||||
```
|
||||
|
||||
首次运行这个命令时将询问你智能卡的 PIN,在你运行 `gpg —verify` 之后,它将显示 “Good signature”。
|
||||
|
||||
祝贺你,你已经成功将窃取你的开发者数字身份变得更加困难了!
|
||||
|
||||
#### 其它常见 GnuPG 操作
|
||||
|
||||
下面是使用你的 PGP 密钥需要做的一些常见操作的快速指南。
|
||||
|
||||
在下面的所有命令中,`[fpr]` 表示你的密钥指纹。
|
||||
|
||||
##### 挂载主密钥离线存储
|
||||
|
||||
下面的一些操作将需要你的主密钥,因此首先需要去挂载你的主密钥离线存储,并告诉 GnuPG 去使用它。首先,找出介质挂载路径,可以通过查看 `mount` 命令的输出找到它。接着,设置你的 GnuPG 目录为你的介质上备份的目录,并告诉 GnuPG 将那个目录做为它的家目录:
|
||||
|
||||
```
|
||||
$ export GNUPGHOME=/media/disk/name/gnupg-backup
|
||||
$ gpg --list-secret-keys
|
||||
```
|
||||
|
||||
确保你在输出中看到的是 `sec` 而不是 `sec#`(这个 `#` 表示密钥不可用,仍然使用的是惯常的那个 Home 目录)。
|
||||
|
||||
##### 更新你惯常使用的那个 GnuPG 工作目录
|
||||
|
||||
在你的离线存储上做了任何更改之后,你应该将这些更改同步应用到你惯常使用的工作目录中:
|
||||
|
||||
```
|
||||
$ gpg --export | gpg --homedir ~/.gnupg --import
|
||||
$ unset GNUPGHOME
|
||||
```
|
||||
|
||||
##### 延长密钥过期日期
|
||||
|
||||
我们创建的主密钥的默认过期日期是自创建之日起两年后。这样做都是为安全考虑,这样将使淘汰密钥最终从密钥服务器上消失。
|
||||
|
||||
延长你的密钥过期日期,从当前日期延长一年,只需要运行如下命令:
|
||||
|
||||
```
|
||||
$ gpg --quick-set-expire [fpr] 1y
|
||||
```
|
||||
|
||||
如果为了好记住,你也可以使用一个特定日期(比如,你的生日、1 月 1 日、或加拿大国庆日):
|
||||
|
||||
```
|
||||
$ gpg --quick-set-expire [fpr] 2020-07-01
|
||||
```
|
||||
|
||||
记得将更新后的密钥发送到密钥服务器:
|
||||
|
||||
```
|
||||
$ gpg --send-key [fpr]
|
||||
```
|
||||
|
||||
##### 吊销身份
|
||||
|
||||
如果你需要吊销一个身份(比如,你换了雇主并且旧的邮件地址不再有效了),你可以使用一行命令搞定:
|
||||
|
||||
```
|
||||
$ gpg --quick-revoke-uid [fpr] 'Alice Engineer <aengineer@example.net>'
|
||||
```
|
||||
|
||||
你也可以通过使用 `gpg --edit-key [fpr]` 在菜单模式下完成同样的事情。
|
||||
|
||||
完成后,记得将更新后的密钥发送到密钥服务器上:
|
||||
|
||||
```
|
||||
$ gpg --send-key [fpr]
|
||||
```
|
||||
|
||||
下一篇文章中,我们将谈谈 Git 如何支持 PGP 的多级别集成。
|
||||
|
||||
通过来自 Linux 基金会和 edX 的免费课程 [“Linux 入门”][8]学习更多 Linux 知识。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-5-moving-subkeys-hardware-device
|
||||
|
||||
作者:[KONSTANTIN RYABITSEV][a]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://linux.cn/article-10402-1.html
|
||||
[5]:https://shop.nitrokey.com/shop/product/nitrokey-start-6
|
||||
[6]:https://shop.nitrokey.com/shop/product/nitrokey-pro-3
|
||||
[7]:https://www.yubico.com/product/yubikey-4-series/
|
||||
[8]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
||||
@@ -0,0 +1,62 @@
|
||||
关于团队敏捷开发实践的 6 个常见问题
|
||||
======
|
||||
|
||||
> 专家回答了敏捷实践如何帮助团队更有效的 6 个常见问题。
|
||||
|
||||

|
||||
|
||||
”有问题么?“
|
||||
|
||||
你可能听过演讲者在演讲结束的时候提出这个问题。这是演讲中最重要的部分 —— 毕竟,你不仅仅是听讲座, 而是参加讨论和社群交流。
|
||||
|
||||
最近,我有机会听到我的同伴 Red Hatters 给当地一所大学的一群技术型学生做一个名为 “[敏捷实践][1]” 的讲座。讲座中有软件工程师 Tomas Tomecek 和敏捷开发的从业者 Fernando Colleone 、Pavel Najman 合作解释了敏捷开发方法的基础,并展示最佳实践在日常活动中的应用。
|
||||
|
||||
知道了学生们参加这个课程是为了了解什么是敏捷实践以及如何将其应用于项目,我想知道学生们的问题会与我作为敏捷从业者在 Red Hat 每天听到的问题相比有什么不同。结果学生的疑问和我的同事们如出一辙。这些问题都直指敏捷实践的核心。
|
||||
|
||||
### 1、完美的团队规模是多大?
|
||||
|
||||
学生们想知道一个小团队和一个大团队的规模是多少。这个问题与任何曾经合作过做项目的人都是相关的。根据 Tomas 作为技术领导的经验,12 个人从事的项目被认为是一个大型团队。现实中,团队规模通常与生产力没有直接关系。在有些时候,在一个地方或同一个时区的小团队也许会比一个成员分布在满世界的大团队更具有生产力。最终,该讲座建议理想的团队大小大概是 5 个人(正如 scrum 开发方法的 7,+-2)。
|
||||
|
||||
### 2、团队会面临哪些实际挑战?
|
||||
|
||||
演讲者比较了由本地团队组成的项目(团队成员都是一个办公室的,或者相邻近的人)与分散型的团队(位于不同时区)。当项目需要团队成员之间密切合作时,工程师更喜欢本地的团队,因为时间差异造成的延迟可能会破坏软件开发的“流”。同时,分散型团队可以将可能不适用与当地项目但适用于某些开发用例的技能集合在一起。此外,还有各种最佳方法可用于改进分散型团队中的合作方式。
|
||||
|
||||
### 3、整理堆积的工作需要多少时间?
|
||||
|
||||
因为这是一个对于新学习敏捷的学生的介绍性质的演讲,演讲者着重把 [Scrum][2] 和 [Kanban][3] 作为介绍敏捷开发的方法。他们使用 Scrum 框架来作为说明软件编写的方法,并且用 Kanban 作为工作规划和沟通的系统。关于需要多少时间来整理项目堆积的工作,演讲者解释说并没有固定的准则,相对的,实践出真知:在开发的早期阶段,当一个崭新的项目 —— 特别如果团队里有新人 —— 每周可能会花费数个小时在整理工作上。随着时间推移和不断地练习,会越来越高效。
|
||||
|
||||
### 4、产品负责人是否是必要的? 他们扮演什么样的角色?
|
||||
|
||||
产品负责人会帮助团队更方便的拓展,然而,职位名称并不重要,重要的是你的团队中有人能够传递用户的意愿。在许多团队中,特别是在大型团队中从事单个任务的团队,首席工程师就可以担任产品负责人。
|
||||
|
||||
### 5、建议使用哪些敏捷开发的工具?使用 Scrum 或 Kanban 做敏捷开发的时候必须用特定的软件么?
|
||||
|
||||
尽管使用一些专业软件例如 Jira 或 Trello 会很有帮助,特别是在与大量从事大型企业项目的工作者合作时,但它们不是必需的。Scrum 和 Kanban 可以使用像纸卡这样简单的工具完成。关键是在团队中要有一个清晰的信息来源和紧密的交流。推荐两个优秀的 kanban 开源工具 [Taiga][4] 和 [Wekan][5]。更多信息请查看 [Trello 的 5 个开源替代品][6] 和 [敏捷团队的最好的 7 个开源项目管理工具][7] 。
|
||||
|
||||
### 6、学生如何在学校项目中使用敏捷开发技术?
|
||||
|
||||
演讲者鼓励学生使用 kanban 在项目结束前使用可视化和概述要完成的任务。关键是要创建一个公共板块,这样整个团队就可以看到项目的状态。通过使用 kanban 或者类似的高度可视化的策略,学生不会在项目后期才发现个别成员没有跟上进度。
|
||||
|
||||
Scrum 实践比如 sprints 和 daily standups 也是确认每个人都在进步以及项目的各个部分最终会一起发挥作用的绝佳方法。定期检查和信息共享也至关重要。更多关于 Scrum 的信息,访问 [什么是 scrum?][8] 。
|
||||
|
||||
牢记 Kanban 和 Scrum 只是敏捷开发中众多框架和工具中的两个而已。它们可能不是应对每一种情况的最佳方法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/agile-mindset
|
||||
|
||||
作者:[Dominika Bula][a]
|
||||
译者:[lixinyuxx](https://github.com/lixinxyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dominika
|
||||
[1]:http://zijemeit.cz/sessions/agile-in-practice/
|
||||
[2]:https://www.scrum.org/resources/what-is-scrum
|
||||
[3]:https://en.wikipedia.org/wiki/Kanban
|
||||
[4]:https://taiga.io/
|
||||
[5]:https://wekan.github.io/
|
||||
[6]:https://opensource.com/alternatives/trello
|
||||
[7]:https://opensource.com/article/18/2/agile-project-management-tools
|
||||
[8]:https://opensource.com/resources/scrum
|
||||
@@ -0,0 +1,283 @@
|
||||
用 PGP 保护代码完整性(六):在 Git 上使用 PGP
|
||||
======
|
||||
|
||||
> 我们继续我们的 PGP 实践系列,来看看签名标签的标签和提交,这可以帮你确保你的仓库没有被篡改。
|
||||
|
||||

|
||||
|
||||
在本系列教程中,我们提供了一个使用 PGP 的实用指南,包括基本概念和工具、生成和保护你的密钥。如果你错过了前面的文章,你可以查看下面的链接。在这篇文章中,我们谈一谈在 Git 中如何集成 PGP、使用签名的标签,然后介绍签名提交,最后添加签名推送的支持。
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
- [第四部分:将主密钥移到离线存储中][4]
|
||||
- [第五部分:将子密钥移到硬件设备中][5]
|
||||
|
||||
Git 的核心特性之一就是它的去中心化本质 —— 一旦仓库克隆到你的本地系统,你就拥有了项目的完整历史,包括所有的标签、提交和分支。然而由于存在着成百上千的克隆仓库,如何才能验证你下载的仓库没有被恶意的第三方做过篡改?你可以从 GitHub 或一些貌似官方的位置来克隆它们,但是如果有些人故意欺骗了你怎么办?
|
||||
|
||||
或者在你参与的一些项目上发现了后门,而 “Author” 行显示是你干的,然而你很确定 [不是你干的][6],会发生什么情况?
|
||||
|
||||
为解决上述问题,Git 添加了 PGP 集成。签名的标签通过确认它的内容与创建这个标签的开发者的工作站上的内容完全一致来证明仓库的完整性,而签名的提交几乎是不可能在不访问你的 PGP 密钥的情况下能够假冒你。
|
||||
|
||||
#### 清单
|
||||
|
||||
* 了解签名的标签、提交和推送(必要)
|
||||
* 配置 git 使用你的密钥(必要)
|
||||
* 学习标签如何签名和验证(必要)
|
||||
* 配置 git 总是签名带注释标签(推荐)
|
||||
* 学习提交如何签名和验证工作(必要)
|
||||
* 配置 git 总是签名提交(推荐)
|
||||
* 配置 gpg-agent 选项(必要)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
git 实现了 PGP 的多级集成,首先从签名标签开始,接着介绍签名提交,最后添加签名推送的支持。
|
||||
|
||||
##### 了解 Git 哈希
|
||||
|
||||
git 是一个复杂的东西,为了你能够更好地掌握它如何集成 PGP,你需要了解什么是”哈希“。我们将它归纳为两种类型的哈希:树哈希和提交哈希。
|
||||
|
||||
###### 树哈希
|
||||
|
||||
每次你向仓库提交一个变更,对于仓库中的每个子目录,git 都会记录它里面所有对象的校验和哈希 —— 内容(blobs)、目录(trees)、文件名和许可等等。它只对每次提交中发生变更的树和内容做此操作,这样在只变更树的一小部分时就不必去重新计算整个树的校验和。
|
||||
|
||||
然后再计算和存储处于顶级的树的校验和,这样如果仓库的任何一部分发生变化,校验和将不可避免地发生变化。
|
||||
|
||||
###### 提交哈希
|
||||
|
||||
一旦创建了树哈希,git 将计算提交哈希,它将包含有关仓库和变更的下列信息:
|
||||
|
||||
* 树哈希的校验和
|
||||
* 变更前树哈希的校验和(父级)
|
||||
* 有关作者的信息(名字、email、创作时间)
|
||||
* 有关提交者的信息(名字、email、提交时间)
|
||||
* 提交信息
|
||||
|
||||
###### 哈希函数
|
||||
|
||||
在写这篇文章时,虽然研究一种更强大的、抗碰撞的算法的工作正在进行,但 git 仍然使用的是 SHA1 哈希机制去计算校验和。注意,git 已经包含了碰撞防范程序,因此认为对 git 成功进行碰撞攻击仍然是不可行的。
|
||||
|
||||
#### 带注释标签和标签签名
|
||||
|
||||
在每个 Git 仓库中,标签允许开发者标记特定的提交。标签可以是 “轻量级的” —— 几乎只是一个特定提交上的指针,或者它们可以是 “带注释的”,它自己将成为 git 树中的项目。一个带注释标签对象包含所有下列的信息:
|
||||
|
||||
* 成为标签的提交的哈希的校验和
|
||||
* 标签名字
|
||||
* 关于打标签的人的信息(名字、email、打标签时间)
|
||||
* 标签信息
|
||||
|
||||
一个 PGP 签名的标签是一个带有将所有这些条目封装进一个 PGP 签名的带注释标签。当开发者签名他们的 git 标签时,他们实际上是向你保证了如下的信息:
|
||||
|
||||
* 他们是谁(以及他们为什么应该被信任)
|
||||
* 他们在签名时的仓库状态是什么样:
|
||||
* 标签包含的提交的哈希
|
||||
* 提交的哈希包含了顶级树的哈希
|
||||
* 顶级树哈希包含了所有文件、内容和子树的哈希
|
||||
* 它也包含有关作者的所有信息
|
||||
* 包含变更发生时的精确时间
|
||||
|
||||
当你克隆一个仓库并验证一个签名的标签时,就是向你以密码方式保证:仓库中的所有内容、包括所有它的历史,与开发者签名时在它的计算机上的仓库完全一致。
|
||||
|
||||
#### 签名的提交
|
||||
|
||||
签名的提交与签名的标签非常类似 —— PGP 签名的是提交对象的内容,而不是标签对象的内容。一个提交签名也给你提供了开发者签名时开发者树上的全部可验证信息。标签签名和提交的 PGP 签名提供了有关仓库和它的完整历史的完全一致的安全保证。
|
||||
|
||||
#### 签名的推送
|
||||
|
||||
为了完整起见,在这里包含了签名的推送这一功能,因为在你使用这个功能之前,需要在接收推送的服务器上先启用它。正如我们在上面所说过的,PGP 签名一个 git 对象就是提供了开发者的 git 树当时的可验证信息,但不提供开发者对那个树意图相关的信息。
|
||||
|
||||
比如,你可以在你自己复刻的 git 仓库的一个实验分支上尝试一个很酷的特性,为了评估它,你提交了你的工作,但是有人在你的代码中发现了一个恶意的 bug。由于你的提交是经过正确签名的,因此有人可能将包含有恶意 bug 的分支推入到 master 分支中,从而在生产系统中引入一个漏洞。由于提交是经过你的密钥正确签名的,所以一切看起来都是合理合法的,而当 bug 被发现时,你的声誉就会因此而受到影响。
|
||||
|
||||
在 `git push` 时,为了验证提交的意图而不仅仅是验证它的内容,添加了要求 PGP 推送签名的功能。
|
||||
|
||||
#### 配置 git 使用你的 PGP 密钥
|
||||
|
||||
如果在你的钥匙环上只有一个密钥,那么你就不需要再做额外的事了,因为它是你的默认密钥。
|
||||
|
||||
然而,如果你有多个密钥,那么你必须要告诉 git 去使用哪一个密钥。(`[fpr]` 是你的密钥的指纹):
|
||||
|
||||
```
|
||||
$ git config --global user.signingKey [fpr]
|
||||
```
|
||||
|
||||
注意:如果你有一个不同的 `gpg2` 命令,那么你应该告诉 git 总是去使用它,而不是传统的版本 1 的 `gpg`:
|
||||
|
||||
```
|
||||
$ git config --global gpg.program gpg2
|
||||
```
|
||||
|
||||
#### 如何使用签名标签
|
||||
|
||||
创建一个签名的标签,只要传递一个简单地 `-s` 开关给 `tag` 命令即可:
|
||||
|
||||
```
|
||||
$ git tag -s [tagname]
|
||||
```
|
||||
|
||||
我们建议始终对 git 标签签名,这样让其它的开发者确信他们使用的 git 仓库没有被恶意地修改过(比如,引入后门):
|
||||
|
||||
##### 如何验证签名的标签
|
||||
|
||||
验证一个签名的标签,只需要简单地使用 `verify-tag` 命令即可:
|
||||
|
||||
```
|
||||
$ git verify-tag [tagname]
|
||||
```
|
||||
|
||||
如果你要验证其他人的 git 标签,那么就需要你导入他的 PGP 公钥。请参考 “可信任的团队沟通” 一文中关于此主题的指导。
|
||||
|
||||
##### 在拉取时验证
|
||||
|
||||
如果你从项目仓库的其它复刻中拉取一个标签,git 将自动验证签名,并在合并操作时显示结果:
|
||||
|
||||
```
|
||||
$ git pull [url] tags/sometag
|
||||
```
|
||||
|
||||
合并信息将包含类似下面的内容:
|
||||
|
||||
```
|
||||
Merge tag 'sometag' of [url]
|
||||
|
||||
[Tag message]
|
||||
|
||||
# gpg: Signature made [...]
|
||||
# gpg: Good signature from [...]
|
||||
```
|
||||
|
||||
#### 配置 git 始终签名带注释标签
|
||||
|
||||
很可能的是,你正在创建一个带注释标签,你应该去签名它。强制 git 始终签名带注释的标签,你可以设置一个全局配置选项:
|
||||
|
||||
```
|
||||
$ git config --global tag.forceSignAnnotated true
|
||||
```
|
||||
|
||||
或者,你始终记得每次都传递一个 `-s` 开关:
|
||||
|
||||
```
|
||||
$ git tag -asm "Tag message" tagname
|
||||
```
|
||||
|
||||
#### 如何使用签名的提交
|
||||
|
||||
创建一个签名的提交很容易,但是将它纳入到你的工作流中却很困难。许多项目使用签名的提交作为一种 “Committed-by:” 的等价行,它记录了代码来源 —— 除了跟踪项目历史外,签名很少有人去验证。在某种意义上,签名的提交用于 “篡改证据”,而不是 git 工作流的 “篡改证明”。
|
||||
|
||||
为创建一个签名的提交,你只需要 `git commit` 命令传递一个 `-S` 标志即可(由于它与另一个标志冲突,所以改为大写的 `-S`):
|
||||
|
||||
```
|
||||
$ git commit -S
|
||||
```
|
||||
|
||||
我们建议始终使用签名提交,并要求项目所有成员都这样做,这样其它人就可以验证它们(下面就讲到如何验证)。
|
||||
|
||||
##### 如何去验证签名的提交
|
||||
|
||||
验证签名的提交需要使用 `verify-commit` 命令:
|
||||
|
||||
```
|
||||
$ git verify-commit [hash]
|
||||
```
|
||||
|
||||
你也可以查看仓库日志,要求所有提交签名是被验证和显示的:
|
||||
|
||||
```
|
||||
$ git log --pretty=short --show-signature
|
||||
```
|
||||
|
||||
##### 在 git 合并时验证提交
|
||||
|
||||
如果项目的所有成员都签名了他们的提交,你可以在合并时强制进行签名检查(然后使用 `-S` 标志对合并操作本身进行签名):
|
||||
|
||||
```
|
||||
$ git merge --verify-signatures -S merged-branch
|
||||
```
|
||||
|
||||
注意,如果有一个提交没有签名或验证失败,将导致合并操作失败。通常情况下,技术是最容易的部分 —— 而人的因素使得项目中很难采用严格的提交验证。
|
||||
|
||||
##### 如果你的项目在补丁管理上采用邮件列表
|
||||
|
||||
如果你的项目在提交和处理补丁时使用一个邮件列表,那么一般很少使用签名提交,因为通过那种方式发送时,签名信息将会丢失。对提交进行签名仍然是非常有用的,这样其他人就能引用你托管在公开 git 树作为参考,但是上游项目接收你的补丁时,仍然不能直接使用 git 去验证它们。
|
||||
|
||||
尽管,你仍然可以签名包含补丁的电子邮件。
|
||||
|
||||
#### 配置 git 始终签名提交
|
||||
|
||||
你可以告诉 git 总是签名提交:
|
||||
|
||||
```
|
||||
git config --global commit.gpgSign true
|
||||
```
|
||||
|
||||
或者你每次都记得给 `git commit` 操作传递一个 `-S` 标志(包括 `—amend`)。
|
||||
|
||||
#### 配置 gpg-agent 选项
|
||||
|
||||
GnuPG agent 是一个守护工具,它能在你使用 gpg 命令时随时自动启动,并运行在后台来缓存私钥的密码。这种方式让你只需要解锁一次密钥就可以重复地使用它(如果你需要在一个自动脚本中签署一组 git 操作,而不想重复输入密钥,这种方式就很方便)。
|
||||
|
||||
为了调整缓存中的密钥过期时间,你应该知道这两个选项:
|
||||
|
||||
* `default-cache-ttl`(秒):如果在 TTL 过期之前再次使用同一个密钥,这个倒计时将重置成另一个倒计时周期。缺省值是 600(10 分钟)。
|
||||
* `max-cache-ttl`(秒):自首次密钥输入以后,不论最近一次使用密钥是什么时间,只要最大值的 TTL 倒计时过期,你将被要求再次输入密码。它的缺省值是 30 分钟。
|
||||
|
||||
如果你认为这些缺省值过短(或过长),你可以编辑 `~/.gnupg/gpg-agent.conf` 文件去设置你自己的值:
|
||||
|
||||
```
|
||||
# set to 30 minutes for regular ttl, and 2 hours for max ttl
|
||||
default-cache-ttl 1800
|
||||
max-cache-ttl 7200
|
||||
```
|
||||
|
||||
##### 补充:与 ssh 一起使用 gpg-agent
|
||||
|
||||
如果你创建了一个 [A](验证)密钥,并将它移到了智能卡,你可以将它用到 ssh 上,为你的 ssh 会话添加一个双因子验证。为了与 agent 沟通你只需要告诉你的环境去使用正确的套接字文件即可。
|
||||
|
||||
首先,添加下列行到你的 `~/.gnupg/gpg-agent.conf` 文件中:
|
||||
|
||||
```
|
||||
enable-ssh-support
|
||||
```
|
||||
|
||||
接着,添加下列行到你的 `.bashrc` 文件中:
|
||||
|
||||
```
|
||||
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
|
||||
```
|
||||
|
||||
为了让改变生效,你需要杀掉正在运行的 gpg-agent 进程,并重新启动一个新的登入会话:
|
||||
|
||||
```
|
||||
$ killall gpg-agent
|
||||
$ bash
|
||||
$ ssh-add -L
|
||||
```
|
||||
|
||||
最后的命令将列出代表你的 PGP Auth 密钥的 SSH(注释应该会在结束的位置显示: cardno:XXXXXXXX,表示它来自智能卡)。
|
||||
|
||||
为了启用 ssh 的基于密钥的登入,只需要在你要登入的远程系统上添加 `ssh-add -L` 的输出到 `~/.ssh/authorized_keys` 中。祝贺你,这将使你的 SSH 登入凭据更难以窃取。
|
||||
|
||||
此外,你可以从公共密钥服务器上下载其它人的基于 PGP 的 ssh 公钥,这样就可以赋予他登入 ssh 的权利:
|
||||
|
||||
```
|
||||
$ gpg --export-ssh-key [keyid]
|
||||
```
|
||||
|
||||
如果你有让开发人员通过 ssh 来访问 git 仓库的需要,这将让你非常方便。下一篇文章,我们将提供像保护你的密钥那样保护电子邮件帐户的小技巧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-6-using-pgp-git
|
||||
|
||||
作者:[KONSTANTIN RYABITSEV][a]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://linux.cn/article-10402-1.html
|
||||
[5]:https://linux.cn/article-10415-1.html
|
||||
[6]:https://github.com/jayphelps/git-blame-someone-else
|
||||
@@ -0,0 +1,205 @@
|
||||
使用 Ansible 来管理你的工作站:配置自动化
|
||||
======
|
||||
> 学习如何使 Ansible 自动对一系列台式机和笔记本应用配置。
|
||||
|
||||

|
||||
|
||||
Ansible 是一个令人惊讶的自动化的配置管理工具。其主要应用在服务器和云部署上,但在工作站上的应用(无论是台式机还是笔记本)却鲜少得到关注,这就是本系列所要关注的。
|
||||
|
||||
在这个系列的[第一部分][1],我向你展示了 `ansible-pull` 命令的基本用法,我们创建了一个安装了少量包的剧本。它本身是没有多大的用处的,但是为后续的自动化做了准备。
|
||||
|
||||
在这篇文章中,将会达成闭环,而且在最后部分,我们将会有一个针对工作站自动配置的完整的工作解决方案。现在,我们将要设置 Ansible 的配置,这样未来将要做的改变将会自动的部署应用到我们的工作站上。现阶段,假设你已经完成了[第一部分][1]的工作。如果没有的话,当你完成的时候回到本文。你应该已经有一个包含第一篇文章中代码的 GitHub 库。我们将直接在之前创建的部分之上继续。
|
||||
|
||||
首先,因为我们要做的不仅仅是安装包文件,所以我们要做一些重新的组织工作。现在,我们已经有一个名为 `local.yml` 并包含以下内容的剧本:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Install packages
|
||||
apt: name={{item}}
|
||||
with_items:
|
||||
- htop
|
||||
- mc
|
||||
- tmux
|
||||
```
|
||||
|
||||
如果我们仅仅想实现一个任务那么上面的配置就足够了。随着向我们的配置中不断的添加内容,这个文件将会变的相当的庞大和杂乱。最好能够根据不同类型的配置将我们的<ruby>动作<rt>play</rt></ruby>分为独立的文件。为了达到这个要求,创建一个名为<ruby>任务手册<rt>taskbook</rt></ruby>的东西,它和<ruby>剧本<rt>playbook</rt></ruby>很像但内容更加的流线型。让我们在 Git 库中为任务手册创建一个目录。
|
||||
|
||||
```
|
||||
mkdir tasks
|
||||
```
|
||||
|
||||
`local.yml ` 剧本中的代码可以很好地过渡为安装包文件的任务手册。让我们把这个文件移动到刚刚创建好的 `task` 目录中,并重新命名。
|
||||
|
||||
```
|
||||
mv local.yml tasks/packages.yml
|
||||
```
|
||||
|
||||
现在,我们编辑 `packages.yml` 文件将它进行大幅的瘦身,事实上,我们可以精简除了独立任务本身之外的所有内容。让我们把 `packages.yml` 编辑成如下的形式:
|
||||
|
||||
```
|
||||
- name: Install packages
|
||||
apt: name={{item}}
|
||||
with_items:
|
||||
- htop
|
||||
- mc
|
||||
- tmux
|
||||
```
|
||||
|
||||
正如你所看到的,它使用同样的语法,但我们去掉了对这个任务无用没有必要的所有内容。现在我们有了一个专门安装包文件的任务手册。然而我们仍然需要一个名为 `local.yml` 的文件,因为执行 `ansible-pull` 命令时仍然会去找这个文件。所以我们将在我们库的根目录下(不是在 `task` 目录下)创建一个包含这些内容的全新文件:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: update repositories
|
||||
apt: update_cache=yes
|
||||
changed_when: False
|
||||
|
||||
tasks:
|
||||
- include: tasks/packages.yml
|
||||
```
|
||||
|
||||
这个新的 `local.yml` 扮演的是导入我们的任务手册的索引的角色。我已经在这个文件中添加了一些你在这个系列中还没见到的内容。首先,在这个文件的开头处,我添加了 `pre_tasks`,这个任务的作用是在其他所有任务运行之前先运行某个任务。在这种情况下,我们给 Ansible 的命令是让它去更新我们的发行版的软件库的索引,下面的配置将执行这个任务要求:
|
||||
|
||||
```
|
||||
apt: update_cache=yes
|
||||
```
|
||||
|
||||
通常 `apt` 模块是用来安装包文件的,但我们也能够让它来更新软件库索引。这样做的目的是让我们的每个动作在 Ansible 运行的时候能够以最新的索引工作。这将确保我们在使用一个老旧的索引安装一个包的时候不会出现问题。因为 `apt` 模块仅仅在 Debian、Ubuntu 及它们的衍生发行版下工作。如果你运行的一个不同的发行版,你要使用特定于你的发行版的模块而不是 `apt`。如果你需要使用一个不同的模块请查看 Ansible 的相关文档。
|
||||
|
||||
下面这行也需要进一步解释:
|
||||
|
||||
```
|
||||
changed_when: False
|
||||
```
|
||||
|
||||
在某个任务中的这行阻止了 Ansible 去报告动作改变的结果,即使是它本身在系统中导致的一个改变。在这里,我们不会去在意库索引是否包含新的数据;它几乎总是会的,因为库总是在改变的。我们不会去在意 `apt` 库的改变,因为索引的改变是正常的过程。如果我们删除这行,我们将在过程报告的后面看到所有的变动,即使仅仅库的更新而已。最好忽略这类的改变。
|
||||
|
||||
接下来是常规任务的阶段,我们将创建好的任务手册导入。我们每次添加另一个任务手册的时候,要添加下面这一行:
|
||||
|
||||
```
|
||||
tasks:
|
||||
- include: tasks/packages.yml
|
||||
```
|
||||
|
||||
如果你现在运行 `ansible-pull` 命令,它应该基本上像上一篇文章中做的一样。不同的是我们已经改进了我们的组织方式,并且能够更有效的扩展它。为了节省你到上一篇文章中去寻找,`ansible-pull` 命令的语法参考如下:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<github_user>/ansible.git
|
||||
```
|
||||
|
||||
如果你还记得话,`ansible-pull` 的命令拉取一个 Git 仓库并且应用它所包含的配置。
|
||||
|
||||
既然我们的基础已经搭建好,我们现在可以扩展我们的 Ansible 并且添加功能。更特别的是,我们将添加配置来自动化的部署对工作站要做的改变。为了支撑这个要求,首先我们要创建一个特殊的账户来应用我们的 Ansible 配置。这个不是必要的,我们仍然能够在我们自己的用户下运行 Ansible 配置。但是使用一个隔离的用户能够将其隔离到不需要我们参与的在后台运行的一个系统进程中,
|
||||
|
||||
我们可以使用常规的方式来创建这个用户,但是既然我们正在使用 Ansible,我们应该尽量避开使用手动的改变。替代的是,我们将会创建一个任务手册来处理用户创建任务。这个任务手册目前将会仅仅创建一个用户,但你可以在这个任务手册中添加额外的动作来创建更多的用户。我将这个用户命名为 `ansible`,你可以按照自己的想法来命名(如果你做了这个改变要确保更新所有出现地方)。让我们来创建一个名为 `user.yml` 的任务手册并且将以下代码写进去:
|
||||
|
||||
```
|
||||
- name: create ansible user
|
||||
user: name=ansible uid=900
|
||||
```
|
||||
|
||||
下一步,我们需要编辑 `local.yml` 文件,将这个新的任务手册添加进去,像如下这样写:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: update repositories
|
||||
apt: update_cache=yes
|
||||
changed_when: False
|
||||
|
||||
tasks:
|
||||
- include: tasks/users.yml
|
||||
- include: tasks/packages.yml
|
||||
```
|
||||
|
||||
现在当我们运行 `ansible-pull` 命令的时候,一个名为 `ansible` 的用户将会在系统中被创建。注意我特地通过参数 `uid` 为这个用户声明了用户 ID 为 900。这个不是必须的,但建议直接创建好 UID。因为在 1000 以下的 UID 在登录界面是不会显示的,这样是很棒的,因为我们根本没有需要去使用 `ansibe` 账户来登录我们的桌面。UID 900 是随便定的;它应该是在 1000 以下没有被使用的任何一个数值。你可以使用以下命令在系统中去验证 UID 900 是否已经被使用了:
|
||||
|
||||
```
|
||||
cat /etc/passwd |grep 900
|
||||
```
|
||||
|
||||
不过,你使用这个 UID 应该不会遇到什么问题,因为迄今为止在我使用的任何发行版中我还没遇到过它是被默认使用的。
|
||||
|
||||
现在,我们已经拥有了一个名为 `ansible` 的账户,它将会在之后的自动化配置中使用。接下来,我们可以创建实际的定时作业来自动操作。我们应该将其分开放到它自己的文件中,而不是将其放置到我们刚刚创建的 `users.yml` 文件中。在任务目录中创建一个名为 `cron.yml` 的任务手册并且将以下的代码写进去:
|
||||
|
||||
```
|
||||
- name: install cron job (ansible-pull)
|
||||
cron: user="ansible" name="ansible provision" minute="*/10" job="/usr/bin/ansible-pull -o -U https://github.com/<github_user>/ansible.git > /dev/null"
|
||||
```
|
||||
|
||||
`cron` 模块的语法几乎不需加以说明。通过这个动作,我们创建了一个通过用户 `ansible` 运行的定时作业。这个作业将每隔 10 分钟执行一次,下面是它将要执行的命令:
|
||||
|
||||
```
|
||||
/usr/bin/ansible-pull -o -U https://github.com/<github_user>/ansible.git > /dev/null
|
||||
```
|
||||
|
||||
同样,我们也可以添加想要我们的所有工作站部署的额外的定时作业到这个文件中。我们只需要在新的定时作业中添加额外的动作即可。然而,仅仅是添加一个定时的任务手册是不够的,我们还需要将它添加到 `local.yml` 文件中以便它能够被调用。将下面的一行添加到末尾:
|
||||
|
||||
```
|
||||
- include: tasks/cron.yml
|
||||
```
|
||||
|
||||
现在当 `ansible-pull` 命令执行的时候,它将会以用户 `ansible` 每隔十分钟设置一个新的定时作业。但是,每个十分钟运行一个 Ansible 作业并不是一个好的方式,因为这个将消耗很多的 CPU 资源。每隔十分钟来运行对于 Ansible 来说是毫无意义的,除非我们已经在 Git 仓库中改变一些东西。
|
||||
|
||||
然而,我们已经解决了这个问题。注意我在定时作业中的命令 `ansible-pill` 添加的我们之前从未用到过的参数 `-o`。这个参数告诉 Ansible 只有在从上次 `ansible-pull` 被调用以后库有了变化后才会运行。如果库没有任何变化,它将不会做任何事情。通过这个方法,你将不会无端的浪费 CPU 资源。当然在拉取存储库的时候会使用一些 CPU 资源,但不会像再一次应用整个配置的时候使用的那么多。当 `ansible-pull` 执行的时候,它将会遍历剧本和任务手册中的所有任务,但至少它不会毫无目的的运行。
|
||||
|
||||
尽管我们已经添加了所有必须的配置要素来自动化 `ansible-pull`,它仍然还不能正常的工作。`ansible-pull` 命令需要 `sudo` 的权限来运行,这将允许它执行系统级的命令。然而我们创建的用户 `ansible` 并没有被设置为以 `sudo` 的权限来执行命令,因此当定时作业触发的时候,执行将会失败。通常我们可以使用命令 `visudo` 来手动的去设置用户 `ansible` 去拥有这个权限。然而我们现在应该以 Ansible 的方式来操作,而且这将会是一个向你展示 `copy` 模块是如何工作的机会。`copy` 模块允许你从库复制一个文件到文件系统的任何位置。在这个案列中,我们将会复制 `sudo` 的一个配置文件到 `/etc/sudoers.d/` 以便用户 `ansible` 能够以管理员的权限执行任务。
|
||||
|
||||
打开 `users.yml`,将下面的的动作添加到文件末尾。
|
||||
|
||||
```
|
||||
- name: copy sudoers_ansible
|
||||
copy: src=files/sudoers_ansible dest=/etc/sudoers.d/ansible owner=root group=root mode=0440
|
||||
```
|
||||
|
||||
正如我们看到的,`copy`模块从我们的仓库中复制一个文件到其他任何位置。在这个过程中,我们正在抓取一个名为 `sudoers_ansible`(我们将在后续创建)的文件并将它复制为 `/etc/sudoers/ansible`,并且拥有者为 `root`。
|
||||
|
||||
接下来,我们需要创建我们将要复制的文件。在你的仓库的根目录下,创建一个名为 `files` 的目录:
|
||||
|
||||
```
|
||||
mkdir files
|
||||
```
|
||||
|
||||
然后,在我们刚刚创建的 `files` 目录里,创建名为 `sudoers_ansible` 的文件,包含以下内容:
|
||||
|
||||
```
|
||||
ansible ALL=(ALL) NOPASSWD: ALL
|
||||
```
|
||||
|
||||
就像我们正在这样做的,在 `/etc/sudoer.d` 目录里创建一个文件允许我们为一个特殊的用户配置 `sudo` 权限。现在我们正在通过 `sudo` 允许用户 `ansible` 不需要密码提示就拥有完全控制权限。这将允许 `ansible-pull` 以后台任务的形式运行而不需要手动去运行。
|
||||
|
||||
现在,你可以通过再次运行 `ansible-pull` 来拉取最新的变动:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<github_user>/ansible.git
|
||||
```
|
||||
|
||||
从这里开始,`ansible-pull` 的定时作业将会在后台每隔十分钟运行一次来检查你的仓库是否有变化,如果它发现有变化,将会运行你的剧本并且应用你的任务手册。
|
||||
|
||||
所以现在我们有了一个完整的可工作方案。当你第一次设置一台新的笔记本或者台式机的时候,你要去手动的运行 `ansible-pull` 命令,但仅仅是在第一次的时候。从第一次之后,用户 `ansible` 将会在后台接手后续的运行任务。当你想对你的机器做变动的时候,你只需要简单的去拉取你的 Git 仓库来做变动,然后将这些变化回传到库中。接着,当定时作业下次在每台机器上运行的时候,它将会拉取变动的部分并应用它们。你现在只需要做一次变动,你的所有工作站将会跟着一起变动。这方法尽管有一点不同寻常,通常,你会有一个包含你的机器列表和不同机器所属规则的清单文件。然而,`ansible-pull` 的方法,就像在文章中描述的,是管理工作站配置的非常有效的方法。
|
||||
|
||||
我已经在我的 [Github 仓库][2]中更新了这篇文章中的代码,所以你可以随时去浏览来对比检查你的语法。同时我将前一篇文章中的代码移到了它自己的目录中。
|
||||
|
||||
在[第三部分][3],我们将通过介绍使用 Ansible 来配置 GNOME 桌面设置来结束这个系列。我将会告诉你如何设置你的墙纸和锁屏壁纸、应用一个桌面主题以及更多的东西。
|
||||
|
||||
同时,到了布置一些作业的时候了,大多数人都有我们所使用的各种应用的配置文件。可能是 Bash、Vim 或者其他你使用的工具的配置文件。现在你可以尝试通过我们在使用的 Ansible 库来自动复制这些配置到你的机器中。在这篇文章中,我已将向你展示了如何去复制文件,所以去尝试以下看看你是都已经能应用这些知识。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/manage-your-workstation-configuration-ansible-part-2
|
||||
|
||||
作者:[Jay LaCroix][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[FelixYFZ](https://github.com/FelixYFZ)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/jlacroix
|
||||
[1]:https://linux.cn/article-10434-1.html
|
||||
[2]:https://github.com/jlacroix82/ansible_article.git
|
||||
[3]:https://opensource.com/article/18/5/manage-your-workstation-ansible-part-3
|
||||
@@ -0,0 +1,110 @@
|
||||
用 PGP 保护代码完整性(七):保护在线帐户
|
||||
======
|
||||
|
||||
> 在这个系列的最后一篇当中,我们将为你展示如何用双因子认证保护你的在线账户。
|
||||
|
||||

|
||||
|
||||
到目前为止,本系列教程已经提供了 PGP 的实用指南,包括基本概念和工具、生成和保护你的密钥的步骤。如果你错过了前面的文章,可以通过下面的链接查看。在本系列的最后一篇文章中,我们将为你保护在线帐户提供一个额外的指南,保护在线帐户是当今非常重要的一件事情。
|
||||
|
||||
- [第一部分:基本概念和工具][1]
|
||||
- [第二部分:生成你的主密钥][2]
|
||||
- [第三部分:生成 PGP 子密钥][3]
|
||||
- [第四部分:将主密钥移到离线存储中][4]
|
||||
- [第五部分:将子密钥移到硬件设备中][5]
|
||||
- [第六部分:在 Git 中使用 PGP][6]
|
||||
|
||||
#### 清单
|
||||
|
||||
* 取得一个具备 U2F 功能的设备(必要)
|
||||
* 为你的在线帐户启用双因子认证(必要)
|
||||
* GitHub/GitLab
|
||||
* Google
|
||||
* 社交媒体
|
||||
* 使用 U2F 作为主验证机制,使用 TOTP 作为备选(必要)
|
||||
|
||||
#### 考虑事项
|
||||
|
||||
你可能注意到,很多在线开发者身份是捆绑了 email 地址的。如果有人能够访问你的邮箱,他们就能够去做一些对你会产生危害的事情,进而会损害你作为自由软件开发者的声誉。应该像保护你的 PGP 密钥那样保护你的 email 地址。
|
||||
|
||||
##### 使用 Fido U2F 的双因子认证
|
||||
|
||||
[双因子认证][7] 是一种提升帐户安全性的机制,它除了要求用户名和密码之外,还要求一个物理令牌。它的目标是即便在有人窃取了你的密码(通过按键记录器、肩窥攻击或其它方式)的情况下,仍然能确保你的帐户安全,他们在没有得到你的一个专用的物理设备(“必备”的那个因子)的情况下,始终不能获取你的帐户。
|
||||
|
||||
广为人知的双因子认证机制有:
|
||||
|
||||
* 基于 SMS 的验证
|
||||
* 借助智能手机应用程序的基于时间的一次性令牌(TOTP),比如 Google Authenticator 或类似解决方案
|
||||
* 支持 Fido U2F 的硬件令牌
|
||||
|
||||
基于 SMS 的验证很容易配置,但是它有如下的缺点:它在没有手机信号的地方无法使用(比如,建筑物的地下室),并且如果攻击者能够阻断或转向 SMS 信息,这种方式可能就会失败,比如通过克隆你的 SIM 卡。
|
||||
|
||||
基于 TOTP 的多因子认证提供了比 SMS 更好的安全保护,但它也有一些重要的缺点(你要在智能手机中添加的那么多令牌中找到正确的那个)。此外,还不能避免一个事实,那就是你的密钥最终还是保存在你的智能手机中 —— 它是一个复杂的、全球连接的设备,它有可能还没有及时从制造商那儿收到安全补丁。
|
||||
|
||||
更重要的是,不论是使用 TOTP 还是 SMS 的方法来保护你免受诱骗攻击 —— 如果诱骗攻击者能够窃取你的帐户密码和双因子令牌,他们就可以在合法的站点上使用它们,访问你的帐户。
|
||||
|
||||
[Fido U2F][8] 是一个按标准开发的专用设备,它能够提供双因子认证机制来对付诱骗攻击。U2F 协议在 USB 令牌中保存每个站点的的唯一密钥,如果你在任何合法站点以外的地方尝试使用它,它将阻止你,以防范偶然让攻击者获得你的密码和一次性令牌。
|
||||
|
||||
Chrome 和 Firefox 都支持 U2F 双因子认证,希望其它浏览器也能够提供对 U2F 的支持。
|
||||
|
||||
#### 获得一个支持 Fido U2F 功能的令牌
|
||||
|
||||
支持 U2F 的硬件令牌的 [可选目标很多][9],但如果你已经订购了一个支持智能卡的物理设备,那么你最好的选择就是 Yubikey 4,它两者都支持。
|
||||
|
||||
#### 启用你的在线帐户的双因子认证
|
||||
|
||||
你要确定想启用双因子认证的在线账户,你的 email 提供商已经使用了(特别是 Google,它对 U2F 的支持非常好)。其它的站点这个功能应该是启用了:
|
||||
|
||||
* GitHub:当你上传你的 PGP 公钥时,你应该要想到,如果其他人能够获得访问你的帐户,他们可以用他们自己的 PGP 公钥替换掉你的 PGP 公钥。如果在 GitHub 上发布代码,你应该使用 U2F 认证来保护你的帐户安全。
|
||||
* GitLab:理由同上
|
||||
* Google:如果你有 google 帐户,你就惊奇地发现,许多帐户都允许以 Google 帐户来代替站点专用的认证来登入它们。
|
||||
* Facebook:理由同上,许多在线站点都提供一个选择让你以 Facebook 的帐户来认证。即便你不使用 Facebook 也应该使用双因子认证来保护你的 Facebook 帐户。
|
||||
* 你认为必要的其它站点。查看 [dongleauth.info][10] 去找找灵感。
|
||||
|
||||
#### 如有可能,配置 TOTP 作为备选
|
||||
|
||||
许多站点都允许你配置多个双因子认证机制,推荐的设置是:
|
||||
|
||||
* U2F 令牌作为主认证机制
|
||||
* TOTP 手机应用作为辅助认证机制
|
||||
|
||||
通过这种方式,即便你丢失了你的 U2F 令牌,你仍然能够重新获取对你的帐户的访问。或者,你可以注册多个 U2F 令牌(即:你可以用一个便宜的令牌仅用它做 U2F,并且将它用作备份)。
|
||||
|
||||
### 延伸阅读
|
||||
|
||||
到目前为止,你已经完成了下列的重要任务:
|
||||
|
||||
1. 创建你的开发者身份并使用 PGP 加密来保护它。
|
||||
2. 通过将你的主密钥移到一个离线存储中并将子密钥移到一个外置硬件设备中的方式来配置你的环境,让窃取你的身份变得极为困难。
|
||||
3. 配置你的 Git 环境去确保任何使用你项目的人都能够验证仓库的完整性和它的整个历史。
|
||||
4. 使用双因子认证强化你的在线帐户。
|
||||
|
||||
在安全保护方面,你已经做的很好了,但是你还应该去阅读以下的主题:
|
||||
|
||||
* 如何去强化你的团队沟通。你的项目开发和治理决策的要求应该和保护提交代码那样去保护,如果不这样做,应该确保你的团队沟通是可信任的,并且所有决策的完整性是可验证的。
|
||||
* 如何去强化你的工作站的安全。你的目标是尽可能减少导致项目代码被污染的危险或你的开发者身份被窃的行为。
|
||||
* 如何写出安全的代码(查看相关编程语言和你项目所使用的库的各种文档)。即便引入它的提交代码上有一个 PGP 签名,糟糕的、不安全的代码仍然是糟糕的、不安全的代码!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/pgp/2018/3/protecting-code-integrity-pgp-part-7-protecting-online-accounts
|
||||
|
||||
作者:[Konstantin Ryabitsev][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/mricon
|
||||
[1]:https://linux.cn/article-9524-1.html
|
||||
[2]:https://linux.cn/article-9529-1.html
|
||||
[3]:https://linux.cn/article-9607-1.html
|
||||
[4]:https://linux.cn/article-10402-1.html
|
||||
[5]:https://linux.cn/article-10415-1.html
|
||||
[6]:https://linux.cn/article-10421-1.html
|
||||
[7]:https://en.wikipedia.org/wiki/Multi-factor_authentication
|
||||
[8]:https://en.wikipedia.org/wiki/Universal_2nd_Factor
|
||||
[9]:http://www.dongleauth.info/dongles/
|
||||
[10]:http://www.dongleauth.info/
|
||||
@@ -0,0 +1,176 @@
|
||||
如何即时设置一个静态文件服务器
|
||||
======
|
||||
|
||||

|
||||
|
||||
曾经想通过网络共享你的文件或项目,但不知道怎么做?别担心!这里有一个名为 **serve** 的简单实用程序,可以通过网络即时共享你的文件。这个简单的实用程序会立即将你的系统变成一个静态文件服务器,允许你通过网络提供文件。你可以从任何设备访问这些文件,而不用担心它们的操作系统是什么。你所需的只是一个 Web 浏览器。这个实用程序还可以用来服务静态网站。它以前称为 “list” 或 “micri-list”,但现在名称已改为 “serve”(提供),这更适合这个实用程序的目的。
|
||||
|
||||
### 使用 Serve 来设置一个静态文件服务器
|
||||
|
||||
要安装 serve,首先你需要安装 NodeJS 和 NPM。参考以下链接在 Linux 中安装 NodeJS 和 NPM。
|
||||
|
||||
* [如何在 Linux 上安装 NodeJS](https://www.ostechnix.com/install-node-js-linux/)
|
||||
|
||||
NodeJS 和 NPM 安装完成后,运行以下命令来安装 serve:
|
||||
|
||||
```
|
||||
$ npm install -g serve
|
||||
```
|
||||
|
||||
完成!现在是时候 serve 文件或文件夹了。
|
||||
|
||||
使用 serve 的典型语法是:
|
||||
|
||||
```
|
||||
$ serve [options] <path-to-files-or-folders>
|
||||
```
|
||||
|
||||
### 提供特定文件或文件夹
|
||||
|
||||
例如,让我们共享 `Documents` 目录里的内容。为此,运行:
|
||||
|
||||
```
|
||||
$ serve Documents/
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
![][2]
|
||||
|
||||
正如你在上图中看到的,给定目录的内容已通过两个 URL 提供网络支持。
|
||||
|
||||
要从本地系统访问内容,你只需打开 Web 浏览器,输入 URL `http://localhost:5000/`:
|
||||
|
||||
![][3]
|
||||
|
||||
serve 实用程序以简单的布局显示给定目录的内容。你可以下载(右键单击文件并选择“将链接另存为...”)或只在浏览器中查看它们。
|
||||
|
||||
如果想要在浏览器中自动打开本地地址,使用 `-o` 选项。
|
||||
|
||||
```
|
||||
$ serve -o Documents/
|
||||
```
|
||||
|
||||
运行上述命令后,serve 实用程序将自动打开 Web 浏览器并显示共享项的内容。
|
||||
|
||||
同样,要通过网络从远程系统访问共享目录,可以在浏览器地址栏中输入 `http://192.168.43.192:5000`。用你系统的 IP 替换 192.168.43.192。
|
||||
|
||||
### 通过不同的端口提供内容
|
||||
|
||||
你可能已经注意到,默认情况下,serve 实用程序使用端口 5000。因此,确保防火墙或路由器中允许使用端口 5000。如果由于某种原因被阻止,你可以使用 `-p` 选项使用不同端口来提供内容。
|
||||
|
||||
```
|
||||
$ serve -p 1234 Documents/
|
||||
```
|
||||
|
||||
上面的命令将通过端口 1234 提供 `Documents` 目录的内容。
|
||||
|
||||
![][4]
|
||||
|
||||
要提供文件而不是文件夹,只需给它完整的路径,如下所示。
|
||||
|
||||
```
|
||||
$ serve Documents/Papers/notes.txt
|
||||
```
|
||||
|
||||
只要知道路径,网络上的任何用户都可以访问共享目录的内容。
|
||||
|
||||
### 提供整个 `$HOME` 目录
|
||||
|
||||
打开终端输入
|
||||
|
||||
```
|
||||
$ serve
|
||||
```
|
||||
|
||||
这将通过网络共享整个 `$HOME` 目录的内容。
|
||||
|
||||
要停止共享,按下 `CTRL+C`。
|
||||
|
||||
### 提供选定的文件或文件夹
|
||||
|
||||
你可能不想共享所有文件或目录,只想共享其中的一些。你可以使用 `-i` 选项排除文件或目录。
|
||||
|
||||
```
|
||||
$ serve -i Downloads/
|
||||
```
|
||||
|
||||
以上命令将提供整个文件系统,除了 `Downloads` 目录。
|
||||
|
||||
### 仅在本地主机上提供内容
|
||||
|
||||
有时,你只想在本地系统而不是整个网络上提供内容。为此,使用 `-l` 标志,如下所示:
|
||||
|
||||
```
|
||||
$ serve -l Documents/
|
||||
```
|
||||
|
||||
此命令会仅在本地提供 `Documents` 目录。
|
||||
|
||||
![][5]
|
||||
|
||||
当你在共享服务器上工作时,这可能会很有用。系统中的所有用户都可以访问共享,但远程用户不能。
|
||||
|
||||
### 使用 SSL 提供内容
|
||||
|
||||
由于我们通过本地网络提供内容,因此我们不需要使用 SSL。但是,serve 实用程序可以使用 `-ssl` 选项来使用 SSL 共享内容。
|
||||
|
||||
```
|
||||
$ serve --ssl Documents/
|
||||
```
|
||||
|
||||
![][6]
|
||||
|
||||
要通过 Web 浏览器访问共享,输入 `https://localhost:5000` 或 `https://ip:5000`。
|
||||
|
||||
![][7]
|
||||
|
||||
### 通过身份验证提供内容
|
||||
|
||||
在上面的所有示例中,我们在没有任何身份验证的情况下提供内容,所以网络上的任何人都可以在没有任何身份验证的情况下访问共享内容。你可能会觉得应该使用用户名和密码访问某些内容。
|
||||
|
||||
为此,使用:
|
||||
|
||||
```
|
||||
$ SERVE_USER=ostechnix SERVE_PASSWORD=123456 serve --auth
|
||||
```
|
||||
|
||||
现在用户需要输入用户名(即 `ostechnix`)和密码(`123456`)来访问共享。(LCTT 译注:123456 是非常不好的密码,仅在实验情况下使用)
|
||||
|
||||
![][8]
|
||||
|
||||
serve 实用程序还有一些其它功能,例如禁用 [Gzip 压缩][9],设置 CORS 头以允许来自任河源的请求,防止自动复制地址到剪贴板等。通过以下命令,你可以阅读完整的帮助部分。
|
||||
|
||||
```
|
||||
$ serve help
|
||||
```
|
||||
|
||||
好了,这就是全部了。希望这可以帮助到你。更多好东西要来了,敬请关注!
|
||||
|
||||
共勉!
|
||||
|
||||
资源:
|
||||
|
||||
* [Serve GitHub 仓库](https://github.com/zeit/serve)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-setup-static-file-server-instantly/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.ostechnix.com/author/sk/
|
||||
[1]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-1.png
|
||||
[3]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-2.png
|
||||
[4]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-4.png
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-3.png
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-6.png
|
||||
[7]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-5-1.png
|
||||
[8]:http://www.ostechnix.com/wp-content/uploads/2018/04/serve-7-1.png
|
||||
[9]:https://www.ostechnix.com/how-to-compress-and-decompress-files-in-linux/
|
||||
@@ -0,0 +1,157 @@
|
||||
设计微服务架构前应该了解的 5 项指导原则
|
||||
======
|
||||
> 顶级 CTO 基于五个简单的原则为精心设计的微服务提供建议。
|
||||
|
||||

|
||||
|
||||
对于从微服务开始的团队来说,最大的挑战之一就是坚持<ruby>金发女孩原则<rt>The Goldilocks principle</rt></ruby>(该典故来自于童话《金发姑娘和三只熊》):不要太大,不要太小,不能太紧密耦合。之所以是挑战的部分原因是会对究竟什么是设计良好的微服务感到疑惑。
|
||||
|
||||
数十位 CTO 通过采访分享了他们的经验,这些对话说明了设计良好的微服务的五个特点。本文将帮助指导团队设计微服务。(有关详细信息,请查看即将出版的书籍 [Microservices for Startups][1],LCTT 译注:已可免费下载完整的电子版)。本文将简要介绍微服务的边界和主观的 “规则”,以避免在深入了解五个特征之前就开始指导您的微服务设计。
|
||||
|
||||
### 微服务边界
|
||||
|
||||
[使用微服务开发新系统的核心优势][2]之一是该体系结构允许开发人员独立构建和修改各个组件,但在最大限度地减少每个 API 之间的回调数量方面可能会出现问题。根据 [SparkPost][3] 工程副总裁 Chris McFadden 所说,解决方案是应用适当的服务边界。
|
||||
|
||||
关于边界,与有时难以理解和抽象的领域驱动设计(DDD,一种微服务框架)形成鲜明对比,本文重点介绍了和我们行业的一些顶级 CTO 一同建立的明确定义的微服务边界的实用原则。
|
||||
|
||||
### 避免主观的 “规则”
|
||||
|
||||
如果您阅读了足够多的关于设计和创建微服务的建议,您一定会遇到下面的一些 “规则”。 尽管将它们用作创建微服务的指南很有吸引力,但加入这些主观规则并不是思考确定微服务的边界的原则性方式。
|
||||
|
||||
#### “微服务应该有 X 行代码”
|
||||
|
||||
让我们直说:微服务中有多少行代码没有限制。微服务不会因为您写了几行额外的代码而突然变成一个独石应用。关键是要确保服务中的代码具有很高的内聚性(稍后将对此进行更多介绍)。
|
||||
|
||||
#### “将每个功能转换为微服务”
|
||||
|
||||
如果函数基于三个输入值计算某些内容并返回结果,它是否是微服务的理想候选项?它是否应该是单独可部署应用程序?这确实取决于该函数是什么以及它是如何服务于整个系统。将每个函数转换为微服务在您的情景中可能根本没有意义。
|
||||
|
||||
其他主观规则包括不考虑整个情景的规则,例如团队的经验、DevOps 能力、服务正在执行的操作以及数据的可用性需求。
|
||||
|
||||
### 精心设计的服务的 5 个特点
|
||||
|
||||
如果您读过关于微服务的文章,您无疑会遇到有关设计良好的服务的建议。简单地说,高内聚和低耦合。如果您不熟悉这些概念,有[许多][4][文章][4]关于这些概念的文章。虽然它们提供了合理的建议,但这些概念是相当抽象的。基于与经验丰富的 CTO 们的对话,下面是在创建设计良好的微服务时需要牢记的关键特征。
|
||||
|
||||
#### #1:不与其他服务共享数据库表
|
||||
|
||||
在 SparkPost 的早期,Chris McFadden 和他的团队必须解决每个 SaaS 业务需要面对的问题:它们需要提供基本服务,如身份验证、帐户管理和计费。
|
||||
|
||||
为了解决这个问题,他们创建了两个微服务:用户 API 和帐户 API。用户 API 将处理用户帐户、API 密钥和身份验证,而帐户 API 将处理所有与计费相关的逻辑。这是一个非常合乎逻辑的分离 —— 但没过多久,他们发现了一个问题。
|
||||
|
||||
McFadden 解释说,“我们有一个名为‘用户 API’的服务,还有一个名为‘帐户 API’的服务。问题是,他们之间实际上有几个来回的调用。因此,您会在帐户服务中执行一些操作,然后调用并终止于用户服务,反之亦然”
|
||||
|
||||
这两个服务的耦合太紧密了。
|
||||
|
||||
在设计微服务时,如果您有多个服务引用同一个表,则它是一个危险的信号,因为这可能意味着您的数据库是耦合的源头。
|
||||
|
||||
这确实是关于服务与数据的关系,这正是 [Swiftype SRE,Elastic][6] 的负责人 Oleksiy Kovrin 告诉我。他说,“我们在开发新服务时使用的主要基本原则之一是,它们不应跨越数据库边界。每个服务都应依赖于自己的一组底层数据存储。这使我们能够集中访问控制、审计日志记录、缓存逻辑等。”
|
||||
|
||||
Kovrin 接着解释说,如果数据库表的某个子集“与数据集的其余部分没有或很少连接,则这是一个强烈的信号,表明该组件可以被隔离到单独的 API 或单独的服务中”。
|
||||
|
||||
[Lead Honestly][7] 的联合创始人 Darby Frey 与此的观点相呼应:“每个服务都应该有自己的表并且永远不应该共享数据库表。”
|
||||
|
||||
#### #2:数据库表数量最小化
|
||||
|
||||
微服务的理想尺寸应该足够小,但不能太小。每个服务的数据库表的数量也是如此。
|
||||
|
||||
[Scaylr][8] 的工程主管 Steven Czerwinski 在接受采访时解释说 Scaylr 的最佳选择是“一个或两个服务的数据库表。”
|
||||
|
||||
SparkPost 的 Chris McFadden 表示同意:“我们有一个 suppression 微服务,它处理、跟踪数以百万计和数十亿围绕 suppression 的条目,但它们都非常专注于围绕 suppression,所以实际上只有一个或两个表。其他服务也是如此,比如 webhooks。
|
||||
|
||||
#### #3:考虑有状态和无状态
|
||||
|
||||
在设计微服务时,您需要问问自己它是否需要访问数据库,或者它是否是处理 TB 级数据 (如电子邮件或日志) 的无状态服务。
|
||||
|
||||
[Algolia][9] 的 CTO Julien Lemoine 解释说:“我们通过定义服务的输入和输出来定义服务的边界。有时服务是网络 API,但它也可能是使用文件并在数据库中生成记录的进程 (这就是我们的日志处理服务)。”
|
||||
|
||||
事先要明确是否有状态,这将引导一个更好的服务设计。
|
||||
|
||||
#### #4:考虑数据可用性需求
|
||||
|
||||
在设计微服务时,请记住哪些服务将依赖于此新服务,以及在该数据不可用时的整个系统的影响。考虑到这一点,您可以正确地设计此服务的数据备份和恢复系统。
|
||||
|
||||
Steven Czerwinski 提到,在 Scaylr 由于关键客户行空间映射数据的重要性,它将以不同的方式复制和分离。
|
||||
|
||||
相比之下,他补充说,“每个分片信息,都在自己的小分区里。如果部分客户群体因为没有可用日志而停止服务那很糟糕,但它只影响 5% 的客户,而不是100% 的客户。”
|
||||
|
||||
#### #5:单一的真实来源
|
||||
|
||||
设计服务,使其成为系统中某些内容的唯一真实来源。
|
||||
|
||||
例如,当您从电子商务网站订购内容时,则会生成订单 ID,其他服务可以使用此订单 ID 来查询订单服务,以获取有关订单的完整信息。使用 [发布/订阅模式][10],在服务之间传递的数据应该是订单 ID ,而不是订单本身的属性信息。只有订单服务具有订单的完整信息,并且是给定订单信息的唯一真实来源。
|
||||
|
||||
### 大型团队的注意事项
|
||||
|
||||
考虑到上面列出的五个注意事项,较大的团队应了解其组织结构对微服务边界的影响。
|
||||
|
||||
对于较大的组织,整个团队可以专门拥有服务,在确定服务边界时,组织性就会发挥作用。还有两个需要考虑的因素:**独立的发布计划**和**不同的正常运行时间**的重要性。
|
||||
|
||||
[Cloud66.][11] 的 CEO Khash Sajadi 说:“我们所看到的微服务最成功的实现要么基于类似领域驱动设计这样的软件设计原则 (如面向服务的体系结构),要么基于反映组织方法的设计原则。”
|
||||
|
||||
“所以 (对于) 支付团队” Sajadi 说,“他们有支付服务或信用卡验证服务,这就是他们向外界提供的服务。所以这不一定是关于软件的。这主要是关于为外界提供更多服务的业务单位。”
|
||||
|
||||
### 双披萨原理
|
||||
|
||||
Amazon 是一个拥有多个团队的大型组织的完美示例。正如在一篇发表于 [API Evangelist][12] 的文章中所提到的,Jeff Bezos 向所有员工发布一项要求,告知他们公司内的每个团队都必须通过 API 进行沟通。任何不这样做的人都会被解雇。
|
||||
|
||||
这样,所有数据和功能都通过该接口公开。Bezos 还设法让每个团队解耦,定义他们的资源,并通过 API 提供。Amazon 正在从头建立一个系统。这使得公司内的每一支团队都能成为彼此的合作伙伴。
|
||||
|
||||
我与 [Iron.io][13] 的 CTO Travis Reeder 谈到了 Bezos 的内部倡议。
|
||||
|
||||
“Jeff Bezos 规定所有团队都必须构建 API 才能与其他团队进行沟通,” Reeder 说。“他也是提出‘双披萨’规则的人:一支团队不应该比两个比萨饼能养活的大。”
|
||||
|
||||
“我认为这里也可以适用同样的方法:无论一个小型团队是否能够开发、管理和富有成效。如果它开始变得笨重或开始变慢,它可能变得太大了。” Reeder 告诉我。
|
||||
|
||||
### 最后注意事项: 您的服务是否具有合适的大小和正确的定义?
|
||||
|
||||
在微服务系统的测试和实施阶段,有一些指标需要记住。
|
||||
|
||||
#### 指标 #1: 服务之间是否存在过度依赖?
|
||||
|
||||
如果两个服务不断地相互回调,那么这就是强烈的耦合信号,也是它们可能更好地合并为一个服务的信号。
|
||||
|
||||
回到 Chris McFadden 的例子, 他有两个 API 服务,帐户服务和用户服务不断地相互通信, McFadden 提出了一个合并服务的想法,并决定将其称为 “账户用户 API”。事实证明,这是一项富有成效的战略。
|
||||
|
||||
“我们开始做的是消除这些内部 API 之间调用的链接,” McFadden 告诉我。“这有助于简化代码。”
|
||||
|
||||
#### 指标 #2: 设置服务的开销是否超过了服务独立的好处?
|
||||
|
||||
Darby Frey 解释说,“每个应用都需要将其日志聚合到某个位置,并需要进行监视。你需要设置它的警报。你需要有标准的操作程序,和在出现问题时的操作手册。您必须管理 SSH 对它的访问。只是为了让一个应用运行起来,就有大量的基础性工作必须存在。”
|
||||
|
||||
### 关键要点
|
||||
|
||||
设计微服务往往会让人感觉更像是一门艺术,而不是一门科学。对工程师来说,这可能并不顺利。有很多一般性的建议,但有时可能有点太抽象了。让我们回顾一下在设计下一组微服务时要注意的五个具体特征:
|
||||
|
||||
1. 不与其他服务共享数据库表
|
||||
2. 数据库表数量最小化
|
||||
3. 考虑有状态和无状态
|
||||
4. 考虑数据可用性需求
|
||||
5. 单一的真实来源
|
||||
|
||||
下次设计一组微服务并确定服务边界时,回顾这些原则应该会使任务变得更容易。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/4/guide-design-microservices
|
||||
|
||||
作者:[Jake Lumetta][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/jakelumetta
|
||||
[1]:https://buttercms.com/books/microservices-for-startups/
|
||||
[2]:https://buttercms.com/books/microservices-for-startups/should-you-always-start-with-a-monolith
|
||||
[3]:https://www.sparkpost.com/
|
||||
[4]:https://thebojan.ninja/2015/04/08/high-cohesion-loose-coupling/
|
||||
[5]:https://en.wikipedia.org/wiki/Single_responsibility_principle
|
||||
[6]:https://www.elastic.co/solutions/site-search
|
||||
[7]:https://leadhonestly.com/
|
||||
[8]:https://www.scalyr.com/
|
||||
[9]:https://www.algolia.com/
|
||||
[10]:https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern
|
||||
[11]:https://www.cloud66.com/
|
||||
[12]:https://apievangelist.com/2012/01/12/the-secret-to-amazons-success-internal-apis/
|
||||
[13]:https://www.iron.io/
|
||||
304
published/201901/20180428 A Beginners Guide To Flatpak.md
Normal file
304
published/201901/20180428 A Beginners Guide To Flatpak.md
Normal file
@@ -0,0 +1,304 @@
|
||||
Flatpak 新手指南
|
||||
======
|
||||
|
||||

|
||||
|
||||
以前,我们介绍 Ubuntu 推出的 [Snaps][1]。Snaps 是由 Canonical 公司为 Ubuntu 开发的,并随后移植到其他的 Linux 发行版,如 Arch、Gentoo、Fedora 等等。由于一个 snap 包中含有软件的二进制文件和其所需的所有依赖和库,所以可以在无视软件版本、在任意 Linux 发行版上安装软件。和 Snaps 类似,还有一个名为 Flatpak 的工具。也许你已经知道,为不同的 Linux 发行版打包并分发应用是一件多么费时又复杂的工作,因为不同的 Linux 发行版的库不同,库的版本也不同。现在,Flatpak 作为分发桌面应用的新框架可以让开发者完全摆脱这些负担。开发者只需构建一个 Flatpak app 就可以在多种发行版上安装使用。这真是又酷又棒!
|
||||
|
||||
用户也完全不用担心库和依赖的问题了,所有的东西都和 app 打包在了一起。更重要的是 Flatpak app 们都自带沙箱,而且与宿主操作系统的其他部分隔离。对了,Flatpak 还有一个很棒的特性,它允许用户在同一个系统中安装同一应用的多个版本,例如 VLC 播放器的 2.1 版、2.2 版、2.3 版。这使开发者测试同一个软件的多个版本变得更加方便。
|
||||
|
||||
在本文中,我们将指导你如何在 GNU/Linux 中安装 Flatpak。
|
||||
|
||||
### 安装 Flatpak
|
||||
|
||||
Flatpak 可以在大多数的主流 Linux 发行版上安装使用,如 Arch Linux、Debian、Fedora、Gentoo、Red Hat、Linux Mint、openSUSE、Solus、Mageia 还有 Ubuntu。
|
||||
|
||||
在 Arch Linux 上,使用这一条命令来安装 Flatpak:
|
||||
|
||||
```
|
||||
$ sudo pacman -S flatpak
|
||||
```
|
||||
|
||||
对于 Debian 用户,Flatpak 被收录进 Stretch 或之后版本的默认软件源中。要安装 Flatpak,直接执行:
|
||||
|
||||
```
|
||||
$ sudo apt install flatpak
|
||||
```
|
||||
|
||||
对于 Fedora 用户,Flatpak 是发行版默认安装的软件。你可以直接跳过这一步。
|
||||
|
||||
如果因为某种原因没有安装的话,可以执行:
|
||||
|
||||
```
|
||||
$ sudo dnf install flatpak
|
||||
```
|
||||
|
||||
对于 RHEL 7 用户,安装 Flatpak 的命令为:
|
||||
|
||||
```
|
||||
$ sudo yum install flatpak
|
||||
```
|
||||
|
||||
如果你在使用 Linux Mint 18.3,那么 Flatpat 也随系统默认安装,所以跳过这一步。
|
||||
|
||||
在 openSUSE Tumbleweed 中,使用 Zypper 包管理来安装 Flatpak:
|
||||
|
||||
```
|
||||
$ sudo zypper install flatpak
|
||||
```
|
||||
|
||||
而 Ubuntu 需要添加下面的软件源再安装 Flatpak,命令如下:
|
||||
|
||||
```
|
||||
$ sudo add-apt-repository ppa:alexlarsson/flatpak
|
||||
$ sudo apt update
|
||||
$ sudo apt install flatpak
|
||||
```
|
||||
|
||||
Gnome 提供了一个 Flatpak 插件,安装它就可以使用图形界面来安装 Flatpak app 了。插件的安装命令为:
|
||||
|
||||
```
|
||||
$ sudo apt install gnome-software-plugin-flatpak
|
||||
```
|
||||
|
||||
如果你是用发行版没有在上述的说明里,请你参考官方[安装指南][2]。
|
||||
|
||||
### 开始使用 Flatpak
|
||||
|
||||
有不少流行应用都支持 Flatpak 安装,如 Gimp、Kdenlive、Steam、Spotify、Visual Sudio Code 等。
|
||||
|
||||
下面让我来一起学习 flatpak 的基本操作命令。
|
||||
|
||||
首先,我们需要添加远程仓库。
|
||||
|
||||
#### 添加软件仓库
|
||||
|
||||
**添加 Flathub 仓库:**
|
||||
|
||||
Flathub 是一个包含了几乎所有 flatpak 应用的仓库。运行这条命令来启用它:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
```
|
||||
|
||||
对于流行应用来说,Flathub 已经可以满足需求。如果你想试试 GNOME 应用的话,可以添加 GNOME 的仓库。
|
||||
|
||||
**添加 GNOME 仓库:**
|
||||
|
||||
GNOME 仓库包括了所有的 GNOME 核心应用,它提供了两种版本:<ruby>稳定版<rt>stable</rt></ruby>和<strong><ruby>每日构建版<rt>nightly</rt></ruby></strong>。
|
||||
|
||||
使用下面的命令来添加 GNOME 稳定版仓库:
|
||||
|
||||
```
|
||||
$ wget https://sdk.gnome.org/keys/gnome-sdk.gpg
|
||||
$ sudo flatpak remote-add --gpg-import=gnome-sdk.gpg --if-not-exists gnome-apps https://sdk.gnome.org/repo-apps/
|
||||
```
|
||||
|
||||
需要注意的是,GNOME 稳定版仓库中的应用需要 **3.20 版本的 org.gnome.Platform 运行时环境**。
|
||||
|
||||
安装稳定版运行时环境,请执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-add --gpg-import=gnome-sdk.gpg gnome https://sdk.gnome.org/repo/
|
||||
```
|
||||
|
||||
如果想使用每日构建版的 GNOME 仓库,使用如下的命令:
|
||||
|
||||
```
|
||||
$ wget https://sdk.gnome.org/nightly/keys/nightly.gpg
|
||||
$ sudo flatpak remote-add --gpg-import=nightly.gpg --if-not-exists gnome-nightly-apps https://sdk.gnome.org/nightly/repo-apps/
|
||||
```
|
||||
|
||||
同样,每日构建版的 GNOME 仓库也需要 **org.gnome.Platform 运行时环境的每日构建版本**。
|
||||
|
||||
执行下面的命令安装每日构建版的运行时环境:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-add --gpg-import=nightly.gpg gnome-nightly https://sdk.gnome.org/nightly/repo/
|
||||
```
|
||||
|
||||
#### 查看软件仓库
|
||||
|
||||
要查看已经添加的软件仓库,执行下面的命令:
|
||||
|
||||
```
|
||||
$ flatpak remotes
|
||||
Name Options
|
||||
flathub system
|
||||
gnome system
|
||||
gnome-apps system
|
||||
gnome-nightly system
|
||||
gnome-nightly-apps system
|
||||
```
|
||||
|
||||
如你所见,上述命令会列出你添加到系统中的软件仓库。此外,执行结果还表明了软件仓库的配置是<ruby>用户级<rt>per-user</rt></ruby>还是<ruby>系统级<rt>system-wide</rt></ruby>。
|
||||
|
||||
#### 删除软件仓库
|
||||
|
||||
要删除软件仓库,例如 flathub,用这条命令:
|
||||
|
||||
```
|
||||
$ sudo flatpak remote-delete flathub
|
||||
```
|
||||
|
||||
这里的 flathub 是软件仓库的名字。
|
||||
|
||||
#### 安装 Flatpak 应用
|
||||
|
||||
这一节,我们将学习如何安装 flatpak 应用。
|
||||
|
||||
要安装一个应用,只要一条命令就能完成:
|
||||
|
||||
```
|
||||
$ sudo flatpak install flathub com.spotify.Client
|
||||
```
|
||||
|
||||
所有的稳定版 GNOME 软件仓库中的应用,都使用“stable”作为版本名。
|
||||
|
||||
例如,想从稳定版 GNOME 软件仓库中安装稳定版 Evince,就执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak install gnome-apps org.gnome.Evince stable
|
||||
```
|
||||
|
||||
所有的每日构建版 GNOME 仓库中的应用,都使用“master”作为版本名。
|
||||
|
||||
例如,要从每日构建版 GNOME 软件仓库中安装 gedit 的每次构建版本,就执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak install gnome-nightly-apps org.gnome.gedit master
|
||||
```
|
||||
|
||||
如果不希望应用安装在<ruby>系统级<rt>system-wide</rt></ruby>,而只安装在<ruby>用户级<rt>per-user</rt></ruby>,那么你可以这样安装软件:
|
||||
|
||||
```
|
||||
$ flatpak install --user <name-of-app>
|
||||
```
|
||||
|
||||
所有的应用都会被存储在 `$HOME/.var/app/` 目录下.
|
||||
|
||||
```
|
||||
$ ls $HOME/.var/app/
|
||||
com.spotify.Client
|
||||
```
|
||||
|
||||
#### 执行 Flatpak 应用
|
||||
|
||||
你可以直接使用<ruby>应用启动器<rt>application launcher</rt></ruby>来运行已安装的 Flatpak 应用。如果你想从命令行启动的话,以 Spotify 为例,执行下面的命令:
|
||||
|
||||
```
|
||||
$ flatpak run com.spotify.Client
|
||||
```
|
||||
|
||||
#### 列出已安装的 Flatpak 应用
|
||||
|
||||
要查看已安装的应用程序和运行时环境,执行:
|
||||
|
||||
```
|
||||
$ flatpak list
|
||||
```
|
||||
|
||||
想只查看已安装的应用,那就用这条命令:
|
||||
|
||||
```
|
||||
$ flatpak list --app
|
||||
```
|
||||
|
||||
如果想查询已添加的软件仓库中的可安装程序和可安装的运行时环境,使用命令:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls
|
||||
```
|
||||
|
||||
只列出可安装的应用程序的命令是:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls --app
|
||||
```
|
||||
|
||||
查询指定远程仓库中的所有可安装的应用程序和运行时环境,这里以 gnome-apps 为例,执行命令:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls gnome-apps
|
||||
```
|
||||
|
||||
只列出可安装的应用程序,这里以 flathub 为例:
|
||||
|
||||
```
|
||||
$ flatpak remote-ls flathub --app
|
||||
```
|
||||
|
||||
#### 更新应用程序
|
||||
|
||||
更新所有的 Flatpak 应用程序,执行:
|
||||
|
||||
```
|
||||
$ flatpak update
|
||||
```
|
||||
|
||||
更新指定的 Flatpak 应用程序,执行:
|
||||
|
||||
```
|
||||
$ flatpak update com.spotify.Client
|
||||
```
|
||||
|
||||
#### 获取应用详情
|
||||
|
||||
执行下面的命令来查看已安装应用程序的详细信息:
|
||||
|
||||
```
|
||||
$ flatpak info io.github.mmstick.FontFinder
|
||||
```
|
||||
|
||||
输出样例:
|
||||
|
||||
```
|
||||
Ref: app/io.github.mmstick.FontFinder/x86_64/stable
|
||||
ID: io.github.mmstick.FontFinder
|
||||
Arch: x86_64
|
||||
Branch: stable
|
||||
Origin: flathub
|
||||
Date: 2018-04-11 15:10:31 +0000
|
||||
Subject: Workaround appstream issues (391ef7f5)
|
||||
Commit: 07164e84148c9fc8b0a2a263c8a468a5355b89061b43e32d95008fc5dc4988f4
|
||||
Parent: dbff9150fce9fdfbc53d27e82965010805f16491ec7aa1aa76bf24ec1882d683
|
||||
Location: /var/lib/flatpak/app/io.github.mmstick.FontFinder/x86_64/stable/07164e84148c9fc8b0a2a263c8a468a5355b89061b43e32d95008fc5dc4988f4
|
||||
Installed size: 2.5 MB
|
||||
Runtime: org.gnome.Platform/x86_64/3.28
|
||||
```
|
||||
|
||||
#### 删除应用程序
|
||||
|
||||
要删除一个 Flatpak 应用程序,这里以 spotify 为例,执行:
|
||||
|
||||
```
|
||||
$ sudo flatpak uninstall com.spotify.Client
|
||||
```
|
||||
|
||||
如果你需要更多信息,可以参考 Flatpak 的帮助。
|
||||
|
||||
```
|
||||
$ flatpak --help
|
||||
```
|
||||
|
||||
到此,希望你对 Flatpak 有了一些基础了解。
|
||||
|
||||
如果你觉得这篇指南有些帮助,请在你的社交媒体上分享它来支持我们。
|
||||
|
||||
稍后还有更多精彩内容,敬请期待~
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/flatpak-new-framework-desktop-applications-linux/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[wwhio](https://github.com/wwhio)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.ostechnix.com/author/sk/
|
||||
[1]:http://www.ostechnix.com/introduction-ubuntus-snap-packages/
|
||||
[2]:https://flatpak.org/setup/
|
||||
@@ -0,0 +1,188 @@
|
||||
Linux 上查看系统/服务器运行时间的 11 种方法
|
||||
======
|
||||
|
||||
你是否想知道自己的 Linux 系统正常运行了多长时间而没有宕机?系统是什么时候启动的?
|
||||
|
||||
Linux 上有多个查看服务器/系统运行时间的命令,大多数用户喜欢使用标准并且很有名的 `uptime` 命令获取这些具体的信息。
|
||||
|
||||
服务器的运行时间对一些用户来说不那么重要,但是当服务器运行诸如在线商城<ruby>门户<rt>portal</rt></ruby>、网上银行门户等<ruby>关键任务应用<rt>mission-critical applications</rt></ruby>时,它对于<ruby>服务器管理员<rt>server adminstrators</rt></ruby>来说就至关重要。
|
||||
|
||||
它必须做到零宕机,因为一旦停机就会影响到数百万用户。
|
||||
|
||||
正如我所说,许多命令都可以让用户看到 Linux 服务器的运行时间。在这篇教程里我会教你如何使用下面 11 种方式来查看。
|
||||
|
||||
<ruby>正常运行时间<rt>uptime</rt></ruby>指的是服务器自从上次关闭或重启以来经过的时间。
|
||||
|
||||
`uptime` 命令获取 `/proc` 文件中的详细信息并输出正常运行时间,而 `/proc` 文件并不适合人直接看。
|
||||
|
||||
以下这些命令会输出系统运行和启动的时间。也会显示一些额外的信息。
|
||||
|
||||
### 方法 1:使用 uptime 命令
|
||||
|
||||
`uptime` 命令会告诉你系统运行了多长时间。它会用一行显示以下信息。
|
||||
|
||||
当前时间、系统运行时间、当前登录用户的数量、过去 1 分钟/5 分钟/15 分钟系统负载的均值。
|
||||
|
||||
```
|
||||
# uptime
|
||||
|
||||
08:34:29 up 21 days, 5:46, 1 user, load average: 0.06, 0.04, 0.00
|
||||
```
|
||||
|
||||
### 方法 2:使用 w 命令
|
||||
|
||||
`w` 命令为每个登录进系统的用户,每个用户当前所做的事情,所有活动的负载对计算机的影响提供了一个快速的概要。这个单一命令结合了多个 Unix 程序:`who`、`uptime`,和 `ps -a` 的结果。
|
||||
|
||||
```
|
||||
# w
|
||||
|
||||
08:35:14 up 21 days, 5:47, 1 user, load average: 0.26, 0.09, 0.02
|
||||
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
|
||||
root pts/1 103.5.134.167 08:34 0.00s 0.01s 0.00s w
|
||||
```
|
||||
|
||||
### 方法 3:使用 top 命令
|
||||
|
||||
`top` 命令是 Linux 上监视实时系统进程的基础命令之一。它显示系统信息和运行进程的信息,例如正常运行时间、平均负载、运行的任务、登录用户数量、CPU 数量 & CPU 利用率、内存 & 交换空间信息。
|
||||
|
||||
**推荐阅读:**[TOP 命令监视服务器性能的例子][1]
|
||||
|
||||
```
|
||||
# top -c
|
||||
|
||||
top - 08:36:01 up 21 days, 5:48, 1 user, load average: 0.12, 0.08, 0.02
|
||||
Tasks: 98 total, 1 running, 97 sleeping, 0 stopped, 0 zombie
|
||||
Cpu(s): 0.0%us, 0.3%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
|
||||
Mem: 1872888k total, 1454644k used, 418244k free, 175804k buffers
|
||||
Swap: 2097148k total, 0k used, 2097148k free, 1098140k cached
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 19340 1492 1172 S 0.0 0.1 0:01.04 /sbin/init
|
||||
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 [kthreadd]
|
||||
3 root RT 0 0 0 0 S 0.0 0.0 0:00.00 [migration/0]
|
||||
4 root 20 0 0 0 0 S 0.0 0.0 0:34.32 [ksoftirqd/0]
|
||||
5 root RT 0 0 0 0 S 0.0 0.0 0:00.00 [stopper/0]
|
||||
```
|
||||
|
||||
### 方法 4:使用 who 命令
|
||||
|
||||
`who` 命令列出当前登录进计算机的用户。`who` 命令与 `w` 命令类似,但后者还包含额外的数据和统计信息。
|
||||
|
||||
```
|
||||
# who -b
|
||||
system boot 2018-04-12 02:48
|
||||
```
|
||||
|
||||
### 方法 5:使用 last 命令
|
||||
|
||||
`last` 命令列出最近登录过的用户。`last` 回溯 `/var/log/wtmp` 文件并显示自从文件创建后登录进(出)的用户。
|
||||
|
||||
```
|
||||
# last reboot -F | head -1 | awk '{print $5,$6,$7,$8,$9}'
|
||||
Thu Apr 12 02:48:04 2018
|
||||
```
|
||||
|
||||
### 方法 6:使用 /proc/uptime 文件
|
||||
|
||||
这个文件中包含系统上次启动后运行时间的详细信息。`/proc/uptime` 的输出相当精简。
|
||||
|
||||
第一个数字是系统自从启动的总秒数。第二个数字是总时间中系统空闲所花费的时间,以秒为单位。
|
||||
|
||||
```
|
||||
# cat /proc/uptime
|
||||
1835457.68 1809207.16
|
||||
```
|
||||
|
||||
### 方法 7:使用 tuptime 命令
|
||||
|
||||
`tuptime` 是一个汇报系统运行时间的工具,输出历史信息并作以统计,保留重启之间的数据。和 `uptime` 命令很像,但输出更有意思一些。
|
||||
|
||||
```
|
||||
$ tuptime
|
||||
```
|
||||
|
||||
### 方法 8:使用 htop 命令
|
||||
|
||||
`htop` 是运行在 Linux 上的一个交互式进程查看器,是 Hisham 使用 ncurses 库开发的。`htop` 比起 `top` 有很多的特性和选项。
|
||||
|
||||
**推荐阅读:** [使用 Htop 命令监控系统资源][2]
|
||||
|
||||
```
|
||||
# htop
|
||||
|
||||
CPU[| 0.5%] Tasks: 48, 5 thr; 1 running
|
||||
Mem[||||||||||||||||||||||||||||||||||||||||||||||||||| 165/1828MB] Load average: 0.10 0.05 0.01
|
||||
Swp[ 0/2047MB] Uptime: 21 days, 05:52:35
|
||||
|
||||
PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command
|
||||
29166 root 20 0 110M 2484 1240 R 0.0 0.1 0:00.03 htop
|
||||
29580 root 20 0 11464 3500 1032 S 0.0 0.2 55:15.97 /bin/sh ./OSWatcher.sh 10 1
|
||||
1 root 20 0 19340 1492 1172 S 0.0 0.1 0:01.04 /sbin/init
|
||||
486 root 16 -4 10780 900 348 S 0.0 0.0 0:00.07 /sbin/udevd -d
|
||||
748 root 18 -2 10780 932 360 S 0.0 0.0 0:00.00 /sbin/udevd -d
|
||||
```
|
||||
|
||||
### 方法 9:使用 glances 命令
|
||||
|
||||
`glances` 是一个跨平台的基于 curses 库的监控工具,它是使用 python 编写的。可以说它非常强大,仅用一点空间就能获得很多信息。它使用 psutil 库从系统中获取信息。
|
||||
|
||||
`glances` 可以监控 CPU、内存、负载、进程、网络接口、磁盘 I/O、<ruby>磁盘阵列<rt>RAID</rt></ruby>、传感器、文件系统(与文件夹)、容器、监视器、Alert 日志、系统信息、运行时间、<ruby>快速查看<rt>Quicklook</rt></ruby>(CPU,内存、负载)等。
|
||||
|
||||
**推荐阅读:** [Glances (集大成)– Linux 上高级的实时系统运行监控工具][3]
|
||||
|
||||
```
|
||||
glances
|
||||
|
||||
ubuntu (Ubuntu 17.10 64bit / Linux 4.13.0-37-generic) - IP 192.168.1.6/24 Uptime: 21 days, 05:55:15
|
||||
|
||||
CPU [|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 90.6%] CPU - 90.6% nice: 0.0% ctx_sw: 4K MEM \ 78.4% active: 942M SWAP - 5.9% LOAD 2-core
|
||||
MEM [||||||||||||||||||||||||||||||||||||||||||||||||||||||||| 78.0%] user: 55.1% irq: 0.0% inter: 1797 total: 1.95G inactive: 562M total: 12.4G 1 min: 4.35
|
||||
SWAP [|||| 5.9%] system: 32.4% iowait: 1.8% sw_int: 897 used: 1.53G buffers: 14.8M used: 749M 5 min: 4.38
|
||||
idle: 7.6% steal: 0.0% free: 431M cached: 273M free: 11.7G 15 min: 3.38
|
||||
|
||||
NETWORK Rx/s Tx/s TASKS 211 (735 thr), 4 run, 207 slp, 0 oth sorted automatically by memory_percent, flat view
|
||||
docker0 0b 232b
|
||||
enp0s3 12Kb 4Kb Systemd 7 Services loaded: 197 active: 196 failed: 1
|
||||
lo 616b 616b
|
||||
_h478e48e 0b 232b CPU% MEM% VIRT RES PID USER NI S TIME+ R/s W/s Command
|
||||
63.8 18.9 2.33G 377M 2536 daygeek 0 R 5:57.78 0 0 /usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
DefaultGateway 83ms 78.5 10.9 3.46G 217M 2039 daygeek 0 S 21:07.46 0 0 /usr/bin/gnome-shell
|
||||
8.5 10.1 2.32G 201M 2464 daygeek 0 S 8:45.69 0 0 /usr/lib/firefox/firefox -new-window
|
||||
DISK I/O R/s W/s 1.1 8.5 2.19G 170M 2653 daygeek 0 S 2:56.29 0 0 /usr/lib/firefox/firefox -contentproc -childID 4 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
dm-0 0 0 1.7 7.2 2.15G 143M 2880 daygeek 0 S 7:10.46 0 0 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
sda1 9.46M 12K 0.0 4.9 1.78G 97.2M 6125 daygeek 0 S 1:36.57 0 0 /usr/lib/firefox/firefox -contentproc -childID 7 -isForBrowser -intPrefs 6:50|7:-1|19:0|34:1000|42:20|43:5|44:10|51
|
||||
```
|
||||
|
||||
### 方法 10:使用 stat 命令
|
||||
|
||||
`stat` 命令显示指定文件或文件系统的详细状态。
|
||||
|
||||
```
|
||||
# stat /var/log/dmesg | grep Modify
|
||||
Modify: 2018-04-12 02:48:04.027999943 -0400
|
||||
```
|
||||
|
||||
### 方法 11:使用 procinfo 命令
|
||||
|
||||
`procinfo` 从 `/proc` 文件夹下收集一些系统数据并将其很好的格式化输出在标准输出设备上。
|
||||
|
||||
```
|
||||
# procinfo | grep Bootup
|
||||
Bootup: Fri Apr 20 19:40:14 2018 Load average: 0.16 0.05 0.06 1/138 16615
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/11-methods-to-find-check-system-server-uptime-in-linux/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
选题:[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/) 荣誉推出
|
||||
|
||||
[a]:https://www.2daygeek.com/author/magesh/
|
||||
[1]:https://www.2daygeek.com/top-command-examples-to-monitor-server-performance/
|
||||
[2]:https://www.2daygeek.com/htop-command-examples-to-monitor-system-resources/
|
||||
[3]:https://www.2daygeek.com/install-glances-advanced-real-time-linux-system-performance-monitoring-tool-on-centos-fedora-ubuntu-debian-opensuse-arch-linux/
|
||||
@@ -0,0 +1,67 @@
|
||||
Fedora 28 服务器版的模块化
|
||||
========
|
||||
|
||||

|
||||
|
||||
### 什么是模块化
|
||||
|
||||
所有开源发行版都面临的一个经典难题是“太快/太慢”的问题。用户安装操作系统是为了能够使用其应用程序。像 Fedora 这样的全面的发行版在大量可用软件方面有其优势和劣势。虽然有用户想要的软件包,但可能无法使用其所需的版本。以下是<ruby>模块化<rt>Modularity</rt></ruby>如何帮助解决该问题。
|
||||
|
||||
对于某些用户,Fedora 有时升级得太快。其快速发布周期以及尽可能提供最新稳定软件的愿望可能导致与应用程序的兼容性下降。如果因为 Fedora 将 Web 框架升级为不兼容的版本而导致用户无法运行 Web 应用程序,则会非常令人沮丧。对“太快”问题的经典回答是“Fedora 应该有一个 LTS 版本。”然而,这种方法只能解决问题的一半,并使这个难题的另一面变得更糟。
|
||||
|
||||
有时候 Fedora 对某些用户而言又升级速度太慢。例如,Fedora 的发布可能与其它想要的软件的发布时间不匹配。一旦 Fedora 版本宣布稳定,打包者必须遵守 [稳定更新政策][1] 并且不能在系统中引入不兼容的更改。
|
||||
|
||||
Fedora 的模块化从两个方面解决了这个问题。Fedora 仍将根据其传统政策发布标准版本。但是,它还将提供一组模块给出流行软件的限定替代版本。那些处于“太快”阵营的人仍然可以享受 Fedora 的新内核和其它通用平台增强功能。此外,他们仍然可以访问支持其应用程序的旧框架或工具链。
|
||||
|
||||
此外,那些喜欢更新潮一些的用户可以访问比发布时更新的软件。
|
||||
|
||||
### 模块化不是什么?
|
||||
|
||||
模块化不是 <ruby>[软件集合][2]<rt>Software Collections</rt></ruby> 的直接替代品。这两种技术试图解决许多相同的问题,但有明显的差异。
|
||||
|
||||
软件集合可以在系统上并行安装不同版本的软件包。但是,它们的缺点是每份安装包都存在于文件系统上的它们自己的命名空间里面。此外,需要告诉每个依赖它们的应用程序在哪里找到它们。
|
||||
|
||||
使用模块化,系统上只存在一个版本的软件包,但用户可以选择哪个版本。优点是该版本位于系统的标准位置。该程序包不需要对依赖它的应用程序进行特殊更改。来自用户研究的反馈表明,大多数用户实际上并不依赖于并行安装。容器化和虚拟化解决了这个问题。
|
||||
|
||||
### 为什么不干脆使用容器化?
|
||||
|
||||
这是另一个常见问题。为什么用户在可以使用容器时还需要模块?答案是,人们仍然需要维护容器中的软件。 模块为那些用户不需要自己维护、更新和修补的容器提供预打包的内容。这就是 Fedora 如何利用发行版的传统价值并将其转移到新的容器化的世界。
|
||||
|
||||
以下是模块化如何为 Node.js 和 Review Board 的用户解决问题的示例。
|
||||
|
||||
### Node.js
|
||||
|
||||
许多读者可能熟悉 Node.js,这是一个流行的服务器端 JavaScript 运行时环境。Node.js 采用偶数/奇数版本策略。它的社区支持偶数版本(6.x、8.x、10.x 等)约 30 个月。同时,他们也支持奇数版本,基本上是 9 个月的开发者预览版。
|
||||
|
||||
由于这个周期的原因,Fedora 在其稳定的仓库中只携带最新的偶数版本的 Node.js。它完全避免了奇数版本,因为它们的生命周期比 Fedora 短,并且通常与 Fedora 发布周期不一致。对于一些希望获得最新和最大增强功能的 Fedora 用户来说,这并不合适。
|
||||
|
||||
由于模块化,Fedora 28 不是提供了一个版本,而是提供了三个版本的 Node.js,以满足开发人员和稳定部署的需求。Fedora 28 的传统仓库带有 Node.js 8.x。此版本是发布时最新的长期稳定版本。模块仓库(默认情况下在 Fedora 28 Server 版本上可用)也使得更旧的 Node.js 6.x 版本和更新的 Node.js 9.x 开发版本可用。
|
||||
|
||||
另外,Node.js 在 Fedora 28 之后几天发布了 10.x 上游版本。过去,想要部署该版本的用户必须等到 Fedora 29,或者使用来自 Fedora 之外的源代码。但是,再次感谢模块化,Node.js 10.x 已经在 Fedora 28 的 Modular Updates-Testing 仓库中 [可用][3] 了。
|
||||
|
||||
### Review Board
|
||||
|
||||
Review Board 是一个流行的 Django 应用程序,用于执行代码审查。Fedora 从 Fedora 13 到 Fedora 21 都包括了 Review Board。此时,Fedora 转移到了 Django 1.7。由于 Django 数据库支持的向后兼容性在不断变化,而 Review Board 无法跟上。它在 RHEL / CentOS 7 的 EPEL 仓库中仍然存在,而仅仅是因为这些发行版的版本幸运地被冻结在 Django 1.6上。尽管如此,它在 Fedora 的时代显然已经过去了。
|
||||
|
||||
然而,随着模块化的出现,Fedora 能够再次将旧的 Django 作为非默认模块流发布。因此,Review Board 已作为一个模块在 Fedora 上恢复了。Fedora 承载了来自上游的两个受支持的版本:2.5.x 和 3.0.x。
|
||||
|
||||
### 组合在一起
|
||||
|
||||
Fedora 一直为用户提供非常广泛的软件使用。Fedora 模块化现在为他们所需的软件版本提供了更深入的选择。接下来的几年对于 Fedora 来说将是非常令人兴奋的,因为开发人员和用户可以以新的和令人兴奋的(或旧的和令人兴奋的)方式组合他们的软件。
|
||||
|
||||
------
|
||||
|
||||
via: https://fedoramagazine.org/working-modules-fedora-28/
|
||||
|
||||
作者:[Stephen Gallagher][a]
|
||||
选题:[wxy](https://github.com/wxy)
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/sgallagh/
|
||||
[1]: https://fedoraproject.org/wiki/Updates_Policy#Stable_Releases
|
||||
[2]: https://www.softwarecollections.org/
|
||||
[3]: https://bodhi.fedoraproject.org/updates/FEDORA-MODULAR-2018-2b0846cb86
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
4 个值得一提的 Firefox 扩展插件
|
||||
======
|
||||
|
||||
> 这些扩展可以使火狐更具生产力和使用乐趣。
|
||||
|
||||

|
||||
|
||||
自从大约 12 年前 Firefox(火狐浏览器)v2.0 推出以来, 我一直是它的用户。它不是那时最好的网络浏览器,但是总会有一个理由让我回到它:我最喜爱的浏览器扩展插件不能工作在其它浏览器上。
|
||||
|
||||
如今,我喜欢现下的 Firefox,因为它快速、可定制和开源,我也很欣赏那些体现了原开发人员从未想到过的想法的扩展插件:如果你想在没有鼠标的情况下浏览网页呢?如果你不喜欢盯着晚上从显示器里发出来的强光呢?如何在 YouTube 和其他视频托管网站上使用一个更专业的播放器来获得更好的性能和更多播放控制呢?如果你需要更复杂的方法来禁用跟踪器和加快加载页面,该怎么办?
|
||||
|
||||
幸运的是,这些问题都有答案,我将展现给你我最喜爱的扩展 —— 所有这些都是免费软件或开源的 (即,在 [GNU GPL][1]、[MPL][2] 或 [Apache][3] 许可帧下) ,它们可以使一个优秀的浏览器更优秀。
|
||||
|
||||
尽管术语<ruby>加载项<rt>add-on</rt></ruby>和<ruby>扩展<rt>extension</rt></ruby>的含义稍微不同,但我在本文中的使用不会区分它们。
|
||||
|
||||
### Tridactyl
|
||||
|
||||
![Tridactyl screenshot][5]
|
||||
|
||||
*Tridactyl 的新选项卡页面,展示了链接的指引。*
|
||||
|
||||
[Tridactyl][6] 使你能够在大多数浏览活动中使用键盘。它的灵感来自于现已不复存在的 [Vimperator][7] 和 [Pentadactyl][8],而它们受到了 [Vim][9] 的默认键绑定的启发。由于我已经习惯了 Vim 和其他命令行应用程序,我发现了它的功能类似于使用键值 `h/j/k/l` 进行导航,用 `f/F` 可以与超链接进行交互,而且创建自定义的键绑定和命令非常方便。
|
||||
|
||||
Tridactyl 最近刚刚实现了一个可选的本地信使(目前,仅适用于 GNU/Linux 和 Mac OSX),提供了更酷的功能。例如,有了它,你可以隐藏 Firefox 用户界面上的一些元素(以 Vimperator 和 Pentadactyl 的方式)、在外部程序中打开链接或当前页(我经常用 [mpv][10] 和 [youtube-dl][11] 播放视频)、通过按 `Ctrl-I`(或者任意你选择的组合键)用你喜爱的编辑器来编辑文本框的内容。
|
||||
|
||||
话虽如此,但要记住,这是一个相对早期的项目,细节可能还是很粗糙。另一方面,它的开发非常活跃,当你回顾它早期的缺陷时,未尝不是一种乐趣。
|
||||
|
||||
### Open With
|
||||
|
||||
![Open With Screenshot][13]
|
||||
|
||||
*Open With 提供的菜单。我可以用这里列出的一个外部程序打开当前页面。*
|
||||
|
||||
说到与外部程序的互动,有时能够用鼠标来做到这一点还是让人很高兴的。这是 [Open With][14] 的用武之地。
|
||||
|
||||
除了添加的上下文菜单(如屏幕截图所示)之外,你还可以通过单击加载项栏上的扩展图标来找到自己定义的命令。如[它在 Mozilla Add-ons 页面上][14] 的图标和描述所示,它主要是为了切换到其它的 web 浏览器,但我也可以轻松地将它与 mpv 和 youtube-dl 相配合。
|
||||
|
||||
它也提供了键盘快捷方式,但它们受到了严重限制。可以在扩展设置的下拉列表中选择的组合不超过三种。相反,Tridactyl 允许我将命令分配给几乎任何没有被 Firefox 所阻止的东西。没错,Open With 目前为鼠标而准备的。
|
||||
|
||||
### Stylus
|
||||
|
||||
![Stylus Screenshot][16]
|
||||
|
||||
*在这个屏幕截图中,我刚刚搜索并为当前正在浏览的 Stylus 的网站安装了一个黑暗主题。即使是弹出窗口也可以定制风格(称为 Deepdark Stylus)!*
|
||||
|
||||
[Stylus][17] 是一个用户样式管理器,这意味着可以通过编写自定义 CSS 规则并将其加载到 Stylus 中来更改任何网页的外观。如果你不懂 CSS,在如 [userstyles.org][18] 这样网站上有大量的其他人制作的样式。
|
||||
|
||||
现在,你可能会问,“这不就是 [Stylish][19] 么?” 你是对的!Stylus 是基于 Stylish 的,并提供了更多的改进:它不包含任何远程记录、尊重你的隐私,所有开发都是公开的(尽管 Stylish 仍在积极开发,我一直未能找到最新版本的源代码),而且它还支持 [UserCSS][20]。
|
||||
|
||||
UserCSS 是一种有趣的格式,尤其是对于开发人员来说。我已经为不同的网站写了几种用户样式(主要是黑暗主题,和为了提高可读性的调整),虽然 Stylus 的内部编辑器很好,我还是喜欢用 Neovim 编辑代码。为了做到这样我所需要做的就是用 “.user.css” 作为本地加载文件的后缀名,在 Stylus 里启动 “Live Reload” 选项,只要我在 Neovim 中保存文件就会应用所有的更改。它也支持远程 UserCSS 文件,因此,每当我将更改推送到 GitHub 或任何基于 git 的开发平台时,它们将自动对用户可用。(我提供了指向该文件的原始版本的链接,以便他们可以轻松地访问它。)
|
||||
|
||||
### uMatrix
|
||||
|
||||
![uMatrix Screenshot][22]
|
||||
|
||||
*uMatrix 的用户界面,显示当前访问过的网页的当前规则。*
|
||||
|
||||
Jeremy Garcia 在他发表在 Opensource.com 的[文章][23]中提到了一个优秀的拦截器 uBlock Origin。我想提请大家关注另一个由 [gorhill][24] 开发的扩展插件: uMatrix 。
|
||||
|
||||
[uMatrix][25] 允许你为网页上的某些请求设置拦截规则,可以通过点击该加载项的弹出窗口来切换(在上面的屏幕截图中可以看到)。这些请求的区别在于脚本的类别、脚本发起的请求、cookies、CSS 规则、图像、媒体、帧,和被 uMatrix 标记为“other” 的其它内容。例如,你可以设置全局规则,以便在默认情况下允许所有请求,并将特定的请求添加到黑名单中(更方便的方法),或在默认情况下阻止所有内容,并手动将某些请求列入白名单(更安全的方法)。如果你一直在使用 NoScript 或 RequestPolicy,你可以从它们 [导入][26] 你的白名单规则。
|
||||
|
||||
另外 uMatrix 支持 [hosts 文件][27],可用于阻止来自某些域的请求。不要与 uBlock Origin 所使用的筛选列表混淆,它使用的语法同 Adblock Plus 一样。默认情况下,uMatrix 会通过几个 hosts 文件阻止已知的分发广告、跟踪器和恶意软件的服务器,如果需要,你可以添加更多外部数据源。
|
||||
|
||||
那么你将选择哪一个:uBlock Origin 或 uMatrix ?就个人而言,我在电脑上两个都用,而只在安卓手机上用 uMatrix 。[据 gorhill 所说][28],两者之间存在某种重叠,但它们有不同的目标用户和目地。如果你想要的只是阻止跟踪器和广告的简单方法,uBlock Origine 是更好的选择;另一方面,如果你希望对网页在浏览器中可以执行或不能执行的操作进行精细的控制,即使需要一些时间来进行配置,并且可能会阻止某些网站如预期的工作,uMatrix 也是更好的选择。
|
||||
|
||||
### 结论
|
||||
|
||||
目前,这些是 Firefox 里我最喜欢的扩展。Tridactyl 通过依靠键盘和与外部程序交互,加快了浏览导航速度;Open With 能让我用鼠标在另外一个程序中打开页面;Stylus 是全面的用户样式管理器,对用户和开发人员都很有吸引力;uMatrix 本质上是 Firefox 的防火墙,可以用于过滤未知的请求。
|
||||
|
||||
尽管我基本上只是讨论了这些加载项的好处,但没有一个软件是完美的。如果你喜欢它们中的任何一个,并认为它们的某些方面可以改进,我建议你去它们的 Github 页面,并查看它们的贡献指南。通常情况下,自由开源软件的开发人员是欢迎错误报告和提交请求的。告诉你的朋友或道谢也是帮助开发者的好方法,特别是如果这些开发者是在业余时间从事他们的项目的话。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/firefox-open-source-extensions
|
||||
|
||||
作者:[Zsolt Szakács][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/zsolt
|
||||
[1]:https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
[2]:https://www.mozilla.org/en-US/MPL/
|
||||
[3]:https://www.apache.org/licenses/LICENSE-2.0
|
||||
[4]:/file/398411
|
||||
[5]:https://opensource.com/sites/default/files/uploads/tridactyl.png "Tridactyl's new tab page, showcasing link hinting"
|
||||
[6]:https://addons.mozilla.org/en-US/firefox/addon/tridactyl-vim/
|
||||
[7]:https://github.com/vimperator/vimperator-labs
|
||||
[8]:https://addons.mozilla.org/en-US/firefox/addon/pentadactyl/
|
||||
[9]:https://www.vim.org/
|
||||
[10]:https://mpv.io/
|
||||
[11]:https://rg3.github.io/youtube-dl/index.html
|
||||
[12]:/file/398416
|
||||
[13]:https://opensource.com/sites/default/files/uploads/openwith.png "A context menu provided by Open With. I can open the current page with one of the external programs listed here."
|
||||
[14]:https://addons.mozilla.org/en-US/firefox/addon/open-with/
|
||||
[15]:/file/398421
|
||||
[16]:https://opensource.com/sites/default/files/uploads/stylus.png "In this screenshot, I've just searched for and installed a dark theme for the site I'm currently on with Stylus. Even the popup has custom style (called Deepdark Stylus)!"
|
||||
[17]:https://addons.mozilla.org/en-US/firefox/addon/styl-us/
|
||||
[18]:https://userstyles.org/
|
||||
[19]:https://addons.mozilla.org/en-US/firefox/addon/stylish/
|
||||
[20]:https://github.com/openstyles/stylus/wiki/Usercss
|
||||
[21]:/file/398426
|
||||
[22]:https://opensource.com/sites/default/files/uploads/umatrix.png "The user interface of uMatrix, showing the current rules for the currently visited webpage."
|
||||
[23]:https://opensource.com/article/18/5/firefox-extensions
|
||||
[24]:https://addons.mozilla.org/en-US/firefox/user/gorhill/
|
||||
[25]:https://addons.mozilla.org/en-US/firefox/addon/umatrix
|
||||
[26]:https://github.com/gorhill/uMatrix/wiki/FAQ
|
||||
[27]:https://en.wikipedia.org/wiki/Hosts_(file)
|
||||
[28]:https://github.com/gorhill/uMatrix/issues/32#issuecomment-61372436
|
||||
140
published/201901/20180606 Working with modules in Fedora 28.md
Normal file
140
published/201901/20180606 Working with modules in Fedora 28.md
Normal file
@@ -0,0 +1,140 @@
|
||||
使用 Fedora 28 中的模块
|
||||
======
|
||||
|
||||

|
||||
|
||||
最近 Fedora Magazine 中题为 [Fedora 28 服务器版的模块化][1]在解释 Fedora 28 中的模块化方面做得很好。它还给出了一些示例模块并解释了它们解决的问题。本文将其中一个模块用于实际应用,包括使用模块安装设置 Review Board 3.0。
|
||||
|
||||
### 入门
|
||||
|
||||
想要继续并使用模块,你需要一个 [Fedora 28 服务器版][2]并拥有 [sudo 管理权限][3]。另外,运行此命令以确保系统上的所有软件包都是最新的:
|
||||
|
||||
```
|
||||
sudo dnf -y update
|
||||
```
|
||||
|
||||
虽然你可以在 Fedora 28 非服务器版本上使用模块,但请注意[上一篇文章评论中提到的警告][4]。
|
||||
|
||||
### 检查模块
|
||||
|
||||
首先,看看 Fedora 28 可用的模块。运行以下命令:
|
||||
|
||||
```
|
||||
dnf module list
|
||||
```
|
||||
|
||||
输出列出了一组模块,这些模块显示了每个模块的关联的流、版本和可用安装配置文件。模块流旁边的 `[d]` 表示安装命名模块时使用的默认流。
|
||||
|
||||
输出还显示大多数模块都有名为 `default` 的配置文件。这不是巧合,因为 `default` 是默认配置文件使用的名称。
|
||||
|
||||
要查看所有这些模块的来源,请运行:
|
||||
|
||||
```
|
||||
dnf repolist
|
||||
```
|
||||
|
||||
与通常的 [fedora 和更新包仓库][5]一起,输出还显示了 fedora-modular 和 updates-modular 仓库。
|
||||
|
||||
介绍声明你将设置 Review Board 3.0。也许名为 reviewboard 的模块在之前的输出中引起了你的注意。接下来,要获取有关该模块的一些详细信息,请运行以下命令:
|
||||
|
||||
```
|
||||
dnf module info reviewboard
|
||||
```
|
||||
|
||||
根据描述确认它是 Review Board 模块,但也说明是 2.5 的流。然而你想要 3.0 的。查看可用的 reviewboard 模块:
|
||||
|
||||
```
|
||||
dnf module list reviewboard
|
||||
```
|
||||
|
||||
2.5 旁边的 `[d]` 表示它被配置为 reviewboard 的默认流。因此,请明确你想要的流:
|
||||
|
||||
```
|
||||
dnf module info reviewboard:3.0
|
||||
```
|
||||
|
||||
有关 reviewboard:3.0 模块的更多详细信息,请添加详细选项:
|
||||
|
||||
```
|
||||
dnf module info reviewboard:3.0 -v
|
||||
```
|
||||
|
||||
### 安装 Review Board 3.0 模块
|
||||
|
||||
现在你已经跟踪了所需的模块,请使用以下命令安装它:
|
||||
|
||||
```
|
||||
sudo dnf -y module install reviewboard:3.0
|
||||
```
|
||||
|
||||
输出显示已安装 ReviewBoard 以及其他几个依赖软件包,其中包括 django:1.6 模块中的几个软件包。安装还启用了 reviewboard:3.0 模块和相关的 django:1.6 模块。
|
||||
|
||||
接下来,要查看已启用的模块,请使用以下命令:
|
||||
|
||||
```
|
||||
dnf module list --enabled
|
||||
```
|
||||
|
||||
输出中,`[e]` 表示已启用的流,`[i]` 表示已安装的配置。对于 reviewboard:3.0 模块,已安装默认配置。你可以在安装模块时指定其他配置。实际上,你仍然可以安装它,而且这次你不需要指定 3.0,因为它已经启用:
|
||||
|
||||
```
|
||||
sudo dnf -y module install reviewboard/server
|
||||
```
|
||||
|
||||
但是,安装 reviewboard:3.0/server 配置非常平常。reviewboard:3.0 模块的服务器配置与默认配置文件相同 —— 因此无需安装。
|
||||
|
||||
### 启动 Review Board 网站
|
||||
|
||||
现在已经安装了 Review Board 3.0 模块及其相关软件包,[创建一个本地运行的 Review Board 网站][6]。无需解释,请复制并粘贴以下命令:
|
||||
|
||||
```
|
||||
sudo rb-site install --noinput \
|
||||
--domain-name=localhost --db-type=sqlite3 \
|
||||
--db-name=/var/www/rev.local/data/reviewboard.db \
|
||||
--admin-user=rbadmin --admin-password=secret \
|
||||
/var/www/rev.local
|
||||
sudo chown -R apache /var/www/rev.local/htdocs/media/uploaded \
|
||||
/var/www/rev.local/data
|
||||
sudo ln -s /var/www/rev.local/conf/apache-wsgi.conf \
|
||||
/etc/httpd/conf.d/reviewboard-localhost.conf
|
||||
sudo setsebool -P httpd_can_sendmail=1 httpd_can_network_connect=1 \
|
||||
httpd_can_network_memcache=1 httpd_unified=1
|
||||
sudo systemctl enable --now httpd
|
||||
```
|
||||
|
||||
现在启动系统中的 Web 浏览器,打开 <http://localhost>,然后享受全新的 Review Board 网站!要以 Review Board 管理员身份登录,请使用上面 `rb-site` 命令中的用户 ID 和密码。
|
||||
|
||||
### 模块清理
|
||||
|
||||
完成后清理是个好习惯。为此,删除 Review Board 模块和站点目录:
|
||||
|
||||
```
|
||||
sudo dnf -y module remove reviewboard:3.0
|
||||
sudo rm -rf /var/www/rev.local
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
现在你已经探索了如何检测和管理 Review Board 模块,那么去体验 Fedora 28 中提供的其他模块吧。
|
||||
|
||||
在 [Fedora 模块化][7]网站上了解有关在 Fedora 28 中使用模块的更多信息。dnf 手册页中的 module 命令部分也包含了有用的信息。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/working-modules-fedora-28/
|
||||
|
||||
作者:[Merlin Mathesius][a]
|
||||
选题:[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/) 荣誉推出
|
||||
|
||||
[a]:https://fedoramagazine.org/author/merlinm/
|
||||
[1]:https://linux.cn/article-10479-1.html
|
||||
[2]:https://getfedora.org/server/
|
||||
[3]:https://fedoramagazine.org/howto-use-sudo/
|
||||
[4]:https://fedoramagazine.org/modularity-fedora-28-server-edition/#comment-476696
|
||||
[5]:https://fedoraproject.org/wiki/Repositories
|
||||
[6]:https://www.reviewboard.org/docs/manual/dev/admin/installation/creating-sites/
|
||||
[7]:https://docs.pagure.org/modularity/
|
||||
@@ -0,0 +1,86 @@
|
||||
使用 Xfce Linux 桌面环境的 8 个理由
|
||||
============================
|
||||
> 整体上很优雅的 Xfce 桌面所具备的足够轻巧和快速的特性能够让它很容易地知道如何做好一件事。
|
||||
|
||||

|
||||
|
||||
由于某些原因(也包括好奇),几周前我开始使用 [Xfce][1] 作为我的 Linux 桌面。促使我更换 Linux 桌面环境的原因之一是桌面相关的守护进程占据了我的性能非常强大的主工作站的绝大部分 CPU 资源和 I/O 带宽。当然,有些不稳定性可能是因为我删除了提供这些守护进程的 RPM 包。然而,事实是在我删除这些 RPM 包之前,KDE 就已经很不稳定了而且还导致了一系列其他方面的性能和稳定性问题。所以我需要换一个桌面来避免这些问题。
|
||||
|
||||
在回顾了我为 Linux 桌面所写的一系列文章后我才意识到我忽略了 Xfce。这篇文章也是力图能够纠正弥补这个疏忽。我非常喜欢 Xfce 也很享受它所带给我超乎预期的快速、轻量的体验。
|
||||
|
||||
作为研究的一部分,我有尝试过在 Google 上查询 Xfce 对应什么意思。有个历史参考是它对应着 “XForms Common Environment”,但 Xfce 早已不在使用 XForms 工具。几年前,我找到另一个参考是 “Xtra fine computing environment” 而且我也很喜欢这个解释。我将会用它作为 Xfce 的全称(尽管再也找不到这个参考页面)。
|
||||
|
||||
### 推荐 Xfce 的 8 个理由
|
||||
|
||||
#### 1、轻量级架构
|
||||
|
||||
Xfce 相对于其他的桌面如 KDE 和 GNOME,不管是内存还是 CPU 的占用率都非常小。在我的系统中,组成 Xfce 桌面的程序仅占用了少量内存就构成一个如此强大的桌面。超低的 CPU 占用率也是 Xfce 桌面的一个特点。了解到 Xfce 内存占用特别低后,我对它的 CPU 占用率也非常低这个特性自然而言也就不感到奇怪了。
|
||||
|
||||
#### 2、简洁
|
||||
|
||||
Xfce 桌面很简单,就像绒毛整洁的动物让人一目了然、赏心悦目。基础的桌面有两个面板和一条在左边垂直的图标行。面板 0 在底部,并由一些基础的应用启动程序和能访问到系统里对应程序的图标组成。面板 1 在顶部,由一个应用程序启动器和一个能够允许用户在多个工作区之间来回切换的工作区切换器组成。面板可以通过补充项自定义修改,比如增加个新的应用启动器或者更改它们的宽高。
|
||||
|
||||
桌面左侧的图标对应是家目录和垃圾桶。它也可以显示其他的图标,如完整的文件系统目录树和已连接上系统的可插拔的任意 USB 存储设备。这些图标可以用来挂载和卸载设备,也可以用来打开默认的文件管理器。如果你愿意,它们都可以被隐藏,同时文件系统、垃圾箱、家目录对应的图标都可以逐个控制管理。所有的可移动设备也可以被隐藏或作为一个组显示。
|
||||
|
||||
#### 3、文件管理
|
||||
|
||||
作为 Xfce 的默认文件管理器 Thunar,它很简单,既易于使用和配置也非常容易学习。尽管它并不像其他的文件管理器比如 Konqueror 或者 Dolphin 那样效果华丽,但它很强大也很快。Thunar 并不能在一个窗口里面打开多个面板,但它提供了选项卡来支持多个目录的同时打开。Thunar 也有一个非常漂亮的侧边栏,其上同样的图标就像桌面那样能够显示完整的文件系统目录树和所有已连接的 USB 存储设备。设备能够被挂载和卸载,可移动媒介如 CD 也能够被弹出。Thunar 也可以使用类似 Ark 这种帮助软件来在你点击归档文件的时候打开它们。比如 ZIP、TAR、RPM 这种归档文件都可以被浏览也可以从中复制单个文件。
|
||||
|
||||
![Xfce desktop][3]
|
||||
|
||||
*Xfce 桌面及 Thunar 和 Xfce 下的终端模拟器。*
|
||||
|
||||
在我的[文件管理器系列][4]文章中,我已经使用体验过很多不同的文件管理器软件,我不得不说 Thunar 的简单易用让你无法不喜欢上它。它可以让你通过使用侧边栏来很容易地浏览文件系统。
|
||||
|
||||
#### 4、稳定
|
||||
|
||||
Xfce 桌面非常稳定。新版本的发布周期似乎是三年,但也会根据需要发布相关更新。最新的版本是于 2015 年 2 月发布的 4.12。在使用 KDE 遇到一系列问题后,稳如磐石的 Xfce 桌面环境显得让人格外放心。在我使用 Xfce 的过程中,它从来没有崩溃过,也不会产生额外的守护进程占据过多的系统资源。这正是我想要的:它安安静静地工作,不会给你带来额外的困扰。
|
||||
|
||||
#### 5、优雅
|
||||
|
||||
Xfce 简单优雅。在我的今年秋天将面世的新书《系统管理员的 Linux 哲学》中我谈到了关于简单的一系列好处,包括简单事实上也是优雅的诸多标志之一。很明确能够确定的就是 Xfce 及相关组件程序的开发者和维护者也是极力推崇简单至上。这种简单特性很可能也是 Xfce 如此稳定的主要原因,但它也给用户带来了一个整洁的桌面外观,一个反应灵敏的操作界面,一个会让人感觉很自然也很易用的导航结构,而且 Xfce 整体上的优雅特性也会让用户的使用过程中充满愉悦感。
|
||||
|
||||
#### 6、终端仿真程序
|
||||
|
||||
Xfce4 的终端仿真程序非常强大,而且和其他很多终端仿真程序一样可以允许你使用多个选项卡来让多个终端在一个单独窗口里共存。尽管它与 Tilix、Terminator、Konsole 这种终端仿真程序比起来相对简陋,但它也能很好的完成工作。选项卡的名字可以更改,而且选项卡也可以通过拖放或者工具栏的箭头图标或者菜单栏的选项重新排列。我特别喜欢 Xfce 的终端仿真程序的一点就是不管你连接了多少主机,相对应的选项卡都会显示对应的主机名,比如,从 host1=>host2=>host3=>host4,会准确地在选项卡显示了 “host4”。但其他的终端仿真程序最多也就显示 “host2”。
|
||||
|
||||
至于这个终端仿真程序功能和外观的其他方面都可以根据你的需要很容易配置成你想要的。当然同 Xfce 的其他组件一样,这款终端仿真程序占用了系统资源的很少一部分。
|
||||
|
||||
#### 7、可配置性
|
||||
|
||||
Xfce 能够配置的范围极大。虽然 Xfce 桌面的可配置性比不上 KDE,但依旧远超 GNOME,而且比它更容易配置。比如,我发现设置管理器是 Xfce 配置一切的入口。虽然每个配置程序都可以单独使用,但是设置管理器把他们都放在一个窗口里以便快速访问。关于 Xfce 桌面很多重要的部分都可以通过配置来满足我的需求。
|
||||
|
||||
#### 8、模块化
|
||||
|
||||
Xfce 是由一系列单个的项目组成的整体,而且在你的 Linux 桌面发行版中也未必安装了 Xfce 的所有组件。[Xfce 项目][5] 的主页列出了主要的项目,所以你可以根据需要安装你想安装的附加组件。比如在我的 Fedora 28 workstation 版本上我安装的 Xfce 组时就没有 [Xfce 项目][5] 主页最下面的说明的一些程序。
|
||||
|
||||
这里还有个关于 Xfce 的 [文档页面][6] 和 一个被称为 [Xfce 超值项目][7] 的 wiki 列举了其他的 Xfce 相关的项目,它们为 Xfce 的面板及 Thunar 提供了很多不错的应用程序、精美的插图、好用的插件。
|
||||
|
||||
### 总结
|
||||
|
||||
整体上很优雅的 Xfce 桌面所具备的足够轻巧和快速的特性能够让它很容易地知道如何做好一件事。它的轻量级的结构也节省了大量的 CPU 和内存资源。这也使得 Xfce 非常适合那种由于硬件有限而无法分配给桌面太多资源的旧主机。然而,Xfce 又是足够的灵活和强大的,能够满足高级用户的需要。
|
||||
|
||||
我知道,更换到一个新的 Linux 桌面环境需要你自己按照你想要的做些对应的自定义设置:比如面板上显示你最爱用的程序对应的启动器,设置下你最喜欢的桌面背景壁纸等一系列工作。这些年来我已经在切换到新桌面环境或更新旧桌面环境折腾很多次了。这需要时间也需要耐心。
|
||||
|
||||
我觉得切换 Linux 的桌面环境就像我在工作中换个办公工位或者办公室一样。别人把我的东西装箱从旧办公室搬到新办公室,然后我在我的新办公室里组装连接好我的电脑,打开箱子再把里面的东西放在合适的位置。而切换到 Xfce 桌面大概就是我做过的最简单省事容易的桌面环境更换了。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/xfce-desktop
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[WangYueScream](https://github.com/WangYueScream)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dboth
|
||||
[1]:https://xfce.org/
|
||||
[2]:/file/401856
|
||||
[3]:https://opensource.com/sites/default/files/uploads/xfce-desktop-01.png (Xfce desktop)
|
||||
[4]:https://opensource.com/sitewide-search?search_api_views_fulltext=David%20Both%20File%20managers
|
||||
[5]:https://xfce.org/projects
|
||||
[6]:https://docs.xfce.org/
|
||||
[7]:https://goodies.xfce.org/
|
||||
@@ -0,0 +1,69 @@
|
||||
软件 bug 的生命周期
|
||||
======
|
||||
|
||||
> 从发现软件故障到解决它们,这里讲述是开发团队如何压制软件 bug。
|
||||
|
||||

|
||||
|
||||
1947 年,发现了第一个计算机 bug —— 被困在计算机继电器中的飞蛾。
|
||||
|
||||
要是所有的 bug 都能如此简单地发现就好了。随着软件变得越来越复杂,测试和调试的过程也变得更加复杂。如今,软件 bug 的生命周期可能会很长,尽管正确的技术和业务流程可能会有所帮助。对于开源软件,开发人员使用严格的工单服务和协作来查找和解决 bug。
|
||||
|
||||
### 确认计算机 bug
|
||||
|
||||
在测试过程中,发现的 bug 会报告给开发团队。质量保证测试人员尽可能详细地描述 bug ,报告他们的系统状态、他们正在进行的过程以及 bug 是如何表现出来的。
|
||||
|
||||
尽管如此,一些 bug 从未得到确认;它们可能会在测试中报告,但永远无法在可控环境中重现。在这种情况下,它们可能得不到解决,而是被关闭。
|
||||
|
||||
有些计算机 bug 可能很难确认,因为使用的平台种类繁多,用户行为也非常多。有些 bug 只是间歇性地或在非常特殊的情况下发生的,而另一些 bug 可能会出现在随机的情况下。
|
||||
|
||||
许多人使用开源软件并与之交互,许多 bug 和问题可能是不可重复的,或者可能没有得到充分的描述。不过,由于每个用户和开发人员也都扮演质量保证测试人员的角色,至少在一定程度上,bug 还是很有可能会发现的。
|
||||
|
||||
确认 bug 后,修复工作就开始了。
|
||||
|
||||
### 分配要修复的 bug
|
||||
|
||||
已确认的 bug 被分配给负责解决的开发人员或开发团队。在此阶段,需要重现 bug,发现问题,并修复相关代码。如果 bug 的优先级较低,开发人员可以将此 bug 分类为稍后要修复的问题,也可以在该 bug 具有高优先级的情况下直接指派某人修复。无论哪种方式,都会在开发过程中打开一个工单,并且 bug 将成为已知的问题。
|
||||
|
||||
在开源解决方案中,开发人员可以进行选择他们想要解决的 bug,要么选择他们最熟悉的程序区域,要么从优先级最高的的开始。综合解决方案,如 [GitHub][1] 使得多个开发人员能够轻松地着手解决,而不会干扰彼此的工作。
|
||||
|
||||
当将 bug 设置为需要修复时,bug 报告者还可以为该 bug 选择优先级。主要的 bug 可能具有较高的优先级,而仅与外观相关的 bug 可能具有较低的级别。优先级确定开发团队解决这些问题的方式和时间。无论哪种方式,所有的 bug 都需要先解决,然后才能认为产品已完成。在这方面,适当的回溯到优先级高的需求也会很有帮助。
|
||||
|
||||
### 解决 bug
|
||||
|
||||
一旦修复了 bug ,通常会将其作为已解决的 bug 发送回质量保证测试人员。然后,质量保证测试人员再次将产品置于其工作中,以重现 bug。如果无法重现 bug ,质量保证测验人员将假定它已得到适当解决。
|
||||
|
||||
在开源情况下,任何更改都会被分发,通常是作为正在测试的暂定版本。此测试版本分发给用户,用户再次履行质量保证测试人员的职责并测试产品。
|
||||
|
||||
如果 bug 再次出现,问题将被发送回开发团队。在此阶段,该 bug 将重新触发,开发团队有责任重复解决该 bug 的循环。这种情况可能会发生多次,尤其是在 bug 不可预知或间歇性发生的情况下。众所周知,间歇性的 bug 很难解决。
|
||||
|
||||
如果该 bug 不再出现,则该问题将被标记为已解决。在某些情况下,最初的 bug 得到了解决,但由于所做的更改,会出现其他 bug。发生这种情况时,可能需要新的 bug 报告,然后重新开始该过程。
|
||||
|
||||
### 关闭 bug
|
||||
|
||||
在处理、识别和解决 bug 后,该 bug 将被关闭,开发人员可以转到软件开发和测试的其他阶段。如果始终找不到 bug ,或者开发人员无法重现 bug ,则该 bug 也将被关闭 —— 无论哪种方式,都将开始开发和测试的下一阶段。
|
||||
|
||||
在测试版本中对解决方案所做的任何更改都将滚动到产品的下一个版本中。如果 bug 是严重的,则在下一个版本发布之前,可能会为当前用户提供修补程序或修补程序。这在安全问题中很常见。
|
||||
|
||||
软件 bug 可能很难找到,但通过遵循过程,开发人员可以使开发更快、更容易、更一致。质量保证是这一过程的重要组成部分,因为质量保证测试人员必须发现和识别 bug ,并帮助开发人员重现这些 bug 。在 bug 不再发生之前,无法关闭和解决 bug。
|
||||
|
||||
开源的解决方案分散了质量保证测试、开发和缓解的负担,这往往导致 bug 被更快、更全面地发现和缓解。但是,由于开源技术的性质,此过程的速度和准确性通常取决于解决方案的受欢迎程度及其维护和开发团队的敬业精神。
|
||||
|
||||
Rich Butkevic 是一个 PMP 项目经理认证,,敏捷开发框架认证(certified scrum master) 并且 维护 [Project Zendo][2],这是供项目管理专业人员去发现、简化和改进其项目成果策略的网站。可以在 [Richbutkevic.com][3] 或者使用 [LinkedIn][4] 与 Rich 联系。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/life-cycle-software-bug
|
||||
|
||||
作者:[Rich Butkevic][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/rich-butkevic
|
||||
[1]:https://github.com/
|
||||
[2]:https://projectzendo.com
|
||||
[3]:https://richbutkevic.com
|
||||
[4]:https://www.linkedin.com/in/richbutkevic
|
||||
@@ -0,0 +1,99 @@
|
||||
10 个供管理员救急的杀手级工具
|
||||
======
|
||||
|
||||
> 可以让你赶快离开办公室的网络管理技巧和工具。
|
||||
|
||||

|
||||
|
||||
当工作任务堆积成山时,管理网络和系统就变得十分有压力了。没有人能真正意识到需要花费多长时间,每个人都希望在昨天就完成他们的工作。
|
||||
|
||||
所以难怪我们这么多人都被致力于找出有效的方法并与大家分享的开源精神所吸引。因为,当截止日期来临,并且当天没有足够多的时间时,如果你可以找到立刻施行的免费答案,那会非常有帮助。
|
||||
|
||||
因此,闲话少叙,下述是我的瑞士军刀,可以保证你在晚饭前离开办公室。
|
||||
|
||||
### 服务器配置和脚本
|
||||
|
||||
让我们看一看!
|
||||
|
||||
- [NixCraft][1]
|
||||
|
||||
使用该网站的搜索功能。经过十多年的定期更新,这里遍地是黄金!有用的脚本和方便的技巧可以立刻解决你的问题。这是我一般使用 Google 后的第二个选项。
|
||||
|
||||
- [Webmin][2]
|
||||
|
||||
它提供给你了一个很好的 Web 界面来帮助你远程编辑配置文件。它减少了在处理目录路径和 `sudo nano` 上花费的大量时间,在你处理多个客户时,非常方便。
|
||||
|
||||
- [Windows 下的 Linux 子系统][3]
|
||||
|
||||
现代工作场所的现实是大多数员工都运行着 Windows,而服务器机房中不断增长的设备则运行着 Linux 。因此,有些时候你会发现尝试在 Windows 桌面上执行管理任务。
|
||||
|
||||
你怎么做?装一个虚拟机?如果安装目前 Windows 10 中免费提供的 Linux 子系统的兼容层,实际上要快得多,配置要少的多。
|
||||
|
||||
这为你提供了一个 Bash 终端窗口,你可以在这个窗口中执行本地计算机上的 Bash 脚本和 Linux 二进制文件,可以完全访问 Windows 和 Linux 文件系统,以及安装网络驱动器。它包含 Ubuntu 、OpenSUSE、SLES、Debian 和 Kali 发行版。
|
||||
|
||||
- [mRemoteNG][4]
|
||||
|
||||
当你有 100 多个服务器需要去管理时,这会是一个出色的 SSH 和远程桌面客户端。
|
||||
|
||||
### 设置网络,这样你就无需再这样做了。
|
||||
|
||||
一个设计不周的网络是厌恶加班的管理员的死敌。
|
||||
|
||||
- [可拓展的 IP 寻址方案][5]
|
||||
|
||||
IP 地址耗尽的可怕之处在于,当 IP 地址耗尽时,网络已经变的足够大,而新的寻址方案是众所周知的昂贵、令人痛苦的耗时。
|
||||
|
||||
没有人有时间做这件事!
|
||||
|
||||
到了某个时候,IPv6 终将到来,来拯救这世界。但在那之前,无论世界向我们扔了多少可穿戴设备、平板电脑、智能锁、灯、安全摄像头、VoIP 耳机和浓缩咖啡机,这些以不变应万变的 IP 寻址方案都应该让我们继续前行。
|
||||
|
||||
- [Linux Chmod 权限备忘录][6]
|
||||
|
||||
一个简短但是有用的 Bash 命令备忘录可以帮助你通过网络设置权限。所以,客户服务部的账单落入到勒索软件骗局时,你可以只恢复他们的文件,而不是整个公司的文件。
|
||||
|
||||
- [VLSM 子网计算器][7]
|
||||
|
||||
只需要输入你想要从地址空间中创建的网络的数量,以及每个网络所需要的主机数量,它就可以计算出所有的子网掩码应该是什么。
|
||||
|
||||
### 单一用途的 Linux 发行版
|
||||
|
||||
需要一个只做一件事的 Linux 容器?如果其他人已经在一个操作系统上搞好了一个小东西,你就可以快速安装它并马上投入使用。
|
||||
|
||||
下面这些每一个都使得我的工作变得轻松了许多。
|
||||
|
||||
- [Porteus Kiosk][8]
|
||||
|
||||
这个工具用来帮你把一台电脑上锁定到一个浏览器上。通过稍稍一些调整,你甚至可以把浏览器锁定在一个特定的网站上。它对于公共访问机器来说非常方便。它可以与触摸屏或键盘鼠标配合使用。
|
||||
|
||||
- [Parted Magic][9]
|
||||
|
||||
这是一个你可以从 USB 驱动器启动的,可以用来划分磁盘驱动器、恢复数据并运行基准测试工具的操作系统。
|
||||
|
||||
- [IPFire][10]
|
||||
|
||||
啊哈~我还是不敢相信有人把路由器/防火墙/代理组合成为“我尿火”(LCTT 译注:IPFire 和 “I pee Fire“ 同音)。这是我在这个 Linux 发行版中第二喜欢的东西。我最喜欢的是它是一个非常可靠的软件套件,设置和配置十分容易,而且有一系列的插件可以拓展它。
|
||||
|
||||
那么,你呢?你发现了哪些工具、资源和备忘录可以让我们的工作日更加的轻松?我很高兴知道,请在评论中分享您的工具。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/7/tools-admin
|
||||
|
||||
作者:[Grant Hamono][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[bestony](https://github.com/bestony)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/grantdxm
|
||||
[1]:https://www.cyberciti.biz/
|
||||
[2]:http://www.webmin.com/
|
||||
[3]:http://wsl-guide.org/en/latest/
|
||||
[4]:https://mremoteng.org/
|
||||
[5]:https://blog.dxmtechsupport.com.au/ip-addressing-for-a-small-business-that-might-grow/
|
||||
[6]:https://isabelcastillo.com/linux-chmod-permissions-cheat-sheet
|
||||
[7]:http://www.vlsm-calc.net/
|
||||
[8]:http://porteus-kiosk.org/
|
||||
[9]:https://partedmagic.com/
|
||||
[10]:https://www.ipfire.org/
|
||||
@@ -0,0 +1,140 @@
|
||||
微型计算机的始祖:Altair 8800
|
||||
======
|
||||
|
||||
《<ruby>大众电子<rt>Popular Electronics</rt></ruby>》的订阅者们是个复杂的群体,该杂志的编辑 Arthur Salsberg 不得不在 [1974 年 12 月刊][1] 中的前言部分指出这点。此前,杂志编辑组曾收到了对《如何搭建家庭媒体中心》文章的抱怨,称这篇文章激励了许多业余电视爱好者走出去,削弱了专业修理人员存在的必要性,这对许多人的电视造成了极大伤害。Salsberg 认为,这个担忧的产生可能是因为大家不清楚《大众电子》读者们的真实水平。他解释道,据杂志内部调查的数据显示,52% 的订阅者都是某方面的电子专家,并且其中的 150,000 人在最近 60 天之内都修过电视。此外,订阅者们平均在电子产品上花费了 470 美金(2018 年则是 3578 美金),并且他们拥有万用表、真空管伏特计、电子管测试仪、晶体管测试仪、射频讯号产生器和示波器等必要设备。“《大众电子》的读者们并不全都是新手。”Salsberg 总结道。
|
||||
|
||||
熟悉《大众电子》的人居然会质疑它的订阅者,这令我十分吃惊。不过最近 60 天我的确没修过电视。我的电脑对我来说就是一块铝,我甚至没把它拆开看过。1974 年 12 月的《大众电子》刊登的像《驻波比是什么以及如何处理它》和《对万用表的测试》之类的特色文章,甚至连广告都令人生畏。它们中有个看起来像某种立体声系统的东西大胆地写道“除了‘四通道单元(即内建的 SQ、RM 和 CD-4 解码接收器)’,没有任何音频设备是值得期待的”。这也表明了《大众电子》的订阅者一定对电子有很多深入的了解。
|
||||
|
||||
不过在 [1975 年 1 月刊][2] 中,该杂志为读者们带来了一些他们从没见过的东西。在标题“突破性项目”下面,杂志的封面是一个大大的黑灰色盒子,其前面板上有一组复杂开关和灯。这便是 Altair 8800,“世界上首个有商业竞争力的小型机”,它的售价低于 400 美元。尽管 Altair 被宣传作“<ruby>小型机<rt>minicomputer</rt></ruby>”,但它实际上是首个商业上成功的新型计算机成员,它首先被称为“<ruby>微型计算机<rt>microcomputers</rt></ruby>”,最终被称为 PC(<ruby>个人计算机<rt>Personal Computer</rt></ruby>)。Altair 十分小巧而且很便宜,以至于它成为了当时家家户户都能用起的电脑。正如 Salsberg 所写道,它在《大众电子》上的出现意味着:“家用电脑的时代终于到来了。”
|
||||
|
||||
![《大众电子》1975 年 1 月刊的封面][3]
|
||||
|
||||
此前,我曾写过 [关于 Altair 的文章][4],但我觉得 Altair 值得重新审视。与当时其它的计算机相比,它并不是一台性能强劲的计算机(尽管它的成本要低得多),它也不是首个采用微处理器的通用计算机(在它之前已经至少有三个基于微处理器的计算机)。但是 Altair 是一种可供我们所有人使用的计算机。它是历史上我们所拥有的设备中首台流行的计算机,而早于 Altair 计算机都是完全不同的机器,那些大型机和笨重的迷你计算机由穿孔卡编程并且很少与之直接交互。不过 Altair 也是台极其简单的计算机,它没有附带任何操作系统甚至是引导程序。除非你为它购买外围设备,否则 Altair 就是一台装配了 RAM、前面板只有一组开关和灯泡的机器。由于 Altair 操作简单,使得重新理解基本的计算概念都成了十分简单的事情,正如模拟信号时代的人们第一次接触到数字设备一样。
|
||||
|
||||
### Roberts 和他的公司
|
||||
|
||||
Altair 是由一家名为<ruby>微型仪器和遥测系统<rt>Micro Instrumentation and Telemetry Systems</rt></ruby>(MITS)的公司所设计制造,这家公司位于美国新墨西哥州的阿尔布开克。MITS 由一个叫 H. Edward Roberts 的人经营。在进入计算器市场之前,该公司已经开始制造模型火箭的遥测系统,该市场在 20 世纪 70 年代初期蓬勃发展。集成电路大大降低了计算器的成本,突然之间它就成了美国每个在职的专业人士的必需品。不幸的是,由于计算器市场竞争过于激烈,到了 1974 年初,MITS 便负债累累。
|
||||
|
||||
1974 年在计算机界是<ruby>奇迹迭出的一年<rt>annus mirabilis</rt></ruby>。[^1] 一月的时候,惠普公司推出了世界首个可编程的手持计算器 HP-65。四月的时候,Intel 发布了 Intel 8080,这是他们的第二款 8 位微处理器,它也是首款广受欢迎的微处理器。接着,六月的时候,《<ruby>无线电电子<rt>Radio Electronics</rt></ruby>》杂志宣传了一台名为 Mark-8 的自制小型计算机,它使用了 Intel 在 1972 年推出的 Intel 8008 微处理器。Mark-8 是有史以来使用微处理器搭建的第三台电脑,它的首次登场是在杂志的封面上。[^2] Mark-8 在《无线电电子》上的出现促使了《大众电子》寻找他们要自己宣传的小型机项目。
|
||||
|
||||
《大众电子》的订阅者们其实早在 1974 年 12 月就通过邮件获得了 1975 年 1 月刊的刊物。[^3] 所以 Altair 的宣布为这个<ruby>奇迹迭出的一年<rt>annus mirabilis</rt></ruby>画上了圆满的句号。Altair 的出现是十分重要的,因为此前从未有过向公众提供的价格公道而又功能齐全的电脑。当时,作为最受欢迎的小型计算机之一的 PDP-8 要几千美金才能买到。然而作为 Altair 核心的 Intel 8080 芯片几乎能与 PDP-8 匹敌,甚至更强;8080 支持更广泛的指令集,而且 Altair 可以扩展到 64 kb 内存,显然强于仅有 4 kb 内存的 PDP-8。并且,Mark-8 也不是它的对手,因为它搭载的是只能处理 16 kb 内存的 Intel 8008。在 Mark-8 必须由用户按照说明书在印刷电路板上手动拼装的情况下,Altair 在购买时就已经被组装好了(不过由于后来 MITS 被大量订单淹没,最后真正能获得 Altair 的方式也只有买套件拼装了)。
|
||||
|
||||
对许多《大众电子》的读者来说,Altair 是他们了解数字计算的起点。1975 年 1 月刊上那篇介绍 Altair 的文章由 Roberts 和 Altair 的共同设计师 William Yates 所写。Roberts 和 Yates 煞费苦心地用电工和无线电狂热者们所熟悉的词汇来介绍了数字硬件和计算机编程的基本概念。他们写道:“一台计算机其实由一块可变的硬件。仅需修改储存于内存之中的位组合形式,便可改变硬件设备的种类。”同时,Roberts 和 Yates 认为编程的基本概念是“足够简单并能在较短时间内掌握,但是想要成为一个高效的程序员必须经验丰富且富有创造力。”对此我十分认同。尽管该部分已经完全组装好了,文章仍包含了用来讲解 Intel 8080 的组成电路的详细图表。文章解释了 CPU 和计算机内存单元的区别,堆栈指针的用法,和汇编语言以及更高级的语言(例如 FORTRAN 和 BASIC)比起手动输入机器码所带来的巨大优势。
|
||||
|
||||
其实,《大众电子》在 1975 年 1 月刊之前就出版过 Roberts 撰写的系列文章。这一系列作为短期课程被收录在“数字逻辑”专栏中。在 1974 年 12 月刊中,Roberts 为读者们带来了关于构建“超低成本计算机终端”的文章,文章中介绍了可以用于 8 位电脑中输入值的八进制键盘。在介绍这个键盘时,Roberts 解释了晶体管到晶体管的逻辑工作原理,以及关于构建一种可以“记住”数字值的触发器的方法。Roberts 承诺说,这个键盘可以在下个月即将公布的 Altair 电脑中使用。
|
||||
|
||||
有多少《大众电子》的读者制作了这个键盘我们无从得知,但是那个键盘的确是个很有用的东西。如果没有键盘和其它输入设备,我们只能通过拨动 Altair 面板上的开关来输入值。Altair 的前面板上有一行 16 个开关被用来设置地址,而下方的 8 个则是用来操作计算机的。一行 16 个开关中最右边的 8 个开关也能用来指定要储存在内存中的值。这么做不无道理,因为 Intel 8080 使用 16 位的值来寻址 8 位的字。而前面板的这 16 个开关每一个都代表了一个位,当开关向上时代表 1,向下则代表 0。用这样的方式与计算机交互是个启示(一会儿我们就会讲到),因为 Altair 的面板是真正的二进制界面。这使得你可以尽可能地接触到计算机实体。
|
||||
|
||||
尽管在当下 Altair 的界面对我们来说完全不像是人用的,不过在那个时代却并不罕见。比如 PDP-8 的面板上有个类似的但更漂亮的二进制输入装置,而且它被涂上了吸引人的黄色和橙色,不过讲真,它真的应该卷土重来。然而 PDP-8 经常与纸带阅读器或电传打字机配合使用,这使得程序输入更加容易。这些 I/O 设备价格高昂,这意味着 Altair 的用户们大都会被那个前面板拦住。正如你可能想象的那样,通过这一堆开关输入一个大型程序是个苦差事。不过幸运的是,Altair 可以与盒式记录器连接,这样一来载入程序就不是什么难事了。Bill Gates 和 Paul Allen 在 MITS 的授权下为 Altair 编写了一个 BASIC 语言版本,并在 1975 年中期发行,这成为了微软有史以来的首次商业尝试。此后,那些买得起电传打字机的用户就能 [通过纸带来将 BASIC 载入 Altair][5] 了,并能使得用户能够通过文字与 Altair 交互。之后,BASIC 便成为了学生们最爱的入门编程语言,并成了早期小型机时代的标准接口。
|
||||
|
||||
### z80pack
|
||||
|
||||
多亏了网络上一些人,特别是 Udo Munk 的努力,你可以在你的计算机上运行 Altair 的模拟器。这个模拟器是在 Zilog Z80 CPU 的虚拟套件上构建的,这个 CPU 可以运行 Intel 8080 的软件。Altair 模拟器允许你像 Altair 的早期用户们一样拨动前面板上的开关。尽管点击这些开关的感觉不如拨动真实开关的触觉,但是使用 Altair 模拟器仍是一个能让你感受二进制人机交互效率有多低的途径,至少在我看来这非常简明直观。
|
||||
|
||||
z80pack 是 Udo Munk 开发的 Z80 模拟器套件,你可以在 z80pack 的官网上找到它的下载链接。我在 [上一篇介绍 Altair 的文章中][4] 写到过在 macOS 上使用它的详细过程。如果你能编译 FrontPanel 库和 `altairsim` 可执行程序,你应该能直接运行 `altairsim` 并看到这个窗口:
|
||||
|
||||
![模拟器中的 Altair 面板][6]
|
||||
|
||||
在新版的 z80pack 中(比如我正在使用的 1.36 版本),你可以使用一个叫 Tarbell boot ROM 的功能,我觉得这是用来加载磁盘镜像的。经我测试,这意味着你不能写入到 RAM 中的前几个字。在编辑 `/altairsim/conf/system.conf` 之后,你可以构建带有一个 16 页 RAM 且没有 ROM 或引导加载器的 Altair。除此之外,你还可以用这个配置文件来扩大运行模拟器的窗口大小,不得不说这还是挺方便的。
|
||||
|
||||
Altair 的面板看起来令人生畏,不过事实上并没有我们想象中的这么可怕。[Altair 说明书][7] 对解释开关和指示灯起到了很大的作用,这个 [YouTube 视频][8] 也是如此。若想输入和运行一个简易的程序,你只需要了解一点点东西。Altair 右上方标签为 D0 到 D7 的指示灯代表当前寻址的字的内容。标签为 A0 到 A15 的指示灯表示当前的地址。地址指示灯下的 16 个开关可以用来设置新地址;当 “EXAMINE” 开关被向上推动时,数据指示灯才会更新以显示新地址上的内容。用这个功能,你便能“观察”到内存中所有的信息了。你也可以将 “EXAMINE” 推下来“EXAMINE NEXT”位置,以自动检查下一个位置上的信息,这使得查看连续的信息更容易了。
|
||||
|
||||
要将位组合方式保存到内存信息中,请使用最右边的 8 个标签为 0 到 7 的开关。然后,请向上推动 “DEPOSIT” 按钮。
|
||||
|
||||
在《大众电子》 的 [1975 年 2 月刊][9] 中,Roberts 和 Yates 引导用户输入一小段程序来确保他们的 Altair 正常工作。这个程序从内存中读取两个整型数据并相加之后将和存回内存中。这个小程序仅由 6 条指令组成,但是这 6 条指令涉及了 14 个字的内存,所以要正确地输入它们需要一点时间。这个示例程序也被写入了 Altair 的说明书,原文如下:
|
||||
|
||||
| Address | Mnemonic | Bit Pattern | Octal Equivalent |
|
||||
| :------: | :------: | :------: | :------: |
|
||||
| 0 | LDA | 00 111 010 | 0 7 2 |
|
||||
| 1 | (address) | 10 000 000 | 2 0 0 |
|
||||
| 2 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 3 | MOV B, A | 01 000 111 | 1 0 7 |
|
||||
| 4 | LDA | 00 111 010 | 0 7 2 |
|
||||
| 5 | (address) | 10 000 001 | 2 0 1 |
|
||||
| 6 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 7 | ADD B | 10 000 000 | 2 0 0 |
|
||||
| 8 | STA | 00 110 010 | 0 6 2 |
|
||||
| 9 | (address) | 10 000 010 | 2 0 2 |
|
||||
| 10 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 11 | JMP | 11 000 011 | 3 0 3 |
|
||||
| 12 | (address) | 00 000 000 | 0 0 0 |
|
||||
| 13 | (address) | 00 000 000 | 0 0 0 |
|
||||
|
||||
如果你通过开关来将上表的这些值输入到 Altair,最终会得到一个程序,它会读取内存 128 中的值,并将其与 129 中的值相加,最终将其保存至 130 中。伴随每条取一个地址的指令的地址,它们最开始会给出最低有效位,这便是第二个字节总会被清零的原因了(没有高于 255 的地址)。在输入这个程序并在 128 和 129 中输入了一些值之后,你可以向下短暂推动 “RUN” ,之后再将它推到 “STOP” 位置。因为程序循环执行,以一秒内执行上千次的速度反复地添加并保存那些值。并且最后得到的值总是相同的,如果你停止该程序并查看 130 的内容,你应该能找到正确答案。
|
||||
|
||||
我不知道普通的 Altair 用户是否使用过汇编程序,不过 z80pack 包括了一个:`z80asm`,意思是<ruby>适用于 Z80 的汇编程序<rt>Z80 assembly</rt></ruby>,所以它使用了一组不同的助记符。不过因为 Z80 是被设计来兼容为 Intel 8080 写的软件的,所以即使助记符不一样,它们的操作码也是相同的。你可以直接将 `z80asm` 汇编码装载进 Altair:
|
||||
|
||||
```
|
||||
ORG 0000H
|
||||
START: LD A,(80H) ;Load from address 128.
|
||||
LD B,A ;Move loaded value from accumulator (A) to reg B.
|
||||
LD A,(81H) ;Load from address 129.
|
||||
ADD A,B ;Add A and B.
|
||||
LD (82H),A ;Store A at address 130.
|
||||
JP START ;Jump to start.
|
||||
```
|
||||
|
||||
编译之后,你可以调用汇编程序来将其转换为 Intel HEX 文件:
|
||||
|
||||
```shell
|
||||
$ ./z80asm -fh -oadd.hex add.asm
|
||||
```
|
||||
|
||||
我们用带有 `h` 参数的 `-f` 标识来定义输出的 HEX 文件。你可以用 `-x` 标识来传递 HEX 文件,从而使得 Altair 能够加载该程序:
|
||||
|
||||
```shell
|
||||
$ ./altairsim -x add.hex
|
||||
```
|
||||
|
||||
这会在内存中自动设置前 14 个字,就和你通过开关手动输入这些值一样。你可以直接使用 “RUN” 按钮来替代以前那些繁琐的步骤,这是如此的简单!
|
||||
|
||||
我不觉得有很多 Altair 用户以这种方式来编写软件。Altair BASIC 发布后,使得 BASIC 成为了 Altair 编程最简单的方法。z80pack 同时也包括了一些不同版本 Altair BASIC 的 HEX 文件;在模拟器中,你可以用这个方式加载 4.0 版本的 4K BASIC:
|
||||
|
||||
```shell
|
||||
$ ./altairsim -x basic4k40.hex
|
||||
```
|
||||
|
||||
当你开启模拟器并按下 “RUN” 按钮之后,你就会看到 BASIC 开始执行了,同时它会在终端中与你交互。它首先会提示你输入你的内存可用量,我们输入 4000 字节。随后,在显示 “OK” 提示符之前,它会问你几个问题,Gates 和 Allen 用这个“OK”来代替标准的 “READY” 并以此节省内存。在这之后,你便可以使用 BASIC 了:
|
||||
|
||||
```
|
||||
OK
|
||||
PRINT 3 + 4
|
||||
7
|
||||
```
|
||||
|
||||
虽然运行 BASIC 只有 4kb 的内存并没有给你足够的空间,但你可以看到它是如何从使用前面板迈出了重要的一步。
|
||||
|
||||
很显然,Altair 远不及如今的家用电脑和笔记本电脑,并且比它晚十多年发布的 Mac 电脑看上去也是对 这个简朴的 Altair 电脑的巨大飞跃。但是对第一批购买并亲手组装了 Altair 的《大众电子》的读者们来说,Altair 才是他们拥有的第一个真正的全功能电脑,而这一切只用了 400 美金低价和一半的书柜空间。对那时只能用 [一叠卡片][10] 或一卷磁带来与计算机交互的人们来说,Altair 是个令人眼前一亮的玩意。这之后的微型计算机基本都是在对 Altair 改进,使得它更易用。从某种意义上来说,它们只是更复杂的 Altair。Altair,一个野兽派的极简作品,却为之后的许多微型计算机打下了铺垫。
|
||||
|
||||
如果你觉得这篇文章写的不错,你可以在推特上关注 [@TwoBitHistory][11] 或订阅 [RSS feed][12] 来获得我们文章的更新提醒。文章每两周就会更新一次!
|
||||
|
||||
[^1]: Paul E. Ceruzzi, A History of Modern Computing (Cambridge, Mass: MIT Press, 2003), 226.
|
||||
[^2]: “Mark-8 Minicomputer,” Byran’s Old Computers, accessed July 21, 2018, http://bytecollector.com/mark_8.htm.
|
||||
[^3]: Paul E. Ceruzzi, A History of Modern Computing (Cambridge, Mass: MIT Press, 2003), 226.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://twobithistory.org/2018/07/22/dawn-of-the-microcomputer.html
|
||||
|
||||
作者:[Sinclair Target][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zhs852](https://github.com/zhs852)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://twobithistory.org
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.americanradiohistory.com/Archive-Poptronics/70s/1974/Poptronics-1974-12.pdf
|
||||
[2]: https://www.americanradiohistory.com/Archive-Poptronics/70s/1975/Poptronics-1975-01.pdf
|
||||
[3]: https://twobithistory.org/images/jan1975-altair.jpg
|
||||
[4]: https://linux.cn/article-10181-1.html
|
||||
[5]: https://www.youtube.com/watch?v=qv5b1Xowxdk
|
||||
[6]: https://www.autometer.de/unix4fun/z80pack/altair.png
|
||||
[7]: http://www.classiccmp.org/dunfield/altair/d/88opman.pdf
|
||||
[8]: https://www.youtube.com/watch?v=suyiMfzmZKs
|
||||
[9]: https://www.americanradiohistory.com/Archive-Poptronics/70s/1975/Poptronics-1975-02.pdf
|
||||
[10]: https://linux.cn/article-10382-1.html
|
||||
[11]: https://twitter.com/TwoBitHistory
|
||||
[12]: https://twobithistory.org/feed.xml
|
||||
[13]: https://twitter.com/TwoBitHistory/status/1015647820353867776?ref_src=twsrc%5Etfw
|
||||
@@ -0,0 +1,335 @@
|
||||
使用 Node.js 构建交互式命令行工具
|
||||
======
|
||||
|
||||
> 使用 Node.js 构建一个根据询问创建文件的命令行工具。
|
||||
|
||||

|
||||
|
||||
当用于构建命令行界面(CLI)时,Node.js 十分有用。在这篇文章中,我将会教你如何使用 [Node.js][1] 来构建一个问一些问题并基于回答创建一个文件的命令行工具。
|
||||
|
||||
### 开始
|
||||
|
||||
首先,创建一个新的 [npm][2] 包(NPM 是 JavaScript 包管理器)。
|
||||
|
||||
```
|
||||
mkdir my-script
|
||||
cd my-script
|
||||
npm init
|
||||
```
|
||||
|
||||
NPM 将会问一些问题。随后,我们需要安装一些包。
|
||||
|
||||
```
|
||||
npm install --save chalk figlet inquirer shelljs
|
||||
```
|
||||
|
||||
这是我们需要的包:
|
||||
|
||||
* Chalk:正确设定终端的字符样式
|
||||
* Figlet:使用普通字符制作大字母的程序(LCTT 译注:使用标准字符,拼凑出图片)
|
||||
* Inquirer:通用交互式命令行用户界面的集合
|
||||
* ShellJS:Node.js 版本的可移植 Unix Shell 命令行工具
|
||||
|
||||
### 创建一个 index.js 文件
|
||||
|
||||
现在我们要使用下述内容创建一个 `index.js` 文件。
|
||||
|
||||
```
|
||||
#!/usr/bin/env node
|
||||
|
||||
const inquirer = require("inquirer");
|
||||
const chalk = require("chalk");
|
||||
const figlet = require("figlet");
|
||||
const shell = require("shelljs");
|
||||
```
|
||||
|
||||
### 规划命令行工具
|
||||
|
||||
在我们写命令行工具所需的任何代码之前,做计划总是很棒的。这个命令行工具只做一件事:**创建一个文件**。
|
||||
|
||||
它将会问两个问题:文件名是什么以及文件后缀名是什么?然后创建文件,并展示一个包含了所创建文件路径的成功信息。
|
||||
|
||||
```
|
||||
// index.js
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
// ask questions
|
||||
// create the file
|
||||
// show success message
|
||||
};
|
||||
|
||||
run();
|
||||
```
|
||||
|
||||
第一个函数只是该脚本的介绍。让我们使用 `chalk` 和 `figlet` 来把它完成。
|
||||
|
||||
```
|
||||
const init = () => {
|
||||
console.log(
|
||||
chalk.green(
|
||||
figlet.textSync("Node JS CLI", {
|
||||
font: "Ghost",
|
||||
horizontalLayout: "default",
|
||||
verticalLayout: "default"
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
// create the file
|
||||
// show success message
|
||||
};
|
||||
|
||||
run();
|
||||
```
|
||||
|
||||
然后,我们来写一个函数来问问题。
|
||||
|
||||
```
|
||||
const askQuestions = () => {
|
||||
const questions = [
|
||||
{
|
||||
name: "FILENAME",
|
||||
type: "input",
|
||||
message: "What is the name of the file without extension?"
|
||||
},
|
||||
{
|
||||
type: "list",
|
||||
name: "EXTENSION",
|
||||
message: "What is the file extension?",
|
||||
choices: [".rb", ".js", ".php", ".css"],
|
||||
filter: function(val) {
|
||||
return val.split(".")[1];
|
||||
}
|
||||
}
|
||||
];
|
||||
return inquirer.prompt(questions);
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
// show success message
|
||||
};
|
||||
```
|
||||
|
||||
注意,常量 `FILENAME` 和 `EXTENSIONS` 来自 `inquirer` 包。
|
||||
|
||||
下一步将会创建文件。
|
||||
|
||||
```
|
||||
const createFile = (filename, extension) => {
|
||||
const filePath = `${process.cwd()}/${filename}.${extension}`
|
||||
shell.touch(filePath);
|
||||
return filePath;
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
const filePath = createFile(FILENAME, EXTENSION);
|
||||
|
||||
// show success message
|
||||
};
|
||||
```
|
||||
|
||||
最后,重要的是,我们将展示成功信息以及文件路径。
|
||||
|
||||
```
|
||||
const success = (filepath) => {
|
||||
console.log(
|
||||
chalk.white.bgGreen.bold(`Done! File created at ${filepath}`)
|
||||
);
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
const filePath = createFile(FILENAME, EXTENSION);
|
||||
|
||||
// show success message
|
||||
success(filePath);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
来让我们通过运行 `node index.js` 来测试这个脚本,这是我们得到的:
|
||||
|
||||

|
||||
|
||||
### 完整代码
|
||||
|
||||
下述代码为完整代码:
|
||||
|
||||
```
|
||||
#!/usr/bin/env node
|
||||
|
||||
const inquirer = require("inquirer");
|
||||
const chalk = require("chalk");
|
||||
const figlet = require("figlet");
|
||||
const shell = require("shelljs");
|
||||
|
||||
const init = () => {
|
||||
console.log(
|
||||
chalk.green(
|
||||
figlet.textSync("Node JS CLI", {
|
||||
font: "Ghost",
|
||||
horizontalLayout: "default",
|
||||
verticalLayout: "default"
|
||||
})
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const askQuestions = () => {
|
||||
const questions = [
|
||||
{
|
||||
name: "FILENAME",
|
||||
type: "input",
|
||||
message: "What is the name of the file without extension?"
|
||||
},
|
||||
{
|
||||
type: "list",
|
||||
name: "EXTENSION",
|
||||
message: "What is the file extension?",
|
||||
choices: [".rb", ".js", ".php", ".css"],
|
||||
filter: function(val) {
|
||||
return val.split(".")[1];
|
||||
}
|
||||
}
|
||||
];
|
||||
return inquirer.prompt(questions);
|
||||
};
|
||||
|
||||
const createFile = (filename, extension) => {
|
||||
const filePath = `${process.cwd()}/${filename}.${extension}`
|
||||
shell.touch(filePath);
|
||||
return filePath;
|
||||
};
|
||||
|
||||
const success = filepath => {
|
||||
console.log(
|
||||
chalk.white.bgGreen.bold(`Done! File created at ${filepath}`)
|
||||
);
|
||||
};
|
||||
|
||||
const run = async () => {
|
||||
// show script introduction
|
||||
init();
|
||||
|
||||
// ask questions
|
||||
const answers = await askQuestions();
|
||||
const { FILENAME, EXTENSION } = answers;
|
||||
|
||||
// create the file
|
||||
const filePath = createFile(FILENAME, EXTENSION);
|
||||
|
||||
// show success message
|
||||
success(filePath);
|
||||
};
|
||||
|
||||
run();
|
||||
```
|
||||
|
||||
### 使用这个脚本
|
||||
|
||||
想要在其它地方执行这个脚本,在你的 `package.json` 文件中添加一个 `bin` 部分,并执行 `npm link`:
|
||||
|
||||
```
|
||||
{
|
||||
"name": "creator",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node index.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"chalk": "^2.4.1",
|
||||
"figlet": "^1.2.0",
|
||||
"inquirer": "^6.0.0",
|
||||
"shelljs": "^0.8.2"
|
||||
},
|
||||
"bin": {
|
||||
"creator": "./index.js"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
执行 `npm link` 使得这个脚本可以在任何地方调用。
|
||||
|
||||
这就是是当你运行这个命令时的结果。
|
||||
|
||||
```
|
||||
/usr/bin/creator -> /usr/lib/node_modules/creator/index.js
|
||||
/usr/lib/node_modules/creator -> /home/hugo/code/creator
|
||||
```
|
||||
|
||||
这会连接 `index.js` 作为一个可执行文件。这是完全可能的,因为这个 CLI 脚本的第一行是 `#!/usr/bin/env node`。
|
||||
|
||||
现在我们可以通过执行如下命令来调用。
|
||||
|
||||
```
|
||||
$ creator
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
正如你所看到的,Node.js 使得构建一个好的命令行工具变得非常简单。如果你希望了解更多内容,查看下列包。
|
||||
|
||||
* [meow][3]:一个简单的命令行助手工具
|
||||
* [yargs][4]:一个命令行参数解析工具
|
||||
* [pkg][5]:将你的 Node.js 程序包装在一个可执行文件中。
|
||||
|
||||
在评论中留下你关于构建命令行工具的经验吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/7/node-js-interactive-cli
|
||||
|
||||
作者:[Hugo Dias][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[bestony](https://github.com/bestony)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/hugodias
|
||||
[1]:https://nodejs.org/en/
|
||||
[2]:https://www.npmjs.com/
|
||||
[3]:https://github.com/sindresorhus/meow
|
||||
[4]:https://github.com/yargs/yargs
|
||||
[5]:https://github.com/zeit/pkg
|
||||
118
published/201901/20180731 How to be the lazy sysadmin.md
Normal file
118
published/201901/20180731 How to be the lazy sysadmin.md
Normal file
@@ -0,0 +1,118 @@
|
||||
如何成为一名懒惰的系统管理员
|
||||
======
|
||||
> 我们是聪明地工作,而不是刻苦工作,但仍能把工作做好。
|
||||
|
||||

|
||||
|
||||
Linux 的系统管理员的工作总是复杂的,并且总是伴随着各种陷阱和障碍。做每件事都没有足够时间,当你想完成那个半秃头老板(PHB)给的任务时,他(只会)不停在你的后面盯着,而最核心的服务器总是在最不合时宜的时间点崩溃,问题和挑战比比皆是。而我发现,成为一名<ruby>懒惰的系统管理员<rt>Lazy SysAdmin</rt></ruby>可以解决这一困境。
|
||||
|
||||
(LCTT 译注:<ruby>[半秃头老板](https://en.wikipedia.org/wiki/Pointy-haired_Boss)<rt>Pointy-Haired Boss</rt></ruby>(PHB),那是[呆伯特漫画](https://zh.wikipedia.org/wiki/%E5%91%86%E4%BC%AF%E7%89%B9)中的角色,缺乏一般知识常识及其职位所应具有的管理能力,爱说大话且富有向物理显示挑战的精神,大概长成下图这样。)
|
||||
|
||||

|
||||
|
||||
我在即将在 Apress 出版的新书 《The Linux Philosophy for SysAdmins》(LCTT 译注:暂译《系统管理员的 Linux 哲学》)中更详细地讨论如何成为一个懒惰的系统管理员,那书预计会在 9 月出版(LCTT 译注:已于 2018 年 8 月出版)。这本的部分内容摘录自该书,特别是第九章,“成为一名懒惰的系统管理员”。在我们讨论如何做到这点前,让我们简单了解一下成为一个名懒惰的系统管理员意味着什么。
|
||||
|
||||

|
||||
|
||||
### 真实生产力 vs. 虚假生产力
|
||||
|
||||
#### 虚假生产力
|
||||
|
||||
在我工作的地方,半秃头老板相信的管理风格叫“<ruby>走动式管理<rt>management by walking around</rt></ruby>”。通过判断某人在不在他的键盘上输入东西,或者至少要看看他们显示器上显示的东西,来判断他们的工作是否有效率。这是一个糟糕的工作场所。各部门间有道很高的行政墙,这会造就了许多的、微小的沟通壁垒,大量无用的文书工作,以及获得任何事情的许可都要等待漫长的时间。因为这样、那样的原因,不可能高效地做任何事情,如果真的是这样,那是非常低效。为了看起来很忙,我们都有自己的一套<ruby>“看起来很忙”的工具包<rt>Look Busy Kits</rt></ruby>(LBK),可能是一些短小的、用来显示一些行为活动的 Bash 脚本,或者是 `top`、`htop`、`iotop` 之类的程序,或者是一些持续显示某些行为活动的监控工具。这种工作场所的风气让人不可能真正高效,我讨厌这种地方,也讨厌那个几乎不可能完成任何有价值的事情的事实。
|
||||
|
||||
这种糟糕场所对真实的系统管理员来讲是场噩梦。没有人会感到快乐。在那里花费四五个月才能完成的事,在其他地方只需的一个早晨。我们没有什么实际工作要做,却要花大量的时间干活来让自己看起来很忙。我们在默默地竞赛,看谁能创造最好的“看起来很忙”的工具包,这就是我们花费最多时间的地方了。那份工作我只做了几个月,但好像已经耗费了一生。如果你看到的这个监狱的表面,你可能会说我们是很懒,因为我们只完成了几乎为 0 的实际工作。
|
||||
|
||||
这是个极端的例子,它完全与我所说的“我是一个懒惰的系统管理员”的意思相反,而做一个懒惰的系统管理是件好事。
|
||||
|
||||
#### 真实生产力
|
||||
|
||||
我很幸运,曾为一些真正的管理者工作过 —— 他们明白,系统管理员的生产力并不是以每天花多少小时敲键盘来衡量。毕竟,即使一只猴子能敲击他们的键盘,但也不能说明结果的价值。
|
||||
|
||||
正如我书中所言:
|
||||
|
||||
> “我是一个懒惰的系统管理员,同时我也是一个高效的系统管理员。这两者看似矛盾的说法不是相互排斥的,而是会以一种非常积极的方式相辅相成……
|
||||
>
|
||||
> “系统管理员在思考的时候是最高效的 —— 思考关于如何解决现有问题和避免未来的问题;思考怎样监控 Linux 计算机,以便找到预测和预示这些未来的问题的线索;思考如何让他们的工作更有效率;思考如何自动化所有这些要执行的任务,无论是每天还是每年一次的任务。
|
||||
>
|
||||
> “系统管理员冥思苦想的那一面是不会被非系统管理员所熟知的,那些人包括很多管理着系统管理员的人,比如那个半秃头老板。系统管理员都会以不同的方式解决他们工作中苦思的部分。一些我认识的系统管理员会在沙滩、骑自行车、参加马拉松或者攀岩时找到最好的想法。另一些人会认为静坐或听音乐的时候思考得最好。还有一些会在阅读小说、学习不相关的学科、甚至在学习 Linux 系统的时候可以最佳思考。关键是我们都有不同的方式激发我们的创造力,而这些创造力的推进器中很多并不涉及键盘上的任何一个按键。我们真正的生产力对于系统管理员周围的人来说可能是完全看不见的。”
|
||||
|
||||
成为懒惰的系统管理员有一些简单的秘诀 —— 系统管理员要完成一切需要完成的事,而且更多的是,当所有人都处于恐慌的状态时要保持冷静和镇定。秘诀的一部分是高效工作,另一部分是把预防问题放在首位。
|
||||
|
||||
### 成为懒惰系统管理员的方法
|
||||
|
||||
#### 多思考
|
||||
|
||||
我相信关于懒惰系统管理员最重要的秘诀在于思考。正如上面的摘录所言,优秀的系统管理员会花大量的时候思考这些事情,如何更有效率地工作,在异常成为问题前如何定位,更聪明地工作,做其它事情的同时会考虑如何完成这些事情等等。
|
||||
|
||||
例如,除了撰写本文之外,我现在正在想一个项目,我打算在从亚马逊和本地计算机商店采购的新部件到达时才开始。我有一台不太关键的计算机上的主板坏了,最近它的崩溃更频率。但我的一台非常老的小服务器并没有出现故障,它负责处理我的电子邮件和外部网站,以及为我的网络的其余部分提供 DHCP 和 DNS 服务,但需要解决由于各种外部攻击而导致的间歇性过载。
|
||||
|
||||
我一开始想,我只要替换故障设备的主板及其直接部件:内存、CPU,可能还有电源。但是在考虑了一段时间之后,我决定将新部件放到服务器中,并将旧的(但仍然可用的)部件从服务器移到故障设备中。可以这样做的,只需一、两个小时就可以从服务器上移除旧部件并安装新的。然后我就可以花时间更换出故障的电脑里的部件了。太好了,所以我开始在脑海中列出要完成的任务。
|
||||
|
||||
然而,当我查看这个任务列表时,我意识到服务器中唯一不能替换的部件是机箱和硬盘驱动器,这两台计算机的机箱几乎完全相同。在有了这个小小的发现之后,我开始考虑用新的部件替换出了故障的计算机的部件,并将之作为我的服务器。经过一些测试之后,我只需从当前的服务器移除硬盘,并将它安装到用了新组件的机箱中,改下网络配置项,再更改 KVM 交换机端口上的主机名,并更改机箱上的主机名标签,就可以了。这将大大减少服务器停机时间,大大减少我的压力。此外,如果出现故障,我可以简单地将硬盘移回原来的服务器,直到我可以用新服务器解决问题为止。
|
||||
|
||||
所以,现在我在脑海中已经创建了一个完成这项工作我所需要做的任务清单。而且,我希望你能仔细观察,当我脑子里想着这一切的时候,我的手指从来没有碰过键盘。我新的心理行动计划风险很低,与我最初的计划相比,涉及的服务器停机时间要少得多。
|
||||
|
||||
当我在 IBM 工作的时候,我经常看到很多语言中都有写着“**思考**”的标语。思考可以节省时间和压力,是懒散的系统管理员的主要标志。
|
||||
|
||||
#### 做预防性维护
|
||||
|
||||
在 1970 年代中期,我被 IBM 聘为客户工程师,我的领地由相当多的[穿孔卡片设备][2]组成。这也就是说,它们是处理打孔卡的重型机械设备,其中一些可以追溯到 20 世纪 30 年代。因为这些机器主要是机械的,所以它们的部件经常磨损或失调。我的部分工作是在它们损坏时修复它们。我工作的主要部分,也是最重要的部分,是首先要防止它们损坏。预防性维护的目的是在磨损部件损坏之前进行更换,并对还在运行的部件进行润滑和调整,以确保它们工作正常。
|
||||
|
||||
正如我在《系统管理员的 Linux 哲学》中所言:
|
||||
|
||||
>“我在 IBM 的经理们明白这只是冰山一角;他们和我都知道,我的工作是让顾客满意。虽然这通常意味着修复损坏的硬件,但也意味着减少硬件损坏的次数。这对客户来说是好事,因为他们的机器在工作时工作效率更高。这对我有好处,因为我从那些快乐的客户那里接到的电话要少得多。我也睡了更多的觉,因为这样做的结果是更少的非工作时间的紧急电话。我是个懒惰的(客户工程师)。通过提前做额外的工作,从长远来看,我需要做的工作要少得多。
|
||||
>
|
||||
>“这一原则已成为系统管理员的 Linux 哲学的功能原则之一。作为系统管理员,我们的时间最好用在最大限度地减少未来工作量的任务上。”
|
||||
|
||||
在 Linux 计算机中查找要解决的问题相当于项目管理。我检查系统日志,寻找以后可能会变得非常危险的问题的迹象。如果出现了一些小问题,或者我注意到我的工作站、服务器没有做出该有的响应,或者如果日志显示了一些不寻常的东西,所有这些都可以暗示出潜在的问题,而对于用户或半秃头老板来说,这些问题并没有产生明显的症状。
|
||||
|
||||
我经常检查 `/var/log/` 中的文件,特别是 `messages` 和 `security` 文件。我最常见的问题之一是许多脚本小子在我的防火墙系统上尝试各种类型的攻击。而且,不,我不依赖 ISP 提供的调制解调器/路由器中的所谓的防火墙。这些日志包含了大量关于企图攻击来源的信息,非常有价值。但是要扫描不同主机上的日志并将解决方案部署到位,需要做大量的工作,所以我转向自动化。
|
||||
|
||||
#### 自动化
|
||||
|
||||
我发现我的工作有很大一部分可以通过某种形式的自动化来完成。系统管理员的 Linux 哲学的原则之一是 “自动化一切”,这包括每天扫描日志文件等枯燥乏味的任务。
|
||||
|
||||
像是 [Logwatch][3] 这类的程序能够监控你的日志文件中的异常条目,并在异常条目发生时通知您。Logwatch 通常作为 cron 任务每天运行一次,并向本地主机上的 root 用户发送电子邮件。你可以从命令行运行 Logwatch,并立即在显示器上查看结果。现在我只需要每天查看 Logwatch 的电子邮件通知。
|
||||
|
||||
但现实是,仅仅收到通知是不够的,因为我们不能坐以待毙。有时需要立即作出反应。我喜欢的另一个程序是——它能为我做所有事(看,这就是懒惰的管理员)——它就是 [Fail2ban][4]。Fail2Ban 会扫描指定的日志文件,查找各种类型的黑客攻击和入侵尝试,如果它发现某个 IP 地址在持续做特定类型的活动,它会向防火墙添加一个条目,在指定的时间内阻止来自该 IP 地址的任何进一步的黑客尝试。默认值通常在 10 分钟左右,但我喜欢为大多数类型的攻击指定为 12 或 24 小时。每种类型的黑客攻击都是单独配置的,例如尝试通过 SSH 登录和那些 Web 服务器的攻击。
|
||||
|
||||
#### 写脚本
|
||||
|
||||
自动化是这种哲学的关键组成部分之一。一切可以自动化的东西都应该自动化的,其余的尽可能地自动化。所以,我也写了很多脚本来解决问题,也就是说我编写了脚本来完成我的大部分工作。
|
||||
|
||||
我的脚本帮我节省了大量时间,因为它们包含执行特定任务的命令,这大大减少了我需要输入的数量。例如,我经常重新启动我的电子邮件服务器和垃圾邮件过滤软件(当修改 SpamAssassin 的 `local.cf` 配置文件时,就需要重启)。必须按特定顺序停止并重新启动这些服务。因此,我用几个命令编写了一个简短的脚本,并将其存储在可访问的 `/usr/local/bin` 中。现在,不用键入几个命令并等待每个命令都完成,然后再键入下一个命令,更不用记住正确的命令顺序和每个命令的正确语法,我输入一个三个字符的命令,其余的留给我的脚本来完成。
|
||||
|
||||
#### 简化键入
|
||||
|
||||
另一种成为懒惰的系统管理员的方法是减少我们需要键入的数量。而且,我的打字技巧真的很糟糕(也就是说,我一点也没有,顶多是几个笨拙的手指)。导致错误的一个可能原因是我糟糕的打字技巧,所以我会尽量少打字。
|
||||
|
||||
绝大多数 GNU 和 Linux 核心实用程序都有非常短的名称。然而,它们都是有意义的名字。诸如用于更改目录的 `cd` 、用于列出目录内容的 `ls` 和用于磁盘转储的 `dd` 等工具都一目了然。短名字意味着更少的打字和更少的产生错误机会。我认为短的名字通常更容易记住。
|
||||
|
||||
当我编写 shell 脚本时,我喜欢保持名称简短而意义(至少对我来说是),比如用于 rsync 备份的 `rsbu`(LCTT 译注,Rsync Backup 的简写)。但在某些情况下,我喜欢使用更长的名称,比如 `doUpdates` 来执行系统更新。在后一种情况下,更长一点的名字让脚本的目的更明显。这可以节省时间,因为很容易记住脚本的名称。
|
||||
|
||||
其他减少键入的方法包括命令行别名、历史命令调回和编辑。别名只是你在 Bash shell 键入命令时才做的替换。键入 `alias` 命令会看到默认配置的别名列表。例如,当你输入命令 `ls` 时,会被条目 `alias ls='ls –color=auto'` 替成较长的命令,因此你只需键入 2 个字符而不是 14 个字符即可获得带有颜色的文件列表。还可以使用 `alias` 命令添加你自己定义的别名。
|
||||
|
||||
历史命令调回允许你使用键盘的向上和向下箭头键滚动浏览命令历史记录。如果需要再次使用相同的命令,只需在找到所需的命令时按回车键即可。如果在找到命令后需要更改该命令,则可以使用标准命令行编辑功能进行更改。
|
||||
|
||||
### 结束语
|
||||
|
||||
一名懒惰的系统管理员实际上也有很多的工作。但我们是聪明地工作,而不是刻苦工作。早在一堆小问题汇聚成大问题之前,我们就花时间探索我们负责的主机,并处理好所有的小问题。我们花了很多时间思考解决问题的最佳方法,我们也花了很多时间来发现新的方法,让自己更聪明地工作,成为懒惰的系统管理员。
|
||||
|
||||
除了这里描述的少数方法外,还有许多其他的方式可以成为懒惰的系统管理员。我相信你也有一些自己的方式;请在评论中和我们分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/7/how-be-lazy-sysadmin
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[zgj1024](https://github.com/zgj1024)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dboth
|
||||
[1]:https://www.apress.com/us/book/9781484237298
|
||||
[2]:https://en.wikipedia.org/wiki/Unit_record_equipment
|
||||
[3]:https://www.techrepublic.com/article/how-to-install-and-use-logwatch-on-linux/
|
||||
[4]:https://www.fail2ban.org/wiki/index.php/Main_Page
|
||||
@@ -0,0 +1,137 @@
|
||||
使用 PyHamcrest 执行健壮的单元测试
|
||||
======
|
||||
> 使用此框架编写断言,提高开发测试的准确性。
|
||||
|
||||

|
||||
|
||||
在[测试金字塔][1]的底部是单元测试。单元测试每次只测试一个代码单元,通常是一个函数或方法。
|
||||
|
||||
通常,设计单个单元测试是为了测试通过一个函数或特定分支的特定执行流程,这使得将失败的单元测试和导致失败的 bug 对应起来变得容易。
|
||||
|
||||
理想情况下,单元测试很少使用或不使用外部资源,从而隔离它们并使它们更快。
|
||||
|
||||
单元测试套件通过在开发过程的早期发现问题来帮助维护高质量的产品。有效的单元测试可以在代码离开开发人员机器之前捕获 bug,或者至少可以在特定分支上的持续集成环境中捕获 bug。这标志着好的和坏的单元测试之间的区别:*好的*测试通过尽早捕获 bug 并使测试更快来提高开发人员的生产力。*坏的*测试降低了开发人员的工作效率。
|
||||
|
||||
当测试*附带的特性*时,生产率通常会降低。当代码更改时测试会失败,即使它仍然是正确的。发生这种情况是因为输出的不同,但在某种程度上是因为它不是<ruby>函数契约<rt>function's contract</rt></ruby>的一部分。
|
||||
|
||||
因此,一个好的单元测试可以帮助执行函数所提交的契约。
|
||||
|
||||
如果单元测试中断,那意味着该契约被违反了,应该(通过更改文档和测试)明确修改,或者(通过修复代码并保持测试不变)来修复。
|
||||
|
||||
虽然将测试限制为只执行公共契约是一项需要学习的复杂技能,但有一些工具可以提供帮助。
|
||||
|
||||
其中一个工具是 [Hamcrest][2],这是一个用于编写断言的框架。最初是为基于 Java 的单元测试而发明的,但它现在支持多种语言,包括 [Python][3]。
|
||||
|
||||
Hamcrest 旨在使测试断言更容易编写和更精确。
|
||||
|
||||
```
|
||||
def add(a, b):
|
||||
return a + b
|
||||
|
||||
from hamcrest import assert_that, equal_to
|
||||
|
||||
def test_add():
|
||||
assert_that(add(2, 2), equal_to(4))
|
||||
```
|
||||
|
||||
这是一个用于简单函数的断言。如果我们想要断言更复杂的函数怎么办?
|
||||
|
||||
```
|
||||
def test_set_removal():
|
||||
my_set = {1, 2, 3, 4}
|
||||
my_set.remove(3)
|
||||
assert_that(my_set, contains_inanyorder([1, 2, 4]))
|
||||
assert_that(my_set, is_not(has_item(3)))
|
||||
```
|
||||
|
||||
注意,我们可以简单地断言其结果是任何顺序的 `1`、`2` 和 `4`,因为集合不保证顺序。
|
||||
|
||||
我们也可以很容易用 `is_not` 来否定断言。这有助于我们编写*精确的断言*,使我们能够把自己限制在执行函数的公共契约方面。
|
||||
|
||||
然而,有时候,内置的功能都不是我们*真正*需要的。在这些情况下,Hamcrest 允许我们编写自己的<ruby>匹配器<rt>matchers</rt></ruby>。
|
||||
|
||||
想象一下以下功能:
|
||||
|
||||
```
|
||||
def scale_one(a, b):
|
||||
scale = random.randint(0, 5)
|
||||
pick = random.choice([a,b])
|
||||
return scale * pick
|
||||
```
|
||||
|
||||
我们可以自信地断言其结果均匀地分配到至少一个输入。
|
||||
|
||||
匹配器继承自 `hamcrest.core.base_matcher.BaseMatcher`,重写两个方法:
|
||||
|
||||
```
|
||||
class DivisibleBy(hamcrest.core.base_matcher.BaseMatcher):
|
||||
def __init__(self, factor):
|
||||
self.factor = factor
|
||||
|
||||
def _matches(self, item):
|
||||
return (item % self.factor) == 0
|
||||
|
||||
def describe_to(self, description):
|
||||
description.append_text('number divisible by')
|
||||
description.append_text(repr(self.factor))
|
||||
```
|
||||
|
||||
编写高质量的 `describe_to` 方法很重要,因为这是测试失败时显示的消息的一部分。
|
||||
|
||||
```
|
||||
def divisible_by(num):
|
||||
return DivisibleBy(num)
|
||||
```
|
||||
|
||||
按照惯例,我们将匹配器包装在一个函数中。有时这给了我们进一步处理输入的机会,但在这种情况下,我们不需要进一步处理。
|
||||
|
||||
```
|
||||
def test_scale():
|
||||
result = scale_one(3, 7)
|
||||
assert_that(result,
|
||||
any_of(divisible_by(3),
|
||||
divisible_by(7)))
|
||||
```
|
||||
|
||||
请注意,我们将 `divisible_by` 匹配器与内置的 `any_of` 匹配器结合起来,以确保我们只测试函数提交的内容。
|
||||
|
||||
在编辑这篇文章时,我听到一个传言,取 “Hamcrest” 这个名字是因为它是 “matches” 字母组成的字谜。嗯...
|
||||
|
||||
```
|
||||
>>> assert_that("matches", contains_inanyorder(*"hamcrest")
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 43, in assert_that
|
||||
_assert_match(actual=arg1, matcher=arg2, reason=arg3)
|
||||
File "/home/moshez/src/devops-python/build/devops/lib/python3.6/site-packages/hamcrest/core/assert_that.py", line 57, in _assert_match
|
||||
raise AssertionError(description)
|
||||
AssertionError:
|
||||
Expected: a sequence over ['h', 'a', 'm', 'c', 'r', 'e', 's', 't'] in any order
|
||||
but: no item matches: 'r' in ['m', 'a', 't', 'c', 'h', 'e', 's']
|
||||
```
|
||||
|
||||
经过进一步的研究,我找到了传言的来源:它是 “matchers” 字母组成的字谜。
|
||||
|
||||
```
|
||||
>>> assert_that("matchers", contains_inanyorder(*"hamcrest"))
|
||||
>>>
|
||||
```
|
||||
|
||||
如果你还没有为你的 Python 代码编写单元测试,那么现在是开始的好时机。如果你正在为你的 Python 代码编写单元测试,那么使用 Hamcrest 将允许你使你的断言更加*精确*,既不会比你想要测试的多也不会少。这将在修改代码时减少误报,并减少修改工作代码的测试所花费的时间。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/8/robust-unit-tests-hamcrest
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/moshez
|
||||
[1]:https://martinfowler.com/bliki/TestPyramid.html
|
||||
[2]:http://hamcrest.org/
|
||||
[3]:https://www.python.org/
|
||||
@@ -0,0 +1,103 @@
|
||||
5 款开源的 Linux 策略模拟游戏
|
||||
======
|
||||
|
||||
> 用这些开源游戏来挑战你的战略技能,探索新世界。
|
||||
|
||||

|
||||
|
||||
长久以来,游戏都是 Linux 的软肋。近些年,Steam、GOG 等游戏发布平台上不少商业游戏都开始支持 Linux,这对于 Linux 的游戏生态来说是件好事,但是我们能在这些平台上玩到的游戏通常是不开源的商业作品。当然,这些游戏在一个开源的操作系统上运行,但对于一个开源提倡者来说这似乎还不够纯粹。
|
||||
|
||||
那么,我们能找到既自由开源又能给玩家带来完整游戏体验的优质游戏吗?当然!虽然绝大多数的开源游戏很难和 3A 商业游戏大作竞争,但仍然有不少各种类型的开源游戏,不仅内容有趣而且直接可以通过几大 Linux 发行版本库中直接安装。就算某个游戏在不在某个发行版本的库中,我们也可以在这个游戏项目的网站上找到直接的安装方法。
|
||||
|
||||
本篇文章将会介绍策略和模拟类游戏。我已经写了[街机游戏][1]、[桌面卡牌游戏][2]、[解谜游戏][3]、[竞速飞行游戏][4]以及[角色扮演游戏][5]。
|
||||
|
||||
### 开源版“文明”(Freeciv)
|
||||
|
||||

|
||||
|
||||
[Freeciv][6] 可以被视为是[文明系列][7]游戏的开源版本。游戏玩法和文明系列最早期的游戏十分类似,Freeciv 可以让玩家选择选用文明 1 或者文明 2 中的游戏规则设置。Freeciv 中包含了很多元素,例如建造城市、探索世界地图、发展科技以及和其他扩张中的文明竞争。胜利条件包括打败所有其他的文明或建立一个外星殖民地,如果在前两者都没有达成的话,在游戏时间期限前存活下来也可以算作胜利。这个游戏可以和其他玩家联机也可以和 AI 对战,不同的地图集可以改变游戏的外观。
|
||||
|
||||
安装 Freeciv,你只需要在终端下运行以下指令。
|
||||
|
||||
* Fedora 用户: `dnf install freeciv`
|
||||
* Debian/Ubuntu 用户:`apt install freeciv`
|
||||
|
||||
### MegaGlest
|
||||
|
||||

|
||||
|
||||
[MegaGlest][8] 是一个开源的实时战略游戏,类似暴雪公司制作的游戏[魔兽世界][9]和[星际争霸][10]。玩家控制不同派别的人员、建造新建筑、招募士兵、拓展领土并与敌人作战。在游戏比赛的最开始,玩家仅能建造最基础的建筑和招募最基础的士兵。为了建造更高级的建筑并招募级别更高的人员,玩家必须通过增加建筑和人员从而一路提高科技树、解锁更加高级的选项。当敌人进入国土领域之中,战斗单元将会迎战。但是最好的应对策略是,通过控制战斗单元直接操控每一场战斗。在管理新建筑的建立,新人员的招募的同时控制战斗局势听上去十分困难,但是这就是 RTS(实时战略游戏)游戏的精华所在。MegaGlest 这个游戏提供了大量的人员派别,玩家可以不断尝试这些不同的技巧。
|
||||
|
||||
安装 MegaGlest,你只需要在终端下运行以下指令:
|
||||
|
||||
* Fedora 用户: `dnf install megaglest`
|
||||
* Debian/Ubuntu 用户:`apt install megaglest`
|
||||
|
||||
### 开源版“运输大亨”(OpenTTD)
|
||||
|
||||

|
||||
|
||||
[OpenTTD][11](见我们的 [评测][12] )是一个开源实现的 [运输大亨][13] 。该游戏的目的在于创建一个交通运输网络并获得金钱,从而建立更加复杂的运输网络。这个运输网络包括了船只、巴士、火车、货车和飞机。默认的游戏时间在 1950 和 2050 之间,玩家的目标就是在规定时间内拿到最高的游戏分数。游戏的最终分数基于很多因素,例如货物运输的数量、玩家所拥有的汽车数量以及他们赚到的钱。
|
||||
|
||||
安装 OpenTTD,你只需要在终端运行以下指令:
|
||||
|
||||
* Fedora 用户: `dnf install openttd`
|
||||
* Debian/Ubuntu 用户 `apt install openttd`
|
||||
|
||||
### <ruby>韦诺之战<rt>The Battle for Wesnoth</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[韦诺之战][14] 是目前最完善的开源游戏之一。这个回合制游戏在一个奇幻的故事设定下。游戏在一个六角形网格中进行,各个单元可以互相操作进行战斗。每个类型的单元都有它独特的能力和弱点,因此玩家需要根据这些特点来设计不同的行动。韦诺之战中有很多不同的行动分支,每个行动分支都有它特别的故事线和目标。韦诺之战同时也有一个地图编辑器,感兴趣的玩家可以创作自己的地图以及行动分支。
|
||||
|
||||
安装韦诺之战,你只需要在终端运行以下指令:
|
||||
|
||||
* Fedora 用户: `dnf install wesnoth`
|
||||
* Debian/Ubuntu 用户: `apt install wesnoth`
|
||||
|
||||
### <ruby>UFO:外星入侵<rt>UFO: Alien Invasion</rt></ruby>
|
||||
|
||||

|
||||
|
||||
[UFO: Alien Invasion][15] 是一个开源策略游戏,基于 <ruby>[幽浮系列][20]<rt>X-COM</rt></ruby>。 有两个不同的游戏模式: geoscape 和 tactical。在 geoscape 模式下,玩家控制大局、管理基地、开发新技术以及掌控整体策略。 在 tactical 游戏模式下,玩家控制一群士兵并且以回合制的形式直接迎战外星侵略者。两个游戏模式提供了不同的游戏玩法,两者都需要相当复杂的策略和战术。
|
||||
|
||||
安装这个游戏,你只需要在终端下运行以下指令:
|
||||
|
||||
* Debian/Ubuntu 用户: `apt install ufoai`
|
||||
|
||||
遗憾的是,UFO: 外星入寝不支持 Fedora 发行版。
|
||||
|
||||
如果你知道除了这些以外的开源策略模拟游戏的话,欢迎在评论中分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/8/strategy-simulation-games-linux
|
||||
|
||||
作者:[Joshua Allen Holm][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[Scoutydren](https://github.com/Scoutydren)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/holmja
|
||||
[1]:https://linux.cn/article-10433-1.html
|
||||
[2]:https://opensource.com/article/18/3/card-board-games-linux
|
||||
[3]:https://opensource.com/article/18/6/puzzle-games-linux
|
||||
[4]:https://opensource.com/article/18/7/racing-flying-games-linux
|
||||
[5]:https://opensource.com/article/18/8/role-playing-games-linux
|
||||
[6]:http://www.freeciv.org/
|
||||
[7]:https://en.wikipedia.org/wiki/Civilization_(series)
|
||||
[8]:https://megaglest.org/
|
||||
[9]:https://en.wikipedia.org/wiki/Warcraft
|
||||
[10]:https://en.wikipedia.org/wiki/StarCraft
|
||||
[11]:https://www.openttd.org/
|
||||
[12]:https://opensource.com/life/15/7/linux-game-review-openttd
|
||||
[13]:https://en.wikipedia.org/wiki/Transport_Tycoon#Transport_Tycoon_Deluxe
|
||||
[14]:https://www.wesnoth.org/
|
||||
[15]:https://ufoai.org/
|
||||
[16]:https://opensource.com/downloads/cheat-sheets?intcmp=7016000000127cYAAQ
|
||||
[17]:https://opensource.com/alternatives?intcmp=7016000000127cYAAQ
|
||||
[18]:https://opensource.com/tags/linux?intcmp=7016000000127cYAAQ
|
||||
[19]:https://developers.redhat.com/cheat-sheets/advanced-linux-commands/?intcmp=7016000000127cYAAQ
|
||||
[20]:https://en.wikipedia.org/wiki/X-COM
|
||||
@@ -0,0 +1,79 @@
|
||||
|
||||
DevSecOps 提升安全性的五种方式
|
||||
======
|
||||
|
||||
> 安全必须进化以跟上当今的应用开发和部署方式。
|
||||
|
||||

|
||||
|
||||
对于我们是否需要扩展 DevOps 以确实提升安全性,我们一直都有争议。毕竟,我们认为,DevOps 一直是一系列的新实践的简写,使用新工具(通常是开源的)并且在这之上构建更多的协作文化。为什么 [DevBizOps][3] 不能更好地满足商业的需求?或者说 DevChatOps 强调的是更快更好的沟通?
|
||||
|
||||
然而,如 [John Willis][4] 在今年(LCTT 译注:此处是 2018 年)的早些时候写的关于他对 [DevSecOps][5] 术语的理解,“我希望,有一天我们能在任何地方都不再使用 DevSecOps 这个词,安全会是所有关于服务交付的讨论中理所应当的部分。在那一天到来前,在这一点上,我的一般性结论是,这个词只是三个新的特性而已。更重要的是,我们作为一个产业,在信息安全方面并没有做的很好,而这个名称切实地区分出了问题的状况。”
|
||||
|
||||
所以,为什么我们在[信息安全][6]方面做的不好,在 DevSecOps 的语境下安全做的好又是什么意思呢?
|
||||
|
||||
尽管(也可能是因为)庞大的复杂行业的单点产品解决了特定方面的问题,但我们可以说是从未做好过信息安全。我们仍然可以在这个时代把工作做得足够好,以此来防范威胁,这些威胁主要集中在一个范围内,网络的连接是受限的,而且大多数的用户都是公司的员工,使用的是公司提供的设备。
|
||||
|
||||
这些年来,这些情况并没有能准确地描述出大多数组织的真实现状。但在现在这个时代,不止引入了 DevSecOps,也同时引入了新的应用架构模型、开发实践,和越来越多的安全威胁,这些一起定义了一个需要更快迭代的新常态。与其说 DevSecOps 孤立地改变了安全,不如说信息安全公司在 2018 年需要新的方法。
|
||||
|
||||
请仔细思考下面这五个领域。
|
||||
|
||||
### 自动化
|
||||
|
||||
大量的自动化通常是 DevOps 的标志,这部分是关于速度的,如果你要快速变化(并且不会造成破坏),你需要有可重复的过程,而且这个过程不需要太多的人工干预。实际上,自动化是 DevOps 最好的切入点之一,甚至是在仍然主要使用老式的<ruby>独石应用<rt>monolithic app</rt></ruby>的组织里也是如此。使用像 Ansible 这样易于使用的工具来自动化地处理相关的配置或者是测试,这是快速开始 DevOps 之路的常用方法。
|
||||
|
||||
DevSecOps 也不例外,在今天,安全已经变成了一个持续性的过程,而不是在应用的生命周期里进行不定期的检查,甚至是每周、每月的检查。当漏洞被厂商发现并修复的时候,这些修复能被快速地应用是很重要的,这样对这些漏洞的利用程序很快就会被淘汰。
|
||||
|
||||
### “左移”
|
||||
|
||||
在开发流程结束时,传统的安全通常被视作一个守门人。检查所有的部分确保没有问题,然后这个应用程序就可以投入生产了。否则,就要再来一次。安全小组以说“不”而闻名。
|
||||
|
||||
因此,我们想的是,为什么不把安全这个部分提到前面呢(在一个典型的从左到右的开发流程图的“左边”)?安全团队仍然可以说“不”,但在开发的早期进行重构的影响要远远小于开发已经完成并且准备上线时进行重构的影响。
|
||||
|
||||
不过,我不喜欢“左移”这个词,这意味着安全仍然是一个只不过提前进行的一次性工作。在应用程序的整个生命周期里,从供应链到开发,再到测试,直到上线部署,安全都需要进行大量的自动化处理。
|
||||
|
||||
### 管理依赖
|
||||
|
||||
我们在现代应用程序开发过程中看到的一个最大的改变,就是你通常不需要去编写这个程序的大部分代码。使用开源的函数库和框架就是一个明显的例子。而且你也可以从公共的云服务商或其他来源那里获得额外的服务。在许多情况下,这些额外的代码和服务比你给自己写的要好得多。
|
||||
|
||||
因此,DevSecOps 需要你把重点放在你的[软件供应链][8]上,你是从可信的来源那里获取你的软件的吗?这些软件是最新的吗?它们已经集成到了你为自己的代码所使用的安全流程中了吗?对于这些你能使用的代码和 API 你有哪些策略?你为自己的产品代码使用的组件是否有可用的商业支持?
|
||||
|
||||
没有一套标准答案可以应对所有的情况。对于概念验证和大规模的生产,它们可能会有所不同。但是,正如制造业长期存在的情况(DevSecOps 和制造业的发展方面有许多相似之处),供应链的可信是至关重要的。
|
||||
|
||||
### 可见性
|
||||
|
||||
关于贯穿应用程序整个生命周期里所有阶段的自动化的需求,我已经谈过很多了。这里假设我们能看见每个阶段里发生的情况。
|
||||
|
||||
有效的 DevSecOps 需要有效的检测,以便于自动化程序知道要做什么。这个检测分了很多类别。一些长期的和高级别的指标能帮助我们了解整个 DevSecOps 流程是否工作良好。严重威胁级别的警报需要立刻有人进行处理(安全扫描系统已经关闭!)。有一些警报,比如扫描失败,需要进行修复。我们记录了许多参数的志以便事后进行分析(随着时间的推移,哪些发生了改变?导致失败的原因是什么?)。
|
||||
|
||||
### 分散服务 vs 一体化解决方案
|
||||
|
||||
虽然 DevSecOps 实践可以应用于多种类型的应用架构,但它们对小型且松散耦合的组件最有效,这些组件可以进行更新和复用,而且不会在应用程序的其他地方进行强制更改。在纯净版的形式里,这些组件可以是微服务或者函数,但是这个一般性原则适用于通过网络进行通信的松散耦合服务的任何地方。
|
||||
|
||||
这种方法确实带来了一些新的安全挑战,组件之间的交互可能会很复杂,总的攻击面会更大,因为现在应用程序通过网络有了更多的切入点。
|
||||
|
||||
另一方面,这种类型的架构还意味着自动化的安全和监视可以更加精细地查看应用程序的组件,因为它们不再深埋在一个独石应用程序之中。
|
||||
|
||||
不要过多地关注 DevSecOps 这个术语,但要提醒一下,安全正在不断地演变,因为我们编写和部署程序的方式也在不断地演变。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/9/devsecops-changes-security
|
||||
|
||||
作者:[Gordon Haff][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[hopefully2333](https://github.com/hopefully2333)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ghaff
|
||||
[1]: https://opensource.com/resources/devops
|
||||
[2]: https://opensource.com/tags/devops
|
||||
[3]: https://opensource.com/article/18/5/steps-apply-devops-culture-beyond-it
|
||||
[4]: https://www.devsecopsdays.com/articles/its-just-a-name
|
||||
[5]: https://opensource.com/article/18/4/devsecops
|
||||
[6]: https://opensource.com/article/18/6/where-cycle-security-devops
|
||||
[7]: https://opensource.com/tags/ansible
|
||||
[8]: https://opensource.com/article/17/1/be-open-source-supply-chain
|
||||
[9]: https://opensource.com/tags/microservices
|
||||
@@ -0,0 +1,128 @@
|
||||
dbxfs:在 Linux 中本地挂载 Dropbox 文件夹
|
||||
======
|
||||
|
||||

|
||||
|
||||
不久前,我们总结了所有 [在本地挂载 Google Drive][1] 作为虚拟文件系统,并从 Linux 系统访问存储在 Google Drive 中的文件的方法。今天,我们将学习使用 `dbxfs` 将 Dropbox 文件夹挂载到本地文件系统中。`dbxfs` 用于在类 Unix 操作系统中本地挂载 Dropbox 文件夹作为虚拟文件系统。虽然在 Linux 中很容易[安装 Dropbox 客户端][2],但这种方法与官方方法略有不同。它是一个命令行 dropbox 客户端,且无需磁盘空间即可访问。`dbxfs` 是自由开源的,并且是用 Python 3.5+ 编写的。
|
||||
|
||||
### 安装 dbxfs
|
||||
|
||||
`dbxfs` 官方支持 Linux 和 Mac OS。但是,它应该适用于任何提供 **FUSE 兼容库**或能够挂载 SMB 共享的 POSIX 系统。由于它是用 Python 3.5 编写的,因此可以使用 pip3 包管理器进行安装。如果尚未安装 pip,请参阅以下指南。
|
||||
|
||||
- [如何使用 pip 管理 Python 包][13]
|
||||
|
||||
并且也要安装 FUSE 库。
|
||||
|
||||
在基于 Debian 的系统上,运行以下命令以安装 FUSE:
|
||||
|
||||
```
|
||||
$ sudo apt install libfuse2
|
||||
```
|
||||
|
||||
在 Fedora 上:
|
||||
|
||||
```
|
||||
$ sudo dnf install fuse
|
||||
```
|
||||
|
||||
安装完所有必需的依赖项后,运行以下命令以安装 `dbxfs`:
|
||||
|
||||
```
|
||||
$ pip3 install dbxfs
|
||||
```
|
||||
|
||||
### 在本地挂载 Dropbox 文件夹
|
||||
|
||||
创建一个挂载点以将 Dropbox 文件夹挂载到本地文件系统中。
|
||||
|
||||
```
|
||||
$ mkdir ~/mydropbox
|
||||
```
|
||||
|
||||
然后,使用 `dbxfs` 在本地挂载 dropbox 文件夹,如下所示:
|
||||
|
||||
```
|
||||
$ dbxfs ~/mydropbox
|
||||
```
|
||||
|
||||
你将被要求生成一个访问令牌:
|
||||
|
||||

|
||||
|
||||
要生成访问令牌,只需在 Web 浏览器中输入上面输出的 URL,然后单击 **允许** 以授权 Dropbox 访问。你需要登录 Dropbox 帐户才能完成授权过程。
|
||||
|
||||
下一个页面将生成新的授权码。复制代码并返回终端将其粘贴到 cli-dbxfs 提示符中以完成该过程。
|
||||
|
||||
然后,系统会要求你保存凭据以供将来访问。根据你是要保存还是拒绝,输入 `Y` 或 `N`。然后,你需要为新的访问令牌输入两次密码。
|
||||
|
||||
最后,输入 `Y` 接受 `/home/username/mydropbox` 作为默认挂载点。如果你要设置不同的路径,输入 `N` 并输入你选择的位置。
|
||||
|
||||
![Generate access token 2][4]
|
||||
|
||||
完成了!从现在开始,你可以看到你的 Dropbox 文件夹已挂载到本地文件系统中。
|
||||
|
||||

|
||||
|
||||
### 更改访问令牌存储路径
|
||||
|
||||
默认情况下,`dbxfs` 会将 Dropbox 访问令牌存储在系统密钥环或加密文件中。但是,你可能希望将其存储在 gpg 加密文件或其他地方。如果是这样,请在 [Dropbox 开发者应用控制台][5]上创建个人应用来获取访问令牌。
|
||||
|
||||

|
||||
|
||||
创建应用后,单击下一步中的**生成**按钮。此令牌可用于通过 API 访问你的 Dropbox 帐户。不要与任何人共享你的访问令牌。
|
||||
|
||||

|
||||
|
||||
创建访问令牌后,使用任何你选择的加密工具对其进行加密,例如 [Cryptomater][6]、[Cryptkeeper][7]、[CryptGo][8]、[Cryptr][9]、[Tomb][10]、[Toplip][11] 和 [**GnuPG][12] 等,并在你喜欢的位置保存。
|
||||
|
||||
接下来编辑 dbxfs 配置文件并添加以下行:
|
||||
|
||||
```
|
||||
"access_token_command": ["gpg", "--decrypt", "/path/to/access/token/file.gpg"]
|
||||
```
|
||||
|
||||
你可以通过运行以下命令找到 dbxfs 配置文件:
|
||||
|
||||
```
|
||||
$ dbxfs --print-default-config-file
|
||||
```
|
||||
|
||||
有关更多详细信息,请参阅 dbxfs 帮助:
|
||||
|
||||
```
|
||||
$ dbxfs -h
|
||||
```
|
||||
|
||||
如你所见,使用 `dbxfs` 在你的文件系统中本地挂载 Dropfox 文件夹并不复杂。经过测试,`dbxfs` 如常工作。如果你有兴趣了解它是如何工作的,请尝试一下,并在下面的评论栏告诉我们你的体验。
|
||||
|
||||
就是这些了。希望这篇文章有用。还有更多好东西。敬请期待!
|
||||
|
||||
干杯!
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/dbxfs-mount-dropbox-folder-locally-as-virtual-file-system-in-linux/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[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/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[1]: https://www.ostechnix.com/how-to-mount-google-drive-locally-as-virtual-file-system-in-linux/
|
||||
[2]: https://www.ostechnix.com/install-dropbox-in-ubuntu-18-04-lts-desktop/
|
||||
[3]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[4]: http://www.ostechnix.com/wp-content/uploads/2018/10/Generate-access-token-2.png
|
||||
[5]: https://dropbox.com/developers/apps
|
||||
[6]: https://www.ostechnix.com/cryptomator-open-source-client-side-encryption-tool-cloud/
|
||||
[7]: https://www.ostechnix.com/how-to-encrypt-your-personal-foldersdirectories-in-linux-mint-ubuntu-distros/
|
||||
[8]: https://www.ostechnix.com/cryptogo-easy-way-encrypt-password-protect-files/
|
||||
[9]: https://www.ostechnix.com/cryptr-simple-cli-utility-encrypt-decrypt-files/
|
||||
[10]: https://www.ostechnix.com/tomb-file-encryption-tool-protect-secret-files-linux/
|
||||
[11]: https://www.ostechnix.com/toplip-strong-file-encryption-decryption-cli-utility/
|
||||
[12]: https://www.ostechnix.com/an-easy-way-to-encrypt-and-decrypt-files-from-commandline-in-linux/
|
||||
[13]:https://www.ostechnix.com/manage-python-packages-using-pip/
|
||||
94
published/201901/20181016 Final JOS project.md
Normal file
94
published/201901/20181016 Final JOS project.md
Normal file
@@ -0,0 +1,94 @@
|
||||
Caffeinated 6.828:实验 7:最终的 JOS 项目
|
||||
======
|
||||
|
||||
### 简介
|
||||
|
||||
对于最后的项目,你有两个选择:
|
||||
|
||||
* 继续使用你自己的 JOS 内核并做 [实验 6][1],包括实验 6 中的一个挑战问题。(你可以随意地、以任何有趣的方式去扩展实验 6 或者 JOS 的任何部分,当然了,这不是课程规定的。)
|
||||
* 在一个、二个或三个人组成的团队中,你选择去做一个涉及了你的 JOS 的项目。这个项目必须是涉及到与实验 6 相同或更大的领域(如果你是团队中的一员)。
|
||||
|
||||
目标是为了获得乐趣或探索更高级的 O/S 的话题;你不需要做最新的研究。
|
||||
|
||||
如果你做了你自己的项目,我们将根据你的工作量有多少、你的设计有多优雅、你的解释有多高明、以及你的解决方案多么有趣或多有创意来为你打分。我们知道时间有限,因此也不期望你能在本学期结束之前重写 Linux。要确保你的目标是合理的;合理地设定一个绝对可以实现的最小目标(即:控制你的实验 6 的规模),如果进展顺利,可以设定一个更大的目标。
|
||||
|
||||
如果你做了实验 6,我们将根据你是否通过了测试和挑战练习来为你打分。
|
||||
|
||||
### 交付期限
|
||||
|
||||
> 11 月 3 日:Piazza 讨论和 1、2、或 3 年级组选择(根据你的最终选择来定)。使用在 Piazza 上的 lab7 标记/目录。在 Piazza 上的文章评论区与其它人计论想法。使用这些文章帮你去找到有类似想法的其它学生一起组建一个小组。课程的教学人员将在 Piazza 上为你的项目想法给出反馈;如果你想得到更详细的反馈,可以与我们单独讨论。
|
||||
|
||||
.
|
||||
|
||||
> 11 月 9 日:在 [提交网站][19] 上提交一个提议,只需要一到两个段落就可以。提议要包括你的小组成员列表、你的计划、以及明确的设计和实现打算。(如果你做实验 6,就不用做这个了)
|
||||
|
||||
.
|
||||
|
||||
> 12 月 7 日:和你的简短报告一起提交源代码。将你的报告放在与名为 “README.pdf” 的文件相同的目录下。由于你只是这个实验任务小组中的一员,你可能需要去使用 git 在小组成员之间共享你的项目代码。因此你需要去决定哪些源代码将作为你的小组项目的共享起始点。一定要为你的最终项目去创建一个分支,并且命名为 `lab7`。(如果你做了实验 6,就按实验 6 的提交要求做即可。)
|
||||
|
||||
.
|
||||
|
||||
> 12 月 11 日这一周:简短的课堂演示。为你的 JOS 项目准备一个简短的课堂演示。为了你的项目演示,我们将提供一个投影仪。根据小组数量和每个小组选择的项目类型,我们可能会限制总的演讲数,并且有些小组可能最终没有机会上台演示。
|
||||
|
||||
.
|
||||
|
||||
> 12 月 11 日这一周:助教们验收。向助教演示你的项目,因此我们可能会提问一些问题,去了解你所做的一些细节。
|
||||
|
||||
### 项目想法
|
||||
|
||||
如果你不做实验 6,下面是一个启迪你的想法列表。但是,你应该大胆地去实现你自己的想法。其中一些想法只是一个开端,并且本身不在实验 6 的领域内,并且其它的可能是在更大的领域中。
|
||||
|
||||
* 使用 [x86 虚拟机支持][2] 去构建一个能够运行多个访客系统(比如,多个 JOS 实例)的虚拟机监视器。
|
||||
* 使用 Intel SGX 硬件保护机制做一些有用的事情。[这是使用 Intel SGX 的最新的论文][3]。
|
||||
* 让 JOS 文件系统支持写入、文件创建、为持久性使用日志、等等。或许你可以从 Linux EXT3 上找到一些启示。
|
||||
* 从 [软更新][4]、[WAFL][5]、ZFS、或其它较高级的文件系统上找到一些使用文件系统的想法。
|
||||
* 给一个文件系统添加快照功能,以便于用户能够查看过去的多个时间点上的文件系统。为了降低空间使用量,你或许要使用一些写时复制技术。
|
||||
* 使用分页去提供实时共享的内存,来构建一个 [分布式的共享内存][6](DSM)系统,以便于你在一个机器集群上运行多线程的共享内存的并行程序。当一个线程尝试去访问位于另外一个机器上的页时,页故障将给 DSM 系统提供一个机会,让它基于网络去从当前存储这个页的任意一台机器上获取这个页。
|
||||
* 允许进程在机器之间基于网络进行迁移。你将需要做一些关于一个进程状态的多个片段方面的事情,但是由于在 JOS 中许多状态是在用户空间中,它或许从 Linux 上的进程迁移要容易一些。
|
||||
* 在 JOS 中实现 [分页][7] 到磁盘,这样那个进程使用的内存就可以大于真实的内存。使用交换空间去扩展你的内存。
|
||||
* 为 JOS 实现文件的 [mmap()][8]。
|
||||
* 使用 [xfi][9] 将一个进程的代码沙箱化。
|
||||
* 支持 x86 的 [2MB 或 4MB 的页大小][10]。
|
||||
* 修改 JOS 让内核支持进程内的线程。从查看 [课堂上的 uthread 任务][11] 去开始。实现调度器触发将是实现这个项目的一种方式。
|
||||
* 在 JOS 的内核中或文件系统中(实现多线程之后),使用细粒度锁或无锁并发。Linux 内核使用 [读复制更新][12] 去执行无需上锁的读取操作。通过在 JOS 中实现它来探索 RCU,并使用它去支持无锁读取的名称缓存。
|
||||
* 实现 [外内核论文][13] 中的想法。例如包过滤器。
|
||||
* 使 JOS 拥有软实时行为。用它来辨识一些应用程序时非常有用。
|
||||
* 使 JOS 运行在 64 位 CPU 上。这包括重设计虚拟内存让它使用 4 级页表。有关这方面的文档,请查看 [参考页][14]。
|
||||
* 移植 JOS 到一个不同的微处理器。这个 [osdev wiki][15] 或许对你有帮助。
|
||||
* 为 JOS 系统增加一个“窗口”系统,包括图形驱动和鼠标。有关这方面的文档,请查看 [参考页][16]。[sqrt(x)][17] 就是一个 JOS “窗口” 系统的示例。
|
||||
* 在 JOS 中实现 [dune][18],以提供特权硬件指令给用户空间应用程序。
|
||||
* 写一个用户级调试器,添加类似跟踪的功能;硬件寄存器概要(即:Oprofile);调用跟踪等等。
|
||||
* 为(静态的)Linux 可运行程序做一个二进制仿真。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://pdos.csail.mit.edu/6.828/2018/labs/lab7/
|
||||
|
||||
作者:[csail.mit][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://pdos.csail.mit.edu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://pdos.csail.mit.edu/6.828/2018/labs/lab6/index.html
|
||||
[2]: http://www.intel.com/technology/itj/2006/v10i3/1-hardware/3-software.htm
|
||||
[3]: https://www.usenix.org/system/files/conference/osdi14/osdi14-paper-baumann.pdf
|
||||
[4]: http://www.ece.cmu.edu/~ganger/papers/osdi94.pdf
|
||||
[5]: https://ng.gnunet.org/sites/default/files/10.1.1.40.3691.pdf
|
||||
[6]: http://www.cdf.toronto.edu/~csc469h/fall/handouts/nitzberg91.pdf
|
||||
[7]: http://en.wikipedia.org/wiki/Paging
|
||||
[8]: http://en.wikipedia.org/wiki/Mmap
|
||||
[9]: http://static.usenix.org/event/osdi06/tech/erlingsson.html
|
||||
[10]: http://en.wikipedia.org/wiki/Page_(computer_memory)
|
||||
[11]: http://pdos.csail.mit.edu/6.828/2018/homework/xv6-uthread.html
|
||||
[12]: http://en.wikipedia.org/wiki/Read-copy-update
|
||||
[13]: http://pdos.csail.mit.edu/6.828/2018/readings/engler95exokernel.pdf
|
||||
[14]: http://pdos.csail.mit.edu/6.828/2018/reference.html
|
||||
[15]: http://wiki.osdev.org/Main_Page
|
||||
[16]: http://pdos.csail.mit.edu/6.828/2018/reference.html
|
||||
[17]: http://web.mit.edu/amdragon/www/pubs/sqrtx-6.828.html
|
||||
[18]: https://www.usenix.org/system/files/conference/osdi12/osdi12-final-117.pdf
|
||||
[19]: https://6828.scripts.mit.edu/2018/handin.py/
|
||||
465
published/201901/20181016 Lab 6- Network Driver.md
Normal file
465
published/201901/20181016 Lab 6- Network Driver.md
Normal file
@@ -0,0 +1,465 @@
|
||||
Caffeinated 6.828:实验 6:网络驱动程序
|
||||
======
|
||||
|
||||
### 简介
|
||||
|
||||
这个实验是默认你能够自己完成的最终项目。
|
||||
|
||||
现在你已经有了一个文件系统,一个典型的操作系统都应该有一个网络栈。在本实验中,你将继续为一个网卡去写一个驱动程序。这个网卡基于 Intel 82540EM 芯片,也就是众所周知的 E1000 芯片。
|
||||
|
||||
#### 预备知识
|
||||
|
||||
使用 Git 去提交你的实验 5 的源代码(如果还没有提交的话),获取课程仓库的最新版本,然后创建一个名为 `lab6` 的本地分支,它跟踪我们的远程分支 `origin/lab6`:
|
||||
|
||||
```c
|
||||
athena% cd ~/6.828/lab
|
||||
athena% add git
|
||||
athena% git commit -am 'my solution to lab5'
|
||||
nothing to commit (working directory clean)
|
||||
athena% git pull
|
||||
Already up-to-date.
|
||||
athena% git checkout -b lab6 origin/lab6
|
||||
Branch lab6 set up to track remote branch refs/remotes/origin/lab6.
|
||||
Switched to a new branch "lab6"
|
||||
athena% git merge lab5
|
||||
Merge made by recursive.
|
||||
fs/fs.c | 42 +++++++++++++++++++
|
||||
1 files changed, 42 insertions(+), 0 deletions(-)
|
||||
athena%
|
||||
```
|
||||
|
||||
然后,仅有网卡驱动程序并不能够让你的操作系统接入互联网。在新的实验 6 的代码中,我们为你提供了网络栈和一个网络服务器。与以前的实验一样,使用 git 去拉取这个实验的代码,合并到你自己的代码中,并去浏览新的 `net/` 目录中的内容,以及在 `kern/` 中的新文件。
|
||||
|
||||
除了写这个驱动程序以外,你还需要去创建一个访问你的驱动程序的系统调用。你将要去实现那些在网络服务器中缺失的代码,以便于在网络栈和你的驱动程序之间传输包。你还需要通过完成一个 web 服务器来将所有的东西连接到一起。你的新 web 服务器还需要你的文件系统来提供所需要的文件。
|
||||
|
||||
大部分的内核设备驱动程序代码都需要你自己去从头开始编写。本实验提供的指导比起前面的实验要少一些:没有框架文件、没有现成的系统调用接口、并且很多设计都由你自己决定。因此,我们建议你在开始任何单独练习之前,阅读全部的编写任务。许多学生都反应这个实验比前面的实验都难,因此请根据你的实际情况计划你的时间。
|
||||
|
||||
#### 实验要求
|
||||
|
||||
与以前一样,你需要做实验中全部的常规练习和至少一个挑战问题。在实验中写出你的详细答案,并将挑战问题的方案描述写入到 `answers-lab6.txt` 文件中。
|
||||
|
||||
### QEMU 的虚拟网络
|
||||
|
||||
我们将使用 QEMU 的用户模式网络栈,因为它不需要以管理员权限运行。QEMU 的文档的[这里][1]有更多关于用户网络的内容。我们更新后的 makefile 启用了 QEMU 的用户模式网络栈和虚拟的 E1000 网卡。
|
||||
|
||||
缺省情况下,QEMU 提供一个运行在 IP 地址 10.2.2.2 上的虚拟路由器,它给 JOS 分配的 IP 地址是 10.0.2.15。为了简单起见,我们在 `net/ns.h` 中将这些缺省值硬编码到网络服务器上。
|
||||
|
||||
虽然 QEMU 的虚拟网络允许 JOS 随意连接互联网,但 JOS 的 10.0.2.15 的地址并不能在 QEMU 中的虚拟网络之外使用(也就是说,QEMU 还得做一个 NAT),因此我们并不能直接连接到 JOS 上运行的服务器,即便是从运行 QEMU 的主机上连接也不行。为解决这个问题,我们配置 QEMU 在主机的某些端口上运行一个服务器,这个服务器简单地连接到 JOS 中的一些端口上,并在你的真实主机和虚拟网络之间传递数据。
|
||||
|
||||
你将在端口 7(echo)和端口 80(http)上运行 JOS,为避免在共享的 Athena 机器上发生冲突,makefile 将为这些端口基于你的用户 ID 来生成转发端口。你可以运行 `make which-ports` 去找出是哪个 QEMU 端口转发到你的开发主机上。为方便起见,makefile 也提供 `make nc-7` 和 `make nc-80`,它允许你在终端上直接与运行这些端口的服务器去交互。(这些目标仅能连接到一个运行中的 QEMU 实例上;你必须分别去启动它自己的 QEMU)
|
||||
|
||||
#### 包检查
|
||||
|
||||
makefile 也可以配置 QEMU 的网络栈去记录所有的入站和出站数据包,并将它保存到你的实验目录中的 `qemu.pcap` 文件中。
|
||||
|
||||
使用 `tcpdump` 命令去获取一个捕获的 hex/ASCII 包转储:
|
||||
|
||||
```
|
||||
tcpdump -XXnr qemu.pcap
|
||||
```
|
||||
|
||||
或者,你可以使用 [Wireshark][2] 以图形化界面去检查 pcap 文件。Wireshark 也知道如何去解码和检查成百上千的网络协议。如果你在 Athena 上,你可以使用 Wireshark 的前辈:ethereal,它运行在加锁的保密互联网协议网络中。
|
||||
|
||||
#### 调试 E1000
|
||||
|
||||
我们非常幸运能够去使用仿真硬件。由于 E1000 是在软件中运行的,仿真的 E1000 能够给我们提供一个人类可读格式的报告、它的内部状态以及它遇到的任何问题。通常情况下,对祼机上做驱动程序开发的人来说,这是非常难能可贵的。
|
||||
|
||||
E1000 能够产生一些调试输出,因此你可以去打开一个专门的日志通道。其中一些对你有用的通道如下:
|
||||
|
||||
| 标志 | 含义 |
|
||||
| --------- | :----------------------- |
|
||||
| tx | 包发送日志 |
|
||||
| txerr | 包发送错误日志 |
|
||||
| rx | 到 RCTL 的日志通道 |
|
||||
| rxfilter | 入站包过滤日志 |
|
||||
| rxerr | 接收错误日志 |
|
||||
| unknown | 未知寄存器的读写日志 |
|
||||
| eeprom | 读取 EEPROM 的日志 |
|
||||
| interrupt | 中断和中断寄存器变更日志 |
|
||||
|
||||
例如,你可以使用 `make E1000_DEBUG=tx,txerr` 去打开 “tx” 和 “txerr” 日志功能。
|
||||
|
||||
注意:`E1000_DEBUG` 标志仅能在打了 6.828 补丁的 QEMU 版本上工作。
|
||||
|
||||
你可以使用软件去仿真硬件,来做进一步的调试工作。如果你使用它时卡壳了,不明白为什么 E1000 没有如你预期那样响应你,你可以查看在 `hw/e1000.c` 中的 QEMU 的 E1000 实现。
|
||||
|
||||
### 网络服务器
|
||||
|
||||
从头开始写一个网络栈是很困难的。因此我们将使用 lwIP,它是一个开源的、轻量级 TCP/IP 协议套件,它能做包括一个网络栈在内的很多事情。你能在 [这里][3] 找到很多关于 lwIP 的信息。在这个任务中,对我们而言,lwIP 就是一个实现了一个 BSD 套接字接口和拥有一个包输入端口和包输出端口的黑盒子。
|
||||
|
||||
一个网络服务器其实就是一个有以下四个环境的混合体:
|
||||
|
||||
* 核心网络服务器环境(包括套接字调用派发器和 lwIP)
|
||||
* 输入环境
|
||||
* 输出环境
|
||||
* 定时器环境
|
||||
|
||||
下图展示了各个环境和它们之间的关系。下图展示了包括设备驱动的整个系统,我们将在后面详细讲到它。在本实验中,你将去实现图中绿色高亮的部分。
|
||||
|
||||
![Network server architecture][4]
|
||||
|
||||
#### 核心网络服务器环境
|
||||
|
||||
核心网络服务器环境由套接字调用派发器和 lwIP 自身组成的。套接字调用派发器就像一个文件服务器一样。用户环境使用 stubs(可以在 `lib/nsipc.c` 中找到它)去发送 IPC 消息到核心网络服务器环境。如果你看了 `lib/nsipc.c`,你就会发现核心网络服务器与我们创建的文件服务器 `i386_init` 的工作方式是一样的,`i386_init` 是使用 NS_TYPE_NS 创建的 NS 环境,因此我们检查 `envs`,去查找这个特殊的环境类型。对于每个用户环境的 IPC,网络服务器中的派发器将调用相应的、由 lwIP 提供的、代表用户的 BSD 套接字接口函数。
|
||||
|
||||
普通用户环境不能直接使用 `nsipc_*` 调用。而是通过在 `lib/sockets.c` 中的函数来使用它们,这些函数提供了基于文件描述符的套接字 API。以这种方式,用户环境通过文件描述符来引用套接字,就像它们引用磁盘上的文件一样。一些操作(`connect`、`accept` 等等)是特定于套接字的,但 `read`、`write` 和 `close` 是通过 `lib/fd.c` 中一般的文件描述符设备派发代码的。就像文件服务器对所有的打开的文件维护唯一的内部 ID 一样,lwIP 也为所有的打开的套接字生成唯一的 ID。不论是文件服务器还是网络服务器,我们都使用存储在 `struct Fd` 中的信息去映射每个环境的文件描述符到这些唯一的 ID 空间上。
|
||||
|
||||
尽管看起来文件服务器的网络服务器的 IPC 派发器行为是一样的,但它们之间还有很重要的差别。BSD 套接字调用(像 `accept` 和 `recv`)能够无限期阻塞。如果派发器让 lwIP 去执行其中一个调用阻塞,派发器也将被阻塞,并且在整个系统中,同一时间只能有一个未完成的网络调用。由于这种情况是无法接受的,所以网络服务器使用用户级线程以避免阻塞整个服务器环境。对于每个入站 IPC 消息,派发器将创建一个线程,然后在新创建的线程上来处理请求。如果线程被阻塞,那么只有那个线程被置入休眠状态,而其它线程仍然处于运行中。
|
||||
|
||||
除了核心网络环境外,还有三个辅助环境。核心网络服务器环境除了接收来自用户应用程序的消息之外,它的派发器也接收来自输入环境和定时器环境的消息。
|
||||
|
||||
#### 输出环境
|
||||
|
||||
在为用户环境套接字调用提供服务时,lwIP 将为网卡生成用于发送的包。lwIP 将使用 `NSREQ_OUTPUT` 去发送在 IPC 消息页参数中附加了包的 IPC 消息。输出环境负责接收这些消息,并通过你稍后创建的系统调用接口来转发这些包到设备驱动程序上。
|
||||
|
||||
#### 输入环境
|
||||
|
||||
网卡接收到的包需要传递到 lwIP 中。输入环境将每个由设备驱动程序接收到的包拉进内核空间(使用你将要实现的内核系统调用),并使用 `NSREQ_INPUT` IPC 消息将这些包发送到核心网络服务器环境。
|
||||
|
||||
包输入功能是独立于核心网络环境的,因为在 JOS 上同时实现接收 IPC 消息并从设备驱动程序中查询或等待包有点困难。我们在 JOS 中没有实现 `select` 系统调用,这是一个允许环境去监视多个输入源以识别准备处理哪个输入的系统调用。
|
||||
|
||||
如果你查看了 `net/input.c` 和 `net/output.c`,你将会看到在它们中都需要去实现那个系统调用。这主要是因为实现它要依赖你的系统调用接口。在你实现了驱动程序和系统调用接口之后,你将要为这两个辅助环境写这个代码。
|
||||
|
||||
#### 定时器环境
|
||||
|
||||
定时器环境周期性发送 `NSREQ_TIMER` 类型的消息到核心服务器,以提醒它那个定时器已过期。lwIP 使用来自线程的定时器消息来实现各种网络超时。
|
||||
|
||||
### Part A:初始化和发送包
|
||||
|
||||
你的内核还没有一个时间概念,因此我们需要去添加它。这里有一个由硬件产生的每 10 ms 一次的时钟中断。每收到一个时钟中断,我们将增加一个变量值,以表示时间已过去 10 ms。它在 `kern/time.c` 中已实现,但还没有完全集成到你的内核中。
|
||||
|
||||
> **练习 1**、为 `kern/trap.c` 中的每个时钟中断增加一个到 `time_tick` 的调用。实现 `sys_time_msec` 并增加到 `kern/syscall.c` 中的 `syscall`,以便于用户空间能够访问时间。
|
||||
|
||||
使用 `make INIT_CFLAGS=-DTEST_NO_NS run-testtime` 去测试你的代码。你应该会看到环境计数从 5 开始以 1 秒为间隔减少。`-DTEST_NO_NS` 参数禁止在网络服务器环境上启动,因为在当前它将导致 JOS 崩溃。
|
||||
|
||||
#### 网卡
|
||||
|
||||
写驱动程序要求你必须深入了解硬件和软件中的接口。本实验将给你提供一个如何使用 E1000 接口的高度概括的文档,但是你在写驱动程序时还需要大量去查询 Intel 的手册。
|
||||
|
||||
> **练习 2**、为开发 E1000 驱动,去浏览 Intel 的 [软件开发者手册][5]。这个手册涵盖了几个与以太网控制器紧密相关的东西。QEMU 仿真了 82540EM。
|
||||
|
||||
> 现在,你应该去浏览第 2 章,以对设备获得一个整体概念。写驱动程序时,你需要熟悉第 3 到 14 章,以及 4.1(不包括 4.1 的子节)。你也应该去参考第 13 章。其它章涵盖了 E1000 的组件,你的驱动程序并不与这些组件去交互。现在你不用担心过多细节的东西;只需要了解文档的整体结构,以便于你后面需要时容易查找。
|
||||
|
||||
> 在阅读手册时,记住,E1000 是一个拥有很多高级特性的很复杂的设备,一个能让 E1000 工作的驱动程序仅需要它一小部分的特性和 NIC 提供的接口即可。仔细考虑一下,如何使用最简单的方式去使用网卡的接口。我们强烈推荐你在使用高级特性之前,只去写一个基本的、能够让网卡工作的驱动程序即可。
|
||||
|
||||
##### PCI 接口
|
||||
|
||||
E1000 是一个 PCI 设备,也就是说它是插到主板的 PCI 总线插槽上的。PCI 总线有地址、数据、和中断线,并且 PCI 总线允许 CPU 与 PCI 设备通讯,以及 PCI 设备去读取和写入内存。一个 PCI 设备在它能够被使用之前,需要先发现它并进行初始化。发现 PCI 设备是 PCI 总线查找已安装设备的过程。初始化是分配 I/O 和内存空间、以及协商设备所使用的 IRQ 线的过程。
|
||||
|
||||
我们在 `kern/pci.c` 中已经为你提供了使用 PCI 的代码。PCI 初始化是在引导期间执行的,PCI 代码遍历PCI 总线来查找设备。当它找到一个设备时,它读取它的供应商 ID 和设备 ID,然后使用这两个值作为关键字去搜索 `pci_attach_vendor` 数组。这个数组是由像下面这样的 `struct pci_driver` 条目组成:
|
||||
|
||||
```c
|
||||
struct pci_driver {
|
||||
uint32_t key1, key2;
|
||||
int (*attachfn) (struct pci_func *pcif);
|
||||
};
|
||||
```
|
||||
|
||||
如果发现的设备的供应商 ID 和设备 ID 与数组中条目匹配,那么 PCI 代码将调用那个条目的 `attachfn` 去执行设备初始化。(设备也可以按类别识别,那是通过 `kern/pci.c` 中其它的驱动程序表来实现的。)
|
||||
|
||||
绑定函数是传递一个 _PCI 函数_ 去初始化。一个 PCI 卡能够发布多个函数,虽然这个 E1000 仅发布了一个。下面是在 JOS 中如何去表示一个 PCI 函数:
|
||||
|
||||
```c
|
||||
struct pci_func {
|
||||
struct pci_bus *bus;
|
||||
|
||||
uint32_t dev;
|
||||
uint32_t func;
|
||||
|
||||
uint32_t dev_id;
|
||||
uint32_t dev_class;
|
||||
|
||||
uint32_t reg_base[6];
|
||||
uint32_t reg_size[6];
|
||||
uint8_t irq_line;
|
||||
};
|
||||
```
|
||||
|
||||
上面的结构反映了在 Intel 开发者手册里第 4.1 节的表 4-1 中找到的一些条目。`struct pci_func` 的最后三个条目我们特别感兴趣的,因为它们将记录这个设备协商的内存、I/O、以及中断资源。`reg_base` 和 `reg_size` 数组包含最多六个基址寄存器或 BAR。`reg_base` 为映射到内存中的 I/O 区域(对于 I/O 端口而言是基 I/O 端口)保存了内存的基地址,`reg_size` 包含了以字节表示的大小或来自 `reg_base` 的相关基值的 I/O 端口号,而 `irq_line` 包含了为中断分配给设备的 IRQ 线。在表 4-2 的后半部分给出了 E1000 BAR 的具体涵义。
|
||||
|
||||
当设备调用了绑定函数后,设备已经被发现,但没有被启用。这意味着 PCI 代码还没有确定分配给设备的资源,比如地址空间和 IRQ 线,也就是说,`struct pci_func` 结构的最后三个元素还没有被填入。绑定函数将调用 `pci_func_enable`,它将去启用设备、协商这些资源、并在结构 `struct pci_func` 中填入它。
|
||||
|
||||
> **练习 3**、实现一个绑定函数去初始化 E1000。添加一个条目到 `kern/pci.c` 中的数组 `pci_attach_vendor` 上,如果找到一个匹配的 PCI 设备就去触发你的函数(确保一定要把它放在表末尾的 `{0, 0, 0}` 条目之前)。你在 5.2 节中能找到 QEMU 仿真的 82540EM 的供应商 ID 和设备 ID。在引导期间,当 JOS 扫描 PCI 总线时,你也可以看到列出来的这些信息。
|
||||
|
||||
> 到目前为止,我们通过 `pci_func_enable` 启用了 E1000 设备。通过本实验我们将添加更多的初始化。
|
||||
|
||||
> 我们已经为你提供了 `kern/e1000.c` 和 `kern/e1000.h` 文件,这样你就不会把构建系统搞糊涂了。不过它们现在都是空的;你需要在本练习中去填充它们。你还可能在内核的其它地方包含这个 `e1000.h` 文件。
|
||||
|
||||
> 当你引导你的内核时,你应该会看到它输出的信息显示 E1000 的 PCI 函数已经启用。这时你的代码已经能够通过 `make grade` 的 `pci attach` 测试了。
|
||||
|
||||
##### 内存映射的 I/O
|
||||
|
||||
软件与 E1000 通过内存映射的 I/O(MMIO)来沟通。你在 JOS 的前面部分可能看到过 MMIO 两次:CGA 控制台和 LAPIC 都是通过写入和读取“内存”来控制和查询设备的。但这些读取和写入不是去往内存芯片的,而是直接到这些设备的。
|
||||
|
||||
`pci_func_enable` 为 E1000 协调一个 MMIO 区域,来存储它在 BAR 0 的基址和大小(也就是 `reg_base[0]` 和 `reg_size[0]`),这是一个分配给设备的一段物理内存地址,也就是说你可以通过虚拟地址访问它来做一些事情。由于 MMIO 区域一般分配高位物理地址(一般是 3GB 以上的位置),因此你不能使用 `KADDR` 去访问它们,因为 JOS 被限制为最大使用 256MB。因此,你可以去创建一个新的内存映射。我们将使用 `MMIOBASE`(从实验 4 开始,你的 `mmio_map_region` 区域应该确保不能被 LAPIC 使用的映射所覆盖)以上的部分。由于在 JOS 创建用户环境之前,PCI 设备就已经初始化了,因此你可以在 `kern_pgdir` 处创建映射,并且让它始终可用。
|
||||
|
||||
> **练习 4**、在你的绑定函数中,通过调用 `mmio_map_region`(它就是你在实验 4 中写的,是为了支持 LAPIC 内存映射)为 E1000 的 BAR 0 创建一个虚拟地址映射。
|
||||
|
||||
> 你将希望在一个变量中记录这个映射的位置,以便于后面访问你映射的寄存器。去看一下 `kern/lapic.c` 中的 `lapic` 变量,它就是一个这样的例子。如果你使用一个指针指向设备寄存器映射,一定要声明它为 `volatile`;否则,编译器将允许缓存它的值,并可以在内存中再次访问它。
|
||||
|
||||
> 为测试你的映射,尝试去输出设备状态寄存器(第 12.4.2 节)。这是一个在寄存器空间中以字节 8 开头的 4 字节寄存器。你应该会得到 `0x80080783`,它表示以 1000 MB/s 的速度启用一个全双工的链路,以及其它信息。
|
||||
|
||||
提示:你将需要一些常数,像寄存器位置和掩码位数。如果从开发者手册中复制这些东西很容易出错,并且导致调试过程很痛苦。我们建议你使用 QEMU 的 [e1000_hw.h][6] 头文件做为基准。我们不建议完全照抄它,因为它定义的值远超过你所需要,并且定义的东西也不见得就是你所需要的,但它仍是一个很好的参考。
|
||||
|
||||
##### DMA
|
||||
|
||||
你可能会认为是从 E1000 的寄存器中通过写入和读取来传送和接收数据包的,其实这样做会非常慢,并且还要求 E1000 在其中去缓存数据包。相反,E1000 使用直接内存访问(DMA)从内存中直接读取和写入数据包,而且不需要 CPU 参与其中。驱动程序负责为发送和接收队列分配内存、设置 DMA 描述符、以及配置 E1000 使用的队列位置,而在这些设置完成之后的其它工作都是异步方式进行的。发送包的时候,驱动程序复制它到发送队列的下一个 DMA 描述符中,并且通知 E1000 下一个发送包已就绪;当轮到这个包发送时,E1000 将从描述符中复制出数据。同样,当 E1000 接收一个包时,它从接收队列中将它复制到下一个 DMA 描述符中,驱动程序将能在下一次读取到它。
|
||||
|
||||
总体来看,接收队列和发送队列非常相似。它们都是由一系列的描述符组成。虽然这些描述符的结构细节有所不同,但每个描述符都包含一些标志和包含了包数据的一个缓存的物理地址(发送到网卡的数据包,或网卡将接收到的数据包写入到由操作系统分配的缓存中)。
|
||||
|
||||
队列被实现为一个环形数组,意味着当网卡或驱动到达数组末端时,它将重新回到开始位置。它有一个头指针和尾指针,队列的内容就是这两个指针之间的描述符。硬件就是从头开始移动头指针去消费描述符,在这期间驱动程序不停地添加描述符到尾部,并移动尾指针到最后一个描述符上。发送队列中的描述符表示等待发送的包(因此,在平静状态下,发送队列是空的)。对于接收队列,队列中的描述符是表示网卡能够接收包的空描述符(因此,在平静状态下,接收队列是由所有的可用接收描述符组成的)。正确的更新尾指针寄存器而不让 E1000 产生混乱是很有难度的;要小心!
|
||||
|
||||
指向到这些数组及描述符中的包缓存地址的指针都必须是物理地址,因为硬件是直接在物理内存中且不通过 MMU 来执行 DMA 的读写操作的。
|
||||
|
||||
#### 发送包
|
||||
|
||||
E1000 中的发送和接收功能本质上是独立的,因此我们可以同时进行发送接收。我们首先去攻克简单的数据包发送,因为我们在没有先去发送一个 “I'm here!” 包之前是无法测试接收包功能的。
|
||||
|
||||
首先,你需要初始化网卡以准备发送,详细步骤查看 14.5 节(不必着急看子节)。发送初始化的第一步是设置发送队列。队列的详细结构在 3.4 节中,描述符的结构在 3.3.3 节中。我们先不要使用 E1000 的 TCP offload 特性,因此你只需专注于 “传统的发送描述符格式” 即可。你应该现在就去阅读这些章节,并要熟悉这些结构。
|
||||
|
||||
##### C 结构
|
||||
|
||||
你可以用 C `struct` 很方便地描述 E1000 的结构。正如你在 `struct Trapframe` 中所看到的结构那样,C `struct` 可以让你很方便地在内存中描述准确的数据布局。C 可以在字段中插入数据,但是 E1000 的结构就是这样布局的,这样就不会是个问题。如果你遇到字段对齐问题,进入 GCC 查看它的 "packed” 属性。
|
||||
|
||||
查看手册中表 3-8 所给出的一个传统的发送描述符,将它复制到这里作为一个示例:
|
||||
|
||||
```
|
||||
63 48 47 40 39 32 31 24 23 16 15 0
|
||||
+---------------------------------------------------------------+
|
||||
| Buffer address |
|
||||
+---------------|-------|-------|-------|-------|---------------+
|
||||
| Special | CSS | Status| Cmd | CSO | Length |
|
||||
+---------------|-------|-------|-------|-------|---------------+
|
||||
```
|
||||
|
||||
从结构右上角第一个字节开始,我们将它转变成一个 C 结构,从上到下,从右到左读取。如果你从右往左看,你将看到所有的字段,都非常适合一个标准大小的类型:
|
||||
|
||||
```c
|
||||
struct tx_desc
|
||||
{
|
||||
uint64_t addr;
|
||||
uint16_t length;
|
||||
uint8_t cso;
|
||||
uint8_t cmd;
|
||||
uint8_t status;
|
||||
uint8_t css;
|
||||
uint16_t special;
|
||||
};
|
||||
```
|
||||
|
||||
你的驱动程序将为发送描述符数组去保留内存,并由发送描述符指向到包缓冲区。有几种方式可以做到,从动态分配页到在全局变量中简单地声明它们。无论你如何选择,记住,E1000 是直接访问物理内存的,意味着它能访问的任何缓存区在物理内存中必须是连续的。
|
||||
|
||||
处理包缓存也有几种方式。我们推荐从最简单的开始,那就是在驱动程序初始化期间,为每个描述符保留包缓存空间,并简单地将包数据复制进预留的缓冲区中或从其中复制出来。一个以太网包最大的尺寸是 1518 字节,这就限制了这些缓存区的大小。主流的成熟驱动程序都能够动态分配包缓存区(即:当网络使用率很低时,减少内存使用量),或甚至跳过缓存区,直接由用户空间提供(就是“零复制”技术),但我们还是从简单开始为好。
|
||||
|
||||
> **练习 5**、执行一个 14.5 节中的初始化步骤(它的子节除外)。对于寄存器的初始化过程使用 13 节作为参考,对发送描述符和发送描述符数组参考 3.3.3 节和 3.4 节。
|
||||
|
||||
> 要记住,在发送描述符数组中要求对齐,并且数组长度上有限制。因为 TDLEN 必须是 128 字节对齐的,而每个发送描述符是 16 字节,你的发送描述符数组必须是 8 个发送描述符的倍数。并且不能使用超过 64 个描述符,以及不能在我们的发送环形缓存测试中溢出。
|
||||
|
||||
> 对于 TCTL.COLD,你可以假设为全双工操作。对于 TIPG、IEEE 802.3 标准的 IPG(不要使用 14.5 节中表上的值),参考在 13.4.34 节中表 13-77 中描述的缺省值。
|
||||
|
||||
尝试运行 `make E1000_DEBUG=TXERR,TX qemu`。如果你使用的是打了 6.828 补丁的 QEMU,当你设置 TDT(发送描述符尾部)寄存器时你应该会看到一个 “e1000: tx disabled” 的信息,并且不会有更多 “e1000” 信息了。
|
||||
|
||||
现在,发送初始化已经完成,你可以写一些代码去发送一个数据包,并且通过一个系统调用使它可以访问用户空间。你可以将要发送的数据包添加到发送队列的尾部,也就是说复制数据包到下一个包缓冲区中,然后更新 TDT 寄存器去通知网卡在发送队列中有另外的数据包。(注意,TDT 是一个进入发送描述符数组的索引,不是一个字节偏移量;关于这一点文档中说明的不是很清楚。)
|
||||
|
||||
但是,发送队列只有这么大。如果网卡在发送数据包时卡住或发送队列填满时会发生什么状况?为了检测这种情况,你需要一些来自 E1000 的反馈。不幸的是,你不能只使用 TDH(发送描述符头)寄存器;文档上明确说明,从软件上读取这个寄存器是不可靠的。但是,如果你在发送描述符的命令字段中设置 RS 位,那么,当网卡去发送在那个描述符中的数据包时,网卡将设置描述符中状态字段的 DD 位,如果一个描述符中的 DD 位被设置,你就应该知道那个描述符可以安全地回收,并且可以用它去发送其它数据包。
|
||||
|
||||
如果用户调用你的发送系统调用,但是下一个描述符的 DD 位没有设置,表示那个发送队列已满,该怎么办?在这种情况下,你该去决定怎么办了。你可以简单地丢弃数据包。网络协议对这种情况的处理很灵活,但如果你丢弃大量的突发数据包,协议可能不会去重新获得它们。可能需要你替代网络协议告诉用户环境让它重传,就像你在 `sys_ipc_try_send` 中做的那样。在环境上回推产生的数据是有好处的。
|
||||
|
||||
> **练习 6**、写一个函数去发送一个数据包,它需要检查下一个描述符是否空闲、复制包数据到下一个描述符并更新 TDT。确保你处理的发送队列是满的。
|
||||
|
||||
现在,应该去测试你的包发送代码了。通过从内核中直接调用你的发送函数来尝试发送几个包。在测试时,你不需要去创建符合任何特定网络协议的数据包。运行 `make E1000_DEBUG=TXERR,TX qemu` 去测试你的代码。你应该看到类似下面的信息:
|
||||
|
||||
```c
|
||||
e1000: index 0: 0x271f00 : 9000002a 0
|
||||
...
|
||||
```
|
||||
|
||||
在你发送包时,每行都给出了在发送数组中的序号、那个发送的描述符的缓存地址、`cmd/CSO/length` 字段、以及 `special/CSS/status` 字段。如果 QEMU 没有从你的发送描述符中输出你预期的值,检查你的描述符中是否有合适的值和你配置的正确的 TDBAL 和 TDBAH。如果你收到的是 “e1000: TDH wraparound @0, TDT x, TDLEN y” 的信息,意味着 E1000 的发送队列持续不断地运行(如果 QEMU 不去检查它,它将是一个无限循环),这意味着你没有正确地维护 TDT。如果你收到了许多 “e1000: tx disabled” 的信息,那么意味着你没有正确设置发送控制寄存器。
|
||||
|
||||
一旦 QEMU 运行,你就可以运行 `tcpdump -XXnr qemu.pcap` 去查看你发送的包数据。如果从 QEMU 中看到预期的 “e1000: index” 信息,但你捕获的包是空的,再次检查你发送的描述符,是否填充了每个必需的字段和位。(E1000 或许已经遍历了你的发送描述符,但它认为不需要去发送)
|
||||
|
||||
> **练习 7**、添加一个系统调用,让你从用户空间中发送数据包。详细的接口由你来决定。但是不要忘了检查从用户空间传递给内核的所有指针。
|
||||
|
||||
#### 发送包:网络服务器
|
||||
|
||||
现在,你已经有一个系统调用接口可以发送包到你的设备驱动程序端了。输出辅助环境的目标是在一个循环中做下面的事情:从核心网络服务器中接收 `NSREQ_OUTPUT` IPC 消息,并使用你在上面增加的系统调用去发送伴随这些 IPC 消息的数据包。这个 `NSREQ_OUTPUT` IPC 是通过 `net/lwip/jos/jif/jif.c` 中的 `low_level_output` 函数来发送的。它集成 lwIP 栈到 JOS 的网络系统。每个 IPC 将包含一个页,这个页由一个 `union Nsipc` 和在 `struct jif_pkt pkt` 字段中的一个包组成(查看 `inc/ns.h`)。`struct jif_pkt` 看起来像下面这样:
|
||||
|
||||
```c
|
||||
struct jif_pkt {
|
||||
int jp_len;
|
||||
char jp_data[0];
|
||||
};
|
||||
```
|
||||
|
||||
`jp_len` 表示包的长度。在 IPC 页上的所有后续字节都是为了包内容。在结构的结尾处使用一个长度为 0 的数组来表示缓存没有一个预先确定的长度(像 `jp_data` 一样),这是一个常见的 C 技巧(也有人说这是一个令人讨厌的做法)。因为 C 并不做数组边界的检查,只要你确保结构后面有足够的未使用内存即可,你可以把 `jp_data` 作为一个任意大小的数组来使用。
|
||||
|
||||
当设备驱动程序的发送队列中没有足够的空间时,一定要注意在设备驱动程序、输出环境和核心网络服务器之间的交互。核心网络服务器使用 IPC 发送包到输出环境。如果输出环境在由于一个发送包的系统调用而挂起,导致驱动程序没有足够的缓存去容纳新数据包,这时核心网络服务器将阻塞以等待输出服务器去接收 IPC 调用。
|
||||
|
||||
> **练习 8**、实现 `net/output.c`。
|
||||
|
||||
你可以使用 `net/testoutput.c` 去测试你的输出代码而无需整个网络服务器参与。尝试运行 `make E1000_DEBUG=TXERR,TX run-net_testoutput`。你将看到如下的输出:
|
||||
|
||||
```c
|
||||
Transmitting packet 0
|
||||
e1000: index 0: 0x271f00 : 9000009 0
|
||||
Transmitting packet 1
|
||||
e1000: index 1: 0x2724ee : 9000009 0
|
||||
...
|
||||
```
|
||||
|
||||
运行 `tcpdump -XXnr qemu.pcap` 将输出:
|
||||
|
||||
```c
|
||||
reading from file qemu.pcap, link-type EN10MB (Ethernet)
|
||||
-5:00:00.600186 [|ether]
|
||||
0x0000: 5061 636b 6574 2030 30 Packet.00
|
||||
-5:00:00.610080 [|ether]
|
||||
0x0000: 5061 636b 6574 2030 31 Packet.01
|
||||
...
|
||||
```
|
||||
|
||||
使用更多的数据包去测试,可以运行 `make E1000_DEBUG=TXERR,TX NET_CFLAGS=-DTESTOUTPUT_COUNT=100 run-net_testoutput`。如果它导致你的发送队列溢出,再次检查你的 DD 状态位是否正确,以及是否告诉硬件去设置 DD 状态位(使用 RS 命令位)。
|
||||
|
||||
你的代码应该会通过 `make grade` 的 `testoutput` 测试。
|
||||
|
||||
> **问题 1**、你是如何构造你的发送实现的?在实践中,如果发送缓存区满了,你该如何处理?
|
||||
|
||||
### Part B:接收包和 web 服务器
|
||||
|
||||
#### 接收包
|
||||
|
||||
就像你在发送包中做的那样,你将去配置 E1000 去接收数据包,并提供一个接收描述符队列和接收描述符。在 3.2 节中描述了接收包的操作,包括接收队列结构和接收描述符、以及在 14.4 节中描述的详细的初始化过程。
|
||||
|
||||
> **练习 9**、阅读 3.2 节。你可以忽略关于中断和 offload 校验和方面的内容(如果在后面你想去使用这些特性,可以再返回去阅读),你现在不需要去考虑阈值的细节和网卡内部缓存是如何工作的。
|
||||
|
||||
除了接收队列是由一系列的等待入站数据包去填充的空缓存包以外,接收队列的其它部分与发送队列非常相似。所以,当网络空闲时,发送队列是空的(因为所有的包已经被发送出去了),而接收队列是满的(全部都是空缓存包)。
|
||||
|
||||
当 E1000 接收一个包时,它首先与网卡的过滤器进行匹配检查(例如,去检查这个包的目标地址是否为这个 E1000 的 MAC 地址),如果这个包不匹配任何过滤器,它将忽略这个包。否则,E1000 尝试从接收队列头部去检索下一个接收描述符。如果头(RDH)追上了尾(RDT),那么说明接收队列已经没有空闲的描述符了,所以网卡将丢弃这个包。如果有空闲的接收描述符,它将复制这个包的数据到描述符指向的缓存中,设置这个描述符的 DD 和 EOP 状态位,并递增 RDH。
|
||||
|
||||
如果 E1000 在一个接收描述符中接收到了一个比包缓存还要大的数据包,它将按需从接收队列中检索尽可能多的描述符以保存数据包的全部内容。为表示发生了这种情况,它将在所有的这些描述符上设置 DD 状态位,但仅在这些描述符的最后一个上设置 EOP 状态位。在你的驱动程序上,你可以去处理这种情况,也可以简单地配置网卡拒绝接收这种”长包“(这种包也被称为”巨帧“),你要确保接收缓存有足够的空间尽可能地去存储最大的标准以太网数据包(1518 字节)。
|
||||
|
||||
> **练习 10**、设置接收队列并按 14.4 节中的流程去配置 E1000。你可以不用支持 ”长包“ 或多播。到目前为止,我们不用去配置网卡使用中断;如果你在后面决定去使用接收中断时可以再去改。另外,配置 E1000 去除以太网的 CRC 校验,因为我们的评级脚本要求必须去掉校验。
|
||||
|
||||
> 默认情况下,网卡将过滤掉所有的数据包。你必须使用网卡的 MAC 地址去配置接收地址寄存器(RAL 和 RAH)以接收发送到这个网卡的数据包。你可以简单地硬编码 QEMU 的默认 MAC 地址 52:54:00:12:34:56(我们已经在 lwIP 中硬编码了这个地址,因此这样做不会有问题)。使用字节顺序时要注意;MAC 地址是从低位字节到高位字节的方式来写的,因此 52:54:00:12 是 MAC 地址的低 32 位,而 34:56 是它的高 16 位。
|
||||
|
||||
> E1000 的接收缓存区大小仅支持几个指定的设置值(在 13.4.22 节中描述的 RCTL.BSIZE 值)。如果你的接收包缓存够大,并且拒绝长包,那你就不用担心跨越多个缓存区的包。另外,要记住的是,和发送一样,接收队列和包缓存必须是连接的物理内存。
|
||||
|
||||
> 你应该使用至少 128 个接收描述符。
|
||||
|
||||
现在,你可以做接收功能的基本测试了,甚至都无需写代码去接收包了。运行 `make E1000_DEBUG=TX,TXERR,RX,RXERR,RXFILTER run-net_testinput`。`testinput` 将发送一个 ARP(地址解析协议)通告包(使用你的包发送的系统调用),而 QEMU 将自动回复它,即便是你的驱动尚不能接收这个回复,你也应该会看到一个 “e1000: unicast match[0]: 52:54:00:12:34:56” 的消息,表示 E1000 接收到一个包,并且匹配了配置的接收过滤器。如果你看到的是一个 “e1000: unicast mismatch: 52:54:00:12:34:56” 消息,表示 E1000 过滤掉了这个包,意味着你的 RAL 和 RAH 的配置不正确。确保你按正确的顺序收到了字节,并不要忘记设置 RAH 中的 “Address Valid” 位。如果你没有收到任何 “e1000” 消息,或许是你没有正确地启用接收功能。
|
||||
|
||||
现在,你准备去实现接收数据包。为了接收数据包,你的驱动程序必须持续跟踪希望去保存下一下接收到的包的描述符(提示:按你的设计,这个功能或许已经在 E1000 中的一个寄存器来实现了)。与发送类似,官方文档上表示,RDH 寄存器状态并不能从软件中可靠地读取,因为确定一个包是否被发送到描述符的包缓存中,你需要去读取描述符中的 DD 状态位。如果 DD 位被设置,你就可以从那个描述符的缓存中复制出这个数据包,然后通过更新队列的尾索引 RDT 来告诉网卡那个描述符是空闲的。
|
||||
|
||||
如果 DD 位没有被设置,表明没有接收到包。这就与发送队列满的情况一样,这时你可以有几种做法。你可以简单地返回一个 ”重传“ 错误来要求对端重发一次。对于满的发送队列,由于那是个临时状况,这种做法还是很好的,但对于空的接收队列来说就不太合理了,因为接收队列可能会保持好长一段时间的空的状态。第二个方法是挂起调用环境,直到在接收队列中处理了这个包为止。这个策略非常类似于 `sys_ipc_recv`。就像在 IPC 的案例中,因为我们每个 CPU 仅有一个内核栈,一旦我们离开内核,栈上的状态就会被丢弃。我们需要设置一个标志去表示那个环境由于接收队列下溢被挂起并记录系统调用参数。这种方法的缺点是过于复杂:E1000 必须被指示去产生接收中断,并且驱动程序为了恢复被阻塞等待一个包的环境,必须处理这个中断。
|
||||
|
||||
> **练习 11**、写一个函数从 E1000 中接收一个包,然后通过一个系统调用将它发布到用户空间。确保你将接收队列处理成空的。
|
||||
|
||||
.
|
||||
|
||||
> 小挑战!如果发送队列是满的或接收队列是空的,环境和你的驱动程序可能会花费大量的 CPU 周期是轮询、等待一个描述符。一旦完成发送或接收描述符,E1000 能够产生一个中断,以避免轮询。修改你的驱动程序,处理发送和接收队列是以中断而不是轮询的方式进行。
|
||||
|
||||
> 注意,一旦确定为中断,它将一直处于中断状态,直到你的驱动程序明确处理完中断为止。在你的中断服务程序中,一旦处理完成要确保清除掉中断状态。如果你不那样做,从你的中断服务程序中返回后,CPU 将再次跳转到你的中断服务程序中。除了在 E1000 网卡上清除中断外,也需要使用 `lapic_eoi` 在 LAPIC 上清除中断。
|
||||
|
||||
#### 接收包:网络服务器
|
||||
|
||||
在网络服务器输入环境中,你需要去使用你的新的接收系统调用以接收数据包,并使用 `NSREQ_INPUT` IPC 消息将它传递到核心网络服务器环境。这些 IPC 输入消息应该会有一个页,这个页上绑定了一个 `union Nsipc`,它的 `struct jif_pkt pkt` 字段中有从网络上接收到的包。
|
||||
|
||||
> **练习 12**、实现 `net/input.c`。
|
||||
|
||||
使用 `make E1000_DEBUG=TX,TXERR,RX,RXERR,RXFILTER run-net_testinput` 再次运行 `testinput`,你应该会看到:
|
||||
|
||||
```c
|
||||
Sending ARP announcement...
|
||||
Waiting for packets...
|
||||
e1000: index 0: 0x26dea0 : 900002a 0
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
input: 0000 5254 0012 3456 5255 0a00 0202 0806 0001
|
||||
input: 0010 0800 0604 0002 5255 0a00 0202 0a00 0202
|
||||
input: 0020 5254 0012 3456 0a00 020f 0000 0000 0000
|
||||
input: 0030 0000 0000 0000 0000 0000 0000 0000 0000
|
||||
```
|
||||
|
||||
“input:” 打头的行是一个 QEMU 的 ARP 回复的十六进制转储。
|
||||
|
||||
你的代码应该会通过 `make grade` 的 `testinput` 测试。注意,在没有发送至少一个包去通知 QEMU 中的 JOS 的 IP 地址上时,是没法去测试包接收的,因此在你的发送代码中的 bug 可能会导致测试失败。
|
||||
|
||||
为彻底地测试你的网络代码,我们提供了一个称为 `echosrv` 的守护程序,它在端口 7 上设置运行 `echo` 的服务器,它将回显通过 TCP 连接发送给它的任何内容。使用 `make E1000_DEBUG=TX,TXERR,RX,RXERR,RXFILTER run-echosrv` 在一个终端中启动 `echo` 服务器,然后在另一个终端中通过 `make nc-7` 去连接它。你输入的每一行都被这个服务器回显出来。每次在仿真的 E1000 上接收到一个包,QEMU 将在控制台上输出像下面这样的内容:
|
||||
|
||||
```c
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
e1000: index 2: 0x26ea7c : 9000036 0
|
||||
e1000: index 3: 0x26f06a : 9000039 0
|
||||
e1000: unicast match[0]: 52:54:00:12:34:56
|
||||
```
|
||||
|
||||
做到这一点后,你应该也就能通过 `echosrv` 的测试了。
|
||||
|
||||
> **问题 2**、你如何构造你的接收实现?在实践中,如果接收队列是空的并且一个用户环境要求下一个入站包,你怎么办?
|
||||
|
||||
.
|
||||
|
||||
> 小挑战!在开发者手册中阅读关于 EEPROM 的内容,并写出从 EEPROM 中加载 E1000 的 MAC 地址的代码。目前,QEMU 的默认 MAC 地址是硬编码到你的接收初始化代码和 lwIP 中的。修复你的初始化代码,让它能够从 EEPROM 中读取 MAC 地址,和增加一个系统调用去传递 MAC 地址到 lwIP 中,并修改 lwIP 去从网卡上读取 MAC 地址。通过配置 QEMU 使用一个不同的 MAC 地址去测试你的变更。
|
||||
|
||||
.
|
||||
|
||||
> 小挑战!修改你的 E1000 驱动程序去使用 "零复制" 技术。目前,数据包是从用户空间缓存中复制到发送包缓存中,和从接收包缓存中复制回到用户空间缓存中。一个使用 ”零复制“ 技术的驱动程序可以通过直接让用户空间和 E1000 共享包缓存内存来实现。还有许多不同的方法去实现 ”零复制“,包括映射内容分配的结构到用户空间或直接传递用户提供的缓存到 E1000。不论你选择哪种方法,都要注意你如何利用缓存的问题,因为你不能在用户空间代码和 E1000 之间产生争用。
|
||||
|
||||
.
|
||||
|
||||
> 小挑战!把 “零复制” 的概念用到 lwIP 中。
|
||||
|
||||
> 一个典型的包是由许多头构成的。用户发送的数据被发送到 lwIP 中的一个缓存中。TCP 层要添加一个 TCP 包头,IP 层要添加一个 IP 包头,而 MAC 层有一个以太网头。甚至还有更多的部分增加到包上,这些部分要正确地连接到一起,以便于设备驱动程序能够发送最终的包。
|
||||
|
||||
> E1000 的发送描述符设计是非常适合收集分散在内存中的包片段的,像在 lwIP 中创建的包的帧。如果你排队多个发送描述符,但仅设置最后一个描述符的 EOP 命令位,那么 E1000 将在内部把这些描述符串成包缓存,并在它们标记完 EOP 后仅发送串起来的缓存。因此,独立的包片段不需要在内存中把它们连接到一起。
|
||||
|
||||
> 修改你的驱动程序,以使它能够发送由多个缓存且无需复制的片段组成的包,并且修改 lwIP 去避免它合并包片段,因为它现在能够正确处理了。
|
||||
|
||||
.
|
||||
|
||||
> 小挑战!增加你的系统调用接口,以便于它能够为多于一个的用户环境提供服务。如果有多个网络栈(和多个网络服务器)并且它们各自都有自己的 IP 地址运行在用户模式中,这将是非常有用的。接收系统调用将决定它需要哪个环境来转发每个入站的包。
|
||||
|
||||
> 注意,当前的接口并不知道两个包之间有何不同,并且如果多个环境去调用包接收的系统调用,各个环境将得到一个入站包的子集,而那个子集可能并不包含调用环境指定的那个包。
|
||||
|
||||
> 在 [这篇][7] 外内核论文的 2.2 节和 3 节中对这个问题做了深度解释,并解释了在内核中(如 JOS)处理它的一个方法。用这个论文中的方法去解决这个问题,你不需要一个像论文中那么复杂的方案。
|
||||
|
||||
#### Web 服务器
|
||||
|
||||
一个最简单的 web 服务器类型是发送一个文件的内容到请求的客户端。我们在 `user/httpd.c` 中提供了一个非常简单的 web 服务器的框架代码。这个框架内码处理入站连接并解析请求头。
|
||||
|
||||
> **练习 13**、这个 web 服务器中缺失了发送一个文件的内容到客户端的处理代码。通过实现 `send_file` 和 `send_data` 完成这个 web 服务器。
|
||||
|
||||
在你完成了这个 web 服务器后,启动这个 web 服务器(`make run-httpd-nox`),使用你喜欢的浏览器去浏览 `http://host:port/index.html` 地址。其中 _host_ 是运行 QEMU 的计算机的名字(如果你在 athena 上运行 QEMU,使用 `hostname.mit.edu`(其中 hostname 是在 athena 上运行 `hostname` 命令的输出,或者如果你在运行 QEMU 的机器上运行 web 浏览器的话,直接使用 `localhost`),而 _port_ 是 web 服务器运行 `make which-ports` 命令报告的端口号。你应该会看到一个由运行在 JOS 中的 HTTP 服务器提供的一个 web 页面。
|
||||
|
||||
到目前为止,你的评级测试得分应该是 105 分(满分为 105)。
|
||||
|
||||
> 小挑战!在 JOS 中添加一个简单的聊天服务器,多个人可以连接到这个服务器上,并且任何用户输入的内容都被发送到其它用户。为实现它,你需要找到一个一次与多个套接字通讯的方法,并且在同一时间能够在同一个套接字上同时实现发送和接收。有多个方法可以达到这个目的。lwIP 为 `recv`(查看 `net/lwip/api/sockets.c` 中的 `lwip_recvfrom`)提供了一个 MSG_DONTWAIT 标志,以便于你不断地轮询所有打开的套接字。注意,虽然网络服务器的 IPC 支持 `recv` 标志,但是通过普通的 `read` 函数并不能访问它们,因此你需要一个方法来传递这个标志。一个更高效的方法是为每个连接去启动一个或多个环境,并且使用 IPC 去协调它们。而且碰巧的是,对于一个套接字,在结构 Fd 中找到的 lwIP 套接字 ID 是全局的(不是每个环境私有的),因此,比如一个 `fork` 的子环境继承了它的父环境的套接字。或者,一个环境通过构建一个包含了正确套接字 ID 的 Fd 就能够发送到另一个环境的套接字上。
|
||||
|
||||
> **问题 3**、由 JOS 的 web 服务器提供的 web 页面显示了什么?
|
||||
|
||||
.
|
||||
|
||||
> **问题 4**、你做这个实验大约花了多长的时间?
|
||||
|
||||
|
||||
**本实验到此结束了。**一如既往,不要忘了运行 `make grade` 并去写下你的答案和挑战问题的解决方案的描述。在你动手之前,使用 `git status` 和 `git diff` 去检查你的变更,并不要忘了去 `git add answers-lab6.txt`。当你完成之后,使用 `git commit -am 'my solutions to lab 6’` 去提交你的变更,然后 `make handin` 并关注它的动向。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://pdos.csail.mit.edu/6.828/2018/labs/lab6/
|
||||
|
||||
作者:[csail.mit][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://pdos.csail.mit.edu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://wiki.qemu.org/download/qemu-doc.html#Using-the-user-mode-network-stack
|
||||
[2]: http://www.wireshark.org/
|
||||
[3]: http://www.sics.se/~adam/lwip/
|
||||
[4]: https://pdos.csail.mit.edu/6.828/2018/labs/lab6/ns.png
|
||||
[5]: https://pdos.csail.mit.edu/6.828/2018/readings/hardware/8254x_GBe_SDM.pdf
|
||||
[6]: https://pdos.csail.mit.edu/6.828/2018/labs/lab6/e1000_hw.h
|
||||
[7]: http://pdos.csail.mit.edu/papers/exo:tocs.pdf
|
||||
@@ -0,0 +1,111 @@
|
||||
怎样如软件工程师一样组织知识
|
||||
==========
|
||||
|
||||
总体上说,软件开发和技术是以非常快的速度发展的领域,所以持续学习是必不可少的。在互联网上花几分钟找一下,在 Twitter、媒体、RSS 订阅、Hacker News 和其它专业网站和社区等地方,就可以从文章、案例研究、教程、代码片段、新应用程序和信息中找到大量有用的信息。
|
||||
|
||||
保存和组织所有这些信息可能是一项艰巨的任务。在这篇文章中,我将介绍一些我用来组织信息的工具。
|
||||
|
||||
我认为在知识管理方面非常重要的一点就是避免锁定在特定平台。我使用的所有工具都允许以标准格式(如 Markdown 和 HTML)导出数据。
|
||||
|
||||
请注意,我的流程并不完美,我一直在寻找新工具和方法来优化它。每个人都不同,所以对我有用的东西可能不适合你。
|
||||
|
||||
|
||||
### 用 NotionHQ 做知识库
|
||||
|
||||
对我来说,知识管理的基本部分是拥有某种个人知识库或维基。这是一个你可以以有组织的方式保存链接、书签、备注等的地方。
|
||||
|
||||
我使用 [NotionHQ][7] 做这件事。我使用它来记录各种主题,包括资源列表,如通过编程语言分组的优秀的库或教程,为有趣的博客文章和教程添加书签等等,不仅与软件开发有关,而且与我的个人生活有关。
|
||||
|
||||
我真正喜欢 NotionHQ 的是,创建新内容是如此简单。你可以使用 Markdown 编写它并将其组织为树状。
|
||||
|
||||
这是我的“开发”工作区的顶级页面:
|
||||
|
||||
[][8]
|
||||
|
||||
NotionHQ 有一些很棒的其他功能,如集成了电子表格/数据库和任务板。
|
||||
|
||||
如果您想认真使用 NotionHQ,您将需要订阅付费个人计划,因为免费计划有所限制。我觉得它物有所值。NotionHQ 允许将整个工作区导出为 Markdown 文件。导出功能存在一些重要问题,例如丢失页面层次结构,希望 Notion 团队可以改进这一点。
|
||||
|
||||
作为一个免费的替代方案,我可能会使用 [VuePress][9] 或 [GitBook][10] 来托管我自己的知识库。
|
||||
|
||||
### 用 Pocket 保存感兴趣的文章
|
||||
|
||||
[Pocket][11] 是我最喜欢的应用之一!使用 Pocket,您可以创建一个来自互联网上的文章的阅读列表。每当我看到一篇看起来很有趣的文章时,我都会使用 Chrome 扩展程序将其保存到 Pocket。稍后,我会阅读它,如果我发现它足够有用,我将使用 Pocket 的“存档”功能永久保存该文章并清理我的 Pocket 收件箱。
|
||||
|
||||
我尽量保持这个阅读清单足够小,并存档我已经处理过的信息。Pocket 允许您标记文章,以便以后更轻松地搜索特定主题的文章。
|
||||
|
||||
如果原始网站消失,您还可以在 Pocket 服务器中保存文章的副本,但是您需要 Pocket Premium 订阅计划。
|
||||
|
||||
Pocket 还具有“发现”功能,根据您保存的文章推荐类似的文章。这是找到可以阅读的新内容的好方法。
|
||||
|
||||
### 用 SnippetStore 做代码片段管理
|
||||
|
||||
从 GitHub 到 Stack Overflow 的答案,到博客文章,经常能找到一些你想要保存备用的好代码片段。它可能是一些不错的算法实现、一个有用的脚本或如何在某种语言中执行某种操作的示例。
|
||||
|
||||
我尝试了很多应用程序,从简单的 GitHub Gists 到 [Boostnote][12],直到我发现 [SnippetStore][13]。
|
||||
|
||||
SnippetStore 是一个开源的代码片段管理应用。SnippetStore 与其他产品的区别在于其简单性。您可以按语言或标签整理片段,并且可以拥有多个文件片段。它不完美,但是可以用。例如,Boostnote 具有更多功能,但我更喜欢 SnippetStore 组织内容的简单方法。
|
||||
|
||||
对于我每天使用的缩写和片段,我更喜欢使用我的编辑器 / IDE 的代码片段功能,因为它更便于使用。我使用 SnippetStore 更像是作为编码示例的参考。
|
||||
|
||||
[Cacher][14] 也是一个有趣的选择,因为它与许多编辑器进行了集成,他有一个命令行工具,并使用 GitHub Gists 作为后端,但其专业计划为 6 美元/月,我觉这有点太贵。
|
||||
|
||||
### 用 DevHints 管理速查表
|
||||
|
||||
[Devhints][15] 是由 Rico Sta. Cruz 创建的一个速查表集合。它是开源的,是用 Jekyll 生成的,Jekyll 是最受欢迎的静态站点生成器之一。
|
||||
|
||||
这些速查表是用 Markdown 编写的,带有一些额外的格式化支持,例如支持列。
|
||||
|
||||
我非常喜欢其界面的外观,并且不像可以在 [Cheatography][16] 等网站上找到 PDF 或图像格式的速查表, Markdown 非常容易添加新内容并保持更新和进行版本控制。
|
||||
|
||||
因为它是开源,我创建了自己的分叉版本,删除了一些我不需要的速查表,并添加了更多。
|
||||
|
||||
我使用速查表作为如何使用某些库或编程语言或记住一些命令的参考。速查表的单个页面非常方便,例如,可以列出特定编程语言的所有基本语法。
|
||||
|
||||
我仍在尝试这个工具,但到目前为止它的工作很好。
|
||||
|
||||
### Diigo
|
||||
|
||||
[Diigo][17] 允许您注释和突出显示部分网站。我在研究新东西时使用它来注释重要信息,或者从文章、Stack Overflow 答案或来自 Twitter 的鼓舞人心的引语中保存特定段落!;)
|
||||
|
||||
* * *
|
||||
|
||||
就这些了。某些工具的功能方面可能存在一些重叠,但正如我在开始时所说的那样,这是一个不断演进的工作流程,因为我一直在尝试和寻找改进和提高工作效率的方法。
|
||||
|
||||
你呢?是如何组织你的知识的?请随时在下面发表评论。
|
||||
|
||||
谢谢你的阅读。
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
作者简介:Bruno Paz,Web 工程师,专精 #PHP 和 @Symfony 框架。热心于新技术。喜欢运动,@FCPorto 的粉丝!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://dev.to/brpaz/how-do-i-organize-my-knowledge-as-a-software-engineer-4387
|
||||
|
||||
作者:[Bruno Paz][a]
|
||||
选题:[oska874](https://github.com/oska874)
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://brunopaz.net/
|
||||
[1]:https://dev.to/brpaz
|
||||
[2]:http://twitter.com/brunopaz88
|
||||
[3]:http://github.com/brpaz
|
||||
[4]:https://dev.to/t/knowledge
|
||||
[5]:https://dev.to/t/learning
|
||||
[6]:https://dev.to/t/development
|
||||
[7]:https://www.notion.so/
|
||||
[8]:https://res.cloudinary.com/practicaldev/image/fetch/s--uMbaRUtu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://i.imgur.com/kRnuvMV.png
|
||||
[9]:https://vuepress.vuejs.org/
|
||||
[10]:https://www.gitbook.com/?t=1
|
||||
[11]:https://getpocket.com/
|
||||
[12]:https://boostnote.io/
|
||||
[13]:https://github.com/ZeroX-DG/SnippetStore
|
||||
[14]:https://www.cacher.io/
|
||||
[15]:https://devhints.io/
|
||||
[16]:https://cheatography.com/
|
||||
[17]:https://www.diigo.com/index
|
||||
@@ -0,0 +1,122 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "Auk7F7"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: subject: "Arch-Audit : A Tool To Check Vulnerable Packages In Arch Linux"
|
||||
[#]: via: "https://www.2daygeek.com/arch-audit-a-tool-to-check-vulnerable-packages-in-arch-linux/"
|
||||
[#]: author: "Prakash Subramanian https://www.2daygeek.com/author/prakash/"
|
||||
[#]: url: "https://linux.cn/article-10473-1.html"
|
||||
|
||||
Arch-Audit:一款在 Arch Linux 上检查易受攻击的软件包的工具
|
||||
======
|
||||
|
||||
我们必须经常更新我们的系统以减少宕机时间和问题。每月给系统打一次补丁,60 天一次或者最多 90 天一次,这是 Linux 管理员的例行任务之一。这是忙碌的工作计划,我们不能在不到一个月内做到这一点,因为它涉及到多种活动和环境。
|
||||
|
||||
基本上,基础设施会一同提供测试、开发、 QA 环境(即各个分段和产品)。
|
||||
|
||||
最初,我们会在测试环境中部署补丁,相应的团队将监视系统一周,然后他们将给出一份或好或坏的状态的报告。如果成功的话,我们将会在其他环境中继续测试,若正常运行,那么最后我们会给生产服务器打上补丁。
|
||||
|
||||
许多组织会对整个系统打上补丁,我的意思是全系统更新,对于典型基础设施这是一种常规修补计划。
|
||||
|
||||
某些基础设施中可能只有生产环境,因此,我们不应该做全系统更新,而是应该使用安全修补程序来使系统更加稳定和安全。
|
||||
|
||||
由于 Arch Linux 及其衍生的发行版属于滚动更新版本,因此可以认为它们始终是最新的,因为它使用上游软件包的最新版本。
|
||||
|
||||
在某些情况下,如果要单独更新安全修补程序,则必须使用 arch-audit 工具来标识和修复安全修补程序。
|
||||
|
||||
### 漏洞是什么?
|
||||
|
||||
漏洞是软件程序或硬件组件(固件)中的安全漏洞。这是一个可以让它容易受到攻击的缺陷。
|
||||
|
||||
为了缓解这种情况,我们需要相应地修补漏洞,就像应用程序/硬件一样,它可能是代码更改或配置更改或参数更改。
|
||||
|
||||
### Arch-Audit 工具是什么?
|
||||
|
||||
[Arch-audit][1] 是一个类似于 Arch Linux 的 pkg-audit 工具。它使用了令人称赞的 Arch 安全小组收集的数据。它不会扫描以发现系统中易受攻击的包(就像 `yum –security check-update & yum updateinfo` 一样列出可用的软件包),它只需解析 <https://security.archlinux.org/> 页面并在终端中显示结果,因此,它将显示准确的数据。(LCTT 译注:此处原作者叙述不清晰。该功能虽然不会像病毒扫描软件一样扫描系统上的文件,但是会读取已安装的软件列表,并据此查询上述网址列出风险报告。)
|
||||
|
||||
Arch 安全小组是一群以跟踪 Arch Linux 软件包的安全问题为目的的志愿者。所有问题都在 Arch 安全追踪者的监视下。
|
||||
|
||||
该小组以前被称为 Arch CVE 监测小组,Arch 安全小组的使命是为提高 Arch Linux 的安全性做出贡献。
|
||||
|
||||
### 如何在 Arch Linux 上安装 Arch-Audit 工具
|
||||
|
||||
Arch-audit 工具已经存在社区的仓库中,所以你可以使用 Pacman 包管理器来安装它。
|
||||
|
||||
```
|
||||
$ sudo pacman -S arch-audit
|
||||
```
|
||||
|
||||
运行 `arch-audit` 工具以查找在基于 Arch 的发行版本上的存在缺陷的包。
|
||||
|
||||
```
|
||||
$ arch-audit
|
||||
Package cairo is affected by CVE-2017-7475. Low risk!
|
||||
Package exiv2 is affected by CVE-2017-11592, CVE-2017-11591, CVE-2017-11553, CVE-2017-17725, CVE-2017-17724, CVE-2017-17723, CVE-2017-17722. Medium risk!
|
||||
Package libtiff is affected by CVE-2018-18661, CVE-2018-18557, CVE-2017-9935, CVE-2017-11613. High risk!. Update to 4.0.10-1!
|
||||
Package openssl is affected by CVE-2018-0735, CVE-2018-0734. Low risk!
|
||||
Package openssl-1.0 is affected by CVE-2018-5407, CVE-2018-0734. Low risk!
|
||||
Package patch is affected by CVE-2018-6952, CVE-2018-1000156. High risk!. Update to 2.7.6-7!
|
||||
Package pcre is affected by CVE-2017-11164. Low risk!
|
||||
Package systemd is affected by CVE-2018-6954, CVE-2018-15688, CVE-2018-15687, CVE-2018-15686. Critical risk!. Update to 239.300-1!
|
||||
Package unzip is affected by CVE-2018-1000035. Medium risk!
|
||||
Package webkit2gtk is affected by CVE-2018-4372. Critical risk!. Update to 2.22.4-1!
|
||||
```
|
||||
|
||||
上述结果显示了系统的脆弱性风险状况,比如:低、中和严重三种情况。
|
||||
|
||||
若要仅显示易受攻击的包及其版本,请执行以下操作。
|
||||
|
||||
```
|
||||
$ arch-audit -q
|
||||
cairo
|
||||
exiv2
|
||||
libtiff>=4.0.10-1
|
||||
openssl
|
||||
openssl-1.0
|
||||
patch>=2.7.6-7
|
||||
pcre
|
||||
systemd>=239.300-1
|
||||
unzip
|
||||
webkit2gtk>=2.22.4-1
|
||||
```
|
||||
|
||||
仅显示已修复的包。
|
||||
|
||||
```
|
||||
$ arch-audit --upgradable --quiet
|
||||
libtiff>=4.0.10-1
|
||||
patch>=2.7.6-7
|
||||
systemd>=239.300-1
|
||||
webkit2gtk>=2.22.4-1
|
||||
```
|
||||
|
||||
为了交叉检查上述结果,我将测试在 <https://www.archlinux.org/packages/> 列出的一个包以确认漏洞是否仍处于开放状态或已修复。是的,它已经被修复了,并于昨天在社区仓库中发布了更新后的包。
|
||||
|
||||
![][3]
|
||||
|
||||
仅打印包名称和其相关的 CVE。
|
||||
|
||||
```
|
||||
$ arch-audit -uf "%n|%c"
|
||||
libtiff|CVE-2018-18661,CVE-2018-18557,CVE-2017-9935,CVE-2017-11613
|
||||
patch|CVE-2018-6952,CVE-2018-1000156
|
||||
systemd|CVE-2018-6954,CVE-2018-15688,CVE-2018-15687,CVE-2018-15686
|
||||
webkit2gtk|CVE-2018-4372
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/arch-audit-a-tool-to-check-vulnerable-packages-in-arch-linux/
|
||||
|
||||
作者:[Prakash Subramanian][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Auk7F7](https://github.com/Auk7F7)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.2daygeek.com/author/prakash/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/ilpianista/arch-audit
|
||||
[2]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[3]: https://www.2daygeek.com/wp-content/uploads/2018/11/A-Tool-To-Check-Vulnerable-Packages-In-Arch-Linux.png
|
||||
@@ -0,0 +1,89 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (Turn an old Linux desktop into a home media center)
|
||||
[#]: via: (https://opensource.com/article/18/11/old-linux-desktop-new-home-media-center)
|
||||
[#]: author: ([Alan Formy-Duval](https://opensource.com/users/alanfdoss))
|
||||
[#]: url: (https://linux.cn/article-10446-1.html)
|
||||
|
||||
将旧的 Linux 台式机变成家庭媒体中心
|
||||
======
|
||||
|
||||
> 重新利用过时的计算机来浏览互联网并在大屏电视上观看视频。
|
||||
|
||||

|
||||
|
||||
我第一次尝试搭建一台“娱乐电脑”是在 20 世纪 90 年代后期,使用了一台带 Trident ProVidia 9685 PCI 显卡的普通旧台式电脑。我使用了所谓的“电视输出”卡,它有一个额外的输出可以连接到标准电视端子上。屏幕显示看起来不太好,而且没有音频输出。并且外观很丑:有一条 S-Video 线穿过了客厅地板连接到我的 19 英寸 Sony Trinitron CRT 电视机上。
|
||||
|
||||
我在 Linux 和 Windows 98 上得到了同样令人遗憾的结果。在和那些看起来不对劲的系统挣扎之后,我放弃了几年。值得庆幸的是,如今的 HDMI 拥有更好的性能和标准化的分辨率,这使得廉价的家庭媒体中心成为现实。
|
||||
|
||||
我的新媒体中心娱乐电脑实际上是我的旧 Ubuntu Linux 桌面,最近我用更快的电脑替换了它。这台电脑在工作中太慢,但是它的 3.4GHz 的 AMD Phenom II X4 965 处理器和 8GB 的 RAM 足以满足一般浏览和视频流的要求。
|
||||
|
||||
以下是我让旧系统在新角色中发挥最佳性能所采取的步骤。
|
||||
|
||||
### 硬件
|
||||
|
||||
首先,我移除了不必要的设备,包括读卡器、硬盘驱动器、DVD 驱动器和后置 USB 卡,我添加了一块 PCI-Express 无线网卡。我将 Ubuntu 安装到单个固态硬盘 (SSD) 上,这可以切实提高任何旧系统的性能。
|
||||
|
||||
### BIOS
|
||||
|
||||
在 BIOS 中,我禁用了所有未使用的设备,例如软盘和 IDE 驱动器控制器。我禁用了板载显卡,因为我安装了带 HDMI 输出的 NVidia GeForce GTX 650 PCI Express 显卡。我还禁用了板载声卡,因为 NVidia 显卡芯片组提供音频。
|
||||
|
||||
### 音频
|
||||
|
||||
Nvidia GeForce GTX 音频设备在 GNOME 控制中心的声音设置中被显示为 GK107 HDMI Audio Controller,因此单条 HDMI 线缆可同时处理音频和视频。无需将音频线连接到板载声卡的输出插孔。
|
||||
|
||||
![Sound settings screenshot][2]
|
||||
|
||||
*GNOME 音频设置中的 HDMI 音频控制器。*
|
||||
|
||||
### 键盘和鼠标
|
||||
|
||||
我有罗技的无线键盘和鼠标。当我安装它们时,我插入了两个外置 USB 接收器,它们可以使用,但我经常遇到信号反应问题。接着我发现其中一个被标记为联合接收器,这意味着它可以自己处理多个罗技输入设备。罗技不提供在 Linux 中配置联合接收器的软件。但幸运的是,有个开源程序 [Solaar][3] 能够做到。使用单个接收器解决了我的输入性能问题。
|
||||
|
||||
![Solaar][5]
|
||||
|
||||
*Solaar 联合接收器界面。*
|
||||
|
||||
### 视频
|
||||
|
||||
最初很难在我的 47 英寸平板电视上阅读文字,所以我在 Universal Access 下启用了“大文字”。我下载了一些与电视 1920x1080 分辨率相匹配的壁纸,这看起来很棒!
|
||||
|
||||
### 最后处理
|
||||
|
||||
我需要在电脑的冷却需求和我对不受阻碍的娱乐的渴望之间取得平衡。由于这是一台标准的 ATX 微型塔式计算机,我确保我有足够的风扇转速,以及在 BIOS 中精心配置过的温度以减少噪音。我还把电脑放在我的娱乐控制台后面,以进一步减少风扇噪音,但同时我可以按到电源按钮。
|
||||
|
||||
最后得到一台简单的、没有巨大噪音的机器,而且只使用了两根线缆:交流电源线和 HDMI。它应该能够运行任何主流或专门的媒体中心 Linux 发行版。我不期望去玩高端的游戏,因为这可能需要更多的处理能力。
|
||||
|
||||
![Showing Ubuntu Linux About page onscreen][7]
|
||||
|
||||
*Ubuntu Linux 的关于页面。*
|
||||
|
||||
![YouTube on the big screen][9]
|
||||
|
||||
*在大屏幕上测试 YouTube 视频。*
|
||||
|
||||
我还没安装像 [Kodi][10] 这样专门的媒体中心发行版。截至目前,它运行的是 Ubuntu Linux 18.04.1 LTS,而且很稳定。
|
||||
|
||||
这是一个有趣的挑战,可以充分利用我已经拥有的东西,而不是购买新的硬件。这只是开源软件的一个好处。最终,我可能会用一个更小,更安静的带有媒体中心的系统或其他小机顶盒替换它,但是现在,它很好地满足了我的需求。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/11/old-linux-desktop-new-home-media-center
|
||||
|
||||
作者:[Alan Formy-Duval][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/alanfdoss
|
||||
[b]: https://github.com/lujun9972
|
||||
[2]: https://opensource.com/sites/default/files/uploads/soundsettings.png (Sound settings screenshot)
|
||||
[3]: https://pwr.github.io/Solaar/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/solaar_interface.png (Solaar)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/finalresult1.png (Showing Ubuntu Linux About page onscreen)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/finalresult2.png (YouTube on the big screen)
|
||||
[10]: https://kodi.tv/
|
||||
@@ -0,0 +1,88 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (How to bring good fortune to your Linux terminal)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-fortune)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
[#]: url: (https://linux.cn/article-10486-1.html)
|
||||
|
||||
如何为你的 Linux 终端带来好运
|
||||
======
|
||||
> 使用 fortune 实用程序将名言和俏皮话带到命令行。
|
||||
|
||||

|
||||
|
||||
这是 12 月,如果你还没有找到一款能激发你灵感的[科技降临节日历][1],那么,也许这个系列可以。从现在到 24 日,每天我们都会为你带来一个不同的 Linux 命令行玩具。你可能会问,什么是命令行玩具?它可能是一个游戏或任何简单的娱乐程序,为你的终端带来一点点快乐。
|
||||
|
||||
你可能之前已经看过其中的一些,我们希望你也能发现一些新的东西。不管怎样,我们都希望你在关注时保有乐趣。
|
||||
|
||||
今天的玩具是 `fortune`,它很古老。它的版本可以追溯到 1980 年,当时它包含在 Unix 中。我在 Fedora 中安装的版本是在 BSD 许可下提供的,我可以使用以下命令获取它。(LCTT 译注:fortune 这个命令得名于 fortune cookies,是流行于西方的中餐馆的一种脆饼干,里面包含格言、幸运数字等。)
|
||||
|
||||
```
|
||||
$ sudo dnf install fortune-mod -y
|
||||
```
|
||||
|
||||
你的发行版可能会有所不同。在某些情况下,你可能需要在 `fortune` 命令之外单独安装那些“幸运饼干”(尝试在你的包管理器中搜索 “fortunes”)。你还可以在 [GitHub][2] 上查看它的源代码,然后,只需运行 `fortune` 即可获得好运。
|
||||
|
||||
```
|
||||
$ fortune
|
||||
"Time is an illusion. Lunchtime doubly so."
|
||||
-- Ford Prefect, _Hitchhiker's Guide to the Galaxy_
|
||||
```
|
||||
|
||||
那么,你为什么会在终端上需要 `fortune` 呢?当然是为了好玩啦。也许你想将它们添加到系统上的每天消息(motd)中?
|
||||
|
||||
就我个人而言,当我使用终端来解析文本时,我喜欢使用 `fortune` 命令作为一段内置的虚拟数据,特别是使用[正则表达式][3]时,我想要一些简单的东西来尝试一下。
|
||||
|
||||
例如,假设我使用 `tr` 命令来测试转换,用数字 3 替换字母 e。
|
||||
|
||||
```
|
||||
$ fortune | tr 'eE' '3'
|
||||
Unix 3xpr3ss:
|
||||
All pass3ng3r bring a pi3c3 of th3 a3roplan3 and a box of tools with th3m to
|
||||
th3 airport. Th3y gath3r on th3 tarmac, arguing constantly about what kind
|
||||
of plan3 th3y want to build and how to put it tog3th3r. 3v3ntually, th3
|
||||
pass3ng3rs split into groups and build s3v3ral diff3r3nt aircraft, but giv3
|
||||
th3m all th3 sam3 nam3. Som3 pass3ng3rs actually r3ach th3ir d3stinations.
|
||||
All pass3ng3rs b3li3v3 th3y got th3r3.
|
||||
```
|
||||
|
||||
那么你的发行版带来了什么幸运饼干呢?看看你的 `/usr/share/games/fortune` 目录,找到它们。以下我最喜欢的几个。
|
||||
|
||||
```
|
||||
Never laugh at live dragons.
|
||||
-- Bilbo Baggins [J.R.R. Tolkien, "The Hobbit"]
|
||||
|
||||
I dunno, I dream in Perl sometimes...
|
||||
-- Larry Wall in <8538@jpl-devvax.JPL.NASA.GOV>
|
||||
|
||||
I have an existential map. It has "You are here" written all over it.
|
||||
-- Steven Wright
|
||||
```
|
||||
|
||||
关于 `fortune` 想要了解更多?当然,你可以经常查看 man 页来了解更多选项,或者在[维基百科][4]上阅读更多关于此命令的历史信息。
|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。请在评论区留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
看看昨天的玩具:[驾驶火车头通过你的 Linux 终端][5]。记得明天再来!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-fortune
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/16/11/7-tech-advent-calendars-holiday-season
|
||||
[2]: https://github.com/shlomif/fortune-mod
|
||||
[3]: https://opensource.com/article/18/5/getting-started-regular-expressions
|
||||
[4]: https://en.wikipedia.org/wiki/Fortune_%28Unix%29
|
||||
[5]: https://opensource.com/article/18/12/linux-toy-sl
|
||||
@@ -0,0 +1,106 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10409-1.html)
|
||||
[#]: subject: (How To Boot Into Rescue Mode Or Emergency Mode In Ubuntu 18.04)
|
||||
[#]: via: (https://www.ostechnix.com/how-to-boot-into-rescue-mode-or-emergency-mode-in-ubuntu-18-04/)
|
||||
[#]: author: (SK https://www.ostechnix.com/author/sk/)
|
||||
|
||||
如何在 Ubuntu 18.04 中启动到救援模式或紧急模式
|
||||
======
|
||||
|
||||

|
||||
|
||||
正如你可能已经知道的那样,**运行级别** 在许多最近的 Linux 发行版(如 RHEL 7 和 Ubuntu 16.04 LTS)中被 **systemd 的目标** 替换。有关它们的更多详细信息,请参阅[这个指南][1]。在这个简短的教程中,我们将看到如何启动**救援模式**以及**紧急模式**。本指南在 Ubuntu 18.04 LTS 中进行了测试,但是下面给出的步骤适用于大多数使用 systemd 作为默认服务管理器的 Linux 发行版。在进一步讨论之前,让我澄清什么是救援模式和紧急模式以及这两种模式的目的是什么。
|
||||
|
||||
### 什么是救援模式?
|
||||
|
||||
**救援模式**相当于使用 **SysV** 作为默认的服务管理器的 Linux 发行版中的 **单用户模式**。在救援模式下,将挂载所有本地文件系统,仅启动一些重要服务。但是,不会启动正常服务(例如网络服务)。救援模式在系统无法正常启动的情况下很有用。此外,我们可以在救援模式下执行一些重要的救援操作,例如[重置 root 密码][2]。
|
||||
|
||||
### 什么是紧急模式?
|
||||
|
||||
与救援模式相比,在**紧急模式**中不启动任何东西。没有服务启动、没有挂载点、没有建立套接字,什么也没有。你所拥有的只是一个**原始的 shell**。紧急模式适用于调试目的。
|
||||
|
||||
### 在 Ubuntu 18.04 LTS 中进入救援模式
|
||||
|
||||
启动你的 Ubuntu 系统。出现 Grub 菜单时,选择第一条并按下 `e` 进行编辑。
|
||||
|
||||

|
||||
|
||||
如果你没有看到 Grub 菜单,只需在 BIOS 的 logo 消失后立即按下 `ESC` 键。
|
||||
|
||||
找到以单词 `linux` 开头的行,并在该行的末尾添加以下内容(要到达末尾,只需按下 `CTRL+e` 或使用 `END` 键或左右箭头键):
|
||||
|
||||
```
|
||||
systemd.unit=rescue.target
|
||||
```
|
||||
|
||||

|
||||
|
||||
添加完成后,只需按下 `CTRL+x` 或 `F10` 即可继续启动救援模式。几秒钟后,你将以 root 用户身份进入救援模式(单用户模式)。以下是 Ubuntu 18.04 LTS 服务器版中救援模式的样子:
|
||||
|
||||

|
||||
|
||||
接下来,输入以下命令将根 (`/`) 文件系统重新挂载成读/写模式。
|
||||
|
||||
```
|
||||
mount -n -o remount,rw /
|
||||
```
|
||||
|
||||
### 启动到紧急模式
|
||||
|
||||
将 Ubuntu 引导到紧急模式与上述方法相同。你只需在编辑 Grub 菜单时将 `systemd.unit=rescue.target` 替换为 `systemd.unit=emergency.target` 即可。
|
||||
|
||||
![emergency mode][4]
|
||||
|
||||
添加 `systemd.unit=emergency.target` 后,按下 `Ctrl+x` 或 `F10` 继续启动到紧急模式。
|
||||
|
||||

|
||||
|
||||
最后,你可以使用以下命令将根文件系统重新挂载成读/写模式:
|
||||
|
||||
```
|
||||
mount -n -o remount,rw /
|
||||
```
|
||||
|
||||
### 在救援模式和紧急模式之间切换
|
||||
|
||||
如果你处于救援模式,则不必像上面提到的那样编辑 Grub 条目。相反,只需输入以下命令即可立即切换到紧急模式:
|
||||
|
||||
```
|
||||
systemctl emergency
|
||||
```
|
||||
|
||||
同样,要从紧急模式切换到救援模式,请输入:
|
||||
|
||||
```
|
||||
systemctl rescue
|
||||
```
|
||||
|
||||
你现在知道了什么是救援模式和紧急模式以及如何在 Ubuntu 18.04 中启动这些模式。就像我已经提到的,这里提供的步骤将适用于许多使用 systemd 的 Linux 版本。
|
||||
|
||||
就是这些了。希望这篇文章有用。
|
||||
|
||||
还有更多好东西。敬请期待!
|
||||
|
||||
干杯!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-boot-into-rescue-mode-or-emergency-mode-in-ubuntu-18-04/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.ostechnix.com/check-runlevel-linux/
|
||||
[2]: https://www.ostechnix.com/how-to-reset-or-recover-root-user-password-in-linux/
|
||||
[3]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[4]: http://www.ostechnix.com/wp-content/uploads/2018/12/emergency-mode.png
|
||||
@@ -0,0 +1,135 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10495-1.html)
|
||||
[#]: subject: (Plan your own holiday calendar at the Linux command line)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-cal)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
在 Linux 命令行中规划你的假期日历
|
||||
======
|
||||
|
||||
> 将命令链接在一起,构建一个彩色日历,然后在暴风雪中将其拂去。
|
||||
|
||||

|
||||
|
||||
欢迎阅读今天推出的 Linux 命令行玩具降临日历。如果这是你第一次访问本系列,你可能会问:什么是命令行玩具。即使我不太确定,但一般来说,它可以是一个游戏或任何简单的娱乐,可以帮助你在终端玩得开心。
|
||||
|
||||
很可能你们中的一些人之前已经看过我们日历上的各种选择,但我们希望给每个人至少一件新东西。
|
||||
|
||||
我们在没有创建实际日历的情况下完成了本系列的第 7 天,所以今天让我们使用命令行工具来做到这一点:`cal`。就其本身而言,`cal` 可能不是最令人惊奇的工具,但我们可以使用其它一些实用程序来为它增添一些趣味。
|
||||
|
||||
很可能,你的系统上已经安装了 `cal`。要使用它,只需要输入 `cal` 即可。
|
||||
|
||||
```
|
||||
$ cal
|
||||
December 2018
|
||||
Su Mo Tu We Th Fr Sa
|
||||
1
|
||||
2 3 4 5 6 7 8
|
||||
9 10 11 12 13 14 15
|
||||
16 17 18 19 20 21 22
|
||||
23 24 25 26 27 28 29
|
||||
30 31
|
||||
```
|
||||
|
||||
我们不打算在本文中深入介绍高级用法,因此如果你想了解有关 `cal` 的更多信息,查看 Opensouce.com 社区版主 Don Watkin 的优秀文章 [date 和 cal 命令概述][1]。
|
||||
|
||||
现在,让我们用一个漂亮的盒子来为它增添趣味,就像我们在上一篇 Linux 玩具文章中介绍的那样。我将使用钻石块,用一点内边距来对齐。
|
||||
|
||||
|
||||
```
|
||||
$ cal | boxes -d diamonds -p a1l4t2
|
||||
/\ /\ /\
|
||||
/\//\\/\ /\//\\/\ /\//\\/\
|
||||
/\//\\\///\\/\//\\\///\\/\//\\\///\\/\
|
||||
//\\\//\/\\///\\\//\/\\///\\\//\/\\///\\
|
||||
\\//\/ \/\\//
|
||||
\/ \/
|
||||
/\ December 2018 /\
|
||||
//\\ Su Mo Tu We Th Fr Sa //\\
|
||||
\\// 1 \\//
|
||||
\/ 2 3 4 5 6 7 8 \/
|
||||
/\ 9 10 11 12 13 14 15 /\
|
||||
//\\ 16 17 18 19 20 21 22 //\\
|
||||
\\// 23 24 25 26 27 28 29 \\//
|
||||
\/ 30 31 \/
|
||||
/\ /\
|
||||
//\\/\ /\//\\
|
||||
\\///\\/\//\\\///\\/\//\\\///\\/\//\\\//
|
||||
\/\\///\\\//\/\\///\\\//\/\\///\\\//\/
|
||||
\/\\//\/ \/\\//\/ \/\\//\/
|
||||
\/ \/ \/
|
||||
```
|
||||
|
||||
看起来很不错,但是为了更规整,让我们把整个东西放到另一个盒子里,为了好玩,这次我们将使用卷轴式设计。
|
||||
|
||||
```
|
||||
cal | boxes -d diamonds -p a1t2l3 | boxes -a c -d scroll
|
||||
/ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \
|
||||
| /~~\ /~~\ |
|
||||
|\ \ | /\ /\ /\ | / /|
|
||||
| \ /| /\//\\/\ /\//\\/\ /\//\\/\ |\ / |
|
||||
| ~~ | /\//\\\///\\/\//\\\///\\/\//\\\///\\/\ | ~~ |
|
||||
| | //\\\//\/\\///\\\//\/\\///\\\//\/\\///\\ | |
|
||||
| | \\//\/ \/\\// | |
|
||||
| | \/ \/ | |
|
||||
| | /\ December 2018 /\ | |
|
||||
| | //\\ Su Mo Tu We Th Fr Sa //\\ | |
|
||||
| | \\// 1 \\// | |
|
||||
| | \/ 2 3 4 5 6 7 8 \/ | |
|
||||
| | /\ 9 10 11 12 13 14 15 /\ | |
|
||||
| | //\\ 16 17 18 19 20 21 22 //\\ | |
|
||||
| | \\// 23 24 25 26 27 28 29 \\// | |
|
||||
| | \/ 30 31 \/ | |
|
||||
| | /\ /\ | |
|
||||
| | //\\/\ /\//\\ | |
|
||||
| | \\///\\/\//\\\///\\/\//\\\///\\/\//\\\// | |
|
||||
| | \/\\///\\\//\/\\///\\\//\/\\///\\\//\/ | |
|
||||
| | \/\\//\/ \/\\//\/ \/\\//\/ | |
|
||||
| | \/ \/ \/ | |
|
||||
| | | |
|
||||
\ |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| /
|
||||
\ / \ /
|
||||
~~~ ~~~
|
||||
```
|
||||
|
||||
完美。现在,这事有点小激动了。我喜欢我们的设计,但我想更妙一些,所以我要给它上色。但是 Opensource.com 员工所在的北卡罗来版纳州罗利办公室,本周末很有可能下雪。所以,让我们享受彩色降临日历,然后用雪擦掉它。
|
||||
|
||||
关于雪,我抓取了一些 Bash 和 Gawk 的漂亮[代码片段][2],幸亏我发现了 CLIMagic。如果你不熟悉 CLIMagic,去查看他们的[网站][3],在 [Twitter][4] 上关注他们。你会满意的。
|
||||
|
||||
我们开始吧。让我们清除屏幕,扔掉四四方方的日历,给它上色,等几秒钟,然后用暴风雪把它吹走。这些在终端可以用一行命令完成。
|
||||
|
||||
```
|
||||
$ clear;cal|boxes -d diamonds -p a1t2l3|boxes -a c -d scroll|lolcat;sleep 3;while :;do echo $LINES $COLUMNS $(($RANDOM%$COLUMNS)) $(printf "\u2744\n");sleep 0.1;done|gawk '{a[$3]=0;for(x in a) {o=a[x];a[x]=a[x]+1;printf "\033[%s;%sH ",o,x;printf "\033[%s;%sH%s \033[0;0H",a[x],x,$4;}}'
|
||||
```
|
||||
|
||||
大功告成。
|
||||
|
||||

|
||||
|
||||
要使它在你的系统上工作,你需要所有它引用的实用程序(`box`、`lolcat`、`gawk` 等),还需要使用支持 Unicode 的终端仿真器。
|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。请在评论区留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
看看昨天的玩具:[使用 Nyan Cat 在 Linux 命令行休息][5]。记得明天再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-cal
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/16/12/using-calendar-function-linux
|
||||
[2]: http://climagic.org/coolstuff/let-it-snow.html
|
||||
[3]: http://climagic.org/
|
||||
[4]: https://twitter.com/climagic
|
||||
[5]: https://opensource.com/article/18/12/linux-toy-nyancat
|
||||
@@ -0,0 +1,54 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10447-1.html)
|
||||
[#]: subject: (Powers of two, powers of Linux: 2048 at the command line)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-2048)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
2 的威力,Linux 的威力:终端中的 2048
|
||||
======
|
||||
|
||||
> 正在寻找基于终端的游戏来打发时间么?来看看 2048-cli 吧。
|
||||
|
||||

|
||||
|
||||
你好,欢迎来到今天的 Linux 命令行玩具日历。每天,我们会为你的终端带来一个不同的玩具:它可能是一个游戏或任何简单的消遣,可以帮助你获得乐趣。
|
||||
|
||||
很可能你们中的一些人之前已经看过我们日历中的各种玩具,但我们希望每个人至少见到一件新事物。
|
||||
|
||||
今天的玩具是我最喜欢的休闲游戏之一 [2048][2] (它本身就是另外一个克隆品的克隆)的[命令行版本][1]。
|
||||
|
||||
要进行游戏,你只需将滑块向上、向下、向左、向右移动,组合成对的数字,并增加数值,直到你得到数字为 2048 的块。最吸引人的地方(以及挑战)是你不能只移动一个滑块,而是需要移动屏幕上的每一块。(LCTT 译注:不知道有没有人在我们 Linux 中国的网站上遇到过 404 页面?那就是一个 2048 游戏,经常我错误地打开一个不存在的页面时,本应该去修复这个问题,却不小心沉迷于其中……)
|
||||
|
||||
它简单、有趣,很容易在里面沉迷几个小时。这个 2048 的克隆 [2048-cli][1] 是 Marc Tiehuis 用 C 编写的,并在 MIT 许可下开源。你可以在 [GitHub][1] 上找到源代码,你也可在这找到适用于你的平台的安装说明。由于它已为 Fedora 打包,因此我来说,安装就像下面那样简单:
|
||||
|
||||
```
|
||||
$ sudo dnf install 2048-cli
|
||||
```
|
||||
|
||||
这是这样,玩得开心!
|
||||
|
||||

|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。如果你有特别想了解的可以评论留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
查看昨天的玩具,[在 Linux 终端中玩俄罗斯方块][3],记得明天再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-2048
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/tiehuis/2048-cli
|
||||
[2]: https://github.com/gabrielecirulli/2048
|
||||
[3]: https://opensource.com/article/18/12/linux-toy-tetris
|
||||
@@ -0,0 +1,174 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (LazyWolfLin)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10406-1.html)
|
||||
[#]: subject: (How to Update Ubuntu [Terminal & GUI Methods] It's FOSS)
|
||||
[#]: via: (https://itsfoss.com/update-ubuntu/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
初级:如何在终端及图形界面中更新 Ubuntu
|
||||
======
|
||||
|
||||
> 这篇教程将向你展示如何更新服务器版本或者桌面版本的 Ubuntu。它还解释了更新和升级之间的区别以及你应该了解的有关于 Ubuntu Linux 中的更新的一些其他内容。
|
||||
|
||||
如果你是一个新手并已经体验 Ubuntu 数天或几周,你可能想知道如何更新你的 [Ubuntu][1] 系统以获取安全补丁,错误修复和应用升级。
|
||||
|
||||
更新 Ubuntu 非常简单。我并不是瞎说。它简单得只要运行两个命令。让我来告诉你这两个命令的更多细节。
|
||||
|
||||
请注意,本教程适用于 Ubuntu 18.04、16.04 或任何其他版本。命令行方式也适用于基于 Ubuntu 的发行版如 Linux Mint、Linux Lite、elementary OS 等。
|
||||
|
||||
### 通过命令行更新 Ubuntu
|
||||
|
||||
![如何更新 Ubuntu][2]
|
||||
|
||||
在桌面上,打开终端。你可以在菜单里找到它或者使用 `Ctrl+Alt+T` [快捷键][3]。如果你是登录到一台 [Ubuntu 服务器][4],那你已经在访问一个终端了。
|
||||
|
||||
在终端里,你只需要使用以下命令:
|
||||
|
||||
```
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
```
|
||||
|
||||
它将询问你密码,而你可以使用你的账号密码。输入时,你将不会看到任何内容在屏幕上,所以请继续输入你的密码并按回车键。
|
||||
|
||||
现在,我来解释下上面的命令。
|
||||
|
||||
事实上,这不是一条命令。它由两条命令组成。符号 `&&` 是合并两条命令的一个方法,第二条命令仅在前一条命令执行成功时执行。
|
||||
|
||||
当命令 `apt upgrade` 要求你在安装更新前确认时,末尾的参数 `-y` 会自动输入 `yes`。
|
||||
|
||||
请注意,你也可以逐条使用这两条命令:
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt upgrade
|
||||
```
|
||||
|
||||
这将花费更长的时间,因为你必须等待第一条命令执行完成后才能输入第二条命令。
|
||||
|
||||
#### 说明:sudo apt update
|
||||
|
||||
这条命令更新了可用软件包的本地数据库。如果你没运行这条命令,本地数据库将不会被更新,而你的系统将不会知道是否有可用的新版本。
|
||||
|
||||
这就是为什么当你运行 `sudo apt update`,你会在输出中看到大量的 URL。这条命令会从对应的储存库(你在输出中看到的 URL)中获取软件包信息。
|
||||
|
||||
![更新 Ubuntu Linux][5]
|
||||
|
||||
在命令的末尾,它告诉你有多少个软件包可以被更新。你可以使用下列命令查看这些软件包:
|
||||
|
||||
```
|
||||
apt list --upgradable
|
||||
```
|
||||
|
||||
**补充阅读:** 阅读这篇文章了解[命令 apt update 的输出中的 Ign、Hit 和 Get 是什么][6]。
|
||||
|
||||
#### 说明:sudo apt upgrade
|
||||
|
||||
这条命令将已安装的软件包版本与本地数据库进行匹配。它收集全部信息,然后列出所有具有更新版本的软件包。此时,它会询问您是否要升级(已安装的软件包更新到新版本)。
|
||||
|
||||
![通过命令行更新 Ubuntu Linux][7]
|
||||
|
||||
你可以键入 `yes`、`y` 或者只敲回车键去确认安装这些更新。
|
||||
|
||||
所以总的来说,`sudo apt update` 会检查可用的新版本,而 `sudo apt upgrade` 实际上会执行更新。
|
||||
|
||||
命令 `update` 可能会令人困惑,因为你可能期望通过命令 `apt update` 安装更新来更新系统,但这并不会发生。
|
||||
|
||||
### 通过 GUI 更新 Ubuntu(适用于桌面用户)
|
||||
|
||||
如果你使用桌面版 Ubuntu,你并不需要为了更新系统而打开终端。你可以仍可以使用命令行更新,但这只是一个选择。
|
||||
|
||||
在菜单里,找到 “软件更新” 并运行它。
|
||||
|
||||
![在 Ubuntu 中运行 Software Updater][8]
|
||||
|
||||
它将检查你的系统是否有可用的更新。
|
||||
|
||||
![检查 Ubuntu 是否有可用更新][9]
|
||||
|
||||
如果有可用的更新,它将给你提供安装更新的选择。
|
||||
|
||||
![在 Ubuntu 中通过更新管理器安装更新][10]
|
||||
|
||||
现在,点击 “安装”,它可能会向你询问密码。
|
||||
|
||||
![通过 GUI 在 Ubuntu Linux 中安装更新][11]
|
||||
|
||||
一旦你输入你的密码,它将开始安装更新。
|
||||
|
||||
![通过 GUI 更新 Ubuntu][12]
|
||||
|
||||
在某些情况下,你可能需要重启系统才能使已安装的更新正常工作。如果需要重启系统,你将在更新结束时收到通知。
|
||||
|
||||
![通过 GUI 更新 Ubuntu][12]
|
||||
|
||||
如果你不希望马上重启你的系统,可以选择稍后重启。
|
||||
|
||||
![通过 GUI 在 Ubuntu 中安装更新][13]
|
||||
|
||||
提示:如果“软件更新”返回一个错误,你需要在终端是使用命令 `sudo apt update`。输出的最后几行将包含真正的错误信息。你可以在因特网上搜索该错误并解决问题。
|
||||
|
||||
### 更新 Ubuntu 时要记住几件事
|
||||
|
||||
你刚学习了如何更新你的 Ubuntu 系统。如果你感兴趣,你还需要了解一些关于 Ubuntu 更新的内容。
|
||||
|
||||
#### 更新后清理
|
||||
|
||||
你的系统将会有一些更新后不再需要的软件包。你可用使用这条命令删除这些软件包并[释放空间][14]:
|
||||
|
||||
```
|
||||
sudo apt autoremove
|
||||
```
|
||||
|
||||
#### 在 Ubuntu Server 中内核热修复以避免重启
|
||||
|
||||
如果是 Linux 内核更新,你将需要在系统更新后重启。当你不希望服务器停机时,这将会是一个问题。
|
||||
|
||||
[热修复][15]功能允许 Linux 内核在持续运行时打补丁。换句话说就是你不需要重启你的系统。
|
||||
|
||||
如果你在管理服务器,你可能需要[在 Ubuntu 中启用热修复][16]。
|
||||
|
||||
#### 版本升级是不同的
|
||||
|
||||
本文讨论的更新是使你安装的 Ubuntu 保持最新。但它不包括[版本升级][17](例如从 Ubuntu 16.04 升级到 18.04)。
|
||||
|
||||
[Ubuntu 版本][18] 升级完全是另一回事。它更新整个操作系统核心。你需要在这个漫长的过程开始前做好备份。
|
||||
|
||||
### 总结
|
||||
|
||||
我希望你喜欢这个关于 Ubuntu 系统更新的教程并学到一些新东西。
|
||||
|
||||
如果你有其他问题,请随时提出。如果你是一位经验丰富的 Linux 用户并且有些更好的技巧,请同我们分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/update-ubuntu/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[LazyWolfLin](https://github.com/LazyWolfLin)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.ubuntu.com/
|
||||
[2]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/how-to-update-ubuntu.png?resize=800%2C450&ssl=1
|
||||
[3]: https://itsfoss.com/ubuntu-shortcuts/
|
||||
[4]: https://www.ubuntu.com/download/server
|
||||
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/12/update-ubunt-1.jpeg?resize=800%2C357&ssl=1
|
||||
[6]: https://itsfoss.com/apt-get-linux-guide/
|
||||
[7]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/update-ubunt-2.jpeg?ssl=1
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/12/update-ubuntu-via-GUI-1.jpeg?resize=800%2C250&ssl=1
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/update-ubuntu-via-GUI-2.jpeg?resize=800%2C250&ssl=1
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/12/update-ubuntu-GUI-3.jpeg?resize=800%2C365&ssl=1
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/install-update-ubuntu-1.jpg?resize=800%2C450&ssl=1
|
||||
[12]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/12/installing-updates-ubuntu.jpg?ssl=1
|
||||
[13]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/installing-updates-ubuntu-2.jpeg?ssl=1
|
||||
[14]: https://itsfoss.com/free-up-space-ubuntu-linux/
|
||||
[15]: https://www.ubuntu.com/livepatch
|
||||
[16]: https://www.cyberciti.biz/faq/howto-live-patch-ubuntu-linux-server-kernel-without-rebooting/
|
||||
[17]: https://itsfoss.com/upgrade-ubuntu-version/
|
||||
[18]: https://itsfoss.com/how-to-know-ubuntu-unity-version/
|
||||
@@ -0,0 +1,158 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (FSSlc)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10414-1.html)
|
||||
[#]: subject: (McFly – A Replacement To ‘Ctrl+R’ Bash History Search Feature)
|
||||
[#]: via: (https://www.ostechnix.com/mcfly-a-replacement-to-ctrlr-bash-history-search-feature/)
|
||||
[#]: author: (SK https://www.ostechnix.com/author/sk/)
|
||||
|
||||
McFly:利用神经网络为 Bash 提供历史命令搜索功能
|
||||
======
|
||||
|
||||

|
||||
|
||||
假如你在命令行模式下渡过了很长时间,那么你必定使用过或者听说过 BASH 的 **反向搜索** 功能,在 Bash 中执行反向搜索功能的快捷键是 `Ctrl+r`。通过使用这个特性,我们可以找到我们执行过的命令而无需再次输入它们。当然,你可以使用上下键来搜索你的 bash 命令记录,但使用 `Ctrl+r` 快捷键可以让这个搜索过程更简单快速。今天我找寻到了 Bash 历史命令搜索特性 `Ctrl+r` 的一个替代品,它就是 McFly。McFly 是一个使用 Rust 编程语言写就的简洁工具,自带一个智能的搜索引擎,用来替换默认的 `Ctrl+r` 这个 Bash 历史命令搜索功能。 McFly 提供的命令建议都是通过一个小巧的 **神经网络** 来实时排序给出的。
|
||||
|
||||
McFly 重新绑定了 `Ctrl+r` 快捷键,可以从你的 Bash 历史命令中找到所有最近执行过的命令。它通过追溯下面的信息来增强你的 shell 历史命令搜索特性:
|
||||
|
||||
* 命令结束状态
|
||||
* 当你运行命令时的时间戳
|
||||
* 以及你运行命令的执行目录
|
||||
|
||||
它将所有追溯的信息保存在一个 SQLite 数据库中。由于它追溯了命令的历史结束状态,所以你可以很轻易地忽略掉失败的命令。听起来很酷,对吧?
|
||||
|
||||
在给出一个命令建议时,它将考虑如下因素:
|
||||
|
||||
* 你在哪个目录执行的这个命令,将来你很有可能在相同的目录重复这个命令
|
||||
* 在你执行这个命令之前,执行过什么命令
|
||||
* 你执行这个命令有多频繁
|
||||
* 你最后执行该命令的时间
|
||||
* 你是否在 McFly 中选择过这个命令
|
||||
* 以及这个命令的历史结束状态。因为你很有可能不会去执行失败过的命令,对吧?
|
||||
|
||||
McFly 维护着你的默认 Bash 历史文件,所以你可以随时停止使用它。McFly 也并不只服务于 BASH, 它也可以扩展到其他 shell 程序。
|
||||
|
||||
### 安装 McFly
|
||||
|
||||
在 Linux 中,McFly 可以使用 Linuxbrew 来安装。如若你还没有安装过 Linuxbrew,那么你可以参考下面的这个链接。(LCTT 译注:从其 [GitHub 主页](https://github.com/cantino/mcfly)了解到也可以下载其二进制来使用。)
|
||||
|
||||
- [Linuxbrew:一个用于 Linux 和 Mac OS X 的通用包管理][1]
|
||||
|
||||
一旦安装好了 Linuxbrew,运行下面的命令来安装 McFly:
|
||||
|
||||
```
|
||||
$ brew tap cantino/mcfly https://github.com/cantino/mcfly
|
||||
|
||||
$ brew install mcfly
|
||||
```
|
||||
|
||||
在安装完成后,你将看到下面的输出:
|
||||
|
||||
```
|
||||
==> Installing mcfly from cantino/mcfly
|
||||
==> Downloading https://github.com/cantino/mcfly/releases/download/v0.2.5/mcfly-v0
|
||||
==> Downloading from https://github-production-release-asset-2e65be.s3.amazonaws.c
|
||||
######################################################################## 100.0%
|
||||
==> ONE MORE STEP! Edit ~/.bashrc and add the following:
|
||||
|
||||
if [ -f $(brew --prefix)/opt/mcfly/mcfly.bash ]; then
|
||||
. $(brew --prefix)/opt/mcfly/mcfly.bash
|
||||
fi
|
||||
🍺 /home/linuxbrew/.linuxbrew/Cellar/mcfly/v0.2.5: 4 files, 3.5MB, built in 33 seconds
|
||||
```
|
||||
|
||||

|
||||
|
||||
正如你上面看到的那样,在使用 McFly 之前我们需要再做一些配置。
|
||||
|
||||
将下面几行添加到你的 `~/.bashrc` 文件中:
|
||||
|
||||
```
|
||||
if [ -f $(brew --prefix)/opt/mcfly/mcfly.bash ]; then
|
||||
. $(brew --prefix)/opt/mcfly/mcfly.bash
|
||||
fi
|
||||
```
|
||||
|
||||
最后,再运行下面的命令来让更改生效。
|
||||
|
||||
```
|
||||
$ source ~/.bashrc
|
||||
```
|
||||
|
||||
当你第一次执行上面的这个命令时,你的 BASH 历史将会被导入 McFly 的数据库。依据你的 bash 历史文件的大小,这个过程将花费一些时间。一旦导入完成,你讲看到下面的提示信息。
|
||||
|
||||
```
|
||||
McFly: Importing Bash history for the first time. This may take a minute or two...done.
|
||||
```
|
||||
|
||||
现在你就可以使用 McFly 了。
|
||||
|
||||
### 使用方法
|
||||
|
||||
要在你的命令历史中执行搜索,只需要键入 `mcfly search` 再加上命令名的一部分,最后敲击回车键即可。Mcfly 将会基于你刚才键入的搜索查询语句给出命令建议。
|
||||
|
||||
```
|
||||
$ mcfly search <part-of-the-command>
|
||||
```
|
||||
|
||||
例如我键入了下面的命令:
|
||||
|
||||
```
|
||||
$ mcfly search mk
|
||||
```
|
||||
|
||||
下面展示的是我 Ubuntu 机子上的示例输出:
|
||||
|
||||

|
||||
|
||||
如你所见,我已经使用过 `mkdir` 这个命令两次。假如你想从这些命令建议中执行其中之一,只需使用上下键来选择它,然后敲击**回车键**来执行它就可以了。假如你想编辑其中一个命令,则需要先选择它,然后敲 `TAB` 键将这个命令放置到终端中,最后在运行它之前更改它就行了。要从历史中删除已经选择的命令,按 `F2` 即可。
|
||||
|
||||
或者,输入下面的命令来打开历史搜索,然后输入任意一个命令或者命令的一部分来从你的历史命令中查看它提供的建议。
|
||||
|
||||
```
|
||||
$ mcfly search
|
||||
```
|
||||
|
||||
在你输入的同时, McFly 将会展示命令的提示。
|
||||
|
||||
下面是一个介绍 McFly 的简短演示视频:
|
||||
|
||||

|
||||
|
||||
你还可以使用下面的命令来查看帮助:
|
||||
|
||||
```
|
||||
$ mcfly --help
|
||||
```
|
||||
|
||||
### 移除 McFly
|
||||
|
||||
不喜欢 McFly,没问题!可以使用下面的命令来移除它:
|
||||
|
||||
```
|
||||
$ brew uninstall mcfly
|
||||
|
||||
$ brew untap cantino/mcfly
|
||||
```
|
||||
|
||||
最后,移除先前添加到 `~/.bashrc` 文件中的几行命令。
|
||||
|
||||
好了,这些就是所有了,更多精彩内容敬请期待,请保存关注!
|
||||
|
||||
干杯!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/mcfly-a-replacement-to-ctrlr-bash-history-search-feature/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[FSSlc](https://github.com/FSSlc)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.ostechnix.com/linuxbrew-common-package-manager-linux-mac-os-x/
|
||||
@@ -0,0 +1,56 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10435-1.html)
|
||||
[#]: subject: (Snake your way across your Linux terminal)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-snake)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
在 Linux 终端中玩贪吃蛇
|
||||
======
|
||||
|
||||
> 有了这个 20 世纪 70 年代的经典重制游戏,Python 将不再是你在 Linux 终端能发现的唯一的“蛇”。
|
||||
|
||||

|
||||
|
||||
欢迎回到 Linux 命令行玩具日历。如果这是你第一次访问该系列,你可能会问什么是命令行玩具。这很难确切地说,但我的定义是任何可以帮助你在终端玩得开心的东西。
|
||||
|
||||
我们这周都在介绍游戏,这很有趣,接着让我们看下今天的游戏,贪吃蛇!
|
||||
|
||||
贪吃蛇是一个古老又很好的游戏,这些年一直有各种版本。我记得我第一次玩得版本是 20 世纪 90 年代与 [QBasic][2] 一起打包发布的 [Nibbles][1],它对我理解什么是编程语言起了很重要的作用。我有游戏的源码,我可以修改并查看会发生什么,并学习到一些组成这个编程语言的有趣词汇究竟是什么意思。
|
||||
|
||||
今天的[贪吃蛇][3]是用 Go 写的,它很简单并且和原版的游戏一样有趣。像大多数简单的老游戏一样,它有很多版本可供选择。这今天的贪吃蛇中,甚至还有一个经典的 [bsdgames][4] 形式的包,它的发行版几乎一定有它。
|
||||
|
||||
但我喜欢的是用 Docker 打包的贪吃蛇,因为我可以轻松地在命令行中运行,而不用担心发行版相关的问题。这个版本使用 15 个随机的食物 emoji 图案让蛇来吃。我玩得不好。不管怎样,请试一下:
|
||||
|
||||
```
|
||||
$ docker run -ti dyego/snake-game
|
||||
```
|
||||
|
||||
这个贪吃蛇以 MIT 许可证开源,你可在 [Github][3] 取得源码。
|
||||
|
||||

|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。请在评论区留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
请查看昨天的玩具,[数字 2 的力量,Linux 的力量:在命令行中玩 2048][5],记得明天再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-snake
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://en.wikipedia.org/wiki/Nibbles_(video_game)
|
||||
[2]: https://en.wikipedia.org/wiki/QBasic
|
||||
[3]: https://github.com/DyegoCosta/snake-game
|
||||
[4]: https://github.com/vattam/BSDGames
|
||||
[5]: https://opensource.com/article/18/12/linux-toy-2048
|
||||
@@ -0,0 +1,86 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10450-1.html)
|
||||
[#]: subject: (Winterize your Bash prompt in Linux)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-bash-prompt)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
在 Linux 中打扮你的冬季 Bash 提示符
|
||||
======
|
||||
|
||||
> 你的 Linux 终端可能支持 Unicode,那么为何不利用它在提示符中添加季节性的图标呢?
|
||||
|
||||

|
||||
|
||||
欢迎再次来到 Linux 命令行玩具日历的另一篇。如果这是你第一次访问该系列,你甚至可能会问自己什么是命令行玩具?我们对此比较随意:它会是终端上有任何有趣的消遣,对于任何节日主题相关的还有额外的加分。
|
||||
|
||||
也许你以前见过其中的一些,也许你没有。不管怎样,我们希望你玩得开心。
|
||||
|
||||
今天的玩具非常简单:它是你的 Bash 提示符。你的 Bash 提示符?是的!我们还有几个星期的假期可以盯着它看,在北半球冬天还会再多几周,所以为什么不玩玩它。
|
||||
|
||||
目前你的 Bash 提示符号可能是一个简单的美元符号( `$`),或者更有可能是一个更长的东西。如果你不确定你的 Bash 提示符是什么,你可以在环境变量 `$PS1` 中找到它。要查看它,请输入:
|
||||
|
||||
```
|
||||
echo $PS1
|
||||
```
|
||||
|
||||
对于我而言,它返回:
|
||||
|
||||
```
|
||||
[\u@\h \W]\$
|
||||
```
|
||||
|
||||
`\u`、`\h` 和 `\W` 分别是用户名、主机名和工作目录的特殊字符。你还可以使用其他一些符号。为了帮助构建你的 Bash 提示符,你可以使用 [EzPrompt][1],这是一个 `PS1` 配置的在线生成器,它包含了许多选项,包括日期和时间、Git 状态等。
|
||||
|
||||
你可能还有其他变量来组成 Bash 提示符。对我来说,`$PS2` 包含了我命令提示符的结束括号。有关详细信息,请参阅 [这篇文章][2]。
|
||||
|
||||
要更改提示符,只需在终端中设置环境变量,如下所示:
|
||||
|
||||
```
|
||||
$ PS1='\u is cold: '
|
||||
jehb is cold:
|
||||
```
|
||||
|
||||
要永久设置它,请使用你喜欢的文本编辑器将相同的代码添加到 `/etc/bashrc` 中。
|
||||
|
||||
那么这些与冬季化有什么关系呢?好吧,你很有可能有现代一下的机器,你的终端支持 Unicode,所以你不仅限于标准的 ASCII 字符集。你可以使用任何符合 Unicode 规范的 emoji,包括雪花 ❄、雪人 ☃ 或一对滑雪板 🎿。你有很多冬季 emoji 可供选择。
|
||||
|
||||
```
|
||||
🎄 圣诞树
|
||||
🧥 外套
|
||||
🦌 鹿
|
||||
🧤 手套
|
||||
🤶 圣诞夫人
|
||||
🎅 圣诞老人
|
||||
🧣 围巾
|
||||
🎿 滑雪者
|
||||
🏂 滑雪板
|
||||
❄ 雪花
|
||||
☃ 雪人
|
||||
⛄ 没有雪的雪人
|
||||
🎁 包装好的礼物
|
||||
```
|
||||
|
||||
选择你最喜欢的,享受冬天的欢乐。有趣的事实:现代文件系统也支持文件名中的 Unicode 字符,这意味着技术上你可以将你下个程序命名为 `❄❄❄❄❄.py`。只是说说,不要这么做。
|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。如果你有特别想了解的可以评论留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
查看昨天的玩具,[在 Linux 终端玩贪吃蛇][3],记得明天再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
via: https://opensource.com/article/18/12/linux-toy-bash-prompt
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://ezprompt.net/
|
||||
[2]: https://access.redhat.com/solutions/505983
|
||||
[3]: https://opensource.com/article/18/12/linux-toy-snake
|
||||
@@ -0,0 +1,66 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (bestony)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10448-1.html)
|
||||
[#]: subject: (5 resolutions for open source project maintainers)
|
||||
[#]: via: (https://opensource.com/article/18/12/resolutions-open-source-project-maintainers)
|
||||
[#]: author: (Ben Cotton https://opensource.com/users/bcotton)
|
||||
|
||||
一位开源项目维护者的 5 个决心
|
||||
======
|
||||
|
||||
> 不管怎么说,好的交流是一个活跃的开源社区的必备品。
|
||||
|
||||

|
||||
|
||||
我通常不会定下大的新年决心。当然,我在自我提升方面没有任何问题,这篇文章我希望锚定的是这个日历中的另外一部分。不过即使是这样,这里也有一些东西要从今年的免费日历上划掉,并将其替换为一些可以激发我的自省的新日历内容。
|
||||
|
||||
在 2017 年,我从不在社交媒体上分享我从未阅读过的文章。我一直保持这样的状态,我也认为它让我成为了一个更好的互联网公民。对于 2019 年,我正在考虑让我成为更好的开源软件维护者的决心。
|
||||
|
||||
下面是一些我在一些项目中担任维护者或共同维护者时坚持的决心:
|
||||
|
||||
### 1、包含行为准则
|
||||
|
||||
Jono Bacon 在他的文章“[7 个你可能犯的错误][1]”中包含了一条“不强制执行行为准则”。当然,要强制执行行为准则,你首先需要有一个行为准则。我打算默认用[贡献者契约][2],但是你可以使用其他你喜欢的。关于这个许可协议,最好的方法是使用别人已经写好的,而不是你自己写的。但是重要的是,要找到一些能够定义你希望你的社区执行的,无论它们是什么样子。一旦这些被记录下来并强制执行,人们就能自行决定是否成为他们想象中社区的一份子。
|
||||
|
||||
### 2、使许可证清晰且明确
|
||||
|
||||
你知道什么真的很烦么?不清晰的许可证。"这个软件基于 GPL 授权",如果没有进一步提供更多信息的文字,我无法知道更多信息。基于哪个版本的[GPL][3]?我可以用它吗?对于项目的非代码部分,“根据知识共享许可证(CC)授权”更糟糕。我喜欢[知识共享许可证][4],但它有几个不同的许可证包含着不同的权利和义务。因此,我将非常清楚的说明哪个许可证的变种和版本适用于我的项目。我将会在仓库中包含许可的全文,并在其他文件中包含简明的注释。
|
||||
|
||||
与此相关的一类问题是使用 [OSI][5] 批准的许可证。想出一个新的准确的说明了你想要表达什么的许可证是有可能的,但是如果你需要强制推行它,祝你好运。会坚持使用它么?使用您项目的人会理解么?
|
||||
|
||||
### 3、快速分类错误报告和问题
|
||||
|
||||
在技术领域, 很少有比开源维护者更贫乏的东西了。即使在小型项目中,也很难找到时间去回答每个问题并修复每个错误。但这并不意味着我不能哪怕回应一下,它没必要是多段的回复。即使只是给 GitHub 问题贴了个标签也表明了我看见它了。也许我马上就会处理它,也许一年后我会处理它。但是让社区看到它很重要,是的,这里还有人管。
|
||||
|
||||
### 4、如果没有伴随的文档,请不要推送新特性或错误修复
|
||||
|
||||
尽管多年来我的开源贡献都围绕着文档,但我的项目并没有反映出我对它的重视。我能推送的提交不多,并不不需要某种形式的文档。新的特性显然应该在他们被提交时甚至是在之前就编写文档。但即使是错误修复,也应该在发行说明中有一个条目提及。如果没有什么意外,推送提交也是很好的改善文档的机会。
|
||||
|
||||
### 5、放弃一个项目时,要说清楚
|
||||
|
||||
我很不擅长对事情说“不”,我告诉编辑我会为 [Opensource.com][6] 写一到两篇文章,而现在我有了将近 60 篇文章。哎呀。但在某些时候,曾经我有兴趣的事情也会不再有兴趣。也许该项目是不必要的,因为它的功能被吸收到更大的项目中;也许只是我厌倦了它。但这对社区是不公平的(并且存在潜在的危险,正如最近的 [event-stream 恶意软件注入][7]所示),会让该项目陷入困境。维护者有权随时离开,但他们离开时应该说清楚。
|
||||
|
||||
无论你是开源维护者还是贡献者,如果你知道项目维护者应该作出的其他决心,请在评论中分享!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/resolutions-open-source-project-maintainers
|
||||
|
||||
作者:[Ben Cotton][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[bestony](https://github.com/bestony)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/bcotton
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/17/8/mistakes-open-source-avoid
|
||||
[2]: https://www.contributor-covenant.org/
|
||||
[3]: https://opensource.org/licenses/gpl-license
|
||||
[4]: https://creativecommons.org/share-your-work/licensing-types-examples/
|
||||
[5]: https://opensource.org/
|
||||
[6]: http://Opensource.com
|
||||
[7]: https://arstechnica.com/information-technology/2018/11/hacker-backdoors-widely-used-open-source-software-to-steal-bitcoin/
|
||||
@@ -0,0 +1,317 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (jlztan)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10456-1.html)
|
||||
[#]: subject: (What is PPA? Everything You Need to Know About PPA in Linux)
|
||||
[#]: via: (https://itsfoss.com/ppa-guide/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
Ubuntu PPA 使用指南
|
||||
======
|
||||
|
||||
> 一篇涵盖了在 Ubuntu 和其他 Linux 发行版中使用 PPA 的几乎所有问题的深入的文章。
|
||||
|
||||
如果你一直在使用 Ubuntu 或基于 Ubuntu 的其他 Linux 发行版,例如 Linux Mint、Linux Lite、Zorin OS 等,你可能会遇到以下三种神奇的命令:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:dr-akulavich/lighttable
|
||||
sudo apt-get update
|
||||
sudo apt-get install lighttable-installer
|
||||
```
|
||||
|
||||
许多网站推荐使用类似于以上几行的形式 [在 Ubuntu 中安装应用程序][1]。这就是所谓的使用 PPA 安装应用程序。
|
||||
|
||||
但什么是 PPA?为什么要用它?使用 PPA 安全吗?如何正确使用 PPA?如何删除 PPA?
|
||||
|
||||
我将在这个详细的指南中回答上述所有问题。即使你已经了解了一些关于 PPA 的事情,我相信这篇文章仍然会让你了解这方面的更多知识。
|
||||
|
||||
请注意我正在使用 Ubuntu 撰写本文。因此,我几乎在各个地方都使用了 Ubuntu 这个术语,但文中的说明和步骤也适用于其他基于 Debian/Ubuntu 的发行版。
|
||||
|
||||
### 什么是 PPA?为什么要使用 PPA?
|
||||
|
||||
![Everything you need to know about PPA in Ubuntu Linux][2]
|
||||
|
||||
PPA 表示<ruby>个人软件包存档<rt>Personal Package Archive</rt></ruby>。
|
||||
|
||||
这样说容易理解吗?可能不是很容易。
|
||||
|
||||
在了解 PPA 之前,你应该了解 Linux 中软件仓库的概念。关于软件仓库,在这里我不会详述。
|
||||
|
||||
#### 软件仓库和包管理的概念
|
||||
|
||||
软件仓库是一组文件,其中包含各种软件及其版本的信息,以及校验和等其他一些详细信息。每个版本的 Ubuntu 都有自己的四个官方软件仓库:
|
||||
|
||||
- Main - Canonical 支持的自由开源软件。
|
||||
- Universe - 社区维护的自由开源软件。
|
||||
- Restricted - 设备的专有驱动程序。
|
||||
- Multiverse - 受版权或法律问题限制的软件。
|
||||
|
||||
你可以在 [这里][3] 看到所有版本的 Ubuntu 的软件仓库。你可以浏览并转到各个仓库。例如,可以在 [这里][4] 找到 Ubuntu 16.04 的主存储库(Main)。
|
||||
|
||||
所以,PPA 基本上是一个包含软件信息的网址。那你的系统又是如何知道这些仓库的位置的呢?
|
||||
|
||||
这些信息存储在 `/etc/apt` 目录中的 `sources.list` 文件中。如果查看此文件的内容,你就会看到里面有软件仓库的网址。`#` 开头的行将被忽略。
|
||||
|
||||
这样的话,当你运行 `sudo apt update` 命令时,你的系统将使用 [APT 工具][5] 来检查软件仓库并将软件及其版本信息存储在缓存中。当你使用 `sudo apt install package_name` 命令时,它通过该信息从实际存储软件的网址获取该软件包。
|
||||
|
||||
如果软件仓库中没有关于某个包的信息,你将看到如下错误:
|
||||
|
||||
```
|
||||
E: Unable to locate package
|
||||
```
|
||||
|
||||
此时,建议阅读我的 [apt 命令使用指南][6] 一文,这将帮你更好地理解 `apt`、`update` 等命令。
|
||||
|
||||
以上是关于软件仓库的内容。但什么是 PPA?PPA 和软件仓库又有什么关联呢?
|
||||
|
||||
#### 为什么要用 PPA?
|
||||
|
||||
如你所见,Ubuntu 对系统中的软件进行管理,更重要的是控制你在系统上获得哪个版本的软件。但想象一下开发人员发布了软件的新版本的情况。
|
||||
|
||||
Ubuntu 不会立即提供该新版本的软件。需要一个步骤来检查此新版本的软件是否与系统兼容,从而可以确保系统的稳定性。
|
||||
|
||||
但这也意味着它需要经过几周才能在 Ubuntu 上可用,在某些情况下,这可能需要几个月的时间。不是每个人都想等待那么长时间才能获得他们最喜欢的软件的新版本。
|
||||
|
||||
类似地,假设有人开发了一款软件,并希望 Ubuntu 将该软件包含在官方软件仓库中。在 Ubuntu 做出决定并将其包含在官方存软件仓库之前,还需要几个月的时间。
|
||||
|
||||
另一种情况是在 beta 测试阶段。即使官方软件仓库中提供了稳定版本的软件,软件开发人员也可能希望某些终端用户测试他们即将发布的版本。他们是如何使终端用户对即将发布的版本进行 beta 测试的呢?
|
||||
|
||||
通过 PPA!
|
||||
|
||||
### 如何使用 PPA?PPA 是怎样工作的?
|
||||
|
||||
正如我已经告诉过你的那样,[PPA][7] 代表<ruby>个人软件包存档<rt>Personal Package Archive</rt></ruby>。在这里注意 “个人” 这个词,它暗示了这是开发人员独有的东西,并没有得到分发的正式许可。
|
||||
|
||||
Ubuntu 提供了一个名为 Launchpad 的平台,使软件开发人员能够创建自己的软件仓库。终端用户,也就是你,可以将 PPA 仓库添加到 `sources.list` 文件中,当你更新系统时,你的系统会知道这个新软件的可用性,然后你可以使用标准的 `sudo apt install` 命令安装它。
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:dr-akulavich/lighttable
|
||||
sudo apt-get update
|
||||
sudo apt-get install lighttable-installer
|
||||
```
|
||||
|
||||
概括一下上面三个命令:
|
||||
|
||||
- `sudo add-apt-repository <PPA_info>` <- 此命令将 PPA 仓库添加到列表中。
|
||||
- `sudo apt-get update` <- 此命令更新可以在当前系统上安装的软件包列表。
|
||||
- `sudo apt-get install <package_in_PPA>` <- 此命令安装软件包。
|
||||
|
||||
你会发现使用 `sudo apt update` 命令非常重要,否则你的系统将无法知道新软件包何时可用。
|
||||
|
||||
现在让我们更详细地看一下第一个命令。
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:dr-akulavich/lighttable
|
||||
```
|
||||
|
||||
你会注意到此命令没有软件仓库的 URL。这是因为该工具被设计成将 URL 信息抽象之后再展示给你。
|
||||
|
||||
小小注意一下:如果你添加的是 `ppa:dr-akulavich/lighttable`,你会得到 Light Table。但是如果你添加 `ppa:dr-akulavich`,你将得到 “上层软件仓库” 中的所有仓库或软件包。它是按层级划分的。
|
||||
|
||||
基本上,当您使用 `add-apt-repository` 添加 PPA 时,它将执行与手动运行这些命令相同的操作:
|
||||
|
||||
```
|
||||
deb http://ppa.launchpad.net/dr-akulavich/lighttable/ubuntu YOUR_UBUNTU_VERSION_HERE main
|
||||
deb-src http://ppa.launchpad.net/dr-akulavich/lighttable/ubuntu YOUR_UBUNTU_VERSION_HERE main
|
||||
```
|
||||
|
||||
以上两行是将任何软件仓库添加到你系统的 `sources.list` 文件的传统方法。但 PPA 会自动为你完成这些工作,无需考虑确切的软件仓库 URL 和操作系统版本。
|
||||
|
||||
此处不那么重要的一点是,当你使用 PPA 时,它不会更改原始的 `sources.list` 文件。相反,它在 `/etc/apt/sources.d` 目录中创建了两个文件,一个 `.list` 文件和一个带有 `.save` 后缀的备份文件。
|
||||
|
||||
![Using a PPA in Ubuntu][8]
|
||||
|
||||
*PPA 创建了单独的 `sources.list` 文件*
|
||||
|
||||
带有后缀 `.list` 的文件含有添加软件仓库的信息的命令。
|
||||
|
||||
![PPA add repository information][9]
|
||||
|
||||
*一个 PPA 的 `source.list` 文件的内容*
|
||||
|
||||
这是一种安全措施,可以确保添加的 PPA 不会和原始的 `sources.list` 文件弄混,它还有助于移除 PPA。
|
||||
|
||||
#### 为什么使用 PPA?为何不用 DEB 包
|
||||
|
||||
你可能会问为什么要使用 PPA,PPA 需要通过命令行使用,而不是每个人都喜欢用命令行。为什么不直接分发可以图形方式安装的 DEB 包呢?
|
||||
|
||||
答案在于更新的过程。如果使用 DEB 包安装软件,将无法保证在运行 `sudo apt update` 和 `sudo apt upgrade` 命令时,已安装的软件会被更新为较新的版本。
|
||||
|
||||
这是因为 `apt` 的升级过程依赖于 `sources.list` 文件。如果文件中没有相应的软件条目,则不会通过标准软件更新程序获得更新。
|
||||
|
||||
那么这是否意味着使用 DEB 安装的软件永远不会得到更新?不是的。这取决于 DEB 包的创建方式。
|
||||
|
||||
一些开发人员会自动在 `sources.list` 中添加一个条目,这样软件就可以像普通软件一样更新。谷歌 Chrome 浏览器就是这样一个例子。
|
||||
|
||||
某些软件会在运行时通知你有新版本可用。你必须下载新的 DEB 包并再次运行,来将当前软件更新为较新版本。Oracle Virtual Box 就是这样一个例子。
|
||||
|
||||
对于其余的 DEB 软件包,你必须手动查找更新,这很不方便,尤其是在你的软件面向 Beta 测试者时,你需要频繁的添加很多更新。这正是 PPA 要解决的问题。
|
||||
|
||||
#### 官方 PPA vs 非官方 PPA
|
||||
|
||||
你或许听过官方 PPA 或非官方 PPA 这个词,二者有什么不同呢?
|
||||
|
||||
开发人员为他们的软件创建的 PPA 称为官方 PPA。很明显,这是因为它来自项目开发者。
|
||||
|
||||
但有时,个人会创建由其他开发人员所创建的项目的 PPA。
|
||||
|
||||
为什么会有人这样做? 因为许多开发人员只提供软件的源代码,而且你也知道 [在 Linux 中从源代码安装软件][10] 是一件痛苦的事情,并不是每个人都可以或者会这样做。
|
||||
|
||||
这就是志愿者自己从这些源代码创建 PPA 以便其他用户可以轻松安装软件的原因。毕竟,使用这 3 行命令比从源代码安装要容易得多。
|
||||
|
||||
#### 确保你的 Linux 发行版本可以使用 PPA
|
||||
|
||||
当在 Ubuntu 或任何其他基于 Debian 的发行版中使用 PPA 时,你应该记住一些事情。
|
||||
|
||||
并非每个 PPA 都适用于你的特定版本。你应该知道正在使用 [哪个版本的 Ubuntu][11]。版本的开发代号很重要,因为当你访问某个 PPA 的页面时,你可以看到该 PPA 都支持哪些版本的 Ubuntu。
|
||||
|
||||
对于其他基于 Ubuntu 的发行版,你可以查看 `/etc/os-release` 的内容来 [找出 Ubuntu 版本][11] 的信息。
|
||||
|
||||
![Verify PPA availability for Ubuntu version][12]
|
||||
|
||||
*检查 PPA 是否适用于你的 Ubuntu 版本*
|
||||
|
||||
如何知道 PPA 的网址呢?只需在网上搜索 PPA 的名称,如 `ppa:dr-akulavich/lighttable`,第一个搜索结果来自 [Launchpad][13],这是托管 PPA 的官方平台。你也可以转到 Launchpad 并直接在那里搜索所需的 PPA。
|
||||
|
||||
如果不验证是否适用当前的版本就添加 PPA,当尝试安装不适用于你的系统版本的软件时,可能会看到类似下面的错误。
|
||||
|
||||
```
|
||||
E: Unable to locate package
|
||||
```
|
||||
|
||||
更糟糕的是,因为它已经添加到你的 `source.list` 中,每次运行软件更新程序时,你都会看到 “[无法下载软件仓库信息][14]” 的错误。
|
||||
|
||||
![Failed to download repository information Ubuntu 13.04][15]
|
||||
|
||||
如果你在终端中运行 `sudo apt update`,错误提示将包含导致此问题的仓库的更多详细信息。你可以在 `sudo apt update` 的输出内容结尾看到类似的内容:
|
||||
|
||||
```
|
||||
W: Failed to fetch http://ppa.launchpad.net/venerix/pkg/ubuntu/dists/raring/main/binary-i386/Packages 404 Not Found
|
||||
E: Some index files failed to download. They have been ignored, or old ones used instead.
|
||||
```
|
||||
|
||||
上面的错误提示说的很明白,是因为系统找不到当前版本对应的仓库。还记得我们之前看到的仓库结构吗?APT 将尝试在 `http://ppa.launchpad.net/<PPA_NAME>/ubuntu/dists/<Ubuntu_Version>` 中寻找软件信息。
|
||||
|
||||
如果特定版本的 PPA 不可用,它将永远无法打开 URL,你会看到著名的 404 错误。
|
||||
|
||||
#### 为什么 PPA 不适用于所有 Ubuntu 发行版?
|
||||
|
||||
这是因为 PPA 的作者必须编译软件并在特定版本上创建 PPA。考虑到每六个月发布一个新的 Ubuntu 版本,为每个版本的 Ubuntu 更新 PPA 是一项繁琐的任务,并非所有开发人员都有时间这样做。
|
||||
|
||||
#### 如果 PPA 不适用于你的系统版本,该如何安装应用程序?
|
||||
|
||||
尽管 PPA 不适用于你的 Ubuntu 版本,你仍然可以下载 DEB 文件并安装应用程序。
|
||||
|
||||
比如说,你访问 Light Table 的 PPA 页面,使用刚刚学到的有关 PPA 的知识,你会发现 PPA 不适用于你的特定 Ubuntu 版本。
|
||||
|
||||
你可以点击 “查看软件包详细信息”。
|
||||
|
||||
![Get DEB file from PPA][16]
|
||||
|
||||
在这里,你可以单击软件包以显示更多详细信息,还可以在此处找到包的源代码和 DEB 文件。
|
||||
|
||||
![Download DEB file from PPA][17]
|
||||
|
||||
我建议 [使用 Gdebi 安装这些 DEB 文件][18] 而不是通过软件中心,因为 Gdebi 在处理依赖项方面要好得多。
|
||||
|
||||
请注意,以这种方式安装的软件包可能无法获得任何将来的更新。
|
||||
|
||||
我认为你已经阅读了足够多的关于添加 PPA 的内容,那么如何删除 PPA 及其安装的软件呢?
|
||||
|
||||
### 如何删除 PPA?
|
||||
|
||||
我过去曾写过 [删除 PPA][19] 的教程,这里写的也是同样的方法。
|
||||
|
||||
我建议在删除 PPA 之前删除从 PPA 安装的软件。如果只是删除 PPA,则已安装的软件仍保留在系统中,但不会获得任何更新。这不是你想要的,不是吗?
|
||||
|
||||
那么,问题来了,如何知道是哪个 PPA 安装了哪个应用程序?
|
||||
|
||||
#### 查找 PPA 安装的软件包并将其移除
|
||||
|
||||
Ubuntu 软件中心无法移除 PPA 安装的软件包,你必须使用具有更多高级功能的 Synaptic 包管理器。
|
||||
|
||||
可以从软件中心安装 Synaptic 或使用以下命令进行安装:
|
||||
|
||||
```
|
||||
sudo apt install synaptic
|
||||
```
|
||||
|
||||
安装后,启动 Synaptic 包管理器并选择 “Origin”。你会看到添加到系统的各种软件仓库。PPA 条目将以前缀 PPA 进行标识,单击以查看 PPA 可用的包。已安装的软件前面会有恰当的符号进行标识。
|
||||
|
||||
![Managing PPA with Synaptic package manager][20]
|
||||
|
||||
*查找通过 PPA 安装的软件包*
|
||||
|
||||
找到包后,你可以从 Synaptic 删除它们。此外,也始终可以选择使用命令行进行移除:
|
||||
|
||||
```
|
||||
sudo apt remove package_name
|
||||
```
|
||||
|
||||
删除 PPA 安装的软件包后,你可以继续从 `sources.list` 中删除PPA。
|
||||
|
||||
#### 以图形界面的方式删除 PPA
|
||||
|
||||
在设置中打开 “软件和更新”,然后点击 “其他软件” 选项卡。查找要删除的 PPA:
|
||||
|
||||
![Delete a PPA from Software Source][21]
|
||||
|
||||
此处你可以进项两项操作,可以取消选择 PPA 或选择 “删除” 选项。
|
||||
|
||||
区别在于,当你取消选择 PPA 条目时,系统将在 `/etc/apt/sources.list.d` 中的`ppa_name.list` 文件中注释掉仓库条目;但如果选择 “删除” 选项,将会删除 `/etc/apt/sources.list.d`目录中 `ppa_name.list` 文件里的仓库条目。
|
||||
|
||||
在这两种情况下,文件 `ppa_name.list` 都保留在所在的目录中,即使它是空的。
|
||||
|
||||
### 使用 PPA 安全吗?
|
||||
|
||||
这是一个主观问题。纯粹主义者厌恶 PPA,因为大多数时候 PPA 来自第三方开发者。但与此同时,PPA 在 Debian/Ubuntu 世界中很受欢迎,因为它们提供了更简单的安装选项。
|
||||
|
||||
就安全性而言,很少见到因为使用 PPA 之后你的 Linux 系统被黑客攻击或注入恶意软件。到目前为止,我不记得发生过这样的事件。
|
||||
|
||||
官方 PPA 可以不加考虑的使用,使用非官方 PPA 完全是你自己的决定。
|
||||
|
||||
根据经验,如果程序需要 sudo 权限,则应避免通过第三方 PPA 进行安装。
|
||||
|
||||
### 你如何看待使用 PPA?
|
||||
|
||||
我知道这篇文章需要挺长时间来阅读,但我想让你更好地了解 PPA。我希望这份详细指南能够回答你关于使用 PPA 的大部分问题。
|
||||
|
||||
如果你对 PPA 有更多疑问,请随时在评论区提问。
|
||||
|
||||
如果你发现任何技术或语法错误,或者有改进的建议,请告诉我。
|
||||
|
||||
------
|
||||
|
||||
via: https://itsfoss.com/ppa-guide/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[jlztan](https://github.com/jlztan)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/remove-install-software-ubuntu/
|
||||
[2]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/what-is-ppa.png?resize=800%2C450&ssl=1
|
||||
[3]: http://archive.ubuntu.com/ubuntu/dists/
|
||||
[4]: http://archive.ubuntu.com/ubuntu/dists/xenial/main/
|
||||
[5]: https://wiki.debian.org/Apt
|
||||
[6]: https://itsfoss.com/apt-command-guide/
|
||||
[7]: https://launchpad.net/ubuntu/+ppas
|
||||
[8]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/01/ppa-sources-list-files.png?resize=800%2C259&ssl=1
|
||||
[9]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/01/content-of-ppa-list.png?ssl=1
|
||||
[10]: https://linux.cn/article-9172-1.html
|
||||
[11]: https://itsfoss.com/how-to-know-ubuntu-unity-version/
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2017/12/verify-ppa-availibility-version.jpg?resize=800%2C481&ssl=1
|
||||
[13]: https://launchpad.net/
|
||||
[14]: https://itsfoss.com/failed-to-download-repository-information-ubuntu-13-04/
|
||||
[15]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2013/04/Failed-to-download-repository-information-Ubuntu-13.04.png?ssl=1
|
||||
[16]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/deb-from-ppa.jpg?resize=800%2C483&ssl=1
|
||||
[17]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/deb-from-ppa-2.jpg?resize=800%2C477&ssl=1
|
||||
[18]: https://itsfoss.com/gdebi-default-ubuntu-software-center/
|
||||
[19]: https://itsfoss.com/how-to-remove-or-delete-ppas-quick-tip/
|
||||
[20]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/01/ppa-synaptic-manager.jpeg?resize=800%2C394&ssl=1
|
||||
[21]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2012/08/Delete-a-PPA.jpeg?ssl=1
|
||||
@@ -0,0 +1,68 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10488-1.html)
|
||||
[#]: subject: (The Linux terminal is no one-trick pony)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-ponysay)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
Linux 终端上的漂亮小马
|
||||
======
|
||||
|
||||
> 将小马宝莉的魔力带到终端
|
||||
|
||||

|
||||
|
||||
欢迎再次来到 Linux 命令行玩具日历。如果这是你第一次访问该系列,你甚至可能会问自己什么是命令行玩具。我们正在思考中,但一般来说,它可能是一个游戏,或任何简单的消遣,可以帮助你在终端玩得开心。
|
||||
|
||||
很可能你们中的一些人之前已经看过我们日历中的各种玩具,但我们希望每个人至少见到一件新事物。
|
||||
|
||||
读者 [Lori][1] 在我之前关于 [cowsay][2] 的文章的评论中提出了今天玩具的建议:
|
||||
|
||||
“嗯,我一直在玩一个叫 ponysay 的东西,它似乎是你的 cowsay 的彩色变种。”
|
||||
|
||||
我对此感到好奇,并去看了一下,发现没有让我失望。
|
||||
|
||||
简而言之,[ponysay][3] 的 cowsay 的重写,它包括了来自[小马宝莉][4]中的许多全彩色人物,你可以用它在 Linux 命令行输出短句。它实际上是一个非常完善的项目,拥有超过 400 个字符和字符组合,它还有让人难以置信的的 [78 页的 PDF 文档][5]涵盖了所有的用法。
|
||||
|
||||
要安装 `ponysay`,你需要查看项目的 [README][6] 来选择最适合你的发行版和情况的安装方法。由于 `ponysay` 似乎没有为我的 Fedora 发行版打包,我选择试用 Docker 容器镜像,但你可以选择最适合你的方法。从源码安装可能也适合你。
|
||||
|
||||
作为一个业余容器用户,我很想试试 [podman][7] 来代替 docker。至少对于我而言,它可以正常工作。
|
||||
|
||||
```
|
||||
$ podman run -ti --rm mpepping/ponysay 'Ponytastic'
|
||||
```
|
||||
|
||||
输出很神奇,我建议你也试下,然后告诉我你最喜欢的。这是我其中一个:
|
||||
|
||||

|
||||
|
||||
它的开发人员选择用 [Pony][8] 来编写代码。(更新:很遗憾我写错了。虽然 Gihutb 根据它的文件扩展名认为它是 Pony,但是它是用 Python 写的。)Ponysay 使用 GPLv3 许可,你可以在 [GitHub][3] 中获取它的源码。
|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。如果你有特别想了解的可以评论留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
查看昨天的玩具,[在 Linux 终端中用火焰放松][9],记得明天再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-ponysay
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/users/n8chz
|
||||
[2]: https://opensource.com/article/18/12/linux-toy-cowsay
|
||||
[3]: https://github.com/erkin/ponysay
|
||||
[4]: https://en.wikipedia.org/wiki/My_Little_Pony
|
||||
[5]: https://github.com/erkin/ponysay/blob/master/ponysay.pdf?raw=true
|
||||
[6]: https://github.com/erkin/ponysay/blob/master/README.md
|
||||
[7]: https://opensource.com/article/18/10/podman-more-secure-way-run-containers
|
||||
[8]: https://opensource.com/article/18/5/pony
|
||||
[9]: https://opensource.com/article/18/12/linux-toy-aafire
|
||||
@@ -0,0 +1,55 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10474-1.html)
|
||||
[#]: subject: (Head to the arcade in your Linux terminal with this Pac-man clone)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-myman)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
用这个吃豆人游戏在你的终端中玩街机
|
||||
======
|
||||
|
||||
> 想要重现你最喜欢的街机游戏的魔力么?今天的命令行玩具将带你回到过去。
|
||||
|
||||

|
||||
|
||||
欢迎来到今天的 Linux 命令行玩具日历。如果这是你第一次访问该系列,你会问什么是命令行玩具。基本上,它们是游戏和简单的消遣,可以帮助你在终端玩得开心。
|
||||
|
||||
有些是新的,有些是古老的经典。我们希望你喜欢。
|
||||
|
||||
今天的玩具,MyMan,是经典街机游戏<ruby>[吃豆人][1]<rt>Pac-Man</rt></ruby>(你不会认为这是[类似命名的][2] Linux 包管理器对吧?)的有趣克隆。 如果你和我一样,为了在吃豆人游戏中取得高分,你过去在其中花费了很多时间,那么有机会的话,你应该试试这个。
|
||||
|
||||
MyMan 并不是 Linux 终端上唯一的吃豆人克隆版,但是我选择介绍它,因为 1)我喜欢它与原版一致的视觉风格,2)它为我的 Linux 发行版打包了,因此安装很容易。但是你也应该看看其他的克隆。这是[另一个][3]看起来可能不错的,但我没有尝试过。
|
||||
|
||||
由于 MyMan 已为 Fedora 打包,因此安装非常简单:
|
||||
|
||||
```
|
||||
$ dnf install myman
|
||||
```
|
||||
|
||||
MyMan 在 MIT 许可下可用,你可以在 [SourceForge][4] 上查看源代码。
|
||||
|
||||

|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。如果你有特别想了解的可以评论留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
了解一下昨天的玩具,[Linux 终端能做其他事][5],还有记得明天再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
via: https://opensource.com/article/18/12/linux-toy-myman
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://en.wikipedia.org/wiki/Pac-Man
|
||||
[2]: https://wiki.archlinux.org/index.php/pacman
|
||||
[3]: https://github.com/YoctoForBeaglebone/pacman4console
|
||||
[4]: https://myman.sourceforge.io/
|
||||
[5]: https://opensource.com/article/18/12/linux-toy-ponysay
|
||||
@@ -0,0 +1,96 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10420-1.html)
|
||||
[#]: subject: (4 cool new projects to try in COPR for December 2018)
|
||||
[#]: via: (https://fedoramagazine.org/4-try-copr-december-2018/)
|
||||
[#]: author: (Dominik Turecek https://fedoramagazine.org)
|
||||
|
||||
COPR 仓库中 4 个很酷的新软件(2018.12)
|
||||
======
|
||||
|
||||

|
||||
|
||||
COPR 是软件的个人存储库的[集合][1],它包含那些不在标准的 Fedora 仓库中的软件。某些软件不符合允许轻松打包的标准。或者它可能不符合其他 Fedora 标准,尽管它是自由开源的。COPR 可以在标准的 Fedora 包之外提供这些项目。COPR 中的软件不受 Fedora 基础设施的支持,或者是由项目自己背书的。但是,它是尝试新的或实验性软件的一种很好的方法。
|
||||
|
||||
这是 COPR 中一组新的有趣项目。
|
||||
|
||||
### MindForger
|
||||
|
||||
[MindForger][2] 是一个 Markdown 编辑器和笔记本。除了你预期的 Markdown 编辑器的功能之外,MindForger 还允许你将单个文件拆分为多个笔记。组织笔记并在文件之间移动、搜索它们都很容易。我已经使用 MindForger 一段时间来记录学习笔记了,现在可以在 COPR 中找到它啦。
|
||||
|
||||
![][3]
|
||||
|
||||
#### 安装说明
|
||||
|
||||
该仓库目前在 Fedora 29 和 Rawhide 中提供 MindForger。要安装 MindForger,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable deadmozay/mindforger
|
||||
sudo dnf install mindforger
|
||||
```
|
||||
|
||||
### Clingo
|
||||
|
||||
[Clingo][4] 是使用[回答集编程][5](ASP)建模语言解决逻辑问题的程序。使用 ASP,你可以将问题声明为一个逻辑程序,然后 Clingo 来解决。最后,Clingo 以逻辑模型的形式产生问题的解决方案,称为回答集。
|
||||
|
||||
#### 安装说明
|
||||
|
||||
该仓库目前为 Fedora 28 和 29 提供 Clingo。要安装 Clingo,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable timn/clingo
|
||||
sudo dnf install clingo
|
||||
```
|
||||
|
||||
### SGVrecord
|
||||
|
||||
[SGVrecord][6] 是一个用于录制屏幕的简单工具。它允许你捕获整个屏幕或仅选择其中的一部分。此外,有没有声音都可以进行录制。SGVrecord 以 WebM 格式生成文件。
|
||||
|
||||
![][7]
|
||||
|
||||
#### 安装说明
|
||||
|
||||
该仓库目前为 Fedora 28、29 和 Rawhide 提供 SGVrecord。要安装 SGVrecord,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable youssefmsourani/sgvrecord
|
||||
sudo dnf install sgvrecord
|
||||
```
|
||||
|
||||
### Watchman
|
||||
|
||||
[Watchman][8] 是一个对文件更改进行监视和记录的服务。你可以为指定 Watchman 监视的目录树,以及定义指定文件发生更改时触发的操作。
|
||||
|
||||
#### 安装说明
|
||||
|
||||
该仓库目前为 Fedora 29 和 Rawhide 提供 Watchman。要安装 Watchman,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable eklitzke/watchman
|
||||
sudo dnf install watchman
|
||||
```
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/4-try-copr-december-2018/
|
||||
|
||||
作者:[Dominik Turecek][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://copr.fedorainfracloud.org/
|
||||
[2]: https://www.mindforger.com/
|
||||
[3]: https://fedoramagazine.org/wp-content/uploads/2018/12/mindforger.png
|
||||
[4]: https://potassco.org/clingo/
|
||||
[5]: https://en.wikipedia.org/wiki/Answer_set_programming
|
||||
[6]: https://github.com/yucefsourani/sgvrecord
|
||||
[7]: https://fedoramagazine.org/wp-content/uploads/2018/12/SGVrecord.png
|
||||
[8]: https://facebook.github.io/watchman/
|
||||
101
published/201901/20181217 Working with tarballs on Linux.md
Normal file
101
published/201901/20181217 Working with tarballs on Linux.md
Normal file
@@ -0,0 +1,101 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10418-1.html)
|
||||
[#]: subject: (Working with tarballs on Linux)
|
||||
[#]: via: (https://www.networkworld.com/article/3328840/linux/working-with-tarballs-on-linux.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
在 Linux 上使用 tarball
|
||||
======
|
||||
|
||||
> Tarball 提供了一种在 Linux 系统上备份和管理一组文件的通用方法。请按照以下提示了解如何创建它们,以及从中提取和删除单个文件。
|
||||
|
||||

|
||||
|
||||
“tarball” (LCTT 译注:国内也常称为“tar 包”)一词通常用于描述备份一组选择的文件并将它们打包在一个文件中的一种文件格式。该名称来自 .tar 文件扩展名和 `tar` 命令,它用于将文件打包到一个文件中,有时还会压缩该文件,使其在移动到其它系统时更小。
|
||||
|
||||
tarball 通常用于备份个人或系统文件来创建存档,特别是在进行可能需要撤消的更改之前。例如,Linux 系统管理员通常会在更改应用之前创建包含一系列配置文件的 tarball,以防必须撤消这些更改。从 tarball 中解压文件通常比在备份中搜索文件快。
|
||||
|
||||
### 如何在 Linux 上创建 tarball
|
||||
|
||||
使用如下命令,你可以在单条命令中创建 tarball 并压缩它。
|
||||
|
||||
```
|
||||
$ tar -cvzf PDFs.tar.gz *.pdf
|
||||
```
|
||||
|
||||
其结果是一个压缩文件(gzip 压缩的),其中包含了当前目录中的所有 PDF 文件。当然,压缩是可选的。一个稍微简单的只是将 PDF 文件打包成未压缩 tarball 的命令:
|
||||
|
||||
```
|
||||
$ tar -cvf PDFs.tar *.pdf
|
||||
```
|
||||
|
||||
注意,选项中的 `z` 将文件变成压缩的。 `c` 表明创建文件,`v`(详细)表示你在命令运行时需要一些反馈。如果你不想查看列出的文件,请忽略 `v`。
|
||||
|
||||
另一个常见的命名约定是给压缩的 tarball 命名成 .tgz 而不是双扩展名 .tar.gz,如下所示:
|
||||
|
||||
```
|
||||
$ tar cvzf MyPDFs.tgz *.pdf
|
||||
```
|
||||
|
||||
### 如何从 tarball 中解压文件
|
||||
|
||||
要从 gzip 压缩包中解压所有文件,你可以使用如下命令:
|
||||
|
||||
```
|
||||
$ tar -xvzf file.tar.gz
|
||||
```
|
||||
|
||||
如果使用 .tgz 命名约定,该命令将如下所示:
|
||||
|
||||
```
|
||||
$ tar -xvzf MyPDFs.tgz
|
||||
```
|
||||
|
||||
要从 gzip 包中解压单个文件,你可以执行几乎相同的操作,只需添加文件名:
|
||||
|
||||
```
|
||||
$ tar -xvzf PDFs.tar.gz ShenTix.pdf
|
||||
ShenTix.pdf
|
||||
ls -l ShenTix.pdf
|
||||
-rw-rw-r-- 1 shs shs 122057 Dec 14 14:43 ShenTix.pdf
|
||||
```
|
||||
|
||||
如果未压缩 tarball,你甚至可以从 tarball 中删除文件。例如,如果我们想从 PDFs.tar.gz 中删除我们上面解压过的文件,我们会这样做:
|
||||
|
||||
```
|
||||
$ gunzip PDFs.tar.gz
|
||||
$ ls -l PDFs.tar
|
||||
-rw-rw-r-- 1 shs shs 10700800 Dec 15 11:51 PDFs.tar
|
||||
$ tar -vf PDFs.tar --delete ShenTix.pdf
|
||||
$ ls -l PDFs.tar
|
||||
-rw-rw-r-- 1 shs shs 10577920 Dec 15 11:45 PDFs.tar
|
||||
```
|
||||
|
||||
请注意,我们在删除 ShenTix.pdf 后,缩小了一点 tarball 文件占用的空间。如果我们想要,我们可以再次压缩文件:
|
||||
|
||||
```
|
||||
$ gzip -f PDFs.tar
|
||||
ls -l PDFs.tar.gz
|
||||
-rw-rw-r-- 1 shs shs 10134499 Dec 15 11:51 PDFs.tar.gzFlickr / James St. John
|
||||
```
|
||||
|
||||
丰富的命令行选项使得 tarball 使用起来简单方便。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3328840/linux/working-with-tarballs-on-linux.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.facebook.com/NetworkWorld/
|
||||
[2]: https://www.linkedin.com/company/network-world
|
||||
@@ -0,0 +1,157 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (zhs852)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10441-1.html)
|
||||
[#]: subject: (Termtosvg – Record Your Terminal Sessions As SVG Animations In Linux)
|
||||
[#]: via: (https://www.2daygeek.com/termtosvg-record-your-terminal-sessions-as-svg-animations-in-linux/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
Termtosvg:将你在 Linux 终端中操作录制成 SVG 动画
|
||||
======
|
||||
|
||||
一般人喜欢使用历史命令功能来查看/再次调用之前在终端中输入的命令。不幸的是,那样做只会显示先前输入的命令,而不是之前输出的内容。
|
||||
|
||||
在 Linux 中,有许多可以用来记录终端活动的实用工具。这种工具将会帮助我们记录用户在终端中的活动,并帮助我们识别输出中有用的信息。
|
||||
|
||||
在这之前,我们已经介绍了一些这类实用工具了。今天,让我们接着讨论这类工具。
|
||||
|
||||
如果你希望尝试其它一些记录你终端活动的工具,我推荐你试试 [script][1] 命令和 [Terminalizer][2] 工具。`script` 是在无头服务器中记录终端活动的最佳方式之一。`script` 是一个记录在终端中输入过的 Unix 命令的实用工具(在某些终端中,它会记录显示在你终端中的所有东西)。它会在当前工作目录下以文本文件方式储存所有终端输出。
|
||||
|
||||
不过,如果你在寻找 [GIF 录制器][3] ,你可以尝试 [Gifine][4]、[Kgif][5] 和 [Peek][6]。
|
||||
|
||||
### 什么是 Termtosvg
|
||||
|
||||
Termtosvg 是一个用 Python 编写的 Unix 终端录制器,它可以将你的命令行会话保存为 SVG 动画。
|
||||
|
||||
### Termtosvg 的特点
|
||||
|
||||
* 可以制作嵌入于项目主页的简洁美观的动画。
|
||||
* 可以在 SVG 模板中自定义配色、终端 UI 和动画。
|
||||
* 兼容 asciinema 录制格式。
|
||||
* 要求 Python 版本为 3.5 或更高。
|
||||
|
||||
### 如何在 Linux 中安装 Termtosvg
|
||||
|
||||
它是用 Python 编写的,所以我推荐使用 `pip` 来安装它。
|
||||
|
||||
请确保你已经安装了 python-pip 包。如果你还没安装,请输入下面的命令。
|
||||
对于 Debian 或 Ubuntu 用户,请使用 [apt][7] 或 [apt-get][8] 来安装 `pip`。
|
||||
|
||||
```shell
|
||||
sudo apt install python-pip
|
||||
```
|
||||
|
||||
对于 Archlinux 用户,请使用 [pacman][9] 来安装 `pip`。
|
||||
|
||||
```shell
|
||||
sudo pacman -S python-pip
|
||||
```
|
||||
|
||||
对于 Fedora 用户,请使用 [dnf][10] 来安装 `pip`。
|
||||
|
||||
```shell
|
||||
sudo dnf install python-pip
|
||||
```
|
||||
|
||||
对于 CentOS 或 RHEL 用户,请使用 [yum][11] 来安装 `pip`。
|
||||
|
||||
```shell
|
||||
sudo yum install python-pip
|
||||
```
|
||||
|
||||
对于 openSUSE 用户,请使用 [zypper][12] 来安装 `pip`。
|
||||
|
||||
```shell
|
||||
sudo zypper install python-pip
|
||||
```
|
||||
|
||||
最后,请执行 [pip][13] 来安装 Termtosvg。
|
||||
|
||||
```shell
|
||||
sudo pip3 install termtosvg pyte python-xlib svgwrite
|
||||
```
|
||||
|
||||
### 如何使用 Termtosvg
|
||||
|
||||
成功安装 Termtosvg 后,请使用以下命令来开始录制。
|
||||
|
||||
```shell
|
||||
$ termtosvg
|
||||
Recording started, enter "exit" command or Control-D to end
|
||||
```
|
||||
|
||||
如果只是想测试它是否正常工作,随意输入几行命令即可。
|
||||
|
||||
```shell
|
||||
$ uname -a
|
||||
Linux daygeek-Y700 4.19.8-2-MANJARO #1 SMP PREEMPT Sat Dec 8 14:45:36 UTC 2018 x86_64 GNU/Linux
|
||||
$ hostname
|
||||
daygeek-Y700
|
||||
$ cat /etc/*-release
|
||||
Manjaro Linux
|
||||
DISTRIB_ID=ManjaroLinux
|
||||
DISTRIB_RELEASE=18.0
|
||||
DISTRIB_CODENAME=Illyria
|
||||
DISTRIB_DESCRIPTION="Manjaro Linux"
|
||||
Manjaro Linux
|
||||
NAME="Manjaro Linux"
|
||||
ID=manjaro
|
||||
ID_LIKE=arch
|
||||
PRETTY_NAME="Manjaro Linux"
|
||||
ANSI_COLOR="1;32"
|
||||
HOME_URL="https://www.manjaro.org/"
|
||||
SUPPORT_URL="https://www.manjaro.org/"
|
||||
BUG_REPORT_URL="https://bugs.manjaro.org/"
|
||||
$ free -g
|
||||
free: Multiple unit options doesn't make sense.
|
||||
$ free -m
|
||||
free: Multiple unit options doesn't make sense.
|
||||
$ pip3 --version
|
||||
pip 18.1 from /usr/lib/python3.7/site-packages/pip (python 3.7)
|
||||
```
|
||||
|
||||
完成后,你可以按下 `CTRL+D` 或输入 `exit` 来停止录制。录制完后,输出文件会以一个独一无二的名字被保存在 `/tmp` 文件夹中。
|
||||
|
||||
```shell
|
||||
$ exit
|
||||
exit
|
||||
Recording ended, SVG animation is /tmp/termtosvg_5waorper.svg
|
||||
```
|
||||
|
||||
我们可以在任意浏览器中打开 SVG 文件。
|
||||
|
||||
```shell
|
||||
firefox /tmp/termtosvg_5waorper.svg
|
||||
```
|
||||
|
||||
![最终效果][15]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/termtosvg-record-your-terminal-sessions-as-svg-animations-in-linux/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zhs852](https://github.com/zhs852)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.2daygeek.com/author/magesh/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.2daygeek.com/script-command-record-save-your-terminal-session-activity-linux/
|
||||
[2]: https://www.2daygeek.com/terminalizer-a-tool-to-record-your-terminal-and-generate-animated-gif-images/
|
||||
[3]: https://www.2daygeek.com/category/gif-recorder/
|
||||
[4]: https://www.2daygeek.com/gifine-create-animated-gif-vedio-recorder-linux-mint-debian-ubuntu/
|
||||
[5]: https://www.2daygeek.com/kgif-create-animated-gif-file-active-window-screen-recorder-capture-arch-linux-mint-fedora-ubuntu-debian-opensuse-centos/
|
||||
[6]: https://www.2daygeek.com/peek-create-animated-gif-screen-recorder-capture-arch-linux-mint-fedora-ubuntu/
|
||||
[7]: https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[8]: https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[9]: https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/
|
||||
[10]: https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
|
||||
[11]: https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[12]: https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
|
||||
[13]: https://www.2daygeek.com/install-pip-manage-python-packages-linux/
|
||||
[14]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[15]: https://www.2daygeek.com/wp-content/uploads/2018/12/Termtosvg-Record-Your-Terminal-Sessions-As-SVG-Animations-In-Linux-1.gif
|
||||
@@ -0,0 +1,101 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10428-1.html)
|
||||
[#]: subject: (Use your Linux terminal to celebrate a banner year)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-figlet)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
使用你的 Linux 终端庆祝新年
|
||||
======
|
||||
|
||||
> 想让你的终端被记住么?将它打在横幅上,不要错过。
|
||||
|
||||

|
||||
|
||||
欢迎再次来到为期 24 天的 Linux 命令行玩具日历。如果这是你第一次访问该系列,你甚至可能会问自己什么是命令行玩具。我们也在思考,但一般来说,它可能是一个游戏,或任何简单的消遣,可以帮助你在终端玩得开心。
|
||||
|
||||
很可能你们中的一些人之前已经看过我们日历中的各种玩具,但我们希望每个人至少见到一件新事物。
|
||||
|
||||
今天的玩具是 `figlet`,一个在 Linux 终端上以横幅形式打印文本的程序。
|
||||
|
||||
你可能会再标准仓库中找到 `figlet`。在我的 Fedora 上,这意味着安装就像下面这样简单:
|
||||
|
||||
```
|
||||
$ sudo dnf install figlet
|
||||
```
|
||||
|
||||
之后,只需使用程序的名称来调用它。你可以以交互方式使用它,或者将一些文本通过管道输入,如下所示:
|
||||
|
||||
```
|
||||
echo "Hello world" | figlet
|
||||
_ _ _ _ _ _
|
||||
| | | | ___| | | ___ __ _____ _ __| | __| |
|
||||
| |_| |/ _ \ | |/ _ \ \ \ /\ / / _ \| '__| |/ _` |
|
||||
| _ | __/ | | (_) | \ V V / (_) | | | | (_| |
|
||||
|_| |_|\___|_|_|\___/ \_/\_/ \___/|_| |_|\__,_|
|
||||
```
|
||||
|
||||
`figlet` 有许多不同的字体。要查看可用的字体,请尝试使用命令 `showfigfonts`。在我这里显示了十几个。我在下面复制了一些我的最爱。
|
||||
|
||||
```
|
||||
block :
|
||||
|
||||
_| _| _|
|
||||
_|_|_| _| _|_| _|_|_| _| _|
|
||||
_| _| _| _| _| _| _|_|
|
||||
_| _| _| _| _| _| _| _|
|
||||
_|_|_| _| _|_| _|_|_| _| _|
|
||||
|
||||
|
||||
bubble :
|
||||
_ _ _ _ _ _
|
||||
/ \ / \ / \ / \ / \ / \
|
||||
( b | u | b | b | l | e )
|
||||
\_/ \_/ \_/ \_/ \_/ \_/
|
||||
|
||||
|
||||
lean :
|
||||
|
||||
_/
|
||||
_/ _/_/ _/_/_/ _/_/_/
|
||||
_/ _/_/_/_/ _/ _/ _/ _/
|
||||
_/ _/ _/ _/ _/ _/
|
||||
_/ _/_/_/ _/_/_/ _/ _/
|
||||
|
||||
|
||||
script :
|
||||
|
||||
o
|
||||
, __ ,_ _ _|_
|
||||
/ \_/ / | | |/ \_|
|
||||
\/ \___/ |_/|_/|__/ |_/
|
||||
/|
|
||||
\|
|
||||
```
|
||||
|
||||
你可以在项目的[主页][1]上找到有关 `figlet` 的更多信息。我下载的版本是以 MIT 许可开源的。
|
||||
|
||||
你会发现 `figlet` 不是唯一的 Linux 终端横幅打印机。另外一个你可以选择的是 [toilet][2],它有一套自己的 ASCII 艺术风格的打印选项。
|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?我们的日历基本上满了,但我们仍然希望在新的一年中展示一些很酷的命令行玩具。请在评论中留言,我会查看的。记得让我知道你对今天玩具的看法。
|
||||
|
||||
一定要看看昨天的玩具,[使用 asciiquarium 在终端中游泳][3],记得明天回来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-figlet
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://www.figlet.org/
|
||||
[2]: http://caca.zoy.org/wiki/toilet
|
||||
[3]: https://opensource.com/article/18/12/linux-toy-asciiquarium
|
||||
@@ -0,0 +1,114 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10491-1.html)
|
||||
[#]: subject: (How to open source your Python library)
|
||||
[#]: via: (https://opensource.com/article/18/12/tips-open-sourcing-python-libraries)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
如何开源你的 Python 库
|
||||
======
|
||||
|
||||
> 这 12 个步骤能确保成功发布。
|
||||
|
||||

|
||||
|
||||
你写了一个 Python 库。自己觉着这太棒了!如果让人们能够轻松使用它不是很优雅么?这有一个需要考虑的清单,以及在开源 Python 库时要采取的具体步骤。
|
||||
|
||||
### 1、源码
|
||||
|
||||
将代码放在 [GitHub][1] 上,这里有很多开源项目,并且人们很容易提交拉取请求。
|
||||
|
||||
### 2、许可证
|
||||
|
||||
选择一个开源许可证。一般来说 [MIT 许可证][2]是一个挺好的宽容许可证。如果你有特定要求,Creative Common 的[选择许可证][3]可以指导你完成其它选择。最重要的是,在选择许可证时要记住三条规则:
|
||||
|
||||
* 不要创建自己的许可证。
|
||||
* 不要创建自己的许可证。
|
||||
* 不要创建自己的许可证。
|
||||
|
||||
### 3、README
|
||||
|
||||
将一个名为 `README.rst` 的文件(使用 ReStructured Text 格式化)放在项目树的顶层。
|
||||
|
||||
GitHub 将像 Markdown 一样渲染 ReStructured Text,而 ReST 在 Python 的文档生态系统中的表现更好。
|
||||
|
||||
### 4、测试
|
||||
|
||||
写测试。这对你来说没有用处。但对于想要编写避免破坏相关功能的补丁的人来说,它非常有用。
|
||||
|
||||
测试可帮助协作者进行协作。
|
||||
|
||||
通常情况下,如果可以用 [pytest][4] 运行就最好了。还有其他测试工具 —— 但很少有理由去使用它们。
|
||||
|
||||
### 5、样式
|
||||
|
||||
使用 linter 制定样式:PyLint、Flake8 或者带上 `--check` 的 Black 。除非你使用 Black,否则请确保在一个文件中指定配置选项,并签入到版本控制系统中。
|
||||
|
||||
### 6、API 文档
|
||||
|
||||
使用 docstrings 来记录模块、函数、类和方法。
|
||||
|
||||
你可以使用几种样式。我更喜欢 [Google 风格的 docstrings][5],但 [ReST docstrings][6] 也是一种选择。
|
||||
|
||||
Sphinx 可以同时处理 Google 风格和 ReST 的 docstrings,以将零散的文档集成为 API 文档。
|
||||
|
||||
### 7、零散文档
|
||||
|
||||
使用 [Sphinx][7]。(阅读[我们这篇文章][8]。)教程很有用,但同样重要的是要指明这是什么、它有什么好处、它有什么坏处、以及任何特殊的考虑因素。
|
||||
|
||||
### 8、构建
|
||||
|
||||
使用 tox 或 nox 自动运行测试和 linter,并构建文档。这些工具支持“依赖矩阵”。这些矩阵往往会快速增长,但你可以尝试针对合理的样本进行测试,例如 Python 版本、依赖项版本以及可能安装的可选依赖项。
|
||||
|
||||
### 9、打包
|
||||
|
||||
使用 [setuptools][9] 工具。写一个 `setup.py` 和一个 `setup.cfg`。如果同时支持 Python 2 和 3,请在 `setup.cfg` 中指定 universal 格式的 wheel。
|
||||
|
||||
tox 或 nox 应该做的一件事是构建 wheel 并对已安装的 wheel 进行测试。
|
||||
|
||||
避免使用 C 扩展。如果出于性能或绑定的原因一定需要它们,请将它们放在单独的包中。正确打包 C 扩展可以写一篇新的文章。这里有很多问题!
|
||||
|
||||
### 10、持续集成
|
||||
|
||||
使用公共持续工具。[TravisCI][10] 和 [CircleCI][11] 为开源项目提供免费套餐。将 GitHub 或其他仓库配置为在合并拉请求之前需要先通过检查,那么你就不必担心在代码评审中告知用户修复测试或样式。
|
||||
|
||||
### 11、版本
|
||||
|
||||
使用 [SemVer][12] 或 [CalVer][13]。有许多工具可以帮助你管理版本:[incremental][14]、[bumpversion][15] 和 [setuptools_scm][16] 等都是 PyPI 上的包,都可以帮助你管理版本。
|
||||
|
||||
### 12、发布
|
||||
|
||||
通过运行 tox 或 nox 并使用 twine 将文件上传到 PyPI 上发布。你可以通过在 [DevPI][17] 中“测试上传”。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/tips-open-sourcing-python-libraries
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://github.com/
|
||||
[2]: https://en.wikipedia.org/wiki/MIT_License
|
||||
[3]: https://choosealicense.com/
|
||||
[4]: https://docs.pytest.org/en/latest/
|
||||
[5]: https://github.com/google/styleguide/blob/gh-pages/pyguide.md
|
||||
[6]: https://www.python.org/dev/peps/pep-0287/
|
||||
[7]: http://www.sphinx-doc.org/en/master/
|
||||
[8]: https://opensource.com/article/18/11/building-custom-workflows-sphinx
|
||||
[9]: https://pypi.org/project/setuptools/
|
||||
[10]: https://travis-ci.org/
|
||||
[11]: https://circleci.com/
|
||||
[12]: https://semver.org/
|
||||
[13]: https://calver.org/
|
||||
[14]: https://pypi.org/project/incremental/
|
||||
[15]: https://pypi.org/project/bumpversion/
|
||||
[16]: https://pypi.org/project/setuptools_scm/
|
||||
[17]: https://opensource.com/article/18/7/setting-devpi
|
||||
@@ -0,0 +1,58 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10426-1.html)
|
||||
[#]: subject: (Solve a puzzle at the Linux command line with nudoku)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-nudoku)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
在 Linux 命令行中使用 nudoku 解决谜题
|
||||
======
|
||||
|
||||
> 数独是简单的逻辑游戏,它可以在任何地方玩,包括在 Linux 终端中。
|
||||
|
||||

|
||||
|
||||
欢迎回到我们为期 24 天的 Linux 命令行玩具日历。如果这是你第一次访问该系列,你甚至可能会问什么是命令行玩具。我们在考虑中,但一般来说,它可能是一个游戏,或任何简单的消遣,可以帮助你在终端玩得开心。
|
||||
|
||||
很可能你们中的一些人之前已经看过我们日历中的各种玩具,但我们希望每个人至少见到一件新事物。
|
||||
|
||||
每年圣诞节,我的岳母都会给我妻子一本数独日历。它接着会在我们的咖啡桌上呆上一年。每天都是一张单独的表格(星期六和星期日除外,它们合并在一页上),这样你每天都有一个新的谜题,同时还有一本能用的日历。
|
||||
|
||||
问题在于在实际中它是一本很好的谜题,但不是一本好的日历,因为事实证明有些日子的题目比其他日子更难,我们没有以每天一个的速度解决它们。然后,我们会在懒散的周日来解决这周堆积的谜题。
|
||||
|
||||
既然我在这个系列的一部分中介绍过[日历][1],那么在这里介绍数独也是公平的,除了我们的命令行版本是解耦的,因此将来很容易就能完成它。
|
||||
|
||||
我在 Fedora 的默认仓库中找到了 `nudoku`,因此安装它就像下面这样简单:
|
||||
|
||||
```
|
||||
$ sudo dnf install nudoku
|
||||
```
|
||||
|
||||
安装完后,只需输入 `nudoku` 即可启动它,之后的操作就很明了。如果你以前从未玩过数独,它它很容易:你只需要确保每行、每列、每个 3x3 构成的方块里都包含了 1-9 的所有数字。
|
||||
|
||||
你可在 [Github][2] 中找到 GPLv3 许可的 `nudoku` 源码
|
||||
|
||||

|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?我们的日历基本上满了,但我们仍然希望在新的一年中展示一些很酷的命令行玩具。请在评论中留言,我会查看的。记得让我知道你对今天玩具的看法。
|
||||
|
||||
一定要看看昨天的玩具,[使用 Linux 终端庆祝丰年][3],记得明天回来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-nudoku
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/18/12/linux-toy-cal
|
||||
[2]: https://github.com/jubalh/nudoku
|
||||
[3]: https://opensource.com/article/18/12/linux-toy-figlet
|
||||
@@ -0,0 +1,341 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (runningwater)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10453-1.html)
|
||||
[#]: subject: (How To Install Microsoft .NET Core SDK On Linux)
|
||||
[#]: via: (https://www.ostechnix.com/how-to-install-microsoft-net-core-sdk-on-linux/)
|
||||
[#]: author: (SK https://www.ostechnix.com/author/sk/)
|
||||
|
||||
如何在 Linux 中安装微软的 .NET Core SDK
|
||||
======
|
||||
|
||||

|
||||
|
||||
**.NET Core** 是微软提供的免费、跨平台和开源的开发框架,可以构建桌面应用程序、移动端应用程序、网络应用程序、物联网应用程序和游戏应用程序等。如果你是 Windows 平台下的 dotnet 开发人员的话,使用 .NET core 可以很轻松就设置好任何 Linux 和类 Unix 操作系统下的开发环境。本分步操作指南文章解释了如何在 Linux 中安装 .NET Core SDK 以及如何使用 .NET 开发出第一个应用程序。
|
||||
|
||||
### Linux 中安装 .NET Core SDK
|
||||
|
||||
.NET Core 支持 GNU/Linux、Mac OS 和 Windows 系统,可以在主流的 GNU/Linux 操作系统上安装运行,包括 Debian、Fedora、CentOS、Oracle Linux、RHEL、SUSE/openSUSE 和 Ubuntu 。在撰写这篇教程时,其最新版本为 **2.2**。
|
||||
|
||||
**Debian 9** 系统上安装 .NET Core SDK,请按如下步骤进行。
|
||||
|
||||
首先,需要注册微软的密钥,接着把 .NET 源仓库地址添加进来,运行的命令如下:
|
||||
|
||||
```
|
||||
$ wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg
|
||||
$ sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
|
||||
$ wget -q https://packages.microsoft.com/config/debian/9/prod.list
|
||||
$ sudo mv prod.list /etc/apt/sources.list.d/microsoft-prod.list
|
||||
$ sudo chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg
|
||||
$ sudo chown root:root /etc/apt/sources.list.d/microsoft-prod.list
|
||||
```
|
||||
|
||||
注册好密钥及添加完仓库源后,就可以安装 .NET SDK 了,命令如下:
|
||||
|
||||
```
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
**Debian 8 系统上安装:**
|
||||
|
||||
增加微软密钥,添加 .NET 仓库源:
|
||||
|
||||
```
|
||||
$ wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg
|
||||
$ sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/
|
||||
$ wget -q https://packages.microsoft.com/config/debian/8/prod.list
|
||||
$ sudo mv prod.list /etc/apt/sources.list.d/microsoft-prod.list
|
||||
$ sudo chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg
|
||||
$ sudo chown root:root /etc/apt/sources.list.d/microsoft-prod.list
|
||||
```
|
||||
|
||||
安装 .NET SDK:
|
||||
|
||||
```
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
**Fedora 28 系统上安装:**
|
||||
|
||||
增加微软密钥,添加 .NET 仓库源:
|
||||
|
||||
```
|
||||
$ sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
|
||||
$ wget -q https://packages.microsoft.com/config/fedora/27/prod.repo
|
||||
$ sudo mv prod.repo /etc/yum.repos.d/microsoft-prod.repo
|
||||
$ sudo chown root:root /etc/yum.repos.d/microsoft-prod.repo
|
||||
```
|
||||
|
||||
现在, 可以安装 .NET SDK 了:
|
||||
|
||||
```
|
||||
$ sudo dnf update
|
||||
$ sudo dnf install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
**Fedora 27 系统下:**
|
||||
|
||||
增加微软密钥,添加 .NET 仓库源,命令如下:
|
||||
|
||||
```
|
||||
$ sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
|
||||
$ wget -q https://packages.microsoft.com/config/fedora/27/prod.repo
|
||||
$ sudo mv prod.repo /etc/yum.repos.d/microsoft-prod.repo
|
||||
$ sudo chown root:root /etc/yum.repos.d/microsoft-prod.repo
|
||||
```
|
||||
|
||||
接着安装 .NET SDK ,命令如下:
|
||||
|
||||
```
|
||||
$ sudo dnf update
|
||||
$ sudo dnf install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
**CentOS/Oracle 版本的 Linux 系统上:**
|
||||
|
||||
增加微软密钥,添加 .NET 仓库源,使其可用:
|
||||
|
||||
```
|
||||
$ sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm
|
||||
```
|
||||
|
||||
更新源仓库,安装 .NET SDK:
|
||||
|
||||
```
|
||||
$ sudo yum update
|
||||
$ sudo yum install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
**openSUSE Leap 版本的系统上:**
|
||||
|
||||
添加密钥,使仓库源可用,安装必需的依赖包,其命令如下:
|
||||
|
||||
```
|
||||
$ sudo zypper install libicu
|
||||
$ sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
|
||||
$ wget -q https://packages.microsoft.com/config/opensuse/42.2/prod.repo
|
||||
$ sudo mv prod.repo /etc/zypp/repos.d/microsoft-prod.repo
|
||||
$ sudo chown root:root /etc/zypp/repos.d/microsoft-prod.repo
|
||||
```
|
||||
|
||||
更新源仓库,安装 .NET SDK,命令如下:
|
||||
|
||||
```
|
||||
$ sudo zypper update
|
||||
$ sudo zypper install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
**Ubuntu 18.04 LTS 版本的系统上:**
|
||||
|
||||
注册微软的密钥和 .NET Core 仓库源,命令如下:
|
||||
|
||||
```
|
||||
$ wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb
|
||||
$ sudo dpkg -i packages-microsoft-prod.deb
|
||||
```
|
||||
|
||||
使 Universe 仓库可用:
|
||||
|
||||
```
|
||||
$ sudo add-apt-repository universe
|
||||
```
|
||||
|
||||
然后,安装 .NET Core SDK ,命令如下:
|
||||
|
||||
```
|
||||
$ sudo apt-get install apt-transport-https
|
||||
$sudo apt-get update
|
||||
$ sudo apt-get install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
**Ubuntu 16.04 LTS 版本的系统上:**
|
||||
|
||||
注册微软的密钥和 .NET Core 仓库源,命令如下:
|
||||
|
||||
```
|
||||
$ wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb
|
||||
$ sudo dpkg -i packages-microsoft-prod.deb
|
||||
```
|
||||
|
||||
然后安装 .NET core SDK:
|
||||
|
||||
```
|
||||
$ sudo apt-get install apt-transport-https
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install dotnet-sdk-2.2
|
||||
```
|
||||
|
||||
### 创建你的第一个应用程序
|
||||
|
||||
我们已经成功的在 Linux 机器中安装了 .NET Core SDK。是时候使用 dotnet 创建第一个应用程序了。
|
||||
|
||||
接下来的目的,我们会创建一个名为 ostechnixApp 的应用程序。为此,可以简单的运行如下命令:
|
||||
|
||||
```
|
||||
$ dotnet new console -o ostechnixApp
|
||||
```
|
||||
|
||||
**示例输出:**
|
||||
|
||||
```
|
||||
Welcome to .NET Core!
|
||||
---------------------
|
||||
Learn more about .NET Core: https://aka.ms/dotnet-docs
|
||||
Use 'dotnet --help' to see available commands or visit: https://aka.ms/dotnet-cli-docs
|
||||
|
||||
Telemetry
|
||||
---------
|
||||
The .NET Core tools collect usage data in order to help us improve your experience. The data is anonymous and doesn't include command-line arguments. The data is collected by Microsoft and shared with the community. You can opt-out of telemetry by setting the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true' using your favorite shell.
|
||||
|
||||
Read more about .NET Core CLI Tools telemetry: https://aka.ms/dotnet-cli-telemetry
|
||||
|
||||
ASP.NET Core
|
||||
------------
|
||||
Successfully installed the ASP.NET Core HTTPS Development Certificate.
|
||||
To trust the certificate run 'dotnet dev-certs https --trust' (Windows and macOS only). For establishing trust on other platforms refer to the platform specific documentation.
|
||||
For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.
|
||||
Getting ready...
|
||||
The template "Console Application" was created successfully.
|
||||
|
||||
Processing post-creation actions...
|
||||
Running 'dotnet restore' on ostechnixApp/ostechnixApp.csproj...
|
||||
Restoring packages for /home/sk/ostechnixApp/ostechnixApp.csproj...
|
||||
Generating MSBuild file /home/sk/ostechnixApp/obj/ostechnixApp.csproj.nuget.g.props.
|
||||
Generating MSBuild file /home/sk/ostechnixApp/obj/ostechnixApp.csproj.nuget.g.targets.
|
||||
Restore completed in 894.27 ms for /home/sk/ostechnixApp/ostechnixApp.csproj.
|
||||
|
||||
Restore succeeded.
|
||||
```
|
||||
|
||||
正如上面的输出所示的,.NET 已经为我们创建一个控制台类型的应用程序。`-o` 参数创建了一个名为 “ostechnixApp” 的目录,其包含有存储此应用程序数据所必需的文件。
|
||||
|
||||
让我们切换到 ostechnixApp 目录,看看里面有些什么。
|
||||
|
||||
```
|
||||
$ cd ostechnixApp/
|
||||
$ ls
|
||||
obj ostechnixApp.csproj Program.cs
|
||||
```
|
||||
|
||||
可以看到有两个名为 `ostechnixApp.csproj` 和 `Program.cs` 的文件,以及一个名为 `ojb` 的目录。默认情况下, `Program.cs` 文件包含有可以在控制台中运行的 “Hello World” 程序代码。可以看看此代码:
|
||||
|
||||
```
|
||||
$ cat Program.cs
|
||||
using System;
|
||||
|
||||
namespace ostechnixApp
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
要运行此应用程序,可以简单的使用如下命令:
|
||||
|
||||
```
|
||||
$ dotnet run
|
||||
Hello World!
|
||||
```
|
||||
|
||||

|
||||
|
||||
很简单,对吧?是的,就是如此简单。现在你可以在 `Program.cs` 这文件中写上自己的代码,然后像上面所示的执行。
|
||||
|
||||
或者,你可以创建一个新的目录,如例子所示的 `mycode` 目录,命令如下:
|
||||
|
||||
```
|
||||
$ mkdir ~/.mycode
|
||||
$ cd mycode/
|
||||
```
|
||||
|
||||
然后运行如下命令,使其成为你的新开发环境目录:
|
||||
|
||||
```
|
||||
$ dotnet new console
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
```
|
||||
The template "Console Application" was created successfully.
|
||||
|
||||
Processing post-creation actions...
|
||||
Running 'dotnet restore' on /home/sk/mycode/mycode.csproj...
|
||||
Restoring packages for /home/sk/mycode/mycode.csproj...
|
||||
Generating MSBuild file /home/sk/mycode/obj/mycode.csproj.nuget.g.props.
|
||||
Generating MSBuild file /home/sk/mycode/obj/mycode.csproj.nuget.g.targets.
|
||||
Restore completed in 331.87 ms for /home/sk/mycode/mycode.csproj.
|
||||
|
||||
Restore succeeded.
|
||||
```
|
||||
|
||||
上的命令会创建两个名叫 `mycode.csproj` 和 `Program.cs` 的文件及一个名为 `obj` 的目录。用你喜欢的编辑器打开 `Program.cs` 文件, 删除或修改原来的 “hello world” 代码段,然后编写自己的代码。
|
||||
|
||||
写完代码,保存,关闭 `Program.cs` 文件,然后运行此应用程序,命令如下:
|
||||
|
||||
```
|
||||
$ dotnet run
|
||||
```
|
||||
|
||||
想要查看安装的 .NET core SDK 的版本的话,可以简单的运行:
|
||||
|
||||
```
|
||||
$ dotnet --version
|
||||
2.2.101
|
||||
```
|
||||
|
||||
要获得帮助,请运行:
|
||||
|
||||
```
|
||||
$ dotnet --help
|
||||
```
|
||||
|
||||
### 使用微软的 Visual Studio Code 编辑器
|
||||
|
||||
要编写代码,你可以任选自己喜欢的编辑器。同时微软自己也有一款支持 .NET 的编辑器,其名为 “Microsoft Visual Studio Code”。它是一款开源、轻量级、功能强大的源代码编辑器。其内置了对 JavaScript、TypeScript 和 Node.js 的支持,并为其它语言(如 C++、C#、Python、PHP、Go)和运行时态(如 .NET 和 Unity)提供了丰富的扩展,已经形成一个完整的生态系统。它是一款跨平台的代码编辑器,所以在微软的 Windows 系统、GNU/Linux 系统和 Mac OS X 系统都可以使用。如果对其感兴趣,就可以使用。
|
||||
|
||||
想了解如何在 Linux 上安装和使用,请参阅以下指南。
|
||||
|
||||
[Linux 中安装 Microsoft Visual Studio Code][3]
|
||||
|
||||
关于 Visual Studio Code editor 中 .NET Core 和 .NET Core SDK 工具的使用,[此网页][1]有一些基础的教程。想了解更多就去看看吧。
|
||||
|
||||
### Telemetry
|
||||
|
||||
默认情况下,.NET core SDK 会采集用户使用情况数据,此功能被称为 Telemetry。采集数据是匿名的,并根据[知识共享署名许可][2]分享给其开发团队和社区。因此 .NET 团队会知道这些工具的使用状况,然后根据统计做出决策,改进产品。如果你不想分享自己的使用信息的话,可以使用顺手的 shell 工具把名为 `DOTNET_CLI_TELEMETRY_OPTOUT` 的环境变量参数设置为 `1` 或 `true`,这样就简单的关闭此功能了。
|
||||
|
||||
就这样。你已经知道如何在各 Linux 平台上安装 .NET Core SDK 以及知道如何创建基本的应用程序了。想了解更多 .NET 使用知识的话,请参阅此文章末尾给出的链接。
|
||||
|
||||
会爆出更多干货的。敬请关注!
|
||||
|
||||
祝贺下!
|
||||
|
||||
### 资源
|
||||
|
||||
- [.NET Core](https://dotnet.microsoft.com/)
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-install-microsoft-net-core-sdk-on-linux/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[runningwater](https://github.com/runningwater)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://docs.microsoft.com/en-us/dotnet/core/tutorials/index
|
||||
[2]: https://creativecommons.org/licenses/by/4.0/
|
||||
[3]: https://www.ostechnix.com/install-microsoft-visual-studio-code-linux/
|
||||
@@ -0,0 +1,64 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (zhs852)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10416-1.html)
|
||||
[#]: subject: (Let your Linux terminal speak its mind)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-espeak)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
让 Linux 终端说出它的想法
|
||||
======
|
||||
|
||||
> eSpeak 是一个可在 Linux 命令行中使用的开源的 TTS 合成器。
|
||||
|
||||

|
||||
|
||||
欢迎回到《24 天介绍 Linux 命令行小玩具》。如果这是你首次阅读本系列文章,你可能不知道什么是 Linux 命令行小玩具。无需担心,你只需要边看边体会。通常来说,它有可能是游戏或其它能让你在终端中娱乐的小程序。
|
||||
|
||||
或许你已经对一些玩具有了解了,不过我们相信,在本系列文章中总有那么几个你没见过的玩意。
|
||||
|
||||
年轻读者可能不知道,在 Alexa、Siri 或 Google Assistant 问世之前,计算机就能说话了。
|
||||
|
||||
我们也许永远不会忘记来自 [2001 太空漫游][1] 中与机组人员交流的 HAL 9000。但是在 1960 年代到今天的时间里,是存在着许多能说话的计算机的。它们有些很出色,也有些不那么出色。
|
||||
|
||||
其中一个我最爱的是一个叫做 [eSpeak][2] 的开源项目。它以多种形式发布,比如可以嵌入你自己项目中的库。与此同时,它也提供了可供你安装的命令行版本。在我所用的发行版中,安装十分简单,只需使用:
|
||||
|
||||
```
|
||||
$ sudo dnf install espeak
|
||||
```
|
||||
|
||||
你既可以与 eSpeak 交互,也可以用它来输出其它程序的信息,甚至通过简单的 `echo` 命令来使用它。[这里][3] 有一些可供 eSpeak 使用的声音文件,你可以在无聊时切换他们。甚者你可以制作一个属于你自己的声音。
|
||||
|
||||
在 2015 年,一些希望继续 eSpeak 开发的开发者创建了一个名为 eSpeak NG (即 “Next Generation”,“下一代”的意思)的项目。eSpeak 目前在 GPL v3 许可证下开源,你可以在 [SourceForge][2] 上详细了解这个项目或下载源代码。
|
||||
|
||||
别急,我今天还会介绍一个额外的小程序,它叫 [cava][4]。我经常希望用一张独一无二的截图作为我文章的头图,更何况今天的玩具主要是关于声音的,这就图片更少了。因此,我需要一些东西来填补这些空白。Cava 是<ruby>基于 ALSA 的命令行音频可视化工具<rt>console-based audio visualizer for ALSA</rt></ruby>的简写(尽管它现在支持的比 ALSA 更多),它是一个优秀的命令行音频可视化工具,并且它正以 MIT 许可证开源。下面是一个将 eSpeak 输出可视化的命令:
|
||||
|
||||
```
|
||||
$ echo "Rudolph, the red-nosed reindeer, had a very shiny nose." | espeak
|
||||
```
|
||||
|
||||

|
||||
|
||||
你想让作者介绍你喜欢的命令行玩具吗?请前往原文下留言,作者可能会考虑介绍的。同时,你也可以去原文下评论你对文章的看法。
|
||||
|
||||
欢迎去看看我们昨天介绍的玩具,[在 Linux 命令行中使用 nudoku 解决谜题][5]。敬请期待我们明天的文章吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-espeak
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zhs852](https://github.com/zhs852)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://en.wikipedia.org/wiki/2001:_A_Space_Odyssey_(film)
|
||||
[2]: http://espeak.sourceforge.net/
|
||||
[3]: http://espeak.sourceforge.net/voices.html
|
||||
[4]: https://github.com/karlstav/cava
|
||||
[5]: https://opensource.com/article/18/12/linux-toy-nudoku
|
||||
@@ -0,0 +1,195 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (dianbanjiu)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10438-1.html)
|
||||
[#]: subject: (An Easy Way To Remove Programs Installed From Source In Linux)
|
||||
[#]: via: (https://www.ostechnix.com/an-easy-way-to-remove-programs-installed-from-source-in-linux/)
|
||||
[#]: author: (SK https://www.ostechnix.com/author/sk/)
|
||||
|
||||
在 Linux 中移除从源代码安装的程序的一种简单的方法
|
||||
======
|
||||
|
||||

|
||||
|
||||
不是所有的程序都可以在官方或者第三方库中找到,因此你不能使用常规的包管理来安装它们。有时你不得不从源代码中手动构建这些程序。就如你已经知道的一样,当你从源代码中安装一个程序的时候,这个软件包所包含的文件将会复制到本地的多个位置,例如 `/usr/local/bin`、`/usr/local/etc/`。如果从源代码中安装的程序没有内置的卸载程序,当你不再需要这个程序的时候,卸载它就会很麻烦。你可能会花费双倍(甚至更多)的时间找出这些文件然后手动删除它们。我以前一直是这样做的,直到我发现了 GNU Stow。谢天谢地,Stow 有一个很棒的方法可以轻松管理从源代码安装的程序。
|
||||
|
||||
引用官方网站里的一段介绍,
|
||||
|
||||
> GNU Stow 是一个符号链接归集管理器,它可以收集文件系统上不同目录中的不同软件和/或数据包,使它们看起来像是一个整体。
|
||||
|
||||
简单来说,Stow 帮助你把这些程序文件以一种容易管理的方式组织在了一起。在这个方法中,文件将不会被复制到多个位置。所有的这些文件都会被保存在一个特定的文件夹中,通常是以程序名命名的,然后 Stow 会在一个合适的位置为所有的程序文件创建符号连接。比如 `/usr/local/bin` 中会包含 `/usr/local/stow/vim/bin`、`/usr/local/stow/python/bin` 中文件的符号链接。并且同样递归地用于其他的任何的子目录,例如 `.../share`、`.../man`,等等。在这篇教程中,我将会举例教你如何轻松地使用 Stow 管理从源中安装的程序。
|
||||
|
||||
### 安装 GNU Stow
|
||||
|
||||
GNU Stow 在流行 Linux 操作系统的默认库中都可用。
|
||||
|
||||
在 Arch Linux 及它的衍生版本中,运行下面的命令安装 Stow。
|
||||
|
||||
```
|
||||
$ sudo pacman -S stow
|
||||
```
|
||||
|
||||
在 Debian、Ubuntu、Linux Mint 上:
|
||||
|
||||
```
|
||||
$ sudo apt install stow
|
||||
```
|
||||
|
||||
在 Fedora 上:
|
||||
|
||||
```
|
||||
$ sudo dnf install stow
|
||||
```
|
||||
|
||||
在 RHEL/CentOS 上:
|
||||
|
||||
```
|
||||
$ sudo yum install epel-release
|
||||
$ sudo yum install stow
|
||||
```
|
||||
|
||||
### 在 Linux 上轻松移除从源代码安装的程序
|
||||
|
||||
就像我之前提到的,所有包的程序文件都将被保存在位于 `/usr/local/stow/` 的一个根文件夹。在这个根文件夹或者父目录之下,每个包都将保存在对应的子目录中。例如,如果我们从源代码中安装了 Vim 编辑器,所有关联到 Vim 的程序文件和目录都将保存在 `/usr/local/stow/vim` 文件夹之下。如果你从源代码中安装了 Python,所有关联到 python 的文件都会保存在 `/usr/local/stow/python` 之下。
|
||||
|
||||
我现在从源代码中来安装一个叫做 hello 的程序。
|
||||
|
||||
首先下载 hello 程序的压缩包。
|
||||
|
||||
```
|
||||
$ wget http://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz
|
||||
```
|
||||
|
||||
使用下面的命令解压压缩包:
|
||||
|
||||
```
|
||||
$ tar -zxvf hello-2.10.tar.gz
|
||||
```
|
||||
|
||||
上面的命令将会在当前工作目录下创建一个叫做 `hello-2.10` 的目录,并且提取压缩包中的所有内容到其中去。
|
||||
|
||||
切换到这个目录当中:
|
||||
|
||||
```
|
||||
$ cd hello-2.10/
|
||||
```
|
||||
|
||||
运行下面的命令,并且添加 `-prefix` 选项。
|
||||
|
||||
```
|
||||
$ ./configure --prefix=/usr/local/stow/hello
|
||||
```
|
||||
|
||||
上面的命令将会保存构建文件到一个指定位置,在这个例子中是 `/usr/local/stow/hello`。
|
||||
|
||||
最后,使用下面的命令构建并安装 hello 这个程序:
|
||||
|
||||
```
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
就这样。hello 这个程序就已经安装在 `/usr/local/stow/hello/` 这个位置了。你可以使用下面的 `ls` 命令确认一下。
|
||||
|
||||
```
|
||||
$ ls /usr/local/stow/hello/
|
||||
bin share
|
||||
```
|
||||
|
||||
最后,进入 `/usr/local/stow/` 目录,运行下面的命令来生成必要的符号链接。
|
||||
|
||||
```
|
||||
$ cd /usr/local/stow/
|
||||
$ sudo stow hello
|
||||
```
|
||||
|
||||
大功告成!
|
||||
|
||||
刚才那一步是将包含在 hello 这个程序中的所有文件或者目录创建了链接到 `/usr/local/` 目录中。换一种说法, `/usr/local/stow/hello/bin` 链接到 `/usr/local/share`,以及 `/usr/local/stow/hello/share/man` 链接到 `/usr/local/share`,还有 `/usr/local/stow/hello/share/man` 链接到 `/usr/local/share/man`。
|
||||
|
||||
你可以使用 `ls` 命令来确认一下:
|
||||
|
||||
```
|
||||
$ ls /usr/local/bin/
|
||||
hello
|
||||
```
|
||||
|
||||
可以使用下面的命令来确认 hello 这个程序是否可以正常工作了:
|
||||
|
||||
```
|
||||
$ hello
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
很好,它已经开始工作了!!
|
||||
|
||||
类似地,你可以像上面描述的那样安装程序到它对应的子目录下。
|
||||
|
||||
下面是 Stow 根目录包含的内容:
|
||||
|
||||
```
|
||||
$ tree /usr/local/stow/
|
||||
```
|
||||
|
||||
![][2]
|
||||
|
||||
看,hello 这个程序已经安装在 `/usr/local/stow/hello/` 下。同样地,所有的包都将保存在它们对应的目录之下。
|
||||
|
||||
下面进入主要环节,移除 hello 这个程序。首先进入 `/usr/local/stow/` 目录:
|
||||
|
||||
```
|
||||
$ cd /usr/local/stow/
|
||||
```
|
||||
|
||||
然后运行下面的命令:
|
||||
|
||||
```
|
||||
$ sudo stow --delete hello
|
||||
```
|
||||
|
||||
hello 这个程序就会被移除了。你可以使用下面的命令确认它是否真的被移除了:
|
||||
|
||||
```
|
||||
$ hello
|
||||
-bash: /usr/local/bin/hello: No such file or directory
|
||||
```
|
||||
|
||||
![][3]
|
||||
|
||||
看, Hello 已经被移除了!
|
||||
|
||||
请注意 Stow 仅仅只移除了符号链接。所有与 hello 这个程序相关的文件或者目录还保存在 `/usr/local/stow/hello` 目录下。所以你无需再次下载源文件就可以再次安装 hello 这个程序。如果你不再需要它了,直接删除这个文件夹即可。
|
||||
|
||||
```
|
||||
$ sudo rm -fr /usr/local/stow/hello/
|
||||
```
|
||||
|
||||
想了解更多 Stow 的细节,请参阅 man 手册。
|
||||
|
||||
```
|
||||
$ man stow
|
||||
```
|
||||
|
||||
Stow 可以像安装程序一样轻松地帮你移除它。如果你想知道如何高效的管理很多从源代码中安装的程序,GNU Stow 就是一个使得这个任务更加轻松的一个选择,尝试一下,你一定不会失望的。
|
||||
|
||||
这就是所有的内容了,希望对你有所帮助。还有更多干活即将到来,可以期待一下的!
|
||||
|
||||
祝近祺!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/an-easy-way-to-remove-programs-installed-from-source-in-linux/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[dianbanjiu](https://github.com/dianbanjiu)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]: http://www.ostechnix.com/wp-content/uploads/2018/12/tree-command.png
|
||||
[3]: http://www.ostechnix.com/wp-content/uploads/2018/12/hello-world.png
|
||||
@@ -0,0 +1,282 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10405-1.html)
|
||||
[#]: subject: (How to Build a Netboot Server, Part 3)
|
||||
[#]: via: (https://fedoramagazine.org/how-to-build-a-netboot-server-part-3/)
|
||||
[#]: author: (Gregory Bartholomew https://fedoramagazine.org/author/glb/)
|
||||
|
||||
如何构建一台网络引导服务器(三)
|
||||
======
|
||||
|
||||

|
||||
|
||||
在 [如何构建一台网络引导服务器(一)][1] 中,我们提供了一个极简的 [iPXE][2] 引导脚本来引导你的网络引导镜像。许多用户除了使用网络引导镜像外,可能在机器本地也有一个操作系统。但是使用常见的工作站的 BIOS 去切换引导加载器是很笨拙的。在本系列文件的第三部分,我们将向你展示如何设置一个更复杂的 iPXE 配置。它将允许终端用户以更容易的方式去选择引导哪个操作系统。它也可以配置为让系统管理员从一台中央服务器来统一管理引导菜单。
|
||||
|
||||
### 一个交互式 iPXE 引导菜单
|
||||
|
||||
下面这些命令重定义了网络引导镜像的 `boot.cfg` 来作为一个交互式的 iPXE 引导菜单,并使用了一个 5 秒倒计时的定时器:
|
||||
|
||||
```
|
||||
$ MY_FVER=29
|
||||
$ MY_KRNL=$(ls -c /fc$MY_FVER/lib/modules | head -n 1)
|
||||
$ MY_DNS1=192.0.2.91
|
||||
$ MY_DNS2=192.0.2.92
|
||||
$ MY_NAME=server-01.example.edu
|
||||
$ MY_EMAN=$(echo $MY_NAME | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_NAME})
|
||||
$ MY_ADDR=$(host -t A $MY_NAME | awk '{print $4}')
|
||||
$ cat << END > $HOME/esp/linux/boot.cfg
|
||||
#!ipxe
|
||||
|
||||
set timeout 5000
|
||||
|
||||
:menu
|
||||
menu iPXE Boot Menu
|
||||
item --key 1 lcl 1. Microsoft Windows 10
|
||||
item --key 2 f$MY_FVER 2. RedHat Fedora $MY_FVER
|
||||
choose --timeout \${timeout} --default lcl selected || goto shell
|
||||
set timeout 0
|
||||
goto \${selected}
|
||||
|
||||
:failed
|
||||
echo boot failed, dropping to shell...
|
||||
goto shell
|
||||
|
||||
:shell
|
||||
echo type 'exit' to get the back to the menu
|
||||
set timeout 0
|
||||
shell
|
||||
goto menu
|
||||
|
||||
:lcl
|
||||
exit
|
||||
|
||||
:f$MY_FVER
|
||||
kernel --name kernel.efi \${prefix}/vmlinuz-$MY_KRNL initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=$MY_DNS1 nameserver=$MY_DNS2 root=/dev/disk/by-path/ip-$MY_ADDR:3260-iscsi-iqn.$MY_EMAN:fc$MY_FVER-lun-1 netroot=iscsi:$MY_ADDR::::iqn.$MY_EMAN:fc$MY_FVER console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
|
||||
initrd --name initrd.img \${prefix}/initramfs-$MY_KRNL.img
|
||||
boot || goto failed
|
||||
END
|
||||
```
|
||||
|
||||
上述菜单有五个节:
|
||||
|
||||
* `menu` 定义了显示在屏幕上的实际菜单内容。
|
||||
* `failed` 提示用户发生了错误,并将用户带到 shell 以错误错误。
|
||||
* `shell` 提供了交互式命令提示符。你可以在引导菜单出现时按下 `Esc` 键进入,或者是
|
||||
`boot` 命令失败时也会进入到命令提示符。
|
||||
* `lcl` 包含一个提供给 iPXE 退出的简单命令,以及返还控制权给 BIOS。在 iPXE 之后,无论你希望缺省引导的设备(即:工作站的本地硬件)是什么,都必须在你的工作站的 BIOS 中正确地作为下一个引导设备列出来。
|
||||
* `f29` 包含前面文章提到同一个网络引导代码,但使用最终的退出代码来替换掉 `goto failed`。
|
||||
|
||||
从你的 `$HOME/esp/linux` 目录中复制更新后的 `boot.cfg` 到所有客户端系统的 ESP 中。如果一切顺利,你应该会看到类似下面图片的结果:
|
||||
|
||||
![][3]
|
||||
|
||||
### 一个服务器托管的引导菜单
|
||||
|
||||
你可以添加到网络引导服务器的另一个特性是,能够从一台中央位置去管理所有客户端的引导菜单。这个特性尤其适用于批量安装(升级)一个新版本的操作系统。在你将新内核和新的 `initramfs` 复制到所有客户端的 ESP 之后,这个特性可以让你执行一种 [原子事务][4] 去切换所有客户端到新操作系统。
|
||||
|
||||
安装 Mojolicious:
|
||||
|
||||
```
|
||||
$ sudo -i
|
||||
# dnf install -y perl-Mojolicious
|
||||
```
|
||||
|
||||
定义 “bootmenu” 应用程序:
|
||||
|
||||
```
|
||||
# mkdir /opt/bootmenu
|
||||
# cat << END > /opt/bootmenu/bootmenu.pl
|
||||
#!/usr/bin/env perl
|
||||
use Mojolicious::Lite;
|
||||
use Mojolicious::Plugins;
|
||||
|
||||
plugin 'Config';
|
||||
|
||||
get '/menu';
|
||||
|
||||
app->start;
|
||||
END
|
||||
# chmod 755 /opt/bootmenu/bootmenu.pl
|
||||
```
|
||||
|
||||
为 “bootmenu” 应用程序定义配置文件:
|
||||
|
||||
```
|
||||
# cat << END > /opt/bootmenu/bootmenu.conf
|
||||
{
|
||||
hypnotoad => {
|
||||
listen => ['http://*:80'],
|
||||
pid_file => '/run/bootmenu/bootmenu.pid',
|
||||
}
|
||||
}
|
||||
END
|
||||
```
|
||||
|
||||
这是一个非常简单的 Mojolicious 应用程序,它监听 80 端口,并且只回应对 `/menu` 的请求。如果你想快速了解 Mojolicious 能做什么,运行 `man Mojolicious::Guides::Growing` 去查看手册。按 `Q` 键退出手册。
|
||||
|
||||
将 `boot.cfg` 移到我们的网络引导应用程序中作为一个名为 `menu.html.ep` 的模板:
|
||||
|
||||
```
|
||||
# mkdir /opt/bootmenu/templates
|
||||
# mv $HOME/esp/linux/boot.cfg /opt/bootmenu/templates/menu.html.ep
|
||||
```
|
||||
|
||||
定义一个 systemd 服务去管理引导菜单应用程序:
|
||||
|
||||
```
|
||||
# cat << END > /etc/systemd/system/bootmenu.service
|
||||
[Unit]
|
||||
Description=Serves iPXE Menus over HTTP
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
DynamicUser=true
|
||||
RuntimeDirectory=bootmenu
|
||||
PIDFile=/run/bootmenu/bootmenu.pid
|
||||
ExecStart=/usr/bin/hypnotoad /opt/bootmenu/bootmenu.pl
|
||||
ExecReload=/usr/bin/hypnotoad /opt/bootmenu/bootmenu.pl
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
KillMode=process
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
END
|
||||
```
|
||||
|
||||
在本地防火墙中为 HTTP 服务添加一个例外规则,并启动 bootmenu 服务:
|
||||
|
||||
```
|
||||
# firewall-cmd --add-service http
|
||||
# firewall-cmd --runtime-to-permanent
|
||||
# systemctl enable bootmenu.service
|
||||
# systemctl start bootmenu.service
|
||||
```
|
||||
|
||||
用 `wget` 测试它:
|
||||
|
||||
```
|
||||
$ sudo dnf install -y wget
|
||||
$ MY_BOOTMENU_SERVER=server-01.example.edu
|
||||
$ wget -q -O - http://$MY_BOOTMENU_SERVER/menu
|
||||
```
|
||||
|
||||
以上的命令应该会输出类似下面的内容:
|
||||
|
||||
```
|
||||
#!ipxe
|
||||
|
||||
set timeout 5000
|
||||
|
||||
:menu
|
||||
menu iPXE Boot Menu
|
||||
item --key 1 lcl 1. Microsoft Windows 10
|
||||
item --key 2 f29 2. RedHat Fedora 29
|
||||
choose --timeout ${timeout} --default lcl selected || goto shell
|
||||
set timeout 0
|
||||
goto ${selected}
|
||||
|
||||
:failed
|
||||
echo boot failed, dropping to shell...
|
||||
goto shell
|
||||
|
||||
:shell
|
||||
echo type 'exit' to get the back to the menu
|
||||
set timeout 0
|
||||
shell
|
||||
goto menu
|
||||
|
||||
:lcl
|
||||
exit
|
||||
|
||||
:f29
|
||||
kernel --name kernel.efi ${prefix}/vmlinuz-4.19.4-300.fc29.x86_64 initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc29-lun-1 netroot=iscsi:192.0.2.158::::iqn.edu.example.server-01:fc29 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
|
||||
initrd --name initrd.img ${prefix}/initramfs-4.19.4-300.fc29.x86_64.img
|
||||
boot || goto failed
|
||||
```
|
||||
|
||||
现在,引导菜单服务器已经正常工作了,重新构建 `ipxe.efi` 引导加载器,使用一个初始化脚本指向它。
|
||||
|
||||
第一步,先更新我们在本系列文章的第一部分中创建的 `init.ipxe` 脚本:
|
||||
|
||||
```
|
||||
$ MY_BOOTMENU_SERVER=server-01.example.edu
|
||||
$ cat << END > $HOME/ipxe/init.ipxe
|
||||
#!ipxe
|
||||
|
||||
dhcp || exit
|
||||
set prefix file:///linux
|
||||
chain http://$MY_BOOTMENU_SERVER/menu || exit
|
||||
END
|
||||
```
|
||||
|
||||
现在,重新构建引导加载器:
|
||||
|
||||
```
|
||||
$ cd $HOME/ipxe/src
|
||||
$ make clean
|
||||
$ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe
|
||||
```
|
||||
|
||||
将更新后的引导加载器复制到你的 ESP 中:
|
||||
|
||||
```
|
||||
$ cp $HOME/ipxe/src/bin-x86_64-efi/ipxe.efi $HOME/esp/efi/boot/bootx64.efi
|
||||
```
|
||||
|
||||
将更新后的引导加载器复制到所有的客户端中之后,以后更新引导菜单只需要简单地编辑 `/opt/bootmenu/templates/menu.html.ep` 文件,然后再运行如下命令:
|
||||
|
||||
```
|
||||
$ sudo systemctl restart bootmenu.service
|
||||
```
|
||||
|
||||
### 做一步的改变
|
||||
|
||||
如果引导菜单服务器工作正常,在你的客户端系统上的 `boot.cfg` 文件将更长。
|
||||
|
||||
比如,重新添加 Fedora 28 镜像到引导菜单中:
|
||||
|
||||
```
|
||||
$ sudo -i
|
||||
# MY_FVER=28
|
||||
# MY_KRNL=$(ls -c /fc$MY_FVER/lib/modules | head -n 1)
|
||||
# MY_DNS1=192.0.2.91
|
||||
# MY_DNS2=192.0.2.92
|
||||
# MY_NAME=$(</etc/hostname)
|
||||
# MY_EMAN=$(echo $MY_NAME | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_NAME})
|
||||
# MY_ADDR=$(host -t A $MY_NAME | awk '{print $4}')
|
||||
# cat << END >> /opt/bootmenu/templates/menu.html.ep
|
||||
|
||||
:f$MY_FVER
|
||||
kernel --name kernel.efi \${prefix}/vmlinuz-$MY_KRNL initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=$MY_DNS1 nameserver=$MY_DNS2 root=/dev/disk/by-path/ip-$MY_ADDR:3260-iscsi-iqn.$MY_EMAN:fc$MY_FVER-lun-1 netroot=iscsi:$MY_ADDR::::iqn.$MY_EMAN:fc$MY_FVER console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
|
||||
initrd --name initrd.img \${prefix}/initramfs-$MY_KRNL.img
|
||||
boot || goto failed
|
||||
END
|
||||
# sed -i "/item --key 2/a item --key 3 f$MY_FVER 3. RedHat Fedora $MY_FVER" /opt/bootmenu/templates/menu.html.ep
|
||||
# systemctl restart bootmenu.service
|
||||
```
|
||||
|
||||
如果一切顺利,你的客户端下次引导时,应该看到如下图所示的结果:
|
||||
|
||||
![][5]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/how-to-build-a-netboot-server-part-3/
|
||||
|
||||
作者:[Gregory Bartholomew][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/glb/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linux.cn/article-10379-1.html
|
||||
[2]: https://ipxe.org/
|
||||
[3]: https://fedoramagazine.org/wp-content/uploads/2018/11/netboot-menu-1024x641.png
|
||||
[4]: https://en.wikipedia.org/wiki/Atomicity_(database_systems)
|
||||
[5]: https://fedoramagazine.org/wp-content/uploads/2018/11/netboot-menu-updated-1024x641.png
|
||||
75
published/201901/20181222 A Tale of HTTP-2.md
Normal file
75
published/201901/20181222 A Tale of HTTP-2.md
Normal file
@@ -0,0 +1,75 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10404-1.html)
|
||||
[#]: subject: (A Tale of HTTP/2)
|
||||
[#]: via: (https://veronneau.org/a-tale-of-http2.html)
|
||||
[#]: author: (Louis-Philippe Véronneau https://veronneau.org/)
|
||||
|
||||
一个 HTTP/2 的故事
|
||||
======
|
||||
|
||||
大约一个月前,有人在我所在的 IRC 频道中提到了 [HTTP/2][1]。由于某种原因,我从未听说过它,而且新协议的一些功能(比如无需打开多个 TCP 连接就能复用请求)似乎很酷。
|
||||
|
||||
说实话,我刚刚重写了管理我们备份程序的 Puppet 代码,启用 HTTP/2 似乎是一种转向另一个大型项目之前有效的拖延方式。这有多难?
|
||||
|
||||
结果我花了大约 25 个小时来完成。坐下来穿上舒适的拖鞋,听听这个 HTTP/2 的故事!
|
||||
|
||||
[![The Yule Log][2]][3]
|
||||
|
||||
### 被诅咒的 HTTP/1.1
|
||||
|
||||
当我第一次看到如何在 Apache 上启用 HTTP/2 时,这似乎是一项非常简单的任务。文档提到加载 `http2` 模块并通过如下配置文件确保新协议优先:
|
||||
|
||||
```
|
||||
Protocols h2 h2c http/1.1
|
||||
|
||||
H2Push on
|
||||
H2PushPriority * after
|
||||
H2PushPriority text/css before
|
||||
H2PushPriority image/jpeg after 32
|
||||
H2PushPriority image/png after 32
|
||||
H2PushPriority application/javascript interleaved
|
||||
```
|
||||
|
||||
这当然很容易。即使 Apache 中的所有内容都已正确设置,网站仍然使用的是 HTTP/1.1。不过,显然我做得没错,因为我的网站现在发送了一个新的 HTTP 头:`Upgrade: h2, h2c`。
|
||||
|
||||
在浪费了大量时间调试 TLS 密钥(HTTP/2 [与 TLS 1.1 不兼容][4])之后,我终于发现问题是没有使用正确的 Apache 多进程处理模块。
|
||||
|
||||
事实证明,在使用 `mpm_prefork`(默认 MPM)时,Apache 不会使用 HTTP/2,因为 `mod_http2` 不支持它。尽管 Apache 还有两个其他的 MPM,但只有 `mpm_prefork` 支持 `mod_php`。突然之间,添加对 HTTP/2 的支持意味着我们将要把所有的 PHP 网站切换到 PHP-FPM。
|
||||
|
||||
### 掉进兔子洞
|
||||
|
||||
![A clip from Alice in Wonderlands][5]
|
||||
|
||||
在很长一段时间里,一位好友一直试图让我相信 [PHP-FPM][6] 的优点。虽然表面上看起来很好,但我从来没有真正试过。它看起来很复杂。常规的 `mod_php` 做得很好,还有其他事情需要我注意。
|
||||
|
||||
事实上,这次的 HTTP/2 事件是让我钻研它的一个契机。在我理解了 FPM 池的工作原理后,它实际上很容易设置。由于我不得不重写我们用于部署网站的 Puppet 配置文件,我也借此机会巩固了一堆东西。
|
||||
|
||||
PHP-FPM 允许你在不同的 Unix 用户下运行网站来增加隔离性。最重要的是,我决定是时候让我们服务器上的 PHP 代码以只读模式运行,并且不得不为我们的 Wordpress、Nextcloud、KanBoard 和 Drupal 实例调整一些东西来减少报错。
|
||||
|
||||
过了很长时间通过 Puppet 的自动任务后,我终于能够全部关闭 `mod_php` 和 `mpm_prefork` 并启用 `mpm_event` 和 `mod_http2`。PHP-FPM 和 HTTP/2 带来的速度提升不错,但更让我感到高兴的是这次磨练增强了我们的 Apache 处理 PHP 的能力。
|
||||
|
||||
![Victory!][7]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://veronneau.org/a-tale-of-http2.html
|
||||
|
||||
作者:[Louis-Philippe Véronneau][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://veronneau.org/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://en.wikipedia.org/wiki/HTTP/2
|
||||
[2]: https://veronneau.org/media/blog/2018-12-22/yule_log.jpg (The Yule Log)
|
||||
[3]: https://commons.wikimedia.org/wiki/File:The_Yule_Log.jpg
|
||||
[4]: https://http2.github.io/http2-spec/#TLSUsage
|
||||
[5]: https://veronneau.org/media/blog/2018-12-22/mod_php.gif (A clip from Alice in Wonderlands)
|
||||
[6]: https://wiki.apache.org/httpd/PHP-FPM
|
||||
[7]: https://veronneau.org/media/blog/2018-12-22/victory.png (Victory!)
|
||||
@@ -0,0 +1,330 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (zhs852)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10407-1.html)
|
||||
[#]: subject: (Top 11 best Image Viewer for Ubuntu and other Linux)
|
||||
[#]: via: (https://itsfoss.com/image-viewers-linux/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Linux 下最棒的 11 个图片查看器
|
||||
======
|
||||
|
||||
如果不是因为系统自带的图片查看器没有你想要的功能,或者你想要更棒的体验,你大概不会想切换到其它图片查看器吧。
|
||||
|
||||
不过,如果你喜欢折腾,你可能就会想用不同的图片查看器了吧。我猜最终你会被新图片查看器的全新用户体验或特色功能所吸引的。
|
||||
|
||||
在本篇文章中,无论是简单的还是复杂的、无论是为 Ubuntu 准备的还是其它 Linux 发行版准备的,我们都有提到。
|
||||
|
||||
### Linux 下最棒的图片查看器
|
||||
|
||||
![Ubuntu 或其它 Linux 发行版适用的最棒的图片查看器][1]
|
||||
|
||||
**注意:** 在准备安装一个图片查看器时,请前往您系统中预先安装的软件商店中查找。如果您没有任何软件商店或无法在软件商店中找到它,请手动执行我们给出的命令。
|
||||
|
||||
#### 1. Nomacs
|
||||
|
||||
![Nomacs 图片查看器][2]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 轻快
|
||||
* 内建图像调整工具(可以调整色彩和大小)
|
||||
* 拍摄位置信息
|
||||
* 元数据调节器
|
||||
* 局域网同步
|
||||
* 全屏模式
|
||||
|
||||
Nomacs 是一款自由软件。虽然没有什么出众的功能,但是它的兼容性还不错,可以支持许多常见格式。
|
||||
|
||||
它的界面超级简单,但是提供了简单的图片编辑功能(可以调整色彩、亮度、大小和裁剪)。除此之外,它还支持全屏模式、直方图,以及可以切换显示元数据、编辑历史等信息的许多面板。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
简单起见,你可以在各种软件中心中安装它。如果你想通过终端安装它,请参见它的 [GitHub 页][3] 。或者,在使用 APT 包管理的系统中使用如下命令安装:
|
||||
|
||||
```
|
||||
sudo apt install nomacs
|
||||
```
|
||||
|
||||
#### 2. Gnome 之眼
|
||||
|
||||
![Gnome 之眼][4]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 极其简单的图像查看器
|
||||
* 幻灯片视图
|
||||
* 为 GNOME 量身打造的图片查看器
|
||||
|
||||
这是一款经典的图片查看器,它在数年前作为 GNOME 项目的一部分被开发出来。不过需要注意的是,对它的维护目前已经不是很活跃了。不过它仍能在最新版 Ubuntu LTS 和部分 Linux 发行版中正常工作。
|
||||
|
||||
如果你需要一个简单、有幻灯片视图并可以在侧栏看到元数据的图像查看器,Gnome 之眼是最佳选择。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
若要在 Ubuntu 及基于 Ubuntu 的 Linux 发行版上安装它,仅需一条命令:
|
||||
|
||||
```
|
||||
sudo apt install eog
|
||||
```
|
||||
|
||||
如果你想在其它发行版中安装它,请参见 [该项目的 GitHub 页面][5] 。
|
||||
|
||||
#### 3. EOM
|
||||
|
||||
![EOM 图像查看器][6]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 简洁
|
||||
* 可扩展
|
||||
* 为 MATE 量身打造的图片查看器
|
||||
|
||||
另一个基本功能齐全,支持幻灯片视图和图像旋转的查看器。
|
||||
|
||||
虽然它没什么特色功能,但它支持大部分的图像格式,并且还能处理大体积的图像。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
若要在 Ubuntu 及基于 Ubuntu 的 Linux 发行版上安装它,仅需一条命令:
|
||||
|
||||
```
|
||||
sudo apt install eom
|
||||
```
|
||||
|
||||
如果你想在其它发行版中安装它,请参见 [该项目的 GitHub 页面][7] 。
|
||||
|
||||
#### 4. Geeqie
|
||||
|
||||
![Geeqie 图像查看器][8]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 可扩展的灵活的图像查看器(其它的图像查看器支持它)
|
||||
* 可以显示色彩信息
|
||||
|
||||
Geeqie 是一个令用户印象深刻的图片管理/查看器。它支持将其它查看器作为扩展使用,不过它并不提供任何对图像操作的工具。
|
||||
|
||||
如果你希望获取图像的颜色信息、元数据,或是查看/管理一组图片,它将会是一个不错的选择。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
在终端输入:
|
||||
|
||||
```
|
||||
sudo apt install geeqie
|
||||
```
|
||||
|
||||
若想查看它的源代码,请前往 [它的 GitHub 主页][9]。
|
||||
|
||||
#### 5. gThumb
|
||||
|
||||
![gThumb 图片查看器][10]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 全功能(查看、编辑和管理)
|
||||
* 可清除 EXIF 信息
|
||||
* 图像格式转换
|
||||
* 查找重复的图像
|
||||
|
||||
gThumb 会让你眼前一亮,因为它有很多功能。它的查看/管理界面和编辑工具(裁剪、缩放、颜色编辑等等)将会给你留下很深的印象。
|
||||
|
||||
你甚至可以为图像添加评论或清除它的 EXIF 信息。它使得你可以方便地找到重复的图像或转码图像。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
你可以在终端中输入这条命令:
|
||||
|
||||
```
|
||||
sudo apt install gthumb
|
||||
```
|
||||
|
||||
输了没用?请参阅 [项目 GitHub 主页][11] 来获取帮助。
|
||||
|
||||
#### 6. Gwenview
|
||||
|
||||
![Gwenview 图像查看器][12]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 简单,有基础图像编辑功能(旋转、调整大小)
|
||||
* 可使用 KIPI 插件扩展
|
||||
|
||||
Gwenview 又是一个基本的图像查看器,它为 KDE 量身定做。不过这并不影响你在其它桌面环境中使用它。
|
||||
|
||||
如果你使用 Konqueror 浏览器,你可以将 Gwenview 作为它的内嵌图片浏览器。你也可以为图片添加评论。此外,它还支持 [KIPI][13] 插件。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
你可以在终端中输入这条命令:
|
||||
|
||||
```
|
||||
sudo apt install gwenview
|
||||
```
|
||||
|
||||
若想查看它的源代码,请前往 [它的 GitHub 主页][14]。
|
||||
|
||||
#### 7. Mirage
|
||||
|
||||
![Mirage 图像查看器][15]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 可定制的基本用户界面
|
||||
* 基本图像编辑工具
|
||||
* 可在命令行使用
|
||||
|
||||
如果你想要一个可在命令行中访问、支持全屏和幻灯片视图、带有基础编辑工具以及可定制 UI 的普通查看器,Mirage 是个不二之选。
|
||||
|
||||
它是一个非常快速且兼容性优良的查看器。它支持包括 png、jpg、svg、xpm、gif、bmp 和 tiff 在内的多种图像格式。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
你需要执行:
|
||||
|
||||
```
|
||||
sudo apt install mirage
|
||||
```
|
||||
|
||||
访问 [该项目 GitHub 页面][16] 来获取更多信息。
|
||||
|
||||
#### 8. KPhotoAlbum
|
||||
|
||||
![KPhotoAlbum][17]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 为图像添加标签
|
||||
* 数据库支持
|
||||
* 图片压缩
|
||||
* 将图像合并到一组图像,或移除
|
||||
|
||||
确切地说,KPhotoAlbum 其实不仅仅是一款图像查看器,它还能为图像添加标签并管理图像。
|
||||
|
||||
你可以用它来压缩图片以及使用标签搜索你的图片。你还可以使用幻灯片视图来观看图片。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
在终端中输入:
|
||||
|
||||
```
|
||||
sudo apt kphotoalbum
|
||||
```
|
||||
|
||||
跟从 [官网上的指引][18] 来在其它 Linux 发行版中安装它。
|
||||
|
||||
#### 9. Shotwell
|
||||
|
||||
![Shotwell][19]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 红眼消除工具
|
||||
* 将照片上传到 Facebook 或 Flickr 等社交网络中
|
||||
* 支持原始格式(RAW)的图片
|
||||
|
||||
Shotwell 是一个多功能照片管理器。在此,你能查看或管理你的照片。虽然它没带有许多图像编辑工具,但是你还是可以裁剪和调整亮度的。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
在终端中执行以下命令 (Ubuntu 及其衍生版本):
|
||||
|
||||
```
|
||||
sudo apt install shotwell
|
||||
```
|
||||
|
||||
若想获取更多信息,请 [前往它的 GitHub 页面][20]。
|
||||
|
||||
#### 10. Ristretto
|
||||
|
||||
![Ristretto][21]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 极其简单
|
||||
* 全屏模式
|
||||
* 幻灯片视图
|
||||
|
||||
简易的图像查看器。它能查看、全屏查看、缩放查看或以幻灯片视图查看图片。
|
||||
|
||||
它是为 Xfce 定制的,但你仍然可以在其它任何地方安装它。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
即使它是为 Xfce 桌面环境构建的,你仍能在其它地方安装它。对 Ubuntu 及其衍生发行版,请执行:
|
||||
|
||||
```
|
||||
sudo apt install ristretto
|
||||
```
|
||||
|
||||
#### 11. digiKam
|
||||
|
||||
![digiKam 图像查看器][22]
|
||||
|
||||
**它有什么特点?**
|
||||
|
||||
* 带有高级图像管理功能(查看/管理/编辑)的多合一查看器
|
||||
* 可以进行批处理
|
||||
* 带有 [Light Table 功能][23]
|
||||
|
||||
digiKam 是一个带有多种图像编辑功能的高级照片管理器。你可以使用 SQLite 或 MySQL 来配置它的数据库。
|
||||
|
||||
为了提升你的看图体验,你可以在预览图片时加载低画质的图片。这样一来,即使你有一大堆图片,它也丝滑般流畅。不仅如此,你还可以通过 Google、Facebook、Imgur 等来导入/导出图片。如果你希望使用一个超多功能的查看器,请务必试试这个 digiKam。
|
||||
|
||||
**我该如何安装它?**
|
||||
|
||||
执行这条命令:
|
||||
|
||||
```
|
||||
sudo apt install digikam
|
||||
```
|
||||
|
||||
访问 [项目 GitHub 页面][24] 来获取更多信息。
|
||||
|
||||
### 尾声
|
||||
|
||||
总的来说,无论你想要不同的用户体验、丰富的功能还是强大的管理工具,上面总有适合你的工具。
|
||||
|
||||
你更喜欢哪个图像查看器呢?它是系统自带的吗?
|
||||
|
||||
欢迎前往原文的评论区留下你的答案。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/image-viewers-linux/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[zhs852](https://github.com/zhs852)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/best-image-viewers-linux.png?resize=800%2C450&ssl=1
|
||||
[2]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/nomacs-image-viewer.jpg?resize=800%2C455&ssl=1
|
||||
[3]: https://github.com/nomacs/nomacs
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/eye-of-gnome-image-viewer.jpg?resize=800%2C470&ssl=1
|
||||
[5]: https://github.com/GNOME/eog
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/12/eye-of-mate-image-viewer.jpg?resize=800%2C464&ssl=1
|
||||
[7]: https://github.com/mate-desktop/eom
|
||||
[8]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/geeqie-image-viewer.jpg?resize=800%2C444&ssl=1
|
||||
[9]: https://github.com/BestImageViewer/geeqie
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/gthumb-image-viewer.jpg?resize=800%2C515&ssl=1
|
||||
[11]: https://github.com/GNOME/gthumb
|
||||
[12]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/12/gwenview-image-viewer.jpg?resize=800%2C517&ssl=1
|
||||
[13]: https://en.wikipedia.org/wiki/KDE_Image_Plugin_Interface
|
||||
[14]: https://github.com/KDE/gwenview
|
||||
[15]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/mirage-image-viewer.jpg?resize=800%2C475&ssl=1
|
||||
[16]: https://github.com/xiongchiamiov/Mirage
|
||||
[17]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/12/kphotoalbum-viewer.jpg?fit=800%2C522&ssl=1
|
||||
[18]: https://www.kphotoalbum.org/download/
|
||||
[19]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/shotwell-image-viewer.jpg?resize=800%2C473&ssl=1
|
||||
[20]: https://github.com/GNOME/shotwell
|
||||
[21]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/ristretto-image-viewer.jpg?resize=800%2C437&ssl=1
|
||||
[22]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/12/digitkam-image-viewer.jpg?resize=800%2C550&ssl=1
|
||||
[23]: https://docs.kde.org/trunk5/en/extragear-graphics/digikam/using-lighttable.html
|
||||
[24]: https://github.com/KDE/digikam
|
||||
@@ -0,0 +1,83 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10412-1.html)
|
||||
[#]: subject: (Watch YouTube videos at the Linux terminal)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-youtube-dl)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
在 Linux 终端上观看 YouTube 视频
|
||||
======
|
||||
|
||||
> 视频只能在 GUI 下看么?再想想。
|
||||
|
||||

|
||||
|
||||
我们即将结束为期 24 天的 Linux 命令行玩具日历。希望你一直在看,如果没有,请回到[这里][1]开始,自己试试。你会发现 Linux 终端有很多游戏,消遣和奇怪的东西。
|
||||
|
||||
虽然你之前可能已经看过我们日历中的一些玩具,但我们希望对每个人至少有一个新事物。
|
||||
|
||||
今天我们要在昨天的玩具 [MPlayer][2] 上再加上一个 [youtube-dl][3]。
|
||||
|
||||
正如其名称所暗示的那样,`youtube-dl` 是一个用于下载 YouTube 视频的命令行程序,但它也可以从其他许多站点下载视频,而且它是一个有着[丰富文档][4]的功能齐全的程序,从而使视频获取变得容易。注意:请勿在任何违反你所在司法辖区的版权法的情况下使用 `youtube-dl`。
|
||||
|
||||
`youtube-dl` 使用的是 [Unlicense][5] 这个公共领域许可,类似于 Creative Common 的 [CC0][6]。这里还有哪些公共领域贡献适用于开源领域的[法律意见][7],但它通常被认为与现有的开源许可证兼容,即使是不推荐使用它的组织也是如此。
|
||||
|
||||
最简单地,我们将使用 `youtube-dl` 来获取视频以便在终端中播放。首先,使用适用于你发行版的方法[安装][8]它。对我来说,在 Fedora 中,它被打包在我的仓库中,因此安装非常简单:
|
||||
|
||||
```
|
||||
$ sudo dnf install youtube-dl
|
||||
```
|
||||
|
||||
然后,获取一个视频。YouTube 允许你按照许可证进行搜索,所以今天我们将根据知识共享署名许可证查看来自 [Gemmy's Videos][10] 中的壁炉[视频][9]。对于 YouTube 视频,你可以像这样用文件 ID 下载,我们也可以指定输出文件名。我故意选择了一个短片,因为长视频会变得很大!
|
||||
|
||||
```
|
||||
$ youtube-dl pec8P5K4s8c -o fireplace.mp4
|
||||
```
|
||||
|
||||
如果你昨天没有安装 [MPlayer][2],请继续安装好,如果你之前没有安装 libcaca 则需要安装它。如果你直接用 MPlayer 在命令行中播放视频 ( `$ mplayer fireplace.webm` ),它能够播放,但是会在一个自己的窗口中,这不是我们想要的。
|
||||
|
||||
首先,我设置将 libcaca 强制使用 ncurses 作为显示驱动,使输出保持在我的终端:
|
||||
|
||||
```
|
||||
$ export CACA_DRIVER=ncurses
|
||||
```
|
||||
|
||||
然后,我放大了终端(“像素”越多越好),并使用以下命令播放文件(强制使用 libcaca 并静默 MPlayer 的文本输出):
|
||||
|
||||
```
|
||||
$ mplayer -really-quiet -vo caca fireplace.mp4
|
||||
```
|
||||
|
||||
这就完成了!
|
||||
|
||||

|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?提交今年的建议有点晚了,但我们仍然希望在新的一年里有一些很酷的命令行玩具。请在下面的评论中告诉我,我会查看的。让我知道你对今天的玩具有何看法。
|
||||
|
||||
一定要看看昨天的玩具,[在 Linux 终端收听广播][2],明天还要再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-youtube-dl
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/18/12/linux-toy-boxes
|
||||
[2]: https://linux.cn/article-10393-1.html
|
||||
[3]: https://rg3.github.io/youtube-dl/
|
||||
[4]: https://github.com/rg3/youtube-dl/blob/master/README.md#readme
|
||||
[5]: https://unlicense.org/
|
||||
[6]: https://creativecommons.org/share-your-work/public-domain/cc0/
|
||||
[7]: https://opensource.org/faq#public-domain
|
||||
[8]: https://github.com/rg3/youtube-dl/blob/master/README.md#installation
|
||||
[9]: https://www.youtube.com/watch?v=pec8P5K4s8c
|
||||
[10]: https://www.youtube.com/channel/UCwwaepmpWZVDd605MIRC20A
|
||||
@@ -0,0 +1,65 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10437-1.html)
|
||||
[#]: subject: (The Linux command line can fetch fun from afar)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-remote)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
|
||||
能从远程获得乐趣的 Linux 命令
|
||||
======
|
||||
|
||||
> 使用这些工具从远程了解天气、阅读资料等。
|
||||
|
||||

|
||||
|
||||
我们即将结束为期 24 天的 Linux 命令行玩具日历。希望你有一直在看,如果没有,请回到[开始][1],从头看过来。你会发现 Linux 终端有很多游戏、消遣和奇怪之处。
|
||||
|
||||
虽然你之前可能已经看过我们日历中的一些玩具,但我们希望每个人都遇见一个新事物。
|
||||
|
||||
今天的玩具(实际是玩具集合)有点不同。到目前为止,我主要是想把重点放在那些独立的玩具上,并且完全可在开源许可下使用。但是我从读者那里得到了一些很好的建议,利用开源工具远程访问一些开源或者不开源的东西。今天,我将介绍其中的一些。
|
||||
|
||||
第一个是经典之作:使用 Telnet 观看星球大战的 ASCII 演绎版本。你的系统可能已经安装了 Telnet,因此你只需运行:
|
||||
|
||||
```
|
||||
$ telnet towel.blinkenlights.nl
|
||||
```
|
||||
|
||||
我第一次看到它是十年之前,因此我对于它还存在有点惊奇。如果你还没看过,请留出一点时间看一下。你不会后悔的。
|
||||
|
||||

|
||||
|
||||
接下来,Opensource.com 的撰稿人 [Manuel Dewald][2] 提出了一种从终端获取当地天气的方法。它很简单,你只需安装 `curl`(或者,`wget`)。
|
||||
|
||||
```
|
||||
$ curl wttr.in
|
||||
```
|
||||
|
||||

|
||||
|
||||
最后,在假期中虽然你可以从[命令行 Web 浏览器][3]浏览你喜欢的网站(包括 Opensource.com),但有一些我最喜欢的网站可以通过专用客户端更轻松地浏览。其中两个是 Reddit 和 Hacker News,有人推荐给我一些它们的客户端,你可能也想尝试,它们都使用开源许可。我尝试过 [haxor-news][4] (Hacker News) 和 [rtv][5] (Reddit),它们都还不错。
|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?提交今年的建议有点晚了,但我们仍然希望在新的一年里有一些很酷的命令行玩具。请在下面的评论中告诉我,我会查看的。让我知道你对今天的玩具有何看法。
|
||||
|
||||
一定要看看昨天的玩具,[在 Linux 终端收看 Youtube 视频][2],明天还要再来!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/12/linux-toy-remote
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/18/12/linux-toy-boxes
|
||||
[2]: https://opensource.com/users/ntlx
|
||||
[3]: https://opensource.com/article/16/12/web-browsers-linux-command-line
|
||||
[4]: https://github.com/donnemartin/haxor-news
|
||||
[5]: https://github.com/michael-lazar/rtv
|
||||
[6]: https://opensource.com/article/18/12/linux-toy-youtube-dl
|
||||
@@ -0,0 +1,140 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10439-1.html)
|
||||
[#]: subject: (How to create presentations with Beamer)
|
||||
[#]: via: (https://opensource.com/article/19/1/create-presentations-beamer)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
如何使用 Beamer 创建演示文稿
|
||||
======
|
||||
|
||||
> Beamer 将 LaTeX 强大的排版功能和生态系统带进创建幻灯片中。
|
||||
|
||||

|
||||
|
||||
[Beamer][1] 是用于生成幻灯片的 LaTeX 包。它最棒的功能之一是它可以利用 LaTeX 强大的排版系统和其生态系统中的所有其他软件包。例如,我经常在包含代码的 Beamer 演示文稿中使用 LaTeX 的 [listings][2] 包。
|
||||
|
||||
### 创建演示文稿
|
||||
|
||||
要创建一个 Beamer 文档,输入:
|
||||
|
||||
```
|
||||
\documentclass{beamer}
|
||||
```
|
||||
|
||||
与任何其他 LaTeX 文档一样,添加你要使用的任何包。例如,要使用 `listings` 包,请输入:
|
||||
|
||||
```
|
||||
\usepackage{listings}
|
||||
```
|
||||
|
||||
将所有内容放在 `document` 环境中:
|
||||
|
||||
```
|
||||
\begin{document}
|
||||
```
|
||||
|
||||
Beamer 文档通常时是一系列的 `frame` 环境。包含代码的 `frame` 应该被标记为 `fragile`:
|
||||
|
||||
```
|
||||
\begin{frame}[fragile]
|
||||
```
|
||||
|
||||
使用标题开始你的 `frame`:
|
||||
|
||||
```
|
||||
\frametitle{Function to Do Stuff}
|
||||
```
|
||||
|
||||
### 开始演示前测试你的代码
|
||||
|
||||
世上最糟糕的感受之一你在演讲中说到代码时,突然发现了一个 bug —— 也许是拼错了关键词或者漏掉了括号。
|
||||
|
||||
解决方法之一就是测试演示的代码。在多数演示环境中,这意味着创建一个单独的文件、编写测试接着拷贝和粘贴。
|
||||
|
||||
然而,在 Beamer 中有一种更好的方法。想象一下,你有一个名为 `do_stuff.py` 的文件,其中包含代码。你可以在第二个文件中编写 `do_stuff.py` 代码的测试,你可以将其命名为 `test_do_stuff.py`,并且可以使用 [pytest][3] 测试。但是,`do_stuff.py` 中的大多数行都缺乏教学价值,比如定义辅助函数。
|
||||
|
||||
要简化你受众看到的东西,你可在演示文稿中只导入你要讨论的行到 frame 中:
|
||||
|
||||
```
|
||||
\lstinputlisting[
|
||||
language=Python,
|
||||
firstline=8,
|
||||
lastline=15
|
||||
]{do_stuff.py}
|
||||
```
|
||||
|
||||
由于你会对这几行(从 8 到 15)进行讨论,因此幻灯片上不需要任何其他内容。结束 `frame`:
|
||||
|
||||
```
|
||||
\end{frame}
|
||||
```
|
||||
|
||||
在下一张幻灯片中,你想展示刚才的 `do_stuff()` 函数的用法示例:
|
||||
|
||||
```
|
||||
\begin{frame}[fragile]
|
||||
\frametitle{Calling Function to Do Stuff}
|
||||
\lstinputlisting[
|
||||
language=Python,
|
||||
firstline=17,
|
||||
lastline=19
|
||||
]{do_stuff.py}
|
||||
\end{frame}
|
||||
```
|
||||
|
||||
你使用相同的文件,但这次显示调用该函数的行。最后,结束 `document`:
|
||||
|
||||
```
|
||||
\end{document}
|
||||
```
|
||||
|
||||
假设你在 `do_stuff.py` 中有一个合适的 Python 文件,这将生成一个含有 2 页的幻灯片。
|
||||
|
||||
Beamer 还支持必要的功能如渐进式演示,每次给观众展示一部分以免受到前面的打扰。在行中放入 `\pause` 会将页面分成不同的部分:
|
||||
|
||||
```
|
||||
\begin{frame}
|
||||
Remember:
|
||||
\begin{itemize}
|
||||
\item This will show up on the first slide. \pause
|
||||
\item This will show up on the
|
||||
second slide, as well as the preceding point. \pause
|
||||
\item Finally, on the third slide,
|
||||
all three bullets will show up.
|
||||
\end{frame}
|
||||
```
|
||||
|
||||
### 创建讲义
|
||||
|
||||
Beamer 中我最喜欢的功能是可以用 `\documentclass[ignorenonframetext]{beamer}` 设置忽略 `frame` 外的所有内容。当我准备演示文稿时,我离开顶部(声明文档类的位置)并自动生成它的两个版本:我的演示稿使用 Beamer 忽略任何 `frame` 之外的所有文本,另一个含有类似这样的头:
|
||||
|
||||
```
|
||||
\documentclass{article}
|
||||
\usepackage{beamerarticle}
|
||||
```
|
||||
|
||||
这会生成一份讲义:一份含有所有 `frame` 和它们之间文字的 PDF。
|
||||
|
||||
当会议组织者要求我发布我的幻灯片时,我会包含原始幻灯片作为参考,但我希望人们拿到的是讲义,它包含了所有我不想在幻灯片上写的解释部分。
|
||||
|
||||
在创建幻灯片时,人们经常会考虑是为演讲优化讲稿还是为之后想要阅读它的人们优化。幸运的是,Beamer 提供了两全其美的办法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/1/create-presentations-beamer
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.overleaf.com/learn/latex/Beamer
|
||||
[2]: https://www.overleaf.com/learn/latex/Code_listing
|
||||
[3]: https://docs.pytest.org/en/latest/
|
||||
@@ -0,0 +1,120 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (https://linux.cn/article-10467-1.html)
|
||||
[#]: url: (wxy)
|
||||
[#]: subject: (s-tui: A Terminal Tool To Monitor CPU Temperature, Frequency, Power And Utilization In Linux)
|
||||
[#]: via: (https://www.2daygeek.com/s-tui-stress-terminal-ui-monitor-linux-cpu-temperature-frequency/)
|
||||
[#]: author: (Prakash Subramanian https://www.2daygeek.com/author/prakash/)
|
||||
|
||||
s-tui:在 Linux 中监控 CPU 温度、频率、功率和使用率的终端工具
|
||||
======
|
||||
|
||||
一般每个 Linux 管理员都会使用 [lm_sensors 监控 CPU 温度][1]。lm_sensors (Linux 监控传感器)是一个自由开源程序,它提供了监控温度、电压和风扇的驱动和工具。
|
||||
|
||||
如果你正在找替代的 CLI 工具,我会建议你尝试 s-tui。
|
||||
|
||||
它其实是一个压力测试的终端 UI,可以帮助管理员通过颜色查看 CPU 温度。
|
||||
|
||||
### s-tui 是什么
|
||||
|
||||
s-tui 是一个用于监控计算机的终端 UI。s-tui 可以在终端以图形方式监控 CPU 温度、频率、功率和使用率。此外,它还显示由发热量限制引起的性能下降,它需要很少的资源并且不需要 X 服务器。它是用 Python 编写的,需要 root 权限才能使用它。
|
||||
|
||||
s-tui 是一个独立的程序,可以开箱即用,并且不需要配置文件就可以使用其基本功能。
|
||||
|
||||
s-tui 使用 psutil 来探测你的一些硬件信息。如果不支持你的一些硬件,你可能看不到所有信息。
|
||||
|
||||
以 root 身份运行 s-tui 时,当压测所有 CPU 核心时,可以将 CPU 发挥到最大睿频频率。它在后台使用 Stress 压力测试工具,通过对系统施加某些类型的计算压力来检查其组件的温度是否超过其可接受的范围。只要计算机稳定并且其组件的温度不超过其可接受的范围,PC 超频就没问题。有几个程序可以通过压力测试得到系统的稳定性,从而评估超频水平。
|
||||
|
||||
### 如何在 Linux 中安装 s-tui
|
||||
|
||||
它是用 Python 写的,`pip` 是在 Linux 上安装 s-tui 的推荐方法。确保你在系统上安装了 python-pip 软件包。如果还没有,请使用以下命令进行安装。
|
||||
|
||||
对于 Debian/Ubuntu 用户,使用 [apt 命令][2] 或 [apt-get 命令][3] 来安装 `pip`。
|
||||
|
||||
```
|
||||
$ sudo apt install python-pip stress
|
||||
```
|
||||
|
||||
对于 Archlinux 用户,使用 [pacman 命令][4] 来安装 `pip`。
|
||||
|
||||
```
|
||||
$ sudo pacman -S python-pip stress
|
||||
```
|
||||
|
||||
对于 Fedora 用户,使用 [dnf 命令][5] 来安装 `pip`。
|
||||
|
||||
```
|
||||
$ sudo dnf install python-pip stress
|
||||
```
|
||||
|
||||
对于 CentOS/RHEL 用户,使用 [yum 命令][5] 来安装 `pip`。
|
||||
|
||||
```
|
||||
$ sudo yum install python-pip stress
|
||||
```
|
||||
|
||||
对于 openSUSE 用户,使用 [zypper 命令][5] 来安装 `pip`。
|
||||
|
||||
```
|
||||
$ sudo zypper install python-pip stress
|
||||
```
|
||||
|
||||
最后运行下面的 [pip 命令][8] 在 Linux 中安装 s-tui 工具。
|
||||
|
||||
对于 Python 2.x:
|
||||
|
||||
```
|
||||
$ sudo pip install s-tui
|
||||
```
|
||||
|
||||
对于Python 3.x:
|
||||
|
||||
```
|
||||
$ sudo pip3 install s-tui
|
||||
```
|
||||
|
||||
### 如何使用 s-tui
|
||||
|
||||
正如我在文章开头所说的那样。它需要 root 权限才能从系统获取所有信息。只需运行以下命令即可启动 s-tui。
|
||||
|
||||
```
|
||||
$ sudo s-tui
|
||||
```
|
||||
|
||||
![][10]
|
||||
|
||||
默认情况下,它启用硬件监控并选择 “Stress” 选项以对系统执行压力测试。
|
||||
|
||||
![][11]
|
||||
|
||||
要查看其他选项,请到帮助页面查看。
|
||||
|
||||
```
|
||||
$ s-tui --help
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/s-tui-stress-terminal-ui-monitor-linux-cpu-temperature-frequency/
|
||||
|
||||
作者:[Prakash Subramanian][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.2daygeek.com/author/prakash/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.2daygeek.com/view-check-cpu-hard-disk-temperature-linux/
|
||||
[2]: https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[3]: https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[4]: https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/
|
||||
[5]: https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
|
||||
[6]: https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[7]: https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
|
||||
[8]: https://www.2daygeek.com/install-pip-manage-python-packages-linux/
|
||||
[9]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[10]: https://www.2daygeek.com/wp-content/uploads/2018/12/s-tui-stress-terminal-ui-monitor-linux-cpu-temperature-frequency-1.jpg
|
||||
[11]: https://www.2daygeek.com/wp-content/uploads/2018/12/s-tui-stress-terminal-ui-monitor-linux-cpu-temperature-frequency-2.jpg
|
||||
113
published/201901/20190104 Managing dotfiles with rcm.md
Normal file
113
published/201901/20190104 Managing dotfiles with rcm.md
Normal file
@@ -0,0 +1,113 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10466-1.html)
|
||||
[#]: subject: (Managing dotfiles with rcm)
|
||||
[#]: via: (https://fedoramagazine.org/managing-dotfiles-rcm/)
|
||||
[#]: author: (Link Dupont https://fedoramagazine.org/author/linkdupont/)
|
||||
|
||||
用 rcm 管理隐藏文件
|
||||
======
|
||||
|
||||

|
||||
|
||||
许多 GNU/Linux 程序的一个特点是有个易于编辑的配置文件。几乎所有常见的自由软件都将配置设置保存在纯文本文件中,通常采用结构化格式,如 JSON、YAML 或[“类似 ini”][1] 的文件中。这些配置文件经常隐藏在用户的主目录中。但是,基本的 `ls` 不会显示它们。UNIX 标准要求以点开头的任何文件或目录名称都被视为“隐藏”,除非用户特意要求,否则不会列在目录列表中。例如,要使用 `ls` 列出所有文件,要传递 `-a` 选项。
|
||||
|
||||
随着时间的推移,这些配置文件会有很多定制配置,管理它们变得越来越具有挑战性。不仅如此,在多台计算机之间保持同步是大型组织所面临的共同挑战。最后,许多用户也对其独特的配置感到自豪,并希望以简单的方式与朋友分享。这就是用到 rcm 介入的地方。
|
||||
|
||||
rcm 是一个 “rc” 文件管理套件(“rc” 是命名配置文件的另一种约定,它已被某些 GNU/Linux 程序采用,如 `screen` 或 `bash`)。 rcm 提供了一套命令来管理和列出它跟踪的文件。使用 `dnf` 安装 rcm。
|
||||
|
||||
### 开始使用
|
||||
|
||||
默认情况下,rcm 使用 `~/.dotfiles` 来存储它管理的所有隐藏文件。一个被管理的隐藏文件实际保存在 `~/.dotfiles` 目录中,而它的符号链接会放在文件原本的位置。例如,如果 `~/.bashrc` 由 rcm 所管理,那么详细列表将如下所示。
|
||||
|
||||
```
|
||||
[link@localhost ~]$ ls -l ~/.bashrc
|
||||
lrwxrwxrwx. 1 link link 27 Dec 16 05:19 .bashrc -> /home/link/.dotfiles/bashrc
|
||||
[link@localhost ~]$
|
||||
```
|
||||
|
||||
rcm 包含 4 个命令:
|
||||
|
||||
* `mkrc` – 将文件转换为由 rcm 管理的隐藏文件
|
||||
* `lsrc` – 列出由 rcm 管理的文件
|
||||
* `rcup` – 同步由 rcm 管理的隐藏文件
|
||||
* `rcdn` – 删除 rcm 管理的所有符号链接
|
||||
|
||||
### 在两台计算机上共享 bashrc
|
||||
|
||||
如今用户在多台计算机上拥有 shell 帐户并不罕见。在这些计算机之间同步隐藏文件可能是一个挑战。这里将提供一种可能的解决方案,仅使用 rcm 和 git。
|
||||
|
||||
首先使用 `mkrc` 将文件转换成由 rcm 管理的文件。
|
||||
|
||||
```
|
||||
[link@localhost ~]$ mkrc -v ~/.bashrc
|
||||
Moving...
|
||||
'/home/link/.bashrc' -> '/home/link/.dotfiles/bashrc'
|
||||
Linking...
|
||||
'/home/link/.dotfiles/bashrc' -> '/home/link/.bashrc'
|
||||
[link@localhost ~]$
|
||||
```
|
||||
|
||||
接下来使用 `lsrc` 验证列表是否正确。
|
||||
|
||||
```
|
||||
[link@localhost ~]$ lsrc
|
||||
/home/link/.bashrc:/home/link/.dotfiles/bashrc
|
||||
[link@localhost ~]$
|
||||
```
|
||||
|
||||
现在在 `~/.dotfiles` 中创建一个 git 仓库,并使用你选择的 git 仓库托管设置一个远程仓库。提交 `bashrc` 文件并推送一个新分支。
|
||||
|
||||
```
|
||||
[link@localhost ~]$ cd ~/.dotfiles
|
||||
[link@localhost .dotfiles]$ git init
|
||||
Initialized empty Git repository in /home/link/.dotfiles/.git/
|
||||
[link@localhost .dotfiles]$ git remote add origin git@github.com:linkdupont/dotfiles.git
|
||||
[link@localhost .dotfiles]$ git add bashrc
|
||||
[link@localhost .dotfiles]$ git commit -m "initial commit"
|
||||
[master (root-commit) b54406b] initial commit
|
||||
1 file changed, 15 insertions(+)
|
||||
create mode 100644 bashrc
|
||||
[link@localhost .dotfiles]$ git push -u origin master
|
||||
...
|
||||
[link@localhost .dotfiles]$
|
||||
```
|
||||
|
||||
在第二台机器上,克隆这个仓库到 `~/.dotfiles` 中。
|
||||
|
||||
```
|
||||
[link@remotehost ~]$ git clone git@github.com:linkdupont/dotfiles.git ~/.dotfiles
|
||||
...
|
||||
[link@remotehost ~]$
|
||||
```
|
||||
|
||||
现在使用 `rcup` 更新受 rcm 管理的符号链接。
|
||||
|
||||
```
|
||||
[link@remotehost ~]$ rcup -v
|
||||
replacing identical but unlinked /home/link/.bashrc
|
||||
removed '/home/link/.bashrc'
|
||||
'/home/link/.dotfiles/bashrc' -> '/home/link/.bashrc'
|
||||
[link@remotehost ~]$
|
||||
```
|
||||
|
||||
覆盖现有的 `~/.bashrc`(如果存在)并重启 shell。
|
||||
|
||||
就是这些了!指定主机选项 (`-o`) 是对上面这种情况的有用补充。如往常一样,请阅读手册页。它们包含了很多示例命令。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/managing-dotfiles-rcm/
|
||||
|
||||
作者:[Link Dupont][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/linkdupont/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://en.wikipedia.org/wiki/INI_file
|
||||
@@ -0,0 +1,222 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10471-1.html)
|
||||
[#]: subject: (Getting started with Pelican: A Python-based static site generator)
|
||||
[#]: via: (https://opensource.com/article/19/1/getting-started-pelican)
|
||||
[#]: author: (Craig Sebenik https://opensource.com/users/craig5)
|
||||
|
||||
Pelican 入门:一个 Python 静态网站生成器
|
||||
======
|
||||
|
||||
> Pelican 是那些想要自我托管简单网站或博客的 Python 用户的绝佳选择。
|
||||
|
||||

|
||||
|
||||
如果你想创建一个自定义网站或博客,有很多选择。许多提供商可以托管你的网站并为你完成大部分工作。(WordPress 是一个非常受欢迎的选项。)但是使用托管方式,你会失去一些灵活性。作为一名软件开发人员,我更喜欢管理我自己的服务器,并在我的网站如何运行方面保持更多的自由。
|
||||
|
||||
然而,管理 Web 服务器需要大量的工作。安装它并获得一个简单的应用程序来提供内容是非常容易的。但是,维护安全补丁和更新是非常耗时得。如果你只想提供静态网页,那么拥有一个 Web 服务器和一系列应用程序可能会得不偿失。手动创建 HTML 页面也不是一个好选择。
|
||||
|
||||
这是静态网站生成器的用武之地。这些应用程序使用模板来创建所需的静态页面,并将它们与关联的元数据交叉链接。(例如,所有显示的页面都带有公共标签或关键词。)静态网站生成器可以帮助你使用导航区域、页眉和页脚等元素创建一个具有公共外观的网站。
|
||||
|
||||
我使用 [Pyhton][1] 已经很多年了,所以,当我第一次开始寻找生成静态 HTML 页面的东西时,我想要用 Python 编写的东西。主要原因是我经常想要了解应用程序如何工作的内部细节,而使用一种我已经了解的语言使这一点更容易。(如果这对你不重要或者你不使用 Python,那么还有一些其他很棒的[静态网站生成器][2],它们使用 Ruby、JavaScript 和其它语言。)
|
||||
|
||||
我决定试试 [Pelican][3]。它是一个用 Python 编写的常用静态网站生成器。它支持 [reStructuredText][4](LCTT 译注:这是一种用于文本数据的文件格式,主要用于 Python 社区的技术文档),并且也支持 [Markdown][5],这需要通过安装必需的包来完成。所有任务都是通过命令行界面(CLI)工具执行的,这使得熟悉命令行的任何人都可以轻松完成。它简单的 quickstart CLI 工具使得创建一个网站非常容易。
|
||||
|
||||
在本文中,我将介绍如何安装 Pelican 4,添加一篇文章以及更改默认主题。(注意:我是在 MacOS 上开发的,使用其它 Unix/Linux 实验结果都将相同,但我没有 Windows 主机可以测试。)
|
||||
|
||||
### 安装和配置
|
||||
|
||||
第一步是创建一个[虚拟环境][6],在虚拟环境中安装 Pelican。
|
||||
|
||||
```
|
||||
$ mkdir test-site
|
||||
$ cd test-site
|
||||
$ python3 -m venv venv
|
||||
$ ./venv/bin/pip install --upgrade pip
|
||||
...
|
||||
Successfully installed pip-18.1
|
||||
$ ./venv/bin/pip install pelican
|
||||
Collecting pelican
|
||||
...
|
||||
Successfully installed MarkupSafe-1.1.0 blinker-1.4 docutils-0.14 feedgenerator-1.9 jinja2-2.10 pelican-4.0.1 pygments-2.3.1 python-dateutil-2.7.5 pytz-2018.7 six-1.12.0 unidecode-1.0.23
|
||||
```
|
||||
|
||||
Pelican 的 quickstart CLI 工具将创建基本布局和一些文件来帮助你开始,运行 `pelican-quickstart` 命令。为了简单起见,我输入了**网站标题**和**作者**的名字,并对 URL 前缀和文章分页选择了 “N”。(对于其它选项,我使用了默认值。)稍后在配置文件中更改这些设置非常容易。
|
||||
|
||||
```
|
||||
$ ./venv/bin/pelicanquickstart
|
||||
Welcome to pelicanquickstart v4.0.1.
|
||||
|
||||
This script will help you create a new Pelican-based website.
|
||||
|
||||
Please answer the following questions so this script can generate the files needed by Pelican.
|
||||
|
||||
> Where do you want to create your new web site? [.]
|
||||
> What will be the title of this web site? My Test Blog
|
||||
> Who will be the author of this web site? Craig
|
||||
> What will be the default language of this web site? [en]
|
||||
> Do you want to specify a URL prefix? e.g., https://example.com (Y/n) n
|
||||
> Do you want to enable article pagination? (Y/n) n
|
||||
> What is your time zone? [Europe/Paris]
|
||||
> Do you want to generate a tasks.py/Makefile to automate generation and publishing? (Y/n)
|
||||
> Do you want to upload your website using FTP? (y/N)
|
||||
> Do you want to upload your website using SSH? (y/N)
|
||||
> Do you want to upload your website using Dropbox? (y/N)
|
||||
> Do you want to upload your website using S3? (y/N)
|
||||
> Do you want to upload your website using Rackspace Cloud Files? (y/N)
|
||||
> Do you want to upload your website using GitHub Pages? (y/N)
|
||||
Done. Your new project is available at /Users/craig/tmp/pelican/test-site
|
||||
```
|
||||
|
||||
你需要启动的所有文件都准备好了。
|
||||
|
||||
quickstart 默认为欧洲/巴黎时区,所以在继续之前更改一下。在你喜欢的文本编辑器中打开 `pelicanconf.py` 文件,寻找 `TIMEZONE` 变量。
|
||||
|
||||
```
|
||||
TIMEZONE = 'Europe/Paris'
|
||||
```
|
||||
|
||||
将其改为 `UTC`。
|
||||
|
||||
```
|
||||
TIMEZONE = 'UTC'
|
||||
```
|
||||
|
||||
要更新公共设置,在 `pelicanconf.py` 中查找 `SOCIAL` 变量。
|
||||
|
||||
```
|
||||
SOCIAL = (('You can add links in your config file', '#'),
|
||||
('Another social link', '#'),)
|
||||
```
|
||||
|
||||
我将添加一个我的 Twitter 账户链接。
|
||||
|
||||
```
|
||||
SOCIAL = (('Twitter (#craigs55)', 'https://twitter.com/craigs55'),)
|
||||
```
|
||||
|
||||
注意末尾的逗号,它很重要。这个逗号将帮助 Python 识别变量实际上是一个集合。确保你没有删除这个逗号。
|
||||
|
||||
现在你已经有了网站的基本知识。quickstart 创建了一个包含许多目标的 `Makefile`。将 `devserver` 传给 `make` 命令将在你的计算机上启动一个开发服务器,以便你可以预览所有内容。`Makefile` 中使用的 CLI 命令假定放在 `PATH` 搜索路径中,因此你需要首先激活该虚拟环境。
|
||||
|
||||
```
|
||||
$ source ./venv/bin/activate
|
||||
$ make devserver
|
||||
pelican -lr /Users/craig/tmp/pelican/test-site/content o
|
||||
/Users/craig/tmp/pelican/test-site/output -s /Users/craig/tmp/pelican/test-site/pelicanconf.py
|
||||
|
||||
-> Modified: theme, settings. regenerating...
|
||||
WARNING: No valid files found in content for the active readers:
|
||||
| BaseReader (static)
|
||||
| HTMLReader (htm, html)
|
||||
| RstReader (rst)
|
||||
Done: Processed 0 articles, 0 drafts, 0 pages, 0 hidden pages and 0 draft pages in 0.18 seconds.
|
||||
```
|
||||
|
||||
在你最喜欢的浏览器中打开 <http://localhost:8000> 来查看你的简单测试博客。
|
||||
|
||||

|
||||
|
||||
你可以在右侧看到 Twitter 链接,左侧有 Pelican、Python 和 Jinja 的一些链接。(Jinja 是 Pelican 可以使用的一种很棒的模板语言。你可以在 [Jinja 的文档][7]中了解更多相关信息。)
|
||||
|
||||
### 添加内容
|
||||
|
||||
现在你又了一个基本的网站,试着添加一些内容。首先,将名为 `welcome.rst` 的文件添加到网站的 `content` 目录中。在你喜欢的文本编辑器中,使用以下文本创建一个文件:
|
||||
|
||||
```
|
||||
$ pwd
|
||||
/Users/craig/tmp/pelican/test-site
|
||||
$ cat content/welcome.rst
|
||||
|
||||
Welcome to my blog!
|
||||
###################
|
||||
|
||||
:date: 20181216 08:30
|
||||
:tags: welcome
|
||||
:category: Intro
|
||||
:slug: welcome
|
||||
:author: Craig
|
||||
:summary: Welcome document
|
||||
|
||||
Welcome to my blog.
|
||||
This is a short page just to show how to put up a static page.
|
||||
```
|
||||
|
||||
Pelican 会自动解析元数据行,包括日期、标签等。
|
||||
|
||||
编写完文件后,开发服务器应该输出以下内容:
|
||||
|
||||
```
|
||||
-> Modified: content. regenerating...
|
||||
Done: Processed 1 article, 0 drafts, 0 pages, 0 hidden pages and 0 draft pages in 0.10 seconds.
|
||||
```
|
||||
|
||||
在浏览器中刷新你的测试网站来查看更改。
|
||||
|
||||

|
||||
|
||||
元数据(例如日期和标签)会自动添加到页面中。此外,Pelican 会自动检测到 intro 栏目,并将该部分添加到顶部导航中。
|
||||
|
||||
### 更改主题
|
||||
|
||||
使用像 Pelican 这样流行的开源软件的好处之一是,非常多的用户会做出更改并将其贡献给项目。许多都是以主题形式贡献的。
|
||||
|
||||
网站的主题会设置颜色、布局选项等。尝试一个新主题非常容易,你可以在 [Pelican 主题][8]中预览其中的许多内容。
|
||||
|
||||
首先,克隆 GitHub 仓库:
|
||||
|
||||
```
|
||||
$ cd ..
|
||||
$ git clone --recursive https://github.com/getpelican/pelicanthemes
|
||||
Cloning into 'pelicanthemes'...
|
||||
```
|
||||
|
||||
我喜欢蓝色,那么试试 [blueidea][9]。
|
||||
|
||||
编辑 `pelicanconf.py`,添加以下行:
|
||||
|
||||
```
|
||||
THEME = '/Users/craig/tmp/pelican/pelican-themes/blueidea/'
|
||||
```
|
||||
|
||||
开发服务器将重新生成你的输出。在浏览器中刷新网页来查看新主题。
|
||||
|
||||

|
||||
|
||||
主题控制布局的方方面面。例如,在默认主题中,你可以看到文章旁边带有元标记的栏目(Intro),但这个栏目并未显示在 blueidea 主题中。
|
||||
|
||||
### 其他考虑因素
|
||||
|
||||
本文是对 Pelican 的快速介绍,所以我并没有涉及一些重要的主题。
|
||||
|
||||
首先,我对迁移到静态站点犹豫不决的一个原因是它无法对文章评论。幸运的是,有一些第三方服务商将为你提供评论功能。我目前正在关注的是 [Disqus][10]。
|
||||
|
||||
接下来,上面的所有内容都是在我的本地机器上完成的。如果我希望其他人查看我的网站,我将不得不将预先生成的 HTML 文件上传到某个地方。如果你查看 `pelican-quickstart` 输出,你将看到使用 FTP、 SSH、S3 甚至 GitHub 页面的选项,每个选项都有其优点和缺点。但是,如果我必须选择一个,那么我可能会选择发布到 GitHub 页面。
|
||||
|
||||
Pelican 还有许多其他功能,我每天都在学习它。如果你想自托管一个网站或博客,内容简单并且是静态内容,同时你想使用 Python,那么 Pelican 是一个很好的选择。它有一个活跃的用户社区,可以修复 bug,添加特性,而且还会创建新的和有趣的主题。试试看吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/1/getting-started-pelican
|
||||
|
||||
作者:[Craig Sebenik][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/craig5
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/resources/python
|
||||
[2]: https://opensource.com/sitewide-search?search_api_views_fulltext=static%20site%20generator
|
||||
[3]: http://docs.getpelican.com/en/stable/
|
||||
[4]: http://docutils.sourceforge.net/rst.html
|
||||
[5]: https://daringfireball.net/projects/markdown/
|
||||
[6]: https://virtualenv.pypa.io/en/latest/
|
||||
[7]: http://jinja.pocoo.org/docs/2.10/
|
||||
[8]: http://www.pelicanthemes.com/
|
||||
[9]: https://github.com/nasskach/pelican-blueidea/tree/58fb13112a2707baa7d65075517c40439ab95c0a
|
||||
[10]: https://disqus.com/
|
||||
@@ -0,0 +1,78 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10477-1.html)
|
||||
[#]: subject: (Bash 5.0 Released with New Features)
|
||||
[#]: via: (https://itsfoss.com/bash-5-release)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Bash 5.0 发布及其新功能
|
||||
======
|
||||
|
||||
[邮件列表][1]证实最近发布了 Bash-5.0。而且,令人兴奋的是它还有新的功能和变量。
|
||||
|
||||
如果你一直在使用 Bash 4.4.XX,那么你一定会喜欢 [Bash][2] 的第五个主要版本。
|
||||
|
||||
第五个版本侧重于新的 shell 变量和许多重大漏洞修复。它还引入了一些新功能,以及一些与 bash-4.4 不兼容的更改。
|
||||
|
||||
![Bash logo][3]
|
||||
|
||||
### 新功能怎么样?
|
||||
|
||||
在邮件列表解释了此版本中修复的 bug:
|
||||
|
||||
> 此版本修复了 bash-4.4 中的几个主要错误,并引入了几个新功能。最重要的 bug 修复是对 nameref 变量的解析以及通过模糊测试发现的许多潜在的内存越界错误。在为了符合 Posix 标准解释而不进行单词拆分的上下文中,对 `$@` 和 `$*` 的展开做了许多改变,另外还有解决极端情况中 Posix 一致性的修改。
|
||||
|
||||
它还引入了一些新功能。根据其发布说明,最值得注意的新功能是几个新的 shell 变量:
|
||||
|
||||
> `BASH_ARGV0`、`EPOCHSECONDS` 和 `EPOCHREALTIME`。内置命令 `history` 可以删除指定范围的条目,并能将负数理解为从历史末端开始的偏移量。有一个选项允许局部变量继承前一个范围内具有相同名称的变量的值。有一个新的 shell 选项,在启用它时,会导致 shell 只尝试一次扩展关联数组下标(这在算术表达式中使用时会出现问题)。`globasciiranges` 这个 shell 选项现在默认启用。可以在配置时默认关闭它。
|
||||
|
||||
### Bash-4.4 和 Bash-5.0 之间有哪些变化?
|
||||
|
||||
其更新日志提到了不兼容的更改和所支持的 readline 版本历史记录。它是这么说的:
|
||||
|
||||
> bash-4.4 和 bash-5.0 之间存在一些不兼容的变化。尽管我已经尽量最小化兼容性问题,但是对 `nameref` 变量解析的更改意味着对变量名引用的某些使用会有不同的行为。默认情况下,如果启用了扩展调试模式,shell 仅在启动时设置 `BASH_ARGC` 和 `BASH_ARGV`。它被无条件地设置是一个疏忽,并且在脚本传递大量参数时会导致性能问题。
|
||||
>
|
||||
> 如果需要,可以将 Bash 链接到已安装的 Readline 库,而不是 `lib/readline` 中的私有版本。只有 readline-8.0 及更高版本能够提供 bash-5.0 所需的所有符号。早期版本的 Readline 库无法正常工作。
|
||||
|
||||
我相信一些添加的功能/变量非常有用。我最喜欢的一些是:
|
||||
|
||||
* 有一个新的(默认情况下禁用,文档中没有说明)shell 选项,用于在运行时启用/禁用向 syslog 发送历史记录。
|
||||
* 正如文档一直所说的那样,除非 shell 处于调试模式,否则它不会在启动时自动设置 `BASH_ARGC` 和 `BASH_ARGV`,但如果脚本在上层引用它们且没有启用调试模式,那么 shell 将动态创建它们。
|
||||
* 现在可以使用 `-d start-end` 删除指定范围的 `history` 条目。
|
||||
* 如果启用了作业控制的非交互式 shell 检测到前台作业因 SIGINT 而死亡,则其行为就像接收到 SIGINT 一样。
|
||||
* `BASH_ARGV0`:一个新变量,扩展为 `$0`,并在赋值时设置为 `$0`。
|
||||
|
||||
要查看完整的更改和功能列表,请参阅[邮件列表文章][1]。
|
||||
|
||||
### 总结
|
||||
|
||||
你可以使用下面的命令检查你当前的 Bash 版本:
|
||||
|
||||
```
|
||||
bash --version
|
||||
```
|
||||
|
||||
你很可能安装了 Bash 4.4。如果你想获得新版本,我建议等待你的发行版提供它。
|
||||
|
||||
你怎么看待 Bash-5.0 发布?你在使用其他 bash 的替代品么?如果有的话,这个更新会改变你的想法么?
|
||||
|
||||
请在下面的评论中告诉我们你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/bash-5-release
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://lists.gnu.org/archive/html/bug-bash/2019-01/msg00063.html
|
||||
[2]: https://www.gnu.org/software/bash/
|
||||
[3]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/01/bash-logo.jpg?resize=800%2C450&ssl=1
|
||||
@@ -0,0 +1,75 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10460-1.html)
|
||||
[#]: subject: (Understanding /etc/services file in Linux)
|
||||
[#]: via: (https://kerneltalks.com/linux/understanding-etc-services-file-in-linux/)
|
||||
[#]: author: (kerneltalks https://kerneltalks.com)
|
||||
|
||||
理解 Linux 中的 /etc/services 文件
|
||||
======
|
||||
|
||||
这篇文章将帮助你了解 Linux 中 `/etc/services` 文件,包括它的内容,格式以及重要性。
|
||||
|
||||
![/etc/services file in Linux][1]
|
||||
|
||||
*Linux 中的 /etc/services 文件*
|
||||
|
||||
Internet 守护程序(`ineted`)是 Linux 世界中的重要服务。它借助 `/etc/services` 文件来处理所有网络服务。在本文中,我们将向你介绍这个文件的内容,格式以及它对于 Linux 系统的意义。
|
||||
|
||||
`/etc/services` 文件包含网络服务和它们映射端口的列表。`inetd` 或 `xinetd` 会查看这些细节,以便在数据包到达各自的端口或服务有需求时,它会调用特定的程序。
|
||||
|
||||
作为普通用户,你可以查看此文件,因为文件一般都是可读的。要编辑此文件,你需要有 root 权限。
|
||||
|
||||
```
|
||||
$ ll /etc/services
|
||||
-rw-r--r--. 1 root root 670293 Jun 7 2013 /etc/services
|
||||
```
|
||||
|
||||
### /etc/services 文件格式
|
||||
|
||||
```
|
||||
service-name port/protocol [aliases..] [#comment]
|
||||
```
|
||||
|
||||
最后两个字段是可选的,因此用 `[` `]` 表示。
|
||||
|
||||
其中:
|
||||
|
||||
* `service-name` 是网络服务的名称。例如 [telnet][2]、[ftp][3] 等。
|
||||
* `port/protocol` 是网络服务使用的端口(一个数值)和服务通信使用的协议(TCP/UDP)。
|
||||
* `alias` 是服务的别名。
|
||||
* `comment` 是你可以添加到服务的注释或说明。以 `#` 标记开头。
|
||||
|
||||
### /etc/services 文件示例
|
||||
|
||||
```
|
||||
# 每行描述一个服务,形式如下:
|
||||
#
|
||||
# service-name port/protocol [aliases ...] [# comment]
|
||||
|
||||
tcpmux 1/tcp # TCP port service multiplexer
|
||||
rje 5/tcp # Remote Job Entry
|
||||
echo 7/udp
|
||||
discard 9/udp sink null
|
||||
```
|
||||
|
||||
在这里,你可以看到可选的最后两个字段的用处。`discard` 服务的别名为 `sink` 或 `null`。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://kerneltalks.com/linux/understanding-etc-services-file-in-linux/
|
||||
|
||||
作者:[kerneltalks][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://kerneltalks.com
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i2.wp.com/kerneltalks.com/wp-content/uploads/2019/01/undestanding-etc-service-file-in-linux.png?ssl=1
|
||||
[2]: https://kerneltalks.com/config/configure-telnet-server-linux/
|
||||
[3]: https://kerneltalks.com/config/ftp-server-configuration-steps-rhel-6/
|
||||
@@ -0,0 +1,67 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10476-1.html)
|
||||
[#]: subject: (Get started with Joplin, a note-taking app)
|
||||
[#]: via: (https://opensource.com/article/19/1/productivity-tool-joplin)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney (Kevin Sonney))
|
||||
|
||||
开始使用 Joplin 吧,一款开源笔记应用
|
||||
======
|
||||
|
||||
> 了解开源工具如何帮助你在 2019 年提高工作效率。先从 Joplin 开始。
|
||||
|
||||

|
||||
|
||||
每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心,渴望开启新的一年,当然,“抛弃旧的,拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件,但事实上并不用这样。
|
||||
|
||||
这是我挑选出的 19 个新的(或者对你而言新的)开源项目来帮助你在 2019 年更有效率。
|
||||
|
||||
### Joplin
|
||||
|
||||
在生产力工具领域,笔记应用**非常**方便。是的,你可以使用开源 [NixNote][1] 访问 [Evernote][2] 笔记,但它仍然与 Evernote 服务器相关联,并且仍然依赖于第三方的安全性。虽然你**可以**从 NixNote 导出 Evernote 笔记,但可选格式只有 NixNote XML 或 PDF。
|
||||
|
||||

|
||||
|
||||
*Joplin 的图形界面*
|
||||
|
||||
看看 [Joplin][3]。Joplin 是一个 NodeJS 应用,它在本地运行和存储笔记,它允许你加密笔记并支持多种同步方法。Joplin 可在 Windows、Mac 和 Linux 上作为控制台应用或图形应用运行。Joplin 还有适用于 Android 和 iOS 的移动应用,这意味着你可以随身携带笔记而不会有任何麻烦。Joplin 甚至允许你使用 Markdown、HTML 或纯文本格式笔记。
|
||||
|
||||

|
||||
|
||||
*Joplin 的 Android 应用*
|
||||
|
||||
关于 Joplin 很棒的一件事是它支持两种类型笔记:普通笔记和待办事项笔记。普通笔记是你所想的包含文本的文档。另一个,待办事项笔记在笔记列表中有一个复选框,允许你将其标记为“已完成”。由于待办事项仍然是一个笔记,因此你可以在待办事项中添加列表、文档和其他待办事项。
|
||||
|
||||
当使用图形界面时,你可以在纯文本、WYSIWYG 和同时显示源文本和渲染视图的分屏之间切换编辑器视图。你还可以在图形界面中指定外部编辑器,以便使用 Vim、Emacs 或任何其他能够处理文本文档的编辑器轻松更新笔记。
|
||||
|
||||
![Joplin console version][5]
|
||||
|
||||
*控制台中的 Joplin*
|
||||
|
||||
控制台界面非常棒。虽然它缺少 WYSIWYG 编辑器,但默认登录使用文本编辑器。它还有强大的命令模式,它允许执行在图形版本中几乎所有的操作。并且能够在视图中正确渲染 Markdown。
|
||||
|
||||
你可以将笔记本中的笔记分组,还能为笔记打上标记,以便于在笔记本中进行分组。它甚至还有内置的搜索功能,因此如果你忘了笔记在哪,你可以通过它找到它们。
|
||||
|
||||
总的来说,Joplin 是一款一流的笔记应用([还是 Evernote 的一个很好的替代品][6]),它能帮助你在明年组织化并提高工作效率。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/1/productivity-tool-joplin
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney (Kevin Sonney)
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://nixnote.org/NixNote-Home/
|
||||
[2]: https://evernote.com/
|
||||
[3]: https://joplin.cozic.net/
|
||||
[4]: https://opensource.com/article/19/1/file/419776
|
||||
[5]: https://opensource.com/sites/default/files/uploads/joplin-2_0.png (Joplin console version)
|
||||
[6]: https://opensource.com/article/17/12/joplin-open-source-evernote-alternative
|
||||
@@ -0,0 +1,66 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wwhio)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10454-1.html)
|
||||
[#]: subject: (Get started with Wekan, an open source kanban board)
|
||||
[#]: via: (https://opensource.com/article/19/1/productivity-tool-wekan)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney (Kevin Sonney))
|
||||
|
||||
开始使用 Wekan 吧,一款开源看板软件
|
||||
======
|
||||
|
||||
> 这是开源工具类软件推荐的第二期,本文将让你在 2019 年更具生产力。来,让我们一起看看 Wekan 吧。
|
||||
|
||||

|
||||
|
||||
每年年初,人们似乎都在想方设法地让自己更具生产力。对新年目标、期待,当然还有“新年新气象”这样的口号等等都促人上进。可大部分生产力软件的推荐都严重偏向闭源的专有软件,但事实上并不用这样。
|
||||
|
||||
这是我挑选的 19 款帮助你在 2019 年提升生产力的开源工具中的第 2 个。
|
||||
|
||||
### Wekan
|
||||
|
||||
[看板][1]是当今敏捷开发流程中的重要组成部分。我们中的很多人使用它同时管理自己的工作和生活。有些人在用 [Trello][2] 这样的 APP 来跟踪他们的项目,例如哪些事务正在处理,哪些事务已经完成。
|
||||
|
||||

|
||||
|
||||
但这些 APP 通常需要连接到一个工作账户或者商业服务中。而 [Wekan][3] 作为一款开源看板工具,你可以让它完全在本地运行,或者使用你自己选择的服务运行它。其他的看板 APP 提供的功能在 Wekan 里几乎都有,例如创建看板、列表、泳道、卡片,在列表间拖放,给指定的用户安排任务,给卡片添加标签等等,基本上你对一款现代看板软件的功能需求它都能提供。
|
||||
|
||||

|
||||
|
||||
Wekan 的独到之处在于它的内置规则。虽然其他的看板软件支持<ruby>邮件更新<rt>emailing updates</rt></ruby>,但 Wekan 允许用户自行设定触发器,其触发条件可以是卡片变动、清单变动或标签变动等等。
|
||||
|
||||

|
||||
|
||||
当触发条件满足时, Wekan 可以自动执行如移动卡片、更新标签、添加清单或者发送邮件等操作。
|
||||
|
||||

|
||||
|
||||
Wekan 的本地搭建可以直接使用 snap 。如果你的桌面环境支持 [Snapcraft][4] 构建的应用,那么只需要一条命令就能安装 Wekan :
|
||||
|
||||
```
|
||||
sudo snap install wekan
|
||||
```
|
||||
|
||||
此外 Wekan 还支持 Docker 安装,这使它在大部分服务器环境和桌面环境下的搭建变得相当容易。
|
||||
|
||||
最后,如果你想寻找一款能自建又好用的看板软件,你已经遇上了 Wekan 。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/1/productivity-tool-wekan
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wwhio](https://github.com/wwhio)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney (Kevin Sonney)
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://en.wikipedia.org/wiki/Kanban
|
||||
[2]: https://www.trello.com
|
||||
[3]: https://wekan.github.io/
|
||||
[4]: https://snapcraft.io/
|
||||
@@ -0,0 +1,94 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10464-1.html)
|
||||
[#]: subject: (How To Move Multiple File Types Simultaneously From Commandline)
|
||||
[#]: via: (https://www.ostechnix.com/how-to-move-multiple-file-types-simultaneously-from-commandline/)
|
||||
[#]: author: (SK https://www.ostechnix.com/author/sk/)
|
||||
|
||||
如何从命令行同时移动多种文件类型
|
||||
======
|
||||
|
||||

|
||||
|
||||
前几天,我想知道如何将多个文件类型从一个目录移动(不复制)到另一个目录。我已经知道如何[查找并将某些类型的文件从一个目录复制到另一个目录][1]。但是,我不知道如何同时移动多种文件类型。如果你曾遇到这样的情况,我知道在类 Unix 系统中从命令行执行该操作的一个简单方法。
|
||||
|
||||
### 同时移动多种文件类型
|
||||
|
||||
想象一下这种场景,你在名为 `dir1` 的目录中有多种类型的文件,例如 .pdf、 .doc、 .mp3、 .mp4、 .txt 等等。我们来看看 `dir1` 的内容:
|
||||
|
||||
```
|
||||
$ ls dir1
|
||||
file.txt image.jpg mydoc.doc personal.pdf song.mp3 video.mp4
|
||||
```
|
||||
|
||||
你希望将某些文件类型(不是所有文件类型)移动到另一个位置。例如,假设你想将 .doc、 .pdf 和 .txt 文件一次性移动到名为 `dir2` 的另一个目录中。
|
||||
|
||||
要同时将 .doc、 .pdf 和 .txt 文件从 `dir1` 移动到 `dir2`,命令是:
|
||||
|
||||
```
|
||||
$ mv dir1/*.{doc,pdf,txt} dir2/
|
||||
```
|
||||
|
||||
很容易,不是吗?
|
||||
|
||||
现在让我们来查看一下 `dir2` 的内容:
|
||||
|
||||
```
|
||||
$ ls dir2/
|
||||
file.txt mydoc.doc personal.pdf
|
||||
```
|
||||
|
||||
看到了吗?只有 .doc、 .pdf 和 .txt 从 `dir1` 移到了 `dir2`。
|
||||
|
||||
![][3]
|
||||
|
||||
在上面的命令中,你可以在花括号内添加任意数量的文件类型,以将它们移动到不同的目录中。它在 Bash 上非常适合我。
|
||||
|
||||
另一种移动多种文件类型的方法是转到源目录,在我们的例子中即为 `dir1`:
|
||||
|
||||
```
|
||||
$ cd ~/dir1
|
||||
```
|
||||
|
||||
将你选择的文件类型移动到目的地(即 `dir2`),如下所示:
|
||||
|
||||
```
|
||||
$ mv *.doc *.txt *.pdf /home/sk/dir2/
|
||||
```
|
||||
|
||||
要移动具有特定扩展名的所有文件,例如 .doc,运行:
|
||||
|
||||
```
|
||||
$ mv dir1/*.doc dir2/
|
||||
```
|
||||
|
||||
更多细节,参考 man 页:
|
||||
|
||||
```
|
||||
$ man mv
|
||||
```
|
||||
|
||||
移动一些相同或不同的文件类型很容易!你可以在 GUI 模式下单击几下鼠标,或在 CLI 模式下使用一行命令来完成。但是,如果目录中有数千种不同的文件类型,并且希望一次将多种文件类型移动到不同的目录,这将是一项繁琐的任务。对我来说,上面的方法很容易完成工作!如果你知道任何其它一行命令可以一次移动多种文件类型,请在下面的评论部分与我们分享。我会核对并更新指南。
|
||||
|
||||
这些就是全部了,希望这很有用。更多好东西将要来了,敬请关注!
|
||||
|
||||
共勉!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-move-multiple-file-types-simultaneously-from-commandline/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.ostechnix.com/find-copy-certain-type-files-one-directory-another-linux/
|
||||
[2]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[3]: http://www.ostechnix.com/wp-content/uploads/2019/01/mv-command.gif
|
||||
@@ -0,0 +1,627 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "qhwdw"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-10470-1.html"
|
||||
[#]: subject: "How to Build a Netboot Server, Part 4"
|
||||
[#]: via: "https://fedoramagazine.org/how-to-build-a-netboot-server-part-4/"
|
||||
[#]: author: "Gregory Bartholomew https://fedoramagazine.org/author/glb/"
|
||||
|
||||
如何构建一台网络引导服务器(四)
|
||||
======
|
||||

|
||||
|
||||
在本系列教程中所构建的网络引导服务器有一个很重要的限制,那就是所提供的操作系统镜像是只读的。一些使用场景或许要求终端用户能够修改操作系统镜像。例如,一些教师或许希望学生能够安装和配置一些像 MariaDB 和 Node.js 这样的包来做为他们课程练习的一部分。
|
||||
|
||||
可写镜像的另外的好处是,终端用户“私人定制”的操作系统,在下次不同的工作站上使用时能够“跟着”他们。
|
||||
|
||||
### 修改 Bootmenu 应用程序以使用 HTTPS
|
||||
|
||||
为 bootmenu 应用程序创建一个自签名的证书:
|
||||
|
||||
```
|
||||
$ sudo -i
|
||||
# MY_NAME=$(</etc/hostname)
|
||||
# MY_TLSD=/opt/bootmenu/tls
|
||||
# mkdir $MY_TLSD
|
||||
# openssl req -newkey rsa:2048 -nodes -keyout $MY_TLSD/$MY_NAME.key -x509 -days 3650 -out $MY_TLSD/$MY_NAME.pem
|
||||
```
|
||||
|
||||
验证你的证书的值。确保 `Subject` 行中 `CN` 的值与你的 iPXE 客户端连接你的网络引导服务器所使用的 DNS 名字是相匹配的:
|
||||
|
||||
```
|
||||
# openssl x509 -text -noout -in $MY_TLSD/$MY_NAME.pem
|
||||
```
|
||||
|
||||
接下来,更新 bootmenu 应用程序去监听 HTTPS 端口和新创建的证书及密钥:
|
||||
|
||||
```
|
||||
# sed -i "s#listen => .*#listen => ['https://$MY_NAME:443?cert=$MY_TLSD/$MY_NAME.pem\&key=$MY_TLSD/$MY_NAME.key\&ciphers=AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA'],#" /opt/bootmenu/bootmenu.conf
|
||||
```
|
||||
|
||||
注意 [iPXE 当前支持的][1] 加密算法是有限制的。
|
||||
|
||||
GnuTLS 要求 “CAP_DAC_READ_SEARCH” 能力,因此将它添加到 bootmenu 应用程序的 systemd 服务:
|
||||
|
||||
```
|
||||
# sed -i '/^AmbientCapabilities=/ s/$/ CAP_DAC_READ_SEARCH/' /etc/systemd/system/bootmenu.service
|
||||
# sed -i 's/Serves iPXE Menus over HTTP/Serves iPXE Menus over HTTPS/' /etc/systemd/system/bootmenu.service
|
||||
# systemctl daemon-reload
|
||||
```
|
||||
|
||||
现在,在防火墙中为 bootmenu 服务添加一个例外规则并重启动该服务:
|
||||
|
||||
```
|
||||
# MY_SUBNET=192.0.2.0
|
||||
# MY_PREFIX=24
|
||||
# firewall-cmd --add-rich-rule="rule family='ipv4' source address='$MY_SUBNET/$MY_PREFIX' service name='https' accept"
|
||||
# firewall-cmd --runtime-to-permanent
|
||||
# systemctl restart bootmenu.service
|
||||
```
|
||||
|
||||
使用 `wget` 去验证是否工作正常:
|
||||
|
||||
```
|
||||
$ MY_NAME=server-01.example.edu
|
||||
$ MY_TLSD=/opt/bootmenu/tls
|
||||
$ wget -q --ca-certificate=$MY_TLSD/$MY_NAME.pem -O - https://$MY_NAME/menu
|
||||
```
|
||||
|
||||
### 添加 HTTPS 到 iPXE
|
||||
|
||||
更新 `init.ipxe` 去使用 HTTPS。接着使用选项重新编译 ipxe 引导加载器,以便它包含和信任你为 bootmenu 应用程序创建的自签名证书:
|
||||
|
||||
```
|
||||
$ echo '#define DOWNLOAD_PROTO_HTTPS' >> $HOME/ipxe/src/config/local/general.h
|
||||
$ sed -i 's/^chain http:/chain https:/' $HOME/ipxe/init.ipxe
|
||||
$ cp $MY_TLSD/$MY_NAME.pem $HOME/ipxe
|
||||
$ cd $HOME/ipxe/src
|
||||
$ make clean
|
||||
$ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe CERT="../$MY_NAME.pem" TRUST="../$MY_NAME.pem"
|
||||
```
|
||||
|
||||
你现在可以将启用了 HTTPS 的 iPXE 引导加载器复制到你的客户端上,并测试它能否正常工作:
|
||||
|
||||
```
|
||||
$ cp $HOME/ipxe/src/bin-x86_64-efi/ipxe.efi $HOME/esp/efi/boot/bootx64.efi
|
||||
```
|
||||
|
||||
### 添加用户验证到 Mojolicious 中
|
||||
|
||||
为 bootmenu 应用程序创建一个 PAM 服务定义:
|
||||
|
||||
```
|
||||
# dnf install -y pam_krb5
|
||||
# echo 'auth required pam_krb5.so' > /etc/pam.d/bootmenu
|
||||
```
|
||||
|
||||
添加一个库到 bootmenu 应用程序中,它使用 Authen-PAM 的 Perl 模块去执行用户验证:
|
||||
|
||||
```
|
||||
# dnf install -y perl-Authen-PAM;
|
||||
# MY_MOJO=/opt/bootmenu
|
||||
# mkdir $MY_MOJO/lib
|
||||
# cat << 'END' > $MY_MOJO/lib/PAM.pm
|
||||
package PAM;
|
||||
|
||||
use Authen::PAM;
|
||||
|
||||
sub auth {
|
||||
my $success = 0;
|
||||
|
||||
my $username = shift;
|
||||
my $password = shift;
|
||||
|
||||
my $callback = sub {
|
||||
my @res;
|
||||
while (@_) {
|
||||
my $code = shift;
|
||||
my $msg = shift;
|
||||
my $ans = "";
|
||||
|
||||
$ans = $username if ($code == PAM_PROMPT_ECHO_ON());
|
||||
$ans = $password if ($code == PAM_PROMPT_ECHO_OFF());
|
||||
|
||||
push @res, (PAM_SUCCESS(), $ans);
|
||||
}
|
||||
push @res, PAM_SUCCESS();
|
||||
|
||||
return @res;
|
||||
};
|
||||
|
||||
my $pamh = new Authen::PAM('bootmenu', $username, $callback);
|
||||
|
||||
{
|
||||
last unless ref $pamh;
|
||||
last unless $pamh->pam_authenticate() == PAM_SUCCESS;
|
||||
$success = 1;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
return 1;
|
||||
END
|
||||
```
|
||||
|
||||
以上的代码是一字不差是从 Authen::PAM::FAQ 的 man 页面中复制来的。
|
||||
|
||||
重定义 bootmenu 应用程序,以使它仅当提供了有效的用户名和密码之后返回一个网络引导模板:
|
||||
|
||||
```
|
||||
# cat << 'END' > $MY_MOJO/bootmenu.pl
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use lib 'lib';
|
||||
|
||||
use PAM;
|
||||
use Mojolicious::Lite;
|
||||
use Mojolicious::Plugins;
|
||||
use Mojo::Util ('url_unescape');
|
||||
|
||||
plugin 'Config';
|
||||
|
||||
get '/menu';
|
||||
get '/boot' => sub {
|
||||
my $c = shift;
|
||||
|
||||
my $instance = $c->param('instance');
|
||||
my $username = $c->param('username');
|
||||
my $password = $c->param('password');
|
||||
|
||||
my $template = 'menu';
|
||||
|
||||
{
|
||||
last unless $instance =~ /^fc[[:digit:]]{2}$/;
|
||||
last unless $username =~ /^[[:alnum:]]+$/;
|
||||
last unless PAM::auth($username, url_unescape($password));
|
||||
$template = $instance;
|
||||
}
|
||||
|
||||
return $c->render(template => $template);
|
||||
};
|
||||
|
||||
app->start;
|
||||
END
|
||||
```
|
||||
|
||||
bootmenu 应用程序现在查找 `lib` 命令去找到相应的 `WorkingDirectory`。但是,默认情况下,对于 systemd 单元它的工作目录设置为服务器的 root 目录。因此,你必须更新 systemd 单元去设置 `WorkingDirectory` 为 bootmenu 应用程序的根目录:
|
||||
|
||||
```
|
||||
# sed -i "/^RuntimeDirectory=/ a WorkingDirectory=$MY_MOJO" /etc/systemd/system/bootmenu.service
|
||||
# systemctl daemon-reload
|
||||
```
|
||||
|
||||
更新模块去使用重定义后的 bootmenu 应用程序:
|
||||
|
||||
```
|
||||
# cd $MY_MOJO/templates
|
||||
# MY_BOOTMENU_SERVER=$(</etc/hostname)
|
||||
# MY_FEDORA_RELEASES="28 29"
|
||||
# for i in $MY_FEDORA_RELEASES; do echo '#!ipxe' > fc$i.html.ep; grep "^kernel\|initrd" menu.html.ep | grep "fc$i" >> fc$i.html.ep; echo "boot || chain https://$MY_BOOTMENU_SERVER/menu" >> fc$i.html.ep; sed -i "/^:f$i$/,/^boot /c :f$i\nlogin\nchain https://$MY_BOOTMENU_SERVER/boot?instance=fc$i\&username=\${username}\&password=\${password:uristring} || goto failed" menu.html.ep; done
|
||||
```
|
||||
|
||||
上面的最后的命令将生成类似下面的三个文件:
|
||||
|
||||
`menu.html.ep`:
|
||||
|
||||
```
|
||||
#!ipxe
|
||||
|
||||
set timeout 5000
|
||||
|
||||
:menu
|
||||
menu iPXE Boot Menu
|
||||
item --key 1 lcl 1. Microsoft Windows 10
|
||||
item --key 2 f29 2. RedHat Fedora 29
|
||||
item --key 3 f28 3. RedHat Fedora 28
|
||||
choose --timeout ${timeout} --default lcl selected || goto shell
|
||||
set timeout 0
|
||||
goto ${selected}
|
||||
|
||||
:failed
|
||||
echo boot failed, dropping to shell...
|
||||
goto shell
|
||||
|
||||
:shell
|
||||
echo type 'exit' to get the back to the menu
|
||||
set timeout 0
|
||||
shell
|
||||
goto menu
|
||||
|
||||
:lcl
|
||||
exit
|
||||
|
||||
:f29
|
||||
login
|
||||
chain https://server-01.example.edu/boot?instance=fc29&username=${username}&password=${password:uristring} || goto failed
|
||||
|
||||
:f28
|
||||
login
|
||||
chain https://server-01.example.edu/boot?instance=fc28&username=${username}&password=${password:uristring} || goto failed
|
||||
```
|
||||
|
||||
`fc29.html.ep`:
|
||||
|
||||
```
|
||||
#!ipxe
|
||||
kernel --name kernel.efi ${prefix}/vmlinuz-4.19.5-300.fc29.x86_64 initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc29-lun-1 netroot=iscsi:192.0.2.158::::iqn.edu.example.server-01:fc29 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
|
||||
initrd --name initrd.img ${prefix}/initramfs-4.19.5-300.fc29.x86_64.img
|
||||
boot || chain https://server-01.example.edu/menu
|
||||
```
|
||||
|
||||
`fc28.html.ep`:
|
||||
|
||||
```
|
||||
#!ipxe
|
||||
kernel --name kernel.efi ${prefix}/vmlinuz-4.19.3-200.fc28.x86_64 initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc28-lun-1 netroot=iscsi:192.0.2.158::::iqn.edu.example.server-01:fc28 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
|
||||
initrd --name initrd.img ${prefix}/initramfs-4.19.3-200.fc28.x86_64.img
|
||||
boot || chain https://server-01.example.edu/menu
|
||||
```
|
||||
|
||||
现在,重启动 bootmenu 应用程序,并验证用户认证是否正常工作:
|
||||
|
||||
```
|
||||
# systemctl restart bootmenu.service
|
||||
```
|
||||
|
||||
### 使得 iSCSI Target 可写
|
||||
|
||||
现在,用户验证通过 iPXE 可以正常工作,在用户连接时,你可以按需在只读镜像的上面创建每用户可写的<ruby>overlay<rt>叠加层</rt></ruby>。使用一个 [写时复制][2] 的叠加层与简单地为每个用户复制原始镜像相比有三个好处:
|
||||
|
||||
1. 副本创建非常快。这样就可以按需创建。
|
||||
2. 副本并不增加服务器上的磁盘使用。除了原始镜像之外,仅存储用户写入个人镜像的内容。
|
||||
3. 由于每个副本的扇区大多都是服务器的存储器上的相同扇区,在随后的用户访问这些操作系统的副本时,它们可能已经加载到内存中,这样就提升了服务器的性能,因为对内存的访问速度要比磁盘 I/O 快得多。
|
||||
|
||||
使用写时复制的一个潜在隐患是,一旦叠加层创建后,叠加层之下的镜像就不能再改变。如果它们改变,所有它们之上的叠加层将出错。因此,叠加层必须被删除并用新的、空白的进行替换。即便只是简单地以读写模式加载的镜像,也可能因为某些文件系统更新导致叠加层出错。
|
||||
|
||||
由于这个隐患,如果原始镜像被修改将导致叠加层出错,因此运行下列的命令,将原始镜像标记为不可改变:
|
||||
|
||||
```
|
||||
# chattr +i </path/to/file>
|
||||
```
|
||||
|
||||
你可以使用 `lsattr </path/to/file>` 去查看不可改变标志,并可以使用 `chattr -i </path/to/file>` 取消设置不可改变标志。在设置了不可改变标志之后,即便是 root 用户或以 root 运行的系统进程也不修改或删除这个文件。
|
||||
|
||||
停止 tgtd.service 之后,你就可以改变镜像文件:
|
||||
|
||||
```
|
||||
# systemctl stop tgtd.service
|
||||
```
|
||||
|
||||
当仍有连接打开的时候,运行这个命令一般需要一分钟或更长的时间。
|
||||
|
||||
现在,移除只读的 iSCSI 出口。然后更新模板中的 `readonly-root` 配置文件,以使镜像不再是只读的:
|
||||
|
||||
```
|
||||
# MY_FC=fc29
|
||||
# rm -f /etc/tgt/conf.d/$MY_FC.conf
|
||||
# TEMP_MNT=$(mktemp -d)
|
||||
# mount /$MY_FC.img $TEMP_MNT
|
||||
# sed -i 's/^READONLY=yes$/READONLY=no/' $TEMP_MNT/etc/sysconfig/readonly-root
|
||||
# sed -i 's/^Storage=volatile$/#Storage=auto/' $TEMP_MNT/etc/systemd/journald.conf
|
||||
# umount $TEMP_MNT
|
||||
```
|
||||
|
||||
将 journald 日志从发送到内存修改回缺省值(如果 `/var/log/journal` 存在的话记录到磁盘),因为一个用户报告说,他的客户端由于应用程序生成了大量的系统日志而产生内存溢出错误,导致它的客户端被卡住。而将日志记录到磁盘的负面影响是客户端产生了额外的写入流量,这将在你的网络引导服务器上可能增加一些没有必要的 I/O。你应该去决定到底使用哪个选择 —— 记录到内存还是记录到硬盘 —— 哪个更合适取决于你的环境。
|
||||
|
||||
因为你的模板镜像在以后不能做任何的更改,因此在它上面设置不可更改标志,然后重启动 tgtd.service:
|
||||
|
||||
```
|
||||
# chattr +i /$MY_FC.img
|
||||
# systemctl start tgtd.service
|
||||
```
|
||||
|
||||
现在,更新 bootmenu 应用程序:
|
||||
|
||||
```
|
||||
# cat << 'END' > $MY_MOJO/bootmenu.pl
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use lib 'lib';
|
||||
|
||||
use PAM;
|
||||
use Mojolicious::Lite;
|
||||
use Mojolicious::Plugins;
|
||||
use Mojo::Util ('url_unescape');
|
||||
|
||||
plugin 'Config';
|
||||
|
||||
get '/menu';
|
||||
get '/boot' => sub {
|
||||
my $c = shift;
|
||||
|
||||
my $instance = $c->param('instance');
|
||||
my $username = $c->param('username');
|
||||
my $password = $c->param('password');
|
||||
|
||||
my $chapscrt;
|
||||
my $template = 'menu';
|
||||
|
||||
{
|
||||
last unless $instance =~ /^fc[[:digit:]]{2}$/;
|
||||
last unless $username =~ /^[[:alnum:]]+$/;
|
||||
last unless PAM::auth($username, url_unescape($password));
|
||||
last unless $chapscrt = `sudo scripts/mktgt $instance $username`;
|
||||
$template = $instance;
|
||||
}
|
||||
|
||||
return $c->render(template => $template, username => $username, chapscrt => $chapscrt);
|
||||
};
|
||||
|
||||
app->start;
|
||||
END
|
||||
```
|
||||
|
||||
新版本的 bootmenu 应用程序调用一个定制的 `mktgt` 脚本,如果成功,它将为每个它自己创建的新的 iSCSI 目标返回一个随机的 [CHAP][3] 密码。这个 CHAP 密码可以防止其它用户的 iSCSI 目标以间接方式挂载这个用户的目标。这个应用程序只有在用户密码认证成功之后才返回一个正确的 iSCSI 目标密码。
|
||||
|
||||
`mktgt` 脚本要加 `sudo` 前缀来运行,因为它需要 root 权限去创建目标。
|
||||
|
||||
`$username` 和 `$chapscrt` 变量也传递给 `render` 命令,因此在需要的时候,它们也能够被纳入到模板中返回给用户。
|
||||
|
||||
接下来,更新我们的引导模板,以便于它们能够读取用户名和 `chapscrt` 变量,并传递它们到所属的终端用户。也要更新模板以 rw(读写)模式加载根文件系统:
|
||||
|
||||
```
|
||||
# cd $MY_MOJO/templates
|
||||
# sed -i "s/:$MY_FC/:$MY_FC-<%= \$username %>/g" $MY_FC.html.ep
|
||||
# sed -i "s/ netroot=iscsi:/ netroot=iscsi:<%= \$username %>:<%= \$chapscrt %>@/" $MY_FC.html.ep
|
||||
# sed -i "s/ ro / rw /" $MY_FC.html.ep
|
||||
```
|
||||
|
||||
运行上面的命令后,你应该会看到如下的引导模板:
|
||||
|
||||
```
|
||||
#!ipxe
|
||||
kernel --name kernel.efi ${prefix}/vmlinuz-4.19.5-300.fc29.x86_64 initrd=initrd.img rw ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc29-<%= $username %>-lun-1 netroot=iscsi:<%= $username %>:<%= $chapscrt %>@192.0.2.158::::iqn.edu.example.server-01:fc29-<%= $username %> console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
|
||||
initrd --name initrd.img ${prefix}/initramfs-4.19.5-300.fc29.x86_64.img
|
||||
boot || chain https://server-01.example.edu/menu
|
||||
```
|
||||
|
||||
注意:如果在 [插入][4] 变量后需要查看引导模板,你可以在 `boot` 命令之前,在它自己的行中插入 `shell` 命令。然后在你网络引导你的客户端时,iPXE 将在那里给你提供一个用于交互的 shell,你可以在 shell 中输入 `imgstat` 去查看传递到内核的参数。如果一切正确,你可以输入 `exit` 去退出 shell 并继续引导过程。
|
||||
|
||||
现在,通过 `sudo` 允许 bootmenu 用户以 root 权限去运行 `mktgt` 脚本(仅这个脚本):
|
||||
|
||||
```
|
||||
# echo "bootmenu ALL = NOPASSWD: $MY_MOJO/scripts/mktgt *" > /etc/sudoers.d/bootmenu
|
||||
```
|
||||
|
||||
bootmenu 用户不应该写访问 `mktgt` 脚本或在它的家目录下的任何其它文件。在 `/opt/bootmenu` 目录下的所有文件的属主应该是 root,并且不应该被其它任何 root 以外的用户可写。
|
||||
|
||||
`sudo` 在使用 systemd 的 `DynamicUser` 选项下不能正常工作,因此创建一个普通用户帐户,并设置 systemd 服务以那个用户运行:
|
||||
|
||||
```
|
||||
# useradd -r -c 'iPXE Boot Menu Service' -d /opt/bootmenu -s /sbin/nologin bootmenu
|
||||
# sed -i 's/^DynamicUser=true$/User=bootmenu/' /etc/systemd/system/bootmenu.service
|
||||
# systemctl daemon-reload
|
||||
```
|
||||
|
||||
最后,为写时复制覆盖创建一个目录,并创建管理 iSCSI 目标的 `mktgt` 脚本和它们的覆盖支持存储:
|
||||
|
||||
```
|
||||
# mkdir /$MY_FC.cow
|
||||
# mkdir $MY_MOJO/scripts
|
||||
# cat << 'END' > $MY_MOJO/scripts/mktgt
|
||||
#!/usr/bin/env perl
|
||||
|
||||
# if another instance of this script is running, wait for it to finish
|
||||
"$ENV{FLOCKER}" eq 'MKTGT' or exec "env FLOCKER=MKTGT flock /tmp $0 @ARGV";
|
||||
|
||||
# use "RETURN" to print to STDOUT; everything else goes to STDERR by default
|
||||
open(RETURN, '>&', STDOUT);
|
||||
open(STDOUT, '>&', STDERR);
|
||||
|
||||
my $instance = shift or die "instance not provided";
|
||||
my $username = shift or die "username not provided";
|
||||
|
||||
my $img = "/$instance.img";
|
||||
my $dir = "/$instance.cow";
|
||||
my $top = "$dir/$username";
|
||||
|
||||
-f "$img" or die "'$img' is not a file";
|
||||
-d "$dir" or die "'$dir' is not a directory";
|
||||
|
||||
my $base;
|
||||
die unless $base = `losetup --show --read-only --nooverlap --find $img`;
|
||||
chomp $base;
|
||||
|
||||
my $size;
|
||||
die unless $size = `blockdev --getsz $base`;
|
||||
chomp $size;
|
||||
|
||||
# create the per-user sparse file if it does not exist
|
||||
if (! -e "$top") {
|
||||
die unless system("dd if=/dev/zero of=$top status=none bs=512 count=0 seek=$size") == 0;
|
||||
}
|
||||
|
||||
# create the copy-on-write overlay if it does not exist
|
||||
my $cow="$instance-$username";
|
||||
my $dev="/dev/mapper/$cow";
|
||||
if (! -e "$dev") {
|
||||
my $over;
|
||||
die unless $over = `losetup --show --nooverlap --find $top`;
|
||||
chomp $over;
|
||||
die unless system("echo 0 $size snapshot $base $over p 8 | dmsetup create $cow") == 0;
|
||||
}
|
||||
|
||||
my $tgtadm = '/usr/sbin/tgtadm --lld iscsi';
|
||||
|
||||
# get textual representations of the iscsi targets
|
||||
my $text = `$tgtadm --op show --mode target`;
|
||||
my @targets = $text =~ /(?:^T.*\n)(?:^ .*\n)*/mg;
|
||||
|
||||
# convert the textual representations into a hash table
|
||||
my $targets = {};
|
||||
foreach (@targets) {
|
||||
my $tgt;
|
||||
my $sid;
|
||||
|
||||
foreach (split /\n/) {
|
||||
/^Target (\d+)(?{ $tgt = $targets->{$^N} = [] })/;
|
||||
/I_T nexus: (\d+)(?{ $sid = $^N })/;
|
||||
/Connection: (\d+)(?{ push @{$tgt}, [ $sid, $^N ] })/;
|
||||
}
|
||||
}
|
||||
|
||||
my $hostname;
|
||||
die unless $hostname = `hostname`;
|
||||
chomp $hostname;
|
||||
|
||||
my $target = 'iqn.' . join('.', reverse split('\.', $hostname)) . ":$cow";
|
||||
|
||||
# find the target id corresponding to the provided target name and
|
||||
# close any existing connections to it
|
||||
my $tid = 0;
|
||||
foreach (@targets) {
|
||||
next unless /^Target (\d+)(?{ $tid = $^N }): $target$/m;
|
||||
foreach (@{$targets->{$tid}}) {
|
||||
die unless system("$tgtadm --op delete --mode conn --tid $tid --sid $_->[0] --cid $_->[1]") == 0;
|
||||
}
|
||||
}
|
||||
|
||||
# create a new target if an existing one was not found
|
||||
if ($tid == 0) {
|
||||
# find an available target id
|
||||
my @ids = (0, sort keys %{$targets});
|
||||
$tid = 1; while ($ids[$tid]==$tid) { $tid++ }
|
||||
|
||||
# create the target
|
||||
die unless -e "$dev";
|
||||
die unless system("$tgtadm --op new --mode target --tid $tid --targetname $target") == 0;
|
||||
die unless system("$tgtadm --op new --mode logicalunit --tid $tid --lun 1 --backing-store $dev") == 0;
|
||||
die unless system("$tgtadm --op bind --mode target --tid $tid --initiator-address ALL") == 0;
|
||||
}
|
||||
|
||||
# (re)set the provided target's chap password
|
||||
my $password = join('', map(chr(int(rand(26))+65), 1..8));
|
||||
my $accounts = `$tgtadm --op show --mode account`;
|
||||
if ($accounts =~ / $username$/m) {
|
||||
die unless system("$tgtadm --op delete --mode account --user $username") == 0;
|
||||
}
|
||||
die unless system("$tgtadm --op new --mode account --user $username --password $password") == 0;
|
||||
die unless system("$tgtadm --op bind --mode account --tid $tid --user $username") == 0;
|
||||
|
||||
# return the new password to the iscsi target on stdout
|
||||
print RETURN $password;
|
||||
END
|
||||
# chmod +x $MY_MOJO/scripts/mktgt
|
||||
```
|
||||
|
||||
上面的脚本将做以下五件事情:
|
||||
|
||||
1. 创建 `/<instance>.cow/<username>` 稀疏文件(如果不存在的话)。
|
||||
2. 创建 `/dev/mapper/<instance>-<username>` 设备节点作为 iSCSI 目标的写时复制支持存储(如果不存在的话)。
|
||||
3. 创建 `iqn.<reverse-hostname>:<instance>-<username>` iSCSI 目标(如果不存在的话)。或者,如果已存在了,它将关闭任何已存在的连接,因为在任何时刻,镜像只能以只读模式从一个地方打开。
|
||||
4. 它在 `iqn.<reverse-hostname>:<instance>-<username>` iSCSI 目标上(重新)设置 chap 密码为一个新的随机值。
|
||||
5. (如果前面的所有任务都成功的话)它在 [标准输出][5] 上显示新的 chap 密码。
|
||||
|
||||
你应该可以在命令行上通过使用有效的测试参数来运行它,以测试 `mktgt` 脚本能否正常工作。例如:
|
||||
|
||||
```
|
||||
# echo `$MY_MOJO/scripts/mktgt fc29 jsmith`
|
||||
```
|
||||
|
||||
当你从命令行上运行时,`mktgt` 脚本应该会输出 iSCSI 目标的一个随意的八字符随机密码(如果成功的话)或者是出错位置的行号(如果失败的话)。
|
||||
|
||||
有时候,你可能需要在不停止整个服务的情况下删除一个 iSCSI 目标。例如,一个用户可能无意中损坏了他的个人镜像,在那种情况下,你可能需要按步骤撤销上面的 `mktgt` 脚本所做的事情,以便于他下次登入时他将得到一个原始镜像。
|
||||
|
||||
下面是用于撤销的 `rmtgt` 脚本,它以相反的顺序做了上面 `mktgt` 脚本所做的事情:
|
||||
|
||||
```
|
||||
# mkdir $HOME/bin
|
||||
# cat << 'END' > $HOME/bin/rmtgt
|
||||
#!/usr/bin/env perl
|
||||
|
||||
@ARGV >= 2 or die "usage: $0 <instance> <username> [+d|+f]\n";
|
||||
|
||||
my $instance = shift;
|
||||
my $username = shift;
|
||||
|
||||
my $rmd = ($ARGV[0] eq '+d'); #remove device node if +d flag is set
|
||||
my $rmf = ($ARGV[0] eq '+f'); #remove sparse file if +f flag is set
|
||||
my $cow = "$instance-$username";
|
||||
|
||||
my $hostname;
|
||||
die unless $hostname = `hostname`;
|
||||
chomp $hostname;
|
||||
|
||||
my $tgtadm = '/usr/sbin/tgtadm';
|
||||
my $target = 'iqn.' . join('.', reverse split('\.', $hostname)) . ":$cow";
|
||||
|
||||
my $text = `$tgtadm --op show --mode target`;
|
||||
my @targets = $text =~ /(?:^T.*\n)(?:^ .*\n)*/mg;
|
||||
|
||||
my $targets = {};
|
||||
foreach (@targets) {
|
||||
my $tgt;
|
||||
my $sid;
|
||||
|
||||
foreach (split /\n/) {
|
||||
/^Target (\d+)(?{ $tgt = $targets->{$^N} = [] })/;
|
||||
/I_T nexus: (\d+)(?{ $sid = $^N })/;
|
||||
/Connection: (\d+)(?{ push @{$tgt}, [ $sid, $^N ] })/;
|
||||
}
|
||||
}
|
||||
|
||||
my $tid = 0;
|
||||
foreach (@targets) {
|
||||
next unless /^Target (\d+)(?{ $tid = $^N }): $target$/m;
|
||||
foreach (@{$targets->{$tid}}) {
|
||||
die unless system("$tgtadm --op delete --mode conn --tid $tid --sid $_->[0] --cid $_->[1]") == 0;
|
||||
}
|
||||
die unless system("$tgtadm --op delete --mode target --tid $tid") == 0;
|
||||
print "target $tid deleted\n";
|
||||
sleep 1;
|
||||
}
|
||||
|
||||
my $dev = "/dev/mapper/$cow";
|
||||
if ($rmd or ($rmf and -e $dev)) {
|
||||
die unless system("dmsetup remove $cow") == 0;
|
||||
print "device node $dev deleted\n";
|
||||
}
|
||||
|
||||
if ($rmf) {
|
||||
my $sf = "/$instance.cow/$username";
|
||||
die "sparse file $sf not found" unless -e "$sf";
|
||||
die unless system("rm -f $sf") == 0;
|
||||
die unless not -e "$sf";
|
||||
print "sparse file $sf deleted\n";
|
||||
}
|
||||
END
|
||||
# chmod +x $HOME/bin/rmtgt
|
||||
```
|
||||
|
||||
例如,使用上面的脚本去完全删除 fc29-jsmith 目标,包含它的支持存储设备节点和稀疏文件,可以按下列方式运行命令:
|
||||
|
||||
```
|
||||
# rmtgt fc29 jsmith +f
|
||||
```
|
||||
|
||||
一旦你验证 `mktgt` 脚本工作正常,你可以重启动 bootmenu 服务。下次有人从网络引导时,他们应该能够接收到一个他们可以写入的、可”私人定制“的网络引导镜像的副本:
|
||||
|
||||
```
|
||||
# systemctl restart bootmenu.service
|
||||
```
|
||||
|
||||
现在,就像下面的截屏示范的那样,用户应该可以修改根文件系统了:
|
||||
|
||||
![][6]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/how-to-build-a-netboot-server-part-4/
|
||||
|
||||
作者:[Gregory Bartholomew][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/glb/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: http://ipxe.org/crypto
|
||||
[2]: https://en.wikipedia.org/wiki/Copy-on-write
|
||||
[3]: https://en.wikipedia.org/wiki/Challenge-Handshake_Authentication_Protocol
|
||||
[4]: https://en.wikipedia.org/wiki/String_interpolation
|
||||
[5]: https://en.wikipedia.org/wiki/Standard_streams
|
||||
[6]: https://fedoramagazine.org/wp-content/uploads/2018/11/netboot-fix-pam_mount-1024x819.png
|
||||
@@ -0,0 +1,114 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (jrglinux)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10493-1.html)
|
||||
[#]: subject: (Turn a Raspberry Pi 3B+ into a PriTunl VPN)
|
||||
[#]: via: (https://opensource.com/article/19/1/pritunl-vpn-raspberry-pi)
|
||||
[#]: author: (Stephen Bancroft https://opensource.com/users/stevereaver)
|
||||
|
||||
将树莓派 3B+ 变为 PriTunl VPN
|
||||
======
|
||||
|
||||
> PriTunl 是一种 VPN 解决方案,适用于希望私密的访问其网络的小型企业和个人。
|
||||
|
||||

|
||||
|
||||
[PriTunl][1] 是一款出色的 VPN 终端解决方案,非常适合希望以简单快捷的方式私密的访问网络的小型企业和个人。它是开源的,基本的免费版本涵盖最通用的简单的实例,足以让你快速入门。也有集成了活动目录等高级功能的付费企业版。
|
||||
|
||||
### 有关树莓派 3B+ 的特别注意事项
|
||||
|
||||
PriTunl 的安装通常也很简单,但要在树莓派 3B+ 上安装 PriTunl 有点小复杂。比如,PriTunl 只提供了 AMD64 和 i386 架构的二进制文件,但树莓派 3B+ 是 ARM 架构的,这意味着需要从源码自行编译可用于树莓派 3B+ 的 PriTunl 可执行文件。不过,无需担心,编译过程很简单,只需花一点时间执行几行命令即可。
|
||||
|
||||
另一个问题:PriTunl 好像必须要是 64 位处理器架构,当我在 32 位操作系统上尝试编译的时候报错了。但幸运的是,用于 ARM64 架构的 Ubuntu 18.04 测试版本可以安装在树莓派 3B+ 上。
|
||||
|
||||
同样,树莓派 3B+ 需要和其他树莓派不同的引导程序。需要一组小复杂的命令来安装更新树莓派 3B+ 上必要的组件。
|
||||
|
||||
### 安装 PriTunl
|
||||
|
||||
你可以先在树莓派 3B+ 上安装 64 位的操作系统来避免下面这些问题。此处需要一些必要的基础知识如在树莓派上执行命令行。
|
||||
|
||||
打开终端,用如下命令下载 Ubuntu 18.04 用于 ARM64 架构的测试版:
|
||||
|
||||
```
|
||||
$ wget http://cdimage.ubuntu.com/releases/18.04/beta/ubuntu-18.04-beta-preinstalled-server-arm64+raspi3.img.xz
|
||||
```
|
||||
|
||||
将下载的固件解压:
|
||||
|
||||
```
|
||||
$ xz -d ubuntu-18.04-beta-preinstalled-server-arm64+raspi3.xz
|
||||
```
|
||||
|
||||
将准备好的 SD 卡插入电脑读卡槽,电脑会为 SD 卡分配一个驱动分配器号,例如 `/dev/sda` 或者 `/dev/sdb`。 输入命令 `dmesg` 然后观察屏幕上的最后几行找到 SD 卡的驱动分配器。
|
||||
|
||||
**下一步小心操作,如果搞错了驱动分配器号,可能会破坏你的系统。**
|
||||
|
||||
用如下命令往 SD 卡中写入数据,将其中的 `<DRIVE>` 替换成你的 SD 驱动器号。
|
||||
|
||||
```
|
||||
$ dd if=ubuntu-18.04-beta-preinstalled-server-arm64+raspi3.img of=<DRIVE> bs=8M
|
||||
```
|
||||
|
||||
完成上一步之后,将 SD 卡插入树莓派 3B+ ,并启动它。确保树莓派 3B+ 是连网的,然后登录系统,用户名/密码:`ubuntu` / `ubuntu`。
|
||||
|
||||
在树莓派上输入以下命令以安装一些编译 PriTunl 所需的包:
|
||||
|
||||
```
|
||||
$ sudo apt-get -y install build-essential git bzr python python-dev python-pip net-tools openvpn bridge-utils psmisc golang-go libffi-dev mongodb
|
||||
```
|
||||
|
||||
和 PriTunl 标准源码上的 [安装说明][2] 有一点不一样。确保已经登录进树莓派然后切换到管理员账户:
|
||||
|
||||
```
|
||||
$ sudo su -
|
||||
```
|
||||
|
||||
现在你应该在管理员账户的目录下,按如下命令来安装 PriTunl 1.29.1914.98 版本:
|
||||
|
||||
```
|
||||
export VERSION=1.29.1914.98
|
||||
tee -a ~/.bashrc << EOF
|
||||
export GOPATH=\$HOME/go
|
||||
export PATH=/usr/local/go/bin:\$PATH
|
||||
EOF
|
||||
source ~/.bashrc
|
||||
mkdir pritunl && cd pritunl
|
||||
go get -u github.com/pritunl/pritunl-dns
|
||||
go get -u github.com/pritunl/pritunl-web
|
||||
sudo ln -s ~/go/bin/pritunl-dns /usr/bin/pritunl-dns
|
||||
sudo ln -s ~/go/bin/pritunl-web /usr/bin/pritunl-web
|
||||
wget https://github.com/pritunl/pritunl/archive/$VERSION.tar.gz
|
||||
tar -xf $VERSION.tar.gz
|
||||
cd pritunl-$VERSION
|
||||
python2 setup.py build
|
||||
pip install -r requirements.txt
|
||||
python2 setup.py install --prefix=/usr/local
|
||||
```
|
||||
|
||||
现在,不出意外的话应该可以启动 MongoDB 和 PriTunl 的 systemd 单元了。假如现在还是以管理员账户登录的话,输入:
|
||||
|
||||
```
|
||||
systemctl daemon-reload
|
||||
systemctl start mongodb pritunl
|
||||
systemctl enable mongodb pritunl
|
||||
```
|
||||
|
||||
大功告成!你现在可以登录 PriTunl 的用户界面并按照官网上的 [安装和配置手册][3] 来配置它了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/1/pritunl-vpn-raspberry-pi
|
||||
|
||||
作者:[Stephen Bancroft][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[jrg](https://github.com/jrglinux)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/stevereaver
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://pritunl.com/
|
||||
[2]: https://github.com/pritunl/pritunl
|
||||
[3]: https://docs.pritunl.com/docs/configuration-5
|
||||
@@ -0,0 +1,82 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (beamrolling)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10469-1.html)
|
||||
[#]: subject: (You (probably) don't need Kubernetes)
|
||||
[#]: via: (https://arp242.net/weblog/dont-need-k8s.html)
|
||||
[#]: author: (Martin Tournoij https://arp242.net/)
|
||||
|
||||
你(多半)不需要 Kubernetes
|
||||
======
|
||||
|
||||
这也许是一个不太受欢迎的观点,但大多数主流公司最好不要再使用 k8s 了。
|
||||
|
||||
你知道那个古老的“以程序员技能写 Hello world ”笑话吗?—— 从一个新手程序员的 `printf("hello, world\n")` 语句开始,最后结束于高级软件架构工程师令人费解的 Java OOP 模式设计。使用 k8s 就有点像这样。
|
||||
|
||||
* 新手系统管理员:
|
||||
|
||||
`./binary`
|
||||
* 有经验的系统管理员:
|
||||
|
||||
在 EC2 上的 `./binary`
|
||||
* DevOp:
|
||||
|
||||
在 EC2 上自部署的 CI 管道运行 `./binary`
|
||||
* 高级云编排工程师:
|
||||
|
||||
在 EC2 上通过 k8s 编排的自部署 CI 管道运行 `./binary`
|
||||
|
||||
`¯\\_(ツ)_/¯`
|
||||
|
||||
这不意味着 Kubernetes 或者任何这样的东西本身都是*坏的*,就像 Java 或者 OOP 设计本身并不是坏的一样,但是,在很多情况下,它们被严重地误用,就像在一个 hello world 的程序中可怕地误用 Java 面向对象设计模式一样。对大多数公司而言,系统运维从根本上来说并不十分复杂,此时在这上面应用 k8s 起效甚微。
|
||||
|
||||
复杂性本质上来说创造了工作,我十分怀疑使用 k8s 对大多数使用者来说是省时的这一说法。这就好像花一天时间来写一个脚本,用来自动完成一些你一个月进行一次,每次只花 10 分钟完成的工作。这不是一个好的时间投资(特别是你可能会在未来由于扩展或调试这个脚本而进一步投入的更多时间)。
|
||||
|
||||
你的部署大概应该*需要*自动化 – 以免你 [最终像 Knightmare][1] 那样 —— 但 k8s 通常可以被一个简单的 shell 脚本所替代。
|
||||
|
||||
在我们公司,系统运维团队用了很多时间来设置 k8s 。他们还不得不用了很大一部分时间来更新到新一点的版本(1.6 ➙ 1.8)。结果是如果没有真正深入理解 k8s ,有些东西就没人会真的明白,甚至连深入理解 k8s 这一点也很难(那些 YAML 文件,哦呦!)
|
||||
|
||||
在我能自己调试和修复部署问题之前 —— 现在这更难了,我理解基本概念,但在真正调试实际问题的时候,它们并不是那么有用。我不经常用 k8s 足以证明这点。
|
||||
|
||||
---
|
||||
|
||||
k8s 真的很难这点并不是什么新看法,这也是为什么现在会有这么多 “k8s 简单用”的解决方案。在 k8s 上再添一层来“让它更简单”的方法让我觉得,呃,不明智。复杂性并没有消失,你只是把它藏起来了。
|
||||
|
||||
以前我说过很多次:在确定一样东西是否“简单”时,我最关心的不是写东西的时候有多简单,而是当失败的时候调试起来有多容易。包装 k8s 并不会让调试更加简单,恰恰相反,它让事情更加困难了。
|
||||
|
||||
---
|
||||
|
||||
Blaise Pascal 有一句名言:
|
||||
|
||||
> 几乎所有的痛苦都来自于我们不善于在房间里独处。
|
||||
|
||||
k8s —— 略微拓展一下,Docker —— 似乎就是这样的例子。许多人似乎迷失在当下的兴奋中,觉得 “k8s 就是这么回事!”,就像有些人迷失在 Java OOP 刚出来时的兴奋中一样,所以一切都必须从“旧”方法转为“新”方法,即使“旧”方法依然可行。
|
||||
|
||||
有时候 IT 产业挺蠢的。
|
||||
|
||||
或者用 [一条推特][2] 来总结:
|
||||
|
||||
> - 2014 - 我们必须采用 #微服务 来解决独石应用的所有问题
|
||||
> - 2016 - 我们必须采用 #docker 来解决微服务的所有问题
|
||||
> - 2018 - 我们必须采用 #kubernetes 来解决 docker 的所有问题
|
||||
|
||||
你可以通过 [martin@arp242.net][3] 给我发邮件或者 [创建 GitHub issue][4] 来给我反馈或提出问题等。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://arp242.net/weblog/dont-need-k8s.html
|
||||
|
||||
作者:[Martin Tournoij][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[beamrolling](https://github.com/beamrolling)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://arp242.net/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://dougseven.com/2014/04/17/knightmare-a-devops-cautionary-tale/
|
||||
[2]: https://twitter.com/sahrizv/status/1018184792611827712
|
||||
[3]: mailto:martin@arp242.net
|
||||
[4]: https://github.com/Carpetsmoker/arp242.net/issues/new
|
||||
185
published/201901/20190115 Linux Tools- The Meaning of Dot.md
Normal file
185
published/201901/20190115 Linux Tools- The Meaning of Dot.md
Normal file
@@ -0,0 +1,185 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (asche910)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10465-1.html)
|
||||
[#]: subject: (Linux Tools: The Meaning of Dot)
|
||||
[#]: via: (https://www.linux.com/blog/learn/2019/1/linux-tools-meaning-dot)
|
||||
[#]: author: (Paul Brown https://www.linux.com/users/bro66)
|
||||
|
||||
Linux 工具:点的含义
|
||||
======
|
||||
|
||||
> Paul Brown 解释了 Linux shell 命令中那个不起眼的“点”的各种意思和用法。
|
||||
|
||||

|
||||
|
||||
在现实情况中,使用 shell 命令编写的单行命令或脚本可能会令人很困惑。你使用的很多工具的名称与它们的实际功能相差甚远(`grep`、`tee` 和 `awk`,还有吗?),而当你将两个或更多个组合起来时,所组成的 “句子” 看起来更像某种外星人的天书。
|
||||
|
||||
因此,上面说的这些对于你并无帮助,因为你用来编写一连串的指令所使用的符号根据你使用的场景有着不同的意义。
|
||||
|
||||
### 位置、位置、位置
|
||||
|
||||
就拿这个不起眼的点(`.`)来说吧。当它放在一个需要一个目录名称的命令的参数处时,表示“当前目录”:
|
||||
|
||||
```
|
||||
find . -name "*.jpg"
|
||||
```
|
||||
|
||||
意思就是“在当前目录(包括子目录)中寻找以 `.jpg` 结尾的文件”。
|
||||
|
||||
`ls .` 和 `cd .` 结果也如你想的那样,它们分别列举和“进入”到当前目录,虽然在这两种情况下这个点都是多余的。
|
||||
|
||||
而一个紧接着另一个的两个点呢,在同样的场景下(即当你的命令期望一个文件目录的时候)表示“当前目录的父目录”。如果你当前在 `/home/your_directory` 下并且运行:
|
||||
|
||||
```
|
||||
cd ..
|
||||
```
|
||||
|
||||
你就会进入到 `/home`。所以,你可能认为这仍然适合“点代表附近目录”的叙述,并且毫不复杂,对吧?
|
||||
|
||||
那下面这样会怎样呢?如果你在一个文件或目录的开头加上点,它表示这个文件或目录会被隐藏:
|
||||
|
||||
```
|
||||
$ touch somedir/file01.txt somedir/file02.txt somedir/.secretfile.txt
|
||||
$ ls -l somedir/
|
||||
total 0
|
||||
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file01.txt
|
||||
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file02.txt
|
||||
$ # 注意上面列举的文件中没有 .secretfile.txt
|
||||
$ ls -la somedir/
|
||||
total 8
|
||||
drwxr-xr-x 2 paul paul 4096 Jan 13 19:57 .
|
||||
drwx------ 48 paul paul 4096 Jan 13 19:57 ..
|
||||
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file01.txt
|
||||
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 file02.txt
|
||||
-rw-r--r-- 1 paul paul 0 Jan 13 19:57 .secretfile.txt
|
||||
$ # 这个 -a 选项告诉 ls 去展示“all”文件,包括那些隐藏的
|
||||
```
|
||||
|
||||
然后就是你可以将 `.` 当作命令。是的,你听我说:`.` 是个真真正正的命令。它是 `source` 命令的代名词,所以你可以用它在当前 shell 中执行一个文件,而不是以某种其它的方式去运行一个脚本文件(这通常指的是 Bash 会产生一个新的 shell 去运行它)
|
||||
|
||||
很困惑?别担心 —— 试试这个:创建一个名为 `myscript` 的脚本,内容包含下面一行:
|
||||
|
||||
```
|
||||
myvar="Hello"
|
||||
```
|
||||
|
||||
然后通过常规的方法执行它,也就是用 `sh myscript`(或者通过 `chmod a+x myscript` 命令让它可执行,然后运行 `./myscript`)。现在尝试并且观察 `myvar` 的内容,通过 `echo $myvar`(理所当然你什么也得不到)。那是因为,当你的脚本赋值 `"Hello"` 给 `myvar` 时,它是在一个隔离的bash shell 实例中进行的。当脚本运行结束时,这个新产生的实例会消失并且将控制权转交给原来的shell,而原来的 shell 里甚至都不存在 `myvar` 变量。
|
||||
|
||||
然而,如果你这样运行 `myscript`:
|
||||
|
||||
```
|
||||
. myscript
|
||||
```
|
||||
|
||||
`echo $myvar` 就会打印 `Hello` 到命令行上。
|
||||
|
||||
当你的 `.bashrc` 文件发生变化后,你经常会用到 `.`(或 `source`)命令,[就像当你要扩展 `PATH` 变量那样][1]。在你的当前 shell 实例中,你可以使用 `.` 来让变化立即生效。
|
||||
|
||||
### 双重麻烦
|
||||
|
||||
就像看似无关紧要的一个点有多个含义一样,两个点也是如此。除了指向当前目录的父级之外,两个点(`..`)也用于构建序列。
|
||||
|
||||
尝试下这个:
|
||||
|
||||
```
|
||||
echo {1..10}
|
||||
```
|
||||
|
||||
它会打印出从 1 到 10 的序列。在这种场景下,`..` 表示 “从左边的值开始,计数到右边的值”。
|
||||
|
||||
现在试下这个:
|
||||
|
||||
```
|
||||
echo {1..10..2}
|
||||
```
|
||||
|
||||
你会得到 `1 3 5 7 9`。`..2` 这部分命令告诉 Bash 输出这个序列,不过不是每个相差 1,而是相差 2。换句话说,就是你会得到从 1 到 10 之间的奇数。
|
||||
|
||||
它反着也仍然有效:
|
||||
|
||||
```
|
||||
echo {10..1..2}
|
||||
```
|
||||
|
||||
你也可以用多个 0 填充你的数字。这样:
|
||||
|
||||
```
|
||||
echo {000..121..2}
|
||||
```
|
||||
|
||||
会这样打印出从 0 到 121 之间的偶数(填充了前置 0):
|
||||
|
||||
```
|
||||
000 002 004 006 ... 050 052 054 ... 116 118 120
|
||||
```
|
||||
|
||||
不过这样的序列发生器有啥用呢?当然,假设您的新年决心之一是更加谨慎控制您的帐户花销。作为决心的一部分,您需要创建目录,以便对过去 10 年的数字发票进行分类:
|
||||
|
||||
```
|
||||
mkdir {2009..2019}_Invoices
|
||||
```
|
||||
|
||||
工作完成。
|
||||
|
||||
或者你可能有数百个带编号的文件,比如从视频剪辑中提取的帧,或许因为某种原因,你只想从第 43 帧到第 61 帧每隔三帧删除一帧:
|
||||
|
||||
```
|
||||
rm frame_{043..61..3}
|
||||
```
|
||||
|
||||
很可能,如果你有超过 100 个帧,它们将以填充 0 命名,如下所示:
|
||||
|
||||
```
|
||||
frame_000 frame_001 frame_002 ...
|
||||
```
|
||||
|
||||
那就是为什么你在命令中要用 `043`,而不是`43` 的原因。
|
||||
|
||||
### 花括号花招
|
||||
|
||||
说实话,序列的神奇之处不在于双点,而是花括号(`{}`)的巫术。看看它对于字母是如何工作的。这样做:
|
||||
|
||||
```
|
||||
touch file_{a..z}.txt
|
||||
```
|
||||
|
||||
它创建了从 `file_a.txt` 到 `file_z.txt` 的文件。
|
||||
|
||||
但是,你必须小心。使用像 `{Z..a}` 这样的序列将产生一大堆大写字母和小写字母之间的非字母、数字的字符(既不是数字或字母的字形)。其中一些字形是不可打印的或具有自己的特殊含义。使用它们来生成文件名称可能会导致一系列意外和可能令人不快的影响。
|
||||
|
||||
最后一件值得指出的事:包围在 `{...}` 的序列,它们也可以包含字符串列表:
|
||||
|
||||
```
|
||||
touch {blahg, splurg, mmmf}_file.txt
|
||||
```
|
||||
|
||||
将创建了 `blahg_file.txt`、`splurg_file.txt` 和 `mmmf_file.txt`。
|
||||
|
||||
当然,在别的场景中,大括号也有不同的含义(惊喜吗!)。不过那是别的文章的内容了。
|
||||
|
||||
### 总结
|
||||
|
||||
Bash 以及运行于其中的各种工具已经被寻求解决各种特定问题的系统管理员们把玩了数十年。要说这种有自己之道的系统管理员是一种特殊物种的话,那是有点轻描淡写。总而言之,与其他语言相反,Bash 的设计目标并不是为了用户友好、简单、甚至合乎逻辑。
|
||||
|
||||
但这并不意味着它不强大 —— 恰恰相反。Bash 的语法和 shell 工具可能不一致且很庞大,但它们也提供了一系列令人眼花缭乱的方法来完成您可能想象到的一切。就像有一个工具箱,你可以从中找到从电钻到勺子的所有东西,以及橡皮鸭、一卷胶带和一些指甲钳。
|
||||
|
||||
除了引人入胜之外,探明你可以直接在 shell 中达成的所有能力也很有趣,所以下次我们将深入探讨如何构建更大更好的 Bash 命令行。
|
||||
|
||||
在那之前,玩得开心!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/2019/1/linux-tools-meaning-dot
|
||||
|
||||
作者:[Paul Brown][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[asche910](https://github.com/asche910)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linux.com/users/bro66
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.linux.com/blog/learn/2018/12/bash-variables-environmental-and-otherwise
|
||||
@@ -0,0 +1,91 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10484-1.html)
|
||||
[#]: subject: (Get started with WTF, a dashboard for the terminal)
|
||||
[#]: via: (https://opensource.com/article/19/1/wtf-information-dashboard)
|
||||
[#]: author: (Kevein Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
开始使用 WTF 吧,一款终端仪表板
|
||||
======
|
||||
|
||||
> 使用 WTF 将关键信息置于视野之中,这个系列中第六个开源工具可使你在 2019 年更有工作效率。
|
||||
|
||||

|
||||
|
||||
每年年初似乎都有疯狂的冲动想提高工作效率。新年的决心,渴望开启新的一年,当然,“抛弃旧的,拥抱新的”的态度促成了这一切。通常这时的建议严重偏向闭源和专有软件,但事实上并不用这样。
|
||||
|
||||
这是我挑选出的 19 个新的(或者对你而言新的)开源项目来帮助你在 2019 年更有效率。
|
||||
|
||||
### WTF
|
||||
|
||||
曾几何时,我在一家使用[彭博终端][1]的公司做咨询。我的反应是,“哇,在一个屏幕上显示的信息太多了。” 然而,现在,当我正在工作并且打开多个网页、仪表板和控制台应用程序以试图跟踪事物时,我似乎无法在屏幕上获得足够的信息。
|
||||
|
||||
虽然 [tmux][2] 和 [Screen][3] 可以进行分屏和打开多个窗口,但它们很难设置,并且它们的键绑定可能需要一段时间才能学会(还经常与其他应用程序冲突)。
|
||||
|
||||
[WTF][4] 是一个简单的、易于配置的终端信息仪表板。它是用 [Go][5] 语言编写的,使用 YAML 配置文件,可以从几个不同的源提取数据。所有的数据源都包含在[模块][6]中,包括天气、问题跟踪器、日期和时间、Google 表格以及更多内容。有些窗格是交互式的,有些窗格只是使用最新的信息进行更新。
|
||||
|
||||
安装它就像下载适用于您的操作系统的最新版本并运行命令一样简单。因为它是用 Go 编写的,所以它的移植性很好,应该可以在任何可以编译它的地方运行(尽管开发人员目前只为 Linux 和 MacOS 做了构建)。
|
||||
|
||||

|
||||
|
||||
当您第一次运行 WTF 时,您将看到如上图的默认屏幕。
|
||||
|
||||

|
||||
|
||||
其默认配置文件在 `~/.wtf/config.yml`,您可以编辑该文件以满足您的需要。网格布局的配置在文件的顶部。
|
||||
|
||||
```
|
||||
grid:
|
||||
columns: [45, 45]
|
||||
rows: [7, 7, 7, 4]
|
||||
```
|
||||
|
||||
网格设置中的数字表示每个块的字符尺寸。默认配置是两列,每列 40 个字符,两行 13 个字符高,一行 4 个字符高。在上面的代码中,我使列更宽(`45,45`),行更小,并添加了第四行,所以我可以放更多的小部件。
|
||||
|
||||

|
||||
|
||||
我喜欢在仪表板上看到当天的天气。有两个天气模块可供选择:[Weather][7],它只显示文本信息;[Pretty Weather][8] 则色彩丰富,并使用基于文本的图形显示。
|
||||
|
||||
```
|
||||
prettyweather:
|
||||
enabled: true
|
||||
position:
|
||||
top: 0
|
||||
left: 1
|
||||
height: 2
|
||||
width: 1
|
||||
```
|
||||
|
||||
此代码创建了一个窗格,高为两个块(`height: 2`),宽为一个块(`width: 1`),位于顶行(`top: 0`)的第二列(`left: 1`)上,包含 Pretty Weather 模块.
|
||||
|
||||
一些模块是交互式的,如 Jira、GitHub 和 Todo,您可以在其中滚动、更新和保存信息。您可以使用 Tab 键在交互式窗格之间移动。`\` 键会显示活动窗格的帮助屏幕,以便您可以查看可以执行的操作以及操作方式。Todo 模块允许您添加、编辑和删除待办事项,并在完成后勾掉它们。
|
||||
|
||||

|
||||
|
||||
还有一些模块可以执行命令并显示输出、监视文本文件,以及监视构建和集成服务器的输出。所有文档都做得很好。
|
||||
|
||||
对于需要在不同来源的一个屏幕上查看大量数据的人来说,WTF 是一个有价值的工具。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/1/wtf-information-dashboard
|
||||
|
||||
作者:[Kevein Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://en.wikipedia.org/wiki/Bloomberg_Terminal
|
||||
[2]: https://github.com/tmux/tmux
|
||||
[3]: https://www.gnu.org/software/screen/
|
||||
[4]: https://wtfutil.com/
|
||||
[5]: https://golang.org/
|
||||
[6]: https://wtfutil.com/posts/modules/
|
||||
[7]: https://wtfutil.com/posts/modules/weather/
|
||||
[8]: https://wtfutil.com/posts/modules/prettyweather/
|
||||
190
published/201901/20190118 Top 5 Linux Server Distributions.md
Normal file
190
published/201901/20190118 Top 5 Linux Server Distributions.md
Normal file
@@ -0,0 +1,190 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10490-1.html)
|
||||
[#]: subject: (Top 5 Linux Server Distributions)
|
||||
[#]: via: (https://www.linux.com/blog/learn/2019/1/top-5-linux-server-distributions)
|
||||
[#]: author: (Jack Wallen https://www.linux.com/users/jlwallen)
|
||||
|
||||
5 个用于 SOHO 的 Linux 服务器发行版
|
||||
======
|
||||
|
||||
> Jack Wallen 为 Linux 服务器发行版提供了一些可靠的选择,绝对值回票价。
|
||||
|
||||

|
||||
|
||||
啊,这个古老的问题:哪种 Linux 发行版最适合做服务器?通常,问这种问题时,所浮现出来的标准的答复就是:
|
||||
|
||||
* RHEL
|
||||
* SUSE
|
||||
* Ubuntu 服务器
|
||||
* Debian
|
||||
* CentOS
|
||||
|
||||
然而,假如你将眼界放得更宽(不将服务器只看做是 IDC 托管的那种互联网服务器时),可能答案会有点不同。我准备稍微来点不同的。我想做出一个满足入选标准的发行版列表,这些发行版不仅是优秀的候选者,而且易于使用,可以为你的业务中的许多功能提供服务。在某些情况下,我选择的是一些替代品,可以取代其它需要一些工作才能达成要求的操作系统。
|
||||
|
||||
我的一些选择是企业级服务器的社区版本,它们可以被视为购买更强大平台的入门级产品。你甚至可以在这里找到一两个作为特定任务平台的候选者。然而,最重要的是,你在此列表中找到的并非寻常的泛泛之辈。
|
||||
|
||||
### ClearOS
|
||||
|
||||
什么是 ClearOS?对于家庭和小型企业用途,你可能找不到比它更好的解决方案。ClearOS 开箱即用,包括了入侵检测、强大的防火墙、带宽管理工具、邮件服务器、域控制器等工具。其目的是将服务器作为一个简单的家庭和 SOHO 服务器,并具有用户友好的基于 Web 的图形化界面,这使得 ClearOS 在某些评比中脱颖而出。从其界面中,你可以找到一个应用程序市场(图 1),其中包含数百个应用程序(其中一些是免费的,而另一些则具有相关费用),这使得扩展 ClearOS 功能集非常容易。换句话说,你可以将 ClearOS 作为你的家庭和小型企业所需的平台。最重要的是,与许多其他替代方案不同,你只需支付所需的软件和支持。
|
||||
|
||||

|
||||
|
||||
*图 1:ClearOS 应用程序市场*
|
||||
|
||||
有三种版本的 ClearOS:
|
||||
|
||||
* [ClearOS Community][1] - 免费版 ClearOS
|
||||
* [ClearOS Home][2] - 适于家庭办公
|
||||
* [ClearOS Business][3] - 适于小型企业,包括了付费支持。
|
||||
|
||||
为了使软件安装更加容易,ClearOS 应用市场允许你通过以下方式进行选择软件:
|
||||
|
||||
* 按功能(根据任务显示应用程序)
|
||||
* 按类别(显示相关应用程序组)
|
||||
* 快速选择文件(允许你按预先配置的模板选择,以帮助你快速启动和运行)
|
||||
|
||||
换句话说,如果你正在寻找 Linux 的家庭、SOHO 或 SMB 服务器,ClearOS 是一个出色的选择(特别是如果你没有启动和运行标准的 Linux 服务器的能力时)。
|
||||
|
||||
### Fedora 服务器
|
||||
|
||||
你肯定听说过 Fedora Linux。它是市场上最好的前沿发行版之一。但是你知道这个出色的 Fedora 桌面发行版的开发者们也开发了服务器版吗?Fedora 服务器平台是一个短生命周期的、社区支持的服务器操作系统。这使得经验丰富的、或对任何类型的 Linux(或任何操作系统)有经验的系统管理员,可以使用开源社区中提供的最新技术。在这段描述中有三个关键词:
|
||||
|
||||
* 经验丰富
|
||||
* 系统
|
||||
* 管理员
|
||||
|
||||
换言之,新用户就不要考虑了。虽然 Fedora 服务器完全能够处理你抛出的任何任务,但它需要一些拥有更多的 Linux 功夫的人来使它工作并且运行良好。Fedora 服务器非常好的一点是,开箱即用,它包括了市场上用于服务器的开源的基于 Web 的最好的界面之一。通过 Cockpit(图 2),你可以快速浏览系统资源、日志、存储、网络以及拥有管理帐户、服务、应用程序和更新的能力。
|
||||
|
||||
![Fedora Server][5]
|
||||
|
||||
*图 2:运行在 Fedora 服务器上的 Cockpit*
|
||||
|
||||
如果你可以使用最前沿的软件,并想要一个出色的管理仪表板,Fedora 服务器可能就是你要的平台。
|
||||
|
||||
### NethServer
|
||||
|
||||
正如你所发现的那样,NethServer 是每个人都知道的简单 SMB Linux 服务器。通过 NethServer 的最新版本,你的小型企业将得到:
|
||||
|
||||
* 内置 Samba 活动目录控制器
|
||||
* 与 Nextcloud 的无缝集成
|
||||
* 证书管理
|
||||
* HTTPS 透明代理
|
||||
* 防火墙
|
||||
* 邮件服务器和过滤器
|
||||
* Web 服务器和过滤器
|
||||
* 群件
|
||||
* IPS / IDS 或 VPN
|
||||
|
||||
所有包含的功能都可以通过用户友好的基于 Web 的界面轻松配置,包括单击安装模块以扩展 NethServer 功能集(图 3)。NethServer 与 ClearOS 的区别在于它的设计目的是使管理工作更轻松。换句话说,这个平台提供了更多的灵活性和功能。与面向家庭办公室和 SOHO 部署的 ClearOS 不同,NethServer 在小型商业环境中用起来就像在家庭里使用一样方便。
|
||||
|
||||
![NethServer][8]
|
||||
|
||||
*图 3:给 NethServer 添加模块*
|
||||
|
||||
### Rockstor
|
||||
|
||||
Rockstor 是采用 Linux 和 Btfrs 的高级网络附加存储(NAS)和云存储服务器,可部署用于家庭、SOHO 以及中小型企业。借助 Rockstor,你可以获得一个完整的 NAS /云解决方案,其中包含一个用户友好的基于 Web 的 GUI 工具,管理员可以像普通用户一样轻松使用它来设置。一旦部署好了 Rockstor,你就可以创建存储池、共享、快照、管理复制和用户、共享文件(借助 Samba、NFS、SFTP 和 AFP),甚至扩展它的功能集,这要归功于附加组件(称为 Rock-ons)。Rock-ons 列表包括:
|
||||
|
||||
* CouchPotato(Usenet 和 BitTorrent 用户的下载器)
|
||||
* Deluge(BitTorrent 用户的电影下载器)
|
||||
* EmbyServer(Emby 媒体服务器)
|
||||
* Ghost(专业博主的发布平台)
|
||||
* GitLab CE(Git 仓库托管和协作)
|
||||
* Gogs Go Git Service(轻量级 Git 版本控制服务器和前端)
|
||||
* Headphones(NZB 和 Torrent 的音乐自动下载器)
|
||||
* 用于 Squeezebox 设备的罗技 Squeezebox 服务器
|
||||
* MariaDB(关系型数据管理系统)
|
||||
* NZBGet(高效的 usenet 下载器)
|
||||
* OwnCloud-Official(安全的文件共享和托管)
|
||||
* Plexpy(基于 Python 的 Plex 用量跟踪器)
|
||||
* Rocket.Chat(开源聊天平台)
|
||||
* SaBnzbd(Usenet 下载器)
|
||||
* Sickbeard(用于电视节目的互联网个人视频录像机)
|
||||
* Sickrage(电视节目的自动视频库管理器)
|
||||
* Sonarr(Usenet 和 BitTorrent 用户的个人视频录像机)
|
||||
* Symform(备份设备)
|
||||
|
||||
Rockstor 还包括了一目了然的仪表板,使管理员可以快速访问他们所需的有关其服务器的所有信息(图 4)。
|
||||
|
||||
![Rockstor][10]
|
||||
|
||||
*图 4: Rockstor 面板*
|
||||
|
||||
### Zentyal
|
||||
|
||||
Zentyal 是另一个小型企业服务器,可以很好地处理多个任务。如果你正在寻找可以处理以下内容的 Linux 发行版:
|
||||
|
||||
* 目录和域服务器
|
||||
* 邮件服务器
|
||||
* 网关
|
||||
* DHCP、DNS 和 NTP 服务器
|
||||
* 认证机构(CA)
|
||||
* VPN
|
||||
* 实时消息(IM)
|
||||
* FTP 服务器
|
||||
* 反病毒
|
||||
* SSO 认证
|
||||
* 文件共享
|
||||
* RADIUS 认证
|
||||
* 虚拟化管理
|
||||
* 等等
|
||||
|
||||
Zentyal 可能是你的新选择。从 2004 年 Zentyal 就存在了,它基于 Ubuntu Server,因此它拥有坚实的基础和丰富的应用程序。在 Zentyal 仪表板的帮助下(图 5),管理员可以轻松管理:
|
||||
|
||||
* 系统
|
||||
* 网络
|
||||
* 日志
|
||||
* 软件更新和安装
|
||||
* 用户/组
|
||||
* 域
|
||||
* 文件共享
|
||||
* 邮件
|
||||
* DNS
|
||||
* 防火墙
|
||||
* 证书
|
||||
* 等等
|
||||
|
||||

|
||||
|
||||
*图 5:Zentyal 仪表板*
|
||||
|
||||
向 Zentyal 服务器添加新组件只需要打开仪表板,单击“软件管理” -> “Zentyal 组件”,选择要添加的组件,然后单击安装。Zentyal 可能会遇到的一个问题是,它提供不了与 Nethserver 和 ClearOS 一样多的插件。但它提供的服务,则做得非常好。
|
||||
|
||||
### 更多来自于
|
||||
|
||||
这个 Linux 服务器列表显然不是详尽无遗的。然而,这是一种对你可能没有听说过的五大服务器发行版的独特视角。当然,如果你更愿意使用更传统的 Linux 服务器发行版,你可以随时坚持使用 [CentOS][11]、[Ubuntu 服务器][12]、[SUSE][13]、[RHEL][14] 或 [Debian][15]……它们大多都出现在市场上最好的服务器发行版列表中。但是,如果你正在寻找一些不同的东西,那么试试这五个发行版中的一个。
|
||||
|
||||
通过 Linux 基金会和 edX 的免费[“Linux 简介”][16]课程了解有关 Linux 的更多信息。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/2019/1/top-5-linux-server-distributions
|
||||
|
||||
作者:[Jack Wallen][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linux.com/users/jlwallen
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.clearos.com/clearfoundation/software/clearos-7-community
|
||||
[2]: https://www.clearos.com/products/clearos-editions/clearos-7-home
|
||||
[3]: https://www.clearos.com/products/clearos-editions/clearos-7-business
|
||||
[4]: https://www.linux.com/files/images/fedoraserverjpg
|
||||
[5]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/fedoraserver.jpg?itok=phaAIRXW (Fedora Server)
|
||||
[6]: https://www.linux.com/licenses/category/used-permission
|
||||
[7]: https://www.linux.com/files/images/nethserverjpg
|
||||
[8]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/nethserver.jpg?itok=HO-CRbOV (NethServer)
|
||||
[9]: https://www.linux.com/files/images/rockstorejpg
|
||||
[10]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/rockstore.jpg?itok=EN_5oFxQ (Rockstor)
|
||||
[11]: https://www.centos.org/
|
||||
[12]: https://www.ubuntu.com/download/server
|
||||
[13]: https://www.suse.com/
|
||||
[14]: https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux
|
||||
[15]: https://www.debian.org/
|
||||
[16]: https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
||||
@@ -0,0 +1,61 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10494-1.html)
|
||||
[#]: subject: (Getting started with Isotope, an open source webmail client)
|
||||
[#]: via: (https://opensource.com/article/19/1/productivity-tool-isotope)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney (Kevin Sonney))
|
||||
|
||||
开始使用 Isotope 吧,一款开源的 Web 邮件客户端
|
||||
======
|
||||
|
||||
> 使用轻量级的电子邮件客户端 Isotope 阅读富文本电子邮件,这个开源工具系列的第十一个工具将使你在 2019 年更高效。
|
||||
|
||||

|
||||
|
||||
在每年的年初,似乎都有一股疯狂的寻找提高工作效率方法的冲动。新年决心,渴望以正确的方式开始新的一年。当然,“旧不去的,新的不来”的态度都会导致这种情况。一般的建议都偏向于闭源和专有软件,然而并不是必须这样。
|
||||
|
||||
以下是我挑选的 19 个新的(或者对你来说是新的)开源工具中的第 11 个,它将帮助你在 2019 年提高工作效率。
|
||||
|
||||
### Isotope
|
||||
|
||||
正如我们在[本系列的第四篇文章][1](Cypht)中所讨论的那样,我们花了很多时间来处理电子邮件。有很多方法可以解决它,我已经花了很多时间来寻找最适合我的电子邮件客户端。我认为这是一个重要的区别:对我有效的方法并不总是对其它人有效。有时对我有用的是像 [Thunderbird][2] 这样的完整客户端,有时是像 [Mutt][3] 这样的控制台客户端,有时是像 [Gmail][4] 和 [RoundCube][5] 这样基于 Web 的界面。
|
||||
|
||||

|
||||
|
||||
[Isotope][6] 是一个本地托管的、基于 Web 的电子邮件客户端。它非常轻巧,只使用 IMAP 协议,占用的磁盘空间非常小。与 Cypht 不同,Isotope 具有完整的 HTML 邮件支持,这意味着显示富文本电子邮件没有问题。
|
||||
|
||||

|
||||
|
||||
如果你安装了 [Docker][7],那么安装 Isotope 非常容易。你只需将文档中的命令复制到控制台中,然后按下回车键。在浏览器中输入 `localhost` 来访问 Isotope 登录界面,输入你的 IMAP 服务器,登录名和密码将打开收件箱视图。
|
||||
|
||||

|
||||
|
||||
在这一点上,Isotope 的功能和你想象的差不多。单击消息进行查看,单击铅笔图标以创建新邮件等。你会注意到用户界面(UI)非常简单,没有“移动到文件夹”、“复制到文件夹”和“存档”等常规按钮。你可以通过拖动来移动消息,因此其实你并不太需要这些按钮。
|
||||
|
||||

|
||||
|
||||
总的来说,Isotope 干净、速度快、工作得非常好。更棒的是,它正在积极开发中(最近一次的提交是在我撰写本文的两小时之前),所以它正在不断得到改进。你可以查看代码并在 [GitHub][8] 上为它做出贡献。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/1/productivity-tool-isotope
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney (Kevin Sonney)
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/19/1/productivity-tool-cypht-email
|
||||
[2]: https://www.thunderbird.net/
|
||||
[3]: http://www.mutt.org/
|
||||
[4]: https://mail.google.com/
|
||||
[5]: https://roundcube.net/
|
||||
[6]: https://blog.marcnuri.com/isotope-mail-client-introduction/
|
||||
[7]: https://www.docker.com/
|
||||
[8]: https://github.com/manusa/isotope-mail
|
||||
Reference in New Issue
Block a user