mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-25 23:11:02 +08:00
merge from LCTT
This commit is contained in:
commit
86d2cd329e
@ -0,0 +1,159 @@
|
||||
Linux 下如何避免重复性压迫损伤(RSI)
|
||||
======
|
||||
|
||||
![workrave-image][1]
|
||||
|
||||
<ruby>[重复性压迫损伤][2]<rt>Repetitive Strain Injury</rt></ruby>(RSI)是职业性损伤综合症,非特异性手臂疼痛或工作引起的上肢障碍。RSI 是由于过度使用双手从事重复性任务导致的,如打字、书写和使用鼠标. 不幸的是,大部分人不了解什么是 RSI 以及它的危害有多大。你可以使用名叫 Workrave 的开源软件轻松的预防 RSI。
|
||||
|
||||
### RSI 有哪些症状?
|
||||
|
||||
我从这个[页面][3]引用过来的,看看哪些你被说中了:
|
||||
|
||||
1. 疲惫缺乏忍耐力?
|
||||
2. 手掌及上肢乏力
|
||||
3. 疼痛麻木甚至失去知觉?
|
||||
4. 沉重:你有没有感觉手很沉?
|
||||
5. 笨拙: 你有没有感觉抓不紧东西?
|
||||
6. 你有没有感觉手上无力?很难打开罐子或切菜无力?
|
||||
7. 缺乏协调和控制?
|
||||
8. 手总是冰凉的?
|
||||
9. 健康意识有待提高?稍不注意身体就发现有毛病了。
|
||||
10. 是否过敏?
|
||||
11. 频繁的自我按摩(潜意识的)?
|
||||
12. 共鸣的疼痛?当别人在谈论手痛的时候,你是否也感觉到了手疼?
|
||||
|
||||
### 如何减少发展为 RSI 的风险
|
||||
|
||||
* 使用计算机的时候每隔 30 分钟间隔休息一下。借助软件如 workrave 预防 RSI。
|
||||
* 有规律的锻炼可以预防各种损伤,包括 RSI。
|
||||
* 使用合理的姿势。调整你的电脑桌和椅子使身体保持一个肌肉放松状态。
|
||||
|
||||
### Workrave
|
||||
|
||||
Workrave 是一款预防计算机用户发展为 RSI 或近视的自由开源软件。软件会定期锁屏为一个动画: “Workrave 小姐”,引导用户做各种伸展运动并敦促其休息一下。这个软件经常提醒你暂停休息一下,并限制你每天的限度。程序可以运行在 MS-Window、Linux 以及类 UNIX 操作系统下。
|
||||
|
||||
#### 安装 workrave
|
||||
|
||||
在 Debian/Ubuntu Linux 系统运行以下 [apt 命令][4]/[apt-get 命令][5]:
|
||||
|
||||
```
|
||||
$ sudo apt-get install workrave
|
||||
```
|
||||
|
||||
Fedora Linux 发行版用户运行以下 dnf 命令:
|
||||
|
||||
```
|
||||
$ sudo dnf install workrave
|
||||
```
|
||||
|
||||
RHEL/CentOS Linux 用户可以启动 EPEL 仓库并用 [yum 命令][6]安装:
|
||||
|
||||
```
|
||||
### [ **在CentOS/RHEL 7.x 及衍生版本上测试** ] ###
|
||||
$ sudo yum install epel-release
|
||||
$ sudo yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm
|
||||
$ sudo yum install workrave
|
||||
```
|
||||
|
||||
Arch Linux 用户运行以下 pacman 命令来安装:
|
||||
|
||||
```
|
||||
$ sudo pacman -S workrave
|
||||
```
|
||||
|
||||
FreeBSD 用户可用以下 pkg 命令安装:
|
||||
|
||||
```
|
||||
# pkg install workrave
|
||||
```
|
||||
|
||||
OpenBSD 用户可用以下 pkg_add 命令安装:
|
||||
|
||||
```
|
||||
$ doas pkg_add workrave
|
||||
```
|
||||
|
||||
#### 如何配置 workrave
|
||||
|
||||
Workrave 以一个小程序运行,它的用户界面位于面板中。你可以为 workrave 增加一个面板来控制软件的动作和外观。
|
||||
|
||||
增加一个新 workrave 对象到面板:
|
||||
|
||||
* 在面板空白区域右键,打开面板弹出菜单
|
||||
* 选择新增到面板
|
||||
* 新增面板对话框打开,在加载器顶部,可以看到可用的面板对象按照字母排列。选中 workrave 程序并单击新增。
|
||||
|
||||
![图 01:新增 workrave 对象到面板][7]
|
||||
|
||||
*图 01:新增 workrave 对象到面板*
|
||||
|
||||
如果修改 workrave 对象的属性,执行以下步骤:
|
||||
|
||||
* 右键 workrave 对象打开面板对象弹出
|
||||
* 选中偏好。使用属性对话框修改对应属性
|
||||
|
||||
![图 02:修改 Workrave 对象属性](https://www.cyberciti.biz/media/new/tips/2009/11/linux-gnome-workwave-preferences-.png)
|
||||
|
||||
*图 02:修改 Workrave 对象属性*
|
||||
|
||||
#### Workrave 运行展示
|
||||
|
||||
主窗口显示下一次提醒休息的剩余时间,这个窗口可以关闭,时间提示窗口会显示在面板上。
|
||||
|
||||
![图 03:时间计数器][8]
|
||||
|
||||
*图 03:时间计数器*
|
||||
|
||||
![图 04:Workrave 小姐 - 引导你做伸展运动的动画][9]
|
||||
|
||||
*图 04:Workrave 小姐 - 引导你做伸展运动的动画*
|
||||
|
||||
休息提示窗口,请求你暂停一下工作:
|
||||
|
||||
![图 05:休息提示倒计时][10]
|
||||
|
||||
*图 05:休息提示倒计时*
|
||||
|
||||
![图 06:你可以跳过休息][11]
|
||||
|
||||
*图 06:你可以跳过休息*
|
||||
|
||||
#### 参考链接:
|
||||
|
||||
1. [Workrave 项目][12] 主页
|
||||
2. [pokoy][13] 防止 RSI 和其他计算机压力的轻量级守护进程
|
||||
3. GNOME3 下的 [Pomodoro][14] 计数器
|
||||
4. [RSI][2] 的维基百科
|
||||
|
||||
### 关于作者
|
||||
|
||||
作者是 nixCraft 创始人,经验丰富的系统管理员,同时也是一个 Linux/Unix 系统下的 shell 脚本培训师。他曾服务于全球客户,并与多个行业合作包括 IT、教育、国防和航天研究,以及非盈利机构。可以在 [Twitter][15]、[Facebook][16]、[Google+][17] 上关注他。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cyberciti.biz/tips/repetitive-strain-injury-prevention-software.html
|
||||
|
||||
作者:[Vivek Gite][a]
|
||||
译者:[guevaraya](https://github.com/guevaraya)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.cyberciti.biz/
|
||||
[1]:https://www.cyberciti.biz/media/new/tips/2009/11/workrave-image.jpg
|
||||
[2]:https://en.wikipedia.org/wiki/Repetitive_strain_injury
|
||||
[3]:https://web.eecs.umich.edu/~cscott/rsi.html##symptoms
|
||||
[4]:https://www.cyberciti.biz/faq/ubuntu-lts-debian-linux-apt-command-examples/
|
||||
[5]:https://www.cyberciti.biz/tips/linux-debian-package-management-cheat-sheet.html
|
||||
[6]:https://www.cyberciti.biz/faq/rhel-centos-fedora-linux-yum-command-howto/
|
||||
[7]:https://www.cyberciti.biz/media/new/tips/2009/11/add-workwave-to-panel.png
|
||||
[8]:https://www.cyberciti.biz/media/new/tips/2009/11/screenshot-workrave.png
|
||||
[9]:https://www.cyberciti.biz/media/new/tips/2009/11/miss-workrave.png
|
||||
[10]:https://www.cyberciti.biz/media/new/tips/2009/11/time-for-micro-pause.gif
|
||||
[11]:https://www.cyberciti.biz/media/new/tips/2009/11/Micro-break.png
|
||||
[12]:http://www.workrave.org/
|
||||
[13]:https://github.com/ttygde/pokoy
|
||||
[14]:http://gnomepomodoro.org
|
||||
[15]:https://twitter.com/nixcraft
|
||||
[16]:https://facebook.com/nixcraft
|
||||
[17]:https://plus.google.com/+CybercitiBiz
|
@ -0,0 +1,358 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10519-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 3 OK03)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok03.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 3 OK03
|
||||
======
|
||||
|
||||
OK03 课程基于 OK02 课程来构建,它教你在汇编中如何使用函数让代码可复用和可读性更好。假设你已经有了 [课程 2:OK02][1] 的操作系统,我们将以它为基础。
|
||||
|
||||
### 1、可复用的代码
|
||||
|
||||
到目前为止,我们所写的代码都是以我们希望发生的事为顺序来输入的。对于非常小的程序来说,这种做法很好,但是如果我们以这种方式去写一个完整的系统,所写的代码可读性将非常差。我们应该去使用函数。
|
||||
|
||||
> 一个函数是一段可复用的代码片断,可以用于去计算某些答案,或执行某些动作。你也可以称它们为<ruby>过程<rt>procedure</rt></ruby>、<ruby>例程<rt>routine</rt></ruby>或<ruby>子例程<rt>subroutine</rt></ruby>。虽然它们都是不同的,但人们几乎都没有正确地使用这个术语。
|
||||
|
||||
> 你应该在数学上遇到了函数的概念。例如,余弦函数应用于一个给定的数时,会得到介于 -1 到 1 之间的另一个数,这个数就是角的余弦。一般我们写成 `cos(x)` 来表示应用到一个值 `x` 上的余弦函数。
|
||||
|
||||
> 在代码中,函数可以有多个输入(也可以没有输入),然后函数给出多个输出(也可以没有输出),并可能导致副作用。例如一个函数可以在一个文件系统上创建一个文件,第一个输入是它的名字,第二个输入是文件的长度。
|
||||
|
||||
> ![Function as black boxes][2]
|
||||
|
||||
> 函数可以认为是一个“黑匣子”。我们给它输入,然后它给我们输出,而我们不需要知道它是如何工作的。
|
||||
|
||||
在像 C 或 C++ 这样的高级代码中,函数是语言的组成部分。在汇编代码中,函数只是我们的创意。
|
||||
|
||||
理想情况下,我们希望能够在我们的寄存器中设置一些输入值,然后分支切换到某个地址,然后预期在某个时刻分支返回到我们代码,并通过代码来设置输出值到寄存器。这就是我们所设想的汇编代码中的函数。困难之处在于我们用什么样的方式去设置寄存器。如果我们只是使用平时所接触到的某种方法去设置寄存器,每个程序员可能使用不同的方法,这样你将会发现你很难理解其他程序员所写的代码。另外,编译器也不能像使用汇编代码那样轻松地工作,因为它们压根不知道如何去使用函数。为避免这种困惑,为每个汇编语言设计了一个称为<ruby>应用程序二进制接口<rt>Application Binary Interface</rt></ruby>(ABI)的标准,由它来规范函数如何去运行。如果每个人都使用相同的方法去写函数,这样每个人都可以去使用其他人写的函数。在这里,我将教你们这个标准,而从现在开始,我所写的函数将全部遵循这个标准。
|
||||
|
||||
该标准规定,寄存器 `r0`、`r1`、`r2` 和 `r3` 将被依次用于函数的输入。如果函数没有输入,那么它不会在意值是什么。如果只需要一个输入,那么它应该总是在寄存器 `r0` 中,如果它需要两个输入,那么第一个输入在寄存器 `r0` 中,而第二个输入在寄存器 `r1` 中,依此类推。输出值也总是在寄存器 `r0` 中。如果函数没有输出,那么 `r0` 中是什么值就不重要了。
|
||||
|
||||
另外,该标准要求当一个函数运行之后,寄存器 `r4` 到 `r12` 的值必须与函数启动时的值相同。这意味着当你调用一个函数时,你可以确保寄存器 `r4` 到 `r12` 中的值没有发生变化,但是不能确保寄存器 `r0` 到 `r3` 中的值也没有发生变化。
|
||||
|
||||
当一个函数运行完成后,它将返回到启动它的代码分支处。这意味着它必须知道启动它的代码的地址。为此,需要一个称为 `lr`(链接寄存器)的专用寄存器,它总是在保存调用这个函数的指令后面指令的地址。
|
||||
|
||||
表 1.1 ARM ABI 寄存器用法
|
||||
|
||||
| 寄存器 | 简介 | 保留 | 规则 |
|
||||
| ------ | --------- | ---- | ----------------- |
|
||||
| `r0` | 参数和结果 | 否 | `r0` 和 `r1` 用于给函数传递前两个参数,以及函数返回的结果。如果函数返回值不使用它,那么在函数运行之后,它们可以携带任何值。 |
|
||||
| `r1` | 参数和结果 | 否 | |
|
||||
| `r2` | 参数 | 否 | `r2` 和 `r3` 用去给函数传递后两个参数。在函数运行之后,它们可以携带任何值。 |
|
||||
| `r3` | 参数 | 否 | |
|
||||
| `r4` | 通用寄存器 | 是 | `r4` 到 `r12` 用于保存函数运行过程中的值,它们的值在函数调用之后必须与调用之前相同。 |
|
||||
| `r5` | 通用寄存器 | 是 | |
|
||||
| `r6` | 通用寄存器 | 是 | |
|
||||
| `r7` | 通用寄存器 | 是 | |
|
||||
| `r8` | 通用寄存器 | 是 | |
|
||||
| `r9` | 通用寄存器 | 是 | |
|
||||
| `r10` | 通用寄存器 | 是 | |
|
||||
| `r11` | 通用寄存器 | 是 | |
|
||||
| `r12` | 通用寄存器 | 是 | |
|
||||
| `lr` | 返回地址 | 否 | 当函数运行完成后,`lr` 中保存了分支的返回地址,但在函数运行完成之后,它将保存相同的地址。 |
|
||||
| `sp` | 栈指针 | 是 | `sp` 是栈指针,在下面有详细描述。它的值在函数运行完成后,必须是相同的。 |
|
||||
|
||||
通常,函数需要使用很多的寄存器,而不仅是 `r0` 到 `r3`。但是,由于 `r4` 到 `r12` 必须在函数完成之后值必须保持相同,因此它们需要被保存到某个地方。我们将它们保存到称为栈的地方。
|
||||
|
||||
> ![Stack diagram][3]
|
||||
|
||||
> 一个<ruby>栈<rt>stack</rt></ruby>就是我们在计算中用来保存值的一个很形象的方法。就像是摞起来的一堆盘子,你可以从上到下来移除它们,而添加它们时,你只能从下到上来添加。
|
||||
|
||||
> 在函数运行时,使用栈来保存寄存器值是个非常好的创意。例如,如果我有一个函数需要去使用寄存器 `r4` 和 `r5`,它将在一个栈上存放这些寄存器的值。最后用这种方式,它可以再次将它拿回来。更高明的是,如果为了运行完我的函数,需要去运行另一个函数,并且那个函数需要保存一些寄存器,在那个函数运行时,它将把寄存器保存在栈顶上,然后在结束后再将它们拿走。而这并不会影响我保存在寄存器 `r4` 和 `r5` 中的值,因为它们是在栈顶上添加的,拿走时也是从栈顶上取出的。
|
||||
|
||||
> 用来表示使用特定的方法将值放到栈上的专用术语,我们称之为那个方法的“<ruby>栈帧<rt>stack frame</rt></ruby>”。不是每种方法都使用一个栈帧,有些是不需要存储值的。
|
||||
|
||||
因为栈非常有用,它被直接实现在 ARMv6 的指令集中。一个名为 `sp`(栈指针)的专用寄存器用来保存栈的地址。当需要有值添加到栈上时,`sp` 寄存器被更新,这样就总是保证它保存的是栈上第一个值的地址。`push {r4,r5}` 将推送 `r4` 和 `r5` 中的值到栈顶上,而 `pop {r4,r5}` 将(以正确的次序)取回它们。
|
||||
|
||||
### 2、我们的第一个函数
|
||||
|
||||
现在,关于函数的原理我们已经有了一些概念,我们尝试来写一个函数。由于是我们的第一个很基础的例子,我们写一个没有输入的函数,它将输出 GPIO 的地址。在上一节课程中,我们就是写到这个值上,但将它写成函数更好,因为我们在真实的操作系统中经常需要用到它,而我们不可能总是能够记住这个地址。
|
||||
|
||||
复制下列代码到一个名为 `gpio.s` 的新文件中。就像在 `source` 目录中使用的 `main.s` 一样。我们将把与 GPIO 控制器相关的所有函数放到一个文件中,这样更好查找。
|
||||
|
||||
```assembly
|
||||
.globl GetGpioAddress
|
||||
GetGpioAddress:
|
||||
ldr r0,=0x20200000
|
||||
mov pc,lr
|
||||
```
|
||||
|
||||
> `.globl lbl` 使标签 `lbl` 从其它文件中可访问。
|
||||
|
||||
> `mov reg1,reg2` 复制 `reg2` 中的值到 `reg1` 中。
|
||||
|
||||
这就是一个很简单的完整的函数。`.globl GetGpioAddress` 命令是通知汇编器,让标签 `GetGpioAddress` 在所有文件中全局可访问。这意味着在我们的 `main.s` 文件中,我们可以使用分支指令到标签 `GetGpioAddress` 上,即便这个标签在那个文件中没有定义也没有问题。
|
||||
|
||||
你应该认得 `ldr r0,=0x20200000` 命令,它将 GPIO 控制器地址保存到 `r0` 中。由于这是一个函数,我们必须要让它输出到寄存器 `r0` 中,我们不能再像以前那样随意使用任意一个寄存器了。
|
||||
|
||||
`mov pc,lr` 将寄存器 `lr` 中的值复制到 `pc` 中。正如前面所提到的,寄存器 `lr` 总是保存着方法完成后我们要返回的代码的地址。`pc` 是一个专用寄存器,它总是包含下一个要运行的指令的地址。一个普通的分支命令只需要改变这个寄存器的值即可。通过将 `lr` 中的值复制到 `pc` 中,我们就可以将要运行的下一行命令改变成我们将要返回的那一行。
|
||||
|
||||
理所当然这里有一个问题,那就是我们如何去运行这个代码?我们将需要一个特殊的分支类型 `bl` 指令。它像一个普通的分支一样切换到一个标签,但它在切换之前先更新 `lr` 的值去包含一个在该分支之后的行的地址。这意味着当函数执行完成后,将返回到 `bl` 指令之后的那一行上。这就确保了函数能够像任何其它命令那样运行,它简单地运行,做任何需要做的事情,然后推进到下一行。这是理解函数最有用的方法。当我们使用它时,就将它们按“黑匣子”处理即可,不需要了解它是如何运行的,我们只了解它需要什么输入,以及它给我们什么输出即可。
|
||||
|
||||
到现在为止,我们已经明白了函数如何使用,下一节我们将使用它。
|
||||
|
||||
### 3、一个大的函数
|
||||
|
||||
现在,我们继续去实现一个更大的函数。我们的第一项任务是启用 GPIO 第 16 号针脚的输出。如果它是一个函数那就太好了。我们能够简单地指定一个针脚号和一个函数作为输入,然后函数将设置那个针脚的值。那样,我们就可以使用这个代码去控制任意的 GPIO 针脚,而不只是 LED 了。
|
||||
|
||||
将下列的命令复制到 `gpio.s` 文件中的 `GetGpioAddress` 函数中。
|
||||
|
||||
```assembly
|
||||
.globl SetGpioFunction
|
||||
SetGpioFunction:
|
||||
cmp r0,#53
|
||||
cmpls r1,#7
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
> 带后缀 `ls` 的命令只有在上一个比较命令的结果是第一个数字小于或与第二个数字相同的情况下才会被运行。它是无符号的。
|
||||
|
||||
> 带后缀 `hi` 的命令只有上一个比较命令的结果是第一个数字大于第二个数字的情况下才会被运行。它是无符号的。
|
||||
|
||||
在写一个函数时,我们首先要考虑的事情就是输入,如果输入错了我们怎么办?在这个函数中,我们有一个输入是 GPIO 针脚号,而它必须是介于 0 到 53 之间的数字,因为只有 54 个针脚。每个针脚有 8 个函数,被编号为 0 到 7,因此函数编号也必须是 0 到 7 之间的数字。我们可以假设输入应该是正确的,但是当在硬件上使用时,这种做法是非常危险的,因为不正确的值将导致非常糟糕的副作用。所以,在这个案例中,我们希望确保输入值在正确的范围。
|
||||
|
||||
为了确保输入值在正确的范围,我们需要做一个检查,即 `r0` <= 53 并且 `r1` <= 7。首先我们使用前面看到的比较命令去将 `r0` 的值与 53 做比较。下一个指令 `cmpls` 仅在前一个比较指令结果是小于或与 53 相同时才会去运行。如果是这种情况,它将寄存器 `r1` 的值与 7 进行比较,其它的部分都和前面的是一样的。如果最后的比较结果是寄存器值大于那个数字,最后我们将返回到运行函数的代码处。
|
||||
|
||||
这正是我们所希望的效果。如果 `r0` 中的值大于 53,那么 `cmpls` 命令将不会去运行,但是 `movhi` 会运行。如果 `r0` 中的值 <= 53,那么 `cmpls` 命令会运行,它会将 `r1` 中的值与 7 进行比较,如果 `r1` > 7,`movhi` 会运行,函数结束,否则 `movhi` 不会运行,这样我们就确定 `r0` <= 53 并且 `r1` <= 7。
|
||||
|
||||
`ls`(低于或相同)与 `le`(小于或等于)有一些细微的差别,以及后缀 `hi`(高于)和 `gt`(大于)也一样有一些细微差别,我们在后面将会讲到。
|
||||
|
||||
将这些命令复制到上面的代码的下面位置。
|
||||
|
||||
```assembly
|
||||
push {lr}
|
||||
mov r2,r0
|
||||
bl GetGpioAddress
|
||||
```
|
||||
|
||||
> `push {reg1,reg2,...}` 复制列出的寄存器 `reg1`、`reg2`、... 到栈顶。该命令仅能用于通用寄存器和 `lr` 寄存器。
|
||||
|
||||
> `bl lbl` 设置 `lr` 为下一个指令的地址并切换到标签 `lbl`。
|
||||
|
||||
这三个命令用于调用我们第一个方法。`push {lr}` 命令复制 `lr` 中的值到栈顶,这样我们在后面可以获取到它。当我们调用 `GetGpioAddress` 时必须要这样做,我们将需要使用 `lr` 去保存我们函数要返回的地址。
|
||||
|
||||
如果我们对 `GetGpioAddress` 函数一无所知,我们必须假设它改变了 `r0`、`r1`、`r2` 和 `r3` 的值 ,并移动我们的值到 `r4` 和 `r5` 中,以在函数完成之后保持它们的值一样。幸运的是,我们知道 `GetGpioAddress` 做了什么,并且我们也知道它仅改变了 `r0` 为 GPIO 地址,它并没有影响 `r1`、`r2` 或 `r3` 的值。因此,我们仅去将 GPIO 针脚号从 `r0` 中移出,这样它就不会被覆盖掉,但我们知道,可以将它安全地移到 `r2` 中,因为 `GetGpioAddress` 并不去改变 `r2`。
|
||||
|
||||
最后我们使用 `bl` 指令去运行 `GetGpioAddress`。通常,运行一个函数,我们使用一个术语叫“调用”,从现在开始我们将一直使用这个术语。正如我们前面讨论过的,`bl` 调用一个函数是通过更新 `lr` 为下一个指令的地址并切换到该函数完成的。
|
||||
|
||||
当一个函数结束时,我们称为“返回”。当一个 `GetGpioAddress` 调用返回时,我们已经知道了 `r0` 中包含了 GPIO 的地址,`r1` 中包含了函数编号,而 `r2` 中包含了 GPIO 针脚号。
|
||||
|
||||
我前面说过,GPIO 函数每 10 个保存在一个块中,因此首先我们需要去判断我们的针脚在哪个块中。这似乎听起来像是要使用一个除法,但是除法做起来非常慢,因此对于这些比较小的数来说,不停地做减法要比除法更好。
|
||||
|
||||
将下面的代码复制到上面的代码中最下面的位置。
|
||||
|
||||
```assembly
|
||||
functionLoop$:
|
||||
|
||||
cmp r2,#9
|
||||
subhi r2,#10
|
||||
addhi r0,#4
|
||||
bhi functionLoop$
|
||||
```
|
||||
|
||||
> `add reg,#val` 将数字 `val` 加到寄存器 `reg` 的内容上。
|
||||
|
||||
这个简单的循环代码将针脚号(`r2`)与 9 进行比较。如果它大于 9,它将从针脚号上减去 10,并且将 GPIO 控制器地址加上 4,然后再次运行检查。
|
||||
|
||||
这样做的效果就是,现在,`r2` 中将包含一个 0 到 9 之间的数字,它是针脚号除以 10 的余数。`r0` 将包含这个针脚的函数所设置的 GPIO 控制器的地址。它就如同是 “GPIO 控制器地址 + 4 × (GPIO 针脚号 ÷ 10)”。
|
||||
|
||||
最后,将下面的代码复制到上面的代码中最下面的位置。
|
||||
|
||||
```assembly
|
||||
add r2, r2,lsl #1
|
||||
lsl r1,r2
|
||||
str r1,[r0]
|
||||
pop {pc}
|
||||
```
|
||||
|
||||
> 移位参数 `reg,lsl #val` 表示将寄存器 `reg` 中二进制表示的数逻辑左移 `val` 位之后的结果作为与前面运算的操作数。
|
||||
|
||||
> `lsl reg,amt` 将寄存器 `reg` 中的二进制数逻辑左移 `amt` 中的位数。
|
||||
|
||||
> `str reg,[dst]` 与 `str reg,[dst,#0]` 相同。
|
||||
|
||||
> `pop {reg1,reg2,...}` 从栈顶复制值到寄存器列表 `reg1`、`reg2`、... 仅有通用寄存器与 `pc` 可以这样弹出值。
|
||||
|
||||
这个代码完成了这个方法。第一行其实是乘以 3 的变体。乘法在汇编中是一个大而慢的指令,因为电路需要很长时间才能给出答案。有时使用一些能够很快给出答案的指令会让它变得更快。在本案例中,我们知道 `r2` × 3 与 `r2` × 2 + `r2` 是相同的。一个寄存器乘以 2 是非常容易的,因为它可以通过将二进制表示的数左移一位来很方便地实现。
|
||||
|
||||
ARMv6 汇编语言其中一个非常有用的特性就是,在使用它之前可以先移动参数所表示的位数。在本案例中,我将 `r2` 加上 `r2` 中二进制表示的数左移一位的结果。在汇编代码中,你可以经常使用这个技巧去更快更容易地计算出答案,但如果你觉得这个技巧使用起来不方便,你也可以写成类似 `mov r3,r2`; `add r2,r3`; `add r2,r3` 这样的代码。
|
||||
|
||||
现在,我们可以将一个函数的值左移 `r2` 中所表示的位数。大多数对数量的指令(比如 `add` 和 `sub`)都有一个可以使用寄存器而不是数字的变体。我们执行这个移位是因为我们想去设置表示针脚号的位,并且每个针脚有三个位。
|
||||
|
||||
然后,我们将函数计算后的值保存到 GPIO 控制器的地址上。我们在循环中已经算出了那个地址,因此我们不需要像 OK01 和 OK02 中那样在一个偏移量上保存它。
|
||||
|
||||
最后,我们从这个方法调用中返回。由于我们将 `lr` 推送到了栈上,因此我们 `pop pc`,它将复制 `lr` 中的值并将它推送到 `pc` 中。这个操作类似于 `mov pc,lr`,因此函数调用将返回到运行它的那一行上。
|
||||
|
||||
敏锐的人可能会注意到,这个函数其实并不能正确工作。虽然它将 GPIO 针脚函数设置为所要求的值,但它会导致在同一个块中的所有的 10 个针脚的函数都归 0!在一个大量使用 GPIO 针脚的系统中,这将是一个很恼人的问题。我将这个问题留给有兴趣去修复这个函数的人,以确保只设置相关的 3 个位而不去覆写其它位,其它的所有位都保持不变。关于这个问题的解决方案可以在本课程的下载页面上找到。你可能会发现非常有用的几个函数是 `and`,它是计算两个寄存器的布尔与函数,`mvns` 是计算布尔非函数,而 `orr` 是计算布尔或函数。
|
||||
|
||||
### 4、另一个函数
|
||||
|
||||
现在,我们已经有了能够管理 GPIO 针脚函数的函数。我们还需要写一个能够打开或关闭 GPIO 针脚的函数。我们不需要写一个打开的函数和一个关闭的函数,只需要一个函数就可以做这两件事情。
|
||||
|
||||
我们将写一个名为 `SetGpio` 的函数,它将 GPIO 针脚号作为第一个输入放入 `r0` 中,而将值作为第二个输入放入 `r1` 中。如果该值为 `0`,我们将关闭针脚,而如果为非零则打开针脚。
|
||||
|
||||
将下列的代码复制粘贴到 `gpio.s` 文件的结尾部分。
|
||||
|
||||
```assembly
|
||||
.globl SetGpio
|
||||
SetGpio:
|
||||
pinNum .req r0
|
||||
pinVal .req r1
|
||||
```
|
||||
|
||||
> `alias .req reg` 设置寄存器 `reg` 的别名为 `alias`。
|
||||
|
||||
我们再次需要 `.globl` 命令,标记它为其它文件可访问的全局函数。这次我们将使用寄存器别名。寄存器别名允许我们为寄存器使用名字而不仅是 `r0` 或 `r1`。到目前为止,寄存器别名还不是很重要,但随着我们后面写的方法越来越大,它将被证明非常有用,现在开始我们将尝试使用别名。当在指令中使用到 `pinNum .req r0` 时,它的意思是 `pinNum` 表示 `r0`。
|
||||
|
||||
将下面的代码复制粘贴到上述的代码下面位置。
|
||||
|
||||
```assembly
|
||||
cmp pinNum,#53
|
||||
movhi pc,lr
|
||||
push {lr}
|
||||
mov r2,pinNum
|
||||
.unreq pinNum
|
||||
pinNum .req r2
|
||||
bl GetGpioAddress
|
||||
gpioAddr .req r0
|
||||
```
|
||||
|
||||
> `.unreq alias` 删除别名 `alias`。
|
||||
|
||||
就像在函数 `SetGpio` 中所做的第一件事情是检查给定的针脚号是否有效一样。我们需要同样的方式去将 `pinNum`(`r0`)与 53 进行比较,如果它大于 53 将立即返回。一旦我们想要再次调用 `GetGpioAddress`,我们就需要将 `lr` 推送到栈上来保护它,将 `pinNum` 移动到 `r2` 中。然后我们使用 `.unreq` 语句来删除我们给 `r0` 定义的别名。因为针脚号现在保存在寄存器 `r2` 中,我们希望别名能够反映这个变化,因此我们从 `r0` 移走别名,重新定义到 `r2`。你应该每次在别名使用结束后,立即删除它,这样当它不再存在时,你就不会在后面的代码中因它而产生错误。
|
||||
|
||||
然后,我们调用了 `GetGpioAddress`,并且我们创建了一个指向 `r0`的别名以反映此变化。
|
||||
|
||||
将下面的代码复制粘贴到上述代码的后面位置。
|
||||
|
||||
```assembly
|
||||
pinBank .req r3
|
||||
lsr pinBank,pinNum,#5a
|
||||
lsl pinBank,#2
|
||||
add gpioAddr,pinBank
|
||||
.unreq pinBank
|
||||
```
|
||||
|
||||
> `lsr dst,src,#val` 将 `src` 中二进制表示的数右移 `val` 位,并将结果保存到 `dst`。
|
||||
|
||||
对于打开和关闭 GPIO 针脚,每个针脚在 GPIO 控制器上有两个 4 字节组。第一个 4 字节组每个位控制前 32 个针脚,而第二个 4 字节组控制剩下的 22 个针脚。为了判断我们要设置的针脚在哪个 4 字节组中,我们需要将针脚号除以 32。幸运的是,这很容易,因为它等价于将二进制表示的针脚号右移 5 位。因此,在本案例中,我们将 `r3` 命名为 `pinBank`,然后计算 `pinNum` ÷ 32。因为它是一个 4 字节组,我们需要将它与 4 相乘的结果。它与二进制表示的数左移 2 位相同,这就是下一行的命令。你可能想知道我们能否只将它右移 3 位呢,这样我们就不用先右移再左移。但是这样做是不行的,因为当我们做 ÷ 32 时答案有些位可能被舍弃,而如果我们做 ÷ 8 时却不会这样。
|
||||
|
||||
现在,`gpioAddr` 的结果有可能是 20200000<sub>16</sub>(如果针脚号介于 0 到 31 之间),也有可能是 20200004<sub>16</sub>(如果针脚号介于 32 到 53 之间)。这意味着如果加上 28<sub>10</sub>,我们将得到打开针脚的地址,而如果加上 40<sub>10</sub> ,我们将得到关闭针脚的地址。由于我们用完了 `pinBank` ,所以在它之后立即使用 `.unreq` 去删除它。
|
||||
|
||||
将下面的代码复制粘贴到上述代码的下面位置。
|
||||
|
||||
```assembly
|
||||
and pinNum,#31
|
||||
setBit .req r3
|
||||
mov setBit,#1
|
||||
lsl setBit,pinNum
|
||||
.unreq pinNum
|
||||
```
|
||||
|
||||
> `and reg,#val` 计算寄存器 `reg` 中的数与 `val` 的布尔与。
|
||||
|
||||
该函数的下一个部分是产生一个正确的位集合的数。至于 GPIO 控制器去打开或关闭针脚,我们在针脚号除以 32 的余数里设置了位的数。例如,设置 16 号针脚,我们需要第 16 位设置数字为 1 。设置 45 号针脚,我们需要设置第 13 位数字为 1,因为 45 ÷ 32 = 1 余数 13。
|
||||
|
||||
这个 `and` 命令计算我们需要的余数。它是这样计算的,在两个输入中所有的二进制位都是 1 时,这个 `and` 运算的结果就是 1,否则就是 0。这是一个很基础的二进制操作,`and` 操作非常快。我们给定的输入是 “pinNum and 31<sub>10</sub> = 11111<sub>2</sub>”。这意味着答案的后 5 位中只有 1,因此它肯定是在 0 到 31 之间。尤其是在 `pinNum` 的后 5 位的位置是 1 的地方它只有 1。这就如同被 32 整除的余数部分。就像 31 = 32 - 1 并不是巧合。
|
||||
|
||||
![binary division example][4]
|
||||
|
||||
代码的其余部分使用这个值去左移 1 位。这就有了创建我们所需要的二进制数的效果。
|
||||
|
||||
将下面的代码复制粘贴到上述代码的下面位置。
|
||||
|
||||
```assembly
|
||||
teq pinVal,#0
|
||||
.unreq pinVal
|
||||
streq setBit,[gpioAddr,#40]
|
||||
strne setBit,[gpioAddr,#28]
|
||||
.unreq setBit
|
||||
.unreq gpioAddr
|
||||
pop {pc}
|
||||
```
|
||||
|
||||
> `teq reg,#val` 检查寄存器 `reg` 中的数字与 `val` 是否相等。
|
||||
|
||||
这个代码结束了该方法。如前面所说,当 `pinVal` 为 0 时,我们关闭它,否则就打开它。`teq`(等于测试)是另一个比较操作,它仅能够测试是否相等。它类似于 `cmp` ,但它并不能算出哪个数大。如果你只是希望测试数字是否相同,你可以使用 `teq`。
|
||||
|
||||
如果 `pinVal` 是 0,我们将 `setBit` 保存在 GPIO 地址偏移 40 的位置,我们已经知道,这样会关闭那个针脚。否则将它保存在 GPIO 地址偏移 28 的位置,它将打开那个针脚。最后,我们通过弹出 `pc` 返回,这将设置它为我们推送链接寄存器时保存的值。
|
||||
|
||||
### 5、一个新的开始
|
||||
|
||||
在完成上述工作后,我们终于有了我们的 GPIO 函数。现在,我们需要去修改 `main.s` 去使用它们。因为 `main.s` 现在已经有点大了,也更复杂了。将它分成两节将是一个很好的设计。到目前为止,我们一直使用的 `.init` 应该尽可能的让它保持小。我们可以更改代码来很容易地反映出这一点。
|
||||
|
||||
将下列的代码插入到 `main.s` 文件中 `_start:` 的后面:
|
||||
|
||||
```
|
||||
b main
|
||||
|
||||
.section .text
|
||||
main:
|
||||
mov sp,#0x8000
|
||||
```
|
||||
|
||||
在这里重要的改变是引入了 `.text` 节。我设计了 `makefile` 和链接器脚本,它将 `.text` 节(它是默认节)中的代码放在地址为 8000<sub>16</sub> 的 `.init` 节之后。这是默认加载地址,并且它给我们提供了一些空间去保存栈。由于栈存在于内存中,它也有一个地址。栈向下增长内存,因此每个新值都低于前一个地址,所以,这使得栈顶是最低的一个地址。
|
||||
|
||||
![Layout diagram of operating system][5]
|
||||
|
||||
> 图中的 “ATAGs” 节的位置保存了有关树莓派的信息,比如它有多少内存,默认屏幕分辨率是多少。
|
||||
|
||||
用下面的代码替换掉所有设置 GPIO 函数针脚的代码:
|
||||
|
||||
```assembly
|
||||
pinNum .req r0
|
||||
pinFunc .req r1
|
||||
mov pinNum,#16
|
||||
mov pinFunc,#1
|
||||
bl SetGpioFunction
|
||||
.unreq pinNum
|
||||
.unreq pinFunc
|
||||
```
|
||||
|
||||
这个代码将使用针脚号 16 和函数编号 1 去调用 `SetGpioFunction`。它的效果就是启用了 OK LED 灯的输出。
|
||||
|
||||
用下面的代码去替换打开 OK LED 灯的代码:
|
||||
|
||||
```assembly
|
||||
pinNum .req r0
|
||||
pinVal .req r1
|
||||
mov pinNum,#16
|
||||
mov pinVal,#0
|
||||
bl SetGpio
|
||||
.unreq pinNum
|
||||
.unreq pinVal
|
||||
```
|
||||
|
||||
这个代码使用 `SetGpio` 去关闭 GPIO 第 16 号针脚,因此将打开 OK LED。如果我们(将第 4 行)替换成 `mov pinVal,#1` 它将关闭 LED 灯。用以上的代码去替换掉你关闭 LED 灯的旧代码。
|
||||
|
||||
### 6、继续向目标前进
|
||||
|
||||
但愿你能够顺利地在你的树莓派上测试我们所做的这一切。到目前为止,我们已经写了一大段代码,因此不可避免会出现错误。如果有错误,可以去查看我们的排错页面。
|
||||
|
||||
如果你的代码已经正常工作,恭喜你。虽然我们的操作系统除了做 [课程 2:OK02][1] 中的事情,还做不了别的任何事情,但我们已经学会了函数和格式有关的知识,并且我们现在可以更好更快地编写新特性了。现在,我们在操作系统上修改 GPIO 寄存器将变得非常简单,而它就是用于控制硬件的!
|
||||
|
||||
在 [课程 4:OK04][6] 中,我们将处理我们的 `wait` 函数,目前,它的时间控制还不精确,这样我们就可以更好地控制我们的 LED 灯了,进而最终控制所有的 GPIO 针脚。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok03.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-10478-1.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/functions.png
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/stack.png
|
||||
[4]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/binary3.png
|
||||
[5]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/osLayout.png
|
||||
[6]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok04.html
|
@ -0,0 +1,165 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10526-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 4 OK04)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok04.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 4 OK04
|
||||
======
|
||||
|
||||
OK04 课程在 OK03 的基础上进行构建,它教你如何使用定时器让 OK 或 ACT LED 灯按精确的时间间隔来闪烁。假设你已经有了 [课程 3:OK03][1] 的操作系统,我们将以它为基础来构建。
|
||||
|
||||
### 1、一个新设备
|
||||
|
||||
> 定时器是树莓派保持时间的唯一方法。大多数计算机都有一个电池供电的时钟,这样当计算机关机后仍然能保持时间。
|
||||
|
||||
到目前为止,我们仅看了树莓派硬件的一小部分,即 GPIO 控制器。我只是简单地告诉你做什么,然后它会发生什么事情。现在,我们继续看定时器,并继续带你去了解它的工作原理。
|
||||
|
||||
和 GPIO 控制器一样,定时器也有地址。在本案例中,定时器的基地址在 20003000<sub>16</sub>。阅读手册我们可以找到下面的表:
|
||||
|
||||
表 1.1 GPIO 控制器寄存器
|
||||
|
||||
| 地址 | 大小 / 字节 | 名字 | 描述 | 读或写 |
|
||||
| -------- | ------------ | ---------------- | ---------------------------------------------------------- | ---------------- |
|
||||
| 20003000 | 4 | Control / Status | 用于控制和清除定时器通道比较器匹配的寄存器 | RW |
|
||||
| 20003004 | 8 | Counter | 按 1 MHz 的频率递增的计数器 | R |
|
||||
| 2000300C | 4 | Compare 0 | 0 号比较器寄存器 | RW |
|
||||
| 20003010 | 4 | Compare 1 | 1 号比较器寄存器 | RW |
|
||||
| 20003014 | 4 | Compare 2 | 2 号比较器寄存器 | RW |
|
||||
| 20003018 | 4 | Compare 3 | 3 号比较器寄存器 | RW |
|
||||
|
||||
![Flowchart of the system timer's operation][2]
|
||||
|
||||
这个表只告诉我们一部分内容,在手册中描述了更多的字段。手册上解释说,定时器本质上是按每微秒将计数器递增 1 的方式来运行。每次它是这样做的,它将计数器的低 32 位(4 字节)与 4 个比较器寄存器进行比较,如果匹配它们中的任何一个,它更新 `Control/Status` 以反映出其中有一个是匹配的。
|
||||
|
||||
关于<ruby>位<rt>bit</rt></ruby>、<ruby>字节<rt>byte</rt></ruby>、<ruby>位字段<rt>bit field</rt></ruby>、以及数据大小的更多内容如下:
|
||||
|
||||
>
|
||||
> 一个位是一个单个的二进制数的名称。你可能还记得,一个单个的二进制数既可能是一个 1,也可能是一个 0。
|
||||
>
|
||||
> 一个字节是一个 8 位集合的名称。由于每个位可能是 1 或 0 这两个值的其中之一,因此,一个字节有 2^8 = 256 个不同的可能值。我们一般解释一个字节为一个介于 0 到 255(含)之间的二进制数。
|
||||
>
|
||||
> ![Diagram of GPIO function select controller register 0.][3]
|
||||
>
|
||||
> 一个位字段是解释二进制的另一种方式。二进制可以解释为许多不同的东西,而不仅仅是一个数字。一个位字段可以将二进制看做为一系列的 1(开) 或 0(关)的开关。对于每个小开关,我们都有一个意义,我们可以使用它们去控制一些东西。我们已经遇到了 GPIO 控制器使用的位字段,使用它设置一个针脚的开或关。位为 1 时 GPIO 针脚将准确地打开或关闭。有时我们需要更多的选项,而不仅仅是开或关,因此我们将几个开关组合到一起,比如 GPIO 控制器的函数设置(如上图),每 3 位为一组控制一个 GPIO 针脚的函数。
|
||||
|
||||
我们的目标是实现一个函数,这个函数能够以一个时间数量为输入来调用它,这个输入的时间数量将作为等待的时间,然后返回。想一想如何去做,想想我们都拥有什么。
|
||||
|
||||
我认为这将有两个选择:
|
||||
|
||||
1. 从计数器中读取一个值,然后保持分支返回到相同的代码,直到计数器的等待时间数量大于它。
|
||||
2. 从计数器中读取一个值,加上要等待的时间数量,将它保存到比较器寄存器,然后保持分支返回到相同的代码处,直到 `Control / Status` 寄存器更新。
|
||||
|
||||
这两种策略都工作的很好,但在本教程中,我们将只实现第一个。原因是比较器寄存器更容易出错,因为在增加等待时间并保存它到比较器的寄存器期间,计数器可能已经增加了,并因此可能会不匹配。如果请求的是 1 微秒(或更糟糕的情况是 0 微秒)的等待,这样可能导致非常长的意外延迟。
|
||||
|
||||
> 像这样存在被称为“并发问题”的问题,并且几乎无法解决。
|
||||
|
||||
### 2、实现
|
||||
|
||||
我将把这个创建完美的等待方法的挑战基本留给你。我建议你将所有与定时器相关的代码都放在一个名为 `systemTimer.s` 的文件中(理由很明显)。关于这个方法的复杂部分是,计数器是一个 8 字节值,而每个寄存器仅能保存 4 字节。所以,计数器值将分到 2 个寄存器中。
|
||||
|
||||
> 大型的操作系统通常使用等待函数来抓住机会在后台执行任务。
|
||||
|
||||
下列的代码块是一个示例。
|
||||
|
||||
```assembly
|
||||
ldrd r0,r1,[r2,#4]
|
||||
```
|
||||
|
||||
> `ldrd regLow,regHigh,[src,#val]` 从 `src` 中的数加上 `val` 之和的地址加载 8 字节到寄存器 `regLow` 和 `regHigh` 中。
|
||||
|
||||
上面的代码中你可以发现一个很有用的指令是 `ldrd`。它加载 8 字节的内存到两个寄存器中。在本案例中,这 8 字节内存从寄存器 `r2` 中的地址 + 4 开始,将被复制进寄存器 `r0` 和 `r1`。这种安排的稍微复杂之处在于 `r1` 实际上只持有了高位 4 字节。换句话说就是,如果如果计数器的值是 999,999,999,999<sub>10</sub> = 1110100011010100101001010000111111111111<sub>2</sub> ,那么寄存器 `r1` 中只有 11101000<sub>2</sub>,而寄存器 `r0` 中则是 11010100101001010000111111111111<sub>2</sub>。
|
||||
|
||||
实现它的更明智的方式应该是,去计算当前计数器值与来自方法启动后的那一个值的差,然后将它与要求的等待时间数量进行比较。除非恰好你希望的等待时间是占用 8 字节的,否则上面示例中寄存器 `r1` 中的值将会丢弃,而计数器仅需要使用低位 4 字节。
|
||||
|
||||
当等待开始时,你应该总是确保使用大于比较,而不是使用等于比较,因为如果你尝试去等待一个时间,而这个时间正好等于方法开始的时间与结束的时间之差,那么你就错过这个值而永远等待下去。
|
||||
|
||||
如果你不明白如何编写等待函数的代码,可以参考下面的指南。
|
||||
|
||||
>
|
||||
> 借鉴 GPIO 控制器的创意,第一个函数我们应该去写如何取得系统定时器的地址。示例如下:
|
||||
>
|
||||
> ```assembly
|
||||
> .globl GetSystemTimerBase
|
||||
> GetSystemTimerBase:
|
||||
> ldr r0,=0x20003000
|
||||
> mov pc,lr
|
||||
> ```
|
||||
>
|
||||
> 另一个被证明非常有用的函数是返回在寄存器 `r0` 和 `r1` 中的当前计数器值:
|
||||
>
|
||||
> ```assembly
|
||||
> .globl GetTimeStamp
|
||||
> GetTimeStamp:
|
||||
> push {lr}
|
||||
> bl GetSystemTimerBase
|
||||
> ldrd r0,r1,[r0,#4]
|
||||
> pop {pc}
|
||||
> ```
|
||||
>
|
||||
> 这个函数简单地使用了 `GetSystemTimerBase` 函数,并像我们前面学过的那样,使用 `ldrd` 去加载当前计数器值。
|
||||
>
|
||||
> 现在,我们可以去写我们的等待方法的代码了。首先,在该方法启动后,我们需要知道计数器值,我们可以使用 `GetTimeStamp` 来取得。
|
||||
>
|
||||
> ```assembly
|
||||
> delay .req r2
|
||||
> mov delay,r0
|
||||
> push {lr}
|
||||
> bl GetTimeStamp
|
||||
> start .req r3
|
||||
> mov start,r0
|
||||
> ```
|
||||
>
|
||||
> 这个代码复制了我们的方法的输入,将延迟时间的数量放到寄存器 `r2` 中,然后调用 `GetTimeStamp`,这个函数将会返回寄存器 `r0` 和 `r1` 中的当前计数器值。接着复制计数器值的低位 4 字节到寄存器 `r3` 中。
|
||||
>
|
||||
> 接下来,我们需要计算当前计数器值与读入的值的差,然后持续这样做,直到它们的差至少是 `delay` 的大小为止。
|
||||
>
|
||||
> ```assembly
|
||||
> loop$:
|
||||
>
|
||||
> bl GetTimeStamp
|
||||
> elapsed .req r1
|
||||
> sub elapsed,r0,start
|
||||
> cmp elapsed,delay
|
||||
> .unreq elapsed
|
||||
> bls loop$
|
||||
> ```
|
||||
>
|
||||
> 这个代码将一直等待,一直到等待到传递给它的时间数量为止。它从计数器中读取数值,减去最初从计数器中读取的值,然后与要求的延迟时间进行比较。如果过去的时间数量小于要求的延迟,它切换回 `loop$`。
|
||||
>
|
||||
> ```assembly
|
||||
> .unreq delay
|
||||
> .unreq start
|
||||
> pop {pc}
|
||||
> ```
|
||||
>
|
||||
> 代码完成后,函数返回。
|
||||
>
|
||||
|
||||
|
||||
### 3、另一个闪灯程序
|
||||
|
||||
你一旦明白了等待函数的工作原理,修改 `main.s` 去使用它。修改各处 `r0` 的等待设置值为某个很大的数量(记住它的单位是微秒),然后在树莓派上测试。如果函数不能正常工作,请查看我们的排错页面。
|
||||
|
||||
如果正常工作,恭喜你学会控制另一个设备了,会使用它,则时间由你控制。在下一节课程中,我们将完成 OK 系列课程的最后一节 [课程 5:OK05][4],我们将使用我们已经学习过的知识让 LED 按我们的模式进行闪烁。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok04.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-10519-1.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/systemTimer.png
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/gpioControllerFunctionSelect.png
|
||||
[4]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok05.html
|
@ -0,0 +1,100 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (oska874)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10530-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 5 OK05)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok05.html)
|
||||
[#]: author: (Robert Mullins http://www.cl.cam.ac.uk/~rdm34)
|
||||
|
||||
计算机实验室之树莓派:课程 5 OK05
|
||||
======
|
||||
|
||||
OK05 课程构建于课程 OK04 的基础,使用它来闪烁摩尔斯电码的 SOS 序列(`...---...`)。这里假设你已经有了 [课程 4:OK04][1] 操作系统的代码作为基础。
|
||||
|
||||
### 1、数据
|
||||
|
||||
到目前为止,我们与操作系统有关的所有内容提供的都是指令。然而有时候,指令只是完成了一半的工作。我们的操作系统可能还需要数据。
|
||||
|
||||
> 一些早期的操作系统确实只允许特定文件中的特定类型的数据,但是这通常被认为限制太多了。现代方法确实可以使程序变得复杂的多。
|
||||
|
||||
通常,数据就是些很重要的值。你可能接受过培训,认为数据就是某种类型的,比如,文本文件包含文本,图像文件包含图片,等等。说实话,这只是你的想法而已。计算机上的全部数据都是二进制数字,重要的是我们选择用什么来解释这些数据。在这个例子中,我们会用一个闪灯序列作为数据保存下来。
|
||||
|
||||
在 `main.s` 结束处复制下面的代码:
|
||||
|
||||
```
|
||||
.section .data %定义 .data 段
|
||||
.align 2 %对齐
|
||||
pattern: %定义整形变量
|
||||
.int 0b11111111101010100010001000101010
|
||||
```
|
||||
|
||||
> `.align num` 确保下一行代码的地址是 2^num 的整数倍。
|
||||
|
||||
> `.int val` 输出数值 `val`。
|
||||
|
||||
要区分数据和代码,我们将数据都放在 `.data` 区域。我已经将该区域包含在操作系统的内存布局图。我选择将数据放到代码后面。将我们的指令和数据分开保存的原因是,如果最后我们在自己的操作系统上实现一些安全措施,我们就需要知道代码的那些部分是可以执行的,而那些部分是不行的。
|
||||
|
||||
我在这里使用了两个新命令 `.align` 和 `.int`。`.align` 保证接下来的数据是按照 2 的乘方对齐的。在这个里,我使用 `.align 2` ,意味着数据最终存放的地址是 2^2=4 的整数倍。这个操作是很重要的,因为我们用来读取内存的指令 `ldr` 要求内存地址是 4 的倍数。
|
||||
|
||||
命令 `.int` 直接复制它后面的常量到输出。这意味着 11111111101010100010001000101010<sub>2</sub> 将会被存放到输出,所以该标签模式实际是将这段数据标识为模式。
|
||||
|
||||
> 关于数据的一个挑战是寻找一个高效和有用的展示形式。这种保存一个开、关的时间单元的序列的方式,运行起来很容易,但是将很难编辑,因为摩尔斯电码的 `-` 或 `.` 样式丢失了。
|
||||
|
||||
如我提到的,数据可以代表你想要的所有东西。在这里我编码了摩尔斯电码的 SOS 序列,对于不熟悉的人,就是 `...---...`。我使用 0 表示一个时间单元的 LED 灭灯,而 1 表示一个时间单元的 LED 亮。这样,我们可以像这样编写一些代码在数据中显示一个序列,然后要显示不同序列,我们所有需要做的就是修改这段数据。下面是一个非常简单的例子,操作系统必须一直执行这段程序,解释和展示数据。
|
||||
|
||||
复制下面几行到 `main.s` 中的标记 `loop$` 之前。
|
||||
|
||||
```
|
||||
ptrn .req r4 %重命名 r4 为 ptrn
|
||||
ldr ptrn,=pattern %加载 pattern 的地址到 ptrn
|
||||
ldr ptrn,[ptrn] %加载地址 ptrn 所在内存的值
|
||||
seq .req r5 %重命名 r5 为 seq
|
||||
mov seq,#0 %seq 赋值为 0
|
||||
```
|
||||
|
||||
这段代码加载 `pattrern` 到寄存器 `r4`,并加载 0 到寄存器 `r5`。`r5` 将是我们的序列位置,所以我们可以追踪我们已经展示了多少个 `pattern`。
|
||||
|
||||
如果 `pattern` 的当前位置是 1 且仅有一个 1,下面的代码将非零值放入 `r1`。
|
||||
|
||||
```
|
||||
mov r1,#1 %加载1到 r1
|
||||
lsl r1,seq %对r1 的值逻辑左移 seq 次
|
||||
and r1,ptrn %按位与
|
||||
```
|
||||
|
||||
这段代码对你调用 `SetGpio` 很有用,它必须有一个非零值来关掉 LED,而一个 0 值会打开 LED。
|
||||
|
||||
现在修改 `main.s` 中你的全部代码,这样代码中每次循环会根据当前的序列数设置 LED,等待 250000 毫秒(或者其他合适的延时),然后增加序列数。当这个序列数到达 32 就需要返回 0。看看你是否能实现这个功能,作为额外的挑战,也可以试着只使用一条指令。
|
||||
|
||||
### 2、当你玩得开心时,时间过得很快
|
||||
|
||||
你现在准备好在树莓派上实验。应该闪烁一串包含 3 个短脉冲,3 个长脉冲,然后 3 个短脉冲的序列。在一次延时之后,这种模式应该重复。如果这不工作,请查看我们的问题页。
|
||||
|
||||
一旦它工作,祝贺你已经抵达 OK 系列教程的结束点。
|
||||
|
||||
在这个系列我们学习了汇编代码,GPIO 控制器和系统定时器。我们已经学习了函数和 ABI,以及几个基础的操作系统原理,已经关于数据的知识。
|
||||
|
||||
你现在已经可以准备学习下面几个更高级的课程的某一个。
|
||||
|
||||
* [Screen][2] 系列是接下来的,会教你如何通过汇编代码使用屏幕。
|
||||
* [Input][3] 系列教授你如何使用键盘和鼠标。
|
||||
|
||||
到现在,你已经有了足够的信息来制作操作系统,用其它方法和 GPIO 交互。如果你有任何机器人工具,你可能会想尝试编写一个通过 GPIO 管脚控制的机器人操作系统。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok05.html
|
||||
|
||||
作者:[Robert Mullins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[ezio](https://github.com/oska874)
|
||||
校对:[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-10526-1.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input01.html
|
115
published/20150513 XML vs JSON.md
Normal file
115
published/20150513 XML vs JSON.md
Normal file
@ -0,0 +1,115 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wwhio)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10515-1.html)
|
||||
[#]: subject: (XML vs JSON)
|
||||
[#]: via: (https://www.cs.tufts.edu/comp/150IDS/final_papers/tstras01.1/FinalReport/FinalReport.html)
|
||||
[#]: author: (TOM STRASSNER tomstrassner@gmail.com)
|
||||
|
||||
XML 与 JSON 优劣对比
|
||||
======
|
||||
|
||||
### 简介
|
||||
|
||||
XML 和 JSON 是现今互联网中最常用的两种数据交换格式。XML 格式由 W3C 于 1996 年提出。JSON 格式由 Douglas Crockford 于 2002 年提出。虽然这两种格式的设计目标并不相同,但它们常常用于同一个任务,也就是数据交换中。XML 和 JSON 的文档都很完善([RFC 7159][1]、[RFC 4825][2]),且都同时具有<ruby>人类可读性<rt>human-readable</rt></ruby>和<ruby>机器可读性<rt>machine-readable</rt></ruby>。这两种格式并没有哪一个比另一个更强,只是各自适用的领域不用。(LCTT 译注:W3C 是[互联网联盟](https://www.w3.org/),制定了各种 Web 相关的标准,如 HTML、CSS 等。Douglas Crockford 除了制定了 JSON 格式,还致力于改进 JavaScript,开发了 JavaScript 相关工具 [JSLint](http://jslint.com/) 和 [JSMin](http://www.crockford.com/javascript/jsmin.html))
|
||||
|
||||
### XML 的优点
|
||||
|
||||
XML 与 JSON 相比有很多优点。二者间最大的不同在于 XML 可以通过在标签中添加属性这一简单的方法来存储<ruby>元数据<rt>metadata</rt></ruby>。而使用 JSON 时需要创建一个对象,把元数据当作对象的成员来存储。虽然二者都能达到存储元数据的目的,但在这一情况下 XML 往往是更好的选择,因为 JSON 的表达形式会让客户端程序开发人员误以为要将数据转换成一个对象。举个例子,如果你的 C++ 程序需要使用 JSON 格式发送一个附带元数据的整型数据,需要创建一个对象,用对象中的一个<ruby>名称/值对<rt>name/value pair</rt></ruby>来记录整型数据的值,再为每一个附带的属性添加一个名称/值对。接收到这个 JSON 的程序在读取后很可能把它当成一个对象,可事实并不是这样。虽然这是使用 JSON 传递元数据的一种变通方法,但他违背了 JSON 的核心理念:“<ruby>JSON 的结构与常规的程序语言中的结构相对应,而无需修改。<rt>JSON's structures look like conventional programming language structures. No restructuring is necessary.</rt></ruby>”[^2]
|
||||
|
||||
虽然稍后我会说这也是 XML 的一个缺点,但 XML 中对命名冲突、<ruby>前缀<rt>prefix</rt></ruby>的处理机制赋予了它 JSON 所不具备的能力。程序员们可以通过前缀来把统一名称给予两个不同的实体。[^1] 当不同的实体在客户端中使用的名称相同时,这一特性会非常有用。
|
||||
|
||||
XML 的另一个优势在于大多数的浏览器可以把它以<ruby>具有高可读性和强组织性的方式<rt>highly readable and organized way</rt></ruby>展现给用户。XML 的树形结构让它易于结构化,浏览器也让用户可以自行展开或折叠树中的元素,这简直就是调试的福音。
|
||||
|
||||
XML 对比 JSON 有一个很重要的优势就是它可以记录<ruby>混合内容<rt>mixed content</rt></ruby>。例如在 XML 中处理包含结构化标记的字符串时,程序员们只要把带有标记的文本放在一个标签内就可以了。可因为 JSON 只包含数据,没有用于指明标签的简单方式,虽然可以使用处理元数据的解决方法,但这总有点滥用之嫌。
|
||||
|
||||
### JSON 的优点
|
||||
|
||||
JSON 自身也有很多优点。其中最显而易见的一点就是 JSON 比 XML 简洁得多。因为 XML 中需要打开和关闭标签,而 JSON 使用名称/值对表示数据,使用简单的 `{` 和 `}` 来标记对象,`[` 和 `]` 来标记数组,`,` 来表示数据的分隔,`:` 表示名称和值的分隔。就算是使用 gzip 压缩,JSON 还是比 XML 要小,而且耗时更少。[^6] 正如 Sumaray 和 Makki 在实验中指出的那样,JSON 在很多方面都比 XML 更具优势,得出同样结果的还有 Nurseitov、Paulson、Reynolds 和 Izurieta。首先,由于 JSON 文件天生的简洁性,与包含相同信息的 XML 相比,JSON 总是更小,这意味着更快的传输和处理速度。第二,在不考虑大小的情况下,两组研究 [^3] [^4] 表明使用 JSON 执行序列化和反序列化的速度显著优于使用 XML。第三,后续的研究指出 JSON 的处理在 CPU 资源的使用上也优于 XML。研究人员发现 JSON 在总体上使用的资源更少,其中更多的 CPU 资源消耗在用户空间,系统空间消耗的 CPU 资源较少。这一实验是在 RedHat 的设备上进行的,RedHat 表示更倾向于在用户空间使用 CPU 资源。[^3a] 不出意外,Sumaray 和 Makki 在研究里还说明了在移动设备上 JSON 的性能也优于 XML。[^4a] 这是有道理的,因为 JSON 消耗的资源更少,而移动设备的性能也更弱。
|
||||
|
||||
JSON 的另一个优点在于其对对象和数组的表述和<ruby>宿主语言<rt>host language</rt></ruby>中的数据结构相对应,例如<ruby>对象<rt>object</rt></ruby>、<ruby>记录<rt>record</rt></ruby>、<ruby>结构体<rt>struct</rt></ruby>、<ruby>字典<rt>dictionary</rt></ruby>、<ruby>哈希表<rt>hash table</rt></ruby>、<ruby>键值列表<rt>keyed list</rt></ruby>还有<ruby>数组<rt>array</rt></ruby>、<ruby>向量<rt>vector</rt></ruby>、<ruby>列表<rt>list</rt></ruby>,以及对象组成的数组等等。[^2a] 虽然 XML 里也能表达这些数据结构,也只需调用一个函数就能完成解析,而往往需要更多的代码才能正确的完成 XML 的序列化和反序列化处理。而且 XML 对于人类来说不如 JSON 那么直观,XML 标准缺乏对象、数组的标签的明确定义。当结构化的标记可以替代嵌套的标签时,JSON 的优势极为突出。JSON 中的花括号和中括号则明确表示了数据的结构,当然这一优势也包含前文中的问题,在表示元数据时 JSON 不如 XML 准确。
|
||||
|
||||
虽然 XML 支持<ruby>命名空间<rt>namespace</rt></ruby>与<ruby>前缀<rt>prefix</rt></ruby>,但这不代表 JSON 没有处理命名冲突的能力。比起 XML 的前缀,它处理命名冲突的方式更简洁,在程序中的处理也更自然。在 JSON 里,每一个对象都在它自己的命名空间中,因此不同对象内的元素名称可以随意重复。在大多数编程语言中,不同的对象中的成员可以包含相同的名字,所以 JSON 根据对象进行名称区分的规则在处理时更加自然。
|
||||
|
||||
也许 JSON 比 XML 更优的部分是因为 JSON 是 JavaScript 的子集,所以在 JavaScript 代码中对它的解析或封装都非常的自然。虽然这看起来对 JavaScript 程序非常有用,而其他程序则不能直接从中获益,可实际上这一问题已经被很好的解决了。现在 JSON 的网站的列表上展示了 64 种不同语言的 175 个工具,它们都实现了处理 JSON 所需的功能。虽然我不能评价大多数工具的质量,但它们的存在明确了开发者社区拥抱 JSON 这一现象,而且它们切实简化了在不同平台使用 JSON 的难度。
|
||||
|
||||
### 二者的动机
|
||||
|
||||
简单地说,XML 的目标是标记文档。这和 JSON 的目标想去甚远,所以只要用得到 XML 的地方就尽管用。它使用树形的结构和包含语义的文本来表达混合内容以实现这一目标。在 XML 中可以表示数据的结构,但这并不是它的长处。
|
||||
|
||||
JSON 的目标是用于数据交换的一种结构化表示。它直接使用对象、数组、数字、字符串、布尔值这些元素来达成这一目标。这完全不同于文档标记语言。正如上面说的那样,JSON 没有原生支持<ruby>混合内容<rt>mixed content</rt></ruby>的记录。
|
||||
|
||||
### 软件
|
||||
|
||||
这些主流的开放 API 仅提供 XML:<ruby>亚马逊产品广告 API<rt>Amazon Product Advertising API</rt></ruby>。
|
||||
|
||||
这些主流 API 仅提供 JSON:<ruby>脸书图 API<rt>Facebook Graph API</rt></ruby>、<ruby>谷歌地图 API<rt>Google Maps API</rt></ruby>、<ruby>推特 API<rt>Twitter API</rt></ruby>、AccuWeather API、Pinterest API、Reddit API、Foursquare API。
|
||||
|
||||
这些主流 API 同时提供 XML 和 JSON:<ruby>谷歌云存储<rt>Google Cloud Storage</rt></ruby>、<ruby>领英 API<rt>Linkedin API</rt></ruby>、Flickr API。
|
||||
|
||||
根据<ruby>可编程网络<rt>Programmable Web</rt></ruby> [^9] 的数据,最流行的 10 个 API 中只有一个是仅提供 XML 且不支持 JSON 的。其他的要么同时支持 XML 和 JSON,要么只支持 JSON。这表明了大多数应用开发者都更倾向于使用支持 JSON 的 API,原因大概是 JSON 更快的处理速度与良好口碑,加之与 XML 相比更加轻量。此外,大多数 API 只是传递数据而非文档,所以 JSON 更加合适。例如 Facebook 的重点在于用户的交流与帖子,谷歌地图则主要处理坐标和地图信息,AccuWeather 就只传递天气数据。总之,虽然不能说天气 API 在使用时究竟是 JSON 用的多还是 XML 用的多,但是趋势明确偏向了 JSON。[^10] [^11]
|
||||
|
||||
这些主流的桌面软件仍然只是用 XML:Microsoft Word、Apache OpenOffice、LibraOffice。
|
||||
|
||||
因为这些软件需要考虑引用、格式、存储等等,所以比起 JSON,XML 优势更大。另外,这三款程序都支持混合内容,而 JSON 在这一点上做得并不如 XML 好。举例说明,当用户使用 Microsoft Word 编辑一篇论文时,用户需要使用不同的文字字形、文字大小、文字颜色、页边距、段落格式等,而 XML 结构化的组织形式与标签属性生来就是为了表达这些信息的。
|
||||
|
||||
这些主流的数据库支持 XML:IBM DB2、Microsoft SQL Server、Oracle Database、PostgresSQL、BaseX、eXistDB、MarkLogic、MySQL。
|
||||
|
||||
这些是支持 JSON 的主流数据库:MongoDB、CouchDB、eXistDB、Elastisearch、BaseX、MarkLogic、OrientDB、Oracle Database、PostgreSQL、Riak。
|
||||
|
||||
在很长一段时间里,SQL 和关系型数据库统治着整个数据库市场。像<ruby>甲骨文<rt>Oracle</rt></ruby>和<ruby>微软<rt>Microsoft</rt></ruby>这样的软件巨头都提供这类数据库,然而近几年 NoSQL 数据库正逐步受到开发者的青睐。也许是正巧碰上了 JSON 的普及,大多数 NoSQL 数据库都支持 JSON,像 MongoDB、CouchDB 和 Riak 这样的数据库甚至使用 JSON 来存储数据。这些数据库有两个重要的特性是它们适用于现代网站:一是它们与关系型数据库相比<ruby>更容易扩展<rt>more scalable</rt></ruby>;二是它们设计的目标就是 web 运行所需的核心组件。[^10a] 由于 JSON 更加轻量,又是 JavaScript 的子集,所以很适合 NoSQL 数据库,并且让这两个品质更容易实现。此外,许多旧的关系型数据库增加了 JSON 支持,例如 Oracle Database 和 PostgreSQL。由于 XML 与 JSON 间的转换比较麻烦,所以大多数开发者会直接在他们的应用里使用 JSON,因此开发数据库的公司才有支持 JSON 的理由。(LCTT 译注:NoSQL 是对不同于传统的关系数据库的数据库管理系统的统称。[参考来源](https://zh.wikipedia.org/wiki/NoSQL)) [^7]
|
||||
|
||||
### 未来
|
||||
|
||||
对互联网的种种变革中,最让人期待的便是<ruby>物联网<rt>Internet of Things</rt></ruby>(IoT)。这会给互联网带来大量计算机之外的设备,例如手表、温度计、电视、冰箱等等。这一势头的发展良好,预期在不久的将来迎来爆发式的增长。据估计,到 2020 年时会有 260 亿 到 2000 亿的物联网设备被接入互联网。[^12] [^13] 几乎所有的物联网设备都是小型设备,因此性能比笔记本或台式电脑要弱很多,而且大多数都是嵌入式系统。因此,当它们需要与互联网上的系统交换数据时,更轻量、更快速的 JSON 自然比 XML 更受青睐。[^10b] 受益于 JSON 在 web 上的快速普及,与 XML 相比,这些新的物联网设备更有可能从使用 JSON 中受益。这是一个典型的梅特卡夫定律的例子,无论是 XML 还是 JSON,抑或是什么其他全新的格式,现存的设备和新的设备都会从支持最广泛使用的格式中受益。
|
||||
|
||||
Node.js 是一款服务器端的 JavaScript 框架,随着她的诞生与快速成长,与 MongoDB 等 NoSQL 数据库一起,让全栈使用 JavaScript 开发成为可能。这些都预示着 JSON 光明的未来,这些软件的出现让 JSON 运用在全栈开发的每一个环节成为可能,这将使应用更加轻量,响应更快。这也是任何应用的追求之一,所以,全栈使用 JavaScript 的趋势在不久的未来都不会消退。[^10c]
|
||||
|
||||
此外,另一个应用开发的趋势是从 SOAP 转向 REST。[^11a] [^15] [^16] XML 和 JSON 都可以用于 REST,可 SOAP 只能使用 XML。
|
||||
|
||||
从这些趋势中可以推断,JSON 的发展将统一 Web 的信息交换格式,XML 的使用率将继续降低。虽然不应该把 JSON 吹过头了,因为 XML 在 Web 中的使用依旧很广,而且它还是 SOAP 的唯一选择,可考虑到 SOAP 到 REST 的迁移,NoSQL 数据库和全栈 JavaScript 的兴起,JSON 卓越的性能,我相信 JSON 很快就会在 Web 开发中超过 XML。至于其他领域,XML 比 JSON 更好的情况并不多。
|
||||
|
||||
|
||||
### 角注
|
||||
|
||||
[^1]: [XML Tutorial](http://www.w3schools.com/xml/default.asp)
|
||||
[^2]: [Introducing JSON](http://www.json.org/)
|
||||
[^2a]: [Introducing JSON](http://www.json.org/)
|
||||
[^3]: [Comparison of JSON and XML Data Interchange Formats: A Case Study](http://www.cs.montana.edu/izurieta/pubs/caine2009.pdf)
|
||||
[^3a]: [Comparison of JSON and XML Data Interchange Formats: A Case Study](http://www.cs.montana.edu/izurieta/pubs/caine2009.pdf)
|
||||
[^4]: [A comparison of data serialization formats for optimal efficiency on a mobile platform](http://dl.acm.org/citation.cfm?id=2184810)
|
||||
[^4a]: [A comparison of data serialization formats for optimal efficiency on a mobile platform](http://dl.acm.org/citation.cfm?id=2184810)
|
||||
[^5]: [JSON vs. XML: The Debate](http://ajaxian.com/archives/json-vs-xml-the-debate)
|
||||
[^6]: [JSON vs. XML: Some hard numbers about verbosity](http://www.codeproject.com/Articles/604720/JSON-vs-XML-Some-hard-numbers-about-verbosity)
|
||||
[^7]: [How JSON sparked NoSQL -- and will return to the RDBMS fold](http://www.infoworld.com/article/2608293/nosql/how-json-sparked-nosql----and-will-return-to-the-rdbms-fold.html)
|
||||
[^8]: [Did You Say "JSON Support" in Oracle 12.1.0.2?](https://blogs.oracle.com/OTN-DBA-DEV-Watercooler/entry/did_you_say_json_support)
|
||||
[^9]: [Most Popular APIs: At Least One Will Surprise You](http://www.programmableweb.com/news/most-popular-apis-least-one-will-surprise-you/2014/01/23)
|
||||
[^10]: [Why JSON will continue to push XML out of the picture](https://www.centurylinkcloud.com/blog/post/why-json-will-continue-to-push-xml-out-of-the-picture/)
|
||||
[^10a]: [Why JSON will continue to push XML out of the picture](https://www.centurylinkcloud.com/blog/post/why-json-will-continue-to-push-xml-out-of-the-picture/)
|
||||
[^10b]: [Why JSON will continue to push XML out of the picture](https://www.centurylinkcloud.com/blog/post/why-json-will-continue-to-push-xml-out-of-the-picture/)
|
||||
[^10c]: [Why JSON will continue to push XML out of the picture](https://www.centurylinkcloud.com/blog/post/why-json-will-continue-to-push-xml-out-of-the-picture/)
|
||||
[^11]: [Thousands of APIs Paint a Bright Future for the Web](http://www.webmonkey.com/2011/03/thousand-of-apis-paint-a-bright-future-for-the-web/)
|
||||
[^11a]: [Thousands of APIs Paint a Bright Future for the Web](http://www.webmonkey.com/2011/03/thousand-of-apis-paint-a-bright-future-for-the-web/)
|
||||
[^12]: [A Simple Explanation Of 'The Internet Of Things’](http://www.forbes.com/sites/jacobmorgan/2014/05/13/simple-explanation-internet-things-that-anyone-can-understand/)
|
||||
[^13]: [Proofpoint Uncovers Internet of Things (IoT) Cyberattack](http://www.proofpoint.com/about-us/press-releases/01162014.php)
|
||||
[^14]: [The Internet of Things: New Threats Emerge in a Connected World](http://www.symantec.com/connect/blogs/internet-things-new-threats-emerge-connected-world)
|
||||
[^15]: [3,000 Web APIs: Trends From A Quickly Growing Directory](http://www.programmableweb.com/news/3000-web-apis-trends-quickly-growing-directory/2011/03/08)
|
||||
[^16]: [How REST replaced SOAP on the Web: What it means to you](http://www.infoq.com/articles/rest-soap)
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cs.tufts.edu/comp/150IDS/final_papers/tstras01.1/FinalReport/FinalReport.html
|
||||
|
||||
作者:[TOM STRASSNER][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wwhio](https://github.com/wwhio)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: tomstrassner@gmail.com
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://tools.ietf.org/html/rfc7159
|
||||
[2]: https://tools.ietf.org/html/rfc4825
|
@ -0,0 +1,451 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10540-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 6 Screen01)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html)
|
||||
[#]: author: (Alex Chadwick https://www.cl.cam.ac.uk)
|
||||
|
||||
计算机实验室之树莓派:课程 6 屏幕01
|
||||
======
|
||||
|
||||
欢迎来到屏幕系列课程。在本系列中,你将学习在树莓派中如何使用汇编代码控制屏幕,从显示随机数据开始,接着学习显示一个固定的图像和显示文本,然后格式化数字为文本。假设你已经完成了 OK 系列课程的学习,所以在本系列中出现的有些知识将不再重复。
|
||||
|
||||
第一节的屏幕课程教你一些关于图形的基础理论,然后用这些理论在屏幕或电视上显示一个图案。
|
||||
|
||||
### 1、入门
|
||||
|
||||
预期你已经完成了 OK 系列的课程,以及那个系列课程中在 `gpio.s` 和 `systemTimer.s` 文件中调用的函数。如果你没有完成这些,或你喜欢完美的实现,可以去下载 `OK05.s` 解决方案。在这里也要使用 `main.s` 文件中从开始到包含 `mov sp,#0x8000` 的这一行之前的代码。请删除这一行以后的部分。
|
||||
|
||||
### 2、计算机图形
|
||||
|
||||
正如你所认识到的,从根本上来说,计算机是非常愚蠢的。它们只能执行有限数量的指令,仅仅能做一些数学,但是它们也能以某种方式来做很多很多的事情。而在这些事情中,我们目前想知道的是,计算机是如何将一个图像显示到屏幕上的。我们如何将这个问题转换成二进制?答案相当简单;我们为每个颜色设计一些编码方法,然后我们为在屏幕上的每个像素保存一个编码。一个像素就是你的屏幕上的一个非常小的点。如果你离屏幕足够近,你或许能够辨别出你的屏幕上的单个像素,能够看到每个图像都是由这些像素组成的。
|
||||
|
||||
> 将颜色表示为数字有几种方法。在这里我们专注于 RGB 方法,但 HSL 也是很常用的另一种方法。
|
||||
|
||||
随着计算机时代的进步,人们希望显示越来越复杂的图形,于是发明了图形卡的概念。图形卡是你的计算机上用来在屏幕上专门绘制图像的第二个处理器。它的任务就是将像素值信息转换成显示在屏幕上的亮度级别。在现代计算机中,图形卡已经能够做更多更复杂的事情了,比如绘制三维图形。但是在本系列教程中,我们只专注于图形卡的基本使用;从内存中取得像素然后把它显示到屏幕上。
|
||||
|
||||
不管使用哪种方法,现在马上出现的一个问题就是我们使用的颜色编码。这里有几种选择,每个产生不同的输出质量。为了完整起见,我在这里只是简单概述它们。
|
||||
|
||||
| 名字 | 唯一颜色数量 | 描述 | 示例 |
|
||||
| ----------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------- |
|
||||
| 单色 | 2 | 每个像素使用 1 位去保存,其中 1 表示白色,0 表示黑色。 | ![Monochrome image of a bird][1] |
|
||||
| 灰度 | 256 | 每个像素使用 1 个字节去保存,使用 255 表示白色,0 表示黑色,介于这两个值之间的所有值表示这两个颜色的一个线性组合。 | ![Geryscale image of a bird][2] |
|
||||
| 8 色 | 8 | 每个像素使用 3 位去保存,第一位表示红色通道,第二位表示绿色通道,第三位表示蓝色通道。 | ![8 colour image of a bird][3] |
|
||||
| 低色值 | 256 | 每个像素使用 8 位去保存,前三位表示红色通道的强度,接下来的三位表示绿色通道的强度,最后两位表示蓝色通道的强度。 | ![Low colour image of a bird][4] |
|
||||
| 高色值 | 65,536 | 每个像素使用 16 位去保存,前五位表示红色通道的强度,接下来的六位表示绿色通道的强度,最后的五位表示蓝色通道的强度。 | ![High colour image of a bird][5] |
|
||||
| 真彩色 | 16,777,216 | 每个像素使用 24 位去保存,前八位表示红色通道,第二个八位表示绿色通道,最后八位表示蓝色通道。 | ![True colour image of a bird][6] |
|
||||
| RGBA32 | 16,777,216 带 256 级透明度 | 每个像素使用 32 位去保存,前八位表示红色通道,第二个八位表示绿色通道,第三个八位表示蓝色通道。只有一个图像绘制在另一个图像的上方时才考虑使用透明通道,值为 0 时表示下面图像的颜色,值为 255 时表示上面这个图像的颜色,介于这两个值之间的所有值表示这两个图像颜色的混合。 ||
|
||||
|
||||
> 不过这里的一些图像只用了很少的颜色,因为它们使用了一个叫空间抖动的技术。这允许它们以很少的颜色仍然能表示出非常好的图像。许多早期的操作系统就使用了这种技术。
|
||||
|
||||
在本教程中,我们将从使用高色值开始。这样你就可以看到图像的构成,它的形成过程清楚,图像质量好,又不像真彩色那样占用太多的空间。也就是说,显示一个比较小的 800x600 像素的图像,它只需要小于 1 MiB 的空间。它另外的好处是它的大小是 2 次幂的倍数,相比真彩色这将极大地降低了获取信息的复杂度。
|
||||
|
||||
树莓派和它的图形处理器有一种特殊而奇怪的关系。在树莓派上,首先运行的事实上是图形处理器,它负责启动主处理器。这是很不常见的。最终它不会有太大的差别,但在许多交互中,它经常给人感觉主处理器是次要的,而图形处理器才是主要的。在树莓派上这两者之间依靠一个叫 “邮箱” 的东西来通讯。它们中的每一个都可以为对方投放邮件,这个邮件将在未来的某个时刻被对方收集并处理。我们将使用这个邮箱去向图形处理器请求一个地址。这个地址将是一个我们在屏幕上写入像素颜色信息的位置,我们称为帧缓冲,图形卡将定期检查这个位置,然后更新屏幕上相应的像素。
|
||||
|
||||
> 保存<ruby>帧缓冲<rt>frame buffer</rt></ruby>给计算机带来了很大的内存负担。基于这种原因,早期计算机经常作弊,比如,保存一屏幕文本,在每次单独刷新时,它只绘制刷新了的字母。
|
||||
|
||||
### 3、编写邮差程序
|
||||
|
||||
接下来我们做的第一件事情就是编写一个“邮差”程序。它有两个方法:`MailboxRead`,从寄存器 `r0` 中的邮箱通道读取一个消息。而 `MailboxWrite`,将寄存器 `r0` 中的头 28 位的值写到寄存器 `r1` 中的邮箱通道。树莓派有 7 个与图形处理器进行通讯的邮箱通道。但仅第一个对我们有用,因为它用于协调帧缓冲。
|
||||
|
||||
> 消息传递是组件间通讯时使用的常见方法。一些操作系统在程序之间使用虚拟消息进行通讯。
|
||||
|
||||
下列的表和示意图描述了邮箱的操作。
|
||||
|
||||
表 3.1 邮箱地址
|
||||
|
||||
| 地址 | 大小 / 字节 | 名字 | 描述 | 读 / 写 |
|
||||
| ---- | ---------- | ------------ | -------------------- | ------ |
|
||||
| 2000B880 | 4 | Read | 接收邮件 | R |
|
||||
| 2000B890 | 4 | Poll | 不检索接收 | R |
|
||||
| 2000B894 | 4 | Sender |发送者信息 | R |
|
||||
| 2000B898 | 4 | Status | 信息 | R |
|
||||
| 2000B89C | 4 | Configuration | 设置 | RW |
|
||||
| 2000B8A0 | 4 | Write | 发送邮件 | W |
|
||||
|
||||
为了给指定的邮箱发送一个消息:
|
||||
|
||||
1. 发送者等待,直到 `Status` 字段的头一位为 0。
|
||||
2. 发送者写入到 `Write`,低 4 位是要发送到的邮箱,高 28 位是要写入的消息。
|
||||
|
||||
为了读取一个消息:
|
||||
|
||||
1. 接收者等待,直到 `Status` 字段的第 30 位为 0。
|
||||
2. 接收者读取消息。
|
||||
3. 接收者确认消息来自正确的邮箱,否则再次重试。
|
||||
|
||||
如果你觉得有信心,你现在已经有足够的信息去写出我们所需的两个方法。如果没有信心,请继续往下看。
|
||||
|
||||
与以前一样,我建议你实现的第一个方法是获取邮箱区域的地址。
|
||||
|
||||
```assembly
|
||||
.globl GetMailboxBase
|
||||
GetMailboxBase:
|
||||
ldr r0,=0x2000B880
|
||||
mov pc,lr
|
||||
```
|
||||
|
||||
发送程序相对简单一些,因此我们将首先去实现它。随着你的方法越来越复杂,你需要提前去规划它们。规划它们的一个好的方式是写出一个简单步骤列表,详细地列出你需要做的事情,像下面一样。
|
||||
|
||||
1. 我们的输入将要写什么(`r0`),以及写到什么邮箱(`r1`)。我们必须验证邮箱的真实性,以及它的低 4 位的值是否为 0。不要忘了验证输入。
|
||||
2. 使用 `GetMailboxBase` 去检索地址。
|
||||
3. 读取 `Status` 字段。
|
||||
4. 检查头一位是否为 0。如果不是,回到第 3 步。
|
||||
5. 将写入的值和邮箱通道组合到一起。
|
||||
6. 写入到 `Write`。
|
||||
|
||||
我们来按顺序写出它们中的每一步。
|
||||
|
||||
1. 这将实现我们验证 `r0` 和 `r1` 的目的。`tst` 是通过计算两个操作数的逻辑与来比较两个操作数的函数,然后将结果与 0 进行比较。在本案例中,它将检查在寄存器 `r0` 中的输入的低 4 位是否为全 0。
|
||||
|
||||
```assembly
|
||||
.globl MailboxWrite
|
||||
MailboxWrite:
|
||||
tst r0,#0b1111
|
||||
movne pc,lr
|
||||
cmp r1,#15
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
> `tst reg,#val` 计算寄存器 `reg` 和 `#val` 的逻辑与,然后将计算结果与 0 进行比较。
|
||||
|
||||
2. 这段代码确保我们不会覆盖我们的值,或链接寄存器,然后调用 `GetMailboxBase`。
|
||||
|
||||
```assembly
|
||||
channel .req r1
|
||||
value .req r2
|
||||
mov value,r0
|
||||
push {lr}
|
||||
bl GetMailboxBase
|
||||
mailbox .req r0
|
||||
```
|
||||
|
||||
3. 这段代码加载当前状态。
|
||||
|
||||
```assembly
|
||||
wait1$:
|
||||
status .req r3
|
||||
ldr status,[mailbox,#0x18]
|
||||
```
|
||||
|
||||
4. 这段代码检查状态字段的头一位是否为 0,如果不为 0,循环回到第 3 步。
|
||||
|
||||
```assembly
|
||||
tst status,#0x80000000
|
||||
.unreq status
|
||||
bne wait1$
|
||||
```
|
||||
|
||||
5. 这段代码将通道和值组合到一起。
|
||||
|
||||
```assembly
|
||||
add value,channel
|
||||
.unreq channel
|
||||
```
|
||||
|
||||
6. 这段代码保存结果到写入字段。
|
||||
|
||||
```assembly
|
||||
str value,[mailbox,#0x20]
|
||||
.unreq value
|
||||
.unreq mailbox
|
||||
pop {pc}
|
||||
```
|
||||
|
||||
`MailboxRead` 的代码和它非常类似。
|
||||
|
||||
1. 我们的输入将从哪个邮箱读取(`r0`)。我们必须要验证邮箱的真实性。不要忘了验证输入。
|
||||
2. 使用 `GetMailboxBase` 去检索地址。
|
||||
3. 读取 `Status` 字段。
|
||||
4. 检查第 30 位是否为 0。如果不为 0,返回到第 3 步。
|
||||
5. 读取 `Read` 字段。
|
||||
6. 检查邮箱是否是我们所要的,如果不是返回到第 3 步。
|
||||
7. 返回结果。
|
||||
|
||||
我们来按顺序写出它们中的每一步。
|
||||
|
||||
1. 这一段代码来验证 `r0` 中的值。
|
||||
|
||||
```assembly
|
||||
.globl MailboxRead
|
||||
MailboxRead:
|
||||
cmp r0,#15
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
2. 这段代码确保我们不会覆盖掉我们的值,或链接寄存器,然后调用 `GetMailboxBase`。
|
||||
|
||||
```assembly
|
||||
channel .req r1
|
||||
mov channel,r0
|
||||
push {lr}
|
||||
bl GetMailboxBase
|
||||
mailbox .req r0
|
||||
```
|
||||
|
||||
3. 这段代码加载当前状态。
|
||||
|
||||
```assembly
|
||||
rightmail$:
|
||||
wait2$:
|
||||
status .req r2
|
||||
ldr status,[mailbox,#0x18]
|
||||
```
|
||||
|
||||
4. 这段代码检查状态字段第 30 位是否为 0,如果不为 0,返回到第 3 步。
|
||||
|
||||
```assembly
|
||||
tst status,#0x40000000
|
||||
.unreq status
|
||||
bne wait2$
|
||||
```
|
||||
|
||||
5. 这段代码从邮箱中读取下一条消息。
|
||||
|
||||
```assembly
|
||||
mail .req r2
|
||||
ldr mail,[mailbox,#0]
|
||||
```
|
||||
|
||||
6. 这段代码检查我们正在读取的邮箱通道是否为提供给我们的通道。如果不是,返回到第 3 步。
|
||||
|
||||
```assembly
|
||||
inchan .req r3
|
||||
and inchan,mail,#0b1111
|
||||
teq inchan,channel
|
||||
.unreq inchan
|
||||
bne rightmail$
|
||||
.unreq mailbox
|
||||
.unreq channel
|
||||
```
|
||||
|
||||
7. 这段代码将答案(邮件的前 28 位)移动到寄存器 `r0` 中。
|
||||
|
||||
```assembly
|
||||
and r0,mail,#0xfffffff0
|
||||
.unreq mail
|
||||
pop {pc}
|
||||
```
|
||||
|
||||
### 4、我心爱的图形处理器
|
||||
|
||||
通过我们新的邮差程序,我们现在已经能够向图形卡上发送消息了。我们应该发送些什么呢?这对我来说可能是个很难找到答案的问题,因为它不是任何线上手册能够找到答案的问题。尽管如此,通过查找有关树莓派的 GNU/Linux,我们能够找出我们需要发送的内容。
|
||||
|
||||
消息很简单。我们描述我们想要的帧缓冲区,而图形卡要么接受我们的请求,给我们返回一个 0,然后用我们写的一个小的调查问卷来填充屏幕;要么发送一个非 0 值,我们知道那表示很遗憾(出错了)。不幸的是,我并不知道它返回的其它数字是什么,也不知道它意味着什么,但我们知道仅当它返回一个 0,才表示一切顺利。幸运的是,对于合理的输入,它总是返回一个 0,因此我们不用过于担心。
|
||||
|
||||
> 由于在树莓派的内存是在图形处理器和主处理器之间共享的,我们能够只发送可以找到我们信息的位置即可。这就是 DMA,许多复杂的设备使用这种技术去加速访问时间。
|
||||
|
||||
为简单起见,我们将提前设计好我们的请求,并将它保存到 `framebuffer.s` 文件的 `.data` 节中,它的代码如下:
|
||||
|
||||
```assembly
|
||||
.section .data
|
||||
.align 4
|
||||
.globl FrameBufferInfo
|
||||
FrameBufferInfo:
|
||||
.int 1024 /* #0 物理宽度 */
|
||||
.int 768 /* #4 物理高度 */
|
||||
.int 1024 /* #8 虚拟宽度 */
|
||||
.int 768 /* #12 虚拟高度 */
|
||||
.int 0 /* #16 GPU - 间距 */
|
||||
.int 16 /* #20 位深 */
|
||||
.int 0 /* #24 X */
|
||||
.int 0 /* #28 Y */
|
||||
.int 0 /* #32 GPU - 指针 */
|
||||
.int 0 /* #36 GPU - 大小 */
|
||||
```
|
||||
|
||||
这就是我们发送到图形处理器的消息格式。第一对两个关键字描述了物理宽度和高度。第二对关键字描述了虚拟宽度和高度。帧缓冲的宽度和高度就是虚拟的宽度和高度,而 GPU 按需要伸缩帧缓冲去填充物理屏幕。如果 GPU 接受我们的请求,接下来的关键字将是 GPU 去填充的参数。它们是帧缓冲每行的字节数,在本案例中它是 `2 × 1024 = 2048`。下一个关键字是每个像素分配的位数。使用了一个 16 作为值意味着图形处理器使用了我们上面所描述的高色值模式。值为 24 是真彩色,而值为 32 则是 RGBA32。接下来的两个关键字是 x 和 y 偏移量,它表示当将帧缓冲复制到屏幕时,从屏幕左上角跳过的像素数目。最后两个关键字是由图形处理器填写的,第一个表示指向帧缓冲的实际指针,第二个是用字节数表示的帧缓冲大小。
|
||||
|
||||
在这里我非常谨慎地使用了一个 `.align 4` 指令。正如前面所讨论的,这样确保了下一行地址的低 4 位是 0。所以,我们可以确保将被放到那个地址上的帧缓冲(`FrameBufferInfo`)是可以发送到图形处理器上的,因为我们的邮箱仅发送低 4 位全为 0 的值。
|
||||
|
||||
> 当设备使用 DMA 时,对齐约束变得非常重要。GPU 预期该消息都是 16 字节对齐的。
|
||||
|
||||
到目前为止,我们已经有了待发送的消息,我们可以写代码去发送它了。通讯将按如下的步骤进行:
|
||||
|
||||
1. 写入 `FrameBufferInfo + 0x40000000` 的地址到邮箱 1。
|
||||
2. 从邮箱 1 上读取结果。如果它是非 0 值,意味着我们没有请求一个正确的帧缓冲。
|
||||
3. 复制我们的图像到指针,这时图像将出现在屏幕上!
|
||||
|
||||
我在步骤 1 中说了一些以前没有提到的事情。我们在发送之前,在帧缓冲地址上加了 `0x40000000`。这其实是一个给 GPU 的特殊信号,它告诉 GPU 应该如何写到结构上。如果我们只是发送地址,GPU 将写到它的回复上,这样不能保证我们可以通过刷新缓存看到它。缓存是处理器使用的值在它们被发送到存储之前保存在内存中的片段。通过加上 `0x40000000`,我们告诉 GPU 不要将写入到它的缓存中,这样将确保我们能够看到变化。
|
||||
|
||||
因为在那里发生很多事情,因此最好将它实现为一个函数,而不是将它以代码的方式写入到 `main.s` 中。我们将要写一个函数 `InitialiseFrameBuffer`,由它来完成所有协调和返回指向到上面提到的帧缓冲数据的指针。为方便起见,我们还将帧缓冲的宽度、高度、位深作为这个方法的输入,这样就很容易地修改 `main.s` 而不必知道协调的细节了。
|
||||
|
||||
再一次,来写下我们要做的详细步骤。如果你有信心,可以略过这一步直接尝试去写函数。
|
||||
|
||||
1. 验证我们的输入。
|
||||
2. 写输入到帧缓冲。
|
||||
3. 发送 `frame buffer + 0x40000000` 的地址到邮箱。
|
||||
4. 从邮箱中接收回复。
|
||||
5. 如果回复是非 0 值,方法失败。我们应该返回 0 去表示失败。
|
||||
6. 返回指向帧缓冲信息的指针。
|
||||
|
||||
现在,我们开始写更多的方法。以下是上面其中一个实现。
|
||||
|
||||
1. 这段代码检查宽度和高度是小于或等于 4096,位深小于或等于 32。这里再次使用了条件运行的技巧。相信自己这是可行的。
|
||||
|
||||
```assembly
|
||||
.section .text
|
||||
.globl InitialiseFrameBuffer
|
||||
InitialiseFrameBuffer:
|
||||
width .req r0
|
||||
height .req r1
|
||||
bitDepth .req r2
|
||||
cmp width,#4096
|
||||
cmpls height,#4096
|
||||
cmpls bitDepth,#32
|
||||
result .req r0
|
||||
movhi result,#0
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
2. 这段代码写入到我们上面定义的帧缓冲结构中。我也趁机将链接寄存器推入到栈上。
|
||||
|
||||
```assembly
|
||||
fbInfoAddr .req r3
|
||||
push {lr}
|
||||
ldr fbInfoAddr,=FrameBufferInfo
|
||||
str width,[fbInfoAddr,#0]
|
||||
str height,[fbInfoAddr,#4]
|
||||
str width,[fbInfoAddr,#8]
|
||||
str height,[fbInfoAddr,#12]
|
||||
str bitDepth,[fbInfoAddr,#20]
|
||||
.unreq width
|
||||
.unreq height
|
||||
.unreq bitDepth
|
||||
```
|
||||
|
||||
3. `MailboxWrite` 方法的输入是写入到寄存器 `r0` 中的值,并将通道写入到寄存器 `r1` 中。
|
||||
|
||||
```assembly
|
||||
mov r0,fbInfoAddr
|
||||
add r0,#0x40000000
|
||||
mov r1,#1
|
||||
bl MailboxWrite
|
||||
```
|
||||
|
||||
4. `MailboxRead` 方法的输入是写入到寄存器 `r0` 中的通道,而输出是值读数。
|
||||
|
||||
```assembly
|
||||
mov r0,#1
|
||||
bl MailboxRead
|
||||
```
|
||||
|
||||
5. 这段代码检查 `MailboxRead` 方法的结果是否为 0,如果不为 0,则返回 0。
|
||||
|
||||
```assembly
|
||||
teq result,#0
|
||||
movne result,#0
|
||||
popne {pc}
|
||||
```
|
||||
|
||||
6. 这是代码结束,并返回帧缓冲信息地址。
|
||||
|
||||
```assembly
|
||||
mov result,fbInfoAddr
|
||||
pop {pc}
|
||||
.unreq result
|
||||
.unreq fbInfoAddr
|
||||
```
|
||||
|
||||
### 5、在一帧中一行之内的一个像素
|
||||
|
||||
到目前为止,我们已经创建了与图形处理器通讯的方法。现在它已经能够给我们返回一个指向到帧缓冲的指针去绘制图形了。我们现在来绘制一个图形。
|
||||
|
||||
第一示例中,我们将在屏幕上绘制连续的颜色。它看起来并不漂亮,但至少能说明它在工作。我们如何才能在帧缓冲中设置每个像素为一个连续的数字,并且要持续不断地这样做。
|
||||
|
||||
将下列代码复制到 `main.s` 文件中,并放置在 `mov sp,#0x8000` 行之后。
|
||||
|
||||
```assembly
|
||||
mov r0,#1024
|
||||
mov r1,#768
|
||||
mov r2,#16
|
||||
bl InitialiseFrameBuffer
|
||||
```
|
||||
|
||||
这段代码使用了我们的 `InitialiseFrameBuffer` 方法,简单地创建了一个宽 1024、高 768、位深为 16 的帧缓冲区。在这里,如果你愿意可以尝试使用不同的值,只要整个代码中都一样就可以。如果图形处理器没有给我们创建好一个帧缓冲区,这个方法将返回 0,我们最好检查一下返回值,如果出现返回值为 0 的情况,我们打开 OK LED 灯。
|
||||
|
||||
```assembly
|
||||
teq r0,#0
|
||||
bne noError$
|
||||
|
||||
mov r0,#16
|
||||
mov r1,#1
|
||||
bl SetGpioFunction
|
||||
mov r0,#16
|
||||
mov r1,#0
|
||||
bl SetGpio
|
||||
|
||||
error$:
|
||||
b error$
|
||||
|
||||
noError$:
|
||||
fbInfoAddr .req r4
|
||||
mov fbInfoAddr,r0
|
||||
```
|
||||
|
||||
现在,我们已经有了帧缓冲信息的地址,我们需要取得帧缓冲信息的指针,并开始绘制屏幕。我们使用两个循环来做实现,一个走行,一个走列。事实上,树莓派中的大多数应用程序中,图片都是以从左到右然后从上到下的顺序来保存的,因此我们也按这个顺序来写循环。
|
||||
|
||||
```assembly
|
||||
render$:
|
||||
|
||||
fbAddr .req r3
|
||||
ldr fbAddr,[fbInfoAddr,#32]
|
||||
|
||||
colour .req r0
|
||||
y .req r1
|
||||
mov y,#768
|
||||
drawRow$:
|
||||
|
||||
x .req r2
|
||||
mov x,#1024
|
||||
drawPixel$:
|
||||
|
||||
strh colour,[fbAddr]
|
||||
add fbAddr,#2
|
||||
sub x,#1
|
||||
teq x,#0
|
||||
bne drawPixel$
|
||||
|
||||
sub y,#1
|
||||
add colour,#1
|
||||
teq y,#0
|
||||
bne drawRow$
|
||||
|
||||
b render$
|
||||
|
||||
.unreq fbAddr
|
||||
.unreq fbInfoAddr
|
||||
```
|
||||
|
||||
> `strh reg,[dest]` 将寄存器中的低位半个字保存到给定的 `dest` 地址上。
|
||||
|
||||
这是一个很长的代码块,它嵌套了三层循环。为了帮你理清头绪,我们将循环进行缩进处理,这就有点类似于高级编程语言,而汇编器会忽略掉这些用于缩进的 `tab` 字符。我们看到,在这里它从帧缓冲信息结构中加载了帧缓冲的地址,然后基于每行来循环,接着是每行上的每个像素。在每个像素上,我们使用一个 `strh`(保存半个字)命令去保存当前颜色,然后增加地址继续写入。每行绘制完成后,我们增加绘制的颜色号。在整个屏幕绘制完成后,我们跳转到开始位置。
|
||||
|
||||
### 6、看到曙光
|
||||
|
||||
现在,你已经准备好在树莓派上测试这些代码了。你应该会看到一个渐变图案。注意:在第一个消息被发送到邮箱之前,树莓派在它的四个角上一直显示一个渐变图案。如果它不能正常工作,请查看我们的排错页面。
|
||||
|
||||
如果一切正常,恭喜你!你现在可以控制屏幕了!你可以随意修改这些代码去绘制你想到的任意图案。你还可以做更精彩的渐变图案,可以直接计算每个像素值,因为每个像素包含了一个 Y 坐标和 X 坐标。在下一个 [课程 7:Screen 02][7] 中,我们将学习一个更常用的绘制任务:行。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen01.html
|
||||
|
||||
作者:[Alex Chadwick][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://www.cl.cam.ac.uk
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/colour1bImage.png
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/colour8gImage.png
|
||||
[3]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/colour3bImage.png
|
||||
[4]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/colour8bImage.png
|
||||
[5]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/colour16bImage.png
|
||||
[6]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/images/colour24bImage.png
|
||||
[7]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen02.html
|
@ -0,0 +1,437 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10551-1.html)
|
||||
[#]: subject: (Computer Laboratory – Raspberry Pi: Lesson 7 Screen02)
|
||||
[#]: via: (https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen02.html)
|
||||
[#]: author: (Alex Chadwick https://www.cl.cam.ac.uk)
|
||||
|
||||
计算机实验室之树莓派:课程 7 屏幕02
|
||||
======
|
||||
|
||||
屏幕02 课程在屏幕01 的基础上构建,它教你如何绘制线和一个生成伪随机数的小特性。假设你已经有了 [课程 6:屏幕01][1] 的操作系统代码,我们将以它为基础来构建。
|
||||
|
||||
### 1、点
|
||||
|
||||
现在,我们的屏幕已经正常工作了,现在开始去创建一个更实用的图像,是水到渠成的事。如果我们能够绘制出更实用的图形那就更好了。如果我们能够在屏幕上的两点之间绘制一条线,那我们就能够组合这些线绘制出更复杂的图形了。
|
||||
|
||||
我们将尝试用汇编代码去实现它,但在开始时,我们确实需要使用一些其它的函数去辅助。我们需要一个这样的函数,我将调用 `SetPixel` 去修改指定像素的颜色,而在寄存器 `r0` 和 `r1` 中提供输入。如果我们写出的代码可以在任意内存中而不仅仅是屏幕上绘制图形,这将在以后非常有用,因此,我们首先需要一些控制真实绘制位置的方法。我认为实现上述目标的最好方法是,能够有一个内存片段用于保存将要绘制的图形。我应该最终得到的是一个存储地址,它通常指向到自上次的帧缓存结构上。我们将一直在我们的代码中使用这个绘制方法。这样,如果我们想在我们的操作系统的另一部分绘制一个不同的图像,我们就可以生成一个不同结构的地址值,而使用的是完全相同的代码。为简单起见,我们将使用另一个数据片段去控制我们绘制的颜色。
|
||||
|
||||
> 为了绘制出更复杂的图形,一些方法使用一个着色函数而不是一个颜色去绘制。每个点都能够调用着色函数来确定在那里用什么颜色去绘制。
|
||||
|
||||
复制下列代码到一个名为 `drawing.s` 的新文件中。
|
||||
|
||||
```assembly
|
||||
.section .data
|
||||
.align 1
|
||||
foreColour:
|
||||
.hword 0xFFFF
|
||||
|
||||
.align 2
|
||||
graphicsAddress:
|
||||
.int 0
|
||||
|
||||
.section .text
|
||||
.globl SetForeColour
|
||||
SetForeColour:
|
||||
cmp r0,#0x10000
|
||||
movhs pc,lr
|
||||
ldr r1,=foreColour
|
||||
strh r0,[r1]
|
||||
mov pc,lr
|
||||
|
||||
.globl SetGraphicsAddress
|
||||
SetGraphicsAddress:
|
||||
ldr r1,=graphicsAddress
|
||||
str r0,[r1]
|
||||
mov pc,lr
|
||||
```
|
||||
|
||||
这段代码就是我上面所说的一对函数以及它们的数据。我们将在 `main.s` 中使用它们,在绘制图像之前去控制在何处绘制什么内容。
|
||||
|
||||
我们的下一个任务是去实现一个 `SetPixel` 方法。它需要带两个参数,像素的 x 和 y 轴,并且它应该要使用 `graphicsAddress` 和 `foreColour`,我们只定义精确控制在哪里绘制什么图像即可。如果你认为你能立即实现这些,那么去动手实现吧,如果不能,按照我们提供的步骤,按示例去实现它。
|
||||
|
||||
> 构建一个通用方法,比如 `SetPixel`,我们将在它之上构建另一个方法是一个很好的想法。但我们必须要确保这个方法很快,因为我们要经常使用它。
|
||||
|
||||
1. 加载 `graphicsAddress`。
|
||||
2. 检查像素的 x 和 y 轴是否小于宽度和高度。
|
||||
3. 计算要写入的像素地址(提示:`frameBufferAddress +(x + y * 宽度)* 像素大小`)
|
||||
4. 加载 `foreColour`。
|
||||
5. 保存到地址。
|
||||
|
||||
上述步骤实现如下:
|
||||
|
||||
1、加载 `graphicsAddress`。
|
||||
|
||||
```assembly
|
||||
.globl DrawPixel
|
||||
DrawPixel:
|
||||
px .req r0
|
||||
py .req r1
|
||||
addr .req r2
|
||||
ldr addr,=graphicsAddress
|
||||
ldr addr,[addr]
|
||||
```
|
||||
|
||||
2、记住,宽度和高度被各自保存在帧缓冲偏移量的 0 和 4 处。如有必要可以参考 `frameBuffer.s`。
|
||||
|
||||
```assembly
|
||||
height .req r3
|
||||
ldr height,[addr,#4]
|
||||
sub height,#1
|
||||
cmp py,height
|
||||
movhi pc,lr
|
||||
.unreq height
|
||||
|
||||
width .req r3
|
||||
ldr width,[addr,#0]
|
||||
sub width,#1
|
||||
cmp px,width
|
||||
movhi pc,lr
|
||||
```
|
||||
|
||||
3、确实,这段代码是专用于高色值帧缓存的,因为我使用一个逻辑左移操作去计算地址。你可能希望去编写一个不需要专用的高色值帧缓冲的函数版本,记得去更新 `SetForeColour` 的代码。它实现起来可能更复杂一些。
|
||||
|
||||
```assembly
|
||||
ldr addr,[addr,#32]
|
||||
add width,#1
|
||||
mla px,py,width,px
|
||||
.unreq width
|
||||
.unreq py
|
||||
add addr, px,lsl #1
|
||||
.unreq px
|
||||
```
|
||||
|
||||
> `mla dst,reg1,reg2,reg3` 将寄存器 `reg1` 和 `reg2` 中的值相乘,然后将结果与寄存器 `reg3` 中的值相加,并将结果的低 32 位保存到 `dst` 中。
|
||||
|
||||
4、这是专用于高色值的。
|
||||
|
||||
```assembly
|
||||
fore .req r3
|
||||
ldr fore,=foreColour
|
||||
ldrh fore,[fore]
|
||||
```
|
||||
|
||||
5、这是专用于高色值的。
|
||||
|
||||
```assembly
|
||||
strh fore,[addr]
|
||||
.unreq fore
|
||||
.unreq addr
|
||||
mov pc,lr
|
||||
```
|
||||
|
||||
### 2、线
|
||||
|
||||
问题是,线的绘制并不是你所想像的那么简单。到目前为止,你必须认识到,编写一个操作系统时,几乎所有的事情都必须我们自己去做,绘制线条也不例外。我建议你们花点时间想想如何在任意两点之间绘制一条线。
|
||||
|
||||
我估计大多数的策略可能是去计算线的梯度,并沿着它来绘制。这看上去似乎很完美,但它事实上是个很糟糕的主意。主要问题是它涉及到除法,我们知道在汇编中,做除法很不容易,并且还要始终记录小数,这也很困难。事实上,在这里,有一个叫布鲁塞姆的算法,它非常适合汇编代码,因为它只使用加法、减法和位移运算。
|
||||
|
||||
> 在我们日常编程中,我们对像除法这样的运算通常懒得去优化。但是操作系统不同,它必须高效,因此我们要始终专注于如何让事情做的尽可能更好。
|
||||
|
||||
.
|
||||
|
||||
> 我们从定义一个简单的直线绘制算法开始,代码如下:
|
||||
>
|
||||
> ```matlab
|
||||
> /* 我们希望从 (x0,y0) 到 (x1,y1) 去绘制一条线,只使用一个函数 setPixel(x,y),它的功能是在给定的 (x,y) 上绘制一个点。 */
|
||||
>
|
||||
> if x1 > x0 then
|
||||
>
|
||||
> set deltax to x1 - x0
|
||||
> set stepx to +1
|
||||
>
|
||||
> otherwise
|
||||
>
|
||||
> set deltax to x0 - x1
|
||||
> set stepx to -1
|
||||
>
|
||||
> end if
|
||||
>
|
||||
> if y1 > y0 then
|
||||
>
|
||||
> set deltay to y1 - y0
|
||||
> set stepy to +1
|
||||
>
|
||||
> otherwise
|
||||
>
|
||||
> set deltay to y0 - y1
|
||||
> set stepy to -1
|
||||
>
|
||||
> end if
|
||||
>
|
||||
> if deltax > deltay then
|
||||
>
|
||||
> set error to 0
|
||||
> until x0 = x1 + stepx
|
||||
>
|
||||
> setPixel(x0, y0)
|
||||
> set error to error + deltax ÷ deltay
|
||||
> if error ≥ 0.5 then
|
||||
>
|
||||
> set y0 to y0 + stepy
|
||||
> set error to error - 1
|
||||
>
|
||||
> end if
|
||||
> set x0 to x0 + stepx
|
||||
>
|
||||
> repeat
|
||||
>
|
||||
> otherwise
|
||||
>
|
||||
> end if
|
||||
> ```
|
||||
>
|
||||
> 这个算法用来表示你可能想像到的那些东西。变量 `error` 用来记录你离实线的距离。沿着 x 轴每走一步,这个 `error` 的值都会增加,而沿着 y 轴每走一步,这个 `error` 值就会减 1 个单位。`error` 是用于测量距离 y 轴的距离。
|
||||
>
|
||||
> 虽然这个算法是有效的,但它存在一个重要的问题,很明显,我们使用了小数去保存 `error`,并且也使用了除法。所以,一个立即要做的优化将是去改变 `error` 的单位。这里并不需要用特定的单位去保存它,只要我们每次使用它时都按相同数量去伸缩即可。所以,我们可以重写这个算法,通过在所有涉及 `error` 的等式上都简单地乘以 `deltay`,从面让它简化。下面只展示主要的循环:
|
||||
>
|
||||
> ```matlab
|
||||
> set error to 0 × deltay
|
||||
> until x0 = x1 + stepx
|
||||
>
|
||||
> setPixel(x0, y0)
|
||||
> set error to error + deltax ÷ deltay × deltay
|
||||
> if error ≥ 0.5 × deltay then
|
||||
>
|
||||
> set y0 to y0 + stepy
|
||||
> set error to error - 1 × deltay
|
||||
>
|
||||
> end if
|
||||
> set x0 to x0 + stepx
|
||||
>
|
||||
> repeat
|
||||
> ```
|
||||
>
|
||||
> 它将简化为:
|
||||
>
|
||||
> ```matlab
|
||||
> cset error to 0
|
||||
> until x0 = x1 + stepx
|
||||
>
|
||||
> setPixel(x0, y0)
|
||||
> set error to error + deltax
|
||||
> if error × 2 ≥ deltay then
|
||||
>
|
||||
> set y0 to y0 + stepy
|
||||
> set error to error - deltay
|
||||
>
|
||||
> end if
|
||||
> set x0 to x0 + stepx
|
||||
>
|
||||
> repeat
|
||||
> ```
|
||||
>
|
||||
> 突然,我们有了一个更好的算法。现在,我们看一下如何完全去除所需要的除法运算。最好保留唯一的被 2 相乘的乘法运算,我们知道它可以通过左移 1 位来实现!现在,这是非常接近布鲁塞姆算法的,但还可以进一步优化它。现在,我们有一个 `if` 语句,它将导致产生两个代码块,其中一个用于 x 差异较大的线,另一个用于 y 差异较大的线。对于这两种类型的线,如果审查代码能够将它们转换成一个单语句,还是很值得去做的。
|
||||
>
|
||||
> 困难之处在于,在第一种情况下,`error` 是与 y 一起变化,而第二种情况下 `error` 是与 x 一起变化。解决方案是在一个变量中同时记录它们,使用负的 `error` 去表示 x 中的一个 `error`,而用正的 `error` 表示它是 y 中的。
|
||||
>
|
||||
> ```matlab
|
||||
> set error to deltax - deltay
|
||||
> until x0 = x1 + stepx or y0 = y1 + stepy
|
||||
>
|
||||
> setPixel(x0, y0)
|
||||
> if error × 2 > -deltay then
|
||||
>
|
||||
> set x0 to x0 + stepx
|
||||
> set error to error - deltay
|
||||
>
|
||||
> end if
|
||||
> if error × 2 < deltax then
|
||||
>
|
||||
> set y0 to y0 + stepy
|
||||
> set error to error + deltax
|
||||
>
|
||||
> end if
|
||||
>
|
||||
> repeat
|
||||
> ```
|
||||
>
|
||||
> 你可能需要一些时间来搞明白它。在每一步中,我们都认为它正确地在 x 和 y 中移动。我们通过检查来做到这一点,如果我们在 x 或 y 轴上移动,`error` 的数量会变低,那么我们就继续这样移动。
|
||||
>
|
||||
|
||||
.
|
||||
|
||||
> 布鲁塞姆算法是在 1962 年由 Jack Elton Bresenham 开发,当时他 24 岁,正在攻读博士学位。
|
||||
|
||||
用于画线的布鲁塞姆算法可以通过以下的伪代码来描述。以下伪代码是文本,它只是看起来有点像是计算机指令而已,但它却能让程序员实实在在地理解算法,而不是为机器可读。
|
||||
|
||||
```matlab
|
||||
/* 我们希望从 (x0,y0) 到 (x1,y1) 去绘制一条线,只使用一个函数 setPixel(x,y),它的功能是在给定的 (x,y) 上绘制一个点。 */
|
||||
|
||||
if x1 > x0 then
|
||||
set deltax to x1 - x0
|
||||
set stepx to +1
|
||||
otherwise
|
||||
set deltax to x0 - x1
|
||||
set stepx to -1
|
||||
end if
|
||||
|
||||
set error to deltax - deltay
|
||||
until x0 = x1 + stepx or y0 = y1 + stepy
|
||||
setPixel(x0, y0)
|
||||
if error × 2 ≥ -deltay then
|
||||
set x0 to x0 + stepx
|
||||
set error to error - deltay
|
||||
end if
|
||||
if error × 2 ≤ deltax then
|
||||
set y0 to y0 + stepy
|
||||
set error to error + deltax
|
||||
end if
|
||||
repeat
|
||||
```
|
||||
|
||||
与我们目前所使用的编号列表不同,这个算法的表示方式更常用。看看你能否自己实现它。我在下面提供了我的实现作为参考。
|
||||
|
||||
```assembly
|
||||
.globl DrawLine
|
||||
DrawLine:
|
||||
push {r4,r5,r6,r7,r8,r9,r10,r11,r12,lr}
|
||||
x0 .req r9
|
||||
x1 .req r10
|
||||
y0 .req r11
|
||||
y1 .req r12
|
||||
|
||||
mov x0,r0
|
||||
mov x1,r2
|
||||
mov y0,r1
|
||||
mov y1,r3
|
||||
|
||||
dx .req r4
|
||||
dyn .req r5 /* 注意,我们只使用 -deltay,因此为了速度,我保存它的负值。(因此命名为 dyn)*/
|
||||
sx .req r6
|
||||
sy .req r7
|
||||
err .req r8
|
||||
|
||||
cmp x0,x1
|
||||
subgt dx,x0,x1
|
||||
movgt sx,#-1
|
||||
suble dx,x1,x0
|
||||
movle sx,#1
|
||||
|
||||
cmp y0,y1
|
||||
subgt dyn,y1,y0
|
||||
movgt sy,#-1
|
||||
suble dyn,y0,y1
|
||||
movle sy,#1
|
||||
|
||||
add err,dx,dyn
|
||||
add x1,sx
|
||||
add y1,sy
|
||||
|
||||
pixelLoop$:
|
||||
|
||||
teq x0,x1
|
||||
teqne y0,y1
|
||||
popeq {r4,r5,r6,r7,r8,r9,r10,r11,r12,pc}
|
||||
|
||||
mov r0,x0
|
||||
mov r1,y0
|
||||
bl DrawPixel
|
||||
|
||||
cmp dyn, err,lsl #1
|
||||
addle err,dyn
|
||||
addle x0,sx
|
||||
|
||||
cmp dx, err,lsl #1
|
||||
addge err,dx
|
||||
addge y0,sy
|
||||
|
||||
b pixelLoop$
|
||||
|
||||
.unreq x0
|
||||
.unreq x1
|
||||
.unreq y0
|
||||
.unreq y1
|
||||
.unreq dx
|
||||
.unreq dyn
|
||||
.unreq sx
|
||||
.unreq sy
|
||||
.unreq err
|
||||
```
|
||||
|
||||
### 3、随机性
|
||||
|
||||
到目前,我们可以绘制线条了。虽然我们可以使用它来绘制图片及诸如此类的东西(你可以随意去做!),我想应该借此机会引入计算机中随机性的概念。我将这样去做,选择一对随机的坐标,然后从上一对坐标用渐变色绘制一条线到那个点。我这样做纯粹是认为它看起来很漂亮。
|
||||
|
||||
那么,总结一下,我们如何才能产生随机数呢?不幸的是,我们并没有产生随机数的一些设备(这种设备很罕见)。因此只能利用我们目前所学过的操作,需要我们以某种方式来发明“随机数”。你很快就会意识到这是不可能的。各种操作总是给出定义好的结果,用相同的寄存器运行相同的指令序列总是给出相同的答案。而我们要做的是推导出一个伪随机序列。这意味着数字在外人看来是随机的,但实际上它是完全确定的。因此,我们需要一个生成随机数的公式。其中有人可能会想到很垃圾的数学运算,比如:4x<sup>2</sup>! / 64,而事实上它产生的是一个低质量的随机数。在这个示例中,如果 x 是 0,那么答案将是 0。看起来很愚蠢,我们需要非常谨慎地选择一个能够产生高质量随机数的方程式。
|
||||
|
||||
> 硬件随机数生成器很少用在安全中,因为可预测的随机数序列可能影响某些加密的安全。
|
||||
|
||||
我将要教给你的方法叫“二次同余发生器”。这是一个非常好的选择,因为它能够在 5 个指令中实现,并且能够产生一个从 0 到 232-1 之间的看似很随机的数字序列。
|
||||
|
||||
不幸的是,对为什么使用如此少的指令能够产生如此长的序列的原因的研究,已经远超出了本课程的教学范围。但我还是鼓励有兴趣的人去研究它。它的全部核心所在就是下面的二次方程,其中 `xn` 是产生的第 `n` 个随机数。
|
||||
|
||||
> 这类讨论经常寻求一个问题,那就是我们所谓的随机数到底是什么?通常从统计学的角度来说的随机性是:一组没有明显模式或属性能够概括它的数的序列。
|
||||
|
||||
```
|
||||
x_(n+1) = ax_(n)^2 + bx_(n) + c mod 2^32
|
||||
```
|
||||
|
||||
这个方程受到以下的限制:
|
||||
|
||||
1. a 是偶数
|
||||
2. b = a + 1 mod 4
|
||||
3. c 是奇数
|
||||
|
||||
如果你之前没有见到过 `mod` 运算,我来解释一下,它的意思是被它后面的数相除之后的余数。比如 `b = a + 1 mod 4` 的意思是 `b` 是 `a + 1` 除以 `4` 的余数,因此,如果 `a` 是 12,那么 `b` 将是 `1`,因为 `a + 1` 是 13,而 `13` 除以 4 的结果是 3 余 1。
|
||||
|
||||
复制下列代码到名为 `random.s` 的文件中。
|
||||
|
||||
```assembly
|
||||
.globl Random
|
||||
Random:
|
||||
xnm .req r0
|
||||
a .req r1
|
||||
|
||||
mov a,#0xef00
|
||||
mul a,xnm
|
||||
mul a,xnm
|
||||
add a,xnm
|
||||
.unreq xnm
|
||||
add r0,a,#73
|
||||
|
||||
.unreq a
|
||||
mov pc,lr
|
||||
```
|
||||
|
||||
这是随机函数的一个实现,使用一个在寄存器 `r0` 中最后生成的值作为输入,而接下来的数字则是输出。在我的案例中,我使用 a = EF00<sub>16</sub>,b = 1, c = 73。这个选择是随意的,但是需要满足上述的限制。你可以使用任何数字代替它们,只要符合上述的规则就行。
|
||||
|
||||
### 4、Pi-casso
|
||||
|
||||
OK,现在我们有了所有我们需要的函数,我们来试用一下它们。获取帧缓冲信息的地址之后,按如下的要求修改 `main`:
|
||||
|
||||
1. 使用包含了帧缓冲信息地址的寄存器 `r0` 调用 `SetGraphicsAddress`。
|
||||
2. 设置四个寄存器为 0。一个将是最后的随机数,一个将是颜色,一个将是最后的 x 坐标,而最后一个将是最后的 y 坐标。
|
||||
3. 调用 `random` 去产生下一个 x 坐标,使用最后一个随机数作为输入。
|
||||
4. 调用 `random` 再次去生成下一个 y 坐标,使用你生成的 x 坐标作为输入。
|
||||
5. 更新最后的随机数为 y 坐标。
|
||||
6. 使用 `colour` 值调用 `SetForeColour`,接着增加 `colour` 值。如果它大于 FFFF~16~,确保它返回为 0。
|
||||
7. 我们生成的 x 和 y 坐标将介于 0 到 FFFFFFFF<sub>16</sub>。通过将它们逻辑右移 22 位,将它们转换为介于 0 到 1023<sub>10</sub> 之间的数。
|
||||
8. 检查 y 坐标是否在屏幕上。验证 y 坐标是否介于 0 到 767<sub>10</sub> 之间。如果不在这个区间,返回到第 3 步。
|
||||
9. 从最后的 x 坐标和 y 坐标到当前的 x 坐标和 y 坐标之间绘制一条线。
|
||||
10. 更新最后的 x 和 y 坐标去为当前的坐标。
|
||||
11. 返回到第 3 步。
|
||||
|
||||
一如既往,你可以在下载页面上找到这个解决方案。
|
||||
|
||||
在你完成之后,在树莓派上做测试。你应该会看到一系列颜色递增的随机线条以非常快的速度出现在屏幕上。它一直持续下去。如果你的代码不能正常工作,请查看我们的排错页面。
|
||||
|
||||
如果一切顺利,恭喜你!我们现在已经学习了有意义的图形和随机数。我鼓励你去使用它绘制线条,因为它能够用于渲染你想要的任何东西,你可以去探索更复杂的图案了。它们中的大多数都可以由线条生成,但这需要更好的策略?如果你愿意写一个画线程序,尝试使用 `SetPixel` 函数。如果不是去设置像素值而是一点点地增加它,会发生什么情况?你可以用它产生什么样的图案?在下一节课 [课程 8:屏幕 03][2] 中,我们将学习绘制文本的宝贵技能。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen02.html
|
||||
|
||||
作者:[Alex Chadwick][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://www.cl.cam.ac.uk
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linux.cn/article-10540-1.html
|
||||
[2]: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/screen03.html
|
119
published/20171215 Top 5 Linux Music Players.md
Normal file
119
published/20171215 Top 5 Linux Music Players.md
Normal file
@ -0,0 +1,119 @@
|
||||
Linux 上最好的五款音乐播放器
|
||||
======
|
||||
> Jack Wallen 盘点他最爱的五款 Linux 音乐播放器。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/live-music.jpg?itok=Ejbo4rf7_)
|
||||
|
||||
不管你做什么,你都有时会来一点背景音乐。不管你是开发、运维或是一个典型的电脑用户,享受美妙的音乐都可能是你在电脑上最想做的事情之一。同时随着即将到来的假期,你可能收到一些能让你买几首新歌的礼物卡。如果你所选的音乐是数字形式(我的恰好是唱片形式)而且你的平台是 Linux 的话,你会想要一个好的图形用户界面播放器来享受音乐。
|
||||
|
||||
幸运的是,Linux 不缺好的数字音乐播放器。事实上,Linux 上有不少播放器,大部分是开源并且可以免费获得的。让我们看看其中的几款,看哪个能满足你的需要。
|
||||
|
||||
### Clementine
|
||||
|
||||
我想从我用来许多年的默认选项的播放器开始。[Clementine][1] 可能是最好的平衡了易用性与灵活性的播放器。Clementine 是新停摆的 [Amarok][2] 音乐播放器的复刻,但它不仅限于 Linux; Clementine 在 Mac OS 和 Windows 平台上也可以获得。它的一系列特性十分惊艳,包括:
|
||||
|
||||
* 內建的均衡器
|
||||
* 可定制的界面(将现在的专辑封面显示成背景,见图一)
|
||||
* 播放本地音乐或者从 Spotify、Last.fm 等播放音乐
|
||||
* 便于库导航的侧边栏
|
||||
* 內建的音频转码(转成 MP3、OGG、Flac 等)
|
||||
* 通过 [安卓应用][3] 远程控制
|
||||
* 便利的搜索功能
|
||||
* 选项卡式播放列表
|
||||
* 简单创建常规和智能化的播放列表
|
||||
* 支持 CUE 文件
|
||||
* 支持标签
|
||||
|
||||
![Clementine][5]
|
||||
|
||||
*图一:Clementine 界面可能有一点老派,但是它不可思议得灵活好用。*
|
||||
|
||||
在所有我用过的音乐播放器中,Clementine 是目前为止功能最多也是最容易使用的。它同时也包含了你能在 Linux 音乐播放器中找到的最好的均衡器(有十个频带可以调)。尽管它的界面不够时髦,但它创建、操控播放列表的能力是无与伦比的。如果你的音乐集很大,同时你想完全操控你的音乐集的话,这就是你想要的播放器。
|
||||
|
||||
Clementine 可以在标准仓库中找到。它可以从你的发行版的软件中心或通过命令行来安装。
|
||||
|
||||
### Rhythmbox
|
||||
|
||||
[Rhythmbox][7] 是 GNOME 桌面的默认播放器,但是它在其它桌面工作得也很好。Rhythmbox 的界面比 Clementine 的界面稍微时尚一点,它的设计遵循极简的理念。这并不意味着它缺乏特性,相反 Rhythmbox 提供无间隔回放、支持 Soundcloud、专辑封面显示、从 Last.fm 和 Libre.fm 导入音频、支持 Jamendo、播客订阅(从 [Apple iTunes][8])、从网页远程控制等特性。
|
||||
|
||||
在 Rhythmbox 中发现的一个很好的特性是支持插件,这使得你可以使用像 DAAP 音乐分享、FM 电台、封面查找、通知、ReplayGain、歌词等特性。
|
||||
|
||||
Rhythmbox 播放列表特性不像 Clementine 的那么强大,但是将你的音乐整理进任何形式的快速播放列表还是很简单的。尽管 Rhythmbox 的界面(图二)比 Clementine 要时髦一点,但是它不像 Clementine 那样灵活。
|
||||
|
||||
![Rhythmbox][10]
|
||||
|
||||
*图二:Rhythmbox 界面简单直接。*
|
||||
|
||||
### VLC Media Player
|
||||
|
||||
对于部分人来说,[VLC][11] 在视频播放方面是无懈可击的。然而 VLC 不仅限于视频播放。事实上,VLC在播放音频文件方面做得也很好。对于 [KDE Neon][12] 用户来说,VLC 既是音乐也是视频的默认播放器。尽管 VLC 是 Linux 市场最好的视频播放器的之一(它是我的默认播放器),它在音频方面确实略有瑕疵 —— 缺少播放列表以及不能够连接到你网络中的远程仓库。但如果你是在寻找一种播放本地文件或者网络 mms/rtsp 的简单可靠的方式,VLC 是上佳之选。VLC 包括一个均衡器(图三)、一个压缩器以及一个空间音响。它同样也能够从捕捉到的设备录音。
|
||||
|
||||
![VLC][14]
|
||||
|
||||
*图三:运转中的 VLC 均衡器。*
|
||||
|
||||
### Audacious
|
||||
|
||||
如果你在寻找一个轻量级的音乐播放器,Audacious 完美地满足要求。这个音乐播放器相当的专一,但是它包括了一个均衡器和一小部分能够改善许多音频的声效(比如回声、消除默音、调节速度和音调、去除人声等,见图四)。
|
||||
|
||||
![Audacious][16]
|
||||
|
||||
*图四:Audacious 均衡器和插件。*
|
||||
|
||||
Audacious 也包括了一个十分简便的闹铃功能。它允许你设置一个能在用户选定的时间点和持续的时间段内播放选定乐段的闹铃。
|
||||
|
||||
### Spotify
|
||||
|
||||
我必须承认,我每天都用 Spotify。我是一个 Spotify 的订阅者并用它去发现、购买新的音乐 —— 这意味着我在不停地探索发现。幸运的是,Spotify 有一个我能按照 [Spotify官方 Linux 平台安装指导][17] 轻松安装的桌面客户端。在桌面客户端与 [安卓应用][18] 间无缝转换对我来说也大有帮助,这样我就永远不会错过我喜欢的音乐了。
|
||||
|
||||
![Spotify][16]
|
||||
|
||||
*图五:Linux 上的 Spotify 官方客户端。*
|
||||
|
||||
Spotify 界面十分易于使用,事实上它完胜网页端的播放器。不要在 Linux 上装 [Spotify 网页播放器][21] 因为桌面客户端在创建管理你的播放列表方面简便得多。如果你是 Spotify 重度用户,甚至没必要用其他桌面应用的內建流传输客户端支持 —— 一旦你用过 Spotify 桌面客户端,其它应用就根本没可比性。
|
||||
|
||||
### 选择在你
|
||||
|
||||
其它选择也是有的(查看你的桌面软件中心),但这五款客户端(在我看来)是最好的了。对我来说,Clementine 和 Spotify 的组合拳就已经让我美好得唱赞歌了。尝试它们看看哪个能更好地满足你的需要。
|
||||
|
||||
### 额外奖品
|
||||
|
||||
虽然这篇文章翻译于国外作者,但作为给中国的 Linux 用户看的文章,如果在一篇分享音乐播放器的文章中**不提及**网易云音乐,那一定会被猛烈吐槽(事实上,我们曾经被吐槽过好多次了,哈哈)。
|
||||
|
||||
网易云音乐是我见过的最好的音乐播放器之一,不只是在 Linux 上,它甚至还支持包括 Windows、Mac、 iOS、安卓等在内的 8 个操作系统平台。当前的 Linux 版本是 1.1.0 版,支持 64 位的深度 Linux 15 和 Ubuntu 16.04 及之后的版本。下载地址和截图就不在这里安利了,大家想必自己能找到的。
|
||||
|
||||
通过 edX 和 Linux Foundation 上免费的 ["Introduction to Linux" ][22] 课程学习更多有关 Linux 的知识。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/learn/intro-to-linux/2017/12/top-5-linux-music-players
|
||||
|
||||
作者:[JACK WALLEN][a]
|
||||
译者:[tomjlw](https://github.com/tomjlw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/jlwallen
|
||||
[1]:https://www.clementine-player.org/
|
||||
[2]:https://en.wikipedia.org/wiki/Amarok_(software)
|
||||
[3]:https://play.google.com/store/apps/details?id=de.qspool.clementineremote
|
||||
[4]:https://www.linux.com/files/images/clementinejpg
|
||||
[5]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/clementine.jpg?itok=_k13MtM3 (Clementine)
|
||||
[6]:https://www.linux.com/licenses/category/used-permission
|
||||
[7]:https://wiki.gnome.org/Apps/Rhythmbox
|
||||
[8]:https://www.apple.com/itunes/
|
||||
[9]:https://www.linux.com/files/images/rhythmboxjpg
|
||||
[10]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/rhythmbox.jpg?itok=GOjs9vTv (Rhythmbox)
|
||||
[11]:https://www.videolan.org/vlc/index.html
|
||||
[12]:https://neon.kde.org/
|
||||
[13]:https://www.linux.com/files/images/vlcjpg
|
||||
[14]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/vlc.jpg?itok=hn7iKkmK (VLC)
|
||||
[15]:https://www.linux.com/files/images/audaciousjpg
|
||||
[16]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/audacious.jpg?itok=9YALPzOx (Audacious )
|
||||
[17]:https://www.spotify.com/us/download/linux/
|
||||
[18]:https://play.google.com/store/apps/details?id=com.spotify.music
|
||||
[19]:https://www.linux.com/files/images/spotifyjpg
|
||||
[20]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/spotify.jpg?itok=P3FLfcYt (Spotify)
|
||||
[21]:https://open.spotify.com/browse/featured
|
||||
[22]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
@ -0,0 +1,76 @@
|
||||
采用 snaps 为 Linux 社区构建 Slack
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
作为一个被数以百万计用户使用的企业级软件平台,[Slack][2] 可以让各种规模的团队和企业有效地沟通。Slack 通过在一个单一集成环境中与其它软件工具无缝衔接,为一个组织内的通讯、信息和项目提供了一个易于接触的档案馆。尽管自从诞生后 Slack 就在过去四年中快速成长,但是他们负责该平台的 Windows、MacOS 和 Linux 桌面的工程师团队仅由四人组成。我们采访了这个团队的主任工程师 Felix Rieseberg(他负责追踪[上月首次发布的 Slack snap][3],LCTT 译注:原文发布于 2018.2),来了解更多有关该公司对于 Linux 社区的态度,以及他们决定构建一个 snap 软件包的原因。
|
||||
|
||||
- [安装 Slack snap][4]
|
||||
|
||||
### 你们能告诉我们更多关于已发布的 Slack snap 的信息吗?
|
||||
|
||||
作为发布给 Linux 社区的一种新形式,我们上月发布了我们的第一个 snap。在企业界,我们发现人们更倾向于以一种相对于个人消费者来说较慢的速度来采用新科技,因此我们将会在未来继续提供 .deb 形式的软件包。
|
||||
|
||||
### 你们觉得 Linux 社区会对 Slack 有多大的兴趣呢?
|
||||
|
||||
我很高兴在所有的平台上人们都对 Slack 的兴趣越来越大。因此,很难说来自 Linux 社区的兴趣和我们大体上所见到的兴趣有什么区别。当然,不管用户们在什么平台上面工作,满足他们对我们都是很重要的。我们有一个专门负责 Linux 的测试工程师,并且我们同时也会尽全力提供最好的用户体验。
|
||||
|
||||
只是我们发现总体相对于 Windows 来说,为 Linux 搭建 snap 略微有点难度,因为我们是在一个较难以预测的平台上工作——而这正是 Linux 社区之光照耀的领域。在汇报程序缺陷以及寻找程序崩溃原因方面,我们有相当多极有帮助的用户。
|
||||
|
||||
### 你们是如何得知 snap 的?
|
||||
|
||||
Canonical 公司的 Martin Wimpress 接触了我,并向我解释了 snap 的概念。说实话尽管我也用 Ubuntu 但最初我还是迟疑的,因为它看起来像需要搭建与维护的另一套标准。然而,一当我了解到其中的好处之后,我确信这是一笔值得的投入。
|
||||
|
||||
### snap 的什么方面吸引了你们并使你们决定投入其中?
|
||||
|
||||
毫无疑问,我们决定搭建 snap 最重要的原因是它的更新特性。在 Slack 上我们大量运用了网页技术,这些技术反过来也使得我们提供大量的特性——比如将 YouTube 视频或者 Spotify 播放列表集成在 Slack 中。与浏览器十分相似,这意味着我们需要频繁更新应用。
|
||||
|
||||
在 MacOS 和 Windows 上,我们已经有了一个专门的自动更新器,甚至无需用户关注更新。任何形式的中断都是一种我们需要避免的烦恼,哪怕是为了更新。因此通过 snap 自动化的更新就显得更加无缝和便捷。
|
||||
|
||||
### 相比于其它形式的打包方式,构建 snap 感觉如何?将它与现有的设施和流程集成在一起有多简便呢?
|
||||
|
||||
就 Linux 而言,我们尚未尝试其它的“新”打包方式,但我们迟早会的。鉴于我们的大多数用户都使用 Ubuntu,snap 是一个自然的选择。同时 snap 在其它发行版上同样也可以使用,这也是一个巨大的加分项。Canonical 正将 snap 做到跨发行版,而不是仅仅集中在 Ubuntu 上,这一点我认为是很好的。
|
||||
|
||||
搭建 snap 极其简单,我们有一个创建安装器和软件包的统一流程,我们的 snap 创建过程就是从一个 .deb 软件包炮制出一个 snap。对于其它技术而言,有时候我们为了支持构建链而先打造一个内部工具。但是 snapcraft 工具正是我们需要的东西。在整个过程中 Canonical 的团队非常有帮助,因为我们一路上确实碰到了一些问题。
|
||||
|
||||
### 你们觉得 snap 商店是如何改变用户们寻找、安装你们软件的方式的呢?
|
||||
|
||||
Slack 真正的独特之处在于人们不仅仅是碰巧发现它,他们从别的地方知道它并积极地试图找到它。因此尽管我们已经有了相当高的觉悟,我希望对于我们的用户来说,在商店中可以获得 snap 能够让安装过程变得简单一点。
|
||||
|
||||
我们总是尽力为用户服务。当我们觉得它比其他安装方式更好,我们就会向用户更多推荐它。
|
||||
|
||||
### 通过使用 snap 而不是为其它发行版打包,你期待或者已经看到的节省是什么?
|
||||
|
||||
我们希望 snap 可以给予我们的用户更多的便利,并确保他们能够更加喜欢使用 Slack。在我们看来,鉴于用户们不必被困在之前的版本,这自然而然地解决了许多问题,因此 snap 可以让我们在客户支持方面节约时间。snap 对我们来说也是一个额外的加分项,因为我们能有一个可供搭建的平台,而不是替换我们现有的东西。
|
||||
|
||||
### 如果存在的话,你们正使用或者准备使用边缘 (edge)、测试 (beta)、候选 (candidate)、稳定 (stable) 中的哪种发行频道?
|
||||
|
||||
我们开发中专门使用边缘 (edge) 频道以与 Canonical 团队合作。为 Linux 打造的 Slack 总体仍处于测试 (beta) 频道中。但是长远来看,拥有不同频道的选择十分有意思,同时能够提早一点为感兴趣的客户发布版本也肯定是有好处的。
|
||||
|
||||
### 你们如何认为将软件打包成一个 snap 能够帮助用户?你们从用户那边得到了什么反馈吗?
|
||||
|
||||
对我们的用户来说一个很大的好处是安装和更新总体来说都会变得简便一点。长远来看,问题是“那些安装 snap 的用户是不是比其它用户少碰到一些困难?”,我十分期望 snap 自带的依赖关系能够使其变成可能。
|
||||
|
||||
### 你们对刚使用 snap 的新用户们有什么建议或知识呢?
|
||||
|
||||
我会推荐从 Debian 软件包来着手搭建你们的 snap ——那出乎意料得简单。这同样也缩小了范围,避免变得不堪重负。这只需要投入相当少的时间,并且很大可能是一笔值得的投入。同样如果你们可以的话,尽量试着找到 Canonical 的人员来协作——他们拥有了不起的工程师。
|
||||
|
||||
### 对于开发来说,你们在什么地方看到了最大的机遇?
|
||||
|
||||
我们现在正一步步来,先是让人们接受 snap,再从那里开始搭建。正在使用 snap 的人们将会感到更加稳健,因为他们将会得益于最新的更新。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://insights.ubuntu.com/2018/02/06/building-slack-for-the-linux-community-and-adopting-snaps/
|
||||
|
||||
作者:[Sarah][a]
|
||||
译者:[tomjlw](https://github.com/tomjlw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://insights.ubuntu.com/author/sarahfd/
|
||||
[1]:https://insights.ubuntu.com/wp-content/uploads/a115/Slack_linux_screenshot@2x-2.png
|
||||
[2]:https://slack.com/
|
||||
[3]:https://insights.ubuntu.com/2018/01/18/canonical-brings-slack-to-the-snap-ecosystem/
|
||||
[4]:https://snapcraft.io/slack/
|
@ -0,0 +1,94 @@
|
||||
Pony 编程语言简介
|
||||
======
|
||||
|
||||
> Pony,一种“Rust 遇上 Erlang”的语言,让开发快捷、安全、高效、高并发的程序更简单。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/programming_keys.jpg?itok=O4qaYCHK)
|
||||
|
||||
在 [Wallaroo Labs][1],我是工程副总裁,我们正在构建一个用 [Pony][3] 编程语言编写的 [高性能分布式流处理器][2]。大多数人没有听说过 Pony,但它一直是 Wallaroo 的最佳选择,它也可能成为你的下一个项目的最佳选择。
|
||||
|
||||
> “一门编程语言只是另一种工具。与语法无关,与表达性无关,与范式或模型无关,仅与解决难题有关。” —Sylvan Clebsch,Pony 的创建者
|
||||
|
||||
我是 Pony 项目的贡献者,但在这里我要谈谈为什么 Pony 对于像 Wallaroo 这样的应用是个好选择,并分享我使用 Pony 的方式。如果你对我们为什么使用 Pony 来编写 Wallaroo 甚感兴趣,我们有一篇关于它的 [博文][4]。
|
||||
|
||||
### Pony 是什么?
|
||||
|
||||
你可以把 Pony 想象成某种“Rust 遇上 Erlang”的东西。Pony 有着最引人注目的特性,它们是:
|
||||
|
||||
* 类型安全
|
||||
* 存储安全
|
||||
* 异常安全
|
||||
* 无数据竞争
|
||||
* 无死锁
|
||||
|
||||
此外,它可以被编译为高效的本地代码,它是在开放的情况下开发的,在两句版 BSD 许可证下发布。
|
||||
|
||||
以上说的功能不少,但在这里我将重点关注那些对我们公司来说采用 Pony 至关重要的功能。
|
||||
|
||||
### 为什么使用 Pony?
|
||||
|
||||
使用大多数我们现有的工具编写快速、安全、高效、高并发的程序并非易事。“快速、高效、高并发”是可实现的目标,但加入“安全”之后,就困难了许多。对于 Wallaroo,我们希望同时实现四个目标,而 Pony 让实现它们更加简单。
|
||||
|
||||
#### 高并发
|
||||
|
||||
Pony 让并发变得简单。部分是通过提供一个固执的并发方式实现的。在 Pony 语言中,所有的并发都是通过 [Actor 模型][5] 进行的。
|
||||
|
||||
Actor 模型以在 Erlang 和 Akka 中的实现最为著名。Actor 模型出现于上世纪 70 年代,细节因实现方式而异。不变的是,所有计算都由通过异步消息进行通信的 actor 来执行。
|
||||
|
||||
你可以用这种方式来看待 Actor 模型:面向对象中的对象是状态 + 同步方法,而 actor 是状态 + 异步方法。
|
||||
|
||||
当一个 actor 收到一个消息时,它执行相应的方法。该方法可以在只有该 actor 可访问的状态下运行。Actor 模型允许我们以并发安全的方式使用可变状态。每个 actor 都是单线程的。一个 actor 中的两个方法绝不会并发运行。这意味着,在给定的 actor 中,数据更新不会引起数据竞争或通常与线程和可变状态相关的其他问题。
|
||||
|
||||
#### 快速高效
|
||||
|
||||
Pony actor 通过一个高效的工作窃取调度程序来调度。每个可用的 CPU 都有一个单独 Pony 调度程序。这种每个核心一个线程的并发模型是 Pony 尝试与 CPU 协同工作以尽可能高效运行的一部分。Pony 运行时尝试尽可能利用 CPU 缓存。代码越少干扰缓存,运行得越好。Pony 意在帮你的代码与 CPU 缓存友好相处。
|
||||
|
||||
Pony 的运行时还会有每个 actor 的堆,因此在垃圾收集期间,没有 “停止一切” 的垃圾收集步骤。这意味着你的程序总是至少能做一点工作。因此 Pony 程序最终具有非常一致的性能和可预测的延迟。
|
||||
|
||||
#### 安全
|
||||
|
||||
Pony 类型系统引入了一个新概念:引用能力,它使得数据安全成为类型系统的一部分。Pony 语言中每种变量的类型都包含了有关如何在 actor 之间分享数据的信息。Pony 编译器用这些信息来确认,在编译时,你的代码是无数据竞争和无死锁的。
|
||||
|
||||
如果这听起来有点像 Rust,那是因为本来就是这样的。Pony 的引用功能和 Rust 的借用检查器都提供数据安全性;它们只是以不同的方式来接近这个目标,并有不同的权衡。
|
||||
|
||||
### Pony 适合你吗?
|
||||
|
||||
决定是否要在一个非业余爱好的项目上使用一门新的编程语言是困难的。与其他方法想比,你必须权衡工具的适当性和不成熟度。那么,Pony 和你搭不搭呢?
|
||||
|
||||
如果你有一个困难的并发问题需要解决,那么 Pony 可能是一个好选择。解决并发应用问题是 Pony 之所以存在的理由。如果你能用一个单线程的 Python 脚本就完成所需操作,那你大概不需要它。如果你有一个困难的并发问题,你应该考虑 Pony 及其强大的无数据竞争、并发感知类型系统。
|
||||
|
||||
你将获得一个这样的编译器,它将阻止你引入许多与并发相关的错误,并在运行时为你提供出色的性能特征。
|
||||
|
||||
### 开始使用 Pony
|
||||
|
||||
如果你准备好开始使用 Pony,你需要先在 Pony 的网站上访问 [学习部分][6]。在这里你会找到安装 Pony 编译器的步骤和学习这门语言的资源。
|
||||
|
||||
如果你愿意为你正在使用的这个语言做出贡献,我们会在 GitHub 上为你提供一些 [初学者友好的问题][7]。
|
||||
|
||||
同时,我迫不及待地想在 [我们的 IRC 频道][8] 和 [Pony 邮件列表][9] 上与你交谈。
|
||||
|
||||
要了解更多有关 Pony 的消息,请参阅 Sean Allen 2018 年 7 月 16 日至 19 日在俄勒冈州波特兰举行的 [第 20 届 OSCON 会议][11] 上的演讲: [Pony,我如何学会停止担心并拥抱未经证实的技术][10]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/5/pony
|
||||
|
||||
作者:[Sean T Allen][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[beamrolling](https://github.com/beamrolling)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/seantallen
|
||||
[1]:http://www.wallaroolabs.com/
|
||||
[2]:https://github.com/wallaroolabs/wallaroo
|
||||
[3]:https://www.ponylang.org/
|
||||
[4]:https://blog.wallaroolabs.com/2017/10/why-we-used-pony-to-write-wallaroo/
|
||||
[5]:https://en.wikipedia.org/wiki/Actor_model
|
||||
[6]:https://www.ponylang.org/learn/
|
||||
[7]:https://github.com/ponylang/ponyc/issues?q=is%3Aissue+is%3Aopen+label%3A%22complexity%3A+beginner+friendly%22
|
||||
[8]:https://webchat.freenode.net/?channels=%23ponylang
|
||||
[9]:https://pony.groups.io/g/user
|
||||
[10]:https://conferences.oreilly.com/oscon/oscon-or/public/schedule/speaker/213590
|
||||
[11]:https://conferences.oreilly.com/oscon/oscon-or
|
@ -0,0 +1,591 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (MjSeven)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (An introduction to the Tornado Python web app framework)
|
||||
[#]: via: (https://opensource.com/article/18/6/tornado-framework)
|
||||
[#]: author: (Nicholas Hunt-Walker https://opensource.com/users/nhuntwalker)
|
||||
[#]: url: (https://linux.cn/article-10522-1.html)
|
||||
|
||||
Python Web 应用程序 Tornado 框架简介
|
||||
======
|
||||
|
||||
> 在比较 Python 框架的系列文章的第三部分中,我们来了解 Tornado,它是为处理异步进程而构建的。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tornado.png?itok=kAa3eXIU)
|
||||
|
||||
在这个由四部分组成的系列文章的前两篇中,我们介绍了 [Pyramid][1] 和 [Flask][2] Web 框架。我们已经构建了两次相同的应用程序,看到了一个完整的 DIY 框架和包含了更多功能的框架之间的异同。
|
||||
|
||||
现在让我们来看看另一个稍微不同的选择:[Tornado 框架][3]。Tornado 在很大程度上与 Flask 一样简单,但有一个主要区别:Tornado 是专门为处理异步进程而构建的。在我们本系列所构建的应用程序中,这种特殊的酱料(LCTT 译注:这里意思是 Tornado 的异步功能)在我们构建的 app 中并不是非常有用,但我们将看到在哪里可以使用它,以及它在更一般的情况下是如何工作的。
|
||||
|
||||
让我们继续前两篇文章中模式,首先从处理设置和配置开始。
|
||||
|
||||
### Tornado 启动和配置
|
||||
|
||||
如果你一直关注这个系列,那么第一步应该对你来说习以为常。
|
||||
|
||||
```
|
||||
$ mkdir tornado_todo
|
||||
$ cd tornado_todo
|
||||
$ pipenv install --python 3.6
|
||||
$ pipenv shell
|
||||
(tornado-someHash) $ pipenv install tornado
|
||||
```
|
||||
|
||||
创建一个 `setup.py` 文件来安装我们的应用程序相关的东西:
|
||||
|
||||
```
|
||||
(tornado-someHash) $ touch setup.py
|
||||
# setup.py
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
requires = [
|
||||
'tornado',
|
||||
'tornado-sqlalchemy',
|
||||
'psycopg2',
|
||||
]
|
||||
|
||||
setup(
|
||||
name='tornado_todo',
|
||||
version='0.0',
|
||||
description='A To-Do List built with Tornado',
|
||||
author='<Your name>',
|
||||
author_email='<Your email>',
|
||||
keywords='web tornado',
|
||||
packages=find_packages(),
|
||||
install_requires=requires,
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'serve_app = todo:main',
|
||||
],
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
因为 Tornado 不需要任何外部配置,所以我们可以直接编写 Python 代码来让程序运行。让我们创建 `todo` 目录,并用需要的前几个文件填充它。
|
||||
|
||||
```
|
||||
todo/
|
||||
__init__.py
|
||||
models.py
|
||||
views.py
|
||||
```
|
||||
|
||||
就像 Flask 和 Pyramid 一样,Tornado 也有一些基本配置,放在 `__init__.py` 中。从 `tornado.web` 中,我们将导入 `Application` 对象,它将处理路由和视图的连接,包括数据库(当我们谈到那里时再说)以及运行 Tornado 应用程序所需的其它额外设置。
|
||||
|
||||
```
|
||||
# __init__.py
|
||||
from tornado.web import Application
|
||||
|
||||
def main():
|
||||
"""Construct and serve the tornado application."""
|
||||
app = Application()
|
||||
```
|
||||
|
||||
像 Flask 一样,Tornado 主要是一个 DIY 框架。当构建我们的 app 时,我们必须设置该应用实例。因为 Tornado 用它自己的 HTTP 服务器来提供该应用,我们必须设置如何提供该应用。首先,在 `tornado.options.define` 中定义要监听的端口。然后我们实例化 Tornado 的 `HTTPServer`,将该 `Application` 对象的实例作为参数传递给它。
|
||||
|
||||
```
|
||||
# __init__.py
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.options import define, options
|
||||
from tornado.web import Application
|
||||
|
||||
define('port', default=8888, help='port to listen on')
|
||||
|
||||
def main():
|
||||
"""Construct and serve the tornado application."""
|
||||
app = Application()
|
||||
http_server = HTTPServer(app)
|
||||
http_server.listen(options.port)
|
||||
```
|
||||
|
||||
当我们使用 `define` 函数时,我们最终会在 `options` 对象上创建属性。第一个参数位置的任何内容都将是属性的名称,分配给 `default` 关键字参数的内容将是该属性的值。
|
||||
|
||||
例如,如果我们将属性命名为 `potato` 而不是 `port`,我们可以通过 `options.potato` 访问它的值。
|
||||
|
||||
在 `HTTPServer` 上调用 `listen` 并不会启动服务器。我们必须再做一步,找一个可以监听请求并返回响应的工作应用程序,我们需要一个输入输出循环。幸运的是,Tornado 以 `tornado.ioloop.IOLoop` 的形式提供了开箱即用的功能。
|
||||
|
||||
```
|
||||
# __init__.py
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.options import define, options
|
||||
from tornado.web import Application
|
||||
|
||||
define('port', default=8888, help='port to listen on')
|
||||
|
||||
def main():
|
||||
"""Construct and serve the tornado application."""
|
||||
app = Application()
|
||||
http_server = HTTPServer(app)
|
||||
http_server.listen(options.port)
|
||||
print('Listening on http://localhost:%i' % options.port)
|
||||
IOLoop.current().start()
|
||||
```
|
||||
|
||||
我喜欢某种形式的 `print` 语句,来告诉我什么时候应用程序正在提供服务,这是我的习惯。如果你愿意,可以不使用 `print`。
|
||||
|
||||
我们以 `IOLoop.current().start()` 开始我们的 I/O 循环。让我们进一步讨论输入,输出和异步性。
|
||||
|
||||
### Python 中的异步和 I/O 循环的基础知识
|
||||
|
||||
请允许我提前说明,我绝对,肯定,一定并且放心地说不是异步编程方面的专家。就像我写的所有内容一样,接下来的内容源于我对这个概念的理解的局限性。因为我是人,可能有很深很深的缺陷。
|
||||
|
||||
异步程序的主要问题是:
|
||||
|
||||
* 数据如何进来?
|
||||
* 数据如何出去?
|
||||
* 什么时候可以在不占用我全部注意力情况下运行某个过程?
|
||||
|
||||
由于[全局解释器锁][4](GIL),Python 被设计为一种[单线程][5]语言。对于 Python 程序必须执行的每个任务,其线程执行的全部注意力都集中在该任务的持续时间内。我们的 HTTP 服务器是用 Python 编写的,因此,当接收到数据(如 HTTP 请求)时,服务器的唯一关心的是传入的数据。这意味着,在大多数情况下,无论是程序需要运行还是处理数据,程序都将完全消耗服务器的执行线程,阻止接收其它可能的数据,直到服务器完成它需要做的事情。
|
||||
|
||||
在许多情况下,这不是太成问题。典型的 Web 请求,响应周期只需要几分之一秒。除此之外,构建 HTTP 服务器的套接字可以维护待处理的传入请求的积压。因此,如果请求在该套接字处理其它内容时进入,则它很可能只是在处理之前稍微排队等待一会。对于低到中等流量的站点,几分之一秒的时间并不是什么大问题,你可以使用多个部署的实例以及 [NGINX][6] 等负载均衡器来为更大的请求负载分配流量。
|
||||
|
||||
但是,如果你的平均响应时间超过一秒钟,该怎么办?如果你使用来自传入请求的数据来启动一些长时间的过程(如机器学习算法或某些海量数据库查询),该怎么办?现在,你的单线程 Web 服务器开始累积一个无法寻址的积压请求,其中一些请求会因为超时而被丢弃。这不是一种选择,特别是如果你希望你的服务在一段时间内是可靠的。
|
||||
|
||||
异步 Python 程序登场。重要的是要记住因为它是用 Python 编写的,所以程序仍然是一个单线程进程。除非特别标记,否则在异步程序中仍然会阻塞执行。
|
||||
|
||||
但是,当异步程序结构正确时,只要你指定某个函数应该具有这样的能力,你的异步 Python 程序就可以“搁置”长时间运行的任务。然后,当搁置的任务完成并准备好恢复时,异步控制器会收到报告,只要在需要时管理它们的执行,而不会完全阻塞对新输入的处理。
|
||||
|
||||
这有点夸张,所以让我们用一个人类的例子来证明。
|
||||
|
||||
### 带回家吧
|
||||
|
||||
我经常发现自己在家里试图完成很多家务,但没有多少时间来做它们。在某一天,积压的家务可能看起来像:
|
||||
|
||||
* 做饭(20 分钟准备,40 分钟烹饪)
|
||||
* 洗碗(60 分钟)
|
||||
* 洗涤并擦干衣物(30 分钟洗涤,每次干燥 90 分钟)
|
||||
* 真空清洗地板(30 分钟)
|
||||
|
||||
如果我是一个传统的同步程序,我会亲自完成每项任务。在我考虑处理任何其他事情之前,每项任务都需要我全神贯注地完成。因为如果没有我的全力关注,什么事情都完成不了。所以我的执行顺序可能如下:
|
||||
|
||||
1. 完全专注于准备和烹饪食物,包括等待食物烹饪(60 分钟)
|
||||
2. 将脏盘子移到水槽中(65 分钟过去了)
|
||||
3. 清洗所有盘子(125 分钟过去了)
|
||||
4. 开始完全专注于洗衣服,包括等待洗衣机洗完,然后将衣物转移到烘干机,再等烘干机完成( 250 分钟过去了)
|
||||
5. 对地板进行真空吸尘(280 分钟了)
|
||||
|
||||
从头到尾完成所有事情花费了 4 小时 40 分钟。
|
||||
|
||||
我应该像异步程序一样聪明地工作,而不是努力工作。我的家里到处都是可以为我工作的机器,而不用我一直努力工作。同时,现在我可以将注意力转移真正需要的东西上。
|
||||
|
||||
我的执行顺序可能看起来像:
|
||||
|
||||
1. 将衣物放入洗衣机并启动它(5 分钟)
|
||||
2. 在洗衣机运行时,准备食物(25 分钟过去了)
|
||||
3. 准备好食物后,开始烹饪食物(30 分钟过去了)
|
||||
4. 在烹饪食物时,将衣物从洗衣机移到烘干机机中开始烘干(35 分钟过去了)
|
||||
5. 当烘干机运行中,且食物仍在烹饪时,对地板进行真空吸尘(65 分钟过去了)
|
||||
6. 吸尘后,将食物从炉子中取出并装盘子入洗碗机(70 分钟过去了)
|
||||
7. 运行洗碗机(130 分钟完成)
|
||||
|
||||
现在花费的时间下降到 2 小时 10 分钟。即使我允许在作业之间切换花费更多时间(总共 10-20 分钟)。如果我等待着按顺序执行每项任务,我花费的时间仍然只有一半左右。这就是将程序构造为异步的强大功能。
|
||||
|
||||
#### 那么 I/O 循环在哪里?
|
||||
|
||||
一个异步 Python 程序的工作方式是从某个外部源(输入)获取数据,如果某个进程需要,则将该数据转移到某个外部工作者(输出)进行处理。当外部进程完成时,Python 主程序会收到提醒,然后程序获取外部处理(输入)的结果,并继续这样其乐融融的方式。
|
||||
|
||||
当数据不在 Python 主程序手中时,主程序就会被释放来处理其它任何事情。包括等待全新的输入(如 HTTP 请求)和处理长时间运行的进程的结果(如机器学习算法的结果,长时间运行的数据库查询)。主程序虽仍然是单线程的,但成了事件驱动的,它对程序处理的特定事件会触发动作。监听这些事件并指示应如何处理它们的主要是 I/O 循环在工作。
|
||||
|
||||
我知道,我们走了很长的路才得到这个重要的解释,但我希望在这里传达的是,它不是魔术,也不是某种复杂的并行处理或多线程工作。全局解释器锁仍然存在,主程序中任何长时间运行的进程仍然会阻塞其它任何事情的进行,该程序仍然是单线程的。然而,通过将繁琐的工作外部化,我们可以将线程的注意力集中在它需要注意的地方。
|
||||
|
||||
这有点像我上面的异步任务。当我的注意力完全集中在准备食物上时,它就是我所能做的一切。然而,当我能让炉子帮我做饭,洗碗机帮我洗碗,洗衣机和烘干机帮我洗衣服时,我的注意力就会被释放出来,去做其它事情。当我被提醒,我的一个长时间运行的任务已经完成并准备再次处理时,如果我的注意力是空闲的,我可以获取该任务的结果,并对其做下一步需要做的任何事情。
|
||||
|
||||
### Tornado 路由和视图
|
||||
|
||||
尽管经历了在 Python 中讨论异步的所有麻烦,我们还是决定暂不使用它。先来编写一个基本的 Tornado 视图。
|
||||
|
||||
与我们在 Flask 和 Pyramid 实现中看到的基于函数的视图不同,Tornado 的视图都是基于类的。这意味着我们将不在使用单独的、独立的函数来规定如何处理请求。相反,传入的 HTTP 请求将被捕获并将其分配为我们定义的类的一个属性。然后,它的方法将处理相应的请求类型。
|
||||
|
||||
让我们从一个基本的视图开始,即在屏幕上打印 “Hello, World”。我们为 Tornado 应用程序构造的每个基于类的视图都必须继承 `tornado.web` 中的 `RequestHandler` 对象。这将设置我们需要(但不想写)的所有底层逻辑来接收请求,同时构造正确格式的 HTTP 响应。
|
||||
|
||||
```
|
||||
from tornado.web import RequestHandler
|
||||
|
||||
class HelloWorld(RequestHandler):
|
||||
"""Print 'Hello, world!' as the response body."""
|
||||
|
||||
def get(self):
|
||||
"""Handle a GET request for saying Hello World!."""
|
||||
self.write("Hello, world!")
|
||||
```
|
||||
|
||||
因为我们要处理 `GET` 请求,所以我们声明(实际上是重写)了 `get` 方法。我们提供文本或 JSON 可序列化对象,用 `self.write` 写入响应体。之后,我们让 `RequestHandler` 来做在发送响应之前必须完成的其它工作。
|
||||
|
||||
就目前而言,此视图与 Tornado 应用程序本身并没有实际连接。我们必须回到 `__init__.py`,并稍微更新 `main` 函数。以下是新的内容:
|
||||
|
||||
```
|
||||
# __init__.py
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.options import define, options
|
||||
from tornado.web import Application
|
||||
from todo.views import HelloWorld
|
||||
|
||||
define('port', default=8888, help='port to listen on')
|
||||
|
||||
def main():
|
||||
"""Construct and serve the tornado application."""
|
||||
app = Application([
|
||||
('/', HelloWorld)
|
||||
])
|
||||
http_server = HTTPServer(app)
|
||||
http_server.listen(options.port)
|
||||
print('Listening on http://localhost:%i' % options.port)
|
||||
IOLoop.current().start()
|
||||
```
|
||||
|
||||
#### 我们做了什么
|
||||
|
||||
我们将 `views.py` 文件中的 `HelloWorld` 视图导入到脚本 `__init__.py` 的顶部。然后我们添加了一个路由-视图对应的列表,作为 `Application` 实例化的第一个参数。每当我们想要在应用程序中声明一个路由时,它必须绑定到一个视图。如果需要,可以对多个路由使用相同的视图,但每个路由必须有一个视图。
|
||||
|
||||
我们可以通过在 `setup.py` 中启用的 `serve_app` 命令来运行应用程序,从而确保这一切都能正常工作。查看 `http://localhost:8888/` 并看到它显示 “Hello, world!”。
|
||||
|
||||
当然,在这个领域中我们还能做更多,也将做更多,但现在让我们来讨论模型吧。
|
||||
|
||||
### 连接数据库
|
||||
|
||||
如果我们想要保留数据,就需要连接数据库。与 Flask 一样,我们将使用一个特定于框架的 SQLAchemy 变体,名为 [tornado-sqlalchemy][7]。
|
||||
|
||||
为什么要使用它而不是 [SQLAlchemy][8] 呢?好吧,其实 `tornado-sqlalchemy` 具有简单 SQLAlchemy 的所有优点,因此我们仍然可以使用通用的 `Base` 声明模型,并使用我们习以为常的所有列数据类型和关系。除了我们已经惯常了解到的,`tornado-sqlalchemy` 还为其数据库查询功能提供了一种可访问的异步模式,专门用于与 Tornado 现有的 I/O 循环一起工作。
|
||||
|
||||
我们通过将 `tornado-sqlalchemy` 和 `psycopg2` 添加到 `setup.py` 到所需包的列表并重新安装包来创建环境。在 `models.py` 中,我们声明了模型。这一步看起来与我们在 Flask 和 Pyramid 中已经看到的完全一样,所以我将跳过全部声明,只列出了 `Task` 模型的必要部分。
|
||||
|
||||
```
|
||||
# 这不是完整的 models.py, 但是足够看到不同点
|
||||
from tornado_sqlalchemy import declarative_base
|
||||
|
||||
Base = declarative_base
|
||||
|
||||
class Task(Base):
|
||||
# 等等,因为剩下的几乎所有的东西都一样 ...
|
||||
```
|
||||
|
||||
我们仍然需要将 `tornado-sqlalchemy` 连接到实际应用程序。在 `__init__.py` 中,我们将定义数据库并将其集成到应用程序中。
|
||||
|
||||
```
|
||||
# __init__.py
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.options import define, options
|
||||
from tornado.web import Application
|
||||
from todo.views import HelloWorld
|
||||
|
||||
# add these
|
||||
import os
|
||||
from tornado_sqlalchemy import make_session_factory
|
||||
|
||||
define('port', default=8888, help='port to listen on')
|
||||
factory = make_session_factory(os.environ.get('DATABASE_URL', ''))
|
||||
|
||||
def main():
|
||||
"""Construct and serve the tornado application."""
|
||||
app = Application([
|
||||
('/', HelloWorld)
|
||||
],
|
||||
session_factory=factory
|
||||
)
|
||||
http_server = HTTPServer(app)
|
||||
http_server.listen(options.port)
|
||||
print('Listening on http://localhost:%i' % options.port)
|
||||
IOLoop.current().start()
|
||||
```
|
||||
|
||||
就像我们在 Pyramid 中传递的会话工厂一样,我们可以使用 `make_session_factory` 来接收数据库 URL 并生成一个对象,这个对象的唯一目的是为视图提供到数据库的连接。然后我们将新创建的 `factory` 传递给 `Application` 对象,并使用 `session_factory` 关键字参数将它绑定到应用程序中。
|
||||
|
||||
最后,初始化和管理数据库与 Flask 和 Pyramid 相同(即,单独的 DB 管理脚本,与 `Base` 对象一起工作等)。它看起来很相似,所以在这里我就不介绍了。
|
||||
|
||||
### 回顾视图
|
||||
|
||||
Hello,World 总是适合学习基础知识,但我们需要一些真实的,特定应用程序的视图。
|
||||
|
||||
让我们从 info 视图开始。
|
||||
|
||||
```
|
||||
# views.py
|
||||
import json
|
||||
from tornado.web import RequestHandler
|
||||
|
||||
class InfoView(RequestHandler):
|
||||
"""只允许 GET 请求"""
|
||||
SUPPORTED_METHODS = ["GET"]
|
||||
|
||||
def set_default_headers(self):
|
||||
"""设置默认响应头为 json 格式的"""
|
||||
self.set_header("Content-Type", 'application/json; charset="utf-8"')
|
||||
|
||||
def get(self):
|
||||
"""列出这个 API 的路由"""
|
||||
routes = {
|
||||
'info': 'GET /api/v1',
|
||||
'register': 'POST /api/v1/accounts',
|
||||
'single profile detail': 'GET /api/v1/accounts/<username>',
|
||||
'edit profile': 'PUT /api/v1/accounts/<username>',
|
||||
'delete profile': 'DELETE /api/v1/accounts/<username>',
|
||||
'login': 'POST /api/v1/accounts/login',
|
||||
'logout': 'GET /api/v1/accounts/logout',
|
||||
"user's tasks": 'GET /api/v1/accounts/<username>/tasks',
|
||||
"create task": 'POST /api/v1/accounts/<username>/tasks',
|
||||
"task detail": 'GET /api/v1/accounts/<username>/tasks/<id>',
|
||||
"task update": 'PUT /api/v1/accounts/<username>/tasks/<id>',
|
||||
"delete task": 'DELETE /api/v1/accounts/<username>/tasks/<id>'
|
||||
}
|
||||
self.write(json.dumps(routes))
|
||||
```
|
||||
|
||||
有什么改变吗?让我们从上往下看。
|
||||
|
||||
我们添加了 `SUPPORTED_METHODS` 类属性,它是一个可迭代对象,代表这个视图所接受的请求方法,其他任何方法都将返回一个 [405][9] 状态码。当我们创建 `HelloWorld` 视图时,我们没有指定它,主要是当时有点懒。如果没有这个类属性,此视图将响应任何试图绑定到该视图的路由的请求。
|
||||
|
||||
我们声明了 `set_default_headers` 方法,它设置 HTTP 响应的默认头。我们在这里声明它,以确保我们返回的任何响应都有一个 `"Content-Type"` 是 `"application/json"` 类型。
|
||||
|
||||
我们将 `json.dumps(some_object)` 添加到 `self.write` 的参数中,因为它可以很容易地构建响应主体的内容。
|
||||
|
||||
现在已经完成了,我们可以继续将它连接到 `__init__.py` 中的主路由。
|
||||
|
||||
```
|
||||
# __init__.py
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.options import define, options
|
||||
from tornado.web import Application
|
||||
from todo.views import InfoView
|
||||
|
||||
# 添加这些
|
||||
import os
|
||||
from tornado_sqlalchemy import make_session_factory
|
||||
|
||||
define('port', default=8888, help='port to listen on')
|
||||
factory = make_session_factory(os.environ.get('DATABASE_URL', ''))
|
||||
|
||||
def main():
|
||||
"""Construct and serve the tornado application."""
|
||||
app = Application([
|
||||
('/', InfoView)
|
||||
],
|
||||
session_factory=factory
|
||||
)
|
||||
http_server = HTTPServer(app)
|
||||
http_server.listen(options.port)
|
||||
print('Listening on http://localhost:%i' % options.port)
|
||||
IOLoop.current().start()
|
||||
```
|
||||
|
||||
我们知道,还需要编写更多的视图和路由。每个都会根据需要放入 `Application` 路由列表中,每个视图还需要一个 `set_default_headers` 方法。在此基础上,我们还将创建 `send_response` 方法,它的作用是将响应与我们想要给响应设置的任何自定义状态码打包在一起。由于每个视图都需要这两个方法,因此我们可以创建一个包含它们的基类,这样每个视图都可以继承基类。这样,我们只需要编写一次。
|
||||
|
||||
```
|
||||
# views.py
|
||||
import json
|
||||
from tornado.web import RequestHandler
|
||||
|
||||
class BaseView(RequestHandler):
|
||||
"""Base view for this application."""
|
||||
|
||||
def set_default_headers(self):
|
||||
"""Set the default response header to be JSON."""
|
||||
self.set_header("Content-Type", 'application/json; charset="utf-8"')
|
||||
|
||||
def send_response(self, data, status=200):
|
||||
"""Construct and send a JSON response with appropriate status code."""
|
||||
self.set_status(status)
|
||||
self.write(json.dumps(data))
|
||||
```
|
||||
|
||||
对于我们即将编写的 `TaskListView` 这样的视图,我们还需要一个到数据库的连接。我们需要 `tornado_sqlalchemy` 中的 `SessionMixin` 在每个视图类中添加一个数据库会话。我们可以将它放在 `BaseView` 中,这样,默认情况下,从它继承的每个视图都可以访问数据库会话。
|
||||
|
||||
```
|
||||
# views.py
|
||||
import json
|
||||
from tornado_sqlalchemy import SessionMixin
|
||||
from tornado.web import RequestHandler
|
||||
|
||||
class BaseView(RequestHandler, SessionMixin):
|
||||
"""Base view for this application."""
|
||||
|
||||
def set_default_headers(self):
|
||||
"""Set the default response header to be JSON."""
|
||||
self.set_header("Content-Type", 'application/json; charset="utf-8"')
|
||||
|
||||
def send_response(self, data, status=200):
|
||||
"""Construct and send a JSON response with appropriate status code."""
|
||||
self.set_status(status)
|
||||
self.write(json.dumps(data))
|
||||
```
|
||||
|
||||
只要我们修改 `BaseView` 对象,在将数据发布到这个 API 时,我们就应该定位到这里。
|
||||
|
||||
当 Tornado(从 v.4.5 开始)使用来自客户端的数据并将其组织起来到应用程序中使用时,它会将所有传入数据视为字节串。但是,这里的所有代码都假设使用 Python 3,因此我们希望使用的唯一字符串是 Unicode 字符串。我们可以为这个 `BaseView` 类添加另一个方法,它的工作是将输入数据转换为 Unicode,然后再在视图的其他地方使用。
|
||||
|
||||
如果我们想要在正确的视图方法中使用它之前转换这些数据,我们可以重写视图类的原生 `prepare` 方法。它的工作是在视图方法运行前运行。如果我们重写 `prepare` 方法,我们可以设置一些逻辑来运行,每当收到请求时,这些逻辑就会执行字节串到 Unicode 的转换。
|
||||
|
||||
```
|
||||
# views.py
|
||||
import json
|
||||
from tornado_sqlalchemy import SessionMixin
|
||||
from tornado.web import RequestHandler
|
||||
|
||||
class BaseView(RequestHandler, SessionMixin):
|
||||
"""Base view for this application."""
|
||||
|
||||
def prepare(self):
|
||||
self.form_data = {
|
||||
key: [val.decode('utf8') for val in val_list]
|
||||
for key, val_list in self.request.arguments.items()
|
||||
}
|
||||
|
||||
def set_default_headers(self):
|
||||
"""Set the default response header to be JSON."""
|
||||
self.set_header("Content-Type", 'application/json; charset="utf-8"')
|
||||
|
||||
def send_response(self, data, status=200):
|
||||
"""Construct and send a JSON response with appropriate status code."""
|
||||
self.set_status(status)
|
||||
self.write(json.dumps(data))
|
||||
```
|
||||
|
||||
如果有任何数据进入,它将在 `self.request.arguments` 字典中找到。我们可以通过键访问该数据库,并将其内容(始终是列表)转换为 Unicode。因为这是基于类的视图而不是基于函数的,所以我们可以将修改后的数据存储为一个实例属性,以便以后使用。我在这里称它为 `form_data`,但它也可以被称为 `potato`。关键是我们可以存储提交给应用程序的数据。
|
||||
|
||||
### 异步视图方法
|
||||
|
||||
现在我们已经构建了 `BaseaView`,我们可以构建 `TaskListView` 了,它会继承 `BaseaView`。
|
||||
|
||||
正如你可以从章节标题中看到的那样,以下是所有关于异步性的讨论。`TaskListView` 将处理返回任务列表的 `GET` 请求和用户给定一些表单数据来创建新任务的 `POST` 请求。让我们首先来看看处理 `GET` 请求的代码。
|
||||
|
||||
```
|
||||
# all the previous imports
|
||||
import datetime
|
||||
from tornado.gen import coroutine
|
||||
from tornado_sqlalchemy import as_future
|
||||
from todo.models import Profile, Task
|
||||
|
||||
# the BaseView is above here
|
||||
class TaskListView(BaseView):
|
||||
"""View for reading and adding new tasks."""
|
||||
SUPPORTED_METHODS = ("GET", "POST",)
|
||||
|
||||
@coroutine
|
||||
def get(self, username):
|
||||
"""Get all tasks for an existing user."""
|
||||
with self.make_session() as session:
|
||||
profile = yield as_future(session.query(Profile).filter(Profile.username == username).first)
|
||||
if profile:
|
||||
tasks = [task.to_dict() for task in profile.tasks]
|
||||
self.send_response({
|
||||
'username': profile.username,
|
||||
'tasks': tasks
|
||||
})
|
||||
```
|
||||
|
||||
这里的第一个主要部分是 `@coroutine` 装饰器,它从 `tornado.gen` 导入。任何具有与调用堆栈的正常流程不同步的 Python 可调用部分实际上是“协程”,即一个可以与其它协程一起运行的协程。在我的家务劳动的例子中,几乎所有的家务活都是一个共同的例行协程。有些阻止了例行协程(例如,给地板吸尘),但这种例行协程只会阻碍我开始或关心其它任何事情的能力。它没有阻止已经启动的任何其他协程继续进行。
|
||||
|
||||
Tornado 提供了许多方法来构建一个利用协程的应用程序,包括允许我们设置函数调用锁,同步异步协程的条件,以及手动修改控制 I/O 循环的事件系统。
|
||||
|
||||
这里使用 `@coroutine` 装饰器的唯一条件是允许 `get` 方法将 SQL 查询作为后台进程,并在查询完成后恢复,同时不阻止 Tornado I/O 循环去处理其他传入的数据源。这就是关于此实现的所有“异步”:带外数据库查询。显然,如果我们想要展示异步 Web 应用程序的魔力和神奇,那么一个任务列表就不是好的展示方式。
|
||||
|
||||
但是,这就是我们正在构建的,所以让我们来看看方法如何利用 `@coroutine` 装饰器。`SessionMixin` 混合到 `BaseView` 声明中,为我们的视图类添加了两个方便的,支持数据库的属性:`session` 和 `make_session`。它们的名字相似,实现的目标也相当相似。
|
||||
|
||||
`self.session` 属性是一个关注数据库的会话。在请求-响应周期结束时,在视图将响应发送回客户端之前,任何对数据库的更改都被提交,并关闭会话。
|
||||
|
||||
`self.make_session` 是一个上下文管理器和生成器,可以动态构建和返回一个全新的会话对象。第一个 `self.session` 对象仍然存在。无论如何,反正 `make_session` 会创建一个新的。`make_session` 生成器还为其自身提供了一个功能,用于在其上下文(即缩进级别)结束时提交和关闭它创建的会话。
|
||||
|
||||
如果你查看源代码,则赋值给 `self.session` 的对象类型与 `self.make_session` 生成的对象类型之间没有区别,不同之处在于它们是如何被管理的。
|
||||
|
||||
使用 `make_session` 上下文管理器,生成的会话仅属于上下文,在该上下文中开始和结束。你可以使用 `make_session` 上下文管理器在同一个视图中打开,修改,提交以及关闭多个数据库会话。
|
||||
|
||||
`self.session` 要简单得多,当你进入视图方法时会话已经打开,在响应被发送回客户端之前会话就已提交。
|
||||
|
||||
虽然[读取文档片段][10]和 [PyPI 示例][11]都说明了上下文管理器的使用,但是没有说明 `self.session` 对象或由 `self.make_session` 生成的 `session` 本质上是不是异步的。当我们启动查询时,我们开始考虑内置于 `tornado-sqlalchemy` 中的异步行为。
|
||||
|
||||
`tornado-sqlalchemy` 包为我们提供了 `as_future` 函数。它的工作是装饰 `tornado-sqlalchemy` 会话构造的查询并 yield 其返回值。如果视图方法用 `@coroutine` 装饰,那么使用 `yield as_future(query)` 模式将使封装的查询成为一个异步后台进程。I/O 循环会接管等待查询的返回值和 `as_future` 创建的 `future` 对象的解析。
|
||||
|
||||
要访问 `as_future(query)` 的结果,你必须从它 `yield`。否则,你只能获得一个未解析的生成器对象,并且无法对查询执行任何操作。
|
||||
|
||||
这个视图方法中的其他所有内容都与之前课堂上的类似,与我们在 Flask 和 Pyramid 中看到的内容类似。
|
||||
|
||||
`post` 方法看起来非常相似。为了保持一致性,让我们看一下 `post` 方法以及它如何处理用 `BaseView` 构造的 `self.form_data`。
|
||||
|
||||
```
|
||||
@coroutine
|
||||
def post(self, username):
|
||||
"""Create a new task."""
|
||||
with self.make_session() as session:
|
||||
profile = yield as_future(session.query(Profile).filter(Profile.username == username).first)
|
||||
if profile:
|
||||
due_date = self.form_data['due_date'][0]
|
||||
task = Task(
|
||||
name=self.form_data['name'][0],
|
||||
note=self.form_data['note'][0],
|
||||
creation_date=datetime.now(),
|
||||
due_date=datetime.strptime(due_date, '%d/%m/%Y %H:%M:%S') if due_date else None,
|
||||
completed=self.form_data['completed'][0],
|
||||
profile_id=profile.id,
|
||||
profile=profile
|
||||
)
|
||||
session.add(task)
|
||||
self.send_response({'msg': 'posted'}, status=201)
|
||||
```
|
||||
|
||||
正如我所说,这是我们所期望的:
|
||||
|
||||
* 与我们在 `get` 方法中看到的查询模式相同
|
||||
* 构造一个新的 `Task` 对象的实例,用 `form_data` 的数据填充
|
||||
* 添加新的 `Task` 对象(但不提交,因为它由上下文管理器处理!)到数据库会话
|
||||
* 将响应发送给客户端
|
||||
|
||||
这样我们就有了 Tornado web 应用程序的基础。其他内容(例如,数据库管理和更多完整应用程序的视图)实际上与我们在 Flask 和 Pyramid 应用程序中看到的相同。
|
||||
|
||||
### 关于使用合适的工具完成合适的工作的一点想法
|
||||
|
||||
在我们继续浏览这些 Web 框架时,我们开始看到它们都可以有效地处理相同的问题。对于像这样的待办事项列表,任何框架都可以完成这项任务。但是,有些 Web 框架比其它框架更适合某些工作,这具体取决于对你来说什么“更合适”和你的需求。
|
||||
|
||||
虽然 Tornado 显然和 Pyramid 或 Flask 一样可以处理相同工作,但将它用于这样的应用程序实际上是一种浪费,这就像开车从家走一个街区(LCTT 译注:这里意思应该是从家开始走一个街区只需步行即可)。是的,它可以完成“旅行”的工作,但短途旅行不是你选择汽车而不是自行车或者使用双脚的原因。
|
||||
|
||||
根据文档,Tornado 被称为 “Python Web 框架和异步网络库”。在 Python Web 框架生态系统中很少有人喜欢它。如果你尝试完成的工作需要(或将从中获益)以任何方式、形状或形式的异步性,使用 Tornado。如果你的应用程序需要处理多个长期连接,同时又不想牺牲太多性能,选择 Tornado。如果你的应用程序是多个应用程序,并且需要线程感知以准确处理数据,使用 Tornado。这是它最有效的地方。
|
||||
|
||||
用你的汽车做“汽车的事情”,使用其他交通工具做其他事情。
|
||||
|
||||
### 向前看,进行一些深度检查
|
||||
|
||||
谈到使用合适的工具来完成合适的工作,在选择框架时,请记住应用程序的范围和规模,包括现在和未来。到目前为止,我们只研究了适用于中小型 Web 应用程序的框架。本系列的下一篇也是最后一篇将介绍最受欢迎的 Python 框架之一 Django,它适用于可能会变得更大的大型应用程序。同样,尽管它在技术上能够并且将会处理待办事项列表问题,但请记住,这不是它的真正用途。我们仍然会通过它来展示如何使用它来构建应用程序,但我们必须牢记框架的意图以及它是如何反映在架构中的:
|
||||
|
||||
* **Flask**: 适用于小型,简单的项目。它可以使我们轻松地构建视图并将它们快速连接到路由,它可以简单地封装在一个文件中。
|
||||
* **Pyramid**: 适用于可能增长的项目。它包含一些配置来启动和运行。应用程序组件的独立领域可以很容易地划分并构建到任意深度,而不会忽略中央应用程序。
|
||||
* **Tornado**: 适用于受益于精确和有意识的 I/O 控制的项目。它允许协程,并轻松公开可以控制如何接收请求或发送响应以及何时发生这些操作的方法。
|
||||
* **Django**:(我们将会看到)意味着可能会变得更大的东西。它有着非常庞大的生态系统,包括大量插件和模块。它非常有主见的配置和管理,以保持所有不同部分在同一条线上。
|
||||
|
||||
无论你是从本系列的第一篇文章开始阅读,还是稍后才加入的,都要感谢阅读!请随意留下问题或意见。下次再见时,我手里会拿着 Django。
|
||||
|
||||
### 感谢 Python BDFL
|
||||
|
||||
我必须把功劳归于它应得的地方,非常感谢 [Guido van Rossum][12],不仅仅是因为他创造了我最喜欢的编程语言。
|
||||
|
||||
在 [PyCascades 2018][13] 期间,我很幸运的不仅做了基于这个文章系列的演讲,而且还被邀请参加了演讲者的晚宴。整个晚上我都坐在 Guido 旁边,不停地问他问题。其中一个问题是,在 Python 中异步到底是如何工作的,但他没有一点大惊小怪,而是花时间向我解释,让我开始理解这个概念。他后来[推特给我][14]发了一条消息:是用于学习异步 Python 的广阔资源。我随后在三个月内阅读了三次,然后写了这篇文章。你真是一个非常棒的人,Guido!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/tornado-framework
|
||||
|
||||
作者:[Nicholas Hunt-Walker][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/nhuntwalker
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/article/18/5/pyramid-framework
|
||||
[2]: https://opensource.com/article/18/4/flask
|
||||
[3]: https://tornado.readthedocs.io/en/stable/
|
||||
[4]: https://realpython.com/python-gil/
|
||||
[5]: https://en.wikipedia.org/wiki/Thread_(computing)
|
||||
[6]: https://www.nginx.com/
|
||||
[7]: https://tornado-sqlalchemy.readthedocs.io/en/latest/
|
||||
[8]: https://www.sqlalchemy.org/
|
||||
[9]: https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors
|
||||
[10]: https://tornado-sqlalchemy.readthedocs.io/en/latest/#usage
|
||||
[11]: https://pypi.org/project/tornado-sqlalchemy/#description
|
||||
[12]: https://www.twitter.com/gvanrossum
|
||||
[13]: https://www.pycascades.com
|
||||
[14]: https://twitter.com/gvanrossum/status/956186585493458944
|
@ -0,0 +1,138 @@
|
||||
如何从 Linux 上连接到远程桌面
|
||||
======
|
||||
|
||||
> Remmina 的极简用户界面使得远程访问 Linux / Windows 10 变得轻松。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003499_01_cloud21x_cc.png?itok=5UwC92dO)
|
||||
|
||||
根据维基百科,[远程桌面][1] 是一种“软件或者操作系统特性,它可以让个人电脑上的桌面环境在一个系统(通常是电脑,但是也可以是服务器)上远程运行,但在另一个分开的客户端设备显示”。
|
||||
|
||||
换句话说,远程桌面是用来访问在另一台电脑上运行的环境的。比如说 [ManageIQ/Integration tests][2] 仓库的拉取请求 (PR) 测试系统开放了一个虚拟网络计算 (VNC) 连接端口,使得我能够远程浏览正被实时测试的拉取请求。远程桌面也被用于帮助客户解决电脑问题:在客户的许可下,你可以远程建立 VNC 或者远程桌面协议(RDP)连接来查看或者交互式地访问该电脑以寻找并解决问题。
|
||||
|
||||
运用远程桌面连接软件可以建立这些连接。可供选择的软件有很多,我用 [Remmina][3],因为我喜欢它极简、好用的用户界面 (UI)。它是用 GTK+ 编写的,在 GNU GPL 许可证开源。
|
||||
|
||||
在这篇文章里,我会解释如何使用 Remmina 客户端从一台 Linux 电脑上远程连接到 Windows 10 系统 和 Red Hat 企业版 Linux 7 系统。
|
||||
|
||||
### 在 Linux 上安装 Remmina
|
||||
|
||||
首先,你需要在你用来远程访问其它电脑的的主机上安装 Remmina。如果你用的是 Fedora,你可以运行如下的命令来安装 Remmina:
|
||||
|
||||
```
|
||||
sudo dnf install -y remmina
|
||||
```
|
||||
|
||||
如果你想在一个不同的 Linux 平台上安装 Remmina,跟着 [安装教程][4] 走。然后你会发现 Remmina 正和你其它软件出现在一起(在这张图片里选中了 Remmina)。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina1-on-desktop.png)
|
||||
|
||||
点击图标运行 Remmina,你应该能看到像这样的屏幕:
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina2_launched.png)
|
||||
|
||||
Remmina 提供不同种类的连接,其中包括用来连接到 Windows 系统的 RDP 和用来连接到 Linux 系统的 VNC。如你在上图左上角所见的,Remmina 的默认设置是 RDP。
|
||||
|
||||
### 连接到 Windows 10
|
||||
|
||||
在你通过 RDP 连接到一台 Windows 10 电脑之前,你必须修改权限以允许分享远程桌面并通过防火墙建立连接。
|
||||
|
||||
- [注意: Windows 10 家庭版没有列入 RDP 特性][5]
|
||||
|
||||
要许可远程桌面分享,在“文件管理器”界面右击“我的电脑 → 属性 → 远程设置”,接着在跳出的窗口中,勾选“在这台电脑上允许远程连接”,再点击“应用”。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina3_connect_win10.png)
|
||||
|
||||
然后,允许远程连接通过你的防火墙。首先在“开始菜单”中查找“防火墙设置”,选择“允许应用通过防火墙”。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina4_firewall.png)
|
||||
|
||||
在打开的窗口中,在“允许的应用和特性”下找到“远程桌面”。根据你用来访问这个桌面的网络酌情勾选“隐私”和/或“公开”列的选框。点击“确定”。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina5_firewall_2.png)
|
||||
|
||||
回到你用来远程访问 Windows 主机的 Linux 电脑,打开 Remmina。输入你的 Windows 主机的 IP 地址,敲击回车键。(我怎么在 [Linux][6] 和 [Windws][7] 中确定我的 IP 地址?)看到提示后,输入你的用户名和密码,点击“确定”。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina6_login.png)
|
||||
|
||||
如果你被询问是否接受证书,点击“确定”。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina7_certificate.png)
|
||||
|
||||
你此时应能看到你的 Windows 10 主机桌面。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina8_remote_desktop.png)
|
||||
|
||||
### 连接到 Red Hat 企业版 Linux 7
|
||||
|
||||
要在你的 RHEL7 电脑上允许远程访问,在 Linux 桌面上打开“所有设置”。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina9_settings.png)
|
||||
|
||||
点击分享图标会打开如下的窗口:
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina10_sharing.png)
|
||||
|
||||
如果“屏幕分享”处于关闭状态,点击一下。一个窗口会弹出,你可以滑动到“打开”的位置。如果你想允许远程控制桌面,将“允许远程控制”调到“打开”。你同样也可以在两种访问选项间选择:一个能够让电脑的主要用户接受或者否绝连接要求,另一个能用密码验证连接。在窗口底部,选择被允许连接的网络界面,最后关闭窗口。
|
||||
|
||||
接着,从“应用菜单 → 其它 → 防火墙”打开“防火墙设置”。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina11_firewall_settings.png)
|
||||
|
||||
勾选 “vnc-server”旁边的选框(如下图所示)关闭窗口。接着直接到你远程电脑上的 Remmina,输入你想连接到的 Linux 桌面的 IP 地址,选择 VNC 作为协议,点击回车键。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina12_vncprotocol.png)
|
||||
|
||||
如果你之前选择的验证选项是“新连接必须询问访问许可”,RHEL 系统用户会看到这样的一个弹窗:
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina13_permission.png)
|
||||
|
||||
点击“接受”以成功进行远程连接。
|
||||
|
||||
如果你选择用密码验证连接,Remmina 会向你询问密码。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina14_password-auth.png)
|
||||
|
||||
输入密码然后“确认”,你应该能连接到远程电脑。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina15_connected.png)
|
||||
|
||||
### 使用 Remmina
|
||||
|
||||
Remmina 提供如上图所示的标签化的 UI,就好像一个浏览器一样。在上图所示的左上角你可以看到两个标签:一个是之前建立的 WIndows 10 连接,另一个新的是 RHEL 连接。
|
||||
|
||||
在窗口的左侧,有一个有着“缩放窗口”、“全屏模式”、“偏好”、“截屏”、“断开连接”等选项的工具栏。你可以自己探索看那种适合你。
|
||||
|
||||
你也可以通过点击左上角的“+”号创建保存过的连接。根据你的连接情况填好表单点击“保存”。以下是一个 Windows 10 RDP 连接的示例:
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina16_saved-connection.png)
|
||||
|
||||
下次你打开 Remmina 时连接就在那了。
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/remmina17_connection-available.png)
|
||||
|
||||
点击一下它,你不用补充细节就可以建立连接了。
|
||||
|
||||
### 补充说明
|
||||
|
||||
当你使用远程桌面软件时,你所有的操作都在远程桌面上消耗资源 —— Remmina(或者其它类似软件)仅仅是一种与远程桌面交互的方式。你也可以通过 SSH 远程访问一台电脑,但那将会让你在那台电脑上局限于仅能使用文字的终端。
|
||||
|
||||
你也应当注意到当你允许你的电脑远程连接时,如果一名攻击者用这种方法获得你电脑的访问权同样会给你带来严重损失。因此当你不频繁使用远程桌面时,禁止远程桌面连接以及其在防火墙中相关的服务是很明智的做法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/6/linux-remote-desktop
|
||||
|
||||
作者:[Kedar Vijay Kulkarni][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[tomjlw](https://github.com/tomjlw)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/kkulkarn
|
||||
[1]:https://en.wikipedia.org/wiki/Remote_desktop_software
|
||||
[2]:https://github.com/ManageIQ/integration_tests
|
||||
[3]:https://www.remmina.org/wp/
|
||||
[4]:https://www.tecmint.com/remmina-remote-desktop-sharing-and-ssh-client/
|
||||
[5]:https://superuser.com/questions/1019203/remote-desktop-settings-missing#1019212
|
||||
[6]:https://opensource.com/article/18/5/how-find-ip-address-linux
|
||||
[7]:https://www.groovypost.com/howto/find-windows-10-device-ip-address/
|
@ -0,0 +1,339 @@
|
||||
如何搜索一个包是否在你的 Linux 发行版中
|
||||
======
|
||||
|
||||
如果你知道包名称,那么你可以直接安装所需的包。
|
||||
|
||||
在某些情况下,如果你不知道确切的包名称或者你想搜索某些包,那么你可以在发行版的包管理器的帮助下轻松搜索该包。搜索会自动包括已安装和可用的包。结果的格式取决于选项。如果你的查询没有输出任何信息,那么意味着没有匹配条件的包。这可以通过发行版的包管理器的各种选项来完成。我已经在本文中添加了所有可能的选项,你可以选择最好的和最合适你的选项。
|
||||
|
||||
或者,我们可以通过 `whohas` 命令实现这一点。它会从所有的主流发行版(例如 Debian、Ubuntu、 Fedora 等)中搜索,而不仅仅是你自己的系统发行版。
|
||||
|
||||
建议阅读:
|
||||
|
||||
- [适用于 Linux 的命令行包管理器列表以及用法][1]
|
||||
- [Linux 包管理器的图形前端工具][2]
|
||||
|
||||
### 如何在 Debian/Ubuntu 中搜索一个包
|
||||
|
||||
我们可以使用 `apt`、`apt-cache` 和 `aptitude` 包管理器在基于 Debian 的发行版上查找给定的包。我为这个包管理器中包括了大量的选项。
|
||||
|
||||
我们可以在基于 Debian 的系统中使用三种方式完成此操作。
|
||||
|
||||
* `apt` 命令
|
||||
* `apt-cache` 命令
|
||||
* `aptitude` 命令
|
||||
|
||||
#### 如何使用 apt 命令搜索一个包
|
||||
|
||||
APT 代表<ruby>高级包管理工具<rt>Advanced Packaging Tool</rt></ruby>(APT),它取代了 `apt-get`。它有功能丰富的命令行工具,包括所有功能包含在一个命令(`apt`)里,包括 `apt-cache`、`apt-search`、`dpkg`、`apt-cdrom`、`apt-config`、`apt-key` 等,还有其他几个独特的功能。
|
||||
|
||||
APT 是一个强大的命令行工具,它可以访问 libapt-pkg 底层库的所有特性,它可以用于安装、下载、删除、搜索和管理以及查询包的信息,另外它还包含一些较少使用的与包管理相关的命令行实用程序。
|
||||
|
||||
```
|
||||
$ apt -q list nano vlc
|
||||
Listing...
|
||||
nano/artful,now 2.8.6-3 amd64 [installed]
|
||||
vlc/artful 2.2.6-6 amd64
|
||||
```
|
||||
|
||||
或者,我们可以使用以下格式搜索指定的包。
|
||||
|
||||
```
|
||||
$ apt search ^vlc
|
||||
Sorting... Done
|
||||
Full Text Search... Done
|
||||
vlc/artful 2.2.6-6 amd64
|
||||
multimedia player and streamer
|
||||
|
||||
vlc-bin/artful 2.2.6-6 amd64
|
||||
binaries from VLC
|
||||
|
||||
vlc-data/artful,artful 2.2.6-6 all
|
||||
Common data for VLC
|
||||
|
||||
vlc-l10n/artful,artful 2.2.6-6 all
|
||||
Translations for VLC
|
||||
|
||||
vlc-plugin-access-extra/artful 2.2.6-6 amd64
|
||||
multimedia player and streamer (extra access plugins)
|
||||
|
||||
vlc-plugin-base/artful 2.2.6-6 amd64
|
||||
multimedia player and streamer (base plugins)
|
||||
```
|
||||
|
||||
#### 如何使用 apt-cache 命令搜索一个包
|
||||
|
||||
`apt-cache` 会在 APT 的包缓存上执行各种操作。它会显示有关指定包的信息。`apt-cache` 不会改变系统的状态,但提供了从包的元数据中搜索和生成有趣输出的操作。
|
||||
|
||||
```
|
||||
$ apt-cache search nano | grep ^nano
|
||||
nano - small, friendly text editor inspired by Pico
|
||||
nano-tiny - small, friendly text editor inspired by Pico - tiny build
|
||||
nanoblogger - Small weblog engine for the command line
|
||||
nanoblogger-extra - Nanoblogger plugins
|
||||
nanoc - static site generator written in Ruby
|
||||
nanoc-doc - static site generator written in Ruby - documentation
|
||||
nanomsg-utils - nanomsg utilities
|
||||
nanopolish - consensus caller for nanopore sequencing data
|
||||
```
|
||||
|
||||
或者,我们可以使用以下格式搜索指定的包。
|
||||
|
||||
```
|
||||
$ apt-cache policy vlc
|
||||
vlc:
|
||||
Installed: (none)
|
||||
Candidate: 2.2.6-6
|
||||
Version table:
|
||||
2.2.6-6 500
|
||||
500 http://in.archive.ubuntu.com/ubuntu artful/universe amd64 Packages
|
||||
```
|
||||
|
||||
或者,我们可以使用以下格式搜索给定的包。
|
||||
|
||||
```
|
||||
$ apt-cache pkgnames vlc
|
||||
vlc-bin
|
||||
vlc-plugin-video-output
|
||||
vlc-plugin-sdl
|
||||
vlc-plugin-svg
|
||||
vlc-plugin-samba
|
||||
vlc-plugin-fluidsynth
|
||||
vlc-plugin-qt
|
||||
vlc-plugin-skins2
|
||||
vlc-plugin-visualization
|
||||
vlc-l10n
|
||||
vlc-plugin-notify
|
||||
vlc-plugin-zvbi
|
||||
vlc-plugin-vlsub
|
||||
vlc-plugin-jack
|
||||
vlc-plugin-access-extra
|
||||
vlc
|
||||
vlc-data
|
||||
vlc-plugin-video-splitter
|
||||
vlc-plugin-base
|
||||
```
|
||||
|
||||
#### 如何使用 aptitude 命令搜索一个包
|
||||
|
||||
`aptitude` 是一个基于文本的 Debian GNU/Linux 软件包系统的命令行界面。它允许用户查看包列表,并执行包管理任务,例如安装、升级和删除包,它可以从可视化界面或命令行执行操作。
|
||||
|
||||
```
|
||||
$ aptitude search ^vlc
|
||||
p vlc - multimedia player and streamer
|
||||
p vlc:i386 - multimedia player and streamer
|
||||
p vlc-bin - binaries from VLC
|
||||
p vlc-bin:i386 - binaries from VLC
|
||||
p vlc-data - Common data for VLC
|
||||
v vlc-data:i386 -
|
||||
p vlc-l10n - Translations for VLC
|
||||
v vlc-l10n:i386 -
|
||||
p vlc-plugin-access-extra - multimedia player and streamer (extra access plugins)
|
||||
p vlc-plugin-access-extra:i386 - multimedia player and streamer (extra access plugins)
|
||||
p vlc-plugin-base - multimedia player and streamer (base plugins)
|
||||
p vlc-plugin-base:i386 - multimedia player and streamer (base plugins)
|
||||
p vlc-plugin-fluidsynth - FluidSynth plugin for VLC
|
||||
p vlc-plugin-fluidsynth:i386 - FluidSynth plugin for VLC
|
||||
p vlc-plugin-jack - Jack audio plugins for VLC
|
||||
p vlc-plugin-jack:i386 - Jack audio plugins for VLC
|
||||
p vlc-plugin-notify - LibNotify plugin for VLC
|
||||
p vlc-plugin-notify:i386 - LibNotify plugin for VLC
|
||||
p vlc-plugin-qt - multimedia player and streamer (Qt plugin)
|
||||
p vlc-plugin-qt:i386 - multimedia player and streamer (Qt plugin)
|
||||
p vlc-plugin-samba - Samba plugin for VLC
|
||||
p vlc-plugin-samba:i386 - Samba plugin for VLC
|
||||
p vlc-plugin-sdl - SDL video and audio output plugin for VLC
|
||||
p vlc-plugin-sdl:i386 - SDL video and audio output plugin for VLC
|
||||
p vlc-plugin-skins2 - multimedia player and streamer (Skins2 plugin)
|
||||
p vlc-plugin-skins2:i386 - multimedia player and streamer (Skins2 plugin)
|
||||
p vlc-plugin-svg - SVG plugin for VLC
|
||||
p vlc-plugin-svg:i386 - SVG plugin for VLC
|
||||
p vlc-plugin-video-output - multimedia player and streamer (video output plugins)
|
||||
p vlc-plugin-video-output:i386 - multimedia player and streamer (video output plugins)
|
||||
p vlc-plugin-video-splitter - multimedia player and streamer (video splitter plugins)
|
||||
p vlc-plugin-video-splitter:i386 - multimedia player and streamer (video splitter plugins)
|
||||
p vlc-plugin-visualization - multimedia player and streamer (visualization plugins)
|
||||
p vlc-plugin-visualization:i386 - multimedia player and streamer (visualization plugins)
|
||||
p vlc-plugin-vlsub - VLC extension to download subtitles from opensubtitles.org
|
||||
p vlc-plugin-zvbi - VBI teletext plugin for VLC
|
||||
p vlc-plugin-zvbi:i386
|
||||
```
|
||||
|
||||
### 如何在 RHEL/CentOS 中搜索一个包
|
||||
|
||||
Yum(Yellowdog Updater Modified)是 Linux 操作系统中的包管理器实用程序之一。Yum 命令用于在一些基于 RedHat 的 Linux 发行版上,它用来安装、更新、搜索和删除软件包。
|
||||
|
||||
```
|
||||
# yum search ftpd
|
||||
Loaded plugins: fastestmirror, refresh-packagekit, security
|
||||
Loading mirror speeds from cached hostfile
|
||||
* base: centos.hyve.com
|
||||
* epel: mirrors.coreix.net
|
||||
* extras: centos.hyve.com
|
||||
* rpmforge: www.mirrorservice.org
|
||||
* updates: mirror.sov.uk.goscomb.net
|
||||
============================================================== N/S Matched: ftpd ===============================================================
|
||||
nordugrid-arc-gridftpd.x86_64 : ARC gridftp server
|
||||
pure-ftpd.x86_64 : Lightweight, fast and secure FTP server
|
||||
vsftpd.x86_64 : Very Secure Ftp Daemon
|
||||
|
||||
Name and summary matches only, use "search all" for everything.
|
||||
```
|
||||
|
||||
或者,我们可以使用以下命令搜索相同内容。
|
||||
|
||||
```
|
||||
# yum list ftpd
|
||||
```
|
||||
|
||||
### 如何在 Fedora 中搜索一个包
|
||||
|
||||
DNF 代表 Dandified yum。我们可以说 DNF 是下一代 yum 包管理器(Yum 的衍生品),它使用 hawkey/libsolv 库作为底层。Aleš Kozumplík 从 Fedora 18 开始开发 DNF,最终在 Fedora 22 中发布。
|
||||
|
||||
```
|
||||
# dnf search ftpd
|
||||
Last metadata expiration check performed 0:42:28 ago on Tue Jun 9 22:52:44 2018.
|
||||
============================== N/S Matched: ftpd ===============================
|
||||
proftpd-utils.x86_64 : ProFTPD - Additional utilities
|
||||
pure-ftpd-selinux.x86_64 : SELinux support for Pure-FTPD
|
||||
proftpd-devel.i686 : ProFTPD - Tools and header files for developers
|
||||
proftpd-devel.x86_64 : ProFTPD - Tools and header files for developers
|
||||
proftpd-ldap.x86_64 : Module to add LDAP support to the ProFTPD FTP server
|
||||
proftpd-mysql.x86_64 : Module to add MySQL support to the ProFTPD FTP server
|
||||
proftpd-postgresql.x86_64 : Module to add PostgreSQL support to the ProFTPD FTP
|
||||
: server
|
||||
vsftpd.x86_64 : Very Secure Ftp Daemon
|
||||
proftpd.x86_64 : Flexible, stable and highly-configurable FTP server
|
||||
owfs-ftpd.x86_64 : FTP daemon providing access to 1-Wire networks
|
||||
perl-ftpd.noarch : Secure, extensible and configurable Perl FTP server
|
||||
pure-ftpd.x86_64 : Lightweight, fast and secure FTP server
|
||||
pyftpdlib.noarch : Python FTP server library
|
||||
nordugrid-arc-gridftpd.x86_64 : ARC gridftp server
|
||||
```
|
||||
|
||||
或者,我们可以使用以下命令搜索相同的内容。
|
||||
|
||||
```
|
||||
# dnf list proftpd
|
||||
Failed to synchronize cache for repo 'heikoada-terminix', disabling.
|
||||
Last metadata expiration check: 0:08:02 ago on Tue 26 Jun 2018 04:30:05 PM IST.
|
||||
Available Packages
|
||||
proftpd.x86_64
|
||||
```
|
||||
|
||||
### 如何在 Arch Linux 中搜索一个包
|
||||
|
||||
pacman 代表包管理实用程序(pacman)。它是一个用于安装、构建、删除和管理 Arch Linux 软件包的命令行实用程序。pacman 使用 libalpm(Arch Linux Package Management(ALPM)库)作为底层来执行所有操作。
|
||||
|
||||
在本例中,我将要搜索 chromium 包。
|
||||
|
||||
```
|
||||
# pacman -Ss chromium
|
||||
extra/chromium 48.0.2564.116-1
|
||||
The open-source project behind Google Chrome, an attempt at creating a safer, faster, and more stable browser
|
||||
extra/qt5-webengine 5.5.1-9 (qt qt5)
|
||||
Provides support for web applications using the Chromium browser project
|
||||
community/chromium-bsu 0.9.15.1-2
|
||||
A fast paced top scrolling shooter
|
||||
community/chromium-chromevox latest-1
|
||||
Causes the Chromium web browser to automatically install and update the ChromeVox screen reader extention. Note: This
|
||||
package does not contain the extension code.
|
||||
community/fcitx-mozc 2.17.2313.102-1
|
||||
Fcitx Module of A Japanese Input Method for Chromium OS, Windows, Mac and Linux (the Open Source Edition of Google Japanese
|
||||
Input)
|
||||
```
|
||||
|
||||
默认情况下,`-s` 选项内置 ERE(扩展正则表达式)会导致很多不需要的结果。使用以下格式会仅匹配包名称。
|
||||
|
||||
```
|
||||
# pacman -Ss '^chromium-'
|
||||
```
|
||||
|
||||
`pkgfile` 是一个用于在 Arch Linux 官方仓库的包中搜索文件的工具。
|
||||
|
||||
```
|
||||
# pkgfile chromium
|
||||
```
|
||||
|
||||
### 如何在 openSUSE 中搜索一个包
|
||||
|
||||
Zypper 是 SUSE 和 openSUSE 发行版的命令行包管理器。它用于安装、更新、搜索和删除包以及管理仓库,执行各种查询等。Zypper 命令行对接到 ZYpp 系统管理库(libzypp)。
|
||||
|
||||
```
|
||||
# zypper search ftp
|
||||
or
|
||||
# zypper se ftp
|
||||
Loading repository data...
|
||||
Reading installed packages...
|
||||
S | Name | Summary | Type
|
||||
--+----------------+-----------------------------------------+--------
|
||||
| proftpd | Highly configurable GPL-licensed FTP -> | package
|
||||
| proftpd-devel | Development files for ProFTPD | package
|
||||
| proftpd-doc | Documentation for ProFTPD | package
|
||||
| proftpd-lang | Languages for package proftpd | package
|
||||
| proftpd-ldap | LDAP Module for ProFTPD | package
|
||||
| proftpd-mysql | MySQL Module for ProFTPD | package
|
||||
| proftpd-pgsql | PostgreSQL Module for ProFTPD | package
|
||||
| proftpd-radius | Radius Module for ProFTPD | package
|
||||
| proftpd-sqlite | SQLite Module for ProFTPD | package
|
||||
| pure-ftpd | A Lightweight, Fast, and Secure FTP S-> | package
|
||||
| vsftpd | Very Secure FTP Daemon - Written from-> | package
|
||||
```
|
||||
|
||||
### 如何使用 whohas 命令搜索一个包
|
||||
|
||||
`whohas` 命令是一个智能工具,从所有主流发行版中搜索指定包,如 Debian、Ubuntu、Gentoo、Arch、AUR、Mandriva、Fedora、Fink、FreeBSD 和 NetBSD。
|
||||
|
||||
```
|
||||
$ whohas nano
|
||||
Mandriva nano-debug 2.3.1-1mdv2010.2.x http://sophie.zarb.org/rpms/0b33dc73bca710749ad14bbc3a67e15a
|
||||
Mandriva nano-debug 2.2.4-1mdv2010.1.i http://sophie.zarb.org/rpms/d9dfb2567681e09287b27e7ac6cdbc05
|
||||
Mandriva nano-debug 2.2.4-1mdv2010.1.x http://sophie.zarb.org/rpms/3299516dbc1538cd27a876895f45aee4
|
||||
Mandriva nano 2.3.1-1mdv2010.2.x http://sophie.zarb.org/rpms/98421c894ee30a27d9bd578264625220
|
||||
Mandriva nano 2.3.1-1mdv2010.2.i http://sophie.zarb.org/rpms/cea07b5ef9aa05bac262fc7844dbd223
|
||||
Mandriva nano 2.2.4-1mdv2010.1.s http://sophie.zarb.org/rpms/d61f9341b8981e80424c39c3951067fa
|
||||
Mandriva spring-mod-nanoblobs 0.65-2mdv2010.0.sr http://sophie.zarb.org/rpms/74bb369d4cbb4c8cfe6f6028e8562460
|
||||
Mandriva nanoxml-lite 2.2.3-4.1.4mdv2010 http://sophie.zarb.org/rpms/287a4c37bc2a39c0f277b0020df47502
|
||||
Mandriva nanoxml-manual-lite 2.2.3-4.1.4mdv2010 http://sophie.zarb.org/rpms/17dc4f638e5e9964038d4d26c53cc9c6
|
||||
Mandriva nanoxml-manual 2.2.3-4.1.4mdv2010 http://sophie.zarb.org/rpms/a1b5092cd01fc8bb78a0f3ca9b90370b
|
||||
Gentoo nano 9999 http://packages.gentoo.org/package/app-editors/nano
|
||||
Gentoo nano 9999 http://packages.gentoo.org/package/app-editors/nano
|
||||
Gentoo nano 2.9.8 http://packages.gentoo.org/package/app-editors/nano
|
||||
Gentoo nano 2.9.7
|
||||
```
|
||||
|
||||
如果你希望只从当前发行版仓库中搜索指定包,使用以下格式:
|
||||
|
||||
```
|
||||
$ whohas -d Ubuntu vlc
|
||||
Ubuntu vlc 2.1.6-0ubuntu14.04 1M all http://packages.ubuntu.com/trusty/vlc
|
||||
Ubuntu vlc 2.1.6-0ubuntu14.04 1M all http://packages.ubuntu.com/trusty-updates/vlc
|
||||
Ubuntu vlc 2.2.2-5ubuntu0.16. 1M all http://packages.ubuntu.com/xenial/vlc
|
||||
Ubuntu vlc 2.2.2-5ubuntu0.16. 1M all http://packages.ubuntu.com/xenial-updates/vlc
|
||||
Ubuntu vlc 2.2.6-6 40K all http://packages.ubuntu.com/artful/vlc
|
||||
Ubuntu vlc 3.0.1-3build1 32K all http://packages.ubuntu.com/bionic/vlc
|
||||
Ubuntu vlc 3.0.2-0ubuntu0.1 32K all http://packages.ubuntu.com/bionic-updates/vlc
|
||||
Ubuntu vlc 3.0.3-1 33K all http://packages.ubuntu.com/cosmic/vlc
|
||||
Ubuntu browser-plugin-vlc 2.0.6-2 55K all http://packages.ubuntu.com/trusty/browser-plugin-vlc
|
||||
Ubuntu browser-plugin-vlc 2.0.6-4 47K all http://packages.ubuntu.com/xenial/browser-plugin-vlc
|
||||
Ubuntu browser-plugin-vlc 2.0.6-4 47K all http://packages.ubuntu.com/artful/browser-plugin-vlc
|
||||
Ubuntu browser-plugin-vlc 2.0.6-4 47K all http://packages.ubuntu.com/bionic/browser-plugin-vlc
|
||||
Ubuntu browser-plugin-vlc 2.0.6-4 47K all http://packages.ubuntu.com/cosmic/browser-plugin-vlc
|
||||
Ubuntu libvlc-bin 2.2.6-6 27K all http://packages.ubuntu.com/artful/libvlc-bin
|
||||
Ubuntu libvlc-bin 3.0.1-3build1 17K all http://packages.ubuntu.com/bionic/libvlc-bin
|
||||
Ubuntu libvlc-bin 3.0.2-0ubuntu0.1 17K all
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/how-to-search-if-a-package-is-available-on-your-linux-distribution-or-not/
|
||||
|
||||
作者:[Prakash Subramanian][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.2daygeek.com/author/prakash/
|
||||
[1]:https://www.2daygeek.com/list-of-command-line-package-manager-for-linux/
|
||||
[2]:https://www.2daygeek.com/list-of-graphical-frontend-tool-for-linux-package-manager/
|
@ -0,0 +1,267 @@
|
||||
|
||||
如何把 Google 云端硬盘当做虚拟磁盘一样挂载到 Linux
|
||||
======
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2018/07/Google-Drive-720x340.png)
|
||||
|
||||
[Google 云端硬盘][1] 是全球比较受欢迎的云存储平台. 直到 2017 年, 全球有超过 8 亿的活跃用户在使用它。即使用户数在持续增长,但直到现在 Google 还是没有发布一款可以在 Linux 平台使用的客户端。但这难不倒 Linux 社区。不时就有一些开发者给 Linux 操作系统带来一些客户端。下面我将会介绍三个用于 Linux 系统非官方开发的 Google 云端硬盘客户端。使用这些客户端,你能把 Google 云端硬盘像虚拟磁盘一样挂载到 Linux 系统。请继续阅读。
|
||||
|
||||
### 1、Google-drive-ocamlfuse
|
||||
|
||||
google-drive-ocamlfuse 把 Google 云端硬盘当做是一个 FUSE 类型的文件系统,它是用 OCam 语言写的。FUSE 意即<ruby>用户态文件系统<rt>Filesystem in Userspace</rt></ruby>,此项目允许非管理员用户在用户空间创建虚拟文件系统。google-drive-ocamlfuse 可以让你把 Google 云端硬盘当做磁盘一样挂载到 Linux 系统。支持对普通文件和目录的读写操作,支持对 Google dock、表单和演示稿的只读操作,支持多个 Googe 云端硬盘用户,重复文件处理,支持访问回收站等等。
|
||||
|
||||
#### 安装 google-drive-ocamlfuse
|
||||
|
||||
google-drive-ocamlfuse 能在 Arch 系统的 [AUR][2] 上直接找到,所以你可以使用 AUR 助手程序,如 [Yay][3] 来安装。
|
||||
|
||||
```
|
||||
$ yay -S google-drive-ocamlfuse
|
||||
```
|
||||
|
||||
在 Ubuntu 系统:
|
||||
|
||||
```
|
||||
$ sudo add-apt-repository ppa:alessandro-strada/ppa
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install google-drive-ocamlfuse
|
||||
```
|
||||
|
||||
安装最新的测试版本:
|
||||
|
||||
```
|
||||
$ sudo add-apt-repository ppa:alessandro-strada/google-drive-ocamlfuse-beta
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install google-drive-ocamlfuse
|
||||
```
|
||||
|
||||
#### 使用方法
|
||||
|
||||
安装完成后,直接在终端里面输入如下命令,就可以启动 google-drive-ocamlfuse 程序了:
|
||||
|
||||
```
|
||||
$ google-drive-ocamlfuse
|
||||
```
|
||||
|
||||
当你第一次运行该命令,程序会直接打开你的浏览器并要求你确认是否对 Google 云端硬盘的文件的操作进行授权。当你确认授权后,挂载 Google 云端硬盘所需要的配置文件和目录都会自动进行创建。
|
||||
|
||||
![][5]
|
||||
|
||||
当成功授权后,你会在终端里面看到如下的信息。
|
||||
|
||||
```
|
||||
Access token retrieved correctly.
|
||||
```
|
||||
|
||||
好了,我们可以进行下一步操作了。关闭浏览器并为我们的 Google 云端硬盘创建一个挂载点吧。
|
||||
|
||||
```
|
||||
$ mkdir ~/mygoogledrive
|
||||
|
||||
```
|
||||
|
||||
最后操作,使用如下命令挂载 Google 云端硬盘:
|
||||
|
||||
```
|
||||
$ google-drive-ocamlfuse ~/mygoogledrive
|
||||
```
|
||||
|
||||
恭喜你了!你可以使用终端或文件管理器来访问 Google 云端硬盘里面的文件了。
|
||||
|
||||
使用终端:
|
||||
|
||||
```
|
||||
$ ls ~/mygoogledrive
|
||||
```
|
||||
|
||||
使用文件管理器:
|
||||
|
||||
![][6]
|
||||
|
||||
如何你有不止一个账户,可以使用 `label` 命令对其进行区分不同的账户,就像下面一样:
|
||||
|
||||
```
|
||||
$ google-drive-ocamlfuse -label label [mountpoint]
|
||||
```
|
||||
|
||||
当操作完成后,你可以使用如下的命令卸载 Google 云端硬盘:
|
||||
|
||||
```
|
||||
$ fusermount -u ~/mygoogledrive
|
||||
```
|
||||
|
||||
获取更多信息,你可以参考 man 手册。
|
||||
|
||||
```
|
||||
$ google-drive-ocamlfuse --help
|
||||
```
|
||||
|
||||
当然你也可以看看[官方文档][7]和该项目的 [GitHub 项目][8]以获取更多内容。
|
||||
|
||||
### 2. GCSF
|
||||
|
||||
GCSF 是基于 Google 云端硬盘的 FUSE 文件系统,使用 Rust 语言编写。GCSF 得名于罗马尼亚语中的“ **G** oogle **C** onduce **S** istem de **F** ișiere”,翻译成英文就是“Google Drive Filesystem”(即 Google 云端硬盘文件系统)。使用 GCSF,你可以把 Google 云端硬盘当做虚拟磁盘一样挂载到 Linux 系统,可以通过终端和文件管理器对其进行操作。你肯定会很好奇,这到底与其它的 Google 云端硬盘 FUSE 项目有什么不同,比如 google-drive-ocamlfuse。GCSF 的开发者回应 [Reddit 上的类似评论][9]:“GCSF 意在某些方面更快(递归列举文件、从 Google 云端硬盘中读取大文件)。当文件被缓存后,在消耗更多的内存后,其缓存策略也能让读取速度更快(相对于 google-drive-ocamlfuse 4-7 倍的提升)”。
|
||||
|
||||
#### 安装 GCSF
|
||||
|
||||
GCSF 能在 [AUR][10] 上面找到,对于 Arch 用户来说直接使用 AUR 助手来安装就行了,例如[Yay][3]。
|
||||
|
||||
```
|
||||
$ yay -S gcsf-git
|
||||
```
|
||||
|
||||
对于其它的发行版,需要进行如下的操作来进行安装。
|
||||
|
||||
首先,你得确认系统中是否安装了Rust语言。
|
||||
|
||||
- [在 Linux 上安装 Rust](https://www.ostechnix.com/install-rust-programming-language-in-linux/)
|
||||
|
||||
确保 `pkg-config` 和 `fuse` 软件包是否安装了。它们在绝大多数的 Linux 发行版的默认仓库中都能找到。例如,在 Ubuntu 及其衍生版本中,你可以使用如下的命令进行安装:
|
||||
|
||||
```
|
||||
$ sudo apt-get install -y libfuse-dev pkg-config
|
||||
```
|
||||
|
||||
当所有的依赖软件安装完成后,你可以使用如下的命令来安装 GCSF:
|
||||
|
||||
```
|
||||
$ cargo install gcsf
|
||||
```
|
||||
|
||||
#### 使用方法
|
||||
|
||||
首先,我们需要对 Google 云端硬盘的操作进行授权,简单输入如下命令:
|
||||
|
||||
```
|
||||
$ gcsf login ostechnix
|
||||
```
|
||||
|
||||
你必须指定一个会话名称。请使用自己的会话名称来代 `ostechnix`。你会看到像下图的提示信息和Google 云端硬盘账户的授权验证连接。
|
||||
|
||||
![][11]
|
||||
|
||||
直接复制并用浏览器打开上述 URL,并点击 “allow” 来授权访问你的 Google 云端硬盘账户。当完成授权后,你的终端会显示如下的信息。
|
||||
|
||||
```
|
||||
Successfully logged in. Credentials saved to "/home/sk/.config/gcsf/ostechnix".
|
||||
```
|
||||
|
||||
GCSF 会把配置保存文件在 `$XDG_CONFIG_HOME/gcsf/gcsf.toml`,通常位于 `$HOME/.config/gcsf/gcsf.toml`。授权凭证也会保存在此目录当中。
|
||||
|
||||
下一步,创建一个用来挂载 Google 云端硬盘的目录。
|
||||
|
||||
```
|
||||
$ mkdir ~/mygoogledrive
|
||||
```
|
||||
|
||||
之后,修改 `/etc/fuse.conf` 文件:
|
||||
|
||||
```
|
||||
$ sudo vi /etc/fuse.conf
|
||||
```
|
||||
|
||||
注释掉以下的行,以允许非管理员用 `allow_other` 或 `allow_root` 挂载选项来挂载。
|
||||
|
||||
```
|
||||
user_allow_other
|
||||
```
|
||||
|
||||
保存并关闭文件。
|
||||
|
||||
最后一步,使用如下命令挂载 Google 云端硬盘:
|
||||
|
||||
```
|
||||
$ gcsf mount ~/mygoogledrive -s ostechnix
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
```
|
||||
INFO gcsf > Creating and populating file system...
|
||||
INFO gcsf > File sytem created.
|
||||
INFO gcsf > Mounting to /home/sk/mygoogledrive
|
||||
INFO gcsf > Mounted to /home/sk/mygoogledrive
|
||||
INFO gcsf::gcsf::file_manager > Checking for changes and possibly applying them.
|
||||
INFO gcsf::gcsf::file_manager > Checking for changes and possibly applying them.
|
||||
```
|
||||
|
||||
重复一次,使用自己的会话名来更换 `ostechnix`。你可以使用如下的命令来查看已经存在的会话:
|
||||
|
||||
```
|
||||
$ gcsf list
|
||||
Sessions:
|
||||
- ostechnix
|
||||
```
|
||||
|
||||
你现在可以使用终端和文件管理器对 Google 云端硬盘进行操作了。
|
||||
|
||||
使用终端:
|
||||
|
||||
```
|
||||
$ ls ~/mygoogledrive
|
||||
```
|
||||
|
||||
使用文件管理器:
|
||||
|
||||
![][12]
|
||||
|
||||
如果你不知道自己把 Google 云端硬盘挂载到哪个目录了,可以使用 `df` 或者 `mount` 命令,就像下面一样。
|
||||
|
||||
```
|
||||
$ df -h
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
udev 968M 0 968M 0% /dev
|
||||
tmpfs 200M 1.6M 198M 1% /run
|
||||
/dev/sda1 20G 7.5G 12G 41% /
|
||||
tmpfs 997M 0 997M 0% /dev/shm
|
||||
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
|
||||
tmpfs 997M 0 997M 0% /sys/fs/cgroup
|
||||
tmpfs 200M 40K 200M 1% /run/user/1000
|
||||
GCSF 15G 857M 15G 6% /home/sk/mygoogledrive
|
||||
|
||||
$ mount | grep GCSF
|
||||
GCSF on /home/sk/mygoogledrive type fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000,allow_other)
|
||||
```
|
||||
|
||||
当操作完成后,你可以使用如下命令来卸载 Google 云端硬盘:
|
||||
|
||||
```
|
||||
$ fusermount -u ~/mygoogledrive
|
||||
```
|
||||
|
||||
浏览[GCSF GitHub 项目][13]以获取更多内容。
|
||||
|
||||
### 3、Tuxdrive
|
||||
|
||||
Tuxdrive 也是一个非官方 Linux Google 云端硬盘客户端。我们之前有写过一篇关于 Tuxdrive 比较详细的使用方法。可以查看如下链接:
|
||||
|
||||
- [Tuxdrive: 一个 Linux 下的 Google 云端硬盘客户端](https://www.ostechnix.com/tuxdrive-commandline-google-drive-client-linux/)
|
||||
|
||||
当然,之前还有过其它的非官方 Google 云端硬盘客户端,例如 Grive2、Syncdrive。但它们好像都已经停止开发了。当有更受欢迎的 Google 云端硬盘客户端出现,我会对这个列表进行持续的跟进。
|
||||
|
||||
谢谢你的阅读。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-mount-google-drive-locally-as-virtual-file-system-in-linux/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[sndnvaps](https://github.com/sndnvaps)
|
||||
校对:[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.google.com/drive/
|
||||
[2]:https://aur.archlinux.org/packages/google-drive-ocamlfuse/
|
||||
[3]:https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
|
||||
[4]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2018/07/google-drive.png
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2018/07/google-drive-2.png
|
||||
[7]:https://github.com/astrada/google-drive-ocamlfuse/wiki/Configuration
|
||||
[8]:https://github.com/astrada/google-drive-ocamlfuse
|
||||
[9]:https://www.reddit.com/r/DataHoarder/comments/8vlb2v/google_drive_as_a_file_system/e1oh9q9/
|
||||
[10]:https://aur.archlinux.org/packages/gcsf-git/
|
||||
[11]:http://www.ostechnix.com/wp-content/uploads/2018/07/google-drive-3.png
|
||||
[12]:http://www.ostechnix.com/wp-content/uploads/2018/07/google-drive-4.png
|
||||
[13]:https://github.com/harababurel/gcsf
|
@ -0,0 +1,87 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (oneforalone)
|
||||
[#]: reviewer: (acyanbird wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10510-1.html)
|
||||
[#]: subject: (Two Years With Emacs as a CEO (and now CTO))
|
||||
[#]: via: (https://www.fugue.co/blog/2018-08-09-two-years-with-emacs-as-a-cto.html)
|
||||
[#]: author: (Josh Stella https://www.fugue.co/blog/author/josh-stella)
|
||||
|
||||
作为 CEO 使用 Emacs 的两年经验之谈
|
||||
======
|
||||
|
||||
两年前,我写了一篇[博客][1],并取得了一些反响。这让我有点受宠若惊。那篇博客写的是我准备将 Emacs 作为我的主办公软件,当时我还是 CEO,现在已经是 CTO 了。现在回想起来,我发现我之前不是做程序员就是做软件架构师,而且那时我也喜欢用 Emacs 写代码。重新考虑使用 Emacs 是一次令我振奋的尝试,但我不太清楚这次行动会造成什么反响。在网上,那篇博客的评论也是褒贬不一,但是还是有数万的阅读量,所以总的来说,我写的是一个蛮有意思的题材。在 [Reddit][2] 和 [HackerNews][3] 上有些令人哭笑不得的回复,说我的手会变成鸡爪,或者说我会因白色的背景而近视。在这里我可以很高兴地回答,到目前为止并没有出现什么特别糟糕的后果,相反,我的手腕还因此变得更灵活了。还有一些人担心,说使用 Emacs 会耗费一个 CEO 的精力。把 Fugue 从一个在我家后院的灵感变成强大的产品,并有一大批忠实的顾客,我发现在做这种真正复杂之事的时候,Emacs 可以给你带来安慰。还有,我现在仍然在用白色的背景。
|
||||
|
||||
近段时间那篇博客又被翻出来了,并发到了 [HackerNews][4] 上。我收到了大量的跟帖者问我现在使用状况如何,所以我写了这篇博客来回应他们。在本文中,我还将重点讨论为什么 Emacs 和函数式编程有很高的关联性,以及我们是怎样使用 Emacs 来开发我们的产品 —— Fugue,一个使用函数式编程的自动化的云计算平台的。由于我收到了很多反馈,其众多细节和评论很有用,因此这篇博客比较长,而我确实也需要费点精力来解释我如此作为时的想法,但这篇文章的主要内容还是反映了我担任 CEO 时处理的事务。而我想在之后更频繁地用 Emacs 写代码,所以需要提前做一些准备。一如既往,本文因人而异,后果自负。
|
||||
|
||||
### 意外之喜
|
||||
|
||||
我大部分时间都在不断的处理公司内外沟通。交流是解决问题的唯一方法,但也是反思及思考困难或复杂问题的敌人。对我来说,作为创业公司的 CEO,最需要的是能专注工作而不被打扰的时间。一旦你决定投入时间来学习一些有用的命令,Emacs 就能帮助创造这种不被打扰的可贵环境。其他的应用会弹出提示,但是一个配置好了的 Emacs 可以完全不影响你 —— 无论是视觉上还是精神上。除非你想,否则的话它不会改变,况且没有比空白屏幕和漂亮的字体更干净的界面了。不断被打扰是我的日常状况,因此这种简洁让我能够专注于我在想的事情,而不是电脑本身。好的程序能够默默地操纵电脑,并且不会夺取你的注意力。
|
||||
|
||||
一些人指出,我原来的博客有太多对现代图形界面的批判和对 Emacs 的赞许。我既不赞同,也不否认。现代的界面,特别是那些以应用程序为中心的方法(相对于以内容为中心的方法),既不是以用户为中心的,也不是面向任务的。Emacs 避免了这种错误,这也是我如此喜欢它的部分原因,而它也带来了其他优点。Emacs 是带领你体会计算机魅力的传送门,一个值得跳下去的兔子洞(LCTT 译注:爱丽丝梦游仙境里的兔子洞,跳进去会有新世界)。它的核心是发现和创造属于自己的道路,对我来说这本身就是创造了。现代计算的悲哀之处在于,它很大程度上是由带有闪亮界面的黑盒组成的,这些黑盒提供的是瞬间的喜悦,而不是真正的满足感。这让我们变成了消费者,而不是技术的创造者。无论你是谁或者你的背景是什么;你都可以理解你的电脑,你可以用它创造事物。它很有趣,能令人满意,而且不是你想的那么难学!
|
||||
|
||||
我们常常低估了环境对我们心理的影响。Emacs 给人一种平静和自由的感觉,而不是紧迫感、烦恼或兴奋 —— 后者是思考和沉思的敌人。我喜欢那些持久的、不碍事的东西,当我花时间去关注它们的时候,它们会给我带来真知灼见。Emacs 满足我的所有这些标准。我每天都使用 Emacs 来工作,我也很高兴我很少需要注意到它。Emacs 确实有一个学习曲线,但不会比学自行车的学习曲线来的更陡,而且一旦你掌握了它,你会得到相应的回报,而且不必再去想它了。它赋予你一种其他工具所没有的自由感。这是一个优雅的工具,来自一个更加文明的计算时代。我很高兴我们步入了另一个文明的计算时代,我相信 Emacs 也将越来越受欢迎。
|
||||
|
||||
### 弃用 Org 模式处理日程和待办事项
|
||||
|
||||
在原来的文章中,我花了一些时间介绍如何使用 Org 模式来规划日程。不过现在我放弃了使用 Org 模式来处理待办事项一类的事物,因为我每天都有很多会议要开,很多电话要打,我也不能让其他人来适应我选的工具,而且也没有时间将事务转换或是自动移动到 Org 上。我们主要是 Mac 一族,使用谷歌日历等工具,而且原生的 Mac OS/iOS 工具可以很好的进行团队协作。我还有支老钢笔用来在会议中做笔记,因为我发现在会议中使用笔记本电脑或者说键盘记录很不礼貌,而且这也限制了我的聆听和思考。因此,我基本上放弃了用 Org 模式帮我规划日程或安排生活。当然,Org 模式对其他的方面也很有用,它是我编写文档的首选,包括本文。换句话说,我使用它的方式与其作者的想法背道而驰,但它的确做得很好。我也希望有一天也有人如此评价并使用我们的 Fugue。
|
||||
|
||||
### Emacs 已经在 Fugue 公司中扩散
|
||||
|
||||
我在上篇博客就有说,你可能会喜欢 Emacs,也可能不会。因此,当 Fugue 的文档组将 Emacs 作为标准工具时,我是有点担心的,因为我觉得他们可能是受了我的影响才做出这种选择。不过在两年后,我确信他们做出了正确的选择。文档组的组长是一个很聪明的程序员,但是另外两个编写文档的人却没有怎么接触过技术。我想,如果这是一个经理强迫员工使用错误工具的案例,我就会收到投诉要去解决它,因为 Fugue 有反威权文化,大家不怕挑战任何事和任何人。之前的组长在去年辞职了,但[文档组][5]现在有了一个灵活的集成的 CI/CD 工具链,并且文档组的人已经成为了 Emacs 的忠实用户。Emacs 有一条学习曲线,但即使在最陡的时候,也不至于多么困难,并且翻过顶峰后,对生产力和总体幸福感都得到了提升。这也提醒我们,学文科的人在技术方面和程序员一样聪明,一样能干,也许不那么容易受到技术崇拜与习俗产生的影响。
|
||||
|
||||
### 我的手腕感激我的决定
|
||||
|
||||
上世纪 80 年代中期以来,我每天花 12 个小时左右在电脑前工作,这给我的手腕(以及后背)造成了很大的损伤(因此我强烈安利 Tag Capisco 的椅子)。Emacs 和人机工程学键盘的结合让手腕的 [RSI][10](<ruby>重复性压迫损伤<rt>Repetitive Strain Injury</rt></ruby>)问题消失了,我已经一年多没有想过这种问题了。在那之前,我的手腕每天都会疼,尤其是右手。如果你也有这种问题,你就知道这疼痛很让人分心和忧虑。有几个人问过关于选购键盘和鼠标的问题,如果你也对此有兴趣,那么在过去两年里,我主要使用的是 Truly Ergonomic 键盘,不过我现在用的是[这款键盘][6]。我已经换成现在的键盘有几个星期,而且我爱死它了。大写键的形状很神奇,因为你不用看就能知道它在哪里。而人体工学的拇指键也设计的十分合理,尤其是对于 Emacs 用户而言,Control 和 Meta 是你的坚实伴侣,不要再需要用小指做高度重复的任务了!
|
||||
|
||||
我使用鼠标的次数比使用 Office 和 IDE 时要少得多,这对我的工作效率有很大帮助,但我还是需要一个鼠标。我一直在使用外观相当过时,但功能和人体工程学非常优秀的 Clearly Superior 轨迹球,恰如其名。
|
||||
|
||||
撇开具体的工具不谈,事实证明,一个很棒的键盘,再加上避免使用鼠标,在减少身体的磨损方面很有效。Emacs 是达成这方面的核心,因为我不需要在菜单上滑动鼠标来完成任务,而且导航键就在我的手指下面。我现在十分肯定,我的手离开标准打字位置会给我的肌腱造成很大的压力。不过这也因人而异,我不是医生不好下定论。
|
||||
|
||||
### 我并没有做太多配置……
|
||||
|
||||
有人说我会在界面配置上耗费很多的时间。我想验证下他们说的对不对,所以我特别留意了下。我不仅在很多程度上不用配置,关注这个问题还让我意识到,我使用的其他工具是多么的耗费我的精力和时间。Emacs 是我用过的维护成本最低的软件。Mac OS 和 Windows 一直要求我更新它,但在我看来,这远没有 Adobe 套件和 Office 的更新给我带来的困扰那么大。我只是偶尔更新 Emacs,但对我来说它也没什么变化,所以从我的个人观点而言,更新基本上是一个接近于零成本的操作,我高兴什么时候更新就什么时候更新。
|
||||
|
||||
有一点让你们失望了,因为许多人想知道我为跟上重新打造的 Emacs 社区的更新做了些什么,但是在过去的两年中,我只在配置中添加了少部分内容。我认为这也是一种成功,因为 Emacs 只是一个工具,而不是我的爱好。但即便如此,如果你想和我分享关于 Emacs 的新鲜事物,我很乐意聆听。
|
||||
|
||||
### 期望实现云端控制
|
||||
|
||||
在我们 Fugue 公司有很多 Emacs 的粉丝,所以我们有一段时间在用 [Ludwing 模式][7]。Ludwig 模式是我们用于自动化云基础设施和服务的声明式、功能性的 DSL。最近,Alex Schoof 利用在飞机上和晚上的时间来构建 fugue 模式,它在 Fugue CLI 上充当 Emacs 控制台。要是你不熟悉 Fugue,这是我们开发的一个云自动化和治理工具,它利用函数式编程为用户提供与云的 API 交互的良好体验。但它做的不止这些。fugue 模式很酷的原因有很多,它有一个不断报告云基础设施状态的缓冲区,由于我经常修改这些基础设施,这样我就可以快速看到代码的效果。Fugue 将云工作负载当成进程处理,fugue 模式非常类似于为云工作负载设计的 `top` 工具。它还允许我执行一些操作,比如创建新的设备或删除过期的东西,而且也不需要太多输入。Fugue 模式只是个雏形,但它非常方便,而我现在也经常使用它。
|
||||
|
||||
![fugue-mode-edited.gif][8]
|
||||
|
||||
### 模式及监控
|
||||
|
||||
我添加了一些模式和集成插件,但并不是真正用于工作或 CEO 职能。我喜欢在周末时写写 Haskell 和 Scheme 娱乐,所以我添加了 haskell 模式和 geiser。Emacs 很适合拥有 REPL 的语言,因为你可以在不同的窗口中运行不同的模式,包括 REPL 和 shell。geiser 和 Scheme 很配,要是你还没有用过 Scheme,那么阅读《计算机程序的构造和解释》(SICP)也不失为一种乐趣,在这个有很多货物崇拜编程(LCTT 译注:是一种计算机程序设计中的反模式,其特征为不明就里地、仪式性地使用代码或程序架构)例子的时代,阅读此书或许可以启发你。安装 MIT Scheme 和 geiser,你就会感觉有点像 lore 的符号环境。
|
||||
|
||||
这就引出了我在 2015 年的文章中没有提到的另一个话题:屏幕管理。我喜欢使用单独一个纵向模式的显示器来写作,我在家里和我的主要办公室都有这个配置。对于编程或混合使用,我喜欢我们提供给所有 Fugue 人的新型超宽显示器。对于它来说,我更喜欢将屏幕分成三列,中间是主编辑缓冲区,左边是水平分隔的 shell 和 fugue 模式缓冲区,右边是文档缓冲区或另外一、两个编辑缓冲区。这个很简单,首先按 `Ctl-x 3` 两次,然后使用 `Ctl-x =` 使窗口的宽度相等。这将提供三个相等的列,你也可以使用 `Ctl-x 2` 对分割之后的窗口再次进行水平分割。以下是我的截图。
|
||||
|
||||
![Emacs Screen Shot][9]
|
||||
|
||||
### 这将是最后一篇 CEO/Emacs 文章
|
||||
|
||||
首先是因为我现在是 Fugue 的 CTO 而并非 CEO,其次是我有好多要写的博客主题,而我现在刚好有时间。我还打算写些更深入的东西,比如说函数式编程、基础设施即代码的类型安全,以及我们即将推出的一些 Fugue 的新功能、关于 Fugue 在云上可以做什么的博文等等。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.fugue.co/blog/2018-08-09-two-years-with-emacs-as-a-cto.html
|
||||
|
||||
作者:[Josh Stella][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[oneforalone](https://github.com/oneforalone)
|
||||
校对:[acyanbird](https://github.com/acyanbird), [wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.fugue.co/blog/author/josh-stella
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linux.cn/article-10401-1.html
|
||||
[2]: https://www.reddit.com/r/emacs/comments/7efpkt/a_ceos_guide_to_emacs/
|
||||
[3]: https://news.ycombinator.com/item?id=10642088
|
||||
[4]: https://news.ycombinator.com/item?id=15753150
|
||||
[5]: https://docs.fugue.co/
|
||||
[6]: https://shop.keyboard.io/
|
||||
[7]: https://github.com/fugue/ludwig-mode
|
||||
[8]: https://www.fugue.co/hubfs/Imported_Blog_Media/fugue-mode-edited-1.gif
|
||||
[9]: https://www.fugue.co/hs-fs/hubfs/Emacs%20Screen%20Shot.png?width=929&name=Emacs%20Screen%20Shot.png
|
||||
[10]: https://baike.baidu.com/item/RSI/21509642
|
144
published/20181123 Three SSH GUI Tools for Linux.md
Normal file
144
published/20181123 Three SSH GUI Tools for Linux.md
Normal file
@ -0,0 +1,144 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (Three SSH GUI Tools for Linux)
|
||||
[#]: via: (https://www.linux.com/blog/learn/intro-to-linux/2018/11/three-ssh-guis-linux)
|
||||
[#]: author: (Jack Wallen https://www.linux.com/users/jlwallen)
|
||||
[#]: url: (https://linux.cn/article-10559-1.html)
|
||||
|
||||
3 个 Linux 上的 SSH 图形界面工具
|
||||
======
|
||||
|
||||
> 了解一下这三个用于 Linux 上的 SSH 图形界面工具。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ssh.jpg?itok=3UcXhJt7)
|
||||
|
||||
在你担任 Linux 管理员的职业生涯中,你会使用 Secure Shell(SSH)远程连接到 Linux 服务器或桌面。可能你曾经在某些情况下,会同时 SSH 连接到多个 Linux 服务器。实际上,SSH 可能是 Linux 工具箱中最常用的工具之一。因此,你应该尽可能提高体验效率。对于许多管理员来说,没有什么比命令行更有效了。但是,有些用户更喜欢使用 GUI 工具,尤其是在从台式机连接到远程并在服务器上工作时。
|
||||
|
||||
如果你碰巧喜欢好的图形界面工具,你肯定很乐于了解一些 Linux 上优秀的 SSH 图形界面工具。让我们来看看这三个工具,看看它们中的一个(或多个)是否完全符合你的需求。
|
||||
|
||||
我将在 [Elementary OS][1] 上演示这些工具,但它们都可用于大多数主要发行版。
|
||||
|
||||
### PuTTY
|
||||
|
||||
已经有一些经验的人都知道 [PuTTY][2]。实际上,从 Windows 环境通过 SSH 连接到 Linux 服务器时,PuTTY 是事实上的标准工具。但 PuTTY 不仅适用于 Windows。事实上,通过标准软件库,PuTTY 也可以安装在 Linux 上。 PuTTY 的功能列表包括:
|
||||
|
||||
* 保存会话。
|
||||
* 通过 IP 或主机名连接。
|
||||
* 使用替代的 SSH 端口。
|
||||
* 定义连接类型。
|
||||
* 日志。
|
||||
* 设置键盘、响铃、外观、连接等等。
|
||||
* 配置本地和远程隧道。
|
||||
* 支持代理。
|
||||
* 支持 X11 隧道。
|
||||
|
||||
PuTTY 图形工具主要是一种保存 SSH 会话的方法,因此可以更轻松地管理所有需要不断远程进出的各种 Linux 服务器和桌面。一旦连接成功,PuTTY 就会建立一个到 Linux 服务器的连接窗口,你将可以在其中工作。此时,你可能会有疑问,为什么不在终端窗口工作呢?对于一些人来说,保存会话的便利确实使 PuTTY 值得使用。
|
||||
|
||||
在 Linux 上安装 PuTTY 很简单。例如,你可以在基于 Debian 的发行版上运行命令:
|
||||
|
||||
```
|
||||
sudo apt-get install -y putty
|
||||
```
|
||||
|
||||
安装后,你可以从桌面菜单运行 PuTTY 图形工具或运行命令 `putty`。在 PuTTY “Configuration” 窗口(图 1)中,在 “HostName (or IP address) ” 部分键入主机名或 IP 地址,配置 “Port”(如果不是默认值 22),从 “Connection type”中选择 SSH,然后单击“Open”。
|
||||
|
||||
![PuTTY Connection][4]
|
||||
|
||||
*图 1:PuTTY 连接配置窗口*
|
||||
|
||||
建立连接后,系统将提示你输入远程服务器上的用户凭据(图2)。
|
||||
|
||||
![log in][7]
|
||||
|
||||
*图 2:使用 PuTTY 登录到远程服务器*
|
||||
|
||||
要保存会话(以便你不必始终键入远程服务器信息),请填写主机名(或 IP 地址)、配置端口和连接类型,然后(在单击 “Open” 之前),在 “Saved Sessions” 部分的顶部文本区域中键入名称,然后单击 “Save”。这将保存会话的配置。若要连接到已保存的会话,请从 “Saved Sessions” 窗口中选择它,单击 “Load”,然后单击 “Open”。系统会提示你输入远程服务器上的远程凭据。
|
||||
|
||||
### EasySSH
|
||||
|
||||
虽然 [EasySSH][8] 没有提供 PuTTY 中的那么多的配置选项,但它(顾名思义)非常容易使用。 EasySSH 的最佳功能之一是它提供了一个标签式界面,因此你可以打开多个 SSH 连接并在它们之间快速切换。EasySSH 的其他功能包括:
|
||||
|
||||
* 分组(出于更好的体验效率,可以对标签进行分组)。
|
||||
* 保存用户名、密码。
|
||||
* 外观选项。
|
||||
* 支持本地和远程隧道。
|
||||
|
||||
在 Linux 桌面上安装 EasySSH 很简单,因为可以通过 Flatpak 安装应用程序(这意味着你必须在系统上安装 Flatpak)。安装 Flatpak 后,使用以下命令添加 EasySSH:
|
||||
|
||||
```
|
||||
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
|
||||
sudo flatpak install flathub com.github.muriloventuroso.easyssh
|
||||
```
|
||||
|
||||
用如下命令运行 EasySSH:
|
||||
|
||||
```
|
||||
flatpak run com.github.muriloventuroso.easyssh
|
||||
```
|
||||
|
||||
将会打开 EasySSH 应用程序,你可以单击左上角的 “+” 按钮。 在结果窗口(图 3)中,根据需要配置 SSH 连接。
|
||||
|
||||
![Adding a connection][10]
|
||||
|
||||
*图 3:在 EasySSH 中添加连接很简单*
|
||||
|
||||
添加连接后,它将显示在主窗口的左侧导航中(图 4)。
|
||||
|
||||
![EasySSH][12]
|
||||
|
||||
*图 4:EasySSH 主窗口*
|
||||
|
||||
要在 EasySSH 连接到远程服务器,请从左侧导航栏中选择它,然后单击 “Connect” 按钮(图 5)。
|
||||
|
||||
![Connecting][14]
|
||||
|
||||
*图 5:用 EasySSH 连接到远程服务器*
|
||||
|
||||
对于 EasySSH 的一个警告是你必须将用户名和密码保存在连接配置中(否则连接将失败)。这意味着任何有权访问运行 EasySSH 的桌面的人都可以在不知道密码的情况下远程访问你的服务器。因此,你必须始终记住在你离开时锁定桌面屏幕(并确保使用强密码)。否则服务器容易受到意外登录的影响。
|
||||
|
||||
### Terminator
|
||||
|
||||
(LCTT 译注:这个选择不符合本文主题,本节删节)
|
||||
|
||||
### termius
|
||||
|
||||
(LCTT 译注:本节是根据网友推荐补充的)
|
||||
|
||||
termius 是一个商业版的 SSH、Telnet 和 Mosh 客户端,不是开源软件。支持包括 [Linux](https://www.termius.com/linux)、Windows、Mac、iOS 和安卓在内的各种操作系统。对于单一设备是免费的,支持多设备的白金账号需要按月付费。
|
||||
|
||||
### 很少(但值得)的选择
|
||||
|
||||
Linux 上没有很多可用的 SSH 图形界面工具。为什么?因为大多数管理员更喜欢简单地打开终端窗口并使用标准命令行工具来远程访问其服务器。但是,如果你需要图形界面工具,则有两个可靠选项,可以更轻松地登录多台计算机。虽然对于那些寻找 SSH 图形界面工具的人来说只有不多的几个选择,但那些可用的工具当然值得你花时间。尝试其中一个,亲眼看看。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/intro-to-linux/2018/11/three-ssh-guis-linux
|
||||
|
||||
作者:[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://elementary.io/
|
||||
[2]: https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html
|
||||
[3]: https://www.linux.com/files/images/sshguis1jpg
|
||||
[4]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ssh_guis_1.jpg?itok=DiNTz_wO (PuTTY Connection)
|
||||
[5]: https://www.linux.com/licenses/category/used-permission
|
||||
[6]: https://www.linux.com/files/images/sshguis2jpg
|
||||
[7]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ssh_guis_2.jpg?itok=4ORsJlz3 (log in)
|
||||
[8]: https://github.com/muriloventuroso/easyssh
|
||||
[9]: https://www.linux.com/files/images/sshguis3jpg
|
||||
[10]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ssh_guis_3.jpg?itok=bHC2zlda (Adding a connection)
|
||||
[11]: https://www.linux.com/files/images/sshguis4jpg
|
||||
[12]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ssh_guis_4.jpg?itok=hhJzhRIg (EasySSH)
|
||||
[13]: https://www.linux.com/files/images/sshguis5jpg
|
||||
[14]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ssh_guis_5.jpg?itok=piFEFYTQ (Connecting)
|
||||
[15]: https://www.linux.com/files/images/sshguis6jpg
|
||||
[16]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ssh_guis_6.jpg?itok=-kYl6iSE (Terminator)
|
@ -0,0 +1,332 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (14 Best ASCII Games for Linux That are Insanely Good)
|
||||
[#]: via: (https://itsfoss.com/best-ascii-games/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
[#]: url: (https://linux.cn/article-10546-1.html)
|
||||
|
||||
14 个依然很棒的 Linux ASCII 游戏
|
||||
======
|
||||
|
||||
基于文本的(或者我应该说是[基于终端的][1])游戏在十年前非常流行 —— 当时还没有像<ruby>战神<rt>God Of War</rt></ruby>、<ruby>荒野大镖客:救赎 2<rt>Red Dead Redemption 2</rt></ruby>或<ruby>蜘蛛侠<rt>Spiderman</rt></ruby>这样的视觉游戏大作。
|
||||
|
||||
当然,Linux 平台有很多好游戏 —— 虽然并不总是“最新和最好”。但是,有一些 ASCII 游戏,却是你永远不会玩腻的。
|
||||
|
||||
你或许不相信,有一些 ASCII 游戏被证明是非常容易上瘾的(所以,我可能需要一段时间才能继续写下一篇文章,或者我可能会被解雇? —— 帮帮我!)
|
||||
|
||||
哈哈,开个玩笑。让我们来看看最好的 ASCII 游戏吧。
|
||||
|
||||
**注意:**安装 ASCII 游戏可能要花费不少时间(有些可能会要求你安装其他依赖项或根本不起作用)。你甚至可能会遇到一些需要你从源代码构建的 ASCII 游戏。因此,我们只筛选出那些易于安装和运行的产品 —— 不用费劲。
|
||||
|
||||
### 在运行和安装 ASCII 游戏之前需要做的事情
|
||||
|
||||
如果你没有安装的话,某些 ASCII 游戏可能需要你安装 [Simple DirectMedia Layer][2]。因此,以防万一,你应该先尝试安装它,然后再尝试运行本文中提到的任何游戏。
|
||||
|
||||
要安装它,你需要键入如下命令:
|
||||
|
||||
```
|
||||
sudo apt install libsdl2-2.0
|
||||
sudo apt install libsdl2_mixer-2.0
|
||||
```
|
||||
|
||||
### Linux 上最好的 ASCII 游戏
|
||||
|
||||
![Best Ascii games for Linux][3]
|
||||
|
||||
如下列出的游戏排名不分先后。
|
||||
|
||||
#### 1、战争诅咒
|
||||
|
||||
![Curse of War ascii games][5]
|
||||
|
||||
<ruby>[战争诅咒][4]<rt>Curse of War</rt></ruby>是一个有趣的策略游戏。一开始你可能会发现它有点令人困惑,但一旦你掌握了,就会喜欢上它。在启动游戏之前,我建议你在其 [主页][4] 上查看该游戏规则。
|
||||
|
||||
你将建设基础设施、保护资源并指挥你的军队进行战斗。你所要做的就是把你的旗帜放在一个合适的位置,让你的军队来完成其余的任务。不仅仅是攻击敌人,你还需要管理和保护资源以帮助赢得战斗。
|
||||
|
||||
如果你之前从未玩过任何 ASCII 游戏,请耐心花一些时间来学习它、体验它的全部潜力。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
你可以在官方软件库里找到它。键入如下命令来安装它:
|
||||
|
||||
```
|
||||
sudo apt install curseofwar
|
||||
```
|
||||
|
||||
#### 2、ASCII 领域
|
||||
|
||||
![ascii sector][6]
|
||||
|
||||
讨厌策略游戏?不用担心,<ruby>ASCII 领域<rt>ASCII Sector</rt></ruby>是一款具有空间环境的游戏,可让你进行大量探索。
|
||||
|
||||
此外,不仅仅局限于探索,你还想要采取一些行动吗?也是可以的。当然,虽然战斗体验不是最好的,但它也很有趣。当你看到各种基地、任务和探索时,会让你更加兴奋。你会在这个小小的游戏中遇到一个练级系统,你必须赚取足够的钱或进行交易才能升级你的宇宙飞船。
|
||||
|
||||
而这个游戏最好的地方是你可以创建自己的任务,也可以玩其他人的任务。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
你需要先从其 [官方网站][7] 下载并解压缩归档包。完成后,打开终端并输入这些命令(将 “Downloads” 文件夹替换为你解压缩文件夹所在的位置,如果解压缩文件夹位于你的主目录中,则忽略它):
|
||||
|
||||
```
|
||||
cd Downloads
|
||||
cd asciisec
|
||||
chmod +x asciisec
|
||||
./asciisec
|
||||
```
|
||||
|
||||
#### 3、DoomRL
|
||||
|
||||
![doom ascii game][8]
|
||||
|
||||
你肯定知道经典游戏“<ruby>毁灭战士<rt>DOOM</rt></ruby>”,所以,如果你想把它像 Rogue 类游戏一样略微体验一下,DoomRL 就是适合你的游戏。它是一个基于 ASCII 的游戏,这或许让你想不到。
|
||||
|
||||
这是一个非常小的游戏,但是可以玩很久。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
与你对 “ASCII 领域”所做的类似,你需要从其 [下载页面][9] 下载官方归档文件,然后将其解压缩到一个文件夹。
|
||||
|
||||
解压缩后,输入以下命令:
|
||||
|
||||
```
|
||||
cd Downloads // navigating to the location where the unpacked folder exists
|
||||
cd doomrl-linux-x64-0997
|
||||
chmod +x doomrl
|
||||
./doomrl
|
||||
```
|
||||
|
||||
#### 4、金字塔建造者
|
||||
|
||||
![Pyramid Builder ascii game for Linux][10]
|
||||
|
||||
<ruby>金字塔建造者<rt>Pyramid Builder</rt></ruby> 是一款创新的 ASCII 游戏,你可以通过帮助建造金字塔来提升你的文明。
|
||||
|
||||
你需要指导工人耕种、卸载货物、并移动巨大的石头,以成功建造金字塔。
|
||||
|
||||
这确实是一个值得下载的 ASCII 游戏。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
只需前往其官方网站并下载包以解压缩。提取后,导航到该文件夹并运行可执行文件。
|
||||
|
||||
```
|
||||
cd Downloads
|
||||
cd pyramid_builder_linux
|
||||
chmod +x pyramid_builder_linux.x86_64
|
||||
./pyramid_builder_linux.x86_64
|
||||
```
|
||||
|
||||
#### 5、DiabloRL
|
||||
|
||||
![Diablo ascii RPG game][11]
|
||||
|
||||
如果你是一位狂热的游戏玩家,你一定听说过暴雪的<ruby>暗黑破坏神<rt>Diablo</rt></ruby> 1 代,毫无疑问这是一个精彩的游戏。
|
||||
|
||||
现在你有机会玩一个该游戏的独特演绎版本 —— 一个 ASCII 游戏。DiabloRL 是一款非常棒的基于回合制的 Rogue 类的游戏。你可以从各种职业(战士、巫师或盗贼)中进行选择。每个职业都具有一套不同的属性,可以带来不同游戏体验。
|
||||
|
||||
当然,个人偏好会有所不同,但它是一个不错的暗黑破坏神“降级版”。你觉得怎么样?
|
||||
|
||||
#### 6、Ninvaders
|
||||
|
||||
![Ninvaders terminal game for Linux][12]
|
||||
|
||||
Ninvaders 是最好的 ASCII 游戏之一,因为它是如此简单,且可以消磨时间的街机游戏。
|
||||
|
||||
你必须防御入侵者,需要在它们到达之前击败它们。这听起来很简单,但它极具挑战性。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
与“战争诅咒”类似,你可以在官方软件库中找到它。所以,只需输入此命令即可安装它:
|
||||
|
||||
```
|
||||
sudo apt install ninvaders
|
||||
```
|
||||
|
||||
#### 7、帝国
|
||||
|
||||
![Empire terminal game][13]
|
||||
|
||||
<ruby>帝国<rt>Empire</rt></ruby>这是一款即时战略游戏,你需要互联网连接。我个人不是实时战略游戏的粉丝,但如果你是这类游戏的粉丝,你可以看看他们的 [指南][14] 来玩这个游戏,因为学习起来非常具有挑战性。
|
||||
|
||||
游戏区域包含城市、土地和水。你需要用军队、船只、飞机和其他资源扩展你的城市。通过快速扩张,你可以通过在对方动作之前摧毁它们来捕获其他城市。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
安装很简单,只需输入以下命令:
|
||||
|
||||
```
|
||||
sudo apt install empire
|
||||
```
|
||||
|
||||
#### 8、Nudoku
|
||||
|
||||
![Nudoku is a terminal version game of Sudoku][15]
|
||||
|
||||
喜欢数独游戏?好吧,你也有个 Nudoku 游戏,这是它的克隆。这是当你想放松时的一个完美的消磨时间的 ASCII 游戏。
|
||||
|
||||
它为你提供三个难度级别:简单、正常和困难。如果你想要挑战电脑,其难度会非常难!如果你只是想放松一下,那么就选择简单难度吧。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
安装它很容易,只需在终端输入以下命令:
|
||||
|
||||
```
|
||||
sudo apt install nudoku
|
||||
```
|
||||
|
||||
#### 9、Nethack
|
||||
|
||||
最好的地下城式 ASCII 游戏之一。如果你已经知道一些 Linux 的 ASCII 游戏,我相信这是你的最爱之一。
|
||||
|
||||
它具有许多不同的层(约 45 个),并且包含一堆武器、卷轴、药水、盔甲、戒指和宝石。你也可以选择“永久死亡”模式来玩试试。
|
||||
|
||||
在这里可不仅仅是杀戮,你还有很多需要探索的地方。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
只需按照以下命令安装它:
|
||||
|
||||
```
|
||||
sudo apt install nethack
|
||||
```
|
||||
|
||||
#### 10、ASCII 滑雪
|
||||
|
||||
![ascii jump game][16]
|
||||
|
||||
<ruby>ASCII 滑雪<rt>ASCII Jump</rt></ruby> 是一款简单易玩的游戏,你必须沿着各种轨道滑动,同时跳跃、改变位置,并尽可能长时间地移动以达到最大距离。
|
||||
|
||||
即使看起来很简单,但是看看这个 ASCII 游戏视觉上的表现也是很神奇的。你可以从训练模式开始,然后进入世界杯比赛。你还可以选择你的竞争对手以及你想要开始游戏的山丘。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
只需按照以下命令安装它:
|
||||
|
||||
```
|
||||
sudo apt install asciijump
|
||||
```
|
||||
|
||||
#### 11、Bastet
|
||||
|
||||
![Bastet is tetris game in ascii form][17]
|
||||
|
||||
不要被这个名字误导,它实际上是俄罗斯方块游戏的一个有趣的克隆。
|
||||
|
||||
你不要觉得它只是另一个普通的俄罗斯方块游戏,它会为你丢下最糟糕的砖块。祝你玩得开心!
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
打开终端并键入如下命令:
|
||||
|
||||
```
|
||||
sudo apt install bastet
|
||||
```
|
||||
|
||||
#### 12、Bombardier
|
||||
|
||||
![Bomabrdier game in ascii form][18]
|
||||
|
||||
Bombardier 是另一个简单的 ASCII 游戏,它会让你迷上它。
|
||||
|
||||
在这里,你有一架直升机(或许你想称之为飞机),每一圈它都会降低,你需要投掷炸弹才能摧毁你下面的街区/建筑物。当你摧毁一个街区时,游戏还会在它显示的消息里面添加一些幽默。很好玩。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
Bombardier 可以在官方软件库中找到,所以只需在终端中键入以下内容即可安装它:
|
||||
|
||||
```
|
||||
sudo apt install bombardier
|
||||
```
|
||||
|
||||
#### 13、Angband
|
||||
|
||||
![Angband ascii game][19]
|
||||
|
||||
一个很酷的地下城探索游戏,界面整洁。在探索该游戏时,你可以在一个屏幕上看到所有重要信息。
|
||||
|
||||
它包含不同种类的种族可供选择角色。你可以是精灵、霍比特人、矮人或其他什么,有十几种可供选择。请记住,你需要在最后击败黑暗之王,所以尽可能升级你的武器并做好准备。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
直接键入如下命令:
|
||||
|
||||
```
|
||||
sudo apt install angband
|
||||
```
|
||||
|
||||
#### 14、GNU 国际象棋
|
||||
|
||||
![GNU Chess is a chess game that you can play in Linux terminal][20]
|
||||
|
||||
为什么不下盘棋呢?这是我最喜欢的策略游戏了!
|
||||
|
||||
但是,除非你知道如何使用代表的符号来描述下一步行动,否则 GNU 国际象棋可能很难玩。当然,作为一个 ASCII 游戏,它不太好交互,所以它会要求你记录你的移动并显示输出(当它等待计算机思考它的下一步行动时)。
|
||||
|
||||
##### 如何安装?
|
||||
|
||||
如果你了解国际象棋的代表符号,请输入以下命令从终端安装它:
|
||||
|
||||
```
|
||||
sudo apt install gnuchess
|
||||
```
|
||||
|
||||
#### 一些荣誉奖
|
||||
|
||||
正如我之前提到的,我们试图向你推荐最好的(也是最容易在 Linux 机器上安装的那些) ASCII 游戏。
|
||||
|
||||
然而,有一些标志性的 ASCII 游戏值得关注,它们需要更多的安装工作(你可以获得源代码,但需要构建它/安装它)。
|
||||
|
||||
其中一些游戏是:
|
||||
|
||||
+ [Cataclysm: Dark Days Ahead][22]
|
||||
+ [Brogue][23]
|
||||
+ [Dwarf Fortress][24]
|
||||
|
||||
你可以按照我们的 [从源代码安装软件的完全指南][21] 来进行。
|
||||
|
||||
### 总结
|
||||
|
||||
我们提到的哪些 ASCII 游戏适合你?我们错过了你最喜欢的吗?
|
||||
|
||||
请在下面的评论中告诉我们你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/best-ascii-games/
|
||||
|
||||
作者:[Ankush Das][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://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/best-command-line-games-linux/
|
||||
[2]: https://www.libsdl.org/
|
||||
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/11/best-ascii-games-featured.png?resize=800%2C450&ssl=1
|
||||
[4]: http://a-nikolaev.github.io/curseofwar/
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/11/curseofwar-ascii-game.jpg?fit=800%2C479&ssl=1
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/11/ascii-sector-game.jpg?fit=800%2C424&ssl=1
|
||||
[7]: http://www.asciisector.net/download/
|
||||
[8]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/11/doom-rl-ascii-game.jpg?ssl=1
|
||||
[9]: https://drl.chaosforge.org/downloads
|
||||
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/11/pyramid-builder-ascii-game.jpg?fit=800%2C509&ssl=1
|
||||
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/11/diablo-rl-ascii-game.jpg?ssl=1
|
||||
[12]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/11/ninvaders-ascii-game.jpg?fit=800%2C426&ssl=1
|
||||
[13]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/11/empire-ascii-game.jpg?fit=800%2C570&ssl=1
|
||||
[14]: http://www.wolfpackempire.com/infopages/Guide.html
|
||||
[15]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/11/nudoku-ascii-game.jpg?fit=800%2C434&ssl=1
|
||||
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/11/ascii-jump.jpg?fit=800%2C566&ssl=1
|
||||
[17]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/11/bastet-tetris-clone-ascii.jpg?fit=800%2C465&ssl=1
|
||||
[18]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/11/bombardier.jpg?fit=800%2C571&ssl=1
|
||||
[19]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/11/angband-ascii-game.jpg?ssl=1
|
||||
[20]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/11/gnuchess-ascii-game.jpg?ssl=1
|
||||
[21]: https://linux.cn/article-9172-1.html
|
||||
[22]: https://github.com/CleverRaven/Cataclysm-DDA
|
||||
[23]: https://sites.google.com/site/broguegame/
|
||||
[24]: http://www.bay12games.com/dwarves/index.html
|
||||
|
188
published/201812/20171012 7 Best eBook Readers for Linux.md
Normal file
188
published/201812/20171012 7 Best eBook Readers for Linux.md
Normal file
@ -0,0 +1,188 @@
|
||||
7 个最佳 Linux 电子书阅读器
|
||||
======
|
||||
|
||||
**摘要:** 本文中我们涉及一些 Linux 最佳电子书阅读器。这些应用提供更佳的阅读体验甚至可以管理你的电子书。
|
||||
|
||||
![最佳 Linux 电子书阅读器][1]
|
||||
|
||||
最近,随着人们发现在手持设备、Kindle 或者 PC 上阅读更加舒适,对电子图书的需求有所增加。至于 Linux 用户,也有各种电子书应用满足你阅读和整理电子书的需求。
|
||||
|
||||
在本文中,我们选出了七个最佳 Linux 电子书阅读器。这些电子书阅读器最适合 pdf、epub 和其他电子书格式。
|
||||
|
||||
我提供的是 Ubuntu 安装说明,因为我现在使用它。如果你使用的是[非 Ubuntu 发行版][2],你能在你的发行版软件仓库中找到大多数这些电子书应用。
|
||||
|
||||
### 1. Calibre
|
||||
|
||||
[Calibre][3] 是 Linux 最受欢迎的电子书应用。老实说,这不仅仅是一个简单的电子书阅读器。它是一个完整的电子书解决方案。你甚至能[通过 Calibre 创建专业的电子书][4]。
|
||||
|
||||
通过强大的电子书管理和易用的界面,它提供了创建和编辑电子书的功能。Calibre 支持多种格式和与其它电子书阅读器同步。它也可以让你轻松转换一种电子书格式到另一种。
|
||||
|
||||
Calibre 最大的缺点是,资源消耗太多,因此作为一个独立的电子阅读器来说是一个艰难的选择。
|
||||
|
||||
![Calibre][5]
|
||||
|
||||
#### 特性
|
||||
|
||||
* 管理电子书:Calibre 通过管理元数据来排序和分组电子书。你能从各种来源下载一本电子书的元数据或创建和编辑现有的字段。
|
||||
* 支持所有主流电子书格式:Calibre 支持所有主流电子书格式并兼容多种电子阅读器。
|
||||
* 文件转换:在转换时,你能通过改变电子书风格,创建内容表和调整边距的选项来转换任何一种电子书格式到另一种。你也能转换个人文档为电子书。
|
||||
* 从 web 下载杂志期刊:Calibre 能从各种新闻源或者通过 RSS 订阅源传递故事。
|
||||
* 分享和备份你的电子图书馆:它提供了一个选项,可以托管你电子书集合到它的服务端,从而你能与好友共享或用任何设备从任何地方访问。备份和导入/导出特性可以确保你的收藏安全和方便携带。
|
||||
|
||||
#### 安装
|
||||
|
||||
你能在主流 Linux 发行版的软件库中找到它。对于 Ubuntu,在软件中心搜索它或者使用下面的命令:
|
||||
|
||||
```
|
||||
sudo apt-get install calibre
|
||||
```
|
||||
|
||||
### 2. FBReader
|
||||
|
||||
![FBReader: Linux 电子书阅读器][6]
|
||||
|
||||
[FBReader][7] 是一个开源的轻量级多平台电子书阅读器,它支持多种格式,比如 ePub、fb2、mobi、rtf、html 等。它包括了一些可以访问的流行网络电子图书馆,那里你能免费或付费下载电子书。
|
||||
|
||||
#### 特性
|
||||
|
||||
* 支持多种文件格式和设备比如 Android、iOS、Windows、Mac 和更多。
|
||||
* 同步书集、阅读位置和书签。
|
||||
* 在线管理你图书馆,可以从你的 Linux 桌面添加任何书到所有设备。
|
||||
* 支持 Web 浏览器访问你的书集。
|
||||
* 支持将书籍存储在 Google Drive ,可以通过作者,系列或其他属性整理书籍。
|
||||
|
||||
#### 安装
|
||||
|
||||
你能从官方库或者在终端中输入以下命令安装 FBReader 电子阅读器。
|
||||
|
||||
```
|
||||
sudo apt-get install fbreader
|
||||
```
|
||||
|
||||
或者你能从[这里][8]抓取一个以 .deb 包,并在你的基于 Debian 发行版的系统上安装它。
|
||||
|
||||
### 3. Okular
|
||||
|
||||
[Okular][9] 是另一个开源的基于 KDE 开发的跨平台文档查看器,它已经作为 KDE 应用发布的一部分了。
|
||||
|
||||
![Okular][10]
|
||||
|
||||
#### 特性
|
||||
|
||||
* Okular 支持多种文档格式像 PDF、Postscript、DjVu、CHM、XPS、ePub 和其他。
|
||||
* 支持在 PDF 文档中评论、高亮和绘制不同的形状等。
|
||||
* 无需修改原始 PDF 文件,分别保存上述这些更改。
|
||||
* 电子书中的文本能被提取到一个文本文件,并且有个名为 Jovie 的内置文本阅读服务。
|
||||
|
||||
备注:查看这个应用的时候,我发现这个应用在 Ubuntu 和它的衍生系统中不支持 ePub 文件格式。其他发行版用户仍然可以发挥它全部的潜力。
|
||||
|
||||
#### 安装
|
||||
|
||||
Ubuntu 用户可以在终端中键入下面的命令来安装它:
|
||||
|
||||
```
|
||||
sudo apt-get install okular
|
||||
```
|
||||
|
||||
### 4. Lucidor
|
||||
|
||||
Lucidor 是一个易用的、支持 epub 文件格式和在 OPDS 格式中编目的电子阅读器。它也具有在本地书架里组织电子书集、从互联网搜索和下载,和将 Web 订阅和网页转换成电子书的功能。
|
||||
|
||||
Lucidor 是 XULRunner 应用程序,它向您展示了具有类似火狐的选项卡式布局,和存储数据和配置时的行为。它是这个列表中最简单的电子阅读器,包括诸如文本说明和滚动选项之类的配置。
|
||||
|
||||
![lucidor][11]
|
||||
|
||||
你可以通过选择单词并右击“查找单词”来查找该单词在 Wiktionary.org 的定义。它也包含 web 订阅或 web 页面作为电子书的选项。
|
||||
|
||||
你能从[这里][12]下载和安装 deb 或者 RPM 包。
|
||||
|
||||
### 5. Bookworm
|
||||
|
||||
![Bookworm Linux 电子阅读器][13]
|
||||
|
||||
Bookworm 是另一个支持多种文件格式诸如 epub、pdf、mobi、cbr 和 cbz 的自由开源的电子阅读器。我写了一篇关于 Bookworm 应用程序的特性和安装的专题文章,到这里阅读:[Bookworm:一个简单而强大的 Linux 电子阅读器][14]
|
||||
|
||||
#### 安装
|
||||
|
||||
```
|
||||
sudo apt-add-repository ppa:bookworm-team/bookworm
|
||||
sudo apt-get update
|
||||
sudo apt-get install bookworm
|
||||
```
|
||||
|
||||
### 6. Easy Ebook Viewer
|
||||
|
||||
[Easy Ebook Viewer][15] 是又一个用于读取 ePub 文件的很棒的 GTK Python 应用。具有基本章节导航、从上次阅读位置继续、从其他电子书文件格式导入、章节跳转等功能,Easy Ebook Viewer 是一个简单而简约的 ePub 阅读器.
|
||||
|
||||
![Easy-Ebook-Viewer][16]
|
||||
|
||||
这个应用仍然处于初始阶段,只支持 ePub 文件。
|
||||
|
||||
#### 安装
|
||||
|
||||
你可以从 [GitHub][17] 下载源代码,并自己编译它及依赖项来安装 Easy Ebook Viewer。或者,以下终端命令将执行完全相同的工作。
|
||||
|
||||
```
|
||||
sudo apt install git gir1.2-webkit-3.0 libwebkitgtk-3.0-0 gir1.2-gtk-3.0 python3-gi
|
||||
git clone https://github.com/michaldaniel/Ebook-Viewer.git
|
||||
cd Ebook-Viewer/
|
||||
sudo make install
|
||||
```
|
||||
|
||||
成功完成上述步骤后,你可以从 Dash 启动它。
|
||||
|
||||
### 7. Buka
|
||||
|
||||
Buka 主要是一个具有简单而清爽的用户界面的电子书管理器。它目前支持 PDF 格式,旨在帮助用户更加关注内容。拥有 PDF 阅读器的所有基本特性,Buka 允许你通过箭头键导航,具有缩放选项,并且能并排查看两页。
|
||||
|
||||
你可以创建单独的 PDF 文件列表并轻松地在它们之间切换。Buka 也提供了一个内置翻译工具,但是你需要有效的互联网连接来使用这个特性。
|
||||
|
||||
![Buka][19]
|
||||
|
||||
#### 安装
|
||||
|
||||
你能从[官方下载页面][20]下载一个 AppImage。如果你不知道如何做,请阅读[如何在 Linux 下使用 AppImage][21]。或者,你可以通过命令行安装它:
|
||||
|
||||
```
|
||||
sudo snap install buka
|
||||
```
|
||||
|
||||
### 结束语
|
||||
|
||||
就我个人而言,我发现 Calibre 最适合我的需要。当然,Bookworm 看起来很有前途,这几天我经常使用它。不过,电子书应用的选择完全取决于你的喜好。
|
||||
|
||||
你使用哪个电子书应用呢?在下面的评论中让我们知道。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/best-ebook-readers-linux/
|
||||
|
||||
作者:[Ambarish Kumar][a]
|
||||
译者:[zjon](https://github.com/zjon)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://itsfoss.com/author/ambarish/
|
||||
[1]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/10/best-ebook-readers-linux.png
|
||||
[2]:https://itsfoss.com/non-ubuntu-beginner-linux/
|
||||
[3]:https://www.calibre-ebook.com
|
||||
[4]:https://itsfoss.com/create-ebook-calibre-linux/
|
||||
[5]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Calibre-800x603.jpeg
|
||||
[6]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/10/fbreader-800x624.jpeg
|
||||
[7]:https://fbreader.org
|
||||
[8]:https://fbreader.org/content/fbreader-beta-linux-desktop
|
||||
[9]:https://okular.kde.org/
|
||||
[10]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Okular-800x435.jpg
|
||||
[11]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/lucidor-2.png
|
||||
[12]:http://lucidor.org/lucidor/download.php
|
||||
[13]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/08/bookworm-ebook-reader-linux-800x450.jpeg
|
||||
[14]:https://itsfoss.com/bookworm-ebook-reader-linux/
|
||||
[15]:https://github.com/michaldaniel/Ebook-Viewer
|
||||
[16]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Easy-Ebook-Viewer.jpg
|
||||
[17]:https://github.com/michaldaniel/Ebook-Viewer.git
|
||||
[18]:https://github.com/oguzhaninan/Buka
|
||||
[19]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2017/09/Buka2-800x555.png
|
||||
[20]:https://github.com/oguzhaninan/Buka/releases
|
||||
[21]:https://itsfoss.com/use-appimage-linux/
|
286
published/201812/20171111 A CEOs Guide to Emacs.md
Normal file
286
published/201812/20171111 A CEOs Guide to Emacs.md
Normal file
@ -0,0 +1,286 @@
|
||||
CEO 的 Emacs 秘籍
|
||||
===========
|
||||
|
||||
几年前,不,是几十年前,我就在用 Emacs。不论是码代码、编写文档,还是管理邮件和日程,我都用这个编辑器,或者是说操作系统,而且我还乐此不疲。许多年过去了,我也转向了其他更新、更好的工具。结果,就连最基本的文件浏览,我都已经忘了在不用鼠标的情况下该怎么操作。大约三个月前,我意识到我在应用程序和计算机之间切换上耗费了大量的时间,于是我决定再次使用 Emacs。这是个很正确的决定,原因有以下几个。其中包括用 `.emacs` 和 Dropbox 来搭建一个良好的、可移植的环境的一些技巧。
|
||||
|
||||
对于那些还没用过 Emacs 的人来说,Emacs 会让你爱恨交加。它有点像一个房子大小的<ruby>鲁布·戈德堡机械<rt>Rube Goldberg machine</rt></ruby>,乍一看,它具备烤面包机的所有功能。这听起来不像是一种认可,但关键词是“乍一看”。一旦你了解了 Emacs,你就会意识到它其实是一台可以当发动机用的热核烤面包机……好吧,只是指文本处理的所有事情。当考虑到你计算机的使用周期在很大程度上都是与文本有关时,这是一个相当大胆的声明。大胆,但却是真的。
|
||||
|
||||
也许对我来说更重要的是,Emacs 是我曾经使用过的一个应用,并让我觉得我真正的拥有它,而不是把我塑造成一个匿名的“用户”,就好像位于 [Soma][30](LCTT 译注:旧金山的一个街区)或雷蒙德(LCTT 译注:微软总部所在地)附近某个高档办公室的产品营销部门把钱作为明确的目标一样。现代生产力和创作应用程序(如 Pages 或 IDE)就像碳纤维赛车,它们装备得很好,也很齐全。而 Emacs 就像一盒经典的 [Campagnolo][31] (LCTT 译注:世界上最好的三个公路自行车套件系统品牌之一)零件和一个漂亮的自行车牵引式钢框架,但缺少曲柄臂和刹车杆,你必须在网上某个小众文化中找到它们。前者更快而且很完整,后者是无尽的快乐或烦恼的源泉,当然这取决于你自己,而且这种快乐或烦恼会伴随到你死。我就是那种在找到一堆老古董或用 `Emacs Lisp` 配置编辑器时会感到高兴的人,具体情况因人而异。
|
||||
|
||||
![1933 steel bicycle](https://www.fugue.co/hubfs/Imported_Blog_Media/bicycle-1.jpg)
|
||||
|
||||
*一辆我还在骑的 1933 年产的钢制自行车。你可以看看框架管差别: [https://www.youtube.com/watch?v=khJQgRLKMU0][6]*
|
||||
|
||||
这可能给人一种 Emacs 已经过气或过时的印象。然而并不是,Emacs 是强大和永恒的,只要你耐心地去理解它的一些规则。Emacs 的规则很另类,也很奇怪,但其中的逻辑却引人注目,且魅力十足。对于我来说, Emacs 更像是未来而不是过去。就像牵引式钢框架在未来几十年里将会变得好用和舒适,而神奇的碳纤维自行车将会被扔进垃圾场,在撞击中粉碎一样,Emacs 也将会作为一种在最新的流行应用早已被遗忘的时候的好用的工具继续存在这里。
|
||||
|
||||
使用 Lisp 代码来构建个人工作环境,并将这个恰到好处的环境移植到任何计算机,如果这种想法打动了你,那么你将会爱上 Emacs。如果你喜欢很潮、很炫的,又不想投入太多时间和精力的情况下就能直接工作的话,那么 Emacs 可能不适合你。我已经不再写代码了(除了 Ludwig 和 Emacs Lisp),但是 Fugue 公司的很多工程师都使用 Emacs 来提高码代码的效率。我公司有 30% 的工程师用 Emacs,40% 用 IDE 和 30% 的用 vim。但这篇文章是写给 CEO 和其他<ruby>[精英][32]<rt>Pointy-Haired Bosses</rt></ruby>(PHB[^1] )(以及对 Emacs 感兴趣的人)的,所以我将解释或者说辩解我为什么喜欢它以及我如何使用它。同时我也希望我能介绍清楚,从而让你有个良好的体验,而不是花上几个小时去 Google。
|
||||
|
||||
### 恒久优势
|
||||
|
||||
使用 Emacs 带来的长期优势是让生活更轻松。与最后的收获相比,最开始的付出完全值得。想想这些:
|
||||
|
||||
#### 简单高效
|
||||
|
||||
Org 模式本身就值得花时间,但如果你像我一样,你通常要处理十几份左右的文件 —— 从博客帖子到会议事务清单,再到员工评估。在现代计算世界中,这通常意味着要使用多个应用程序,所有这些程序都有不同的用户界面、保存方式、排序和搜索方式。结果就是你需要不断转换思维环境,记住各种细节。我讨厌在程序间切换,这是在强人所难,因为这是个不完整界面模型[^2] ,并且我讨厌记住本该由计算机记住的东西。在单个环境下,Emacs 对 PHB 甚至比对于程序员更高效,因为程序员更多时候只需要专注于一个程序。转换思维环境的成本比表面上的要更高。操作系统和应用程序厂商已经构建了各种界面,以分散我们对这一现实的注意力。如果你是技术人员,通过快捷键(`M-:`)来访问功能强大的[语言解释器][33]会方便的多[^3] 。
|
||||
|
||||
许多应用程序可以全天全屏地用于编辑文本。但Emacs 是唯一的,因为它既是编辑器也是 Emacs Lisp 解释器。从本质上来说,你工作时只要用电脑上的一两个键就能完成。如果你略懂编程的话,就会发现这代表着你可以在 Emacs 中做 _任何事情_。一旦你在内存中存储了这些指令,你的电脑就可以在工作时几乎实时地为你提供高效的运转。你不会想用 Emacs Lisp 来重建 Excel,因为只要用简单的一两行代码就能实现 Excel 中大多数的功能。比如说我要处理数字,我更有可能转到 scratch 缓冲区,编写一些代码,而不是打开电子表格。即便是要写一封比较大的邮件时,我通常也会先在 Emacs 中写完,然后再复制粘贴到邮件客户端中。当你可以流畅的书写时,为什么要去切换呢?你可以先从一两个简单的算术开始,随着时间的推移,你可以很容易的在 Emacs 中添加你所需要处理的计算。这在应用程序中可能是独一无二的,同时还提供了让为其他的人创造的丰富特性。还记得艾萨克·阿西莫夫书中那些神奇的终端吗? Emacs 是我所遇到的最接近它们的东西[^4] 。我决定不再用什么应用程序来做这个或那个。相反,我只是工作。拥有一个伟大的工具并致力于此,这才是真正的动力和效率。
|
||||
|
||||
#### 静中造物
|
||||
|
||||
拥有所发现的最好的文本编辑功能的最终结果是什么?有一群人在做各种各样有用的补充吗?发挥了 Lisp 键盘的全部威力了吗?我用 Emacs 来完成所有的创作性工作,音乐和图片除外。
|
||||
|
||||
我办公桌上有两个显示器。其中一块竖屏是将 Emacs 全天全屏显示,另一个显示浏览器,用来搜索和阅读,我通常也会打开一个终端。我将日历、邮件等放在 OS X 的另一个桌面上,当我使用 Emacs 时,这个桌面会隐藏起来,同时我也会关掉所有通知。这样就能让我专注于我手头上在做的事了。我发现,越是先进的 UI 应用程序,消除干扰越是不可能,因为这些应用程序致力于提供帮助和易用性。我不需要经常被提醒该如何操作,我已经做了成千上万次了,我真正需要的是一张干净整洁的白纸用来思考。也许因为年龄和自己的“恶习”,我不太喜欢处在嘈杂的环境中,但我认为这值得一试。看看在你电脑环境中有一些真正的宁静是怎样的。当然,现在很多应用程序都有隐藏界面的模式,谢天谢地,苹果和微软现在都有了真正意义上的全屏模式。但是,没有并没有应用程序可以强大到足以“处理”大多数事务。除非你整天写代码,或者像出书一样,处理很长的文档,否则你仍然会面临其他应用程序的干扰。而且,大多数现代应用程序似乎同时显得自视甚高,缺乏功能和可用性[^5] 。比起 office 桌面版,我更讨厌它的在线版。
|
||||
|
||||
![](https://www.fugue.co/hubfs/Imported_Blog_Media/desktop-1.jpg)
|
||||
|
||||
*我的桌面布局, Emacs 在左边*
|
||||
|
||||
但是沟通呢?创造和沟通之间的差别很大。当我将这两件事在不同时间段处理时,我的效率会更高。我们 Fugue 公司使用 Slack,痛并快乐着。我把 Slack 和我的日历、电子邮件放在一个即时通讯的桌面上,这样,当我正在做事时,我就能够忽略所有的聊天信息了。虽然只要一个 Slackstorm 或一封风投或董事会董事的电子邮件,就能让我立刻丢掉手头工作。但是,大多数事情通常可以等上一两个小时。
|
||||
|
||||
#### 普适恒久
|
||||
|
||||
第三个原因是,我发现 Emacs 比其它的环境更有优势的是,你可以很容易地用它来处理事务。我的意思是,你所需要的只是通过类似于 Dropbox 的网站同步一两个目录,而不是让大量的应用程序以它们自己的方式进行交互和同步。然后,你可以在任何你已经精心打造了适合你的目的的套件的环境中工作了。我在 OS X、Windows,或有时在 Linux 都是这样做的。它非常简单可靠。这种功能很有用,以至于我害怕处理 Pages、Google Docs、Office 或其他类型的文件和应用程序,这些文件和应用程序会迫使我回到文件系统或云中的某个地方去寻找。
|
||||
|
||||
限制在计算机上永久存储的因素是文件格式。假设人类已经解决了存储问题[^6] ,随着时间的推移,我们面临的问题是我们能否够继续访问我们创建的信息。文本文件是保存时间最久的格式。你可以用 Emacs 轻松地打开 1970 年的文本文件。然而对于 Office 应用程序却并非如此。同时文本文件要比 Office 应用程序数据文件小得多,也要好的多。作为一个数码背包迷,作为一个在脑子里一闪而过就会做很多小笔记的人,拥有一个简单、轻便、永久、随时可用的东西对我来说很重要。
|
||||
|
||||
如果你准备尝试 Emacs,请继续读下去!下面的部分不是完整的教程,但是在读完后,就可以动手操作了。
|
||||
|
||||
### 驾驭之道 —— 专业定制
|
||||
|
||||
所有这些强大、精神上的平静和安宁的代价是,Emacs 有一个陡峭的学习曲线,它的一切都与你以前所习惯的不同。一开始,这会让你觉得你是在浪费时间在一个过时和奇怪的应用程序上,就好像穿越到过去。这有点像你只开过车,却要你去学骑自行车[^7] 。
|
||||
|
||||
#### 类型抉择
|
||||
|
||||
我用的是来自 GNU 的 OS X 和 Windows 的通用版本的 Emacs。你可以在 [http://emacsformacos.com/][35] 获取 OS X 版本,在 [http://www.gnu.org/software/emacs/][37] 获取 Windows 版本。市面上还有很多其他版本,尤其是 Mac 版本,但我发现,要做一些功能强大的东西(涉及到 Lisp 和许多模式),学习曲线要比实际操作低得多。下载,然后我们就可以开始了[^8] !
|
||||
|
||||
#### 驾驭之始
|
||||
|
||||
在本文中,我将使用 Emacs 的按键和组合键约定。`C` 表示 `Control` 键,`M` 表示 `meta`(通常是 `Alt` 或 `Option` 键),以及用于组合键的连字符。因此,`C-h t` 表示同时按下 `Control` 和 `h` 键,然后释放,再按下 `t`。这个组合快捷键会指向一个教程,这是你首先要做的一件事。
|
||||
|
||||
不要使用方向键或鼠标。它们可以工作,但是你应该给自己一周的时间来使用 Emacs 教程中的原生的导航命令。一旦你这些命令变为了肌肉记忆,你可能就会乐在其中,无论到哪里,你都会非常想念它们。这个 Emacs 教程在介绍它们方面做得很好,但是我将进行总结,所以你不需要阅读全部内容。最无聊的是,不用方向键,用 `C-b` 向前移动,用 `C-f` 向后移动,上一行用 `C-p`,下一行用 `C-n`。你可能会想:“我用方向键就很好,为什么还要这样做?” 有几个原因。首先,你不需要从主键盘区将你的手移开。第二,使用 `Alt`(或用 Emacs 的说法 `Meta`)键来向前或向后在单词间移动。显而易见这样更方便。第三,如果想重复某个命令,可以在命令前面加上一个数字。在编辑文档时,我经常使用这种方法,通过估计向后移动多少个单词或向上或向下移动多少行,然后按下 `C-9 C-p` 或 `M-5 M-b` 之类的快捷键。其它真正重要的导航命令基于开头用 `a` 和结尾用 `e`。在行中使用 `C-a|e`,在句中使用 `M-a|e`。为了让句中的命令正常工作,需要在句号后增加两个空格,这同时提供了一个有用的特性,并消除了脑中一个过时的[观点][38]。如果需要将文档导出到单个空间[发布环境][39],可以编写一个宏来执行此操作。
|
||||
|
||||
Emacs 所附带的教程很值得去看。对于真正缺乏耐心的人,我将介绍一些重要的命令,但那个教程非常有用。记住:用 `C-h t` 进入教程。
|
||||
|
||||
#### 驾驭之复制粘贴
|
||||
|
||||
你可以把 Emacs 设为 CUA 模式,这将会以熟悉的方式工作来操作复制粘贴,但是原生的 Emacs 方法更好,而且你一旦学会了它,就很容易。你可以使用 `Shift` 和导航命令来标记区域(如同选择)。所以 `C-F` 是选中光标前的一个字符,等等。亦可以用 `M-w` 来复制,用 `C-w` 剪切,然后用 `C-y` 粘贴。这些实际上叫做<ruby>删除<rt>killing</rt></ruby>和<ruby>召回<rt>yanking</rt></ruby>,但它非常类似于剪切和粘贴。在删除中还有一些小技巧,但是现在,你只需要关注剪切、复制和粘贴。如果你开始尝试了,那么 `C-x u` 是撤销。
|
||||
|
||||
#### 驾驭之 Ido 模式
|
||||
|
||||
相信我,Ido 会让文件的工作变得很简单。通常,你在 Emacs 中处理文件不需要使用一个单独的访达或文件资源管理器的窗口。相反,你可以用编辑器的命令来创建、打开和保存文件。如果没有 Ido 的话,这将有点麻烦,所以我建议你在学习其他之前安装好它。 Ido 是 Emacs 的 22 版时开始出现的,但是需要对你的 `.emacs` 文件做一些调整,来确保它一直开启着。这是个配置环境的好理由。
|
||||
|
||||
Emacs 中的大多数功能都表现在模式上。要安装指定的模式,需要做两件事。嗯,一开始你需要做一些额外的事情,但这些只需要做一次,然后再做这两件事。那么,这件额外的事情是你需要一个单独的位置来放置所有 Emacs Lisp 文件,并且你需要告诉 Emacs 这个位置在哪。我建议你在 Dropbox 上创建一个单独的目录,那是你 Emacs 主目录。在这里,你需要创建一个 `.emacs` 文件和 `.emacs.d` 目录。在 `.emacs.d` 目录下,创建一个 `lisp` 的目录。就像这样:
|
||||
|
||||
```
|
||||
home
|
||||
|
|
||||
+.emacs
|
||||
|
|
||||
-.emacs.d
|
||||
|
|
||||
-lisp
|
||||
```
|
||||
|
||||
你可以将 `.el` 文件,比如说模式文件,放到 `home/.emacs.d/lisp` 目录下,然后在你的 `.emacs` 文件中添加以下代码来指明该路径:
|
||||
|
||||
```
|
||||
(add-to-list 'load-path "~/.emacs.d/lisp/")
|
||||
```
|
||||
|
||||
Ido 模式是 Emacs 自带的,所以你不需要在你的 `lisp` 目录中放这个 `.el` 文件,但你仍然需要添加上面代码,因为下面的介绍会使用到它.
|
||||
|
||||
#### 驾驭之符号链接
|
||||
|
||||
等等,这里写的 `.emacs` 和 `.emacs.d` 都是存放在你的主目录下,但我们把它们放到了 Dropbox 的某些愚蠢的文件夹!对,这就让你的环境在任何地方都很容易使用。把所有东西都保存在 Dropbox 上,并做符号链接到 `~` 下的 `.emacs` 、`.emacs.d` 和你的主要存放文档的目录。在 OS X 上,使用 `ln -s` 命令非常简单,但在 Windows 上却很麻烦。幸运的是,Emacs 提供了一种简单的方法来替代 Windows 上的符号链接,Windows 的 `HOME` 环境变量。转到 Windows 的环境变量(Windows 10,你可以按 Windows 键然后输入 “环境变量” 来搜索,这是 Windows 10 最好的地方了),在你的帐户下创建一个指向你在 Dropbox 中 Emacs 的文件夹的 `HOME` 环境变量。如果你想方便地浏览 Dropbox 之外的本地文件,你可能想在你的实际主目录下建立一个到 Dropbox 下 Emacs 主目录的符号链接。
|
||||
|
||||
至此,你已经完成了在任意机器上指向你的 Emacs 配置和文件所需的技巧。如果你买了一台新电脑,或者用别人的电脑一小时或一天,你就可以得到你的整个工作环境。第一次操作起来似乎有点难,但是一旦你知道你在做什么,就(最多)只需要 10 分钟。
|
||||
|
||||
但我们现在是在配置 Ido ……
|
||||
|
||||
按下 `C-x` `C-f` 然后输入 `~/.emacs` 和两次回车来创建 `.emacs` 文件,将下面几行添加进去:
|
||||
|
||||
```
|
||||
;; set up ido mode
|
||||
(require `ido)
|
||||
(setq ido-enable-flex-matching t)
|
||||
(setq ido-everywhere t)
|
||||
(ido-mode 1)
|
||||
```
|
||||
|
||||
在 `.emacs` 窗口开着的时候,执行 `M-x evaluate-buffer` 命令。如果某处弄错了的话,将得到一个错误,或者你将得到 Ido。Ido 改变了在 minibuffer 中操作文件操方式。关于这个有一篇比较好的文档,但是我也会指出一些技巧。有效地使用 `~/`;你可以在 minibuffer 的任何地方输入 `~/`,它就会跳转到主目录。这就意味着,你应该让你的大部分东西就近的放在主目录下。我用 `~/org` 目录来保存所有非代码的东西,用 `~/code` 保存代码。一旦你进入到正确的目录,通常会拥有一组具有不同扩展名的文件,特别是当你使用 Org 模式并从中发布的话。你可以输入 `.` 和想要的扩展名,无论你的在文件名的什么位置,Ido 都会将选择限制在具有该扩展名的文件中。例如,我在 Org 模式下写这篇博客,所以该文件是:
|
||||
|
||||
```
|
||||
~/org/blog/emacs.org
|
||||
```
|
||||
|
||||
我偶尔也会用 Org 模式发布成 HTML 格式,所以我将在同一目录下得到 `emacs.html` 文件。当我想打开该 Org 文件时,我会输入:
|
||||
|
||||
```
|
||||
C-x C-f ~/o[RET]/bl[RET].or[RET]
|
||||
```
|
||||
|
||||
其中 `[RET]` 是我使用 `Ido` 模式的自动补全而按下的回车键。所以,这只需要按 12 个键,如果你习惯了的话, 这将比打开访达或文件资源管理器再用鼠标点要节省 _很_ 多时间。 Ido 模式很有用,而这只是操作 Emacs 的一种实用模式而已。下面让我们去探索一些其它对完成工作很有帮助的模式吧。
|
||||
|
||||
#### 驾驭之字体风格
|
||||
|
||||
我推荐在 Emacs 中使用漂亮的字体族。它们可以使用不同的括号、0 和其他字符进行自定义。你可以在字体文件本身中构建额外的行间距。我推荐 1.5 倍的行间距,并在代码和数据中使用不等宽字体。写作中我用 `Serif` 字体,它有一种紧凑但时髦的感觉。你可以在 [http://input.fontbureau.com/][40] 上找到它们,在那里你可以根据自己的喜好进行定制。你可以使用 Emacs 中的菜单手动设置字体,但这会将代码保存到你的 `.emacs` 文件中,如果你使用多个设备,你可能需要一些不同的设置。我将我的 `.emacs` 设置为根据使用的机器的名称来相应配置屏幕。代码如下:
|
||||
|
||||
```
|
||||
;; set up fonts for different OSes. OSX toggles to full screen.
|
||||
(setq myfont "InputSerif")
|
||||
(cond
|
||||
((string-equal system-name "Sampo.local")
|
||||
(set-face-attribute 'default nil :font myfont :height 144)
|
||||
(toggle-frame-fullscreen))
|
||||
((string-equal system-name "Morpheus.local")
|
||||
(set-face-attribute 'default nil :font myfont :height 144))
|
||||
((string-equal system-name "ILMARINEN")
|
||||
(set-face-attribute 'default nil :font myfont :height 106))
|
||||
((string-equal system-name "UKKO")
|
||||
(set-face-attribute 'default nil :font myfont :height 104)))
|
||||
```
|
||||
|
||||
你应该将 Emacs 中的 `system-name` 的值替换成你通过 `(system-name)` 得到的值。注意,在 Sampo (我的 MacBook)上,我还将 Emacs 设置为全屏。我也想在 Windows 实现这个功能,但是 Windows 和 Emacs 好像互相嫌弃对方,当我尝试配置时,它总是不稳定。相反,我只能在启动后手动全屏。
|
||||
|
||||
我还建议去掉 Emacs 中的上世纪 90 年代出现的难看工具栏,当时比较流行在应用程序中使用工具栏。我还去掉了一些其它的“电镀层”,这样我就有了一个简单、高效的界面。把这些加到你的 `.emacs` 的文件中来去掉工具栏和滚动条,但要保留菜单(在 OS X 上,它将被隐藏,除非你将鼠标到屏幕顶部):
|
||||
|
||||
```
|
||||
(if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
|
||||
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
|
||||
(if (fboundp 'menu-bar-mode) (menu-bar-mode 1))
|
||||
```
|
||||
|
||||
#### 驾驭之 Org 模式
|
||||
|
||||
我基本上是在 Org 模式下处理工作的。它是我创作文档、记笔记、列任务清单以及 90% 其他工作的首选环境。Org 模式是笔记和待办事项列表的组合工具,最初是由一个在会议中使用笔记本电脑的人构想出来的。我反对在会议中使用笔记本电脑,自己也不使用,所以我的用法与他的有些不同。对我来说,Org 模式主要是一种处理结构中内容的方式。在 Org 模式中有标题和副标题等,它们的作用就像一个大纲。Org 模式允许你展开或隐藏大纲树,还可以重新排列该树。这正合我意,并且我发现用这种方式使用它是一种乐趣。
|
||||
|
||||
Org 模式也有很多让生活愉快的小功能。例如,脚注处理非常好,LaTeX/PDF 输出也很好。Org 模式能够根据所有文档中的待办事项生成议程,并能很好地将它们与日期/时间联系起来。我不把它用在任何形式的外部任务上,这些任务都是在一个共享的日历上处理的,但是在创建事物和跟踪我未来需要创建的东西时,它是无价的。安装它,你只要将 `org-mode.el` 放到你的 `lisp` 目录下。如果你想要它基于文档的结构进行缩进并在打开时全部展开的话,在你的 `.emacs` 文件中添加如下代码:
|
||||
|
||||
```
|
||||
;; set up org mode
|
||||
(setq org-startup-indented t)
|
||||
(setq org-startup-folded "showall")
|
||||
(setq org-directory "~/org")
|
||||
```
|
||||
|
||||
最后一行是让 Org 模式知道在哪里查找要包含在议程和其他事情中的文件。我把 Org 模式保存在我的主目录中,也就是说,像前面介绍的一样,它是 Dropbox 目录的一个符号链接。
|
||||
|
||||
我有一个总是在缓冲区中打开的 `stuff.org` 文件。我把它当作记事本。Org 模式使得提取待办事项和有期限的事情变得很容易。当你能够内联 Lisp 代码并在需要计算它时,它特别有用。拥有包含内容的代码非常方便。同样,你可以使用 Emacs 访问实际的计算机,这是一种解放。
|
||||
|
||||
##### 用 Org 模式进行发布
|
||||
|
||||
我关心的是文档的外观及格式。我刚开始工作时是个设计师,而且我认为信息可以,也应该表现得清晰和美丽。Org 模式对将 LaTeX 生成 PDF 支持的很好,LaTeX 虽然也有学习曲线,但是很容易处理一些简单的事务。
|
||||
|
||||
如果你想使用字体和样式,而不是典型的 LaTeX 字体和样式,你需要做些事。首先,你要用到 XeLaTeX,这样就可以使用普通的系统字体,而不是 LaTeX 的特殊字体。接下来,你需要将以下代码添加到 `.emacs` 中:
|
||||
|
||||
```
|
||||
(setq org-latex-pdf-process
|
||||
'("xelatex -interaction nonstopmode %f"
|
||||
"xelatex -interaction nonstopmode %f"))
|
||||
```
|
||||
|
||||
我把这个放在 `.emacs` 中 Org 模式配置部分的末尾,使文档变得更整洁。这让你在从 Org 模式发布时可以使用更多格式化选项。例如,我经常使用:
|
||||
|
||||
```
|
||||
#+LaTeX_HEADER: \usepackage{fontspec}
|
||||
#+LATEX_HEADER: \setmonofont[Scale=0.9]{Input Mono}
|
||||
#+LATEX_HEADER: \setromanfont{Maison Neue}
|
||||
#+LATEX_HEADER: \linespread{1.5}
|
||||
#+LATEX_HEADER: \usepackage[margin=1.25in]{geometry}
|
||||
|
||||
#+TITLE: Document Title Here
|
||||
```
|
||||
|
||||
这些都可以在 `.org` 文件中找到。我们的公司规定的正文字体是 `Maison Neue`,但你也可以在这写上任何适当的东西。我很是抵制 `Maison Neue`,因为这是一种糟糕的字体,任何人都不应该使用它。
|
||||
|
||||
这个文件是一个使用该配置输出为 PDF 的实例。这就是开箱即用的 LaTeX 一样。在我看来这还不错,但是字体很平淡,而且有点奇怪。此外,如果你使用标准格式,人们会觉得他们正在阅读的东西是、或者假装是一篇学术论文。别怪我没提醒你。
|
||||
|
||||
#### 驾驭之 Ace Jump 模式
|
||||
|
||||
这只是一个辅助模式,而不是一个主模式,但是你也需要它。其工作原理有点像之前提到的 Jef Raskin 的 Leap 功能[^9] 。 按下 `C-c C-SPC`,然后输入要跳转到单词的第一个字母。它会高亮显示所有以该字母开头的单词,并将其替换为字母表中的字母。你只需键入所需位置的字母,光标就会跳转到该位置。我常将它作为导航键或是用来检索。将 `.el` 文件下到你的 `lisp` 目录下,并在 `.emacs` 文件添加如下代码:
|
||||
|
||||
```
|
||||
;; set up ace-jump-mode
|
||||
(add-to-list 'load-path "which-folder-ace-jump-mode-file-in/")
|
||||
(require 'ace-jump-mode)
|
||||
(define-key global-map (kbd "C-c C-SPC" ) 'ace-jump-mode)
|
||||
```
|
||||
|
||||
### 待续
|
||||
|
||||
本文已经够详细了,你能在其中得到你所想要的。我很想知道除编程之外(或用于编程)Emacs 的使用情况,及其是否高效。在我使用 Emacs 的过程中,可能存在一些自作聪明的老板式想法,如果你能指出来,我将不胜感激。之后,我可能会写一些更新来介绍其它特性或模式。我很确定我将会向你展示如何在 Emacs 和 Ludwig 模式下使用 Fugue,因为我会将它发展成比代码高亮更有用的东西。更多想法,请在 Twitter 上 [@fugueHQ][41] 。
|
||||
|
||||
### 脚注
|
||||
|
||||
[^1]: 如果你是位精英,但从没涉及过技术方面,那么 Emacs 并不适合你。对于少数的人来说,Emacs 可能会为他们开辟一条通往计算机技术方面的道路,但这只是极少数。如果你知道怎么使用 Unix 或 Windows 的终端,或者曾编辑过 dotfile,或者说你曾写过一点代码的话,这对使用 Emacs 有很大的帮助。
|
||||
|
||||
[^2]: 参考链接: http://archive.wired.com/wired/archive/2.08/tufte.html
|
||||
|
||||
[^3]: 我主要是在写作时使用这个模式来进行一些运算。比如说,当我在给一个新雇员写一封入职信时,我想要算这封入职信中有多少个选项。由于我在我的 `.emacs` 为 outstanding-shares 定义了一个变量,所以我只要按下 `M-:` 然后输入 `(* .001 outstanding-shares)` 就能再无需打开计算器或电子表格的情况下得到精度为 0.001 的结果。我使用了 _大量_ 的变量来避免程序间切换。
|
||||
|
||||
[^4]: 缺少的部分是 web。有个名为 eww 的 Emacs 网页浏览器能够让你在 Emacs 中浏览网页。我用的就是这个,因为它既能拦截广告(LCTT 译注:实质上是无法显示,/laugh),同时也在可读性方面为 web 开发者消除了大多数差劲的选项。这个其实有点类似于 Safari 的阅读模式。不幸的是,大部分网站都有很多令人讨厌的繁琐的东西以及难以转换为文本的导航,
|
||||
|
||||
[^5]: 易用性和易学性这两者经常容易被搞混。易学性是指学习使用工具的难易程度。而易用性是指工具高效的程度。通常来说,这是要差别的,就想鼠标和菜单栏的差别一样。菜单栏很容易学会,但是却不怎么高效,以致于早期会存在一些键盘的快捷键。除了在 GUI 方面上,Raskin 在很多方面上的观点都很正确。如今,操作系统正在将一些合适的搜索映射到键盘的快捷键上。比如说在 OS X 和 Windows 上,我默认的导航方式就是搜索。Ubuntu 的搜索做的很差劲,如同它的 GUI 一样差劲。
|
||||
|
||||
[^6]: 在有网的情况下,[AWS S3][42] 是解决文件存储问题的有效方案。数万亿个对象存在 S3 中,但是从来没有遗失过。大部分提供云存储的服务都是在 S3 上或是模拟 S3 构建的。没人能够拥有 S3 一样的规模,所以我将重要的文件通过 Dropbox 存储在上面。
|
||||
|
||||
[^7]: 目前,你可能会想:“这个人和自行车有什么关系?”……我在各个层面上都喜欢自行车。自行车是迄今为止发明的最具机械效率的交通工具。自行车可以是真正美丽的事物。而且,只要注意点的话,自行车可以用一辈子。早在 2001 年,我曾向 Rivendell Bicycle Works 订购了一辆自行车,现在我每次看到那辆自行车依然很高兴,自行车和 Unix 是我接触过的最好的两个发明。对了,还有 Emacs。
|
||||
|
||||
[^8]: 这个网站有一个很棒的 Emacs 教程,但不是这个。当我浏览这个页面时,我确实得到了一些对获取高效的 Emacs 配置很重要的知识,但无论怎么说,这都不是个替代品。
|
||||
|
||||
[^9]: 20 世纪 80 年代,Jef Raskin 与 Steve Jobs 在 Macintosh 项目上闹翻后, Jef Raskin 又设计了 [Canon Cat 计算机][43]。这台 Cat 计算机是以文档为中心的界面(所有的计算机都应如此),并以一种全新的方式使用键盘,你现在可以用 Emacs 来模仿这种键盘。如果现在有一台现代的,功能强大的 Cat 计算机并配有一个高分辨的显示器和 Unix 系统的话,我立马会用 Mac 来换。[https://youtu.be/o_TlE_U_X3c?t=19s][28]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://blog.fugue.co/2015-11-11-guide-to-emacs.html
|
||||
|
||||
作者:[Josh Stella][a]
|
||||
译者:[oneforalone](https://github.com/oneforalone)
|
||||
校对:[wxy](https://github.com/wxy), [oneforalone](https://github.com/oneforalone)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://blog.fugue.co/authors/josh.html
|
||||
[1]:https://blog.fugue.co/2013-10-16-vpc-on-aws-part3.html
|
||||
[2]:https://blog.fugue.co/2013-10-02-vpc-on-aws-part2.html
|
||||
[3]:http://ww2.fugue.co/2017-05-25_OS_AR_GartnerCoolVendor2017_01-LP-Registration.html
|
||||
[4]:https://blog.fugue.co/authors/josh.html
|
||||
[5]:https://twitter.com/joshstella
|
||||
[6]:https://www.youtube.com/watch?v=khJQgRLKMU0
|
||||
[7]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#phb
|
||||
[8]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#tufte
|
||||
[9]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#interpreter
|
||||
[10]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#eww
|
||||
[11]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#usability
|
||||
[12]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#s3
|
||||
[13]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#bicycles
|
||||
[14]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#nottutorial
|
||||
[15]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#canoncat
|
||||
[16]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#phbOrigin
|
||||
[17]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#tufteOrigin
|
||||
[18]:http://archive.wired.com/wired/archive/2.08/tufte.html
|
||||
[19]:http://archive.wired.com/wired/archive/2.08/tufte.html
|
||||
[20]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#interpreterOrigin
|
||||
[21]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#ewwOrigin
|
||||
[22]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#usabilityOrigin
|
||||
[23]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#s3Origin
|
||||
[24]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#bicyclesOrigin
|
||||
[25]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#nottutorialOrigin
|
||||
[26]:https://blog.fugue.co/2015-11-11-guide-to-emacs.html?utm_source=wanqu.co&utm_campaign=Wanqu+Daily&utm_medium=website#canoncatOrigin
|
||||
[27]:https://youtu.be/o_TlE_U_X3c?t=19s
|
||||
[28]:https://youtu.be/o_TlE_U_X3c?t=19s
|
||||
[29]:https://blog.fugue.co/authors/josh.html
|
||||
[30]:http://www.huffingtonpost.com/zachary-ehren/soma-isnt-a-drug-san-fran_b_987841.html
|
||||
[31]:http://www.campagnolo.com/US/en
|
||||
[32]:http://www.businessinsider.com/best-pointy-haired-boss-moments-from-dilbert-2013-10
|
||||
[33]:http://www.webopedia.com/TERM/I/interpreter.html
|
||||
[34]:http://emacsformacosx.com/
|
||||
[35]:http://emacsformacosx.com/
|
||||
[36]:http://www.gnu.org/software/emacs/
|
||||
[37]:http://www.gnu.org/software/emacs/
|
||||
[38]:http://www.huffingtonpost.com/2015/05/29/two-spaces-after-period-debate_n_7455660.html
|
||||
[39]:http://practicaltypography.com/one-space-between-sentences.html
|
||||
[40]:http://input.fontbureau.com/
|
||||
[41]:https://twitter.com/fugueHQ
|
||||
[42]:https://baike.baidu.com/item/amazon%20s3/10809744?fr=aladdin
|
||||
[43]:https://en.wikipedia.org/wiki/Canon_Cat
|
@ -1,145 +1,165 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: translator: (jlztan)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (Celebrate Christmas In Linux Way With These Wallpapers)
|
||||
[#]: via: (https://itsfoss.com/christmas-linux-wallpaper/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
[#]: url: ( )
|
||||
[#]: url: (https://linux.cn/article-10381-1.html)
|
||||
|
||||
Celebrate Christmas In Linux Way With These Wallpapers
|
||||
以 Linux 的方式庆祝圣诞节
|
||||
======
|
||||
|
||||
It’s the holiday season and many of you might be celebrating Christmas already. From the team of It’s FOSS, I would like to wish you a Merry Christmas and a happy new year.
|
||||
当前正是假日季,很多人可能已经在庆祝圣诞节了。祝你圣诞快乐,新年快乐。
|
||||
|
||||
To continue the festive mood, I’ll show you some really awesome [Linux wallpapers][1] on Christmas theme. But before we see that, how about a Christmas Tree in Linux terminal.
|
||||
为了延续节日氛围,我将向你展示一些非常棒的圣诞主题的 [Linux 壁纸][1]。在呈现这些壁纸之前,先来看一棵 Linux 终端下的圣诞树。
|
||||
|
||||
### Display Christmas Tree in Linux Terminal
|
||||
### 让你的桌面飘雪(针对 GNOME 用户)
|
||||
|
||||
<https://giphy.com/embed/xUNda6KphvbpYxL3tm>
|
||||
- [Let it Snow on Your Linux Desktop](https://youtu.be/1QI1ludzZuA)
|
||||
|
||||
If you want to display an animated Christmas tree in the terminal, you can use the command below:
|
||||
如果您在 Ubuntu 18.04 或任何其他 Linux 发行版中使用 GNOME 桌面,您可以使用一个小的 [GNOME 扩展][55]并在桌面上飘雪。
|
||||
|
||||
您可以从软件中心或 GNOME 扩展网站获取此 gsnow 扩展。我建议您阅读一些关于[使用 GNOME 扩展][55]的内容。
|
||||
|
||||
安装此扩展程序后,您会在顶部面板上看到一个小雪花图标。 如果您单击一次,您会看到桌面屏幕上的小絮状物掉落。
|
||||
|
||||
![](https://itsfoss.com/wp-content/uploads/2018/12/snowfall-on-linux-desktop-1.webm)
|
||||
|
||||
你可以再次点击该图标来禁止雪花落下。
|
||||
|
||||
### 在 Linux 终端下显示圣诞树
|
||||
|
||||
![Display Christmas Tree in Linux Terminal](https://i.giphy.com/xUNda6KphvbpYxL3tm.gif)
|
||||
|
||||
如果你想要在终端里显示一个动画的圣诞树,你可以使用如下命令:
|
||||
|
||||
```
|
||||
curl https://raw.githubusercontent.com/sergiolepore/ChristBASHTree/master/tree-EN.sh | bash
|
||||
```
|
||||
|
||||
If you don’t want to get it from the internet all the time, you can get the shell script from its GitHub repository, change the permission and run it like a normal shell script.
|
||||
要是不想一直从互联网上获取这棵圣诞树,也可以从它的 [GitHub 仓库][2] 中获取对应的 shell 脚本,更改权限之后按照运行普通 shell 脚本的方式运行它。
|
||||
|
||||
[ChristBASHTree][2]
|
||||
|
||||
### Display Christmas Tree in Linux terminal using Perl
|
||||
### 使用 Perl 在 Linux 终端下显示圣诞树
|
||||
|
||||
[![Christmas Tree in Linux terminal by NixCraft][3]][4]
|
||||
|
||||
This trick was originally shared by [NixCraft][5]. You’ll need to install a Perl module for this.
|
||||
这个技巧最初由 [NixCraft][5] 分享,你需要为此安装 Perl 模块。
|
||||
|
||||
To be honest, I don’t like using Perl modules because uninstalling them is a real pain. So **use this Perl module knowing that you’ll have to manually remove it**.
|
||||
说实话,我不喜欢使用 Perl 模块,因为卸载它们真的很痛苦。所以使用这个 Perl 模块时需谨记,你必须手动移除它。
|
||||
|
||||
```
|
||||
perl -MCPAN -e 'install Acme::POE::Tree'
|
||||
```
|
||||
|
||||
You can read the original article [here][5] to know more about it.
|
||||
你可以阅读 [原文][5] 来了解更多信息。
|
||||
|
||||
## Download Linux Christmas Wallpapers
|
||||
### 下载 Linux 圣诞主题壁纸
|
||||
|
||||
All these Linux Christmas wallpapers are created by Mark Riedesel and you can find plenty of other artwork on [his website][6].
|
||||
所有这些 Linux 圣诞主题壁纸都是由 Mark Riedesel 制作的,你可以在 [他的网站][6] 上找到很多其他艺术品。
|
||||
|
||||
He has been making such wallpapers almost every year since 2002. Quite understandably some of the earliest wallpapers don’t have modern aspect ratio. I have put them up in reverse chronological order.
|
||||
自 2002 年以来,他几乎每年都在制作这样的壁纸。可以理解的是,最早的一些壁纸不具有现代的宽高比。我把它们按时间倒序排列。
|
||||
|
||||
One tiny note. The images displayed here are highly compressed so download the wallpapers from the provided link only.
|
||||
注意一个小地方,这里显示的图片都是高度压缩的,因此你要通过图片下方提供的链接进行下载。
|
||||
|
||||
![Christmas Linux Wallpaper][56]
|
||||
|
||||
*[下载此壁纸][57]*
|
||||
|
||||
![Christmas Linux Wallpaper][7]
|
||||
|
||||
[Download This Wallpaper][8]
|
||||
*[下载此壁纸][8]*
|
||||
|
||||
[![Christmas Linux Wallpapers][9]][10]
|
||||
|
||||
[Download This Wallpaper][11]
|
||||
*[下载此壁纸][11]*
|
||||
|
||||
[![Christmas Linux Wallpapers][12]][13]
|
||||
|
||||
[Download This Wallpaper][14]
|
||||
*[下载此壁纸][14]*
|
||||
|
||||
[![Christmas Linux Wallpapers][15]][16]
|
||||
|
||||
[Download This Wallpaper][17]
|
||||
*[下载此壁纸][17]*
|
||||
|
||||
[![Christmas Linux Wallpapers][18]][19]
|
||||
|
||||
[Download This Wallpaper][20]
|
||||
*[下载此壁纸][20]*
|
||||
|
||||
[![Christmas Linux Wallpapers][21]][22]
|
||||
|
||||
[Download This Wallpaper][23]
|
||||
*[下载此壁纸][23]*
|
||||
|
||||
[![Christmas Linux Wallpapers][24]][25]
|
||||
|
||||
[Download This Wallpaper][26]
|
||||
*[下载此壁纸][26]*
|
||||
|
||||
[![Christmas Linux Wallpapers][27]][28]
|
||||
|
||||
[Download This Wallpaper][29]
|
||||
*[下载此壁纸][29]*
|
||||
|
||||
[![Christmas Linux Wallpapers][30]][31]
|
||||
|
||||
[Download This Wallpaper][32]
|
||||
*[下载此壁纸][32]*
|
||||
|
||||
[![Christmas Linux Wallpapers][33]][34]
|
||||
|
||||
[Download This Wallpaper][35]
|
||||
*[下载此壁纸][35]*
|
||||
|
||||
[![Christmas Linux Wallpapers][36]][37]
|
||||
|
||||
[Download This Wallpaper][38]
|
||||
*[下载此壁纸][38]*
|
||||
|
||||
[![Christmas Linux Wallpapers][39]][40]
|
||||
|
||||
[Download This Wallpaper][41]
|
||||
*[下载此壁纸][41]*
|
||||
|
||||
[![Christmas Linux Wallpapers][42]][43]
|
||||
|
||||
[Download This Wallpaper][44]
|
||||
*[下载此壁纸][44]*
|
||||
|
||||
[![Christmas Linux Wallpapers][45]][46]
|
||||
|
||||
[Download This Wallpaper][47]
|
||||
*[下载此壁纸][47]*
|
||||
|
||||
[![Christmas Linux Wallpapers][48]][49]
|
||||
|
||||
[Download This Wallpaper][50]
|
||||
*[下载此壁纸][50]*
|
||||
|
||||
### Bonus: Linux Christmas carols
|
||||
### 福利:Linux 圣诞颂歌
|
||||
|
||||
Here is a bonus for you. Christmas carols Linuxified for Linux lovers like us.
|
||||
这是给你的一份福利,给像我们一样的 Linux 爱好者的关于 Linux 的圣诞颂歌。
|
||||
|
||||
In [an article on Computer World][51], [Sandra Henry-Stocker][52] shared such Christmas carols. An excerpt:
|
||||
在 [《计算机世界》的一篇文章][51] 中,[Sandra Henry-Stocker][52] 分享了这些圣诞颂歌。摘录片段如下:
|
||||
|
||||
To the tune of: [Chestnuts Roasting on an Open Fire][53]
|
||||
这一段用的 [Chestnuts Roasting on an Open Fire][53] 的曲调:
|
||||
|
||||
> Running merrily on open source
|
||||
> Running merrily on open source
|
||||
>
|
||||
> With users happy as can be
|
||||
>
|
||||
> We’re using Linux and getting lots done
|
||||
|
||||
> And happy everything is free
|
||||
|
||||
To the tune of: [The Twelve Days of Christmas][54]
|
||||
这一段用的 [The Twelve Days of Christmas][54] 的曲调:
|
||||
|
||||
> On my first day with Linux, my admin gave to me a password and a login ID
|
||||
> On my first day with Linux, my admin gave to me a password and a login ID
|
||||
>
|
||||
> On my second day with Linux my admin gave to me two new commands and a password and a login ID
|
||||
|
||||
You can read full carols [here][51].
|
||||
在 [这里][51] 阅读完整的颂歌。
|
||||
|
||||
Merry Linux to you!!
|
||||
Linux 快乐!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
------
|
||||
|
||||
via: https://itsfoss.com/christmas-linux-wallpaper/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[jlztan](https://github.com/jlztan)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -199,3 +219,6 @@ via: https://itsfoss.com/christmas-linux-wallpaper/
|
||||
[52]: https://twitter.com/bugfarm
|
||||
[53]: https://www.youtube.com/watch?v=dhzxQCTCI3E
|
||||
[54]: https://www.youtube.com/watch?v=oyEyMjdD2uk
|
||||
[55]: https://itsfoss.com/gnome-shell-extensions/
|
||||
[56]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2016/12/ChristmasTux2018.jpeg?w=800&ssl=1
|
||||
[57]: http://www.klowner.com/wallery/christmas_tux_2018/download/ChristmasTux2018_4K_3840x2160.png
|
@ -0,0 +1,240 @@
|
||||
我的个人电子邮件系统设置:notmuch、mbsync、Postfix 和 dovecot
|
||||
======
|
||||
|
||||
我使用个人电子邮件系统已经相当长的时间了,但是一直没有记录过文档。最近我换了我的笔记本电脑(职业变更导致的变动),我在试图重新创建本地邮件系统时迷茫了。所以这篇文章是一个给自己看的文档,这样我就不用费劲就能再次搭建出来。
|
||||
|
||||
### 服务器端
|
||||
|
||||
我运行自己的邮件服务器,并使用 Postfix 作为 SMTP 服务器,用 Dovecot 实现 IMAP。我不打算详细介绍如何配置这些设置,因为我的设置主要是通过使用 Jonas 为 Redpill 基础架构创建的脚本完成的。什么是 Redpill?(用 Jonas 自己的话说):
|
||||
|
||||
> \<jonas> Redpill 是一个概念:一种设置 Debian hosts 去跨组织协作的方式
|
||||
>
|
||||
> \<jonas> 我发展了这个概念,并将其首次用于 Redpill 网中网:redpill.dk,其中涉及到了我自己的网络(jones.dk),我的主要客户的网络(homebase.dk),一个包括 Skolelinux Germany(free-owl.de)的在德国的网络,和 Vasudev 的网络(copyninja.info)
|
||||
|
||||
除此之外, 我还有一个 dovecot sieve 过滤,根据邮件的来源,对邮件进行高级分类,将其放到各种文件夹中。所有的规则都存在于每个有邮件地址的账户下的 `~/dovecot.sieve` 文件中。
|
||||
|
||||
再次,我不会详细介绍如何设置这些东西,因为这不是我这个帖子的目标。
|
||||
|
||||
### 在我的笔记本电脑上
|
||||
|
||||
在我的笔记本电脑上,我已经按照 4 个部分设置
|
||||
|
||||
1. 邮件同步:使用 `mbsync` 命令完成
|
||||
2. 分类:使用 notmuch 完成
|
||||
3. 阅读:使用 notmuch-emacs 完成
|
||||
4. 邮件发送:使用作为中继服务器和 SMTP 客户端运行的 Postfix 完成。
|
||||
|
||||
### 邮件同步
|
||||
|
||||
邮件同步是使用 `mbsync` 工具完成的, 我以前是 OfflineIMAP 的用户,最近切换到 `mbsync`,因为我觉得它比 OfflineIMAP 的配置更轻量、更简单。该命令是由 isync 包提供的。
|
||||
|
||||
配置文件是 `~/.mbsyncrc`。下面是我的例子与一些个人设置。
|
||||
|
||||
```
|
||||
IMAPAccount copyninja
|
||||
Host imap.copyninja.info
|
||||
User vasudev
|
||||
PassCmd "gpg -q --for-your-eyes-only --no-tty --exit-on-status-write-error --batch --passphrase-file ~/path/to/passphrase.txt -d ~/path/to/mailpass.gpg"
|
||||
SSLType IMAPS
|
||||
SSLVersion TLSv1.2
|
||||
CertificateFile /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
|
||||
IMAPAccount gmail-kamathvasudev
|
||||
Host imap.gmail.com
|
||||
User kamathvasudev@gmail.com
|
||||
PassCmd "gpg -q --for-your-eyes-only --no-tty --exit-on-status-write-error --batch --passphrase-file ~/path/to/passphrase.txt -d ~/path/to/mailpass.gpg"
|
||||
SSLType IMAPS
|
||||
SSLVersion TLSv1.2
|
||||
CertificateFile /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
IMAPStore copyninja-remote
|
||||
Account copyninja
|
||||
|
||||
IMAPStore gmail-kamathvasudev-remote
|
||||
Account gmail-kamathvasudev
|
||||
|
||||
MaildirStore copyninja-local
|
||||
Path ~/Mail/vasudev-copyninja.info/
|
||||
Inbox ~/Mail/vasudev-copyninja.info/INBOX
|
||||
|
||||
MaildirStore gmail-kamathvasudev-local
|
||||
Path ~/Mail/Gmail-1/
|
||||
Inbox ~/Mail/Gmail-1/INBOX
|
||||
|
||||
Channel copyninja
|
||||
Master :copyninja-remote:
|
||||
Slave :copyninja-local:
|
||||
Patterns *
|
||||
Create Both
|
||||
SyncState *
|
||||
Sync All
|
||||
|
||||
Channel gmail-kamathvasudev
|
||||
Master :gmail-kamathvasudev-remote:
|
||||
Slave :gmail-kamathvasudev-local:
|
||||
# Exclude everything under the internal [Gmail] folder, except the interesting folders
|
||||
Patterns * ![Gmail]*
|
||||
Create Both
|
||||
SyncState *
|
||||
Sync All
|
||||
```
|
||||
|
||||
对上述配置中的一些有趣部分进行一下说明。一个是 PassCmd,它允许你提供 shell 命令来获取帐户的密码。这样可以避免在配置文件中填写密码。我使用 gpg 的对称加密,并在我的磁盘上存储密码。这当然是由 Unix ACL 保护安全的。
|
||||
|
||||
实际上,我想使用我的公钥来加密文件,但当脚本在后台或通过 systemd 运行时,解锁文件看起来很困难 (或者说几乎不可能)。如果你有更好的建议,我洗耳恭听:-)。
|
||||
|
||||
下一个指令部分是 Patterns。这使你可以有选择地同步来自邮件服务器的邮件。这对我来说真的很有帮助,可以排除所有的 “[Gmail]/ folders” 垃圾目录。
|
||||
|
||||
### 邮件分类
|
||||
|
||||
一旦邮件到达你的本地设备,我们需要一种方法来轻松地在邮件读取器中读取邮件。我最初的设置使用本地 dovecot 实例提供同步的 Maildir,并在 Gnus 中阅读。这种设置相比于设置所有的服务器软件是有点大题小作,但 Gnus 无法很好地应付 Maildir 格式,这是最好的方法。这个设置也有一个缺点,那就是在你快速搜索邮件时,要搜索大量邮件。而这就是 notmuch 的用武之地。
|
||||
|
||||
notmuch 允许我轻松索引上千兆字节的邮件档案而找到我需要的东西。我已经创建了一个小脚本,它结合了执行 `mbsync` 和 `notmuch`。我使用 dovecot sieve 来基于实际上创建在服务器端的 Maildirs 标记邮件。下面是我的完整 shell 脚本,它执行同步分类和删除垃圾邮件的任务。
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
|
||||
MBSYNC=$(pgrep mbsync)
|
||||
NOTMUCH=$(pgrep notmuch)
|
||||
|
||||
if [ -n "$MBSYNC" -o -n "$NOTMUCH" ]; then
|
||||
echo "Already running one instance of mail-sync. Exiting..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Deleting messages tagged as *deleted*"
|
||||
notmuch search --format=text0 --output=files tag:deleted |xargs -0 --no-run-if-empty rm -v
|
||||
|
||||
echo "Moving spam to Spam folder"
|
||||
notmuch search --format=text0 --output=files tag:Spam and \
|
||||
to:vasudev@copyninja.info | \
|
||||
xargs -0 -I {} --no-run-if-empty mv -v {} ~/Mail/vasudev-copyninja.info/Spam/cur
|
||||
notmuch search --format=text0 --output=files tag:Spam and
|
||||
to:vasudev-debian@copyninja.info | \
|
||||
xargs -0 -I {} --no-run-if-empty mv -v {} ~/Mail/vasudev-copyninja.info/Spam/cur
|
||||
|
||||
|
||||
MDIR="vasudev-copyninja.info vasudev-debian Gmail-1"
|
||||
mbsync -Va
|
||||
notmuch new
|
||||
|
||||
for mdir in $MDIR; do
|
||||
echo "Processing $mdir"
|
||||
for fdir in $(ls -d /home/vasudev/Mail/$mdir/*); do
|
||||
if [ $(basename $fdir) != "INBOX" ]; then
|
||||
echo "Tagging for $(basename $fdir)"
|
||||
notmuch tag +$(basename $fdir) -inbox -- folder:$mdir/$(basename $fdir)
|
||||
fi
|
||||
done
|
||||
done
|
||||
```
|
||||
|
||||
因此,在运行 `mbsync` 之前,我搜索所有标记为“deleted”的邮件,并将其从系统中删除。接下来,我在我的帐户上查找标记为“Spam”的邮件,并将其移动到“Spam”文件夹。你没看错,这些邮件逃脱了垃圾邮件过滤器进入到我的收件箱,并被我亲自标记为垃圾邮件。
|
||||
|
||||
运行 `mbsync` 后,我基于它们的文件夹标记邮件(搜索字符串 `folder:`)。这让我可以很容易地得到一个邮件列表的内容,而不需要记住列表地址。
|
||||
|
||||
### 阅读邮件
|
||||
|
||||
现在,我们已经实现同步和分类邮件,是时候来设置阅读部分。我使用 notmuch-emacs 界面来阅读邮件。我使用 emacs 的 Spacemacs 风格,所以我花了一些时间写了一个私有层,它将我所有的快捷键和分类集中在一个地方,而不会扰乱我的整个 `.spacemacs` 文件。你可以在 [notmuch-emacs-layer 仓库][1] 找到我的私有层的代码。
|
||||
|
||||
### 发送邮件
|
||||
|
||||
能阅读邮件这还不够,我们也需要能够回复邮件。而这是最近是我感到迷茫的一个略显棘手的部分,以至于不得不写这篇文章,这样我就不会再忘记了。(当然也不必在网络上参考一些过时的帖子。)
|
||||
|
||||
我的系统发送邮件使用 Postfix 作为 SMTP 客户端,使用我自己的 SMTP 服务器作为它的中继主机。中继的问题是,它不能是具有动态 IP 的主机。有两种方法可以允许具有动态 IP 的主机使用中继服务器, 一种是将邮件来源的 IP 地址放入 `my_network` 或第二个使用 SASL 身份验证。
|
||||
|
||||
我的首选方法是使用 SASL 身份验证。为此,我首先要为每台机器创建一个单独的账户,它将把邮件中继到我的主服务器上。想法是不使用我的主帐户 SASL 进行身份验证。(最初我使用的是主账户,但 Jonas 给出了可行的按账户的想法)
|
||||
|
||||
```
|
||||
adduser <hostname>_relay
|
||||
```
|
||||
|
||||
这里替换 `<hostname>` 为你的笔记本电脑的名称或任何你正在使用的设备。现在我们需要调整 Postfix 作为中继服务器。因此,在 Postfix 配置中添加以下行:
|
||||
|
||||
```
|
||||
# SASL authentication
|
||||
smtp_sasl_auth_enable = yes
|
||||
smtp_tls_security_level = encrypt
|
||||
smtp_sasl_tls_security_options = noanonymous
|
||||
relayhost = [smtp.copyninja.info]:submission
|
||||
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
|
||||
```
|
||||
|
||||
因此, 这里的 `relayhost` 是用于将邮件转发到互联网的 Postfix 实例的服务器名称。`submission` 的部分 Postfix 将邮件转发到端口 587(安全端口)。`smtp_sasl_tls_security_options` 设置为不允许匿名连接。这是必须的,以便中继服务器信任你的移动主机,并同意为你转发邮件。
|
||||
|
||||
`/etc/postfix/sasl_passwd` 是你需要存储用于服务器 SASL 身份验证的帐户密码的文件。将以下内容放入其中。
|
||||
|
||||
```
|
||||
[smtp.example.com]:submission user:password
|
||||
```
|
||||
|
||||
用你已放入 `relayhost` 配置的 SMTP 服务器名称替换 `smtp.example.com`。用你创建的 `<hostname>_relay` 用户及其密码替换 `user` 和 `passwd`。
|
||||
|
||||
若要保护 `sasl_passwd` 文件,并为 Postfix 创建它的哈希文件,使用以下命令。
|
||||
|
||||
```
|
||||
chown root:root /etc/postfix/sasl_passwd
|
||||
chmod 0600 /etc/postfix/sasl_passwd
|
||||
postmap /etc/postfix/sasl_passwd
|
||||
```
|
||||
|
||||
最后一条命令将创建 `/etc/postfix/sasl_passwd.db` 文件,它是你的文件的 `/etc/postfix/sasl_passwd` 的哈希文件,具有相同的所有者和权限。现在重新加载 Postfix,并使用 `mail` 命令检查邮件是否从你的系统中发出。
|
||||
|
||||
### Bonus 的部分
|
||||
|
||||
好吧,因为我有一个脚本创建以上结合了邮件的同步和分类。我继续创建了一个 systemd 计时器,以定期同步后台的邮件。就我而言,每 10 分钟一次。下面是 `mailsync.timer` 文件。
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Check Mail Every 10 minutes
|
||||
RefuseManualStart=no
|
||||
RefuseManualStop=no
|
||||
|
||||
[Timer]
|
||||
Persistent=false
|
||||
OnBootSec=5min
|
||||
OnUnitActiveSec=10min
|
||||
Unit=mailsync.service
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
下面是 mailsync.service 服务,这是 mailsync.timer 执行我们的脚本所需要的。
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=Check Mail
|
||||
RefuseManualStart=no
|
||||
RefuseManualStop=yes
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/mail-sync
|
||||
StandardOutput=syslog
|
||||
StandardError=syslog
|
||||
```
|
||||
|
||||
将这些文件置于 `/etc/systemd/user` 目录下并运行以下代码去开启它们:
|
||||
|
||||
```
|
||||
systemctl enable --user mailsync.timer
|
||||
systemctl enable --user mailsync.service
|
||||
systemctl start --user mailsync.timer
|
||||
```
|
||||
|
||||
这就是我从系统同步和发送邮件的方式。我从 Jonas Smedegaard 那里了解到了 afew,他审阅了这篇帖子。因此, 下一步, 我将尝试使用 afew 改进我的 notmuch 配置,当然还会有一个后续的帖子:-)。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://copyninja.info/blog/email_setup.html
|
||||
|
||||
作者:[copyninja][a]
|
||||
译者:[lixinyuxx](https://github.com/lixinyuxx)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://copyninja.info
|
||||
[1]:https://source.copyninja.info/notmuch-emacs-layer.git/
|
@ -0,0 +1,91 @@
|
||||
27 个全方位的开放式教育解决方案
|
||||
======
|
||||
|
||||
> 阅读这些 2017 年 Opensource.com 发布的开放如何改进教育和学习的好文章。
|
||||
|
||||
![27 open solutions to everything in education](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/EDU_OpenEducationResources_520x292_cm.png?itok=9y4FGgRo)
|
||||
|
||||
开放式理念 (从开源软件到开放硬件,再到开放原则) 正在改变教育的范式。因此,为了庆祝今年发生的一切,我收集了 2017 年(译注:本文原发布于 2018 年初)在 Opensource.com 上发表的 27 篇关于这个主题的最好的文章。我把它们分成明确的主题,而不是按人气来分类。而且,如果这 27 个故事不能满足你对教育方面开源信息的胃口,那就看看我们的合作文章吧 “[教育如何借助 Linux 和树莓派][30]”。
|
||||
|
||||
### 开放对每个人都有好处
|
||||
|
||||
1. [书评:《OPEN》探讨了开放性的广泛文化含义][1]:Scott Nesbitt 评价 David Price 的书 《OPEN》 ,该书探讨了 “开放” 不仅仅是技术转变的观点,而是 “我们未来将如何工作、生活和学习”。
|
||||
2. [通过开源技能快速开始您的职业生涯][2]: VM (Vicky) Brasseur 指出了如何借助学习开源在工作群体中脱颖而出。这个建议不仅仅是针对程序员的;设计师、作家、营销人员和其他创意专业人士也对开源的成功至关重要。
|
||||
3. [研究生学位可以让你跳槽到开源职位][3]:引用的研究表明会 Linux 技能会带来更高的薪水, Joshua Pearce 说对开源的熟练和研究生学位是无与伦比的职业技能组合。
|
||||
4. [彻底改变了宾夕法尼亚的学校文化的三种实践][4]:Charlie Reisinger 向我们展示了开放式实践是如何在宾夕法尼亚州的一个学区创造一种更具包容性、敏捷性和开放性的文化的。Charlie 说,这不仅仅是为了省钱;该区还受益于 “开放式领导原则,促进师生创新,帮助更好地吸引社区,创造一个更有活力和包容性的学习社区”。
|
||||
5. [使用开源工具促使学生进步的 15 种方法][5]:我写了开源是如何让学生自由探索、补拙和学习的,不管他们是在学习基本的数字化素养,还是通过有趣的项目来扩展这些技能。
|
||||
6. [开发人员有机会编写好的代码][6]:开源往往是对社会有益的项目的支柱。正如 Benetech Labs 副总裁 Ahn Bui 在这次采访中指出的那样:“建立开放数据标准是打破数据孤岛不可或缺的一步。这些开放标准将为互操作性提供基础,进而转化为更多的组织共同建设,往往更具成本效益。最终目标是以同样的成本甚至更低的成本为更多的人服务。”
|
||||
|
||||
### 用于再融合和再利用的开放式教育资源
|
||||
|
||||
1. [学术教员可以和维基百科一起教学吗?][7]:Wiki Ed 的项目总监 LiAnna Davis 讨论<ruby>开放式教育资源<rt>open educational resources</rt></ruby> (OER) ,如 Wiki Ed,是如何提供高质量且经济实惠的开源学习资源作为课堂教学工具。
|
||||
2. [书本内外?开放教育资源的状态][8]:Cable Green 是 Creative Common 开放教育主管,分享了高等教育中教育面貌是如何变化的,以及 Creative Common 正在采取哪些措施来促进教育。
|
||||
3. [急需符合标准的课程的学校系统找到了希望][9]:Karen Vaites 是 Open Up Resources 社区布道师和首席营销官,谈论了非营利组织努力为 K-12 学校提供开放的、标准一致的课程。
|
||||
4. [夏威夷大学如何解决当今高等教育的问题][10]:夏威夷大学 Manoa 分校的教育技术专家 Billy Meinke 表示,在大学课程中过渡到 ORE 将 “使教师能够控制他们教授的内容,我们预计这将为他们节省学生的费用。”
|
||||
5. [开放式课程如何削减高等教育成本][11]:塞勒学院的教育总监 Devon Ritter 报告了塞勒学院是如何建立以公开许可内容为基础的大学学分课程,目的是使更多的人能够负担得起和获得高等教育。
|
||||
6. [开放教育资源运动在提速][12]:Alexis Clifton 是纽约州立大学的 OER 服务的执行董事,描述了纽约 800 万美元的投资如何刺激开放教育的增长,并使大学更实惠。
|
||||
7. [开放项目合作,从小学到大学教室][13]:来自杜克大学的 Aria F. Chernik 探索 OSPRI (开源教育学的研究与创新), 这是杜克大学和红帽的合作,旨在建立一个 21 世纪的,开放设计的 preK-12 学习生态系统。
|
||||
8. [Perma.cc 将阻止学术链接腐烂][14]::弗吉尼亚理工大学的 Phillip Young 写的关于 Perma.cc 的文章,这种一种“链接腐烂”的解决方案,在学术论文中的超链接随着时间的推移而消失或变化的概览很高。
|
||||
9. [开放教育:学生如何通过创建开放教科书来节省资金][15]:OER 先驱 Robin DeRosa 谈到 “引入公开许可教科书的自由,以及教育和学习应结合包容性生态系统,以增强公益的总体理念”。
|
||||
|
||||
### 课堂上的开源工具
|
||||
|
||||
1. [开源棋盘游戏如何拯救地球][16]:Joshua Pearce 写的关于拯救地球的一个棋盘游戏,这是一款让学生在玩乐和为创客社区做出贡献的同时解决环境问题的棋盘游戏。
|
||||
2. [一个教孩子们如何阅读的新 Android 应用程序][17]:Michael Hall 谈到了他在儿子被诊断为自闭症后为他开发的儿童识字应用 Phoenicia,以及良好编码的价值,和为什么用户测试比你想象的更重要。
|
||||
3. [8 个用于教育的开源 Android 应用程序][18]:Joshua Allen Holm 推荐了 8 个来自 F-Droid 软件库的开源应用,使我们可以将智能手机用作学习工具。
|
||||
4. [MATLA B的 3 种开源替代方案][19]:Jason Baker 更新了他 2016 年的开源数学计算软件调查报告,提供了 MATLAB 的替代方案,这是数学、物理科学、工程和经济学中几乎无处不在的昂贵的专用解决方案。
|
||||
5. [SVG 与教孩子编码有什么关系?][20]:退休工程师 Jay Nick 谈论他如何使用艺术作为一种创新的方式,向学生介绍编码。他在学校做志愿者,使用 SVG 来教授一种结合数学和艺术原理的编码方法。
|
||||
6. [5 个破灭的神话:在高等教育中使用开源][21]: 拥有德克萨斯理工大学美术博士学位的 Kyle Conway 分享他在一个由专有解决方案统治的世界中使用开源工具的经验。 Kyle 说有一种偏见,反对在计算机科学以外的学科中使用开源:“很多人认为非技术专业的学生不能使用 Linux,他们对在高级学位课程中使用 Linux 的人做出了很多假设……嗯,这是有可能的,我就是证明。”
|
||||
7. [大学开源工具列表][22]:Aaron Cocker 概述了他在攻读计算机科学本科学位时使用的开源工具 (包括演示、备份和编程软件)。
|
||||
8. [5 个可帮助您学习优秀 KDE 应用程序][23]:Zsolt Szakács 提供五个 KDE 应用程序,可以帮助任何想要学习新技能或培养现有技能的人。
|
||||
|
||||
### 在教室编码
|
||||
|
||||
1. [如何尽早让下一代编码][24]:Bryson Payne 说我们需要在高中前教孩子们学会编码: 到了九年级,80% 的女孩和 60% 的男孩已经从 STEM 职业中自选。但他建议,这不仅仅是就业和缩小 IT 技能差距的问题。“教一个年轻人编写代码可能是你能给他们的最改变生活的技能。而且这不仅仅是一个职业提升者。编码是关于解决问题,它是关于创造力,更重要的是,它是提升能力”。
|
||||
2. [孩子们无法在没有计算机的情况下编码][25]:Patrick Masson 推出了 FLOSS 儿童桌面计划, 该计划教授服务不足学校的学生使用开源软件 (如 Linux、LibreOffice 和 GIMP) 重新利用较旧的计算机。该计划不仅为破旧或退役的硬件注入新的生命,还为学生提供了重要的技能,而且还为学生提供了可能转化为未来职业生涯的重要技能。
|
||||
3. [如今 Scratch 是否能像 80 年代的 LOGO 语言一样教孩子们编码?][26]:Anderson Silva 提出使用 [Scratch][27] 以激发孩子们对编程的兴趣,就像在 20 世纪 80 年代开始使用 LOGO 语言时一样。
|
||||
4. [通过这个拖放框架学习Android开发][28]:Eric Eslinger 介绍了 App Inventor,这是一个编程框架,用于构建 Android 应用程序使用可视块语言(类似 Scratch 或者 [Snap][29])。
|
||||
|
||||
在这一年里,我们了解到,教育领域的各个方面都有了开放的解决方案,我预计这一主题将在 2018 年及以后继续下去。在未来的一年里,你是否希望 Opensource.com 涵盖开放式的教育主题?如果是, 请在评论中分享你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/1/best-open-education
|
||||
|
||||
作者:[Don Watkins][a]
|
||||
译者:[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/don-watkins
|
||||
[1]:https://opensource.com/article/17/7/book-review-open
|
||||
[2]:https://opensource.com/article/17/8/jump-start-your-career
|
||||
[3]:https://opensource.com/article/17/1/grad-school-open-source-academic-lab
|
||||
[4]:https://opensource.com/article/17/7/open-school-leadership
|
||||
[5]:https://opensource.com/article/17/7/empower-students-open-source-tools
|
||||
[6]:https://opensource.com/article/17/3/interview-anh-bui-benetech-labs
|
||||
[7]:https://opensource.com/article/17/1/Wiki-Education-Foundation
|
||||
[8]:https://opensource.com/article/17/2/future-textbooks-cable-green-creative-commons
|
||||
[9]:https://opensource.com/article/17/1/open-up-resources
|
||||
[10]:https://opensource.com/article/17/2/interview-education-billy-meinke
|
||||
[11]:https://opensource.com/article/17/7/college-alternatives
|
||||
[12]:https://opensource.com/article/17/10/open-educational-resources-alexis-clifton
|
||||
[13]:https://opensource.com/article/17/3/education-should-be-open-design
|
||||
[14]:https://opensource.com/article/17/9/stop-link-rot-permacc
|
||||
[15]:https://opensource.com/article/17/11/creating-open-textbooks
|
||||
[16]:https://opensource.com/article/17/7/save-planet-board-game
|
||||
[17]:https://opensource.com/article/17/4/phoenicia-education-software
|
||||
[18]:https://opensource.com/article/17/8/8-open-source-android-apps-education
|
||||
[19]:https://opensource.com/alternatives/matlab
|
||||
[20]:https://opensource.com/article/17/5/coding-scalable-vector-graphics-make-steam
|
||||
[21]:https://opensource.com/article/17/5/how-linux-higher-education
|
||||
[22]:https://opensource.com/article/17/6/open-source-tools-university-student
|
||||
[23]:https://opensource.com/article/17/6/kde-education-software
|
||||
[24]:https://opensource.com/article/17/8/teach-kid-code-change-life
|
||||
[25]:https://opensource.com/article/17/9/floss-desktops-kids
|
||||
[26]:https://opensource.com/article/17/3/logo-scratch-teach-programming-kids
|
||||
[27]:https://scratch.mit.edu/
|
||||
[28]:https://opensource.com/article/17/8/app-inventor-android-app-development
|
||||
[29]:http://snap.berkeley.edu/
|
||||
[30]:https://opensource.com/article/17/12/best-opensourcecom-linux-and-raspberry-pi-education
|
95
published/201812/20180128 Getting Linux Jobs.md
Normal file
95
published/201812/20180128 Getting Linux Jobs.md
Normal file
@ -0,0 +1,95 @@
|
||||
Linux 求职建议
|
||||
======
|
||||
|
||||
通过对招聘网站数据的仔细研究,我们发现,即使是非常有经验的 Linux 程序员,也会在面试中陷入困境。
|
||||
|
||||
这就导致了很多优秀并且有经验的人无缘无故地找不到合适的工作,因为如今的就业市场需要我们有一些手段来提高自己的竞争力。
|
||||
|
||||
我有两个同事和一个表哥,他们都有 RedHat 认证,管理过比较大的服务器机房,也都收到过前雇主的认真推荐。
|
||||
|
||||
可是,在他们应聘的时候,所有的这些证书、本身的能力、工作经验好像都没有起到任何作用,他们所面对的招聘广告是某人从技术词汇中临时挑选的一些“技能片段”所组成的。
|
||||
|
||||
现如今,礼貌变得过时了,**不回应**变成了发布招聘广告的公司的新沟通方式。
|
||||
|
||||
这同样也意味着大多公司的招聘或者人事可能会**错过**非常优秀的应聘者。
|
||||
|
||||
我之所以敢说的如此肯定,是因为现在招聘广告大多数看上去都非常的滑稽。
|
||||
|
||||
[Reallylinux.com][3] 另一位特约撰稿人 Walter ,发表过一篇关于 [招聘广告疯掉了][4] 的文章。
|
||||
|
||||
他说的也许是对的,可是我认为 Linux 工作应聘者可以通过注意招聘广告的**三个关键点**避免落入陷阱。
|
||||
|
||||
**首先**,很少会有 Linux 系统管理员的招聘广告只针对 Linux 有要求。
|
||||
|
||||
一定要注意很少有 Linux 系统管理员的职位是实际在服务器上跑 Linux的,反而,很多在搜索 “Linux 管理员” 得到的职位实际上是指大量的 *NX 操作系统的。
|
||||
|
||||
举个例子,有一则关于 **Linux 管理员** 的招聘广告:
|
||||
|
||||
> 该职位需要为建立系统集成提供支持,尤其是 BSD 应用的系统安装...
|
||||
|
||||
或者有一些其他的要求:
|
||||
|
||||
> 有 Windows 系统管理经验的。
|
||||
|
||||
最为讽刺的是,如果你在应聘面试的时候表现出专注于 Linux 的话,你可能不会被聘用。
|
||||
|
||||
另外,如果你直接把 Linux 写在你的特长或者专业上,他们可能都不会仔细看你的简历,因为他们根本区分不了 UNIX、BSD、Linux。
|
||||
|
||||
最终的结果就是,如果你太老实,只在简历上写了 Linux,你可能会被直接过掉,但是如果你把 Linux 改成 UNIX/Linux 的话,可能会走得更远。
|
||||
|
||||
我有两个同事最后修改了他们的简历,然后获得了更好的面试机会,虽然依旧没有被聘用,因为大多数招聘广告其实已经内定人员了,这些招聘信息被放出来仅仅是为了表现出他们有招聘的想法。
|
||||
|
||||
**第二点**,公司里唯一在乎系统管理员职位的只有技术主管,其他人包括人事或管理层根本不关心这个。
|
||||
|
||||
我记得有一次开会旁听的时候,听见一个执行副总裁把服务器管理人员说成“一毛钱一打的人”,这种想法是多么的奇怪啊。
|
||||
|
||||
讽刺的是,等到邮件系统出故障,电话交换机连接时不时会断开,或者核心商业文件从企业内网中消失的时候,这些总裁又是最先打电话给系统管理员的。
|
||||
|
||||
或许如果他们不整天在电话留言中说那么多空话,或者不往邮件里塞满妻子的照片和旅行途中的照片的话,服务器可能就不会崩溃。
|
||||
|
||||
请注意,招聘 Linux 运维或者服务器管理员的广告被放出来是因为公司**技术层**认为有迫切的需求。你也不需要和人事或者公司高层聊什么,搞清楚谁是招聘的技术经理然后打电话给他们。
|
||||
|
||||
你需要直接联系他们因为“有些技术问题”是人事回答不了的,即使你只有 60 秒的时间可以和他们交流,你也必须抓住这个机会和真正有需求并且懂技术的人沟通。
|
||||
|
||||
那如果人事的漂亮 MM 不让你直接联系技术怎么办呢?
|
||||
|
||||
开始记得问人事一些技术性问题,比如说他们的 Linux 集群是如何建立的,它们运行在独立的虚拟机上吗?这些技术性的问题会让人事变得不耐烦,最后让你有机会问出“我能不能直接联系你们团队的技术人员”。
|
||||
|
||||
如果对方的回答是“应该可以”或者“稍后回复你”,那么他们可能已经在两周前就已经计划好了找一个人来填补这个空缺,比如说人事部员工的未婚夫。**他们只是不希望看起来太像裙带主义,而是带有一点利己主义的不确定主义。**
|
||||
|
||||
所以一定要记得花点时间弄清楚到底谁是发布招聘广告的直接**技术**负责人,然后和他们聊一聊,这可能会让你少一番胡扯并且让你更有可能应聘成功。
|
||||
|
||||
**第三点**,现在的招聘广告很少有完全真实的内容了。
|
||||
|
||||
我以前见过一个招聘具有高级别专家也不会有的专门知识的初级系统管理员的广告,他们的计划是列出公司的发展计划蓝图,然后找到应聘者。
|
||||
|
||||
在这种情况下,你应聘 Linux 管理员职位应该提供几个关键性信息,例如工作经验和相关证书。
|
||||
|
||||
诀窍在于,用这些关键词尽量装点你的简历,以匹配他们的招聘信息,这样他们几乎不可能发现你缺失了哪个关键词。
|
||||
|
||||
这并不一定会让你成功找到一份工作,但它可以让你获得一次面试机会,这也算是一个巨大的进步。
|
||||
|
||||
通过理解和应用以上三点,或许可以让那些寻求 Linux 管理员工作的人能够比那些只有一线地狱机会的人领先一步。
|
||||
|
||||
即使这些建议不能让你马上得到面试机会,你也可以利用这些经验和意识去参加贸易展或公司主办的技术会议等活动。
|
||||
|
||||
我强烈建议你们也经常参加这种活动,尤其是当它们比较近的话,可以给你一个扩展人脉的机会。
|
||||
|
||||
请记住,如今的职业人脉已经失去了原来的意义了,现在只是可以用来获取“哪些公司实际上在招聘、哪些公司只是为了给股东带来增长的表象而在职位方面撒谎”的小道消息。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://reallylinux.com/docs/gettinglinuxjobs.shtml
|
||||
|
||||
作者:[Andrea W.Codingly][a]
|
||||
译者:[Ryze-Borgia](https://github.com/Ryze-Borgia)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://reallylinux.com
|
||||
[1]:http://www.reallylinux.com
|
||||
[2]:http://reallylinux.com/docs/linuxrecessionproof.shtml
|
||||
[3]:http://reallylinux.com
|
||||
[4]:http://reallylinux.com/docs/wantadsmad.shtml
|
@ -0,0 +1,179 @@
|
||||
用于游戏开发的图形和音乐工具
|
||||
======
|
||||
> 要在三天内打造一个可玩的游戏,你需要一些快速而稳定的好工具。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_Life_opengame.png?itok=JPxruL3k)
|
||||
|
||||
在十月初,我们的俱乐部马歇尔大学的 [Geeks and Gadgets][1] 参加了首次 [Open Jam][2],这是一个庆祝最佳开源工具的游戏 Jam。游戏 Jam 是一种活动,参与者以团队协作的方式来开发有趣的计算机游戏。Jam 一般都很短,仅有三天,并且非常累。Opensource.com 在八月下旬[发布了][3] Open Jam 活动,足有 [45 支游戏][4] 进入到了竞赛中。
|
||||
|
||||
我们的俱乐部希望在我们的项目中创建和使用开放源码软件,所以 Open Jam 自然是我们想要参与的 Jam 了。我们提交的游戏是一个实验性的游戏,名为 [Mark My Words][5]。我们使用了多种自由和开放源码 (FOSS) 工具来开发它;在这篇文章中,我们将讨论一些我们使用的工具和我们注意到可能有潜在阻碍的地方。
|
||||
|
||||
### 音频工具
|
||||
|
||||
#### MilkyTracker
|
||||
|
||||
[MilkyTracker][6] 是一个可用于编曲老式视频游戏中的音乐的软件包。它是一种<ruby>[音乐声道器][7]<rt>music tracker</rt></ruby>,是一个强大的 MOD 和 XM 文件创建器,带有基于特征网格的模式编辑器。在我们的游戏中,我们使用它来编曲大多数的音乐片段。这个程序最好的地方是,它比我们其它的大多数工具消耗更少的硬盘空间和内存。虽然如此,MilkyTracker 仍然非常强大。
|
||||
|
||||
![](https://opensource.com/sites/default/files/u128651/mtracker.png)
|
||||
|
||||
其用户界面需要一会来习惯,这里有对一些想试用 MilkyTracker 的音乐家的一些提示:
|
||||
|
||||
* 转到 “Config > Misc.” ,设置编辑模式的控制风格为 “MilkyTracker”,这将给你提供几乎全部现代键盘快捷方式。
|
||||
* 用 `Ctrl+Z` 撤销
|
||||
* 用 `Ctrl+Y` 重做
|
||||
* 用空格键切换模式编辑方式
|
||||
* 用退格键删除先前的音符
|
||||
* 用插入键来插入一行
|
||||
* 默认情况下,一个音符将持续作用,直到它在该频道上被替换。你可以明确地结束一个音符,通过使用一个反引号(`)键来插入一个 KeyOff 音符
|
||||
* 在你开始谱写乐曲前,你需要创建或查找采样。我们建议在诸如 [Freesound][9] 或 [ccMixter][10] 这样的网站上查找采用 [Creative Commons][8] 协议的采样,
|
||||
|
||||
另外,把 [MilkyTracker 文档页面][11] 放在手边。它含有数不清的教程和手册的链接。一个好的起点是在该项目 wiki 上的 [MilkyTracker 指南][12]。
|
||||
|
||||
#### LMMS
|
||||
|
||||
我们的两个音乐家使用多用途的现代音乐创建工具 [LMMS][13]。它带有一个绝妙的采样和效果库,以及多种多样的灵活的插件来生成独特的声音。LMMS 的学习曲线令人吃惊的低,在某种程度上是因为其好用的节拍/低音线编辑器。
|
||||
|
||||
![](https://opensource.com/sites/default/files/u128651/lmms_plugins.png)
|
||||
|
||||
我们对于想试试 LMMS 的音乐家有一个建议:使用插件。对于 [chiptune][14]式音乐,我们推荐 [sfxr][15]、[BitInvader][16] 和 [FreeBoy][17]。对于其它风格,[ZynAddSubFX][18] 是一个好的选择。它配备了各种合成仪器,可以根据您的需要进行更改。
|
||||
|
||||
### 图形工具
|
||||
|
||||
#### Tiled
|
||||
|
||||
在开放源码游戏开发中,[Tiled][19] 是一个流行的贴片地图编辑器。我们使用它为来为我们在游戏场景中组合连续的、复古式的背景。
|
||||
|
||||
![](https://opensource.com/sites/default/files/u128651/tiled.png)
|
||||
|
||||
Tiled 可以导出地图为 XML、JSON 或普通的图片。它是稳定的、跨平台的。
|
||||
|
||||
Tiled 的功能之一允许你在地图上定义和放置随意的游戏对象,例如硬币和提升道具,但在 jam 期间我们没有使用它。你需要做的全部是以贴片集的方式加载对象的图像,然后使用“插入平铺”来放置它们。
|
||||
|
||||
一般来说,对于需要一个地图编辑器的项目,Tiled 是我们所推荐的软件中一个不可或缺的部分。
|
||||
|
||||
#### Piskel
|
||||
|
||||
[Piskel][20] 是一个像素艺术编辑器,它的源文件代码以 [Apache 2.0 协议][21] 发布。在这次 Jam 期间,们的大多数的图像资源都使用 Piskel 来处理,我们当然也将在未来的工程中使用它。
|
||||
|
||||
在这个 Jam 期间,Piskel 极大地帮助我们的两个功能是<ruby>洋葱皮<rt>Onion skin</rt></ruby>和<ruby>精灵序列图<rt>spritesheet</rt></ruby>导出。
|
||||
|
||||
##### 洋葱皮
|
||||
|
||||
洋葱皮功能将使 Piskel 以虚影显示你编辑的动画的前一帧和后一帧的,像这样:
|
||||
|
||||
![](https://opensource.com/sites/default/files/u128651/onionshow.gif)
|
||||
|
||||
洋葱皮是很方便的,因为它适合作为一个绘制指引和帮助你在整个动画进程中保持角色的一致形状和体积。 要启用它,只需单击屏幕右上角预览窗口下方的洋葱形图标即可。
|
||||
|
||||
![](https://opensource.com/sites/default/files/u128651/onionenable.png)
|
||||
|
||||
##### 精灵序列图导出
|
||||
|
||||
Piskel 将动画导出为精灵序列图的能力也非常有用。精灵序列图是一个包含动画所有帧的光栅图像。例如,这是我们从 Piskel 导出的精灵序列图:
|
||||
|
||||
![](https://opensource.com/sites/default/files/u128651/sprite-artist.png)
|
||||
|
||||
该精灵序列图包含两帧。一帧位于图像的上半部分,另一帧位于图像的下半部分。精灵序列图通过从单个文件加载整个动画,大大简化了游戏的代码。这是上面精灵序列图的动画版本:
|
||||
|
||||
![](https://opensource.com/sites/default/files/u128651/sprite-artist-anim.gif)
|
||||
|
||||
##### Unpiskel.py
|
||||
|
||||
在 Jam 期间,我们很多次想批量转换 Piskel 文件到 PNG 文件。由于 Piskel 文件格式基于 JSON,我们写一个基于 GPLv3 协议的名为 [unpiskel.py][22] 的 Python 小脚本来做转换。
|
||||
|
||||
它像这样被调用的:
|
||||
|
||||
```
|
||||
python unpiskel.py input.piskel
|
||||
```
|
||||
|
||||
这个脚本将从一个 Piskel 文件(这里是 `input.piskel`)中提取 PNG 数据帧和图层,并将它们各自存储。这些文件采用模式 `NAME_XX_YY.png` 命名,在这里 `NAME` 是 Piskel 文件的缩减名称,`XX` 是帧的编号,`YY` 是层的编号。
|
||||
|
||||
因为脚本可以从一个 shell 中调用,它可以用在整个文件列表中。
|
||||
|
||||
```
|
||||
for f in *.piskel; do python unpiskel.py "$f"; done
|
||||
```
|
||||
|
||||
### Python、Pygame 和 cx_Freeze
|
||||
|
||||
#### Python 和 Pygame
|
||||
|
||||
我们使用 [Python][23] 语言来制作我们的游戏。它是一个脚本语言,通常被用于文本处理和桌面应用程序开发。它也可以用于游戏开发,例如像 [Angry Drunken Dwarves][24] 和 [Ren'Py][25] 这样的项目所展示的。这两个项目都使用一个称为 [Pygame][26] 的 Python 库来显示图形和产生声音,所以我们也决定在 Open Jam 中使用这个库。
|
||||
|
||||
Pygame 被证明是既稳定又富有特色,并且它对我们创建的街机式游戏来说是很棒的。在低分辨率时,库的速度足够快的,但是在高分辨率时,它只用 CPU 的渲染开始变慢。这是因为 Pygame 不使用硬件加速渲染。然而,开发者可以充分利用 OpenGL 基础设施的优势。
|
||||
|
||||
如果你正在寻找一个好的 2D 游戏编程库,Pygame 是值得密切注意的一个。它的网站有 [一个好的教程][27] 可以作为起步。务必看看它!
|
||||
|
||||
#### cx_Freeze
|
||||
|
||||
准备发行我们的游戏是有趣的。我们知道,Windows 用户不喜欢装一套 Python,并且要求他们来安装它可能很过分。除此之外,他们也可能必须安装 Pygame,在 Windows 上,这不是一个简单的工作。
|
||||
|
||||
很显然:我们必须放置我们的游戏到一个更方便的格式中。很多其他的 Open Jam 参与者使用专有的游戏引擎 Unity,它能够使他们的游戏在网页浏览器中来玩。这使得它们非常方便地来玩。便利性是一个我们的游戏中根本不存在的东西。但是,感谢生机勃勃的 Python 生态系统,我们有选择。已有的工具可以帮助 Python 程序员将他们的游戏做成 Windows 上的发布版本。我们考虑过的两个工具是 [cx_Freeze][28] 和 [Pygame2exe][29](它使用 [py2exe][30])。我们最终决定用 cx_Freeze,因为它是跨平台的。
|
||||
|
||||
在 cx_Freeze 中,你可以把一个单脚本游戏打包成发布版本,只要在 shell 中运行一个命令,像这样:
|
||||
|
||||
```
|
||||
cxfreeze main.py --target-dir dist
|
||||
```
|
||||
|
||||
`cxfreeze` 的这个调用将把你的脚本(这里是 `main.py`)和在你系统上的 Python 解释器捆绑到到 `dist` 目录。一旦完成,你需要做的是手动复制你的游戏的数据文件到 `dist` 目录。你将看到,`dist` 目录包含一个可以运行来开始你的游戏的可执行文件。
|
||||
|
||||
这里有使用 cx_Freeze 的更复杂的方法,允许你自动地复制数据文件,但是我们发现简单的调用 `cxfreeze` 足够满足我们的需要。感谢这个工具,我们使我们的游戏玩起来更便利一些。
|
||||
|
||||
### 庆祝开源
|
||||
|
||||
Open Jam 是庆祝开源模式的软件开发的重要活动。这是一个分析开源工具的当前状态和我们在未来工作中需求的一个机会。对于游戏开发者探求其工具的使用极限,学习未来游戏开发所必须改进的地方,游戏 Jam 或许是最好的时机。
|
||||
|
||||
开源工具使人们能够在不损害自由的情况下探索自己的创造力,而无需预先投入资金。虽然我们可能不会成为专业的游戏开发者,但我们仍然能够通过我们的简短的实验性游戏 [Mark My Words][5] 获得一点点体验。它是一个以语言学为主题的游戏,描绘了虚构的书写系统在其历史中的演变。还有很多其他不错的作品提交给了 Open Jam,它们都值得一试。 真的,[去看看][31]!
|
||||
|
||||
在本文结束前,我们想要感谢所有的 [参加俱乐部的成员][32],使得这次经历真正的有价值。我们也想要感谢 [Michael Clayton][33]、[Jared Sprague][34] 和 [Opensource.com][35] 主办 Open Jam。简直酷毙了。
|
||||
|
||||
现在,我们对读者提出了一些问题。你是一个 FOSS 游戏开发者吗?你选择的工具是什么?务必在下面留下一个评论!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/1/graphics-music-tools-game-dev
|
||||
|
||||
作者:[Charlie Murphy][a]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/rsg167
|
||||
[1]:http://mugeeks.org/
|
||||
[2]:https://itch.io/jam/open-jam-1
|
||||
[3]:https://opensource.com/article/17/8/open-jam-announcement
|
||||
[4]:https://opensource.com/article/17/11/open-jam
|
||||
[5]:https://mugeeksalpha.itch.io/mark-omy-words
|
||||
[6]:http://milkytracker.titandemo.org/
|
||||
[7]:https://en.wikipedia.org/wiki/Music_tracker
|
||||
[8]:https://creativecommons.org/
|
||||
[9]:https://freesound.org/
|
||||
[10]:http://ccmixter.org/view/media/home
|
||||
[11]:http://milkytracker.titandemo.org/documentation/
|
||||
[12]:https://github.com/milkytracker/MilkyTracker/wiki/MilkyTracker-Guide
|
||||
[13]:https://lmms.io/
|
||||
[14]:https://en.wikipedia.org/wiki/Chiptune
|
||||
[15]:https://github.com/grimfang4/sfxr
|
||||
[16]:https://lmms.io/wiki/index.php?title=BitInvader
|
||||
[17]:https://lmms.io/wiki/index.php?title=FreeBoy
|
||||
[18]:http://zynaddsubfx.sourceforge.net/
|
||||
[19]:http://www.mapeditor.org/
|
||||
[20]:https://www.piskelapp.com/
|
||||
[21]:https://github.com/piskelapp/piskel/blob/master/LICENSE
|
||||
[22]:https://raw.githubusercontent.com/MUGeeksandGadgets/MarkMyWords/master/tools/unpiskel.py
|
||||
[23]:https://www.python.org/
|
||||
[24]:https://www.sacredchao.net/~piman/angrydd/
|
||||
[25]:https://renpy.org/
|
||||
[26]:https://www.Pygame.org/
|
||||
[27]:http://Pygame.org/docs/tut/PygameIntro.html
|
||||
[28]:https://anthony-tuininga.github.io/cx_Freeze/
|
||||
[29]:https://Pygame.org/wiki/Pygame2exe
|
||||
[30]:http://www.py2exe.org/
|
||||
[31]:https://itch.io/jam/open-jam-1/entries
|
||||
[32]:https://github.com/MUGeeksandGadgets/MarkMyWords/blob/3e1e8aed12ebe13acccf0d87b06d4f3bd124b9db/README.md#credits
|
||||
[33]:https://twitter.com/mwcz
|
||||
[34]:https://twitter.com/caramelcode
|
||||
[35]:https://opensource.com/
|
@ -0,0 +1,114 @@
|
||||
迁移到 Linux:网络和系统设置
|
||||
======
|
||||
|
||||
> 这个系列我们提供了基础知识的概述,以帮助您成功地从另一个操作系统过渡到 Linux;这篇中我们涉及到 Linux 桌面系统上的一些常见设置。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/animals-birds-flock-55832.jpg?itok=NUGAyhDO)
|
||||
|
||||
在这个系列中,我们提供了基础知识的概述,以帮助您成功地从另一个操作系统过渡到 Linux。如果你错过了以前的文章,可以从这访问:
|
||||
|
||||
- [第1部分 - 入门介绍][1]
|
||||
- [第2部分 - 磁盘、文件和文件系统][2]
|
||||
- [第3部分 - 图形操作环境][3]
|
||||
- [第4部分 - 命令行][4]
|
||||
- [第5部分 - 使用 sudo][5]
|
||||
- [第5部分 - 安装软件][6]
|
||||
|
||||
Linux 提供了一系列网络和系统设置。在你的桌面计算机上,Linux 允许您调整系统上的任何内容。大多数这些设置都出现在 `/etc` 目录下的纯文本文件中。这里我将介绍你使用桌面 Linux 操作系统的过程中最常用的设置。
|
||||
|
||||
大多数设置都能够在“设置”程序里面找到,这些设置可能对于不同的 Linux 发行版有所不同。通常来说,你可以修改背景、调整音量、连接打印机、进行显示设置等。对于这些设置尽管我不会全部谈论,但你可以自己探索。
|
||||
|
||||
### 连接互联网
|
||||
|
||||
在 Linux 中连接到互联网通常非常简单。如果您通过以太网电缆连接,Linux 通常会在插入电缆时或启动时(如果电缆已连接)获得 IP 地址并自动连接。
|
||||
|
||||
如果您使用无线网络,则在大多数发行版中都有一个菜单,可以在指示器面板中或在“设置”中(取决于您的发行版),您可以在其中选择无线网络的 SSID。如果网络受密码保护,它通常会提示您输入密码。然后连接,这个过程相当顺利。
|
||||
|
||||
在图形界面您可以通过进入设置来调整网络设置。通常称为“系统设置”或者是“设置”。通常可以轻松找到设置程序,因为它的图标是齿轮或工具图片(图1)。
|
||||
|
||||
![Network Settings][8]
|
||||
|
||||
*图1: Gnome 桌面网络设置指示器图标。*
|
||||
|
||||
### 网络接口名称
|
||||
|
||||
在 Linux 下,网络设备有名称。 从历史上看,它们的名称分别为 eth0 和 wlan0 —— 或“以太网”和“无线网络”。 较新的 Linux 系统一直使用看起来更深奥的不同名称,如 enp4s0 和 wlp5s0 。 如果名称以 en 开头,则它是有线以太网接口。 如果它以 wl 开头,那么它就是一个无线接口。 其余的字母和数字反映了设备如何连接到硬件。
|
||||
|
||||
### 通过命令行进行网络管理
|
||||
|
||||
如果您希望更好地控制网络设置,或者如果您在没有图形桌面的情况下管理网络连接,则还可以从命令行管理网络。
|
||||
|
||||
请注意,用于在图形桌面中管理网络的最常用服务是“<ruby>网络管理器<rt>Network Manager</rt></ruby>”,而网络管理器通常会覆盖在命令行上进行的设置更改。如果您正在使用网络管理器,最好在其界面中更改您的设置,以防止撤消您从命令行或其他位置所做的更改。
|
||||
|
||||
在图形环境中的更改设置与在网络管理器中很类似,您还可以使用名为 `nmtui` 的工具从命令行更改网络管理器设置。`nmtui` 工具提供了您在图形环境中找到的所有设置,但是是在基于文本的半图形界面中提供了该设置,该界面可在命令行上运行(图 2)。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/figure-2_0.png?itok=1QVjDdbJ)
|
||||
|
||||
*图 2:nmtui 界面*
|
||||
|
||||
在命令行上,有一个名为 `ifconfig` 的旧工具来管理网络,还有一个名为 `ip` 的新工具。在某些发行版中,`ifconfig` 被认为是不推荐使用的,默认情况下甚至没有安装。在其他发行版上,`ifconfig` 仍可以使用。
|
||||
|
||||
以下是一些允许您显示和更改网络设置的命令:
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/screen_shot_2018-04-17_at_3.11.48_pm.png?itok=EZsjb-GQ)
|
||||
|
||||
### 进程和系统信息
|
||||
|
||||
在 Windows 系统中,你可以使用任务管理器来查看所有正在运行的程序和服务的列表。你可以停止运行中的程序,并且可以在其中显示的某些选项卡中查看系统性能。
|
||||
|
||||
在 Linux 系统下你可以使用命令行或者图形界面中做同样的事情。Linux 系统中根据你的发行版本会有不同的几个可用的图形工具。大多数所共有的工具是“系统监视器”和 KSysGuard。在这些工具中,你可以查看系统性能,查看进程列表甚至是杀死进程(图 3)。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/figure-3_2.png?itok=ePeXj9PA)
|
||||
|
||||
*图 3:NetHogs 截图*
|
||||
|
||||
在这些工具中,你也可以查看系统全局网络流量(图 4)。
|
||||
|
||||
![System Monitor][11]
|
||||
|
||||
*图 4:Gnome System Monitor 的截图*
|
||||
|
||||
### 管理进程和系统使用
|
||||
|
||||
您还可以从命令行使用相当多的工具。使用 `ps` 命令可以查看系统中的进程列表。默认情况下,这个命令的结果是显示当前终端会话下的所有进程列表。但是你也可以通过使用各种命令行参数显示其他进程。如果 `ps` 命令不会使用,可以使用命令 `info ps` 或者 `man ps` 获取帮助。
|
||||
|
||||
大多数人都希望得到一个进程列表,因为他们想要停止占用过多内存或 CPU 时间的进程。这种情况下有两个非常简单的命令,分别是 `top` 和 `htop` 命令(图 5)。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/figure-5_0.png?itok=2nm5EmAl)
|
||||
|
||||
*图 5:top 截屏*
|
||||
|
||||
`top` 和 `htop` 工具使用效果非常相似。两个命令每秒或者两秒会更新重新排序,这样会把占用 CPU 资源最多的放置在列表顶部。你也可以根据其他资源的使用情况比如内存使用情况来排序。
|
||||
|
||||
使用这两个命令时(`top` 和 `htop`),你可以输入 `?` 来获取使用帮助,输入 `q` 来退出程序。使用 `top` 命令你可以按 `k` 键然后输入进程 ID 来杀死某个进程。
|
||||
|
||||
使用 `htop` 命令时你可以使用 `↑` `↓` 键来将列表中的一条记录进行高亮显示,按下 `F9` 键会杀死进程(需要回车确认)。
|
||||
|
||||
本系列中提供的信息和工具将帮助您开始使用 Linux。 只需一点时间和耐心,您就会感到这非常舒服。
|
||||
|
||||
想学习更多 Linux 内容可访问免费的 [Linux 简介][12]课程,此课程来自 Linux 基金会和 edx。
|
||||
|
||||
------
|
||||
|
||||
via: https://www.linux.com/blog/learn/2018/4/migrating-linux-network-and-system-settings
|
||||
|
||||
作者:[John Bonesio][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[ScarboroughCoral](https://github.com/ScarboroughCoral)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linux.com/users/johnbonesio
|
||||
[1]: https://linux.cn/article-9212-1.html
|
||||
[2]: https://linux.cn/article-9213-1.html
|
||||
[3]: https://linux.cn/article-9293-1.html
|
||||
[4]: https://linux.cn/article-9565-1.html
|
||||
[5]: https://linux.cn/article-9819-1.html
|
||||
[6]: https://linux.cn/article-9823-1.html
|
||||
[7]: https://www.linux.com/files/images/figure-1png-2
|
||||
[8]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/figure-1_2.png?itok=J-C6q-t5 "Network Settings"
|
||||
[9]: https://www.linux.com/licenses/category/used-permission
|
||||
[10]: https://www.linux.com/files/images/figure-4png-1
|
||||
[11]: https://www.linux.com/sites/lcom/files/styles/rendered_file/public/figure-4_1.png?itok=boI-L1mF "System Monitor"
|
||||
[12]: https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
@ -1,21 +1,22 @@
|
||||
糖尿病患者们是怎样使用开源造出自己的医疗设备的
|
||||
======
|
||||
> Red Hat 的 2018 女性开源社区奖获得者 Dana Lewis 的故事。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/health_heartbeat.png?itok=P-GXea-p)
|
||||
|
||||
Dana Lewis 被评选为开源社区 2018 年度最佳女性!下面是开源怎样改善了她的健康的故事。
|
||||
Dana Lewis 被评选为[开源社区 2018 年度最佳女性][1]!下面是开源怎样改善了她的健康的故事。
|
||||
|
||||
Dana 患有1型糖尿病,但当时市面上流通的药品和医疗设备都对她无效。
|
||||
她用来管理血糖的动态血糖监测报警器的声音太小了,根本叫不醒熟睡的她,产品这样的设计无法保证她每天睡眠时间的生命安全。
|
||||
Dana 患有 I 型糖尿病,但当时市面上流通的药品和医疗设备都对她无效。她用来管理血糖的动态血糖监测(CGM)报警器的声音太小了,根本叫不醒熟睡的她,产品这样的设计无法保证她每天睡眠时间的生命安全。
|
||||
|
||||
“我和生产厂家见了一面商议提出意见,厂家的回复是‘我们产品的音量已经足够大了,很少有人叫不醒’,我被告知‘这不是普遍问题,我们正在改进,请期待我们的新产品。’听到这些时我真的很挫败,但我从没想象过我能做出什么改变,毕竟那是通过了 FDA 标准的医疗设备,不是我们能随意改变的。”
|
||||
|
||||
面临着这些阻碍,Dana 想着如果她能把自己的数据从设备里导出,就可以设置手机闹铃来叫醒自己。在2013年末,她看到的一条推特解决了她的疑问。那条推特的作者是一位糖尿病患儿的家长,他把动态血糖监测仪进行了逆向工程,这样就可以导出孩子的血糖数据进行远程监控了。
|
||||
面临着这些阻碍,Dana 想着如果她能把自己的数据从设备里导出,就可以设置手机闹铃来叫醒自己。在 2013 年末,她看到的一条推特解决了她的疑问。那条推特的作者是一位糖尿病患儿的家长,他把动态血糖监测仪进行了逆向工程,这样就可以导出孩子的血糖数据进行远程监控了。
|
||||
|
||||
她意识到如果对方愿意把过程分享给她,她也可以用那些代码做一个自己的响亮的血糖监测仪了。
|
||||
|
||||
“我并不知道向别人要源代码是件稀松平常的事,那是我第一次接触开源。”
|
||||
|
||||
那个系统演化成一个响亮闹钟的代码,她也可以把代码在网页上分享给别人。和她的丈夫 Scott Leibrand 一起,她反复向闹铃添加属性,最终合成了一个算法,这个算法不仅能监测实时血糖水平,还能主动预测未来血糖波动。
|
||||
那个系统演化成一个响亮闹钟的代码,她也可以把代码在网页上分享给别人。和她的丈夫 Scott Leibrand 一起,她逐步向闹铃添加属性,最终形成了一个算法,这个算法不仅能监测实时血糖水平,还能主动预测未来血糖波动。
|
||||
|
||||
随着 Dana 与开源糖尿病患者社区的接触越来越深,她认识了 Ben West,他花了很多年才研究出与 Dana 使用的胰岛素泵沟通数据的方法,与血糖监测仪不同,胰岛素泵不是简单的报告血糖,它是个单独的设备,要按人体需要持续推注胰岛素,比血糖监测仪要复杂得多。
|
||||
|
||||
@ -27,15 +28,15 @@ Dana 患有1型糖尿病,但当时市面上流通的药品和医疗设备都
|
||||
|
||||
“正因为我们使用的是开源软件,在做出这个系统之后我们就把成果开源化了,这样可以造福更多的人。”开源人工胰腺系统 (OpenAPS) 由此诞生。
|
||||
|
||||
OpenAPS 社区已经拥有超过600名用户,大家都提供了各种各样的自制“闭路”系统代码。OpenAPS 贡献者们以 #WeAreNotWaiting 话题团结一致,以表达患者群体不该干等着医疗保健工厂制造出真正有效便捷产品的理念。
|
||||
OpenAPS 社区已经拥有超过 600 名用户,大家都提供了各种各样的自制“闭路”系统代码。OpenAPS 贡献者们聚集到了 #WeAreNotWaiting 话题之下,以表达患者群体不该干等着医疗保健工厂制造出真正有效便捷产品的理念。
|
||||
|
||||
“你可以选择等待未来的商业解决方案,这无可厚非,选择等待是你的自由。等待可以是一种选择,但不能是无法改变的现状。对我来说,开源在医疗保健方面做出的这个举动让等待变成了一种选择。你可以选择不自行解决,你可以选择等待商业解决方案,但如果你不想等了,你无需再等。现在你有很多选择,开源社区的人们已经解决了很多问题。”
|
||||
|
||||
OpenAPS 社区由糖尿病患者,患者家属,还有想要合理利用这项技术的人们。在社区的帮助下,Dana 学会了很多种贡献开源项目的方式。她发现许多从 Facebook 或 [Gitter][2] 上过来的非技术贡献者也对 OpenAPS 做出了很大贡献。
|
||||
OpenAPS 社区由糖尿病患者、患者家属,还有想要合理利用这项技术的人们。在社区的帮助下,Dana 学会了很多种贡献开源项目的方式。她发现许多从 Facebook 或 [Gitter][2] 上过来的非技术贡献者也对 OpenAPS 做出了很大贡献。
|
||||
|
||||
“贡献有很多方式,我们要认识到各种方式的贡献都是平等的。它们一般涉及不同的兴趣领域和技能组合,只有把这些综合起来,才能做成社区的项目。”
|
||||
|
||||
她亲身经历过,所以知道自己的贡献不被社区的其他成员认可是怎样难过的感受。对于人们习惯把女性的贡献打折的这一现象,她也不回避。在她的 [2014 年博客][3] 和 [反思][4] 文章中她初次写道在入围开源年度最佳人物时所遭受到的区别待遇,这些待遇让她意识到身为女性的不同。
|
||||
她亲身经历过,所以知道自己的贡献不被社区的其他成员认可是怎样难过的感受。对于人们习惯把女性的贡献打折的这一现象,她也不回避。在她的 [2014 年博客][3] 和 [反思][4] 文章中她初次写到在入围开源年度最佳人物时所遭受到的区别待遇,这些待遇让她意识到身为女性的不同。
|
||||
|
||||
在她最初的博客中,她写道了自己和丈夫 Scott 同为开源社区成员,遭受到的区别待遇。他们都注意到,Dana 总是被提出一些细枝末节的要求,但 Scott 就不会。而 Scott 总被问道一些技术性问题,即使他向他们推荐 Dana,人们也更倾向于问身为男性的 Scott。大家都或多或少经历过这些行为,Dana 的博文在社区里引起了广泛的讨论。
|
||||
|
||||
@ -45,13 +46,13 @@ OpenAPS 社区由糖尿病患者,患者家属,还有想要合理利用这项
|
||||
|
||||
“我想如果我就放弃努力了,可能开源世界里糖尿病患者们的现状会有很大不同。我知道别人不幸的遭遇,他们在开源社区中感受不到认同感和自身价值,最终离开了开源。我希望我们可以继续这种讨论,大家都能意识到如果我们不故意打击贡献者,我们可以变得更加温暖,成员们也能感受到认同感,大家的付出也能得到相应的认可。
|
||||
|
||||
OpenAPS 社区的交流和分享给我们提供了一个很好的例子,它说明非技术性的贡献者对于整个社区的成功都是至关重要的。Dana 在现实社会中的关系和交流经历对她为开源社区做出的宣传有着很大的贡献。她为社区在 [DIYPS blog][5] 上写了很多篇文章,她还在 [TEDx Talk][6] 做过一场演讲, 在 [开源大会 (OSCON)][7] 上也演讲过很多次,诸如此类的还有很多。
|
||||
OpenAPS 社区的交流和分享给我们提供了一个很好的例子,它说明非技术性的贡献者对于整个社区的成功都是至关重要的。Dana 在现实社会中的关系和交流经历对她为开源社区做出的宣传有着很大的贡献。她为社区在 [DIYPS 博客][5] 上写了很多篇文章,她还在 [TEDx Talk][6] 做过一场演讲, 在 [开源大会 (OSCON)][7] 上也演讲过很多次,诸如此类的还有很多。
|
||||
|
||||
“不是每个项目都像 OpenAPS 一样,对患者有那么大的影响,甚至成为患者中间的主流项目。糖尿病社区在项目的沟通中真的做了很多贡献,引来了很多糖尿病患者,也让需要帮助的人们知道了我们的存在。”
|
||||
|
||||
Dana 现在的目标是帮助其他疾病的患者社区创建项目。她尤其想要把社区成员们学到的工具和技术和其他的患者社区分享,特别是那些想要把项目进一步提升,进行深入研究,或者想和公司合作的社区。
|
||||
|
||||
“听说很多参与项目的患者都听过这样的话,‘你应该申请个专利;你应该拿它开个公司;你应该成立个非营利组织。’但这些都是大事,它们太耗时间了,不仅占据你的工作时间,甚至强行改变你的专业领域。我这样的人并不想做那样的事,我们更倾向于把精力放在壮大其他项目上,以此帮助更多的人。”
|
||||
“我听说很多参与项目的患者都听过这样的话,‘你应该申请个专利;你应该拿它开个公司;你应该成立个非营利组织。’但这些都是大事,它们太耗时间了,不仅占据你的工作时间,甚至强行改变你的专业领域。我这样的人并不想做那样的事,我们更倾向于把精力放在壮大其他项目上,以此帮助更多的人。”
|
||||
|
||||
在此之后,她开始寻找其他不那么占用时间的任务,比如给小孩们写一本书。Dana 在 2017 年进行了这项挑战,她写了本书给侄子侄女,讲解他们婶婶的糖尿病设备是怎样工作的。在她侄女问她“胳膊上的东西是什么”(那是她的血糖监测仪)时,她意识到她不知道怎么和一个小孩子解释糖尿病患者是什么,所以写了[《卡罗琳的机器人亲戚》][8]这本书。
|
||||
|
||||
@ -70,7 +71,7 @@ via: https://opensource.com/article/18/5/dana-lewis-women-open-source-community-
|
||||
作者:[Taylor Greene][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[Valoniakim](https://github.com/Valoniakim)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
77
published/201812/20180623 The IBM 029 Card Punch.md
Normal file
77
published/201812/20180623 The IBM 029 Card Punch.md
Normal file
@ -0,0 +1,77 @@
|
||||
IBM 029 型打孔机
|
||||
======
|
||||
|
||||
我知道这很学院派,可一行超过 80 个字符的代码还是让我抓狂。我也在网上见过不少人认为即使在现代的视网膜屏幕下也应当采用行长度为 80 个字符的标准,可他们都不理解我对破坏这一标准的怒火,就算多 1 个字符也不行。
|
||||
|
||||
在这一标准的黄金时期,一行代码的长度几乎不会超过 80 个字符的限制。在那时,这一限制是物理的,没有第 81 列用于存放第 81 个字符。每一个试图把函数名起的又长又臭的程序员都会在短暂的愉悦后迎来更多的麻烦,而这仅仅是因为没有足够的空间放下整个函数的声明。
|
||||
|
||||
这一黄金时期也是<ruby>打孔卡<rt>punch card</rt></ruby>编程时期。在 20 世纪 60 年代,IBM 打孔卡设立了标准,这个标准就是打孔卡的宽度为 80 列。这个 80 列标准在后来的电传打字机和哑终端时期得以延续,并逐渐成为操作系统中隐藏的细节。时至今日,即使我们用上了更大、更好的屏幕,偏向于使用更长的标识符而不是类似 `iswcntrl()` 这样令人难以猜测的函数名,可当你打开新的终端模拟器窗口时,默认的宽度依然是 80 个字符。
|
||||
|
||||
从 Quora 上的很多问题中可以发现,很多人并不能想象如何使用打孔卡给计算机编程。我承认,在很长的一段时间里我也不能理解打孔卡编程是如何工作的,因为这让我想到就像劳工一样不停的给这些打孔卡打孔。当然,这是一个误解,程序员不需要亲自给打孔卡打孔,就像是火车调度员不用亲自扳道岔。程序员们有<ruby>打孔机<rt>card punch machines</rt></ruby>(也被称为<ruby>键控打孔机<rt>key punches</rt></ruby>),这让他们可以使用打字机式的键盘给打孔卡打孔。这样的设备在 19 世纪 90 年代时就已经不是什么新技术了。
|
||||
|
||||
那时,最为广泛使用的打孔机之一便是 IBM 029 型打孔机。就算在今天,它也许是最棒的打孔机。
|
||||
|
||||
![][1]
|
||||
|
||||
IBM 029 型打孔机在 1964 年作为 IBM 的 System/360 大型电脑的配件发售的。System/360 是计算系统与外设所组成的一个系列,在 20 世纪 60 年代晚期,它几乎垄断了整个大型计算机市场。就像其它 System/360 外设一样,029 型打孔机也是个大块头。那时,计算机和家具的界限还很模糊,但 029 型打孔机可不是那种会占领你的整张桌子的机器。它改进自 026 型打孔机,增加了新的字符支持,如括号,总体上也更加安静。与前辈 026 型所展出 20 世纪 40 年代的圆形按钮与工业化的样貌相比,029 型的按键方正扁平、功能按键还有酷炫的蓝色高亮提示。它的另一个重要买点是它能够在<ruby>数字区<rt>numeric field</rt></ruby>左侧自动的填充 0 ,这证明了 JavaScript 程序员不是第一批懒得自己做<ruby>左填充<rt>left-padding</rt></ruby>的程序员。(LCTT 译注:这项功能需要额外的 4 张 <ruby>[标准模块系统卡](https://en.wikipedia.org/wiki/IBM_Standard_Modular_System)<rt>SMS card</rt></ruby>才能使用。例如设置数字区域长度为 6 列时,操作员只需要输入 73 ,打孔机会自动填充起始位置上的 4 个 0 ,故最终输出 000073。[更多信息](https://en.wikipedia.org/wiki/Keypunch#IBM_029_Card_Punch))
|
||||
|
||||
等等!你说的是 IBM 在 1964 年发布了全新的打孔机?你知道那张在贝尔实验室拍摄的 Unix 之父正在使用电传打字机的照片吗?那是哪一年的来着?1970?打孔机不是应该在 20 世纪 60 年代中期到晚期时就过时了吗?是的,你也许会奇怪,为什么直到 1984 年,IBM 的产品目录中还会出现 029 型打孔机的身影 [^1]。事实上,直到 20 世纪 70 年代,大多数程序员仍然在使用打孔卡编程。其实二战期间就已经有人在用电传打字机了,可那时并没能普及。客观的讲,电传打字机几乎和打孔卡一样古老。也许和你想象的恰恰相反,并不是电传打字机本身限制了它的普及,而是计算时间。人们拒绝使用电传打字机的原因是,它是可交互的,它和计算机使用<ruby>“在线”的传输方式<rt>"online" mode of communication</rt></ruby>。在以 Unix 为代表的分时操作系统被发明前,你和电脑的交互会被任何人的使用而打断,而这一点延迟通常意味着几千美元的损失。所以程序员们普遍选择离线地使用打孔机编程,再将打孔卡放入大型计算机中,作为<ruby>批任务<rt>batch job</rt></ruby>执行。在那时,还没有即廉价又可靠的存储设备,可打孔卡的廉价优势已经足够让它成为那时最流行的数据存储方式了。那时的程序是书架上一摞打孔卡而不是硬盘里的一堆文件。
|
||||
|
||||
那么实际使用 IBM 029 型打孔机是个什么样子呢?这很难向没有实际看过打孔卡的人解释。一张打孔卡通常有 12 行 80 列。打孔卡下面是从 1 到 9 的<ruby>数字行<rt>digit rows</rt></ruby>,打孔卡上的每一列都有这些行所对应的数字。最上面的三行是<ruby>空间行<rt>"zone" rows</rt></ruby>,通常由两行空白行和一行 0 行组成。第 12 行是打孔卡最顶部的行,接下来是 11 行,随后是从数字 0 到 9 所在的行。这个有点让人感到困惑的顺序的原因是打孔卡的上边缘被称为<ruby>12 边<rt>12 edge</rt></ruby>、下边缘被称为 <ruby>9 边<rt>9 edge</rt></ruby>。那时,为了让打孔卡便于整理,常常会剪去打孔卡的一个角。
|
||||
|
||||
![][2]
|
||||
|
||||
(LCTT 译注:可参考[EBCDIC 编码](https://zh.wikipedia.org/wiki/EBCDIC))
|
||||
|
||||
在打孔卡发明之初,孔洞的形状是圆形的,但是 IBM 最终意识到如果使用窄长方形作为孔洞,一张卡就可以放下更多的列了。每一列中孔洞的不同组合就可以表达不同的字符。像 029 型这样的拥有人性化设计的打孔机除了完成本质的打孔任务外,还会在打孔卡最上方打印出每一列所对应的字符。输入是数字就在对应的数字行上打孔。输入的是字母或符号就用一个在空间列的孔和一或俩个在数字列的孔的组合表示,例如字母 A 就用一个在第 12 空间行的空和一个数字 1 所在行的孔表示。这是一种顺序编码,在第一台打孔机被发明后,也叫 Hollerith 编码。这种编码只能表示相对较小的一套字符集,小写字母就没有包含在这套字符集中。如今一些聪明的工程师可能想知道为什么打卡不干脆使用二进制编码 —— 毕竟,有 12 行,你可以编码超过 4000 个字符。 使用 Hollerith 编码是因为它确保在单个列中出现不超过三个孔。这保留了卡的结构强度。二进制编码会带来太多的孔,会因为孔洞过于密集而断裂。
|
||||
|
||||
打孔卡也有不同。在 20 世纪 60 年代,80 列虽然是标准,但表达的方式不一定相同。基础打孔卡是无标注的,但用于 COBOL 编程的打孔卡会把最后的 8 列保留,供标识数保存使用。这一标识数可以在打孔卡被打乱 (例如一叠打孔卡掉在地上了) 后用于自动排序。此外,第 7 列被用于表示本张打孔卡上的是否与上一张打孔卡一起构成一条语句。也就是说当你真的对 80 字符的限制感到绝望的时候,还可以用两张卡甚至更多的卡拼接成一条长语句。用于 FORTRAN 编程的打孔卡和 COBOL 打孔卡类似,但是定义的列不同。大学里使用的打孔卡通常会由其计算机中心加上水印,其它的设计则会在如 [1976 年美国独立 200 周年][3] 的特殊场合才会加入。
|
||||
|
||||
最终,这些打孔卡都要被计算机读取和计算。IBM 出售的 System/360 大型计算机的外设 IBM 2540 可以以每分钟 1000 张打孔卡的速度读取这些卡片[^2] 。IBM 2540 使用电刷扫过每张打孔卡,电刷通过孔洞就可以接触到卡片后面的金属板完成一次读取。一旦读取完毕,System/360 大型计算机就会把每张打孔卡上的数据使用一种定长的 8 位编码保存,这种编码是<ruby>扩增二进式十进交换码<rt>Extended Binary Coded Decimal Interchange Code</rt></ruby>,简写为 EBCDIC 编码。它是一种二进制编码,可以追溯自早期打孔卡所使用的 BCDIDC 编码 —— 其 6 位编码使用低 4 位表示数字行,高 2 位表示空间行。程序员们在打孔卡上编写完程序后,会把卡片们交给计算机操作员,操作员们会把这些卡片放入 IBM 2540 ,再把打印结果交给程序员。那时的程序员大多都没有见过计算机长什么样。
|
||||
|
||||
程序员们真正能见到的是很多打孔机。029 型打孔机虽然不是计算机,但这并不意味着它不是一台复杂的机器。看看这个由<ruby>密歇根大学<rt>University of Michigan</rt></ruby>计算机中心在 1967 年制作的[教学视频][4],你就能更好的理解使用一台 029 型打孔机是什么情形了。我会尽可能在这里总结这段视频,但如果你不去亲自看看的话,你会错过许多惊奇和感叹。
|
||||
|
||||
029 型打孔机的结构围绕着一个打孔卡穿过机器的 U 形轨道开始。使用打孔机时,右手边也就是 U 形轨道的右侧顶部是<ruby>进卡卡槽<rt>hopper</rt></ruby>,使用前通常在里面放入一叠未使用的打孔卡。虽然 029 型打孔机主要使用 80 列打孔卡,但在需要的情况下也可以使用更小号的打孔卡。在打孔机的使用过程中,打孔卡离开轨道右上端的进卡卡槽,顺着 U 形轨道移动并最终进入左上端的<ruby>出卡卡槽<rt>stacker</rt></ruby>。这一流程可以保证出卡卡槽中的打孔卡按打孔时的先后顺序排列。
|
||||
|
||||
029 型打孔机的开关在桌面下膝盖高度的位置。在开机后,连按两次 “<ruby>装入<rt>FEED</rt></ruby>” 键让机器自动将打孔卡从进卡卡槽中取出并移动到机器内。 U 形轨道的底部是打孔机的核心区域,它由三个部分组成:右侧是等待区,中间是打孔操作区,左侧是阅读区。连按两次 “装入” 键,机器就会把一张打孔卡装入打孔机的打孔操作区,另一张打孔卡进入等待区。在打孔操作区上方有一个列数指示器来显示当前打孔所在的列的位置。这时,每按下一个按键,机器就会在打孔卡对应的位置打孔并在卡片的顶部打印按键对应的字符,随后将打孔卡向左移动一列。如果一张卡片的 80 列全部被打上了数据,这张卡片会被打孔操作区自动释放并进入阅读区,同时,一张新的打孔卡会被装入打孔操作区。如果没有打完全部的 80 列,可以使用 “<ruby>释放<rt>REL</rt></ruby>” 键完成上面的操作。
|
||||
|
||||
在打孔卡上打印对应的字符这一设计让人很容易分辨出错误。但就像密歇根大学的视频中警告的那样,打孔卡上修正一个错误可不像擦掉一个打印的字符然后再写上一个新的那样容易,因为计算机只会根据卡片上的孔来读取信息。因为被打出的孔不能被<ruby>复原<rt>unpunched</rt></ruby>,所以并不能直接退回一列然后再打上一个新的字符。打出更多的孔也只能让这一列的组合变成一个无效字符。IBM 029 型打孔机上虽然有一个可以让打孔卡回退一列的退格按键,但这个按键被放置在机器上而非在键盘上。这样的设计也许是为了阻止这个按键的使用,因为实际上很少有用户需要这个功能。
|
||||
|
||||
实际上,只有废弃错误的打孔卡再在新的打孔卡上重新打孔这一种修正错误的方式。这就是阅读区的用武之处了。当你发现打孔卡上的第 68 列出错时,你需要在新的打孔卡上小心的给前 67 列重新打孔,然后给第 68 列打上正确的字母。另一种操作方式是把带有错误信息的打孔卡放在阅读区,同时在打孔操作区载入一张新的打孔卡,然后按下 “<ruby>重复<rt>DUP</rt></ruby>” 按键直到列数指示器显示 68 列。这时按下正确的字符来修正错误。阅读区和重复按键使得 029 型打孔机很容易复制打孔卡上的内容。当然,这一功能的使用可能有各种各样的原因,但改错是最常见的。
|
||||
|
||||
(LCTT 译注:有一种说法是“补丁”这个用于对已经发布的软件进行修复的术语来源于对打孔纸带或打孔卡上打错的孔贴上补丁的做法。可能对于长长的一卷打孔纸带来说,由于个别字母的错误而整个废弃成本过高,会采用“补丁”的方式;而对于这种单张式的打孔卡来说,重新打印一张正确的更为方便。)
|
||||
|
||||
“重复”按键允许 029 型打孔机的操作员手动调用重复的函数。但是 029 型打孔机还可以设置为自动重复。当用于记录数据而不是编程时,这项功能十分有效。举个例子,当用打孔卡来记录大学生的信息时,每张卡片上都需要输入学生的宿舍楼的名字,如果发现所输入信息的学生都在同一栋楼,就可以使用 029 型打孔机的自动重复功能来完成宿舍楼名称的填写。
|
||||
|
||||
像这样的自动化操作可以通过<ruby>程序鼓<rt>program drum</rt></ruby>编程到 029 型打孔机里面。程序鼓就安装在打孔操作区上方的 U 形轨道中间部分的右上角。通过在打孔卡上写下程序,然后把打孔卡装入程序鼓中,就完成了一次给 029 型打孔机的编程任务。用户可以通过这种方式对打孔卡的每一列都按需要定义不同的自动化操作。029 型打孔机允许指定某些列重复上一张打孔卡相同位置的字符,这就是它能更快的输入学生信息的理由。它还允许指定某些列只能输入数字或者字母,指定特定的列为空或者到某一列时就直接跳过一整张打孔卡。编程鼓使它在打孔特定列有特殊含义的固定模式卡片时很容易。密歇根大学制作的另一个[进阶教学视频][5]包括了给 029 型打孔机编程的过程,如果你已经掌握了它的基础操作,就快去看看吧。
|
||||
|
||||
这会儿,无论你是否看了密歇根大学制作的视频,都会感叹打孔机的操作之简便。虽然修正错误的过程很乏味,但除此之外,操作一台打孔机并不像想象的那样复杂。我甚至可以想象打孔卡之间的无缝切换让 COBOL 和 FORTRAN 程序员忘记了他们的程序是打在不同的打孔卡上而不是写在一个连续的文本文件内。另一方面,思考一下打孔机是如何影响编程语言的发展也是很有趣的,虽然它仅仅是一台输入设备。结构化编程最终会出现并鼓励程序员把整个代码块视为一个整体,但可以想象打孔卡程序员们强调每一行的作用且难以认同结构化编程的场景。同时你能够理解他们为什么不把代码块闭合所使用的括号放在单独的一行,只是因为这样会浪费打孔卡。
|
||||
|
||||
现在,虽然没有人再使用打孔卡编程了,每个程序员都该试试[这个][6],哪怕一次也好。或许你因此能够更好的理解 COBOL 和 FORTRAN 的历史,或许你就能体会到为什么每个人把 80 个字符作为长度限制的标注。
|
||||
|
||||
喜欢吗?这里每两周都会发表一篇这样的文章。请在推特上关注我们 [@TwoBitHistory][7] 或者订阅我们的 [RSS][8],这样你就能在第一时间收到新文章的通知。
|
||||
|
||||
[^1]: “IBM 29 Card Punch,” IBM Archives, accessed June 23, 2018, https://www-03.ibm.com/ibm/history/exhibits/vintage/vintage_4506VV4002.html.
|
||||
[^2]: IBM, IBM 2540 Component Description and Operation Procedures (Rochester, MN: IBM Product Publications, 1965), September 06, 2009, accessed June 23, 2018, http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/25xx/A21-9033-1_2540_Card_Punch_Component_Description_1965.pdf.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://twobithistory.org/2018/06/23/ibm-029-card-punch.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/ibm029_front.jpg
|
||||
[2]: https://twobithistory.org/images/card.png
|
||||
[3]: http://www.jkmscott.net/data/Punched%20card%20013.jpg
|
||||
[4]: https://www.youtube.com/watch?v=kaQmAybWn-w
|
||||
[5]: https://www.youtube.com/watch?v=SWD1PwNxpoU
|
||||
[6]: http://www.masswerk.at/keypunch/
|
||||
[7]: https://twitter.com/TwoBitHistory
|
||||
[8]: https://twobithistory.org/feed.xml
|
@ -1,51 +1,58 @@
|
||||
用户,组和其他 Linux 用户
|
||||
用户、组及其它 Linux 特性
|
||||
======
|
||||
|
||||
> Linux 和其他类 Unix 操作系统依赖于用户组,而不是逐个为用户分配权限和特权。一个组就是你想象的那样:一群在某种程度上相关的用户。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/flamingo-2458782_1920.jpg?itok=_gkzGGx5)
|
||||
|
||||
到这个阶段,[在看到如何操作目录或文件夹之后][1],但在让自己一头扎进文件之前,我们必须重新审视 _权限_, _users_ 和 _group_。幸运的是,[有一个网站上已经有了一个优秀而全面的教程,包括了权限][2],所以你应该去立刻阅读它。简而言之,你使用权限来确定谁可以对文件和目录执行操作,以及他们可以对每个文件和目录执行什么操作 -- 从中读取,写入,擦除等等。
|
||||
到这个阶段,[在看到如何操作目录或文件夹之后][1],但在让自己一头扎进文件之前,我们必须重新审视 _权限_、_用户_ 和 _组_。幸运的是,[有一个网站上已经有了一个优秀而全面的教程,讲到了权限][2],所以你应该去立刻阅读它。简而言之,你使用权限来确定谁可以对文件和目录执行操作,以及他们可以对每个文件和目录执行什么操作 —— 从中读取、写入、移动、擦除等等。
|
||||
|
||||
要尝试本教程涵盖的所有内容,你需要在系统上创建新用户。让我们实践起来,为每一个需要借用你电脑的人创建一个用户,我们称之为 _guest 账户_。
|
||||
要尝试本教程涵盖的所有内容,你需要在系统上创建新用户。让我们实践起来,为每一个需要借用你电脑的人创建一个用户,我们称之为 `guest` 账户。
|
||||
|
||||
**警告:** _例如,如果你错误地删除了自己的用户和目录,那么创建,特别是删除用户以及主目录会严重损坏系统。你可能不想在你日常的工作机中练习,那么请在另一台机器或者虚拟机上练习。无论你是否想要安全地练习,经常备份你的东西总是一个好主意。检查备份是否正常工作,为你自己以后避免很多咬牙切齿的事情。_
|
||||
**警告:** 例如,如果你错误地删除了自己的用户和目录,那么创建用户,特别是删除用户以及主目录会严重损坏系统。你可能不想在你日常的工作机中练习,那么请在另一台机器或者虚拟机上练习。无论你是否想要安全地练习,经常备份你的东西总是一个好主意。检查备份是否正常工作,为你自己以后避免很多咬牙切齿的事情。
|
||||
|
||||
### 一个新用户
|
||||
|
||||
你可以使用 `useradd` 命令来创建一个新用户。使用超级用户或 root 权限运行 `useradd`,即使用 `sudo` 或 `su`,这具体取决于你的系统,你可以:
|
||||
|
||||
```
|
||||
sudo useradd -m guest
|
||||
```
|
||||
|
||||
然后输入你的密码。或者也可以这样:
|
||||
|
||||
```
|
||||
su -c "useradd -m guest"
|
||||
```
|
||||
|
||||
然后输入 root 或超级用户的密码。
|
||||
|
||||
(_为了简洁起见,我们将从现在开始假设你使用 `sudo` 获得超级用户或 root 权限。_)
|
||||
( _为了简洁起见,我们将从现在开始假设你使用 `sudo` 获得超级用户或 root 权限。_ )
|
||||
|
||||
通过使用 `-m` 参数,`useradd` 将为新用户创建一个主目录。你可以通过列出 _/home/guest_ 来查看其内容。
|
||||
通过使用 `-m` 参数,`useradd` 将为新用户创建一个主目录。你可以通过列出 `/home/guest` 来查看其内容。
|
||||
|
||||
然后你可以使用以下命令来为新用户设置密码:
|
||||
|
||||
```
|
||||
sudo passwd guest
|
||||
```
|
||||
|
||||
或者你也可以使用 `adduser`,这是一个交互式的命令,它会询问你一些问题,包括你要为用户分配的 shell(是的,不止一个),你希望其主目录在哪里,你希望他们属于哪些组(有关这点稍后会讲到)等等。在运行 `adduser` 结束时,你可以设置密码。注意,默认情况下,在许多发行版中都没有安装 `adduser`,但安装了 `useradd`。
|
||||
或者你也可以使用 `adduser`,这是一个交互式的命令,它会询问你一些问题,包括你要为用户分配的 shell(是的,shell 有不止一种),你希望其主目录在哪里,你希望他们属于哪些组(有关这点稍后会讲到)等等。在运行 `adduser` 结束时,你可以设置密码。注意,默认情况下,在许多发行版中都没有安装 `adduser`,但安装了 `useradd`。
|
||||
|
||||
顺便说一下,你可以使用 `userdel` 来移除一个用户:
|
||||
|
||||
```
|
||||
sudo userdel -r guest
|
||||
```
|
||||
|
||||
使用 `-r` 选项,`userdel` 不仅删除了 _guest_ 用户,还删除了他们的主目录和邮件中的条目(如果有的话)。
|
||||
使用 `-r` 选项,`userdel` 不仅删除了 `guest` 用户,还删除了他们的主目录和邮件中的条目(如果有的话)。
|
||||
|
||||
### home 中的内容
|
||||
### 主目录中的内容
|
||||
|
||||
谈到用户的主目录,它依赖于你所使用的发行版。你可能已经注意到,当你使用 `-m` 选项时,`useradd` 使用子目录填充用户的目录,包括音乐,文档和诸如此类的内容以及各种各样的隐藏文件。要查看 guest 主目录中的所有内容,运行 `sudo ls -la /home/guest`。
|
||||
谈到用户的主目录,它依赖于你所使用的发行版。你可能已经注意到,当你使用 `-m` 选项时,`useradd` 使用子目录填充用户的目录,包括音乐、文档和诸如此类的内容以及各种各样的隐藏文件。要查看 `guest` 主目录中的所有内容,运行 `sudo ls -la /home/guest`。
|
||||
|
||||
进入新用户目录的内容通常是由 `/etc/skel` 架构目录确定的。有时它可能是一个不同的目录。要检查正在使用的目录,运行:
|
||||
|
||||
进入新用户目录的内容通常是由 _/etc/skel_ 架构目录确定的。有时它可能是一个不同的目录。要检查正在使用的目录,运行:
|
||||
```
|
||||
useradd -D
|
||||
GROUP=100
|
||||
@ -57,31 +64,36 @@ SKEL=/etc/skel
|
||||
CREATE_MAIL_SPOOL=no
|
||||
```
|
||||
|
||||
这给你一些额外的有趣信息,但你现在感兴趣的是 `SKEL=/etc/skel` 这一行,在这种情况下,按照惯例,它指向 _/etc/skel/_。
|
||||
这会给你一些额外的有趣信息,但你现在感兴趣的是 `SKEL=/etc/skel` 这一行,在这种情况下,按照惯例,它指向 `/etc/skel/`。
|
||||
|
||||
由于 Linux 中的所有东西都是可定制的,因此你可以更改那些放入新创建的用户目录的内容。试试这样做:在 `/etc/skel/` 中创建一个新目录:
|
||||
|
||||
由于 Linux 中的所有东西都是可定制的,因此你可以更改那些放入新创建的用户目录的内容。试试这样做:在 _/etc/skel/_ 中创建一个新目录:
|
||||
```
|
||||
sudo mkdir /etc/skel/Documents
|
||||
```
|
||||
|
||||
然后创建一个包含欢迎消息的文件,并将其复制过来:
|
||||
|
||||
```
|
||||
sudo cp welcome.txt /etc/skel/Documents
|
||||
```
|
||||
|
||||
现在删除 guest 账户:
|
||||
现在删除 `guest` 账户:
|
||||
|
||||
```
|
||||
sudo userdel -r guest
|
||||
```
|
||||
|
||||
再次创建:
|
||||
|
||||
```
|
||||
sudo useradd -m guest
|
||||
```
|
||||
|
||||
嘿 presto!(to 校正:这个 presto 是什么?)你的 _Documents/_ 目录和 _welcome.txt_ 文件神奇地出现在了 guest 的主目录中。
|
||||
嘿!你的 `Documents/` 目录和 `welcome.txt` 文件神奇地出现在了 `guest` 的主目录中。
|
||||
|
||||
你还可以在创建用户时通过编辑 `/etc/default/useradd` 来修改其他内容。我的看起来像这样:
|
||||
|
||||
你还可以在创建用户时通过编辑 _/etc/default/useradd_ 来修改其他内容。我的看起来像这样:
|
||||
```
|
||||
GROUP=users
|
||||
HOME=/home
|
||||
@ -96,11 +108,12 @@ CREATE_MAIL_SPOOL=no
|
||||
|
||||
### 群组心态
|
||||
|
||||
Linux 和其他类 Unix 操作系统依赖于 _groups_,而不是逐个为用户分配权限和特权。一个组就是你想象的那样:一群在某种程度上相关的用户。在你的系统上可能有一组允许使用打印机的用户,他们属于 _lp_(即 "_line printer_")组。传统上 _wheel_ 组的成员是唯一可以通过使用 _su_ 成为超级用户或 root 的成员。_network_ 用户组可以启动或关闭网络。还有许多诸如此类的。
|
||||
Linux 和其他类 Unix 操作系统依赖于用户组,而不是逐个为用户分配权限和特权。一个组就是你想象的那样:一群在某种程度上相关的用户。在你的系统上可能有一组允许使用打印机的用户,他们属于 `lp`(即 “_line printer_”)组。传统上 `wheel` 组的成员是唯一可以通过使用 `su` 成为超级用户或 root 的成员。`network` 用户组可以启动或关闭网络。还有许多诸如此类的。
|
||||
|
||||
不同的发行版有不同的组,具有相同或相似名称的组具有不同的权限,这也取决于你使用的发行版。因此,如果你在前一段中读到的内容与你系统中的内容不匹配,不要感到惊讶。
|
||||
|
||||
不管怎样g,要查看系统中有哪些组,你可以使用:
|
||||
不管怎样,要查看系统中有哪些组,你可以使用:
|
||||
|
||||
```
|
||||
getent group
|
||||
```
|
||||
@ -108,18 +121,20 @@ getent group
|
||||
`getent` 命令列出了某些系统数据库的内容。
|
||||
|
||||
要查找当前用户所属的组,尝试:
|
||||
|
||||
```
|
||||
groups
|
||||
```
|
||||
|
||||
当你使用 `useradd` 创建新用户时,除非你另行指定,否则用户讲只属于一个组:他们自己。一个 _guest_ 用户属于 _guest_ 组。组使用户有权管理自己的东西,仅此而已。
|
||||
当你使用 `useradd` 创建新用户时,除非你另行指定,否则用户将只属于一个组:他们自己。`guest` 用户属于 `guest` 组。组使用户有权管理自己的东西,仅此而已。
|
||||
|
||||
你可以使用 `groupadd` 命令创建新组,然后添加用户:
|
||||
|
||||
```
|
||||
sudo groupadd photos
|
||||
```
|
||||
|
||||
例如,这将创建 _photos_ 组。下一次,我们将使用它来构建一个共享目录,该组的所有成员都可以读取和写入,我们将更多地了解权限和特权。敬请关注!
|
||||
例如,这将创建 `photos` 组。下一次,我们将使用它来构建一个共享目录,该组的所有成员都可以读取和写入,我们将更多地了解权限和特权。敬请关注!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -129,11 +144,11 @@ via: https://www.linux.com/learn/intro-to-linux/2018/7/users-groups-and-other-li
|
||||
作者:[Paul Brown][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/bro66
|
||||
[1]:https://www.linux.com/blog/learn/2018/5/manipulating-directories-linux
|
||||
[1]:https://linux.cn/article-10066-1.html
|
||||
[2]:https://www.linux.com/learn/understanding-linux-file-permissions
|
||||
[3]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
@ -0,0 +1,114 @@
|
||||
用户、组及其它 Linux 特性(二)
|
||||
======
|
||||
> 我们继续创建和管理用户和组的 Linux 教程之旅。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ducks-94911_1920.jpg?itok=7_ZPiph7)
|
||||
|
||||
在正在进行的 Linux 之旅中,我们了解了[如何操作文件夹或目录][1],现在我们继续讨论 _权限_、_用户_ 和 _组_,这对于确定谁可以操作哪些文件和目录是必要的。[上次][2],我们展示了如何创建新用户,现在我们将重新起航:
|
||||
|
||||
你可以使用 `groupadd` 命令创建新组,然后随意添加用户。例如,使用:
|
||||
|
||||
```
|
||||
sudo groupadd photos
|
||||
```
|
||||
|
||||
这将会创建 `photos` 组。
|
||||
|
||||
你需要在根目录下[创建一个目录][1]:
|
||||
|
||||
```
|
||||
sudo mkdir /photos
|
||||
```
|
||||
|
||||
如果你运行 `ls -l /`,结果中会有如下这一行:
|
||||
|
||||
```
|
||||
drwxr-xr-x 1 root root 0 jun 26 21:14 photos
|
||||
```
|
||||
|
||||
输出中的第一个 `root` 是所属的用户,第二个 `root` 是所属的组。
|
||||
|
||||
要将 `/photos` 目录的所有权转移到 `photos` 组,使用:
|
||||
|
||||
```
|
||||
chgrp photos /photos
|
||||
```
|
||||
|
||||
`chgrp` 命令通常采用两个参数,第一个参数是将要获得文件或目录所有权的组,第二个参数是希望交给组的文件或目录。
|
||||
|
||||
接着,运行 `ls -l /`,你会发现刚才那一行变了:
|
||||
|
||||
```
|
||||
drwxr-xr-x 1 root photos 0 jun 26 21:14 photos
|
||||
```
|
||||
|
||||
你已成功将新目录的所有权转移到了 `photos` 组。
|
||||
|
||||
然后,将你自己的用户和 `guest` 用户添加到 `photos` 组:
|
||||
|
||||
```
|
||||
sudo usermod <你的用户名> -a -G photos
|
||||
sudo usermod guest -a -G photos
|
||||
```
|
||||
|
||||
你可能必须注销并重新登录才能看到更改,但是当你这样做时,运行 `groups` 会将 `photos` 显示为你所属的组之一。
|
||||
|
||||
关于上面提到的 `usermod` 命令,需要指明几点。第一:注意要使用 `-G` 选项而不是 `-g` 选项。`-g` 选项更改你的主要组,如果你意外地使用它,它可能会锁定你的一些东西。另一方面,`-G` 将你添加到列出的组中,并没有干扰主要组。如果要将用户添加到多个组中,在 `-G` 之后逐个列出它们,用逗号分隔,不要有空格:
|
||||
|
||||
```
|
||||
sudo usermod <your username> -a -G photos,pizza,spaceforce
|
||||
```
|
||||
|
||||
第二点:小心点不要忘记 `-a` 参数。`-a` 参数代表追加,将你传递给 `-G` 的组列表附加到你已经属于的组。这意味着,如果你不包含 `-a`,那么你之前所属的组列表将被覆盖,再次将你拒之门外。
|
||||
|
||||
这些都不是灾难性问题,但这意味着你必须手动将用户添加回你所属的所有组,这可能是个麻烦,特别是如果你失去了对 `sudo` 和 `wheel` 组的访问权限。
|
||||
|
||||
### 权限
|
||||
|
||||
在将图像复制到 `/photos` 目录之前,还要做一件事情。注意,当你执行上面的 `ls -l /` 时,该文件夹的权限将以 `drwxr-xr-x` 形式返回。
|
||||
|
||||
如果你阅读[我在本文开头推荐的文章][3],你将知道第一个 `d` 表示文件系统中的条目是一个目录,接着你有三组三个字符(`rwx`、`r-x`、`r-x`),它们表示目录的所属用户(`rwx`)的权限,然后是所属组(`r-x`)的权限,最后是其他用户(`r-x`)的权限。这意味着到目前为止唯一具有写权限的人,即能够在 `/photos` 目录中复制或创建文件的唯一人员是 `root` 用户。
|
||||
|
||||
但是[我提到的那篇文章也告诉你如何更改目录或文件的权限][3]:
|
||||
|
||||
```
|
||||
sudo chmod g+w /photos
|
||||
```
|
||||
|
||||
运行 `ls -l /`,你会看到 `/photos` 权限变为了 `drwxrwxr-x`。这就是你希望的:组成员现在可以对目录进行写操作了。
|
||||
|
||||
现在你可以尝试将图像或任何其他文件复制到目录中,它应该没有问题:
|
||||
|
||||
```
|
||||
cp image.jpg /photos
|
||||
```
|
||||
|
||||
`guest` 用户也可以从目录中读取和写入。他们也可以读取和写入,甚至移动或删除共享目录中其他用户创建的文件。
|
||||
|
||||
### 总结
|
||||
|
||||
Linux 中的权限和特权系统已经磨练了几十年,它继承自昔日的旧 Unix 系统。就其本身而言,它工作的非常好,而且经过了深思熟虑。熟悉它对于任何 Linux 系统管理员都是必不可少的。事实上,除非你理解它,否则你根本就无法做很多事情。但是,这并不难。
|
||||
|
||||
下一次,我们将深入研究文件,并以一个创新的方式查看创建,操作和销毁文件的不同方法。最后一个总是很有趣。
|
||||
|
||||
回头见!
|
||||
|
||||
通过 Linux 基金会和 edX 的免费[“Linux 简介”][4]课程了解有关 Linux 的更多信息。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/intro-to-linux/2018/7/users-groups-and-other-linux-beasts-part-2
|
||||
|
||||
作者:[Paul Brown][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.linux.com/users/bro66
|
||||
[1]:https://linux.cn/article-10066-1.html
|
||||
[2]:https://linux.cn/article-10370-1.html
|
||||
[3]:https://www.linux.com/learn/understanding-linux-file-permissions
|
||||
[4]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
@ -0,0 +1,142 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10375-1.html)
|
||||
[#]: subject: (11 Uses for a Raspberry Pi Around the Office)
|
||||
[#]: via: (https://blog.dxmtechsupport.com.au/11-uses-for-a-raspberry-pi-around-the-office/)
|
||||
[#]: author: (James Mawson https://blog.dxmtechsupport.com.au/author/james-mawson/)
|
||||
|
||||
树莓派在办公室的 11 种用法
|
||||
======
|
||||
|
||||
我知道你在想什么:树莓派只能用在修修补补、原型设计和个人爱好中。它实际不能用在业务中。
|
||||
|
||||
毫无疑问,这台电脑的处理能力相对较低、易损坏的 SD 卡、缺乏电池备份以及支持的 DIY 性质,这意味着它不会是一个能在任何时候执行最关键的操作的[专业的、已安装好、配置好的商业服务器][1]的可行替代品。
|
||||
|
||||
但是它电路板便宜、功耗很小、小到几乎适合任何地方、无限灵活 —— 这实际上是处理办公室一些基本任务的好方法。
|
||||
|
||||
而且,更好的是,已经有一些人完成了这些项目并很乐意分享他们是如何做到的。
|
||||
|
||||
### DNS 服务器
|
||||
|
||||
每次在浏览器中输入网站地址或者点击链接时,都需要将域名转换为数字 IP 地址,然后才能显示内容。
|
||||
|
||||
通常这意味着向互联网上某处 DNS 服务器发出请求 —— 但你可以通过本地处理来加快浏览速度。
|
||||
|
||||
你还可以分配自己的子域,以便本地访问办公室中的计算机。
|
||||
|
||||
[这里了解它是如何工作的。][2]
|
||||
|
||||
### 厕所占用标志
|
||||
|
||||
在厕所排过队吗?
|
||||
|
||||
这对于那些等待的人来说很烦人,花在处理它上面的时间会耗费你在办公室的工作效率。
|
||||
|
||||
我想你希望在办公室里也悬挂飞机上那个厕所有人的标志。
|
||||
|
||||
[Occu-pi][3] 是一个非常简单的解决方案,使用磁性开关和树莓派来判断螺栓何时关闭,并在 Slack 频道中更新“厕所在使用中” —— 这意味着整个办公室的人都可以看一眼电脑或者移动设备知道是否有空闲的隔间。
|
||||
|
||||
### 针对黑客的蜜罐陷阱
|
||||
|
||||
黑客破坏了网络的第一个线索是一些事情变得糟糕,这应该会吓到大多数企业主。
|
||||
|
||||
这就是可以用到蜜罐的地方:一台没有任何服务的计算机位于你的网络,将特定端口打开,伪装成黑客喜欢的目标。
|
||||
|
||||
安全研究人员经常在网络外部部署蜜罐,以收集攻击者正在做的事情的数据。
|
||||
|
||||
但对于普通的小型企业来说,这些作为一种绊脚石部署在内部更有用。因为普通用户没有真正的理由想要连接到蜜罐,所以任何发生的登录尝试都是正在进行捣乱的非常好的指示。
|
||||
|
||||
这可以提供对外部人员入侵的预警,并且也可以提供对值得信赖的内部人员的预警。
|
||||
|
||||
在较大的客户端/服务器网络中,将它作为虚拟机运行可能更为实用。但是在无线路由器上运行的点对点的小型办公室/家庭办公网络中,[HoneyPi][4] 之类的东西是一个很小的防盗报警器。
|
||||
|
||||
### 打印服务器
|
||||
|
||||
联网打印机更方便。
|
||||
|
||||
但更换所有打印机可能会很昂贵 —— 特别是如果你对现有的打印机感到满意的话。
|
||||
|
||||
[将树莓派设置为打印服务器][5]可能会更有意义。
|
||||
|
||||
### 网络附加存储(NAS)
|
||||
|
||||
将硬盘变为 NAS 是树莓派最早的实际应用之一,并且它仍然是最好的之一。
|
||||
|
||||
[这是如何使用树莓派创建 NAS。][6]
|
||||
|
||||
### 工单服务器
|
||||
|
||||
想要在预算不足的情况下在服务台中支持工单?
|
||||
|
||||
有一个名为 osTicket 的完全开源的工单程序,它可以安装在你的树莓派上,它甚至还有[随时可用的 SD 卡镜像][7]。
|
||||
|
||||
### 数字标牌
|
||||
|
||||
无论是用于活动、广告、菜单还是其他任何东西,许多企业都需要一种显示数字标牌的方式 —— 而树莓派的廉价和省电使其成为一个非常有吸引力的选择。
|
||||
|
||||
[这有很多可供选择的选项。] [8]
|
||||
|
||||
### 目录和信息亭
|
||||
|
||||
[FullPageOS][9] 是一个基于 Raspbian 的 Linux 发行版,它直接引导到 Chromium 的全屏版本 —— 这非常适合导购、图书馆目录等。
|
||||
|
||||
### 基本的内联网 Web 服务器
|
||||
|
||||
对于托管一个面向公众的网站,你最好有一个托管帐户。树莓派不适合面对真正的网络流量。
|
||||
|
||||
但对于小型办公室,它可以托管内部业务维基或基本的公司内网。它还可以用作沙箱环境,用于试验代码和服务器配置。
|
||||
|
||||
[这里是如何在树莓派上运行 Apache、MySQL 和 PHP。][10]
|
||||
|
||||
### 渗透测试器
|
||||
|
||||
Kali Linux 是专为探测网络安全漏洞而构建的操作系统。通过将其安装在树莓派上,你就拥有了一个超便携式穿透测试器,其中包含 600 多种工具。
|
||||
|
||||
[你可以在这里找到树莓派镜像的种子链接。][11]
|
||||
|
||||
绝对要小心只在你自己的网络或你有权对它安全审计的网络中使用它 —— 使用此方法来破解其他网络是严重的犯罪行为。
|
||||
|
||||
### VPN 服务器
|
||||
|
||||
当你外出时,依靠的是公共无线互联网,你无法控制还有谁在网络中、谁在窥探你的所有流量。这就是为什么通过 VPN 连接加密所有内容可以让人放心。
|
||||
|
||||
你可以订阅任意数量的商业 VPN 服务,并且你可以在云中安装自己的服务,但是在办公室运行一个 VPN,这样你也可以从任何地方访问本地网络。
|
||||
|
||||
对于轻度使用 —— 比如偶尔的商务旅行 —— 树莓派是一种强大的,节约能源的设置 VPN 服务器的方式。(首先要检查一下你的路由器是不是不支持这个功能,许多路由器是支持的。)
|
||||
|
||||
[这是如何在树莓派上安装 OpenVPN。][12]
|
||||
|
||||
### 无线咖啡机
|
||||
|
||||
啊,美味:好喝的饮料是神赐之物,也是公司内工作效率的支柱。
|
||||
|
||||
那么,为什么不[将办公室的咖啡机变成可以精确控制温度和无线连接的智能咖啡机呢?][13]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://blog.dxmtechsupport.com.au/11-uses-for-a-raspberry-pi-around-the-office/
|
||||
|
||||
作者:[James Mawson][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://blog.dxmtechsupport.com.au/author/james-mawson/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://dxmtechsupport.com.au/server-configuration
|
||||
[2]: https://www.1and1.com/digitalguide/server/configuration/how-to-make-your-raspberry-pi-into-a-dns-server/
|
||||
[3]: https://blog.usejournal.com/occu-pi-the-bathroom-of-the-future-ed69b84e21d5
|
||||
[4]: https://trustfoundry.net/honeypi-easy-honeypot-raspberry-pi/
|
||||
[5]: https://opensource.com/article/18/3/print-server-raspberry-pi
|
||||
[6]: https://howtoraspberrypi.com/create-a-nas-with-your-raspberry-pi-and-samba/
|
||||
[7]: https://everyday-tech.com/a-raspberry-pi-ticketing-system-image-with-osticket/
|
||||
[8]: https://blog.capterra.com/7-free-and-open-source-digital-signage-software-options-for-your-next-event/
|
||||
[9]: https://github.com/guysoft/FullPageOS
|
||||
[10]: https://maker.pro/raspberry-pi/projects/raspberry-pi-web-server
|
||||
[11]: https://www.offensive-security.com/kali-linux-arm-images/
|
||||
[12]: https://medium.freecodecamp.org/running-your-own-openvpn-server-on-a-raspberry-pi-8b78043ccdea
|
||||
[13]: https://www.techradar.com/au/how-to/how-to-build-your-own-smart-coffee-machine
|
@ -0,0 +1,153 @@
|
||||
如何在 VirtualBox 上安装并使用 FreeDOS?
|
||||
======
|
||||
|
||||
> 这份指南将带你如何一步一步在 Linux 平台下利用 VirtualBox 安装 FreeDOS。
|
||||
|
||||
### Linux 下借助 VirtualBox 安装 FreeDOS
|
||||
|
||||
- [How to Install FreeDOS in Linux using Virtual Box](https://www.youtube.com/p1MegqzFAqA)
|
||||
|
||||
2017 年的 11 月份,我[采访了 Jim Hall][1] 关于 [FreeDOS 项目][2] 背后的历史故事。今天,我将告诉你如何安装并使用 FreeDOS。需要注意到是:我将在 [Solus][4](一种针对家庭用户的 Linux 桌面发行版)下使用 5.2.14 版本的 [VirtualBox][3] 来完成这些操作。
|
||||
|
||||
> 注意:在本教程我将使用 Solus 作为主机系统因为它很容易设置。另一个你需要注意的事情是 Solus 的软件中心有两个版本的 VirtualBox:`virtualbox` 和 `virtualbox-current`。Solus 会让你选择是使用 linux-lts 内核还是 linux-current 内核。最终区别就是,`virtualbox` 适用于 linux-lts 而 `virtualbx-current` 适用于 linux-current。
|
||||
|
||||
#### 第一步 – 创建新的虚拟机
|
||||
|
||||
![][5]
|
||||
|
||||
当你打开 VirtualBox,点击 “New” 按钮来新建一个虚拟机。你可以自定义这台虚拟机的名字,我将它命名为 “FreeDOS”。你也可以在标注栏内指明你正在安装的 FreeDOS 的版本。你还需要选择你将要安装的操作系统的类型和版本。选择 “Other” 下的 “DOS”。
|
||||
|
||||
#### 第二步 – 设置内存大小
|
||||
|
||||
![][6]
|
||||
|
||||
下一个对话框会问你要给 FreeDOS 主机分配多少可用的内存空间。默认分配 32 MB。不必更改它。在 DOS 系统盛行的年代,32 MB 大小的内存对于一台搭载 FreeDOS 的机器已经很足够了。如果你有需要,你可以通过对你针对 FreeDOS 新建的虚拟机右键并选择 “Setting -> Symtem” 来增加内存。
|
||||
|
||||
![][7]
|
||||
|
||||
#### 第三步 – 创建虚拟硬盘
|
||||
|
||||
![][8]
|
||||
|
||||
下一步,你会被要求创建一个虚拟硬盘用来存储 FreeDOS 和它的文件。如果你还没有创建,只需要点击 “Create”。
|
||||
|
||||
下一个对话框会问你想用什么磁盘文件类型。默认的类型 (VirtualBox Disk Image) 效果就挺好。点击 “Next”。
|
||||
|
||||
下一个你遇到的问题是你想虚拟硬盘以何种方式创建。你是否希望虚拟硬盘占据的空间刚开始很小然后会随着你创建文件和安装软件逐渐增加直至达到你设置的上限?那么选择动态分配。如果你更喜欢虚拟硬盘 (VHD) 按照既定大小直接创建,选择固定大小即可。如果你不打算使用整个 VHD 或者你的硬盘空余空间不是太足够,那么动态分配是个很不错的分配方式。(需要注意的是,动态分配的虚拟硬盘占据的空间会随着你增加文件而增加,但不会因为你删除文件而变小) 我个人更喜欢动态分配,但你可以根据实际需要来选择最合适你的分配类型然后点击 “Next”。
|
||||
|
||||
![][9]
|
||||
|
||||
现在,你可以选择虚拟磁盘的大小和位置。500 MB 已经很足够了。需要注意的是很多你之后用到的程序都是基于文本的,这意味着它们占据的空间非常小。在你做好这些调整后,点击 “Create”。
|
||||
|
||||
#### 第四步 – 关联 .iso 文件
|
||||
|
||||
在我们继续之前,你需要[下载][10] FreeDOS 的 .iso 文件。你需要选择 CDROM 格式的 “standard” 安装程序。
|
||||
|
||||
![][11]
|
||||
|
||||
当文件下载完毕后,返回到 VirtualBox。选中你的虚拟机并打开设置。你可以通过对虚拟机右键并选中 “Setting” 或者选中虚拟机并点击 “Setting” 按钮。
|
||||
|
||||
接下来,点击 “Storage” 选项卡。在 “Storage Devices” 下面,选中 CD 图标。(它应该会在图标旁边显示 “Empty”。) 在右边的 “Attribute” 面板,点中 CD 图标然后在对应路径选中你刚下载的 .iso 文件。
|
||||
|
||||
> 提示:通常,在你通过 VirtualBox 安装完一个操作系统后你就可以删除对应的 .iso 文件了。但这并不适合 FreeDOS 。如果你想通过 FreeDOS 的包管理器来安装应用程序,你需要这个 .iso 文件。我通常会让这个 .iso 文件连接到虚拟机以便我安装一些程序。如果你也这么做了,你必须要确认下你让 FreeDOS 虚拟机每次启动的时候是从硬盘启动因为虚拟机的默认设置是从已关联的 .iso 文件启动。如果你忘了关联 .iso 文件,也不用担心。你可以通过选择 FreeDOS 虚拟机窗口上方的 “Devices” 来关联。然后就会发现 .iso 文件列在 “Optical Drives”。
|
||||
|
||||
#### 第五步 – 安装 FreeDOS
|
||||
|
||||
![][12]
|
||||
|
||||
既然我们已经完成了所有的准备工作,让我们来开始安装 FreeDOS 吧。
|
||||
|
||||
首先,你需要知道关于最新版本的 VirtualBox 的一个 bug。当我们创建好虚拟硬盘然后选中 “Install to harddisk” 后,如果你开启虚拟机你会发现在 FreeDOS 的欢迎界面出现过后就是不断滚动无群无尽的机器代码。我最近就遇到过这个问题而且不管是 Linux 还是 Windows 平台的 VirtualBox 都会碰到这个问题。(我知道解决办法。)
|
||||
|
||||
为了避开这个问题,你需要做一个简单的修改。当你看到 FreeDOS 的欢迎界面的时候,按下 Tab 键。(确认 “Install to harddrive” 已经选中。)在 “fdboot.img” 之后输入 `raw` 然后按下回车键。接下来就会启动 FreeDOS 的安装程序。
|
||||
|
||||
![][13]
|
||||
|
||||
安装程序会首先处理你的虚拟磁盘的格式化。当格式化完成后,安装程序会重启。当 FreeDOS 的欢迎界面再次出现的时候,你必须重新输入 `raw` 就像你之前输入的内容那样。
|
||||
|
||||
要确保在安装过程中你遇到的所有问题你选的都是 “Yes”。但也要注意有一个很重要的问题:“What FreeDOS packages do you want to install?” 的答案并不是 “Yes” 或者 “No”。答案有两个选择分别是 “Base packages” 和 “Full installation”。“Base packages” 针对的是想体验类似原始的 MS-DOS 环境的人群。“Full installation” 则包括了一系列工具和实用的程序来提升 DOS。
|
||||
|
||||
在整个安装过程的最后,你可以选择重启或者继续停留在 DOS。选择“reboot”。
|
||||
|
||||
#### 第六步 – 设置网络
|
||||
|
||||
不同于原始的 DOS,FreeDOS 可以访问互联网。你可以安装新的软件包或者更新你已经安装的软件包。要想使用网络,你还需要在 FreeDOS 安装些应用程序。
|
||||
|
||||
![][14]
|
||||
|
||||
首先,启动进入你新创建的 FreeDOS 虚拟机。在 FreeDOS 的选择界面,选中 “Boot from System harddrive”。
|
||||
|
||||
![][15]
|
||||
|
||||
现在,你可以通过输入 `fdimples` 来访问 FreeDOS 的软件包管理工具。你也可以借助方向键来浏览软件包管理器,然后用空格键选择类别或者软件包。在 “Networking” 类别中,你需要选中 `fdnet`。FreeDOS project 推荐也安装 `mtcp` 和 `wget`。多次点击 Tab 键直到选中 “OK” 然后在按下回车键。安装完成后,输入 `reboot` 并按下回车键确认执行。系统重启后,引导你的系统驱动。如果网络安装成功的话,你会在终端看到一些关于你的网络信息的新消息。
|
||||
|
||||
![][16]
|
||||
|
||||
注意:
|
||||
|
||||
有时候 VirtualBox 的默认设置并没有生效。如果遇到这种情况,先关闭你的 FreeDOS 虚拟机窗口。在 VirtualBox 主界面右键你的虚拟机并选中 “Setting”。VirtualBox 默认的网络设置是 “NAT”。将它改为 “Bridged Adapter” 后再尝试安装 FreeDOS 的软件包。现在就应该能正常运作了。
|
||||
|
||||
#### 第七步 – FreeDOS 的基本使用
|
||||
|
||||
##### 常见命令
|
||||
|
||||
既然你已经成功安装了 FreeDOS,让我们来看些基础命令。如果你已经在 Windows 平台使用过命令提示符,那么你会发现有很多命令都是相似的。
|
||||
|
||||
* `DIR`– 显示当前目录的内容
|
||||
* `CD` – 改变当前所在的目录
|
||||
* `COPY OLD.TXT NEW.TXT`– 复制文件
|
||||
* `TYPE TEST.TXT` – 显示文件内容
|
||||
* `DEL TEST.TXT` – 删除文件
|
||||
* `XCOPY DIR NEWDIR` – 复制目录及目录下的所有内容
|
||||
* `EDIT TEST.TXT`– 编辑一个文件
|
||||
* `MKDIR NEWDIR` – 创建一个新目录
|
||||
* `CLS` – 清除屏幕
|
||||
|
||||
你可以借助互联网或者 Jim Hall 所创建的 [方便的速查表][17] 来找到更多基本的 DOS 命令。
|
||||
|
||||
##### 运行一个程序
|
||||
|
||||
在 FreeDOS 上运行程序相当简单。需要注意的是当你借助 `fdimples` 软件包管理器来安装一个应用程序的时候,要确保你指定了待安装程序的 .EXE 文件的路径。这个路径会在应用程序的详细信息中显示。要想运行程序,通常你还需要进入到程序所在文件夹并输入该程序的名字。
|
||||
|
||||
例如,FreeDOS 中你可以安装一个叫 `FED` 的编辑器。安装完成后,你还需要做的就是进入 `C:\FED` 这个文件夹下并输入 `FED`。
|
||||
|
||||
对于位于 `\bin` 这个文件夹的程序,比如 Pico。这些程序可以在任意文件夹中被调用。
|
||||
|
||||
对于游戏通常会有一个或者两个 .EXE 程序,你玩游戏之前不得不先运行它们。这些设置文件通常能够修复你遇到的声音,视频,或者控制问题。
|
||||
|
||||
如果你遇到一些本教程中没指出的问题,别忘记访问 [FreeDOS 主站][2] 来寻求解决办法。他们有一个 wiki 和一些其他的支持选项。
|
||||
|
||||
你使用过 FreeDOS 吗?你还想看关于 FreeDOS 哪些方面的教程?请在下面的评论区告诉我们。
|
||||
|
||||
如果你觉得本篇文章很有趣,请花一分钟的时间将它分享在你的社交媒体,Hacker News 或者 [Reddit][18]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/install-freedos/
|
||||
|
||||
作者:[John Paul][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://itsfoss.com/author/john/
|
||||
[1]:https://itsfoss.com/interview-freedos-jim-hall/
|
||||
[2]:http://www.freedos.org/
|
||||
[3]:https://www.virtualbox.org/
|
||||
[4]:https://solus-project.com/home/
|
||||
[5]:https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-1.jpg?w=787&ssl=1
|
||||
[6]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-2.jpg?w=792&ssl=1
|
||||
[7]:https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-3.jpg?w=797&ssl=1
|
||||
[8]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-4.jpg?w=684&ssl=1
|
||||
[9]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-6.jpg?w=705&ssl=1
|
||||
[10]:http://www.freedos.org/download/
|
||||
[11]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-7.jpg?w=800&ssl=1
|
||||
[12]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-8.png?w=789&ssl=1
|
||||
[13]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-9.png?w=748&ssl=1
|
||||
[14]:https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-10.png?w=792&ssl=1
|
||||
[15]:https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-11.png?w=739&ssl=1
|
||||
[16]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/07/freedos-tutorial-12.png?w=744&ssl=1
|
||||
[17]:https://opensource.com/article/18/6/freedos-commands-cheat-sheet
|
||||
[18]:http://reddit.com/r/linuxusersgroup
|
@ -1,24 +1,25 @@
|
||||
量子计算的开源框架 Cirq 介绍
|
||||
======
|
||||
|
||||
我们即将讨论的内容正如标题所示,本文通过使用 Cirq 的一个开源视角,尝试去了解我们已经在量子计算领域取得多大的成就,和该领域的发展方向,以加快科学和技术研究。
|
||||
|
||||
首先,我们将引领你进入量子计算的世界。在我们深入了解 Cirq 在未来的量子计算中扮演什么样的重要角色之前,我们将尽量向你解释其背后的基本概念。Cirq,你最近可能听说过,在这个领域中已经发生了重大新闻,在 Open Science 上的文章中,我们将去尝试找出答案。
|
||||
首先,我们将引领你进入量子计算的世界。在我们深入了解 Cirq 在未来的量子计算中扮演什么样的重要角色之前,我们将尽量向你解释其背后的基本概念。你最近可能听说过,在这个领域中有件重大新闻,就是 Cirq。在这篇开放科学栏目的文章中,我们将去尝试找出答案。
|
||||
|
||||
<https://www.youtube.com/embed/WVv5OAR4Nik?enablejsapi=1&autoplay=0&cc_load_policy=0&iv_load_policy=1&loop=0&modestbranding=1&rel=0&showinfo=0&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=2&>
|
||||
- [How it Works - Quantum Computing](https://www.youtube.com/WVv5OAR4Nik)
|
||||
|
||||
在我们开始了解量子计算之前,必须先去了解“量子”这个术语,量子是已知的 [亚原子粒子][1] 中最小的物质。[量子][2] 这个词来自拉丁语 Quantus,意思是 “有多少”,在下面的短视频链接中有描述:
|
||||
在我们开始了解量子计算之前,必须先去了解“量子”这个术语,量子是已知的 [亚原子粒子][1] 中最小的物质。<ruby>[量子][2]<rt>Quantum</rt></ruby> 这个词来自拉丁语 Quantus,意思是 “有多小”,在下面的短视频链接中有描述:
|
||||
|
||||
<https://www.youtube.com/embed/-pUOxVsxu3o?enablejsapi=1&autoplay=0&cc_load_policy=0&iv_load_policy=1&loop=0&modestbranding=1&rel=0&showinfo=0&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=2&>
|
||||
- [What is a quantum Why is it significant](https://www.youtube.com/-pUOxVsxu3o)
|
||||
|
||||
为了易于我们理解量子计算,我们将量子计算与<ruby>经典计算<rt>Classical Computing</rt></ruby>(也有译做传统计算)进行比较。经典计算是指设计用于工作的、正在使用的计算机,正如你现在用于阅读本文的设备,就是我们所谓的经典计算设备。
|
||||
为了易于我们理解量子计算,我们将<ruby>量子计算<rt>Quantum Computing</rt></ruby>与<ruby>经典计算<rt>Classical Computing</rt></ruby>(LCTT 译注:也有译做“传统计算”)进行比较。经典计算是指今天的传统计算机如何设计工作的,正如你现在用于阅读本文的设备,就是我们所谓的经典计算设备。
|
||||
|
||||
### 经典计算
|
||||
|
||||
经典计算是描述计算机如何工作的另一种方式。它们通过一个二进制系统工作,即信息使用 1 或 0 来存储。经典计算机不会理解除 1 或 0 之外的任何其它东西。
|
||||
经典计算只是描述计算机如何工作的另一种方式。它们通过一个二进制系统工作,即信息使用 1 或 0 来存储。经典计算机不会理解除 1 或 0 之外的任何其它东西。
|
||||
|
||||
直白来说,在计算机内部一个晶体管只能是开(1)或关(0)。我们输入的任何信息都被转换为无数个 1 和 0,所以计算机只能理解和存储 1 和 0。所有的东西都只能用无数个 1 和 0 的组合来表示。
|
||||
直白来说,在计算机内部一个晶体管只能是开(1)或关(0)。我们输入的任何信息都被转换为无数个 1 和 0,以便计算机能理解和存储。所有的东西都只能用无数个 1 和 0 的组合来表示。
|
||||
|
||||
<https://www.youtube.com/embed/Xpk67YzOn5w?enablejsapi=1&autoplay=0&cc_load_policy=0&iv_load_policy=1&loop=0&modestbranding=1&rel=0&showinfo=0&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=2&>
|
||||
- [Why Do Computers Use 1s and 0s Binary and Transistors Explained](https://www.youtube.com/Xpk67YzOn5w)
|
||||
|
||||
### 量子计算
|
||||
|
||||
@ -26,39 +27,39 @@
|
||||
|
||||
请注意,叠加和纠缠 [不是同一个现象][4]。
|
||||
|
||||
<https://www.youtube.com/embed/jiXuVIEg10Q?enablejsapi=1&autoplay=0&cc_load_policy=0&iv_load_policy=1&loop=0&modestbranding=1&rel=0&showinfo=0&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=2&>
|
||||
- [How Do Quantum Computers Work!](https://www.youtube.com/jiXuVIEg10Q)
|
||||
|
||||
![][5]
|
||||
|
||||
就像在经典计算中,我们有<ruby>比特<rt>bit</rt></ruby>,在量子计算中,我们相应也有<ruby>量子比特<rt>qubits</rt></ruby>(或 Quantum bits)。想了解它们二者之间的巨大差异之处,请查看这个 [页面][6],从那里的图片中可以得到答案。
|
||||
就像在经典计算中,我们有<ruby>比特<rt>bit</rt></ruby>,在量子计算中,我们相应也有<ruby>量子比特<rt>qubit</rt></ruby>(即 Quantum bit)。想了解它们二者之间的巨大差异之处,请查看这个 [页面][6],从那里的图片中可以得到答案。
|
||||
|
||||
量子计算机并不是来替代我们的经典计算机的。但是,有一些非常巨大的任务用我们的经典计算机是无法完成的,而那些正是量子计算机大显身手的好机会。下面链接的视频详细描述了上述情况,同时也描述了量子计算机的原理。
|
||||
|
||||
<https://www.youtube.com/embed/JhHMJCUmq28?enablejsapi=1&autoplay=0&cc_load_policy=0&iv_load_policy=1&loop=0&modestbranding=1&rel=0&showinfo=0&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=2&>
|
||||
- [Quantum Computers Explained – Limits of Human Technology](https://www.youtube.com/JhHMJCUmq28)
|
||||
|
||||
下面的视频全面描述了量子计算领域到目前为止的最新进展:
|
||||
|
||||
<https://www.youtube.com/embed/CeuIop_j2bI?enablejsapi=1&autoplay=0&cc_load_policy=0&iv_load_policy=1&loop=0&modestbranding=1&rel=0&showinfo=0&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=2&>
|
||||
- [Quantum Computing 2018 Update](https://www.youtube.com/CeuIop_j2bI)
|
||||
|
||||
### 嘈杂中型量子
|
||||
|
||||
根据最新更新的(2018 年 7 月 31 日)研究论文,术语 “Noisy” 是指由于对量子比特未能完全控制所产生的不准确性。正是这种不准确性严重制约了量子设备短期内实现其目标。
|
||||
根据最新更新的(2018 年 7 月 31 日)研究论文,术语 “<ruby>嘈杂<rt>Noisy</rt></ruby>” 是指由于对量子比特未能完全控制所产生的不准确性。正是这种不准确性在短期内严重制约了量子设备实现其目标。
|
||||
|
||||
“中型” 指的是在接下来的几年中,量子计算机将要实现的量子规模大小,届时,量子比特的数目将可能从 50 到几百个不等。50 个量子比特是一个重大的量程碑,因为它将超越现有的最强大的 [超级计算机][8] 的 [暴力][7] 模拟能力。更多信息请阅读 [这里的][9] 论文。
|
||||
“中型” 指的是在接下来的几年中,量子计算机将要实现的量子规模大小,届时,量子比特的数目将可能从 50 到几百个不等。50 个量子比特是一个重大的量程碑,因为它将超越现有的最强大的 [超级计算机][8] 的 [暴力破解][7] 所能比拟的计算能力。更多信息请阅读 [这里的][9] 论文。
|
||||
|
||||
随着 Cirq 出现,许多事情将会发生变化。
|
||||
|
||||
### Cirq 是什么?
|
||||
|
||||
Cirq 是一个 python 框架,它用于创建、编辑和调用我们前面讨论的嘈杂中型量子(NISQ)。换句话说,Cirq 能够解决挑战,去改善精确度和降低量子计算中的噪声。
|
||||
Cirq 是一个 Python 框架,它用于创建、编辑和调用我们前面讨论的嘈杂中型量子(NISQ)。换句话说,Cirq 能够解决挑战,去改善精确度和降低量子计算中的噪声。
|
||||
|
||||
Cirq 并不需要必须有一台真实的量子计算机。Cirq 能够使用一个类似模拟器的界面去执行量子电路模拟。
|
||||
|
||||
Cirq 的前进步伐越来越快了,[Zapata][10] 是使用它的首批用户之一,Zapata 是由来自哈佛大学的一群专注于量子计算的科学家在去年成立的。
|
||||
Cirq 的前进步伐越来越快了,[Zapata][10] 是使用它的首批用户之一,Zapata 是由来自哈佛大学的专注于量子计算的[一群科学家][11]在去年成立的。
|
||||
|
||||
### Linux 上使用 Cirq 入门
|
||||
|
||||
开源的 [Cirq 库][12] 开发者建议将它安装在像 [virtualenv][14] 这样的一个 [虚拟 python 环境][13] 中。在 Linux 上的开发者安装指南可以在 [这里][15] 找到。
|
||||
开源的 [Cirq 库][12] 开发者建议将它安装在像 [virtualenv][14] 这样的一个 [虚拟 Python 环境][13] 中。在 Linux 上的开发者安装指南可以在 [这里][15] 找到。
|
||||
|
||||
但我们在 Ubuntu 16.04 的系统上成功地安装和测试了 Python3 的 Cirq 库,安装步骤如下:
|
||||
|
||||
@ -66,43 +67,41 @@ Cirq 的前进步伐越来越快了,[Zapata][10] 是使用它的首批用户
|
||||
|
||||
![Cirq Framework for Quantum Computing in Linux][16]
|
||||
|
||||
首先,我们需要 pip 或 pip3 去安装 Cirq。[Pip][17] 是推荐用于安装和管理 Python 包的工具。
|
||||
首先,我们需要 `pip` 或 `pip3` 去安装 Cirq。[Pip][17] 是推荐用于安装和管理 Python 包的工具。
|
||||
|
||||
对于 Python 3.x 版本,Pip 能够用如下的命令来安装:
|
||||
|
||||
```
|
||||
sudo apt-get install python3-pip
|
||||
|
||||
```
|
||||
|
||||
Python3 包能够通过如下的命令来安装:
|
||||
|
||||
```
|
||||
pip3 install <package-name>
|
||||
|
||||
```
|
||||
|
||||
我们继续去使用 Pip3 为 Python3 安装 Cirq 库:
|
||||
|
||||
```
|
||||
pip3 install cirq
|
||||
|
||||
```
|
||||
|
||||
#### 启用 Plot 和 PDF 生成(可选)
|
||||
|
||||
可选系统的依赖没有安装的,可以使用 pip 去安装它:
|
||||
可选系统的依赖没有被 Pip 安装的,可以使用如下命令去安装它:
|
||||
|
||||
```
|
||||
sudo apt-get install python3-tk texlive-latex-base latexmk
|
||||
|
||||
```
|
||||
|
||||
* python3-tk 是 Python 自有的启用了绘图功能的图形库
|
||||
* texlive-latex-base 和 latexmk 启动了 PDF 输出功能。
|
||||
|
||||
|
||||
|
||||
最后,我们使用如下的命令和代码成功测试了 Cirq:
|
||||
|
||||
```
|
||||
python3 -c 'import cirq; print(cirq.google.Foxtail)'
|
||||
|
||||
```
|
||||
|
||||
我们得到的输出如下图:
|
||||
@ -113,27 +112,27 @@ python3 -c 'import cirq; print(cirq.google.Foxtail)'
|
||||
|
||||
我们也配置了一个 Python IDE [PyCharm][19] 去测试同样的结果:
|
||||
|
||||
因为在我们的 Linux 系统上为 Python3 安装了 Cirq,我们在 IDE 中配置项目解释器路径:
|
||||
因为在我们的 Linux 系统上为 Python3 安装了 Cirq,我们在 IDE 中配置项目解释器路径为:
|
||||
|
||||
```
|
||||
/usr/bin/python3
|
||||
|
||||
```
|
||||
|
||||
![][20]
|
||||
|
||||
在上面的输出中,你可能注意到我们刚设置的项目解释器路径与测试程序文件(test.py)的路径显示在一起。退出代码 0 表示程序已经成功退出,没有错误。
|
||||
在上面的输出中,你可能注意到我们刚设置的项目解释器路径与测试程序文件(`test.py`)的路径显示在一起。退出代码 0 表示程序已经成功退出,没有错误。
|
||||
|
||||
因此,那是一个现成的 IDE 环境,你可以导入 Cirq 库去开始使用 Python 去编程和模拟量子电路。
|
||||
因此,那是一个已经就绪的 IDE 环境,你可以导入 Cirq 库去开始使用 Python 去编程和模拟量子电路。
|
||||
|
||||
#### Cirq 使用入门
|
||||
|
||||
Criq 入门的一个好的开端就是它 GitHub 页面上的 [示例][21]。
|
||||
|
||||
Cirq 的开发者在 GitHub 上已经放了学习 [教程][22]。如果你想认真地学习量子计算,他们推荐你去看一本非常好的书,它是[由 Nielsen 和 Chuang 写的名为 “量子计算和量子信息“][23]。
|
||||
Cirq 的开发者在 GitHub 上已经放置了学习 [教程][22]。如果你想认真地学习量子计算,他们推荐你去看一本非常好的书,它是[由 Nielsen 和 Chuang 写的名为 《量子计算和量子信息》][23]。
|
||||
|
||||
#### OpenFermion-Cirq
|
||||
|
||||
[OpenFermion][24] 是一个开源库,它是为了在量子计算机上模拟获取和操纵代表的费米系统(包含量子化学)。根据 [粒子物理学][26] 理论,按照 [费米— 狄拉克统计][27],费米系统与 [费米子][25] 的产生相关。
|
||||
[OpenFermion][24] 是一个开源库,它是为了在量子计算机上模拟获取和操纵代表的费米系统(包含量子化学)。根据 [粒子物理学][26] 理论,按照 [费米—狄拉克统计][27],费米系统与 [费米子][25] 的产生相关。
|
||||
|
||||
OpenFermion 被称为从事 [量子化学][29] 的化学家和研究人员的 [一个极好的实践工具][28]。量子化学主要专注于 [量子力学][30] 在物理模型和化学系统实验中的应用。量子化学也被称为 [分子量子力学][31]。
|
||||
|
||||
@ -141,7 +140,7 @@ Cirq 的出现使 OpenFermion 通过提供程序和工具去扩展功能成为
|
||||
|
||||
#### Google Bristlecone
|
||||
|
||||
2018 年 3 月 5 日,在洛杉矶举行的一年一度的 [美国物理学会会议][33] 上,Google 发布了 [Bristlecone][32],这是他们的最新的量子处理器。这个 [基于门的超导系统][34] 为 Google 提供了一个测试平台,用以研究 [量子比特技术][37] 的 [系统错误率][35] 和 [扩展性][36] ,以及在量子 [仿真][38]、[优化][39]、和 [机器学习][40] 方面的应用。
|
||||
2018 年 3 月 5 日,在洛杉矶举行的一年一度的 [美国物理学会会议][33] 上,Google 发布了 [Bristlecone][32],这是他们的最新的量子处理器。这个 [基于门的超导系统][34] 为 Google 提供了一个测试平台,用以研究 [量子比特技术][37] 的 [系统错误率][35] 和 [扩展性][36] ,以及在量子 [仿真][38]、[优化][39] 和 [机器学习][40] 方面的应用。
|
||||
|
||||
Google 希望在不久的将来,能够制造出它的 [云可访问][41] 的 72 个量子比特的 Bristlecone 量子处理器。Bristlecone 将越来越有能力完成一个经典超级计算机无法在合理时间内完成的任务。
|
||||
|
||||
@ -154,11 +153,9 @@ Cirq 将允许我们去:
|
||||
* 在设备上放置适当的门
|
||||
* 并调度这个门的时刻
|
||||
|
||||
### 开放科学关于 Cirq 的观点
|
||||
|
||||
|
||||
### Open Science 关于 Cirq 的观点
|
||||
|
||||
我们知道 Cirq 是在 GitHub 上开源的,它除了在 Open Science 社区之外,特别是那些专注于量子研究的人们,都可以高效率地合作,通过开发新方法,去降低现有量子模型中的错误率和提升精确度,以解决目前在量子计算中所面临的挑战。
|
||||
我们知道 Cirq 是在 GitHub 上开源的,在开源科学社区之外,特别是那些专注于量子研究的人们,都可以通过高效率地合作,通过开发新方法,去降低现有量子模型中的错误率和提升精确度,以解决目前在量子计算中所面临的挑战。
|
||||
|
||||
如果 Cirq 不走开源模型的路线,事情可能变得更具挑战。一个伟大的创举可能就此错过,我们可能在量子计算领域止步不前。
|
||||
|
||||
@ -170,7 +167,7 @@ Cirq 将允许我们去:
|
||||
|
||||
最后,我们看了两个示例 OpenFermion 和 Bristlecone,介绍了在量子计算中,Cirq 在开发研究中具有什么样的基本优势。最后我们以 Open Science 社区的视角对 Cirq 进行了一些精彩的思考,结束了我们的话题。
|
||||
|
||||
我们希望能以一种易于理解的方式向你介绍量子计算框架 Cirq 的使用。如果你有与此相关的任何反馈,请在下面的评论区告诉我们。感谢阅读,希望我们能在 Open Science 的下一篇文章中再见。
|
||||
我们希望能以一种易于理解的方式向你介绍量子计算框架 Cirq 的使用。如果你有与此相关的任何反馈,请在下面的评论区告诉我们。感谢阅读,希望我们能在开放科学栏目的下一篇文章中再见。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -179,7 +176,7 @@ via: https://itsfoss.com/qunatum-computing-cirq-framework/
|
||||
作者:[Avimanyu Bandyopadhyay][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -188,7 +185,7 @@ via: https://itsfoss.com/qunatum-computing-cirq-framework/
|
||||
[2]:https://en.wikipedia.org/wiki/Quantum
|
||||
[3]:https://www.clerro.com/guide/491/quantum-superposition-and-entanglement-explained
|
||||
[4]:https://physics.stackexchange.com/questions/148131/can-quantum-entanglement-and-quantum-superposition-be-considered-the-same-phenom
|
||||
[5]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/08/bit-vs-qubit.jpg
|
||||
[5]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/bit-vs-qubit.jpg?w=576&ssl=1
|
||||
[6]:http://www.rfwireless-world.com/Terminology/Difference-between-Bit-and-Qubit.html
|
||||
[7]:https://en.wikipedia.org/wiki/Proof_by_exhaustion
|
||||
[8]:https://www.explainthatstuff.com/how-supercomputers-work.html
|
||||
@ -199,11 +196,11 @@ via: https://itsfoss.com/qunatum-computing-cirq-framework/
|
||||
[13]:https://itsfoss.com/python-setup-linux/
|
||||
[14]:https://virtualenv.pypa.io
|
||||
[15]:https://cirq.readthedocs.io/en/latest/install.html#installing-on-linux
|
||||
[16]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/08/cirq-framework-linux.jpeg
|
||||
[16]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/cirq-framework-linux.jpeg
|
||||
[17]:https://pypi.org/project/pip/
|
||||
[18]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/08/cirq-test-output.jpg
|
||||
[18]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/cirq-test-output.jpg
|
||||
[19]:https://itsfoss.com/install-pycharm-ubuntu/
|
||||
[20]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/08/cirq-tested-on-pycharm.jpg
|
||||
[20]:https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/08/cirq-tested-on-pycharm.jpg
|
||||
[21]:https://github.com/quantumlib/Cirq/tree/master/examples
|
||||
[22]:https://github.com/quantumlib/Cirq/blob/master/docs/tutorial.md
|
||||
[23]:http://mmrc.amss.cas.cn/tlb/201702/W020170224608149940643.pdf
|
@ -0,0 +1,61 @@
|
||||
认识存储:块、文件和对象
|
||||
======
|
||||
> 今天产生的大量数据带来了新的存储挑战。在本文中了解各种存储类型以及它们的使用方式。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/block2_1920.jpg?itok=s1y6RLhT)
|
||||
|
||||
现在,对于那些创建或消费数据的公司来说,处理数量巨大的生成数据是个非常大的挑战。而对于那些解决存储相关问题的科技公司来说,也是一个挑战。
|
||||
|
||||
Red Hat 存储首席产品营销经理 Michael St. Jean 说,“数据每年呈几何级增长,而我们发现数据大量增长的主要原因是由于消费增长和为拓展价值而进行的产业转型,毫无疑问,物联网对数据增长的贡献很大,但对软件定义存储来说最重要的挑战是,如何处理用户场景相关的数据增长。“
|
||||
|
||||
任何挑战都意味着机遇。Azure 存储、介质和边缘计算总经理 Tad Brockway 说,“今天,新旧数据源产生的海量数据为我们满足客户在规模、性能、灵活性、治理方面急剧增长的需求提供了一个机遇。”
|
||||
|
||||
### 现代软件定义存储的三种类型
|
||||
|
||||
这里有三个不同类型的存储解决方案 —— 块、文件、和对象 —— 虽然它们每个都可以与其它的共同工作,但它们每个都有不同的用途。
|
||||
|
||||
块存储是数据存储的最古老形式,数据都存储在固定长度的块或多个块中。块存储适用于企业存储环境,并且通常使用光纤通道或 iSCSI 接口。根据 SUSE 的软件定义存储高级产品经理 Larry Morris 的说法,“块存储要求一个应用去映射存储设备上存储数据块的位置。”
|
||||
|
||||
块存储在存储区域网和软件定义存储系统中是虚拟的,它是处于一个共享的硬件基础设施上的抽象逻辑设备,其创建和存在于服务器、虚拟服务器、或运行在基于像 SCSI、SATA、SAS、FCP、FCoE、或 iSCSI 这样的协议的系统管理程序上。
|
||||
|
||||
St. Jean 说“块存储将单个的存储卷(如一个虚拟或云存储节点、或一个老式硬盘)分割成单独的被称为块的实体。”
|
||||
|
||||
每个块独立存在,并且能够用它自己的数据传输协议和操作系统格式化 —— 给用户完全的配置自主权。由于块存储系统并不负责像文件存储系统那样的文件查找职责,所以,块存储是一个非常快的存储系统。由于同时具备速度和配置灵活性,使得块存储非常适合原始服务器存储或富媒体数据库。
|
||||
|
||||
块存储适合于宿主机操作系统、应用程序、数据库、完整虚拟机和容器。传统上,块存储仅能够被独立的机器访问,或呈现给集群中的机器访问。
|
||||
|
||||
### 基于文件的存储
|
||||
|
||||
基于文件的存储使用一个文件系统去映射存储设备上数据的存储位置。这种技术在直连或网络附加存储系统应用领域中处于支配地位。它需要做两件事情:组织数据并呈现给用户。St. Jean 说,”使用文件存储时,数据在服务器侧的存储方式与客户端用户所看到的是完全相同的。这就允许用户通过一些唯一标识符(像文件名、位置、或 URL)去请求一个文件,使用特定的数据传输协议与存储系统沟通。
|
||||
|
||||
其结果就是一种能够从上到下进行浏览的分层的文件结构。文件存储处于块存储之上,允许用户去查看和访问文件、文件夹这样的数据,但是被限制访问处于这些文件和文件夹之下的数据块。
|
||||
|
||||
Brockway 解释说,“文件存储一般用于像 NFS 和 CIFS/SMB 这种很多服务器基于 IP 网络进行访问的共享文件系统上。访问控制通过用户和组的权限实现在文件、目录和导出级别上。基于文件的存储可用于被多个用户和机器、二进制应用程序、数据库、虚拟机所需要的文件的存储上,以及容器上。“
|
||||
|
||||
### 对象存储
|
||||
|
||||
对象存储是最新的数据存储形式,它为非结构化数据提供一个仓库,它将内容从索引中分离出来,并允许多个文件连接到一个对象上。一个对象就是与任何相关元数据配对的一个数据块,这些元数据提供对象中包含的字节的上下文(比如数据创建时间和数据大小等)。也就是说这两样东西 —— 数据和元数据 —— 构成了一个对象。
|
||||
|
||||
对象存储的一个好处是每个数据块都关联了一个唯一标识符。访问数据需要唯一标识符,并且不需要应用程序或用户知道数据的真实存储位置。对象数据是通过 API 来访问的。
|
||||
|
||||
St. Jean 说,“对象中存储的数据是没有压缩和加密的,对象本身被组织在对象存储(一个填满其它对象的中心库)中或容器(包含应用程序运行所需要的所有文件的一个包)中。与文件存储系统的层次结构相比,对象、对象存储和容器在本质上是平面的 —— 这使得它们在存储规模巨大时访问速度很快。”
|
||||
|
||||
对象存储可以扩展到很多 PB 字节大小,以适应巨大的数据集,因此它是图像、音频、视频、日志、备份、和分析服务所使用的数据存储的最佳选择。
|
||||
|
||||
### 结论
|
||||
|
||||
现在你已经知道了各种类型的存储以及它们的用处。后面我们将继续研究这个主题的更多内容,敬请关注。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/2018/9/know-your-storage-block-file-object
|
||||
|
||||
作者:[Swapnil Bhartiya][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/arnieswap
|
||||
[1]: https://events.linuxfoundation.org/events/elc-openiot-europe-2018/
|
@ -0,0 +1,186 @@
|
||||
如何使用 Fedora IoT 点亮 LED 灯
|
||||
======
|
||||
|
||||
![](https://fedoramagazine.org/wp-content/uploads/2018/08/LED-IoT-816x345.jpg)
|
||||
|
||||
如果你喜欢 Fedora、容器,而且有一块树莓派,那么这三者结合操控 LED 会怎么样?本文介绍的是 Fedora IoT,将展示如何在树莓派上安装预览镜像。还将学习如何与 GPIO 交互以点亮 LED。
|
||||
|
||||
### 什么是 Fedora IoT?
|
||||
|
||||
Fedora IoT 是当前 Fedora 项目的目标之一,计划成为一个完整的 Fedora 版本。Fedora IoT 将是一个在 ARM(目前仅限 aarch64)设备上(例如树莓派),以及 x86_64 架构上运行的系统。
|
||||
|
||||
![][1]
|
||||
|
||||
Fedora IoT 基于 OSTree 开发,就像 [Fedora Silverblue][2] 和以往的 [Atomic Host][3]。
|
||||
|
||||
### 下载和安装 Fedora IoT
|
||||
|
||||
官方 Fedora IoT 镜像将和 Fedora 29 一起发布。但是在此期间你可以下载 [基于 Fedora 28 的镜像][4] 来进行这个实验。(LCTT 译注:截止至本译文发布,[Fedora 29 已经发布了][11],但是 IoT 版本并未随同发布,或许会在 Fedora 30 一同发布?)
|
||||
|
||||
你有两种方法来安装这个系统:要么使用 `dd` 命令烧录 SD 卡,或者使用 `fedora-arm-installer` 工具。Fedora 的 Wiki 里面提供了为 IoT [设置物理设备][5] 的更多信息。另外,你可能需要调整第三个分区的大小。
|
||||
|
||||
把 SD 卡插入到设备后,你需要创建一个用户来完成安装。这个步骤需要串行连接或一个 HDMI 显示器和键盘来与设备进行交互。
|
||||
|
||||
当系统安装完成后,下一步就是要设置网络连接。使用你刚才创建的用户登录系统,可以使用下列方式之一完成网络连接设置:
|
||||
|
||||
* 如果你需要手动配置你的网络,可能需要执行类似如下命令,需要保证设置正确的网络地址:
|
||||
|
||||
```
|
||||
$ nmcli connection add con-name cable ipv4.addresses \
|
||||
192.168.0.10/24 ipv4.gateway 192.168.0.1 \
|
||||
connection.autoconnect true ipv4.dns "8.8.8.8,1.1.1.1" \
|
||||
type ethernet ifname eth0 ipv4.method manual
|
||||
```
|
||||
|
||||
* 如果你网络上运行着 DHCP 服务,可能需要类似如下命令:
|
||||
|
||||
```
|
||||
$ nmcli con add type ethernet con-name cable ifname eth0
|
||||
```
|
||||
|
||||
### Fedora 中的 GPIO 接口
|
||||
|
||||
许多关于 Linux 上 GPIO 的教程都关注传统的 GPIO sysfis 接口。这个接口已经不推荐使用了,并且上游 Linux 内核社区由于安全和其他问题的缘故打算完全删除它。
|
||||
|
||||
Fedora 已经不将这个传统的接口编译到内核了,因此在系统上没有 `/sys/class/gpio` 这个文件。此教程使用一个上游内核提供的一个新的字符设备 `/dev/gpiochipN` 。这是目前和 GPIO 交互的方式。
|
||||
|
||||
为了和这个新设备进行交互,你需要使用一个库和一系列命令行界面的工具。常用的命令行工具比如说 `echo` 和 `cat` 在此设备上无法正常工作。
|
||||
|
||||
你可以通过安装 libgpiod-utils 包来安装命令行界面工具。python3-libgpiod 包提供了相应的 Python 库。
|
||||
|
||||
### 使用 Podman 来创建一个容器
|
||||
|
||||
[Podman][6] 是一个容器运行环境,其命令行界面类似于 Docker。Podman 的一大优势是它不会在后台运行任何守护进程。这对于资源有限的设备尤其有用。Podman 还允许您使用 systemd 单元文件启动容器化服务。此外,它还有许多其他功能。
|
||||
|
||||
我们使用如下两步来创建一个容器:
|
||||
|
||||
1. 创建包含所需包的分层镜像。
|
||||
2. 使用分层镜像创建一个新容器。
|
||||
|
||||
首先创建一个 Dockerfile 文件,内容如下。这些内容告诉 Podman 基于可使用的最新 Fedora 镜像来构建我们的分层镜像。然后就是更新系统和安装一些软件包:
|
||||
|
||||
```
|
||||
FROM fedora:latest
|
||||
RUN dnf -y update
|
||||
RUN dnf -y install libgpiod-utils python3-libgpiod
|
||||
```
|
||||
|
||||
这样你就完成了镜像的生成前的配置工作,这个镜像基于最新的 Fedora,而且包含了和 GPIO 交互的软件包。
|
||||
|
||||
现在你就可以运行如下命令来构建你的基本镜像了:
|
||||
|
||||
```
|
||||
$ sudo podman build --tag fedora:gpiobase -f ./Dockerfile
|
||||
```
|
||||
|
||||
你已经成功创建了你的自定义镜像。这样以后你就可以不用每次都重新搭建环境了,而是基于你创建的镜像来完成工作。
|
||||
|
||||
### 使用 Podman 完成工作
|
||||
|
||||
为了确认当前的镜像是否就绪,可以运行如下命令:
|
||||
|
||||
```
|
||||
$ sudo podman images
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
localhost/fedora gpiobase 67a2b2b93b4b 10 minutes ago 488MB
|
||||
docker.io/library/fedora latest c18042d7fac6 2 days ago 300MB
|
||||
```
|
||||
|
||||
现在,启动容器并进行一些实际的实验。容器通常是隔离的,无法访问主机系统,包括 GPIO 接口。因此需要在启动容器时将其挂载在容器内。可以使用以下命令中的 `-device` 选项来解决:
|
||||
|
||||
```
|
||||
$ sudo podman run -it --name gpioexperiment --device=/dev/gpiochip0 localhost/fedora:gpiobase /bin/bash
|
||||
```
|
||||
|
||||
运行之后就进入了正在运行的容器中。在继续之前,这里有一些容器命令。输入 `exit` 或者按下 `Ctrl+D` 来退出容器。
|
||||
|
||||
显示所有存在的容器可以运行如下命令,这包括当前没有运行的,比如你刚刚创建的那个:
|
||||
|
||||
```
|
||||
$ sudo podman container ls -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
64e661d5d4e8 localhost/fedora:gpiobase /bin/bash 37 seconds ago Exited (0) Less than a second ago gpioexperiment
|
||||
```
|
||||
|
||||
使用如下命令创建一个新的容器:
|
||||
|
||||
```
|
||||
$ sudo podman run -it --name newexperiment --device=/dev/gpiochip0 localhost/fedora:gpiobase /bin/bash
|
||||
|
||||
```
|
||||
|
||||
如果想删除容器可以使用如下命令:
|
||||
|
||||
```
|
||||
$ sudo podman rm newexperiment
|
||||
|
||||
```
|
||||
|
||||
### 点亮 LED 灯
|
||||
|
||||
现在可以使用已创建的容器。如果已经从容器退出,请使用以下命令再次启动它:
|
||||
|
||||
```
|
||||
$ sudo podman start -ia gpioexperiment
|
||||
```
|
||||
|
||||
如前所述,可以使用 Fedora 中 libgpiod-utils 包提供的命令行工具。要列出可用的 GPIO 芯片可以使用如下命令:
|
||||
|
||||
```
|
||||
$ gpiodetect
|
||||
gpiochip0 [pinctrl-bcm2835] (54 lines)
|
||||
```
|
||||
|
||||
要获取特定芯片的连线列表,请运行:
|
||||
|
||||
```
|
||||
$ gpioinfo gpiochip0
|
||||
```
|
||||
|
||||
请注意,物理引脚数与前一个命令所打印的连线数之间没有相关性。重要的是 BCM 编号,如 [pinout.xyz][7] 所示。建议不要使用没有相应 BCM 编号的连线。
|
||||
|
||||
现在,将 LED 连接到物理引脚 40,也就是 BCM 21。请记住:LED 的短腿(负极,称为阴极)必须连接到带有 330 欧姆电阻的树莓派的 GND 引脚, 并且长腿(阳极)到物理引脚 40。
|
||||
|
||||
运行以下命令点亮 LED,按下 `Ctrl + C` 关闭:
|
||||
|
||||
```
|
||||
$ gpioset --mode=wait gpiochip0 21=1
|
||||
```
|
||||
|
||||
要点亮一段时间,请添加 `-b`(在后台运行)和 `-s NUM`(多少秒)参数,如下所示。 例如,要点亮 LED 5 秒钟,运行如下命令:
|
||||
|
||||
```
|
||||
$ gpioset -b -s 5 --mode=time gpiochip0 21=1
|
||||
```
|
||||
|
||||
另一个有用的命令是 `gpioget`。 它可以获得引脚的状态(高或低),可用于检测按钮和开关。
|
||||
|
||||
![Closeup of LED connection with GPIO][8]
|
||||
|
||||
### 总结
|
||||
|
||||
你也可以使用 Python 操控 LED —— [这里有一些例子][9]。 也可以在容器内使用 i2c 设备。 此外,Podman 与此 Fedora 版本并不严格相关。你可以在任何现有的 Fedora 版本上安装它,或者在 Fedora 中使用两个基于 OSTree 的新系统进行尝试:[Fedora Silverblue][2] 和 [Fedora CoreOS][10]。
|
||||
|
||||
------
|
||||
|
||||
via: https://fedoramagazine.org/turnon-led-fedora-iot/
|
||||
|
||||
作者:[Alessio Ciregia][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[ScarboroughCoral](https://github.com/ScarboroughCoral)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://alciregi.id.fedoraproject.org/
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2018/08/oled-1024x768.png
|
||||
[2]: https://teamsilverblue.org/
|
||||
[3]: https://www.projectatomic.io/
|
||||
[4]: https://kojipkgs.fedoraproject.org/compose/iot/latest-Fedora-IoT-28/compose/IoT/
|
||||
[5]: https://fedoraproject.org/wiki/InternetOfThings/GettingStarted#Setting_up_a_Physical_Device
|
||||
[6]: https://github.com/containers/libpod
|
||||
[7]: https://pinout.xyz/
|
||||
[8]: https://fedoramagazine.org/wp-content/uploads/2018/08/breadboard-1024x768.png
|
||||
[9]: https://github.com/brgl/libgpiod/tree/master/bindings/python/examples
|
||||
[10]: https://coreos.fedoraproject.org/
|
||||
[11]: https://fedoramagazine.org/announcing-fedora-29/
|
@ -1,4 +1,4 @@
|
||||
实验 5:文件系统、Spawn 和 Shell
|
||||
Caffeinated 6.828:实验 5:文件系统、Spawn 和 Shell
|
||||
======
|
||||
|
||||
### 简介
|
||||
@ -10,31 +10,31 @@
|
||||
使用 Git 去获取最新版的课程仓库,然后创建一个命名为 `lab5` 的本地分支,去跟踪远程的 `origin/lab5` 分支:
|
||||
|
||||
```
|
||||
athena% cd ~/6.828/lab
|
||||
athena% add git
|
||||
athena% git pull
|
||||
Already up-to-date.
|
||||
athena% git checkout -b lab5 origin/lab5
|
||||
Branch lab5 set up to track remote branch refs/remotes/origin/lab5.
|
||||
Switched to a new branch "lab5"
|
||||
athena% git merge lab4
|
||||
Merge made by recursive.
|
||||
.....
|
||||
athena%
|
||||
athena% cd ~/6.828/lab
|
||||
athena% add git
|
||||
athena% git pull
|
||||
Already up-to-date.
|
||||
athena% git checkout -b lab5 origin/lab5
|
||||
Branch lab5 set up to track remote branch refs/remotes/origin/lab5.
|
||||
Switched to a new branch "lab5"
|
||||
athena% git merge lab4
|
||||
Merge made by recursive.
|
||||
.....
|
||||
athena%
|
||||
```
|
||||
|
||||
在实验中这一部分的主要新组件是文件系统环境,它位于新的 `fs` 目录下。通过检查这个目录中的所有文件,我们来看一下新的文件都有什么。另外,在 `user` 和 `lib` 目录下还有一些文件系统相关的源文件。
|
||||
|
||||
fs/fs.c 维护文件系统在磁盘上结构的代码
|
||||
fs/bc.c 构建在我们的用户级页故障处理功能之上的一个简单的块缓存
|
||||
fs/ide.c 极简的基于 PIO(非中断驱动的)IDE 驱动程序代码
|
||||
fs/serv.c 使用文件系统 IPC 与客户端环境交互的文件系统服务器
|
||||
lib/fd.c 实现一个常见的类 UNIX 的文件描述符接口的代码
|
||||
lib/file.c 磁盘上文件类型的驱动,实现为一个文件系统 IPC 客户端
|
||||
lib/console.c 控制台输入/输出文件类型的驱动
|
||||
lib/spawn.c spawn 库调用的框架代码
|
||||
- `fs/fs.c` 维护文件系统在磁盘上结构的代码
|
||||
- `fs/bc.c` 构建在我们的用户级页故障处理功能之上的一个简单的块缓存
|
||||
- `fs/ide.c` 极简的基于 PIO(非中断驱动的)IDE 驱动程序代码
|
||||
- `fs/serv.c` 使用文件系统 IPC 与客户端环境交互的文件系统服务器
|
||||
- `lib/fd.c` 实现一个常见的类 UNIX 的文件描述符接口的代码
|
||||
- `lib/file.c` 磁盘上文件类型的驱动,实现为一个文件系统 IPC 客户端
|
||||
- `lib/console.c` 控制台输入/输出文件类型的驱动
|
||||
- `lib/spawn.c` spawn 库调用的框架代码
|
||||
|
||||
你应该再次去运行 `pingpong`、`primes`、和 `forktree`,测试实验 4 完成后合并到新的实验 5 中的代码能否正确运行。你还需要在 `kern/init.c` 中注释掉 `ENV_CREATE(fs_fs)` 行,因为 `fs/fs.c` 将尝试去做一些 I/O,而 JOS 到目前为止还不具备该功能。同样,在 `lib/exit.c` 中临时注释掉对 `close_all()` 的调用;这个函数将调用你在本实验后面部分去实现的子程序,如果现在去调用,它将导致 JOS 内核崩溃。如果你的实验 4 的代码没有任何 bug,将很完美地通过这个测试。在它们都能正常工作之前是不能继续后续实验的。在你开始做练习 1 时,不要忘记去取消这些行上的注释。
|
||||
你应该再次去运行 `pingpong`、`primes` 和 `forktree`,测试实验 4 完成后合并到新的实验 5 中的代码能否正确运行。你还需要在 `kern/init.c` 中注释掉 `ENV_CREATE(fs_fs)` 行,因为 `fs/fs.c` 将尝试去做一些 I/O,而 JOS 到目前为止还不具备该功能。同样,在 `lib/exit.c` 中临时注释掉对 `close_all()` 的调用;这个函数将调用你在本实验后面部分去实现的子程序,如果现在去调用,它将导致 JOS 内核崩溃。如果你的实验 4 的代码没有任何 bug,将很完美地通过这个测试。在它们都能正常工作之前是不能继续后续实验的。在你开始做练习 1 时,不要忘记去取消这些行上的注释。
|
||||
|
||||
如果它们不能正常工作,使用 `git diff lab4` 去重新评估所有的变更,确保你在实验 4(及以前)所写的代码在本实验中没有丢失。确保实验 4 仍然能正常工作。
|
||||
|
||||
@ -44,11 +44,11 @@ lib/spawn.c spawn 库调用的框架代码
|
||||
|
||||
### 文件系统的雏形
|
||||
|
||||
你将要使用的文件系统比起大多数“真正的”文件系统(包括 xv6 UNIX 的文件系统)要简单的多,但它也是很强大的,足够去提供基本的特性:创建、读取、写入、和删除组织在层次目录结构中的文件。
|
||||
你将要使用的文件系统比起大多数“真正的”文件系统(包括 xv6 UNIX 的文件系统)要简单的多,但它也是很强大的,足够去提供基本的特性:创建、读取、写入和删除组织在层次目录结构中的文件。
|
||||
|
||||
到目前为止,我们开发的是一个单用户操作系统,它提供足够的保护并能去捕获 bug,但它还不能在多个不可信用户之间提供保护。因此,我们的文件系统还不支持 UNIX 的所有者或权限的概念。我们的文件系统目前也不支持硬链接、时间戳、或像大多数 UNIX 文件系统实现的那些特殊的设备文件。
|
||||
|
||||
### 磁盘上文件系统结构
|
||||
### 磁盘上的文件系统结构
|
||||
|
||||
主流的 UNIX 文件系统将可用磁盘空间分为两种主要的区域类型:节点区域和数据区域。UNIX 文件系统在文件系统中为每个文件分配一个节点;一个文件的节点保存了这个文件重要的元数据,比如它的 `stat` 属性和指向数据块的指针。数据区域被分为更大的(一般是 8 KB 或更大)数据块,它在文件系统中存储文件数据和目录元数据。目录条目包含文件名字和指向到节点的指针;如果文件系统中的多个目录条目指向到那个文件的节点上,则称该文件是硬链接的。由于我们的文件系统不支持硬链接,所以我们不需要这种间接的级别,并且因此可以更方便简化:我们的文件系统将压根就不使用节点,而是简单地将文件的(或子目录的)所有元数据保存在描述那个文件的(唯一的)目录条目中。
|
||||
|
||||
@ -71,6 +71,7 @@ UNIX xv6 文件系统使用 512 字节大小的块,与它底层磁盘的扇区
|
||||
#### 文件元数据
|
||||
|
||||
![File structure][2]
|
||||
|
||||
元数据的布局是描述在我们的文件系统中的一个文件中,这个文件就是 `inc/fs.h` 中的 `struct File`。元数据包含文件的名字、大小、类型(普通文件还是目录)、指向构成这个文件的块的指针。正如前面所提到的,我们的文件系统中并没有节点,因此元数据是保存在磁盘上的一个目录条目中,而不是像大多数“真正的”文件系统那样保存在节点中。为简单起见,我们将使用 `File` 这一个结构去表示文件元数据,因为它要同时出现在磁盘上和内存中。
|
||||
|
||||
在 `struct File` 中的数组 `f_direct` 包含一个保存文件的前 10 个块(`NDIRECT`)的块编号的空间,我们称之为文件的直接块。对于最大 `10*4096 = 40KB` 的小文件,这意味着这个文件的所有块的块编号将全部直接保存在结构 `File` 中,但是,对于超过 40 KB 大小的文件,我们需要一个地方去保存文件剩余的块编号。所以我们分配一个额外的磁盘块,我们称之为文件的间接块,由它去保存最多 4096/4 = 1024 个额外的块编号。因此,我们的文件系统最多允许有 1034 个块,或者说不能超过 4MB 大小。为支持大文件,“真正的”文件系统一般都支持两个或三个间接块。
|
||||
@ -91,33 +92,28 @@ UNIX xv6 文件系统使用 512 字节大小的块,与它底层磁盘的扇区
|
||||
|
||||
只要我们依赖轮询、基于 “编程的 I/O”(PIO)的磁盘访问,并且不使用磁盘中断,那么在用户空间中实现磁盘访问还是很容易的。也可以去实现由中断驱动的设备驱动程序(比如像 L3 和 L4 内核就是这么做的),但这样做的话,内核必须接收设备中断并将它派发到相应的用户模式环境上,这样实现的难度会更大。
|
||||
|
||||
x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的代码是否允许执行特定的设备 I/O 指令,比如 `IN` 和 `OUT` 指令。由于我们需要的所有 IDE 磁盘寄存器都位于 x86 的 I/O 空间中而不是映射在内存中,所以,为了允许文件系统去访问这些寄存器,我们需要做的唯一的事情便是授予文件系统环境“I/O 权限”。实际上,在 EFLAGS 寄存器的 IOPL 位上规定,内核使用一个简单的“要么全都能访问、要么全都不能访问”的方法来控制用户模式中的代码能否访问 I/O 空间。在我们的案例中,我们希望文件系统环境能够去访问 I/O 空间,但我们又希望任何其它的环境完全不能访问 I/O 空间。
|
||||
x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的代码是否允许执行特定的设备 I/O 指令,比如 `IN` 和 `OUT` 指令。由于我们需要的所有 IDE 磁盘寄存器都位于 x86 的 I/O 空间中而不是映射在内存中,所以,为了允许文件系统去访问这些寄存器,我们需要做的唯一的事情便是授予文件系统环境“I/O 权限”。实际上,在 EFLAGS 寄存器的 IOPL 位上规定,内核使用一个简单的“要么全都能访问、要么全都不能访问”的方法来控制用户模式中的代码能否访问 I/O 空间。在我们的案例中,我们希望文件系统环境能够去访问 I/O 空间,但我们又希望任何其它的环境完全不能访问 I/O 空间。
|
||||
|
||||
```markdown
|
||||
练习 1、`i386_init` 通过将类型 `ENV_TYPE_FS` 传递给你的环境创建函数 `env_create` 来识别文件系统。修改 `env.c` 中的 `env_create` ,以便于它只授予文件系统环境 I/O 的权限,而不授予任何其它环境 I/O 的权限。
|
||||
> **练习 1**、`i386_init` 通过将类型 `ENV_TYPE_FS` 传递给你的环境创建函数 `env_create` 来识别文件系统。修改 `env.c` 中的 `env_create` ,以便于它只授予文件系统环境 I/O 的权限,而不授予任何其它环境 I/O 的权限。
|
||||
|
||||
确保你能启动这个文件系统环境,而不会产生一般保护故障。你应该要通过在 `make grade` 中的 "fs i/o" 测试。
|
||||
```
|
||||
> 确保你能启动这个文件系统环境,而不会产生一般保护故障。你应该要通过在 `make grade` 中的 "fs i/o" 测试。
|
||||
|
||||
```markdown
|
||||
问题
|
||||
|
||||
1、当你从一个环境切换到另一个环境时,你是否需要做一些操作来确保 I/O 权限设置能被保存和正确地恢复?为什么?
|
||||
```
|
||||
.
|
||||
|
||||
> **问题 1**、当你从一个环境切换到另一个环境时,你是否需要做一些操作来确保 I/O 权限设置能被保存和正确地恢复?为什么?
|
||||
|
||||
注意本实验中的 `GNUmakefile` 文件,它用于设置 QEMU 去使用文件 `obj/kern/kernel.img` 作为磁盘 0 的镜像(一般情况下表示 DOS 或 Windows 中的 “C 盘”),以及使用(新)文件 `obj/fs/fs.img` 作为磁盘 1 的镜像(”D 盘“)。在本实验中,我们的文件系统应该仅与磁盘 1 有交互;而磁盘 0 仅用于去引导内核。如果你想去恢复其中一个有某些错误的磁盘镜像,你可以通过输入如下的命令,去重置它们到最初的、”崭新的“版本:
|
||||
|
||||
```
|
||||
$ rm obj/kern/kernel.img obj/fs/fs.img
|
||||
$ make
|
||||
$ rm obj/kern/kernel.img obj/fs/fs.img
|
||||
$ make
|
||||
```
|
||||
|
||||
或者:
|
||||
|
||||
```
|
||||
$ make clean
|
||||
$ make
|
||||
$ make clean
|
||||
$ make
|
||||
```
|
||||
|
||||
小挑战!实现中断驱动的 IDE 磁盘访问,既可以使用也可以不使用 DMA 模式。由你来决定是否将设备驱动移植进内核中、还是与文件系统一样保留在用户空间中、甚至是将它移植到一个它自己的的单独的环境中(如果你真的想了解微内核的本质的话)。
|
||||
@ -132,45 +128,39 @@ x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的
|
||||
|
||||
当然,将整个磁盘读入到内存中需要很长时间,因此,我们将它实现成”按需“分页的形式,那样我们只在磁盘映射区域中分配页,并且当在这个区域中产生页故障时,从磁盘读取相关的块去响应这个页故障。通过这种方式,我们能够假装将整个磁盘装进了内存中。
|
||||
|
||||
```markdown
|
||||
练习 2、在 `fs/bc.c` 中实现 `bc_pgfault` 和 `flush_block` 函数。`bc_pgfault` 函数是一个页故障服务程序,就像你在前一个实验中编写的写时复制 fork 一样,只不过它的任务是从磁盘中加载页去响应一个页故障。在你编写它时,记住: (1) `addr` 可能并不会做边界对齐,并且 (2) 在扇区中的 `ide_read` 操作并不是以块为单位的。
|
||||
> **练习 2**、在 `fs/bc.c` 中实现 `bc_pgfault` 和 `flush_block` 函数。`bc_pgfault` 函数是一个页故障服务程序,就像你在前一个实验中编写的写时复制 fork 一样,只不过它的任务是从磁盘中加载页去响应一个页故障。在你编写它时,记住: (1) `addr` 可能并不会做边界对齐,并且 (2) 在扇区中的 `ide_read` 操作并不是以块为单位的。
|
||||
|
||||
(如果需要的话)函数 `flush_block` 应该会将一个块写入到磁盘上。如果在块缓存中没有块(也就是说,页没有映射)或者它不是一个脏块,那么 `flush_block` 将什么都不做。我们将使用虚拟内存硬件去跟踪,磁盘块自最后一次从磁盘读取或写入到磁盘之后是否被修改过。查看一个块是否需要写入时,我们只需要去查看 `uvpt` 条目中的 `PTE_D` 的 ”dirty“ 位即可。(`PTE_D` 位由处理器设置,用于表示那个页被写入;具体细节可以查看 x386 参考手册的 [第 5 章][3] 的 5.2.4.3 节)块被写入到磁盘上之后,`flush_block` 函数将使用 `sys_page_map` 去清除 `PTE_D` 位。
|
||||
>(如果需要的话)函数 `flush_block` 应该会将一个块写入到磁盘上。如果在块缓存中没有块(也就是说,页没有映射)或者它不是一个脏块,那么 `flush_block` 将什么都不做。我们将使用虚拟内存硬件去跟踪,磁盘块自最后一次从磁盘读取或写入到磁盘之后是否被修改过。查看一个块是否需要写入时,我们只需要去查看 `uvpt` 条目中的 `PTE_D` 的 ”dirty“ 位即可。(`PTE_D` 位由处理器设置,用于表示那个页被写入;具体细节可以查看 x386 参考手册的 [第 5 章][3] 的 5.2.4.3 节)块被写入到磁盘上之后,`flush_block` 函数将使用 `sys_page_map` 去清除 `PTE_D` 位。
|
||||
|
||||
使用 `make grade` 去测试你的代码。你的代码应该能够通过 "check_bc"、"check_super"、和 "check_bitmap" 的测试。
|
||||
```
|
||||
> 使用 `make grade` 去测试你的代码。你的代码应该能够通过 "check_bc"、"check_super"、和 "check_bitmap" 的测试。
|
||||
|
||||
在 `fs/fs.c` 中的函数 `fs_init` 是块缓存使用的一个很好的示例。在初始化块缓存之后,它简单地在全局变量 `super` 中保存指针到磁盘映射区。在这之后,如果块在内存中,或我们的页故障服务程序按需将它们从磁盘上读入后,我们就能够简单地从 `super` 结构中读取块了。
|
||||
|
||||
```markdown
|
||||
小挑战!到现在为止,块缓存还没有清除策略。一旦某个块因为页故障被读入到缓存中之后,它将一直不会被清除,并且永远保留在内存中。给块缓存增加一个清除策略。在页表中使用 `PTE_A` 的 "accessed" 位来实现,任何环境访问一个页时,硬件就会设置这个位,你可以通过它来跟踪磁盘块的大致使用情况,而不需要修改访问磁盘映射区域的任何代码。使用脏块要小心。
|
||||
```
|
||||
.
|
||||
|
||||
> **小挑战!**到现在为止,块缓存还没有清除策略。一旦某个块因为页故障被读入到缓存中之后,它将一直不会被清除,并且永远保留在内存中。给块缓存增加一个清除策略。在页表中使用 `PTE_A` 的 "accessed" 位来实现,任何环境访问一个页时,硬件就会设置这个位,你可以通过它来跟踪磁盘块的大致使用情况,而不需要修改访问磁盘映射区域的任何代码。使用脏块要小心。
|
||||
|
||||
### 块位图
|
||||
|
||||
在 `fs_init` 设置了 `bitmap` 指针之后,我们可以认为 `bitmap` 是一个装满比特位的数组,磁盘上的每个块就是数组中的其中一个比特位。比如 `block_is_free`,它只是简单地在位图中检查给定的块是否被标记为空闲。
|
||||
|
||||
```markdown
|
||||
练习 3、使用 `free_block` 作为实现 `fs/fs.c` 中的 `alloc_block` 的一个模型,它将在位图中去查找一个空闲的磁盘块,并将它标记为已使用,然后返回块编号。当你分配一个块时,你应该立即使用 `flush_block` 将已改变的位图块刷新到磁盘上,以确保文件系统的一致性。
|
||||
> **练习 3**、使用 `free_block` 作为实现 `fs/fs.c` 中的 `alloc_block` 的一个模型,它将在位图中去查找一个空闲的磁盘块,并将它标记为已使用,然后返回块编号。当你分配一个块时,你应该立即使用 `flush_block` 将已改变的位图块刷新到磁盘上,以确保文件系统的一致性。
|
||||
|
||||
使用 `make grade` 去测试你的代码。现在,你的代码应该要通过 "alloc_block" 的测试。
|
||||
```
|
||||
> 使用 `make grade` 去测试你的代码。现在,你的代码应该要通过 "alloc_block" 的测试。
|
||||
|
||||
### 文件操作
|
||||
|
||||
在 `fs/fs.c` 中,我们提供一系列的函数去实现基本的功能,比如,你将需要去理解和管理结构 `File`、扫描和管理目录”文件“的条目、 以及从根目录开始遍历文件系统以解析一个绝对路径名。阅读 `fs/fs.c` 中的所有代码,并在你开始实验之前,确保你理解了每个函数的功能。
|
||||
|
||||
```markdown
|
||||
练习 4、实现 `file_block_walk` 和 `file_get_block`。`file_block_walk` 从一个文件中的块偏移量映射到 `struct File` 中那个块的指针上或间接块上,它非常类似于 `pgdir_walk` 在页表上所做的事。`file_get_block` 将更进一步,将去映射一个真实的磁盘块,如果需要的话,去分配一个新的磁盘块。
|
||||
> **练习 4**、实现 `file_block_walk` 和 `file_get_block`。`file_block_walk` 从一个文件中的块偏移量映射到 `struct File` 中那个块的指针上或间接块上,它非常类似于 `pgdir_walk` 在页表上所做的事。`file_get_block` 将更进一步,将去映射一个真实的磁盘块,如果需要的话,去分配一个新的磁盘块。
|
||||
|
||||
使用 `make grade` 去测试你的代码。你的代码应该要通过 "file_open"、"file_get_block"、以及 "file_flush/file_truncated/file rewrite"、和 "testfile" 的测试。
|
||||
```
|
||||
> 使用 `make grade` 去测试你的代码。你的代码应该要通过 "file_open"、"file_get_block"、以及 "file_flush/file_truncated/file rewrite"、和 "testfile" 的测试。
|
||||
|
||||
`file_block_walk` 和 `file_get_block` 是文件系统中的”劳动模范“。比如,`file_read` 和 `file_write` 或多或少都在 `file_get_block` 上做必需的登记工作,然后在分散的块和连续的缓存之间复制字节。
|
||||
|
||||
```
|
||||
小挑战!如果操作在中途实然被打断(比如,突然崩溃或重启),文件系统很可能会产生错误。实现软件更新或日志处理的方式让文件系统的”崩溃可靠性“更好,并且演示一下旧的文件系统可能会崩溃,而你的更新后的文件系统不会崩溃的情况。
|
||||
```
|
||||
.
|
||||
|
||||
> **小挑战!**如果操作在中途实然被打断(比如,突然崩溃或重启),文件系统很可能会产生错误。实现软件更新或日志处理的方式让文件系统的”崩溃可靠性“更好,并且演示一下旧的文件系统可能会崩溃,而你的更新后的文件系统不会崩溃的情况。
|
||||
|
||||
### 文件系统接口
|
||||
|
||||
@ -207,19 +197,17 @@ x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的
|
||||
|
||||
服务器也通过 IPC 来发送响应。我们为函数的返回代码使用 32 位的数字。对于大多数 RPC,这已经涵盖了它们全部的返回代码。`FSREQ_READ` 和 `FSREQ_STAT` 也返回数据,它们只是被简单地写入到客户端发送它的请求时的页上。在 IPC 的响应中并不需要去发送这个页,因为这个页是文件系统服务器和客户端从一开始就共享的页。另外,在它的响应中,`FSREQ_OPEN` 与客户端共享一个新的 "Fd page”。我们将快捷地返回到文件描述符页上。
|
||||
|
||||
```markdown
|
||||
练习 5、实现 `fs/serv.c` 中的 `serve_read`。
|
||||
> **练习 5**、实现 `fs/serv.c` 中的 `serve_read`。
|
||||
|
||||
`serve_read` 的重任将由已经在 `fs/fs.c` 中实现的 `file_read` 来承担(它实际上不过是对 `file_get_block` 的一连串调用)。对于文件读取,`serve_read` 只能提供 RPC 接口。查看 `serve_set_size` 中的注释和代码,去大体上了解服务器函数的结构。
|
||||
> `serve_read` 的重任将由已经在 `fs/fs.c` 中实现的 `file_read` 来承担(它实际上不过是对 `file_get_block` 的一连串调用)。对于文件读取,`serve_read` 只能提供 RPC 接口。查看 `serve_set_size` 中的注释和代码,去大体上了解服务器函数的结构。
|
||||
|
||||
使用 `make grade` 去测试你的代码。你的代码通过 "serve_open/file_stat/file_close" 和 "file_read" 的测试后,你得分应该是 70(总分为 150)。
|
||||
```
|
||||
> 使用 `make grade` 去测试你的代码。你的代码通过 "serve_open/file_stat/file_close" 和 "file_read" 的测试后,你得分应该是 70(总分为 150)。
|
||||
|
||||
```markdown
|
||||
练习 6、实现 `fs/serv.c` 中的 `serve_write` 和 `lib/file.c` 中的 `devfile_write`。
|
||||
.
|
||||
|
||||
使用 `make grade` 去测试你的代码。你的代码通过 "file_write"、"file_read after file_write"、"open"、和 "large file" 的测试后,得分应该是 90(总分为150)。
|
||||
```
|
||||
> **练习 6**、实现 `fs/serv.c` 中的 `serve_write` 和 `lib/file.c` 中的 `devfile_write`。
|
||||
|
||||
> 使用 `make grade` 去测试你的代码。你的代码通过 "file_write"、"file_read after file_write"、"open"、和 "large file" 的测试后,得分应该是 90(总分为150)。
|
||||
|
||||
### 进程增殖
|
||||
|
||||
@ -227,21 +215,19 @@ x86 处理器在 EFLAGS 寄存器中使用 IOPL 位去确定保护模式中的
|
||||
|
||||
我们实现的是 `spawn`,而不是一个类 UNIX 的 `exec`,因为 `spawn` 是很容易从用户空间中、以”外内核式“ 实现的,它无需来自内核的特别帮助。为了在用户空间中实现 `exec`,想一想你应该做什么?确保你理解了它为什么很难。
|
||||
|
||||
```markdown
|
||||
练习 7、`spawn` 依赖新的系统调用 `sys_env_set_trapframe` 去初始化新创建的环境的状态。实现 `kern/syscall.c` 中的 `sys_env_set_trapframe`。(不要忘记在 `syscall()` 中派发新系统调用)
|
||||
> **练习 7**、`spawn` 依赖新的系统调用 `sys_env_set_trapframe` 去初始化新创建的环境的状态。实现 `kern/syscall.c` 中的 `sys_env_set_trapframe`。(不要忘记在 `syscall()` 中派发新系统调用)
|
||||
|
||||
运行来自 `kern/init.c` 中的 `user/spawnhello` 程序来测试你的代码`kern/init.c` ,它将尝试从文件系统中增殖 `/hello`。
|
||||
> 运行来自 `kern/init.c` 中的 `user/spawnhello` 程序来测试你的代码`kern/init.c` ,它将尝试从文件系统中增殖 `/hello`。
|
||||
|
||||
使用 `make grade` 去测试你的代码。
|
||||
```
|
||||
> 使用 `make grade` 去测试你的代码。
|
||||
|
||||
```markdown
|
||||
小挑战!实现 Unix 式的 `exec`。
|
||||
```
|
||||
.
|
||||
|
||||
```markdown
|
||||
小挑战!实现 `mmap` 式的文件内存映射,并如果可能的话,修改 `spawn` 从 ELF 中直接映射页。
|
||||
```
|
||||
> **小挑战!**实现 Unix 式的 `exec`。
|
||||
|
||||
.
|
||||
|
||||
> **小挑战!**实现 `mmap` 式的文件内存映射,并如果可能的话,修改 `spawn` 从 ELF 中直接映射页。
|
||||
|
||||
### 跨 fork 和 spawn 共享库状态
|
||||
|
||||
@ -255,11 +241,9 @@ UNIX 文件描述符是一个通称的概念,它还包括管道、控制台 I/
|
||||
|
||||
我们在 `inc/lib.h` 中定义了一个新的 `PTE_SHARE` 位,在 Intel 和 AMD 的手册中,这个位是被标记为”软件可使用的“的三个 PTE 位之一。我们将创建一个约定,如果一个页表条目中这个位被设置,那么在 `fork` 和 `spawn` 中应该直接从父环境中复制 PTE 到子环境中。注意它与标记为写时复制的差别:正如在第一段中所描述的,我们希望确保能共享页更新。
|
||||
|
||||
```markdown
|
||||
练习 8、修改 `lib/fork.c` 中的 `duppage`,以遵循最新约定。如果页表条目设置了 `PTE_SHARE` 位,仅直接复制映射。(你应该去使用 `PTE_SYSCALL`,而不是 `0xfff`,去从页表条目中掩掉有关的位。`0xfff` 仅选出可访问的位和脏位。)
|
||||
> **练习 8**、修改 `lib/fork.c` 中的 `duppage`,以遵循最新约定。如果页表条目设置了 `PTE_SHARE` 位,仅直接复制映射。(你应该去使用 `PTE_SYSCALL`,而不是 `0xfff`,去从页表条目中掩掉有关的位。`0xfff` 仅选出可访问的位和脏位。)
|
||||
|
||||
同样的,在 `lib/spawn.c` 中实现 `copy_shared_pages`。它应该循环遍历当前进程中所有的页表条目(就像 `fork` 那样),复制任何设置了 `PTE_SHARE` 位的页映射到子进程中。
|
||||
```
|
||||
> 同样的,在 `lib/spawn.c` 中实现 `copy_shared_pages`。它应该循环遍历当前进程中所有的页表条目(就像 `fork` 那样),复制任何设置了 `PTE_SHARE` 位的页映射到子进程中。
|
||||
|
||||
使用 `make run-testpteshare` 去检查你的代码行为是否正确。正确的情况下,你应该会看到像 "`fork handles PTE_SHARE right`" 和 "`spawn handles PTE_SHARE right`” 这样的输出行。
|
||||
|
||||
@ -269,9 +253,7 @@ UNIX 文件描述符是一个通称的概念,它还包括管道、控制台 I/
|
||||
|
||||
为了能让 shell 工作,我们需要一些方式去输入。QEMU 可以显示输出,我们将它的输出写入到 CGA 显示器上和串行端口上,但到目前为止,我们仅能够在内核监视器中接收输入。在 QEMU 中,我们从图形化窗口中的输入作为从键盘到 JOS 的输入,虽然键入到控制台的输入作为出现在串行端口上的字符的方式显现。在 `kern/console.c` 中已经包含了由我们自实验 1 以来的内核监视器所使用的键盘和串行端口的驱动程序,但现在你需要去把这些增加到系统中。
|
||||
|
||||
```markdown
|
||||
练习 9、在你的 `kern/trap.c` 中,调用 `kbd_intr` 去处理捕获 `IRQ_OFFSET+IRQ_KBD` 和 `serial_intr`,用它们去处理捕获 `IRQ_OFFSET+IRQ_SERIAL`。
|
||||
```
|
||||
> **练习 9**、在你的 `kern/trap.c` 中,调用 `kbd_intr` 去处理捕获 `IRQ_OFFSET+IRQ_KBD` 和 `serial_intr`,用它们去处理捕获 `IRQ_OFFSET+IRQ_SERIAL`。
|
||||
|
||||
在 `lib/console.c` 中,我们为你实现了文件的控制台输入/输出。`kbd_intr` 和 `serial_intr` 将使用从最新读取到的输入来填充缓冲区,而控制台文件类型去排空缓冲区(默认情况下,控制台文件类型为 stdin/stdout,除非用户重定向它们)。
|
||||
|
||||
@ -282,40 +264,38 @@ UNIX 文件描述符是一个通称的概念,它还包括管道、控制台 I/
|
||||
运行 `make run-icode` 或 `make run-icode-nox` 将运行你的内核并启动 `user/icode`。`icode` 又运行 `init`,它将设置控制台作为文件描述符 0 和 1(即:标准输入 stdin 和标准输出 stdout),然后增殖出环境 `sh`,就是 shell。之后你应该能够运行如下的命令了:
|
||||
|
||||
```
|
||||
echo hello world | cat
|
||||
cat lorem |cat
|
||||
cat lorem |num
|
||||
cat lorem |num |num |num |num |num
|
||||
lsfd
|
||||
echo hello world | cat
|
||||
cat lorem |cat
|
||||
cat lorem |num
|
||||
cat lorem |num |num |num |num |num
|
||||
lsfd
|
||||
```
|
||||
|
||||
注意用户库常规程序 `cprintf` 将直接输出到控制台,而不会使用文件描述符代码。这对调试非常有用,但是对管道连接其它程序却很不利。为将输出打印到特定的文件描述符(比如 1,它是标准输出 stdout),需要使用 `fprintf(1, "...", ...)`。`printf("...", ...)` 是将输出打印到文件描述符 1(标准输出 stdout) 的快捷方式。查看 `user/lsfd.c` 了解更多示例。
|
||||
|
||||
```markdown
|
||||
练习 10、
|
||||
这个 shell 不支持 I/O 重定向。如果能够运行 `run sh <script` 就更完美了,就不用将所有的命令手动去放入一个脚本中,就像上面那样。为 `<` 在 `user/sh.c` 中添加重定向的功能。
|
||||
> **练习 10**、这个 shell 不支持 I/O 重定向。如果能够运行 `run sh <script` 就更完美了,就不用将所有的命令手动去放入一个脚本中,就像上面那样。为 `<` 在 `user/sh.c` 中添加重定向的功能。
|
||||
|
||||
通过在你的 shell 中输入 `sh <script` 来测试你实现的重定向功能。
|
||||
> 通过在你的 shell 中输入 `sh <script` 来测试你实现的重定向功能。
|
||||
|
||||
运行 `make run-testshell` 去测试你的 shell。`testshell` 只是简单地给 shell ”喂“上面的命令(也可以在 `fs/testshell.sh` 中找到),然后检查它的输出是否与 `fs/testshell.key` 一样。
|
||||
```
|
||||
> 运行 `make run-testshell` 去测试你的 shell。`testshell` 只是简单地给 shell ”喂“上面的命令(也可以在 `fs/testshell.sh` 中找到),然后检查它的输出是否与 `fs/testshell.key` 一样。
|
||||
|
||||
```markdown
|
||||
小挑战!给你的 shell 添加更多的特性。最好包括以下的特性(其中一些可能会要求修改文件系统):
|
||||
.
|
||||
|
||||
* 后台命令 (`ls &`)
|
||||
* 一行中运行多个命令 (`ls; echo hi`)
|
||||
* 命令组 (`(ls; echo hi) | cat > out`)
|
||||
* 扩展环境变量 (`echo $hello`)
|
||||
* 引号 (`echo "a | b"`)
|
||||
* 命令行历史和/或编辑功能
|
||||
* tab 命令补全
|
||||
* 为命令行查找目录、cd 和路径
|
||||
* 文件创建
|
||||
* 用快捷键 `ctl-c` 去杀死一个运行中的环境
|
||||
|
||||
可做的事情还有很多,并不仅限于以上列表。
|
||||
```
|
||||
> **小挑战!**给你的 shell 添加更多的特性。最好包括以下的特性(其中一些可能会要求修改文件系统):
|
||||
|
||||
> * 后台命令 (`ls &`)
|
||||
> * 一行中运行多个命令 (`ls; echo hi`)
|
||||
> * 命令组 (`(ls; echo hi) | cat > out`)
|
||||
> * 扩展环境变量 (`echo $hello`)
|
||||
> * 引号 (`echo "a | b"`)
|
||||
> * 命令行历史和/或编辑功能
|
||||
> * tab 命令补全
|
||||
> * 为命令行查找目录、cd 和路径
|
||||
> * 文件创建
|
||||
> * 用快捷键 `ctl-c` 去杀死一个运行中的环境
|
||||
|
||||
> 可做的事情还有很多,并不仅限于以上列表。
|
||||
|
||||
到目前为止,你的代码应该要通过所有的测试。和以前一样,你可以使用 `make grade` 去评级你的提交,并且使用 `make handin` 上交你的实验。
|
||||
|
||||
@ -328,7 +308,7 @@ via: https://pdos.csail.mit.edu/6.828/2018/labs/lab5/
|
||||
作者:[csail.mit][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,180 @@
|
||||
通过询问-响应身份认证提高桌面登录安全
|
||||
======
|
||||
|
||||
![](https://fedoramagazine.org/wp-content/uploads/2018/10/challenge-response-816x345.png)
|
||||
|
||||
### 介绍
|
||||
|
||||
今天,Fedora 提供了多种方式来提高我们账户的身份认证的安全性。当然,它有我们熟悉的用户名密码登录方式,它也同样提供了其他的身份认证选项,比如生物识别、指纹、智能卡、一次性密码,甚至是<ruby>询问-响应<rt>challenge-response</rt></ruby>身份认证。
|
||||
|
||||
每种认证方式都有明确的优缺点。这点本身就可以成为一篇相当冗长的文章的主题。Fedora 杂志之前就已经介绍过了这其中的一些选项:
|
||||
|
||||
- [在 Fedora 中使用 YubiKey4][1]
|
||||
- [Fedora 28:在 OpenSSH 中更好的支持智能卡][2]
|
||||
|
||||
在现在的 Fedora 版本中,最安全的方法之一就是离线硬件询问-响应。它也同样是最容易部署的方法之一。下面是具体方法。
|
||||
|
||||
### 询问-响应认证
|
||||
|
||||
从技术上来讲,当你输入密码的时候,你就正在响应用户名询问。离线的询问、响应包含了这些部分:首先是需要你的用户名,接下来,Fedora 会要你提供一个加密的物理硬件的令牌。令牌会把另一个其存储的加密密钥通过<ruby>可插入式身份认证<rt>Pluggable Authentication Module</rt></ruby>模块(PAM)框架来响应询问。最后,Fedora 才会提示你输入密码。这可以防止其他人仅仅使用了找到的硬件令牌,或是只使用了账户名密码而没有正确的加密密钥。
|
||||
|
||||
这意味着除了你的账户名密码之外,你必须事先在你的操作系统中注册了一个或多个加密硬件令牌。你必须保证你的物理硬件令牌能够匹配你的用户名。
|
||||
|
||||
一些询问-响应的方法,比如一次性密码(OTP),在硬件令牌上获取加密的代码密钥,然后将这个密钥通过网络传输到远程身份认证服务器。然后这个服务器会告诉 Fedora 的 PAM 框架,这是否是该用户的一个有效令牌。如果身份认证服务器在本地网络上,这个方法非常好。但它的缺点是如果网络连接断开或是你在没有网的远程端工作。你会被锁在系统之外,直到你能通过网络连接到身份认证服务器。
|
||||
|
||||
有时候,生产环境会采用通过 Yubikey 使用一次性密码(OTP)的设置,然而,在家庭或个人的系统上,你可能更喜欢询问-响应设置。一切都是本地的,这种方法不需要通过远程网络调用。下面这些过程适用于 Fedora 27、28 和 29.
|
||||
|
||||
### 准备
|
||||
|
||||
#### 硬件令牌密钥
|
||||
|
||||
首先,你需要一个安全的硬件令牌密钥。具体来说,这个过程需要一个 Yubikey 4、Yubikey NEO,或者是最近发布的、同样支持 FIDO2 的 Yubikey 5 系列设备。你应该购买它们中的两个,一个做备份,以避免其中一个丢失或遭到损坏。你可以在不同的工作地点使用这些密钥。较为简单的 FIDO 和 FIDO U2F 版本不适用于这个过程,但是非常适合使用 FIDO 的在线服务。
|
||||
|
||||
#### 备份、备份,以及备份
|
||||
|
||||
接下来,为你所有的重要数据制作备份,你可能想在克隆在 VM 里的 Fedora 27/28/29 里测试配置,来确保你在设置你自己的个人工作环境之前理解这个过程。
|
||||
|
||||
#### 升级,然后安装
|
||||
|
||||
现在,确定你的 Fedora 是最新的,然后通过 `dnf` 命令安装所需要的 Fedora Yubikey 包。
|
||||
|
||||
```
|
||||
$ sudo dnf upgrade
|
||||
$ sudo dnf install ykclient* ykpers* pam_yubico*
|
||||
```
|
||||
|
||||
如果你使用的是 VM 环境,例如 Virtual Box,确保 Yubikey 设备已经插进了 USB 口,然后允许 VM 控制的 USB 访问 Yubikey。
|
||||
|
||||
### 配置 Yubikey
|
||||
|
||||
确认你的账户访问到了 USB Yubikey:
|
||||
|
||||
```
|
||||
$ ykinfo -v
|
||||
version: 3.5.0
|
||||
```
|
||||
|
||||
如果 Yubikey 没有被检测到,会出现下面这些错误信息:
|
||||
|
||||
```
|
||||
Yubikey core error: no yubikey present
|
||||
```
|
||||
|
||||
接下来,通过下面这些 `ykpersonalize` 命令初始化你每个新的 Yubikey。这将设置 Yubikey 配置插槽 2 使用 HMAC-SHA1 算法(即使少于 64 个字符)进行询问响应。如果你已经为询问响应设置好了你的 Yubikey。你就不需要再次运行 `ykpersonalize` 了。
|
||||
|
||||
```
|
||||
ykpersonalize -2 -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible
|
||||
```
|
||||
|
||||
一些用户在使用的时候将 YubiKey 留在了他们的工作站上,甚至用于对虚拟机进行询问-响应。然而,为了更好的安全性,你可能会更愿意使用手动触发 YubiKey 来响应询问。
|
||||
|
||||
要添加手动询问按钮触发器,请添加 `-ochal-btn-trig` 选项,这个选项可以使得 Yubikey 在请求中闪烁其 LED。等待你在 15 秒内按下硬件密钥区域上的按钮来生成响应密钥。
|
||||
|
||||
```
|
||||
$ ykpersonalize -2 -ochal-resp -ochal-hmac -ohmac-lt64 -ochal-btn-trig -oserial-api-visible
|
||||
```
|
||||
|
||||
为你的每个新的硬件密钥执行此操作。每个密钥执行一次。完成编程之后,使用下面的命令将 Yubikey 配置存储到 `~/.yubico`:
|
||||
|
||||
```
|
||||
$ ykpamcfg -2 -v
|
||||
debug: util.c:222 (check_firmware_version): YubiKey Firmware version: 4.3.4
|
||||
|
||||
Sending 63 bytes HMAC challenge to slot 2
|
||||
Sending 63 bytes HMAC challenge to slot 2
|
||||
Stored initial challenge and expected response in '/home/chuckfinley/.yubico/challenge-9992567'.
|
||||
```
|
||||
|
||||
如果你要设置多个密钥用于备份,请将所有的密钥设置为相同,然后使用 `ykpamcfg` 工具存储每个密钥的询问-响应。如果你在一个已经存在的注册密钥上运行 `ykpersonalize` 命令,你就必须再次存储配置信息。
|
||||
|
||||
### 配置 /etc/pam.d/sudo
|
||||
|
||||
现在要去验证配置是否有效,**在同一个终端窗口中**,你需要设置 `sudo` 来要求使用 Yubikey 的询问-响应。将下面这几行插入到 `/etc/pam.d/sudo` 文件中。
|
||||
|
||||
```
|
||||
auth required pam_yubico.so mode=challenge-response
|
||||
```
|
||||
|
||||
将上面的 `auth` 行插入到文件中的 `auth include system-auth` 行的上面,然后保存并退出编辑器。在默认的 Fedora 29 设置中,`/etc/pam.d/sudo` 应该像下面这样:
|
||||
|
||||
```
|
||||
#%PAM-1.0
|
||||
auth required pam_yubico.so mode=challenge-response
|
||||
auth include system-auth
|
||||
account include system-auth
|
||||
password include system-auth
|
||||
session optional pam_keyinit.so revoke
|
||||
session required pam_limits.so
|
||||
session include system-auth
|
||||
```
|
||||
|
||||
**保持这个初始的终端窗口打开**,然后打开一个新的终端窗口进行测试,在新的终端窗口中输入:
|
||||
|
||||
```
|
||||
$ sudo echo testing
|
||||
```
|
||||
|
||||
你应该注意到了 Yubikey 上的 LED 在闪烁。点击 Yubikey 按钮,你应该会看见一个输入 `sudo` 密码的提示。在你输入你的密码之后,你应该会在终端屏幕上看见 “testing” 的字样。
|
||||
|
||||
现在去测试确保失败也正常,启动另一个终端窗口,并从 USB 插口中拔掉 Yubikey。使用下面这条命令验证,在没有 Yubikey 的情况下,`sudo` 是否会不再正常工作。
|
||||
|
||||
```
|
||||
$ sudo echo testing fail
|
||||
```
|
||||
|
||||
你应该立刻被提示输入 `sudo` 密码,但即使你输入了正确密码,登录也应该失败。
|
||||
|
||||
### 设置 Gnome 桌面管理器(GDM)
|
||||
|
||||
一旦你的测试完成后,你就可以为图形登录添加询问-响应支持了。将你的 Yubikey 再次插入进 USB 插口中。然后将下面这几行添加到 `/etc/pam.d/gdm-password` 文件中:
|
||||
|
||||
```
|
||||
auth required pam_yubico.so mode=challenge-response
|
||||
```
|
||||
|
||||
打开一个终端窗口,然后运行下面这些命令。如果需要,你可以使用其他的编辑器:
|
||||
|
||||
```
|
||||
$ sudo vi /etc/pam.d/gdm-password
|
||||
```
|
||||
|
||||
你应该看到 Yubikey 上的 LED 在闪烁,按下 Yubikey 按钮,然后在提示符处输入密码。
|
||||
|
||||
修改 `/etc/pam.d/gdm-password` 文件,在已有的 `auth substack password-auth` 行上添加新的行。这个文件的顶部应该像下面这样:
|
||||
|
||||
```
|
||||
auth [success=done ignore=ignore default=bad] pam_selinux_permit.so
|
||||
auth required pam_yubico.so mode=challenge-response
|
||||
auth substack password-auth
|
||||
auth optional pam_gnome_keyring.so
|
||||
auth include postlogin
|
||||
|
||||
account required pam_nologin.so
|
||||
```
|
||||
|
||||
保存更改并退出编辑器,如果你使用的是 vi,输入键是按 `Esc` 键,然后在提示符处输入 `wq!` 来保存并退出。
|
||||
|
||||
### 结论
|
||||
|
||||
现在注销 GNOME。将 Yubikey 插入到 USB 口,在图形登录界面上点击你的用户名。Yubikey LED 会开始闪烁。触摸那个按钮,你会被提示输入你的密码。
|
||||
|
||||
如果你丢失了 Yubikey,除了重置密码之外,你还可以使用备份的 Yubikey。你还可以给你的账户增加额外的 Yubikey 配置。
|
||||
|
||||
如果有其他人获得了你的密码,他们在没有你的物理硬件 Yubikey 的情况下,仍然不能登录。恭喜!你已经显著提高了你的工作环境登录的安全性了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/login-challenge-response-authentication/
|
||||
|
||||
作者:[nabooengineer][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[hopefully2333](https://github.com/hopefully2333)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/nabooengineer/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/using-the-yubikey4-with-fedora/
|
||||
[2]: https://fedoramagazine.org/fedora-28-better-smart-card-support-openssh/
|
||||
|
@ -1,31 +1,33 @@
|
||||
持续集成与部署的3个最佳实践
|
||||
持续集成与部署的 3 个最佳实践
|
||||
======
|
||||
了解自动化,使用 Git 存储库以及参数化 Jenkins 管道。
|
||||
|
||||
> 了解自动化,使用 Git 存储库以及参数化 Jenkins 管道。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/innovation_lightbulb_gears_devops_ansible.png?itok=TSbmp3_M)
|
||||
|
||||
本文涵盖了三个关键主题:自动化 CI/CD 配置、使用 Git 存储库处理常见的 CI/CD 工件、参数化 Jenkins 管道。
|
||||
|
||||
### 术语
|
||||
|
||||
首先,我们定义一些术语。**CI/CD** 是允许团队快速自动化测试、打包、部署其应用程序的实践。它通常通过利用名为 **[Jenkins][1]** 的服务器来实现,该服务器充当 CI/CD 协调器。Jenkins 侦听特定输入(通常是代码签入后的 Git hook),并在触发时启动管道。
|
||||
首先,我们定义一些术语。**CI/CD** 是允许团队快速自动化测试、打包、部署其应用程序的实践。它通常通过利用名为 [Jenkins][1] 的服务器来实现,该服务器充当 CI/CD 协调器。Jenkins 侦听特定输入(通常是代码签入后的 Git 挂钩),并在触发时启动一个管道。
|
||||
|
||||
**pipeline** 由开发和/或运营团队编写的代码组成,这些代码指导 Jenkins 在 CI/CD 过程中采取哪些操作。这个流水线通常类似于“构建我的代码,然后测试我的代码,如果这些测试通过,则把我的应用程序部署到下一个最高环境(通常是开发、测试或生产环境)”。组织通常具有更复杂的流水线,并入了诸如工件存储库和代码分析器之类的工具,但是这提供了一个高级示例。
|
||||
<ruby>管道<rt>pipeline</rt></ruby> 由开发和/或运营团队编写的代码组成,这些代码指导 Jenkins 在 CI/CD 过程中采取哪些操作。这个流水线通常类似于“构建我的代码,然后测试我的代码,如果这些测试通过,则把我的应用程序部署到下一个最高环境(通常是开发、测试或生产环境)”。组织通常具有更复杂的管道,并入了诸如工件存储库和代码分析器之类的工具,这里提供了一个高级示例。
|
||||
|
||||
现在我们了解了关键术语,让我们深入研究一些最佳实践。
|
||||
|
||||
### 1\. 自动化是关键
|
||||
### 1、自动化是关键
|
||||
|
||||
要在 PaaS 上运行 CI/CD,需要在集群上配置适当的基础设施。在这个例子中,我将使用 [OpenShift][2]。
|
||||
|
||||
"Hello, World" 的实现很容易实现。简单地运行 **oc new-app jenkins- <persistent/ephemeral>** 和 voilà, 你已经准备好运行 Jenkins 服务器了。然而,在企业中的使用要复杂得多。除了 Jenkins 服务器之外,管理员通常还需要部署代码分析工具(如 SonarQube)和构件库(如 Nexus)。然后,它们必须创建管道来执行 CI/CD 和 Jenkins 从服务器,以减少主服务器的负载。这些实体中的大多数都由 OpenShift 资源支持,需要创建这些资源来部署所需的 CI/CD 基础设施。
|
||||
“Hello, World” 的实现很容易实现。简单地运行 `oc new-app jenkins-<persistent/ephemeral>`,然后,你就有了一个已经就绪的运行中的 Jenkins 服务器了。然而,在企业中的使用要复杂得多。除了 Jenkins 服务器之外,管理员通常还需要部署代码分析工具(如 SonarQube)和工件库(如 Nexus)。然后,它们必须创建管道来执行 CI/CD 和 Jenkins 从服务器,以减少主服务器的负载。这些实体中的大多数都由 OpenShift 资源支持,需要创建这些资源来部署所需的 CI/CD 基础设施。
|
||||
|
||||
最后,部署 CI/CD 组件所需要的手动步骤可能是需要被重复的,并且你可能不想成为执行那些重复步骤的人。为了确保结果能够像以前一样快速、无错误和准确地产生,应该在创建基础设施的方式中结合自动化方法。这可以是一个 Ansible 剧本、一个 Bash 脚本,或者任何您希望自动化 CI/CD 基础设施部署的其他方式。我已经使用 [Ansible][3] 和 [OpenShift-Applier][4] 角色来自动化我的实现。您可能会发现这些工具很有价值,或者您可能会发现其他一些对您和组织更有效的工具。无论哪种方式,您都将发现自动化显著地减少了重新创建 CI/CD 组件所需的工作量。
|
||||
最后,部署 CI/CD 组件所需要的手动步骤可能是需要重复进行的,而且你可能不想成为执行那些重复步骤的人。为了确保结果能够像以前一样快速、无错误和准确地产生,应该在创建基础设施的方式中结合自动化方法。这可以是一个 Ansible 剧本、一个 Bash 脚本,或者任何您希望自动化 CI/CD 基础设施部署的其它方式。我已经使用 [Ansible][3] 和 [OpenShift-Applier][4] 角色来自动化我的实现。您可能会发现这些工具很有价值,或者您可能会发现其他一些对您和组织更有效的工具。无论哪种方式,您都将发现自动化显著地减少了重新创建 CI/CD 组件所需的工作量。
|
||||
|
||||
#### 配置Jenkins主服务器
|
||||
#### 配置 Jenkins 主服务器
|
||||
|
||||
除了一般的“自动化”之外,我想单独介绍一下 Jenkins 主服务器,并讨论管理员如何利用 OpenShift 来自动化配置 Jenkins。来自 [Red Hat Container Catalog][5] 的 Jenkins 映像已经安装了 [OpenShift-Sync plugin][6]。在 [视频][7] 中,我们将讨论如何使用这个插件来创建 Jenkins 管道和从设备。
|
||||
除了一般的“自动化”之外,我想单独介绍一下 Jenkins 主服务器,并讨论管理员如何利用 OpenShift 来自动化配置 Jenkins。来自 [Red Hat Container Catalog][5] 的 Jenkins 镜像已经安装了 [OpenShift-Sync plugin][6]。在 [该视频][7] 中,我们将讨论如何使用这个插件来创建 Jenkins 管道和从设备。
|
||||
|
||||
要创建 Jenkins 流水线,请创建一个类似于下面的 OpenShift BuildConfig:
|
||||
要创建 Jenkins 管道,请创建一个类似于下面的 OpenShift BuildConfig:
|
||||
|
||||
```
|
||||
apiVersion: v1
|
||||
@ -43,7 +45,7 @@ spec:
|
||||
type: JenkinsPipeline
|
||||
```
|
||||
|
||||
OpenShift-Sync 插件将注意到已经创建了带有 **jenkinsPipelineStrategy** 策略的 BuildConfig,并将其转换为 Jenkins 管道,从 Git 源指定的 Jenkins 文件中提取。也可以使用内联 Jenkinsfile,而不是从 Git 存储库中提取。有关更多信息,请参阅[文档][8]。
|
||||
OpenShift-Sync 插件将注意到已经创建了带有 `jenkinsPipelineStrategy` 策略的 BuildConfig,并将其转换为 Jenkins 管道,从 Git 源指定的 Jenkinsfile 中提取。也可以使用内联 Jenkinsfile,而不是从 Git 存储库中提取。有关更多信息,请参阅[文档][8]。
|
||||
|
||||
要创建 Jenkins 从站,请创建一个 OpenShift ImageStream,它从以下定义开始:
|
||||
|
||||
@ -55,12 +57,12 @@ metadata:
|
||||
slave-label: jenkins-slave
|
||||
labels:
|
||||
role: jenkins-slave
|
||||
…
|
||||
...
|
||||
```
|
||||
|
||||
注意在这个 ImageStream 中定义的元数据。OpenShift-Sync 插件将把带有标签 **role: jenkins-slave** 的任何ImageStream 转换为 Jenkins 从站。Jenkins 从站将以 **slave-label** 注释中的值命名。
|
||||
注意在这个 ImageStream 中定义的元数据。OpenShift-Sync 插件将把带有标签 `role: jenkins-slave` 的任何 ImageStream 转换为 Jenkins 从站。Jenkins 从站将以 `slave-label` 注释中的值命名。
|
||||
|
||||
ImageStreams 对于简单的 Jenkins 从属配置工作得很好,但是一些团队会发现有必要配置一些细节详情,比如资源限制、准备就绪和活动性探测,以及实例帽。这就是 ConfigMap 发挥作用的地方:
|
||||
ImageStreams 对于简单的 Jenkins 从属配置工作得很好,但是一些团队会发现有必要配置一些细节详情,比如资源限制、准备就绪和活动性探测,以及实例上限。这就是 ConfigMap 发挥作用的地方:
|
||||
|
||||
```
|
||||
apiVersion: v1
|
||||
@ -74,21 +76,21 @@ data:
|
||||
<Kubernetes pod template>
|
||||
```
|
||||
|
||||
注意,仍然需要角色:jenkins-slave 标签来将 ConfigMap 转换为 Jenkins slave。Kubernetes pod 模板由一长段 XML 组成,它将根据组织的喜好配置每个细节。要查看此 XML,以及有关将 ImageStreams 和 ConfigMaps 转换为 Jenkins 从属的更多信息,请参阅[文档][9]。
|
||||
注意,仍然需要角色:`jenkins-slave` 标签来将 ConfigMap 转换为 Jenkins 从站。Kubernetes pod 模板由一长段 XML 组成,它将根据组织的喜好配置每个细节。要查看此 XML,以及有关将 ImageStreams 和 ConfigMaps 转换为 Jenkins 从站的更多信息,请参阅[文档][9]。
|
||||
|
||||
请注意上面所示的三个示例,其中没有一个操作需要管理员对 Jenkins 控制台进行手动更改。通过使用 OpenShift 资源,可以简单的自动化方式配置 Jenkins。
|
||||
|
||||
### 2\. 分享就是关心
|
||||
### 2、分享就是关爱
|
||||
|
||||
第二个最佳实践是维护一个公共 CI/CD 工件的 Git 存储库。主要思想是防止团队重新发明轮子。假设您的团队需要执行到 OpenShift 环境的蓝色/绿色部署,作为管道 CD 阶段的一部分。负责编写流水线的团队成员可能不是 OpenShift 专家,也不可能具有从头开始编写此功能的能力。幸运的是,有人已经编写了一个将此功能合并到一个公共 CI/CD 存储库中的函数,因此您的团队可以使用该函数而不是花时间编写一个函数。
|
||||
第二个最佳实践是维护一个公共 CI/CD 工件的 Git 存储库。主要思想是防止团队重新发明轮子。假设您的团队需要执行到 OpenShift 环境的蓝/绿部署,作为管道 CD 阶段的一部分。负责编写管道的团队成员可能不是 OpenShift 专家,也不可能具有从头开始编写此功能的能力。幸运的是,有人已经编写了一个将此功能合并到一个公共 CI/CD 存储库中的函数,因此您的团队可以使用该函数而不是花时间编写一个函数。
|
||||
|
||||
为了更进一步,您的组织可能决定维护整个管道。您可能会发现团队正在编写具有相似功能的流水线。对于那些团队来说,使用来自公共存储库的参数化管道要比从头开始编写自己的管道更有效。
|
||||
为了更进一步,您的组织可能决定维护整个管道。您可能会发现团队正在编写具有相似功能的管道。对于那些团队来说,使用来自公共存储库的参数化管道要比从头开始编写自己的管道更有效。
|
||||
|
||||
### 3\. 少即是多
|
||||
### 3、少即是多
|
||||
|
||||
正如我在前一节中提到的,第三个也是最后一个最佳实践是参数化您的 CI/CD 管道。参数化将防止过多的管道,使您的 CI/CD 系统更容易维护。假设我有多个区域可以部署应用程序。如果没有参数化,我需要为每个区域设置单独的管道。
|
||||
|
||||
要参数化作为 OpenShift 构建配置编写的管道,请将 **env** 节添加到配置:
|
||||
要参数化一个作为 OpenShift 构建配置编写的管道,请将 `env` 节添加到配置:
|
||||
|
||||
```
|
||||
...
|
||||
@ -103,9 +105,9 @@ spec:
|
||||
type: JenkinsPipeline
|
||||
```
|
||||
|
||||
使用此配置,我可以传递 **REGION** 参数管道以将我的应用程序部署到指定区域。
|
||||
使用此配置,我可以传递 `REGION` 参数给管道以将我的应用程序部署到指定区域。
|
||||
|
||||
这有一个[视频][7]提供了一个更实质性的情况,其中参数化是必须的。一些组织决定把他们的 CI/CD 管道分割成单独的 CI 和 CD 管道,通常是因为在部署之前有一些审批过程。假设我有四个映像和三个不同的环境要部署。如果没有参数化,我需要12个 CD 管道来允许所有部署可能性。这会很快失去控制。为了使 CD 流水线的维护更容易,组织会发现将映像和环境参数化以便允许一个流水线执行多个流水线的工作会更好。
|
||||
这有一个[视频][7]提供了一个更实质性的情况,其中参数化是必须的。一些组织决定把他们的 CI/CD 管道分割成单独的 CI 和 CD 管道,通常是因为在部署之前有一些审批过程。假设我有四个镜像和三个不同的环境要部署。如果没有参数化,我需要 12 个 CD 管道来允许所有部署可能性。这会很快失去控制。为了使 CD 流水线的维护更容易,组织会发现将镜像和环境参数化以便允许一个流水线执行多个流水线的工作会更好。
|
||||
|
||||
### 总结
|
||||
|
||||
@ -120,7 +122,7 @@ via: https://opensource.com/article/18/11/best-practices-cicd
|
||||
作者:[Austin Dewey][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[ChiZelin](https://github.com/ChiZelin)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
73
published/201812/20181121 DevOps is for everyone.md
Normal file
73
published/201812/20181121 DevOps is for everyone.md
Normal file
@ -0,0 +1,73 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (alim0x)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (DevOps is for everyone)
|
||||
[#]: via: (https://opensource.com/article/18/11/how-non-engineer-got-devops)
|
||||
[#]: author: (Dawn Parych https://opensource.com/users/dawnparzych)
|
||||
[#]: url: (https://linux.cn/article-10386-1.html)
|
||||
|
||||
所有人的 DevOps
|
||||
======
|
||||
|
||||
> 让一名非工程师来解释为什么你不必成为一位开发者或运维就能爱上 DevOps。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/team-game-play-inclusive-diversity-collaboration.png?itok=8sUXV7W1)
|
||||
|
||||
我从未做过开发或运维的工作 —— 那怎么我在写一篇关于 [DevOps][1] 的文章?我一直都对计算机和技术有兴趣。我还对社群、心理学以及帮助他人充满热情。当我第一次听到 DevOps 时,这个概念激起了我的兴趣,因为它看起来融合了很多我感兴趣的东西,即便我是不写代码的。
|
||||
|
||||
我的第一台电脑是 TRS-80,我喜欢在上面编写 BASIC 程序。我只上过两门我的高中开设的计算机编程课程。若干年后,我创办了一家计算机公司。我定制邮件标签和信纸,并建立了一个数据库来存储地址。
|
||||
|
||||
问题是我并不能从写代码中获得享受。我想要教育和帮助人们,我没法将写代码看作这样的一个机会。是的,技术可以帮助人们并改变生活,但是写代码没有点燃我的热情。我需要对我的工作感到兴奋并做我喜欢的事情。
|
||||
|
||||
我发现我爱 DevOps。对我而言,DevOps 指的是:
|
||||
|
||||
* 文化,而不是代码
|
||||
* 过程,而不是结果
|
||||
* 建立一个所有人可以持续提升的环境
|
||||
* 沟通与合作,而不是独立工作
|
||||
|
||||
归根结底,DevOps 是指成为社区工作的一部分,实现共同的目标。DevOps 融合了心理学、社群、技术。DevOps 不是一个职位名称,它是一种生活和工作的哲学。
|
||||
|
||||
### 找到我的社群
|
||||
|
||||
快四年前,我在西雅图参加了我的第一个 [DevOps 日][2] 会议。我感觉我找到了我的社群。我觉得受到了欢迎和接受,尽管我从事营销工作而且没有计算机科学文凭。我可以从心理学和技术中寻找乐趣。
|
||||
|
||||
在 DevOps 日,我学到了 [DevOps“三步工作法”][3] —— 流动、反馈、持续实验和学习 —— 以及新(对我而言)的概念,如 Kaizen(改善)和 Kaikaku(改革)。随着我的学习深入,我发现我在说这样的话,“我是这样做的!我都不知道这样做还有个名字!”
|
||||
|
||||
[Kaizen(改善)][4]是持续改进和学习的实践。小的量变积累随着时间的推移可以引起质变。我发现它和卡罗尔·德韦克的[成长型思维][5]的想法很相似。人们不是生来就是专家。在某方面拥有经验需要花费时间、练习,以及常常还有失败。承认增量的改善对确保我们不会放弃是很有必要的。
|
||||
|
||||
另一方面,[Kaikaku(改革)][6]的概念是指,长时间的小的改变有时不能起作用,你需要做一些完全的或破坏性的改变。在没有找到下份工作前就辞职或移居新城市就足够有破坏性 —— 是的,两者我都做过。但这些彻底的改变收获巨大。如果我没有辞职并休息一段时间,我也许不会接触到 DevOps。等我决定继续工作的时候,我一直听到 DevOps,我开始研究它。这引导我参加了我的第一个 DevOps 日,从那里我开始看到我的所有热情开始聚集。从那时起,我已经参加了五次 DevOps 日活动,并且定期撰写关于 DevOps 话题的文章。
|
||||
|
||||
### 将三步工作法用到工作中
|
||||
|
||||
改变是困难的,学习新事物可以听起来很吓人。DevOps 的三步工作法提供了一个管理改变的框架。比如:信息流动是怎样的?是什么驱动着你做出改变?一旦你认为一个改变是必需的,你如何获得这个改变是否正确的反馈?你如何知道你在取得进展?反馈是必要的,并且应该包含积极和有建设性的要素。困难的地方在于保证建设性的要素不要重于积极要素。
|
||||
|
||||
对我而言,第三步 —— 持续实验和学习 —— 是 DevOps 最重要的部分。有一个可以自由地实验和冒险的环境,人们可以获得意想不到的结果。有时这些结果是好的,有时不是太好 —— 但这没事。创建一个可以接受失败结果的环境可以鼓励人们冒险。我们都应该力争定期的持续实验和学习。
|
||||
|
||||
DevOps 的三步工作法提供了一个尝试,获得反馈,以及从错误中获取经验的方法。几年前,我的儿子告诉我,“我从来就没想做到最好,因为那样我就没法从我的错误中学到东西了。”我们都会犯错,从中获得经验帮助我们成长和改善。如果我们的文化不支持尝试和学习,我们就不会愿意去犯错。
|
||||
|
||||
### 成为社区的一部分
|
||||
|
||||
我已经在技术领域工作了超过 20 年,直到我发现 DevOps 社区前,我还经常感觉自己是个外行。如果你像我一样——对技术充满热情,但不是工程和运维那方面——你仍然可以成为 DevOps 的一部分,即便你从事的是销售、营销、产品营销、技术写作、支持或其他工作。DevOps 是属于所有人的。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/11/how-non-engineer-got-devops
|
||||
|
||||
作者:[Dawn Parych][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[alim0x](https://github.com/alim0x)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dawnparzych
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/resources/devops
|
||||
[2]: https://www.devopsdays.org/
|
||||
[3]: https://itrevolution.com/the-three-ways-principles-underpinning-devops/
|
||||
[4]: https://en.wikipedia.org/wiki/Kaizen
|
||||
[5]: https://en.wikipedia.org/wiki/Mindset#Fixed_and_growth
|
||||
[6]: https://en.wikipedia.org/wiki/Kaikaku
|
@ -1,47 +1,51 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qhwdw)
|
||||
[#]: reviewer:
|
||||
[#]: publisher:
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (How to Build a Netboot Server, Part 1)
|
||||
|
||||
[#]: via: (https://fedoramagazine.org/how-to-build-a-netboot-server-part-1/)
|
||||
[#]: author: (Gregory Bartholomew https://fedoramagazine.org/author/glb/)
|
||||
[#]: url: (https://linux.cn/article-10379-1.html)
|
||||
|
||||
[#]: url:
|
||||
|
||||
如何构建一台网络引导服务器(第一部分)
|
||||
======
|
||||
如何构建一台网络引导服务器(一)
|
||||
======
|
||||
|
||||
![](https://fedoramagazine.org/wp-content/uploads/2018/11/build-netboot-816x345.jpg)
|
||||
|
||||
有些计算机网络需要在各个物理机器上维护相同的软件和配置。学校的计算机实验室就是这样的一个环境。一台 [网络引导][1] 服务器能够被配置为基于网络去提供一个完整的操作系统,以便于客户端计算机从一个中央位置获取配置。本教程将向你展示构建一台网络引导服务器的一种方法。
|
||||
有些计算机网络需要在各个物理机器上维护相同的软件和配置。学校的计算机实验室就是这样的一个环境。 [网络引导][1] 服务器能够被配置为基于网络去提供一个完整的操作系统,以便于客户端计算机从一个中央位置获取配置。本教程将向你展示构建一台网络引导服务器的一种方法。
|
||||
|
||||
本教程的第一部分将包括创建一台网络引导服务器和镜像。第二部分将展示如何去添加 Kerberos 验证的 home 目录到网络引导配置中。
|
||||
本教程的第一部分将包括创建一台网络引导服务器和镜像。第二部分将展示如何去添加 Kerberos 验证的家目录到网络引导配置中。
|
||||
|
||||
### 初始化配置
|
||||
|
||||
首先去下载 Fedora 服务器的 [netinst][2] 镜像,将它刻录到一张光盘上,然后它将引导服务器去重新格式化。我们只需要一个典型的 Fedora Server 的“最小化安装”来作为我们的开端,安装完成后,我们可以使用命令行去添加我们需要的任何额外的包。
|
||||
首先去下载 Fedora 服务器的 [netinst][2] 镜像,将它刻录到一张光盘上,然后用它引导服务器来重新格式化。我们只需要一个典型的 Fedora Server 的“最小化安装”来作为我们的开端,安装完成后,我们可以使用命令行去添加我们需要的任何额外的包。
|
||||
|
||||
![][3]
|
||||
|
||||
> 注意:本教程中我们将使用 Fedora 28。其它版本在“最小化安装”中包含的包可能略有不同。如果你使用的是不同的 Fedora 版本,如果一个预期的文件或命令不可用,你可能需要做一些调试。
|
||||
|
||||
最小化安装的 Fedora Server 运行起来之后,以 root 用户登入并设置主机名字:
|
||||
最小化安装的 Fedora Server 运行起来之后,以 root 用户登入:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ sudo -i
|
||||
```
|
||||
|
||||
并设置主机名字:
|
||||
|
||||
```
|
||||
$ MY_HOSTNAME=server-01.example.edu
|
||||
$ hostnamectl set-hostname $MY_HOSTNAME
|
||||
```
|
||||
|
||||
> 注意:Red Hat 建议静态和临时名字应都要与这个机器在 DNS 中的完全合格域名相匹配,比如 host.example.com([了解主机名字][4])。
|
||||
>
|
||||
> 注意:本指南为了你“复制粘贴”友好。需要自定义的任何值都声明为一个 MY_* 变量,在你运行剩余命令之前,你可能需要调整它。如果你注销之后,变量的赋值将被清除。
|
||||
> 注意:本指南为了方便“复制粘贴”。需要自定义的任何值都声明为一个 `MY_*` 变量,在你运行剩余命令之前,你可能需要调整它。如果你注销之后,变量的赋值将被清除。
|
||||
>
|
||||
> 注意:Fedora 28 Server 在默认情况下往往会转储大量的日志到控制台上。你可以通过运行命令:sysctl -w kernel.printk=0 去禁用控制台日志输出。
|
||||
> 注意:Fedora 28 Server 在默认情况下往往会转储大量的日志到控制台上。你可以通过运行命令:`sysctl -w kernel.printk=0` 去禁用控制台日志输出。
|
||||
|
||||
接下来,我们需要在我们的服务器上配置一个静态网络地址。运行下面的一系列命令将找到并重新配置你的默认网络连接:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ MY_DNS1=192.0.2.91
|
||||
$ MY_DNS2=192.0.2.92
|
||||
$ MY_IP=192.0.2.158
|
||||
@ -66,7 +70,7 @@ nmcli con up br0-slave0
|
||||
END
|
||||
```
|
||||
|
||||
> 注意:上面最后的一组命令被封装到一个 “nohup” 脚本中,因为它将临时禁用网络。这个 nohup 命令将允许 nmcli 命令去完成运行,直到你的 SSH 连接断开。注意,连接恢复可能需要 10 秒左右的时间,如果你改变了服务器 IP 地址,你将需要重新启动一个新的 SSH 连接。
|
||||
> 注意:上面最后的一组命令被封装到一个 `nohup` 脚本中,因为它将临时禁用网络。这个 `nohup` 命令可以让 `nmcli` 命令运行完成,即使你的 SSH 连接断开。注意,连接恢复可能需要 10 秒左右的时间,如果你改变了服务器 IP 地址,你将需要重新启动一个新的 SSH 连接。
|
||||
>
|
||||
> 注意:上面的网络配置在默认的连接之上创建了一个 [网桥][5],这样我们在后面的测试中就可以直接运行一个虚拟机实例。如果你不想在这台服务器上去直接测试网络引导镜像,你可以跳过创建网桥的命令,并直接在你的默认网络连接上配置静态 IP 地址。
|
||||
|
||||
@ -80,26 +84,26 @@ $ dnf install -y nfs-utils
|
||||
|
||||
为发布 NFS 去创建一个顶级的 [伪文件系统][6],然后在你的网络上共享它:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ MY_SUBNET=192.0.2.0
|
||||
$ mkdir /export
|
||||
$ echo "/export -fsid=0,ro,sec=sys,root_squash $MY_SUBNET/$MY_PREFIX" > /etc/exports
|
||||
```
|
||||
|
||||
SELinux 将干扰网络引导服务器的运行。在本教程中我们将不涉及为它配置例外的部分,因此我们直接禁用它:
|
||||
SELinux 会干扰网络引导服务器的运行。为它配置例外规则超出了本教程中,因此我们这里直接禁用它:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ sed -i '/GRUB_CMDLINE_LINUX/s/"$/ audit=0 selinux=0"/' /etc/default/grub
|
||||
$ grub2-mkconfig -o /boot/grub2/grub.cfg
|
||||
$ sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/sysconfig/selinux
|
||||
$ setenforce 0
|
||||
```
|
||||
|
||||
> 注意:编辑 grub 命令行应该是不需要的,但在测试过程中发现,简单地编辑 /etc/sysconfig/selinux 被证明重启后是无效的,因此再次确保设置了 “selinux=0” 标志。
|
||||
> 注意:应该不需要编辑 grub 命令行,但我们在测试过程中发现,直接编辑 `/etc/sysconfig/selinux` 被证明重启后是无效的,因此这样做再次确保设置了 `selinux=0` 标志。
|
||||
|
||||
现在,在本地防火墙中为 NFS 服务添加一个例外,然后启动 NFS 服务:
|
||||
现在,在本地防火墙中为 NFS 服务添加一个例外规则,然后启动 NFS 服务:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ firewall-cmd --add-service nfs
|
||||
$ firewall-cmd --runtime-to-permanent
|
||||
$ systemctl enable nfs-server.service
|
||||
@ -116,76 +120,70 @@ $ systemctl start nfs-server.service
|
||||
$ mkdir /fc28
|
||||
```
|
||||
|
||||
使用 “dnf” 命令在新目录下用几个基础包去构建镜像:
|
||||
使用 `dnf` 命令在新目录下用几个基础包去构建镜像:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ dnf -y --releasever=28 --installroot=/fc28 install fedora-release systemd passwd rootfiles sudo dracut dracut-network nfs-utils vim-minimal dnf
|
||||
```
|
||||
|
||||
在上面的命令中省略了很重要的 “kernel” 包。在它们被安装完成之前,我们需要去调整一下 “initramfs” 镜像中包含的驱动程序集,“kernel” 首次安装时将自动构建这个镜像。尤其是,我们需要禁用 “hostonly” 模式,以便于 initramfs 镜像能够在各种硬件平台上正常工作,并且我们还需要添加对网络和 NFS 的支持:
|
||||
在上面的命令中省略了很重要的 `kernel` 包。在它们被安装完成之前,我们需要去调整一下 `initramfs` 镜像中包含的驱动程序集,`kernel` 首次安装时将自动构建这个镜像。尤其是,我们需要禁用 `hostonly` 模式,以便于 `initramfs` 镜像能够在各种硬件平台上正常工作,并且我们还需要添加对网络和 NFS 的支持:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ echo 'hostonly=no' > /fc28/etc/dracut.conf.d/hostonly.conf
|
||||
$ echo 'add_dracutmodules+=" network nfs "' > /fc28/etc/dracut.conf.d/netboot.conf
|
||||
```
|
||||
|
||||
现在,安装 kernel:
|
||||
现在,安装 `kernel` 包:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ dnf -y --installroot=/fc28 install kernel
|
||||
```
|
||||
|
||||
设置一个阻止 kernel 被更新的规则:
|
||||
设置一个阻止 `kernel` 包被更新的规则:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ echo 'exclude=kernel-*' >> /fc28/etc/dnf/dnf.conf
|
||||
```
|
||||
|
||||
设置 locale:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ echo 'LANG="en_US.UTF-8"' > /fc28/etc/locale.conf
|
||||
```
|
||||
|
||||
> 注意:如果 locale 没有正确配置,一些程序(如 GNOME Terminal)将无法正常工作。
|
||||
|
||||
root 用户密码留空:
|
||||
|
||||
```javascript
|
||||
$ sed -i 's/^root:\*/root:/' /fc28/etc/shadow
|
||||
```
|
||||
|
||||
设置客户端的主机名字:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ MY_CLIENT_HOSTNAME=client-01.example.edu
|
||||
$ echo $MY_CLIENT_HOSTNAME > /fc28/etc/hostname
|
||||
```
|
||||
|
||||
禁用控制台日志输出:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ echo 'kernel.printk = 0 4 1 7' > /fc28/etc/sysctl.d/00-printk.conf
|
||||
```
|
||||
|
||||
定义网络引导镜像中的本地 “liveuser” 用户:
|
||||
定义网络引导镜像中的本地 `liveuser` 用户:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ echo 'liveuser:x:1000:1000::/home/liveuser:/bin/bash' >> /fc28/etc/passwd
|
||||
$ echo 'liveuser::::::::' >> /fc28/etc/shadow
|
||||
$ echo 'liveuser:x:1000:' >> /fc28/etc/group
|
||||
$ echo 'liveuser:!::' >> /fc28/etc/gshadow
|
||||
```
|
||||
|
||||
在 sudo 中启用 “liveuser”:
|
||||
允许 `liveuser` 使用 `sudo`:
|
||||
|
||||
```javascript
|
||||
```
|
||||
$ echo 'liveuser ALL=(ALL) NOPASSWD: ALL' > /fc28/etc/sudoers.d/liveuser
|
||||
```
|
||||
|
||||
启用自动 home 目录创建:
|
||||
启用自动创建家目录:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ dnf install -y --installroot=/fc28 authselect oddjob-mkhomedir
|
||||
$ echo 'dirs /home' > /fc28/etc/rwtab.d/home
|
||||
$ chroot /fc28 authselect select sssd with-mkhomedir --force
|
||||
@ -194,19 +192,19 @@ $ chroot /fc28 systemctl enable oddjobd.service
|
||||
|
||||
由于多个客户端将会同时挂载我们的镜像,我们需要去配置镜像工作在只读模式中:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ sed -i 's/^READONLY=no$/READONLY=yes/' /fc28/etc/sysconfig/readonly-root
|
||||
```
|
||||
|
||||
配置日志输出到内存而不是持久存储中:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ sed -i 's/^#Storage=auto$/Storage=volatile/' /fc28/etc/systemd/journald.conf
|
||||
```
|
||||
|
||||
配置 DNS:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ MY_DNS1=192.0.2.91
|
||||
$ MY_DNS2=192.0.2.92
|
||||
$ cat << END > /fc28/etc/resolv.conf
|
||||
@ -215,9 +213,9 @@ nameserver $MY_DNS2
|
||||
END
|
||||
```
|
||||
|
||||
解决编写本教程时存在的只读 root 挂载 bug([BZ1542567][7]):
|
||||
绕开编写本教程时存在的根目录只读挂载的 bug([BZ1542567][7]):
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ echo 'dirs /var/lib/gssproxy' > /fc28/etc/rwtab.d/gssproxy
|
||||
$ cat << END > /fc28/etc/rwtab.d/systemd
|
||||
dirs /var/lib/systemd/catalog
|
||||
@ -227,7 +225,7 @@ END
|
||||
|
||||
最后,为我们镜像创建 NFS 文件系统,并将它共享到我们的子网中:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ mkdir /export/fc28
|
||||
$ echo '/fc28 /export/fc28 none bind 0 0' >> /etc/fstab
|
||||
$ mount /export/fc28
|
||||
@ -237,20 +235,20 @@ $ exportfs -vr
|
||||
|
||||
### 创建引导加载器
|
||||
|
||||
现在,我们已经有了可以进行网络引导的操作系统,我们需要一个引导加载器去从客户端系统上启动它。在本教程中我们使用的是 [iPXE][8].
|
||||
现在,我们已经有了可以进行网络引导的操作系统,我们需要一个引导加载器去从客户端系统上启动它。在本教程中我们使用的是 [iPXE][8]。
|
||||
|
||||
> 注意:本节和接下来的节 — 使用 QEMU 测试 — 能在另外一台单独的计算机上来完成;它们不需要在网络引导服务器上来运行。
|
||||
> 注意:本节和接下来的节使用 QEMU 测试,也能在另外一台单独的计算机上来完成;它们并不需要在网络引导服务器上来运行。
|
||||
|
||||
安装 git 并使用它去下载 iPXE:
|
||||
安装 `git` 并使用它去下载 iPXE:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ dnf install -y git
|
||||
$ git clone http://git.ipxe.org/ipxe.git $HOME/ipxe
|
||||
```
|
||||
|
||||
现在我们需要去为我们的引导加载器创建一个指定的启动脚本:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ cat << 'END' > $HOME/ipxe/init.ipxe
|
||||
#!ipxe
|
||||
|
||||
@ -264,19 +262,19 @@ END
|
||||
|
||||
启动 “file” 下载协议:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ echo '#define DOWNLOAD_PROTO_FILE' > $HOME/ipxe/src/config/local/general.h
|
||||
```
|
||||
|
||||
安装 C 编译器以及相关的工具和库:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ dnf groupinstall -y "C Development Tools and Libraries"
|
||||
```
|
||||
|
||||
构建引导加载器:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ cd $HOME/ipxe/src
|
||||
$ make clean
|
||||
$ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe
|
||||
@ -284,7 +282,7 @@ $ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe
|
||||
|
||||
记下新编译的引导加载器的存储位置。我们将在接下来的节中用到它:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ IPXE_FILE="$HOME/ipxe/src/bin-x86_64-efi/ipxe.efi"
|
||||
```
|
||||
|
||||
@ -292,13 +290,13 @@ $ IPXE_FILE="$HOME/ipxe/src/bin-x86_64-efi/ipxe.efi"
|
||||
|
||||
这一节是可选的,但是你需要去复制下面显示在物理机器上的 [EFI 系统分区][9] 的布局,在网络引导时需要去配置它们。
|
||||
|
||||
> 注意:如果你想实现一个完全的无盘系统,你也可以复制那个文件到一个 TFTP 服务器,然后从 DHCP 上引用那台服务器。
|
||||
> 注意:如果你想实现一个完全的无盘系统,你也可以复制那个文件到一个 TFTP 服务器,然后从 DHCP 上指向那台服务器。
|
||||
|
||||
为了使用 QEMU 去测试我们的引导加载器,我们继续去创建一个仅包含一个 EFI 系统分区和我们的启动文件的、很小的磁盘镜像。
|
||||
|
||||
从创建 EFI 系统分区所需要的目录布局开始,然后把我们在前面节中创建的引导加载器复制进去:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ mkdir -p $HOME/esp/efi/boot
|
||||
$ mkdir $HOME/esp/linux
|
||||
$ cp $IPXE_FILE $HOME/esp/efi/boot/bootx64.efi
|
||||
@ -306,13 +304,13 @@ $ cp $IPXE_FILE $HOME/esp/efi/boot/bootx64.efi
|
||||
|
||||
下面的命令将识别我们的引导加载器镜像正在使用的内核版本,并将它保存到一个变量中,以备后续的配置命令去使用它:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ DEFAULT_VER=$(ls -c /fc28/lib/modules | head -n 1)
|
||||
```
|
||||
|
||||
定义我们的客户端计算机将使用的引导配置:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ MY_DNS1=192.0.2.91
|
||||
$ MY_DNS2=192.0.2.92
|
||||
$ MY_NFS4=server-01.example.edu
|
||||
@ -329,14 +327,14 @@ END
|
||||
|
||||
复制 Linux 内核并分配 initramfs 给 EFI 系统分区:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ cp $(find /fc28/lib/modules -maxdepth 2 -name 'vmlinuz' | grep -m 1 $DEFAULT_VER) $HOME/esp/linux/vmlinuz-$DEFAULT_VER
|
||||
$ cp $(find /fc28/boot -name 'init*' | grep -m 1 $DEFAULT_VER) $HOME/esp/linux/initramfs-$DEFAULT_VER.img
|
||||
```
|
||||
|
||||
我们最终的目录布局应该看起来像下面的样子:
|
||||
|
||||
```livescript
|
||||
```
|
||||
esp
|
||||
├── efi
|
||||
│ └── boot
|
||||
@ -347,17 +345,17 @@ esp
|
||||
└── vmlinuz-4.18.18-200.fc28.x86_64
|
||||
```
|
||||
|
||||
使用 QEMU 去使用我们的 EFI 系统分区,我们需要去创建一个小的 “uefi.img” 磁盘镜像来包含它,然后将它连接到 QEMU 作为主引导驱动器。
|
||||
要让 QEMU 去使用我们的 EFI 系统分区,我们需要去创建一个小的 `uefi.img` 磁盘镜像来包含它,然后将它连接到 QEMU 作为主引导驱动器。
|
||||
|
||||
开始安装必需的工具:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ dnf install -y parted dosfstools
|
||||
```
|
||||
|
||||
现在创建 “uefi.img” 文件,并将 “esp” 目录中文件复制进去:
|
||||
现在创建 `uefi.img` 文件,并将 `esp` 目录中的文件复制进去:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ ESP_SIZE=$(du -ks $HOME/esp | cut -f 1)
|
||||
$ dd if=/dev/zero of=$HOME/uefi.img count=$((${ESP_SIZE}+5000)) bs=1KiB
|
||||
$ UEFI_DEV=$(losetup --show -f $HOME/uefi.img)
|
||||
@ -370,54 +368,55 @@ $ umount $HOME/mnt
|
||||
$ losetup -d ${UEFI_DEV}
|
||||
```
|
||||
|
||||
> 注意:在物理计算机上,你只需要从 “esp” 目录中复制文件到计算机上已存在的 EFI 系统分区中。你不需要使用 “uefi.img” 文件去引导物理计算机。
|
||||
> 注意:在物理计算机上,你只需要从 `esp` 目录中复制文件到计算机上已存在的 EFI 系统分区中。你不需要使用 `uefi.img` 文件去引导物理计算机。
|
||||
>
|
||||
> 注意:在一个物理计算机上,如果文件名已存在,你可以重命名 “bootx64.efi” 文件,如果你重命名了它,就需要去编辑计算机的 BIOS 设置,并添加重命令后的 efi 文件到引导列表中。
|
||||
> 注意:在一个物理计算机上,如果文件名已存在,你可以重命名 `bootx64.efi` 文件,如果你重命名了它,就需要去编辑计算机的 BIOS 设置,并添加重命令后的 efi 文件到引导列表中。
|
||||
|
||||
接下来我们需要去安装 qemu 包:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ dnf install -y qemu-system-x86
|
||||
```
|
||||
|
||||
允许 QEMU 访问我们在本教程“初始化配置”一节中创建的网桥:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ echo 'allow br0' > /etc/qemu/bridge.conf
|
||||
```
|
||||
|
||||
创建一个 “OVMF_VARS.fd” 镜像的副本去保存我们虚拟机的持久 BIOS 配置:
|
||||
创建一个 `OVMF_VARS.fd` 镜像的副本去保存我们虚拟机的持久 BIOS 配置:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ cp /usr/share/edk2/ovmf/OVMF_VARS.fd $HOME
|
||||
```
|
||||
|
||||
现在,启动虚拟机:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ qemu-system-x86_64 -machine accel=kvm -nographic -m 1024 -drive if=pflash,format=raw,unit=0,file=/usr/share/edk2/ovmf/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=$HOME/OVMF_VARS.fd -drive if=ide,format=raw,file=$HOME/uefi.img -net bridge,br=br0 -net nic,model=virtio
|
||||
```
|
||||
|
||||
如果一切顺利,你将看到类似下图所示的结果:
|
||||
|
||||
![][10]
|
||||
你可以使用 “shutdown” 命令关闭虚拟机回到我们的服务器上:
|
||||
|
||||
```livescript
|
||||
你可以使用 `shutdown` 命令关闭虚拟机回到我们的服务器上:
|
||||
|
||||
```
|
||||
$ sudo shutdown -h now
|
||||
```
|
||||
|
||||
> 注意:如果出现了错误或虚拟机挂住了,你可能需要启动一个新的 SSH 会话去连接服务器,使用 “kill” 命令去终止 “qemu-system-x86_64” 进程。
|
||||
> 注意:如果出现了错误或虚拟机挂住了,你可能需要启动一个新的 SSH 会话去连接服务器,使用 `kill` 命令去终止 `qemu-system-x86_64` 进程。
|
||||
|
||||
### 镜像中添加包
|
||||
|
||||
镜像中添加包应该是一个很简单的问题,在服务器上 chroot 进镜像,然后运行 “dnf install <package_name>”。
|
||||
镜像中添加包应该是一个很简单的问题,在服务器上 `chroot` 进镜像,然后运行 `dnf install <package_name>`。
|
||||
|
||||
在网络引导镜像中并不限制你能安装什么包。一个完整的图形化安装应该能够完美地工作。
|
||||
|
||||
下面是一个如何将最小化安装的网络引导镜像变成完整的图形化安装的示例:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ for i in dev dev/pts dev/shm proc sys run; do mount -o bind /$i /fc28/$i; done
|
||||
$ chroot /fc28 /usr/bin/bash --login
|
||||
$ dnf -y groupinstall "Fedora Workstation"
|
||||
@ -430,9 +429,9 @@ $ logout
|
||||
$ for i in run sys proc dev/shm dev/pts dev; do umount /fc28/$i; done
|
||||
```
|
||||
|
||||
可选,你可能希望去启用 “liveuser” 用户的自动登陆:
|
||||
可选地,你可能希望去启用 `liveuser` 用户的自动登录:
|
||||
|
||||
```livescript
|
||||
```
|
||||
$ sed -i '/daemon/a AutomaticLoginEnable=true' /fc28/etc/gdm/custom.conf
|
||||
$ sed -i '/daemon/a AutomaticLogin=liveuser' /fc28/etc/gdm/custom.conf
|
||||
```
|
||||
@ -444,7 +443,7 @@ via: https://fedoramagazine.org/how-to-build-a-netboot-server-part-1/
|
||||
作者:[Gregory Bartholomew][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qhwdw](https://github.com/qhwdw)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,29 +1,30 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (SMPlayer in Linux: Features, Download and Installation)
|
||||
[#]: via: (https://itsfoss.com/smplayer/)
|
||||
[#]: author: (Aquil Roshan;Abhishek Prakash https://itsfoss.com/author/aquil/)
|
||||
[#]: url: ( )
|
||||
[#]: url: (https://linux.cn/article-10365-1.html)
|
||||
|
||||
Linux 中的 SMPlayer:功能,下载和安装
|
||||
SMPlayer:增强版的媒体播放器
|
||||
======
|
||||
|
||||
当你要播放视频时,你会在[全新安装的 Ubuntu][1],或其他许多发行版中,会注意到一个消息:
|
||||
|
||||
![][2]
|
||||
默认媒体播放器没有适合的编解码器
|
||||
|
||||
这意味着系统上没有安装播放媒体的[所需编解码器][3]。现在,由于某些版权问题,某些基于 Linux 的操作系统无法在安装介质中预先打包编解码器。但是它们能让你只需点击即可下载和安装编解码器,或者你可以安装拥有所有媒体编解码器的媒体播放器。了解一下 [SMPlayer][4]。
|
||||
*默认媒体播放器没有适合的编解码器*
|
||||
|
||||
这意味着系统上没有安装播放媒体的[所需编解码器][3]。现在,由于某些版权问题,某些基于 Linux 的操作系统无法在安装介质中预先打包编解码器。但是它们能让你只需点击即可下载和安装编解码器,或者你可以安装拥有所有媒体编解码器的媒体播放器。让我们了解一下 [SMPlayer][4]。
|
||||
|
||||
### 认识 SMPlayer:适用于 Linux 的更好的媒体播放器
|
||||
|
||||
SMPlayer 是一款免费的开源媒体播放器,它基于强大的 [MPlayer][5] 媒体引擎。SMPlayer 能够播放 avi、mp4、mkv、mpeg、mov、divx、h.264 以及其他任何主要媒体格式。锦上添花的是,它也可以播放 [YouTube][6] 视频,并且无广告。
|
||||
SMPlayer 是一款自由开源媒体播放器,它基于强大的 [MPlayer][5] 媒体引擎。SMPlayer 能够播放 avi、mp4、mkv、mpeg、mov、divx、h.264 以及其他任何主要媒体格式。锦上添花的是,它也可以播放 [YouTube][6] 视频,并且无广告。
|
||||
|
||||
![SMPlayer default interface][7]
|
||||
|
||||
SMPlayer 是一个完整的媒体解决方案。它是跨平台的,因此可在所有操作系统上使用。如果你是双启动,则可以将其安装在 Windows 和 Linux 操作系统上,以便在两个系统上获得统一的体验。它还支持带触摸的可变形笔记本。
|
||||
SMPlayer 是一个完整的媒体解决方案。它是跨平台的,因此可在所有操作系统上使用。如果你是双启动系统,则可以将其安装在 Windows 和 Linux 操作系统上,以便在两个系统上获得统一的体验。它还支持带触摸的可变形笔记本。
|
||||
|
||||
你也可以在 SMPlayer 上播放 YouTube。我知道每次复制粘贴视频 URL 并在外部播放器上播放是不切实际的。但是当你观看相对较长的视频时,SMPlayer 特别有用。SMPlayer 以相当好的质量播放 YouTube 视频,我觉得比在浏览器中播放得更好。通过在 SMPlayer 上播放较长的视频,你可以远离视频中间弹出的插播广告。
|
||||
|
||||
@ -51,7 +52,7 @@ SMPlayer 应该可在所有主要 Linux 发行版的软件中心获取。你可
|
||||
sudo apt install smplayer
|
||||
```
|
||||
|
||||
或者,你可以在[这里][11]下载 Fedora、Arch Linux、OpenSUSE 和 Debian 的软件包
|
||||
或者,你可以在[这里][11]下载 Fedora、Arch Linux、OpenSUSE 和 Debian 的软件包。
|
||||
|
||||
### 总结
|
||||
|
||||
@ -66,7 +67,7 @@ via: https://itsfoss.com/smplayer/
|
||||
作者:[Aquil Roshan;Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -83,4 +84,4 @@ via: https://itsfoss.com/smplayer/
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2018/11/SMPlayer-icon-packs.jpg?fit=800%2C450&ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2018/11/SMPlayer-theme.jpg?fit=800%2C450&ssl=1
|
||||
[11]: https://software.opensuse.org/download.html?project=home%3Asmplayerdev&package=smplayer
|
||||
[12]: https://itsfoss.com/essential-linux-applications/
|
||||
[12]: https://itsfoss.com/essential-linux-applications/
|
@ -1,26 +1,22 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10362-1.html)
|
||||
[#]: subject: (Four Easy Ways to Search Or Find Files And Folders in Linux)
|
||||
[#]: via: (https://www.2daygeek.com/four-easy-ways-to-search-or-find-files-and-folders-in-linux/)
|
||||
[#]: author: (Prakash Subramanian https://www.2daygeek.com/author/prakash/)
|
||||
|
||||
四种简单的方法来搜索或查找 Linux 中的文件和文件夹
|
||||
搜索 Linux 中的文件和文件夹的四种简单方法
|
||||
======
|
||||
|
||||
Linux 管理员一天都不能离开搜索文件,因为这是他们的日常活动。
|
||||
Linux 管理员一天都不能离开搜索文件,因为这是他们的日常活动。了解一些搜索的东西是不错的,因为这能帮助你在命令行服务器中工作。这些命令记忆起来不复杂,因为它们使用的是标准语法。
|
||||
|
||||
了解一些搜索的东西是不错的,因为这能帮助你在命令行服务器中工作。
|
||||
|
||||
这些命令记忆起来不复杂,因为它们使用的是标准语法。
|
||||
|
||||
这里执行四个 Linux 命令,每个命令都有自己独特的功能。
|
||||
可以通过四个 Linux 命令啦执行此操作,每个命令都有自己独特的功能。
|
||||
|
||||
### 方法 1:使用 find 命令在 Linux 中搜索文件和文件夹
|
||||
|
||||
find 命令被广泛使用,并且是非常著名的在 Linux 中搜索文件和文件夹的命令。它搜索当前目录中的给定文件,并根据搜索条件递归遍历其子目录。
|
||||
`find` 命令被广泛使用,并且是在 Linux 中搜索文件和文件夹的著名命令。它搜索当前目录中的给定文件,并根据搜索条件递归遍历其子目录。
|
||||
|
||||
它允许用户根据大小、名称、所有者、组、类型、权限、日期和其他条件执行所有类型的文件搜索。
|
||||
|
||||
@ -72,19 +68,19 @@ find 命令被广泛使用,并且是非常著名的在 Linux 中搜索文件
|
||||
|
||||
### 方法 2:使用 locate 命令在 Linux 中搜索文件和文件夹
|
||||
|
||||
locate 命令比 find 命令运行得更快,因为它使用 updatedb 数据库,而 find 命令在真实系统中搜索。
|
||||
`locate` 命令比 `find` 命令运行得更快,因为它使用 `updatedb` 数据库,而 `find` 命令在真实系统中搜索。
|
||||
|
||||
它使用数据库而不是搜索单个目录路径来获取给定文件。
|
||||
|
||||
locate 命令未在大多数发行版中预安装,因此,请使用你的包管理器进行安装。
|
||||
`locate` 命令未在大多数发行版中预安装,因此,请使用你的包管理器进行安装。
|
||||
|
||||
数据库通过 cron 定期更新,但我们可以通过运行以下命令手动更新它。
|
||||
数据库通过 cron 任务定期更新,但我们可以通过运行以下命令手动更新它。
|
||||
|
||||
```
|
||||
$ sudo updatedb
|
||||
```
|
||||
|
||||
只需运行以下命令即可列出给定的文件或文件夹。在 locate 命令中不需要指定特定选项来打印文件或文件夹。
|
||||
只需运行以下命令即可列出给定的文件或文件夹。在 `locate` 命令中不需要指定特定选项来打印文件或文件夹。
|
||||
|
||||
在系统中搜索 `ssh` 文件夹。
|
||||
|
||||
@ -107,13 +103,13 @@ $ sudo updatedb
|
||||
|
||||
### 方法 3:在 Linux 中搜索文件使用 which 命令
|
||||
|
||||
which 返回在终端输入命令时执行的可执行文件的完整路径。
|
||||
`which` 返回在终端输入命令时执行的可执行文件的完整路径。
|
||||
|
||||
当你想要为可执行文件创建桌面快捷方式或符号链接时,它非常有用。
|
||||
|
||||
which 命令搜索当前用户而不是所有用户的 PATH 环境变量中列出的目录。我的意思是,当你登录自己的帐户时,你无法搜索 root 用户文件或目录。
|
||||
`which` 命令搜索当前用户而不是所有用户的 `$PATH` 环境变量中列出的目录。我的意思是,当你登录自己的帐户时,你无法搜索 root 用户文件或目录。
|
||||
|
||||
运行以下命令以打印 vim 可执行文件的完整路径。
|
||||
运行以下命令以打印 `vim` 可执行文件的完整路径。
|
||||
|
||||
```
|
||||
# which vi
|
||||
@ -132,12 +128,13 @@ which 命令搜索当前用户而不是所有用户的 PATH 环境变量中列
|
||||
|
||||
### 方法 4:使用 whereis 命令在 Linux 中搜索文件
|
||||
|
||||
whereis 命令用于搜索给定命令的二进制、源码和手册页文件。
|
||||
`whereis` 命令用于搜索给定命令的二进制、源码和手册页文件。
|
||||
|
||||
```
|
||||
# whereis vi
|
||||
vi: /usr/bin/vi /usr/share/man/man1/vi.1p.gz /usr/share/man/man1/vi.1.gz
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/four-easy-ways-to-search-or-find-files-and-folders-in-linux/
|
||||
@ -145,9 +142,9 @@ via: https://www.2daygeek.com/four-easy-ways-to-search-or-find-files-and-folders
|
||||
作者:[Prakash Subramanian][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[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
|
||||
[b]: https://github.com/lujun9972
|
@ -1,28 +1,30 @@
|
||||
Bash 环境变量的那些事
|
||||
======
|
||||
> 初学者可以在此教程中了解环境变量。
|
||||
|
||||
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/wynand-van-poortvliet-40467-unsplash.jpg?itok=tr6Eb4N0)
|
||||
|
||||
bash 变量,尤其是讨厌的环境变量,已经是一个老生常谈的话题了。我们也更应该对它有一个详细的了解,让它为我们所用。
|
||||
bash 变量,尤其是讨厌的*环境变量*,已经是一个老生常谈的话题了。我们也更应该对它有一个详细的了解,让它为我们所用。
|
||||
|
||||
下面就打开终端,开始吧。
|
||||
|
||||
### 环境变量
|
||||
|
||||
`HOME` 除了是你脱下帽子惬意休息的地方,同时也是 Linux 中的一个变量,它是当前用户主目录的路径:
|
||||
`HOME` (LCTT 译注:双关语)除了是你脱下帽子惬意休息的地方,同时也是 Linux 中的一个变量,它是当前用户主目录的路径:
|
||||
|
||||
```
|
||||
echo $HOME
|
||||
```
|
||||
|
||||
以上这个命令会显示当前用户的主目录路径,通常都在 `/home/` 下。
|
||||
以上这个命令会显示当前用户的主目录路径,通常都在 `/home/<your username>` 下。
|
||||
|
||||
顾名思义,一个变量的值并不是固定的。实际上,Linux 系统中每一个用户的 `HOME` 变量都是不一样的,当然你也可以这样自行更改 `HOME` 变量的值:
|
||||
顾名思义,变量的值是可以根据上下文变化的。实际上,Linux 系统中每一个用户的 `HOME` 变量都是不一样的,当然你也可以这样自行更改 `HOME` 变量的值:
|
||||
|
||||
```
|
||||
HOME=/home/<your username>/Documents
|
||||
```
|
||||
|
||||
以上这个命令将会把 `HOME` 变量设置为 `/home/<your username>/Documents` 目录。
|
||||
以上这个命令将会把 `HOME` 变量设置为你的 `Documents` 目录。
|
||||
|
||||
其中有三点需要留意:
|
||||
|
||||
@ -45,7 +47,7 @@ $ echo $PATH
|
||||
/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
|
||||
```
|
||||
|
||||
每两个目录之间使用冒号(`:`)分隔。如果某个应用程序的所在目录不在 `PATH` 变量中,那么运行的时候就需要声明应用程序的目录让 shell 能够找到。
|
||||
每两个目录之间使用冒号 `:` 分隔。如果某个应用程序的所在目录不在 `PATH` 变量中,那么运行的时候就需要声明应用程序的目录让 shell 能够找到。
|
||||
|
||||
```
|
||||
/home/<user name>/bin/my_program.sh
|
||||
@ -67,9 +69,9 @@ PATH=$PATH:$HOME/bin
|
||||
|
||||
然后 `/home/<user name>/bin/` 目录就会出现在 `PATH` 变量中了。但正如之前所说,这个变更只会在当前的 shell 生效,当前的 shell 一旦关闭,环境变量的值就又恢复原状了。
|
||||
|
||||
如果要让变更对当前用户持续生效,就不能在 shell 中直接执行对应的变更,而是应该将这些变更操作卸载每次启动 shell 时都会运行的文件当中。这个文件就是当前用户主目录中的 `.bashrc` 文件。文件名前面的点号表明这是一个隐藏文件,执行普通的 `ls` 命令是不会将这个文件显示出来的,但只要在 `ls` 命令中加入 `-a` 参数就可以看到这个文件了。
|
||||
如果要让变更对当前用户持续生效,就不能在 shell 中直接执行对应的变更,而是应该将这些变更操作写在每次启动 shell 时都会运行的文件当中。这个文件就是当前用户主目录中的 `.bashrc` 文件。文件名前面的点号表明这是一个隐藏文件,执行普通的 `ls` 命令是不会将这个文件显示出来的,但只要在 `ls` 命令中加入 `-a` 参数就可以看到这个文件了。
|
||||
|
||||
你可以使用诸如 [kate][1]、[gedit][2]、[nano][3] 或者 [vim][4] 这些文本编辑器来打开 `.bashrc` 文件(但不要用 LibreOffice Writer,它是一个文字处理软件,跟前面几个文字编辑器并不一个量级的东西)。打开 `.bashrc` 文件之后,你会看见里面放置了一些 shell 命令,是用于为当前用户设置环境的。
|
||||
你可以使用诸如 [kate][1]、[gedit][2]、[nano][3] 或者 [vim][4] 这些文本编辑器来打开 `.bashrc` 文件(但不要用 LibreOffice Writer,它是一个文字处理软件,跟前面几个文字编辑器完全不同)。打开 `.bashrc` 文件之后,你会看见里面放置了一些 shell 命令,是用于为当前用户设置环境的。
|
||||
|
||||
在文件的末尾添加新行并输入以下内容:
|
||||
|
||||
@ -97,13 +99,13 @@ source .bashrc
|
||||
new_variable="Hello"
|
||||
```
|
||||
|
||||
然后可以用一下的方式读取到已定义变量的值:
|
||||
然后可以用以下的方式读取到已定义变量的值:
|
||||
|
||||
```
|
||||
echo $new_variable
|
||||
```
|
||||
|
||||
程序的正常工作离不开各种变量,例如要将某个选项设置为 on,又或者让程序找到所需的代码库,都需要使用变量。在 bash 中运行程序的时候会生成一个子 shell,这个子 shell 和执行原程序的父 shell 并不是完全一样的,只是继承了父 shell 的部分内容,而且默认是不继承父 shell 中的变量的。因为变量默认情况下是局部变量,出于安全原因,一个 shell 中的局部变量不会被另一个 shell 读取到,即使是子 shell 也不可以。
|
||||
程序的正常工作离不开各种变量,例如要将某个选项设置为打开,又或者让程序找到所需的代码库,都需要使用变量。在 bash 中运行程序的时候会生成一个子 shell,这个子 shell 和执行原程序的父 shell 并不是完全一样的,只是继承了父 shell 的部分内容,而且默认是不继承父 shell 中的变量的。因为变量默认情况下是局部变量,出于安全原因,一个 shell 中的局部变量不会被另一个 shell 读取到,即使是子 shell 也不可以。
|
||||
|
||||
下面举一个例子。首先定义一个变量:
|
||||
|
||||
@ -198,7 +200,7 @@ via: https://www.linux.com/blog/learn/2018/12/bash-variables-environmental-and-o
|
||||
作者:[Paul Brown][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[HankChow](https://github.com/HankChow)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,22 +1,24 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (Bring some color to your Linux terminal with lolcat)
|
||||
[#]: via: (https://opensource.com/article/18/12/linux-toy-lolcat)
|
||||
[#]: author: (Jason Baker https://opensource.com/users/jason-baker)
|
||||
[#]: url: ( )
|
||||
[#]: url: (https://linux.cn/article-10361-1.html)
|
||||
|
||||
使用 lolcat 为你的 Linux 终端带来一些颜色
|
||||
使用 lolcat 为你的 Linux 终端带来彩虹
|
||||
======
|
||||
使用这个简单的程序,你可以为所需的任何程序的输出添加彩色。
|
||||
|
||||
> 使用这个简单的工具,你可以为所需的任何程序的输出变成七彩。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/uploads/linux-toy-lolcat.png?itok=Es6dYcph)
|
||||
|
||||
今天是 Linux 命令行玩具日历的第五天。如果这是你第一次访问该系列,你可能会问自己,什么是命令行玩具。即使我不太确定,但一般来说,它可能是一个游戏,或任何简单的可以帮助你在终端玩得开心的东西。
|
||||
|
||||
很可能你们中的一些人之前已经看过我们日历中的各种选择,但我们希望每个人至少见到一件新事物。
|
||||
很可能你们中的一些人之前已经看过我们日历中的各种玩具,但我们希望每个人至少见到一件新事物。
|
||||
|
||||
今日的选择,**lolcat**,是我选择的第一个没有在我的 Linux 发行版中打包的程序,但它安装仍然很简单。它是一个 Ruby 程序,你应该可以使用下面的命令轻松地添加到系统中。
|
||||
今日的选择,`lolcat`,是我选择的第一个没有在我的 Linux 发行版中打包的程序,但它安装仍然很简单。它是一个 Ruby 程序,你应该可以使用下面的命令轻松地添加到系统中。
|
||||
|
||||
```
|
||||
$ gem install lolcat
|
||||
@ -29,15 +31,18 @@ $ fortune | boxes -a c -d parchment | lolcat
|
||||
```
|
||||
|
||||
根据你的运气,你可能会看到这样:
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/linux-toy-lolcat-parchment.png)
|
||||
|
||||
你可以传递给 **lolcat** 一些参数而不必重复它们,我建议你访问 **lolcat** 的 [GitHub 页面][1] 或者在终端输入 **lolcat --help** 了解。但一般来说,它们能设置彩虹的传递和频率,以及我个人最喜欢的动画。谁不喜欢终端的彩色动画打印?让我们再试一次,用一个不同的边框(当然是以猫为主题)和一句在我的句子列表中的适合猫的句子。
|
||||
你可以传递给 `lolcat` 一些参数。这里不再赘述,我建议你访问 `lolcat` 的 [GitHub 页面][1] 或者在终端输入 `lolcat --help` 了解。但一般来说,它们能设置彩虹的传递和频率,以及我个人最喜欢的动画。谁不喜欢终端的彩色动画输出呢?让我们再试一次,用一个不同的边框(当然是以猫为主题)和一句在我的格言列表中的适合猫的句子。
|
||||
|
||||
```
|
||||
fortune -m "nine tails" | boxes -a c -d cat | lolcat -a
|
||||
```
|
||||
|
||||
![](https://opensource.com/sites/default/files/uploads/linux-toy-lolcat-animated.gif)
|
||||
**lolcat** 是 BSD 许可下的开源软件。
|
||||
|
||||
`lolcat` 是一个 BSD 许可下的开源软件。
|
||||
|
||||
你有特别喜欢的命令行小玩具需要我介绍的吗?这个系列要介绍的小玩具大部分已经有了落实,但还预留了几个空位置。如果你有特别想了解的可以评论留言,我会查看的。如果还有空位置,我会考虑介绍它的。如果没有,但如果我得到了一些很好的意见,我会在最后做一些有价值的提及。
|
||||
|
||||
@ -50,11 +55,11 @@ via: https://opensource.com/article/18/12/linux-toy-lolcat
|
||||
作者:[Jason Baker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[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/busyloop/lolcat
|
||||
[2]: https://opensource.com/article/18/12/linux-toy-cowsay
|
||||
[2]: https://opensource.com/article/18/12/linux-toy-cowsay
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user