mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
commit
1ef71c037d
@ -0,0 +1,149 @@
|
||||
分布式跟踪系统的四大功能模块如何协同工作
|
||||
======
|
||||
|
||||
> 了解分布式跟踪中的主要体系结构决策,以及各部分如何组合在一起。
|
||||
|
||||
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/touch-tracing.jpg?itok=rOmsY-nU)
|
||||
|
||||
早在十年前,认真研究过分布式跟踪基本上只有学者和一小部分大型互联网公司中的人。对于任何采用微服务的组织来说,它如今成为一种筹码。其理由是确立的:微服务通常会发生让人意想不到的错误,而分布式跟踪则是描述和诊断那些错误的最好方法。
|
||||
|
||||
也就是说,一旦你准备将分布式跟踪集成到你自己的应用程序中,你将很快意识到对于不同的人来说“<ruby>分布式跟踪<rt>Distributed Tracing</rt></ruby>”一词意味着不同的事物。此外,跟踪生态系统里挤满了具有相似内容的重叠项目。本文介绍了分布式跟踪系统中四个(可能)独立的功能模块,并描述了它们间将如何协同工作。
|
||||
|
||||
### 分布式跟踪:一种思维模型
|
||||
|
||||
大多数用于跟踪的思维模型来源于 [Google 的 Dapper 论文][1]。[OpenTracing][2] 使用相似的术语,因此,我们从该项目借用了以下术语:
|
||||
|
||||
![Tracing][3]
|
||||
|
||||
* <ruby>跟踪<rt>Trace</rt></ruby>:事物在分布式系统运行的过程描述。
|
||||
* <ruby>跨度<rt>Span</rt></ruby>:一种命名的定时操作,表示工作流的一部分。跨度可接受键值对标签以及附加到特定跨度实例的细粒度的、带有时间戳的结构化日志。
|
||||
* <ruby>跨度上下文<rt>Span context</rt></ruby>:携带分布式事务的跟踪信息,包括当它通过网络或消息总线将服务传递给服务时。跨度上下文包含跟踪标识符、跨度标识符以及跟踪系统所需传播到下游服务的任何其他数据。
|
||||
|
||||
如果你想要深入研究这种思维模式的细节,请仔细参照 [OpenTracing 技术规范][1]。
|
||||
|
||||
### 四大功能模块
|
||||
|
||||
从应用层分布式跟踪系统的观点来看,现代软件系统架构如下图所示:
|
||||
|
||||
![Tracing][5]
|
||||
|
||||
现代软件系统的组件可分为三类:
|
||||
|
||||
* **应用程序和业务逻辑**:你的代码。
|
||||
* **广泛共享库**:他人的代码
|
||||
* **广泛共享服务**:他人的基础架构
|
||||
|
||||
这三类组件有着不同的需求,驱动着监控应用程序的分布式跟踪系统的设计。最终的设计得到了四个重要的部分:
|
||||
|
||||
* <ruby>跟踪检测 API<rt>A tracing instrumentation API</rt></ruby>:修饰应用程序代码
|
||||
* <ruby>线路协议<rt>Wire protocol</rt></ruby>:在 RPC 请求中与应用程序数据一同发送的规定
|
||||
* <ruby>数据协议<rt>Data protocol</rt></ruby>:将异步信息(带外)发送到你的分析系统的规定
|
||||
* <ruby>分析系统<rt>Analysis system</rt></ruby>:用于处理跟踪数据的数据库和交互式用户界面
|
||||
|
||||
为了更深入的解释这个概念,我们将深入研究驱动该设计的细节。如果你只需要我的一些建议,请跳转至下方的四大解决方案。
|
||||
|
||||
### 需求,细节和解释
|
||||
|
||||
应用程序代码、共享库以及共享式服务在操作上有显著的差别,这种差别严重影响了对其进行检测的请求操作。
|
||||
|
||||
#### 检测应用程序代码和业务逻辑
|
||||
|
||||
在任何特定的微服务中,由微服务开发者编写的大部分代码是应用程序或者商业逻辑。这部分代码规定了特定区域的操作。通常,它包含任何特殊、独一无二的逻辑判断,这些逻辑判断首先证明了创建新型微服务的合理性。基本上按照定义,**该代码通常不会在多个服务中共享或者以其他方式出现。**
|
||||
|
||||
也即是说你仍需了解它,这也意味着需要以某种方式对它进行检测。一些监控和跟踪分析系统使用<ruby>黑盒代理<rt>black-box agents</rt></ruby>自动检测代码,另一些系统更想使用显式的白盒检测工具。对于后者,抽象跟踪 API 提供了许多对于微服务的应用程序代码来说更为实用的优势:
|
||||
|
||||
* 抽象 API 允许你在不重新编写检测代码的条件下换新的监视工具。你可能想要变更云服务提供商、供应商和监测技术,而一大堆不可移植的检测代码将会为该过程增加有意义的开销和麻烦。
|
||||
* 事实证明,除了生产监控之外,该工具还有其他有趣的用途。现有的项目使用相同的跟踪工具来驱动测试工具、分布式调试器、“混沌工程”故障注入器和其他元应用程序。
|
||||
* 但更重要的是,若将应用程序组件提取到共享库中要怎么办呢?由上述内容可得到结论:
|
||||
|
||||
#### 检测共享库
|
||||
|
||||
在大多数应用程序中出现的实用程序代码(处理网络请求、数据库调用、磁盘写操作、线程、并发管理等)通常情况下是通用的,而非特别应用于某个特定应用程序。这些代码会被打包成库和框架,而后就可以被装载到许多的微服务上并且被部署到多种不同的环境中。
|
||||
|
||||
其真正的不同是:对于共享代码,其他人则成为了使用者。大多数用户有不同的依赖关系和操作风格。如果尝试去使用该共享代码,你将会注意到几个常见的问题:
|
||||
|
||||
* 你需要一个 API 来编写检测。然而,你的库并不知道你正在使用哪个分析系统。会有多种选择,并且运行在相同应用下的所有库无法做出不兼容的选择。
|
||||
* 由于这些包封装了所有网络处理代码,因此从请求报头注入和提取跨度上下文的任务往往指向 RPC 库。然而,共享库必须了解到每个应用程序正在使用哪种跟踪协议。
|
||||
* 最后,你不想强制用户使用相互冲突的依赖项。大多数用户有不同的依赖关系和操作风格。即使他们使用 gRPC,绑定的 gRPC 版本是否相同?因此任何你的库附带用于跟踪的监控 API 必定是免于依赖的。
|
||||
|
||||
**因此,一个(a)没有依赖关系、(b)与线路协议无关、(c)使用流行的供应商和分析系统的抽象 API 应该是对检测共享库代码的要求。**
|
||||
|
||||
#### 检测共享式服务
|
||||
|
||||
最后,有时整个服务(或微服务集合体)的通用性足以使许多独立的应用程序使用它们。这种共享式服务通常由第三方托管和管理,例如缓存服务器、消息队列以及数据库。
|
||||
|
||||
从应用程序开发者的角度来看,理解共享式服务本质上是黑盒子是极其重要的。它不可能将你的应用程序监控注入到共享式服务。恰恰相反,托管服务通常会运行它自己的监控方案。
|
||||
|
||||
### 四个方面的解决方案
|
||||
|
||||
因此,抽象的跟踪应用程序接口将会帮助库发出数据并且注入/抽取跨度上下文。标准的线路协议将会帮助黑盒服务相互连接,而标准的数据格式将会帮助分离的分析系统合并其中的数据。让我们来看一下部分有希望解决这些问题的方案。
|
||||
|
||||
#### 跟踪 API:OpenTracing 项目
|
||||
|
||||
如你所见,我们需要一个跟踪 API 来检测应用程序代码。为了将这种工具扩展到大多数进行跨度上下文注入和提取的共享库中,则必须以某种关键方式对 API 进行抽象。
|
||||
|
||||
[OpenTracing][2] 项目主要针对解决库开发者的问题,OpenTracing 是一个与供应商无关的跟踪 API,它没有依赖关系,并且迅速得到了许多监控系统的支持。这意味着,如果库附带了内置的本地 OpenTracing 工具,当监控系统在应用程序启动连接时,跟踪将会自动启动。
|
||||
|
||||
就个人而言,作为一个已经编写、发布和操作开源软件十多年的人,在 OpenTracing 项目上工作并最终解决这个观察性的难题令我十分满意。
|
||||
|
||||
除了 API 之外,OpenTracing 项目还维护了一个不断增长的工具列表,其中一些可以在[这里][6]找到。如果你想参与进来,无论是通过提供一个检测插件,对你自己的 OSS 库进行本地测试,或者仅仅只想问个问题,都可以通过 [Gitter][7] 向我们打招呼。
|
||||
|
||||
#### 线路协议: HTTP 报头 trace-context
|
||||
|
||||
为了监控系统能进行互操作,以及减轻从一个监控系统切换为另外一个时带来的迁移问题,需要标准的线路协议来传播跨度上下文。
|
||||
|
||||
[w3c 分布式跟踪上下文社区小组][8]在努力制定此标准。目前的重点是制定一系列标准的 HTTP 报头。该规范的最新草案可以在[此处][9]找到。如果你对此小组有任何的疑问,[邮件列表][10]和[Gitter 聊天室][11]是很好的解惑地点。
|
||||
|
||||
(LCTT 译注:本文原文发表于 2018 年 5 月,可能现在社区已有不同进展)
|
||||
|
||||
#### 数据协议 (还未出现!!)
|
||||
|
||||
对于黑盒服务,在无法安装跟踪程序或无法与程序进行交互的情况下,需要使用数据协议从系统中导出数据。
|
||||
|
||||
目前这种数据格式和协议的开发工作尚处在初级阶段,并且大多在 w3c 分布式跟踪上下文工作组的上下文中进行工作。需要特别关注的是在标准数据模式中定义更高级别的概念,例如 RPC 调用、数据库语句等。这将允许跟踪系统对可用数据类型做出假设。OpenTracing 项目也通过定义一套[标准标签集][12]来解决这一事务。该计划是为了使这两项努力结果相互配合。
|
||||
|
||||
注意当前有一个中间地带。对于由应用程序开发者操作但不想编译或以其他方式执行代码修改的“网络设备”,动态链接可以帮助避免这种情况。主要的例子就是服务网格和代理,就像 Envoy 或者 NGINX。针对这种情况,可将兼容 OpenTracing 的跟踪器编译为共享对象,然后在运行时动态链接到可执行文件中。目前 [C++ OpenTracing API][13] 提供了该选项。而 JAVA 的 OpenTracing [跟踪器解析][14]也在开发中。
|
||||
|
||||
这些解决方案适用于支持动态链接,并由应用程序开发者部署的的服务。但从长远来看,标准的数据协议可以更广泛地解决该问题。
|
||||
|
||||
#### 分析系统:从跟踪数据中提取有见解的服务
|
||||
|
||||
最后不得不提的是,现在有足够多的跟踪监视解决方案。可以在[此处][15]找到已知与 OpenTracing 兼容的监控系统列表,但除此之外仍有更多的选择。我更鼓励你研究你的解决方案,同时希望你在比较解决方案时发现本文提供的框架能派上用场。除了根据监控系统的操作特性对其进行评级外(更不用提你是否喜欢 UI 和其功能),确保你考虑到了上述三个重要方面、它们对你的相对重要性以及你感兴趣的跟踪系统如何为它们提供解决方案。
|
||||
|
||||
### 结论
|
||||
|
||||
最后,每个部分的重要性在很大程度上取决于你是谁以及正在建立什么样的系统。举个例子,开源库的作者对 OpenTracing API 非常感兴趣,而服务开发者对 trace-context 规范更感兴趣。当有人说一部分比另一部分重要时,他们的意思通常是“一部分对我来说比另一部分重要”。
|
||||
|
||||
然而,事实是:分布式跟踪已经成为监控现代系统所必不可少的事物。在为这些系统进行构建模块时,“尽可能解耦”的老方法仍然适用。在构建像分布式监控系统一样的跨系统的系统时,干净地解耦组件是维持灵活性和前向兼容性地最佳方式。
|
||||
|
||||
感谢你的阅读!现在当你准备好在你自己的应用程序中实现跟踪服务时,你已有一份指南来了解他们正在谈论哪部分部分以及它们之间如何相互协作。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/5/distributed-tracing
|
||||
|
||||
作者:[Ted Young][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[chenmu-kk](https://github.com/chenmu-kk)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/tedsuo
|
||||
[1]:https://research.google.com/pubs/pub36356.html
|
||||
[2]:http://opentracing.io/
|
||||
[3]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/uploads/tracing1_0.png?itok=dvDTX0JJ (Tracing)
|
||||
[4]:https://github.com/opentracing/specification/blob/master/specification.md
|
||||
[5]:https://opensource.com/sites/default/files/styles/panopoly_image_original/public/uploads/tracing2_0.png?itok=yokjNLZk (Tracing)
|
||||
[6]:https://github.com/opentracing-contrib/
|
||||
[7]:https://gitter.im/opentracing/public
|
||||
[8]:https://www.w3.org/community/trace-context/
|
||||
[9]:https://w3c.github.io/distributed-tracing/report-trace-context.html
|
||||
[10]:http://lists.w3.org/Archives/Public/public-trace-context/
|
||||
[11]:https://gitter.im/TraceContext/Lobby
|
||||
[12]:https://github.com/opentracing/specification/blob/master/semantic_conventions.md
|
||||
[13]:https://github.com/opentracing/opentracing-cpp
|
||||
[14]:https://github.com/opentracing-contrib/java-tracerresolver
|
||||
[15]:http://opentracing.io/documentation/pages/supported-tracers
|
||||
[16]:https://events.linuxfoundation.org/kubecon-eu-2018/
|
||||
[17]:https://events.linuxfoundation.org/events/kubecon-cloudnativecon-north-america-2018/
|
@ -0,0 +1,159 @@
|
||||
MidnightBSD:或许是你通往 FreeBSD 的大门
|
||||
======
|
||||
|
||||
![](https://www.linux.com/wp-content/uploads/2019/08/midnight_4_0.jpg)
|
||||
|
||||
[FreeBSD][1] 是一个开源操作系统,衍生自著名的 <ruby>[伯克利软件套件][2]<rt>Berkeley Software Distribution</rt></ruby>(BSD)。FreeBSD 的第一个版本发布于 1993 年,并且仍然在继续发展。2007 年左右,Lucas Holt 想要利用 OpenStep(现在是 Cocoa)的 Objective-C 框架、widget 工具包和应用程序开发工具的 [GnuStep][3] 实现,来创建一个 FreeBSD 的分支。为此,他开始开发 MidnightBSD 桌面发行版。
|
||||
|
||||
MidnightBSD(以 Lucas 的猫 Midnight 命名)仍然在积极地(尽管缓慢)开发。从 2017 年 8 月开始,可以获得最新的稳定发布版本(0.8.6)(LCTT 译注:截止至本译文发布时,当前是 2019/10/31 发布的 1.2 版)。尽管 BSD 发行版不是你所说的用户友好型发行版,但上手安装是熟悉如何处理 文本(ncurses)安装过程以及通过命令行完成安装的好方法。
|
||||
|
||||
这样,你最终会得到一个非常可靠的 FreeBSD 分支的桌面发行版。这需要花费一点精力,但是如果你是一名正在寻找扩展你的技能的 Linux 用户……这是一个很好的起点。
|
||||
|
||||
我将带你走过安装 MidnightBSD 的流程,如何添加一个图形桌面环境,然后如何安装应用程序。
|
||||
|
||||
### 安装
|
||||
|
||||
正如我所提到的,这是一个文本(ncurses)安装过程,因此在这里找不到可以用鼠标点击的地方。相反,你将使用你键盘的 `Tab` 键和箭头键。在你下载[最新的发布版本][4]后,将它刻录到一个 CD/DVD 或 USB 驱动器,并启动你的机器(或者在 [VirtualBox][5] 中创建一个虚拟机)。安装程序将打开并给你三个选项(图 1)。使用你的键盘的箭头键选择 “Install”,并敲击回车键。
|
||||
|
||||
![MidnightBSD installer][6]
|
||||
|
||||
*图 1: 启动 MidnightBSD 安装程序。*
|
||||
|
||||
在这里要经历相当多的屏幕。其中很多屏幕是一目了然的:
|
||||
|
||||
1. 设置非默认键盘映射(是/否)
|
||||
2. 设置主机名称
|
||||
3. 添加可选系统组件(文档、游戏、32 位兼容性、系统源码代码)
|
||||
4. 对硬盘分区
|
||||
5. 管理员密码
|
||||
6. 配置网络接口
|
||||
7. 选择地区(时区)
|
||||
8. 启用服务(例如 ssh)
|
||||
9. 添加用户(图 2)
|
||||
|
||||
![Adding a user][7]
|
||||
|
||||
*图 2: 向系统添加一个用户。*
|
||||
|
||||
在你向系统添加用户后,你将被进入到一个窗口中(图 3),在这里,你可以处理任何你可能忘记配置或你想重新配置的东西。如果你不需要作出任何更改,选择 “Exit”,然后你的配置就会被应用。
|
||||
|
||||
![Applying your configurations][8]
|
||||
|
||||
*图 3: 应用你的配置。*
|
||||
|
||||
在接下来的窗口中,当出现提示时,选择 “No”,接下来系统将重启。在 MidnightBSD 重启后,你已经为下一阶段的安装做好了准备。
|
||||
|
||||
### 后安装阶段
|
||||
|
||||
当你最新安装的 MidnightBSD 启动时,你将发现你自己处于命令提示符当中。此刻,还没有图形界面。要安装应用程序,MidnightBSD 依赖于 `mport` 工具。比如说你想安装 Xfce 桌面环境。为此,登录到 MidnightBSD 中,并发出下面的命令:
|
||||
|
||||
```
|
||||
sudo mport index
|
||||
sudo mport install xorg
|
||||
```
|
||||
|
||||
你现在已经安装好 Xorg 窗口服务器了,它允许你安装桌面环境。使用命令来安装 Xfce :
|
||||
|
||||
```
|
||||
sudo mport install xfce
|
||||
```
|
||||
|
||||
现在 Xfce 已经安装好。不过,我们必须让它同命令 `startx` 一起启用。为此,让我们先安装 nano 编辑器。发出命令:
|
||||
|
||||
```
|
||||
sudo mport install nano
|
||||
```
|
||||
|
||||
随着 nano 安装好,发出命令:
|
||||
|
||||
```
|
||||
nano ~/.xinitrc
|
||||
```
|
||||
|
||||
这个文件仅包含一行内容:
|
||||
|
||||
```
|
||||
exec startxfce4
|
||||
```
|
||||
|
||||
保存并关闭这个文件。如果你现在发出命令 `startx`, Xfce 桌面环境将会启动。你应该会感到有点熟悉了吧(图 4)。
|
||||
|
||||
![ Xfce][9]
|
||||
|
||||
*图 4: Xfce 桌面界面已准备好服务。*
|
||||
|
||||
因为你不会总是想必须发出命令 `startx`,你希望启用登录守护进程。然而,它却没有安装。要安装这个子系统,发出命令:
|
||||
|
||||
```
|
||||
sudo mport install mlogind
|
||||
```
|
||||
|
||||
当完成安装后,通过在 `/etc/rc.conf` 文件中添加一个项目来在启动时启用 mlogind。在 `rc.conf` 文件的底部,添加以下内容:
|
||||
|
||||
```
|
||||
mlogind_enable=”YES”
|
||||
```
|
||||
|
||||
保存并关闭该文件。现在,当你启动(或重启)机器时,你应该会看到图形登录屏幕。在写这篇文章的时候,在登录后我最后得到一个空白屏幕和讨厌的 X 光标。不幸的是,目前似乎并没有这个问题的解决方法。所以,要访问你的桌面环境,你必须使用 `startx` 命令。
|
||||
|
||||
### 安装应用
|
||||
|
||||
默认情况下,你找不到很多能可用的应用程序。如果你尝试使用 `mport` 安装应用程序,你很快就会感到沮丧,因为只能找到很少的应用程序。为解决这个问题,我们需要使用 `svnlite` 命令来查看检出的可用 mport 软件列表。回到终端窗口,并发出命令:
|
||||
|
||||
```
|
||||
svnlite co http://svn.midnightbsd.org/svn/mports/trunk mports
|
||||
```
|
||||
|
||||
在你完成这些后,你应该看到一个命名为 `~/mports` 的新目录。使用命令 `cd ~/.mports` 更改到这个目录。发出 `ls` 命令,然后你应该看到许多的类别(图 5)。
|
||||
|
||||
![applications][10]
|
||||
|
||||
*图 5: mport 现在可用的应用程序类别。*
|
||||
|
||||
你想安装 Firefox 吗?如果你查看 `www` 目录,你将看到一个 `linux-firefox` 列表。发出命令:
|
||||
|
||||
```
|
||||
sudo mport install linux-firefox
|
||||
```
|
||||
|
||||
现在你应该会在 Xfce 桌面菜单中看到一个 Firefox 项。翻找所有的类别,并使用 `mport` 命令来安装你需要的所有软件。
|
||||
|
||||
### 一个悲哀的警告
|
||||
|
||||
一个悲哀的小警告是,`mport` (通过 `svnlite`)仅能找到的一个办公套件的版本是 OpenOffice 3 。那是非常过时的。尽管在 `~/mports/editors` 目录中能找到 Abiword ,但是它看起来不能安装。甚至在安装 OpenOffice 3 后,它会输出一个执行格式错误。换句话说,你不能使用 MidnightBSD 在办公生产效率方面做很多的事情。但是,嘿嘿,如果你周围正好有一个旧的 Palm Pilot,你可以安装 pilot-link。换句话说,可用的软件不足以构成一个极其有用的桌面发行版……至少对普通用户不是。但是,如果你想在 MidnightBSD 上开发,你将找到很多可用的工具可以安装(查看 `~/mports/devel` 目录)。你甚至可以使用命令安装 Drupal :
|
||||
|
||||
```
|
||||
sudo mport install drupal7
|
||||
```
|
||||
|
||||
当然,在此之后,你将需要创建一个数据库(MySQL 已经安装)、安装 Apache(`sudo mport install apache24`),并配置必要的 Apache 配置。
|
||||
|
||||
显然地,已安装的和可以安装的是一个应用程序、系统和服务的大杂烩。但是随着足够多的工作,你最终可以得到一个能够服务于特殊目的的发行版。
|
||||
|
||||
### 享受 \*BSD 优良
|
||||
|
||||
这就是如何使 MidnightBSD 启动,并使其运行某种有用的桌面发行版的方法。它不像很多其它的 Linux 发行版一样快速简便,但是如果你想要一个促使你思考的发行版,这可能正是你正在寻找的。尽管大多数竞争对手都准备了很多可以安装的应用软件,但 MidnightBSD 无疑是一个 Linux 爱好者或管理员应该尝试的有趣挑战。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/learn/intro-to-linux/2018/5/midnightbsd-could-be-your-gateway-freebsd
|
||||
|
||||
作者:[Jack Wallen][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[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.freebsd.org/
|
||||
[2]:https://en.wikipedia.org/wiki/Berkeley_Software_Distribution
|
||||
[3]:https://en.wikipedia.org/wiki/GNUstep
|
||||
[4]:http://www.midnightbsd.org/download/
|
||||
[5]:https://www.virtualbox.org/
|
||||
[6]:https://lcom.static.linuxfound.org/sites/lcom/files/midnight_1.jpg (MidnightBSD installer)
|
||||
[7]:https://lcom.static.linuxfound.org/sites/lcom/files/midnight_2.jpg (Adding a user)
|
||||
[8]:https://lcom.static.linuxfound.org/sites/lcom/files/mightnight_3.jpg (Applying your configurations)
|
||||
[9]:https://lcom.static.linuxfound.org/sites/lcom/files/midnight_4.jpg (Xfce)
|
||||
[10]:https://lcom.static.linuxfound.org/sites/lcom/files/midnight_5.jpg (applications)
|
||||
[11]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
236
published/20190407 Manage multimedia files with Git.md
Normal file
236
published/20190407 Manage multimedia files with Git.md
Normal file
@ -0,0 +1,236 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (svtter)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11889-1.html)
|
||||
[#]: subject: (Manage multimedia files with Git)
|
||||
[#]: via: (https://opensource.com/article/19/4/manage-multimedia-files-git)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
|
||||
通过 Git 来管理多媒体文件
|
||||
======
|
||||
|
||||
> 在我们有关 Git 鲜为人知的用法系列的最后一篇文章中,了解如何使用 Git 跟踪项目中的大型多媒体文件。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/13/235436mhub12qhxzmbw11p.png)
|
||||
|
||||
Git 是专用于源代码版本控制的工具。因此,Git 很少被用于非纯文本的项目以及行业。然而,异步工作流的优点是十分诱人的,尤其是在一些日益增长的行业中,这种类型的行业把重要的计算和重要的艺术创作结合起来,这包括网页设计、视觉效果、视频游戏、出版、货币设计(是的,这是一个真实的行业)、教育……等等。还有许多行业属于这个类型。
|
||||
|
||||
在这个 Git 系列文章中,我们分享了六种鲜为人知的 Git 使用方法。在最后一篇文章中,我们将介绍将 Git 的优点带到管理多媒体文件的软件。
|
||||
|
||||
### Git 管理多媒体文件的问题
|
||||
|
||||
众所周知,Git 用于处理非文本文件不是很好,但是这并不妨碍我们进行尝试。下面是一个使用 Git 来复制照片文件的例子:
|
||||
|
||||
```
|
||||
$ du -hs
|
||||
108K .
|
||||
$ cp ~/photos/dandelion.tif .
|
||||
$ git add dandelion.tif
|
||||
$ git commit -m 'added a photo'
|
||||
[master (root-commit) fa6caa7] two photos
|
||||
1 file changed, 0 insertions(+), 0 deletions(-)
|
||||
create mode 100644 dandelion.tif
|
||||
$ du -hs
|
||||
1.8M .
|
||||
```
|
||||
|
||||
目前为止没有什么异常。增加一个 1.8MB 的照片到一个目录下,使得目录变成了 1.8 MB 的大小。所以下一步,我们尝试删除文件。
|
||||
|
||||
```
|
||||
$ git rm dandelion.tif
|
||||
$ git commit -m 'deleted a photo'
|
||||
$ du -hs
|
||||
828K .
|
||||
```
|
||||
|
||||
在这里我们可以看到有些问题:删除一个已经被提交的文件,还是会使得存储库的大小扩大到原来的 8 倍(从 108K 到 828K)。我们可以测试多次来得到一个更好的平均值,但是这个简单的演示与我的经验一致。提交非文本文件,在一开始花费空间比较少,但是一个工程活跃地时间越长,人们可能对静态内容修改的会更多,更多的零碎文件会被加和到一起。当一个 Git 存储库变的越来越大,主要的成本往往是速度。拉取和推送的时间,从最初抿一口咖啡的时间到你觉得你可能断网了。
|
||||
|
||||
静态内容导致 Git 存储库的体积不断扩大的原因是什么呢?那些通过文本的构成的文件,允许 Git 只拉取那些修改的部分。光栅图以及音乐文件对 Git 文件而言与文本不同,你可以查看一下 .png 和 .wav 文件中的二进制数据。所以,Git 只不过是获取了全部的数据,并且创建了一个新的副本,哪怕是一张图仅仅修改了一个像素。
|
||||
|
||||
### Git-portal
|
||||
|
||||
在实践中,许多多媒体项目不需要或者不想追踪媒体的历史记录。相对于文本或者代码的部分,项目的媒体部分一般有一个不同的生命周期。媒体资源一般按一个方向产生:一张图片从铅笔草稿开始,以数字绘画的形式抵达它的目的地。然后,尽管文本能够回滚到早起的版本,但是艺术制品只会一直向前发展。工程中的媒体很少被绑定到一个特定的版本。例外情况通常是反映数据集的图形,通常是可以用基于文本的格式(如 SVG)完成的表、图形或图表。
|
||||
|
||||
所以,在许多同时包含文本(无论是叙事散文还是代码)和媒体的工程中,Git 是一个用于文件管理的,可接受的解决方案,只要有一个在版本控制循环之外的游乐场来给艺术家游玩就行。
|
||||
|
||||
![Graphic showing relationship between art assets and Git][2]
|
||||
|
||||
一个启用这个特性的简单方法是 [Git-portal][3],这是一个通过带有 Git 钩子的 Bash 脚本,它可将静态文件从文件夹中移出 Git 的范围,并通过符号链接来取代它们。Git 提交链接文件(有时候称作别名或快捷方式),这种符号链接文件比较小,所以所有的提交都是文本文件和那些代表媒体文件的链接。因为替身文件是符号链接,所以工程还会像预期的运行,因为本地机器会处理他们,转换成“真实的”副本。当用符号链接替换出文件时,Git-portal 维护了项目的结构,因此,如果你认为 Git-portal 不适合你的项目,或者你需要构建项目的一个没有符号链接的版本(比如用于分发),则可以轻松地逆转该过程。
|
||||
|
||||
Git-portal 也允许通过 `rsync` 来远程同步静态资源,所以用户可以设置一个远程存储位置,来做为一个中心的授权源。
|
||||
|
||||
Git-portal 对于多媒体的工程是一个理想的解决方案。类似的多媒体工程包括视频游戏、桌面游戏、需要进行大型 3D 模型渲染和纹理的虚拟现实工程、[带图][4]以及 .odt 输出的书籍、协作型的[博客站点][5]、音乐项目,等等。艺术家在应用程序中以图层(在图形世界中)和曲目(在音乐世界中)的形式执行版本控制并不少见——因此,Git 不会向多媒体项目文件本身添加任何内容。Git 的功能可用于艺术项目的其他部分(例如散文和叙述、项目管理、字幕文件、致谢、营销副本、文档等),而结构化远程备份的功能则由艺术家使用。
|
||||
|
||||
#### 安装 Git-portal
|
||||
|
||||
Git-portal 的 RPM 安装包位于 <https://klaatu.fedorapeople.org/git-portal>,可用于下载和安装。
|
||||
|
||||
此外,用户可以从 Git-portal 的 Gitlab 主页手动安装。这仅仅是一个 Bash 脚本以及一些 Git 钩子(也是 Bash 脚本),但是需要一个快速的构建过程来让它知道安装的位置。
|
||||
|
||||
```
|
||||
$ git clone https://gitlab.com/slackermedia/git-portal.git git-portal.clone
|
||||
$ cd git-portal.clone
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
#### 使用 Git-portal
|
||||
|
||||
Git-portal 与 Git 一起使用。这意味着,如同 Git 的所有大型文件扩展一样,都需要记住一些额外的步骤。但是,你仅仅需要在处理你的媒体资源的时候使用 Git-portal,所以很容易记住,除非你把大文件都当做文本文件来进行处理(对于 Git 用户很少见)。使用 Git-portal 必须做的一个安装步骤是:
|
||||
|
||||
```
|
||||
$ mkdir bigproject.git
|
||||
$ cd !$
|
||||
$ git init
|
||||
$ git-portal init
|
||||
```
|
||||
|
||||
Git-portal 的 `init` 函数在 Git 存储库中创建了一个 `_portal` 文件夹并且添加到 `.gitignore` 文件中。
|
||||
|
||||
在平日里使用 Git-portal 和 Git 协同十分平滑。一个较好的例子是基于 MIDI 的音乐项目:音乐工作站产生的项目文件是基于文本的,但是 MIDI 文件是二进制数据:
|
||||
|
||||
```
|
||||
$ ls -1
|
||||
_portal
|
||||
song.1.qtr
|
||||
song.qtr
|
||||
song-Track_1-1.mid
|
||||
song-Track_1-3.mid
|
||||
song-Track_2-1.mid
|
||||
$ git add song*qtr
|
||||
$ git-portal song-Track*mid
|
||||
$ git add song-Track*mid
|
||||
```
|
||||
|
||||
如果你查看一下 `_portal` 文件夹,你会发现那里有最初的 MIDI 文件。这些文件在原本的位置被替换成了指向 `_portal` 的链接文件,使得音乐工作站像预期一样运行。
|
||||
|
||||
```
|
||||
$ ls -lG
|
||||
[...] _portal/
|
||||
[...] song.1.qtr
|
||||
[...] song.qtr
|
||||
[...] song-Track_1-1.mid -> _portal/song-Track_1-1.mid*
|
||||
[...] song-Track_1-3.mid -> _portal/song-Track_1-3.mid*
|
||||
[...] song-Track_2-1.mid -> _portal/song-Track_2-1.mid*
|
||||
```
|
||||
|
||||
与 Git 相同,你也可以添加一个目录下的文件。
|
||||
|
||||
```
|
||||
$ cp -r ~/synth-presets/yoshimi .
|
||||
$ git-portal add yoshimi
|
||||
Directories cannot go through the portal. Sending files instead.
|
||||
$ ls -lG _portal/yoshimi
|
||||
[...] yoshimi.stat -> ../_portal/yoshimi/yoshimi.stat*
|
||||
```
|
||||
|
||||
删除功能也像预期一样工作,但是当从 `_portal` 中删除一些东西时,你应该使用 `git-portal rm` 而不是 `git rm`。使用 Git-portal 可以确保文件从 `_portal` 中删除:
|
||||
|
||||
```
|
||||
$ ls
|
||||
_portal/ song.qtr song-Track_1-3.mid@ yoshimi/
|
||||
song.1.qtr song-Track_1-1.mid@ song-Track_2-1.mid@
|
||||
$ git-portal rm song-Track_1-3.mid
|
||||
rm 'song-Track_1-3.mid'
|
||||
$ ls _portal/
|
||||
song-Track_1-1.mid* song-Track_2-1.mid* yoshimi/
|
||||
```
|
||||
|
||||
如果你忘记使用 Git-portal,那么你需要手动删除 `_portal` 下的文件:
|
||||
|
||||
```
|
||||
$ git-portal rm song-Track_1-1.mid
|
||||
rm 'song-Track_1-1.mid'
|
||||
$ ls _portal/
|
||||
song-Track_1-1.mid* song-Track_2-1.mid* yoshimi/
|
||||
$ trash _portal/song-Track_1-1.mid
|
||||
```
|
||||
|
||||
Git-portal 其它的唯一功能,是列出当前所有的链接并且找到里面可能已经损坏的符号链接。有时这种情况会因为项目文件夹中的文件被移动而发生:
|
||||
|
||||
```
|
||||
$ mkdir foo
|
||||
$ mv yoshimi foo
|
||||
$ git-portal status
|
||||
bigproject.git/song-Track_2-1.mid: symbolic link to _portal/song-Track_2-1.mid
|
||||
bigproject.git/foo/yoshimi/yoshimi.stat: broken symbolic link to ../_portal/yoshimi/yoshimi.stat
|
||||
```
|
||||
|
||||
如果你使用 Git-portal 用于私人项目并且维护自己的备份,以上就是技术方面所有你需要知道关于 Git-portal 的事情了。如果你想要添加一个协作者或者你希望 Git-portal 来像 Git 的方式来管理备份,你可以创建一个远程位置。
|
||||
|
||||
#### 增加 Git-portal 远程位置
|
||||
|
||||
为 Git-portal 增加一个远程位置是通过 Git 已有的远程功能来实现的。Git-portal 实现了 Git 钩子(隐藏在存储库 `.git` 文件夹中的脚本),来寻找你的远程位置上是否存在以 `_portal` 开头的文件夹。如果它找到一个,它会尝试使用 `rsync` 来与远程位置同步文件。Git-portal 在用户进行 Git 推送以及 Git 合并的时候(或者在进行 Git 拉取的时候,实际上是进行一次获取和自动合并),都会执行此操作。
|
||||
|
||||
如果你仅克隆了 Git 存储库,那么你可能永远不会自己添加一个远程位置。这是一个标准的 Git 过程:
|
||||
|
||||
```
|
||||
$ git remote add origin git@gitdawg.com:seth/bigproject.git
|
||||
$ git remote -v
|
||||
origin git@gitdawg.com:seth/bigproject.git (fetch)
|
||||
origin git@gitdawg.com:seth/bigproject.git (push)
|
||||
```
|
||||
|
||||
对你的主要 Git 存储库来说,`origin` 这个名字是一个流行的惯例,将其用于 Git 数据是有意义的。然而,你的 Git-portal 数据是分开存储的,所以你必须创建第二个远程位置来让 Git-portal 了解向哪里推送和从哪里拉取。取决于你的 Git 主机,你可能需要一个单独的服务器,因为空间有限的 Git 主机不太可能接受 GB 级的媒体资产。或者,可能你的服务器仅允许你访问你的 Git 存储库而不允许访问外部的存储文件夹:
|
||||
|
||||
```
|
||||
$ git remote add _portal seth@example.com:/home/seth/git/bigproject_portal
|
||||
$ git remote -v
|
||||
origin git@gitdawg.com:seth/bigproject.git (fetch)
|
||||
origin git@gitdawg.com:seth/bigproject.git (push)
|
||||
_portal seth@example.com:/home/seth/git/bigproject_portal (fetch)
|
||||
_portal seth@example.com:/home/seth/git/bigproject_portal (push)
|
||||
```
|
||||
|
||||
你可能不想为所有用户提供服务器上的个人帐户,也不必这样做。为了提供对托管资源库大文件资产的服务器的访问权限,你可以运行一个 Git 前端,比如 [Gitolite][8] 或者你可以使用 `rrsync` (受限的 rsync)。
|
||||
|
||||
现在你可以推送你的 Git 数据到你的远程 Git 存储库,并将你的 Git-portal 数据到你的远程的门户:
|
||||
|
||||
```
|
||||
$ git push origin HEAD
|
||||
master destination detected
|
||||
Syncing _portal content...
|
||||
sending incremental file list
|
||||
sent 9,305 bytes received 18 bytes 1,695.09 bytes/sec
|
||||
total size is 60,358,015 speedup is 6,474.10
|
||||
Syncing _portal content to example.com:/home/seth/git/bigproject_portal
|
||||
```
|
||||
|
||||
如果你已经安装了 Git-portal,并且配置了 `_portal` 的远程位置,你的 `_portal` 文件夹将会被同步,并且从服务器获取新的内容,以及在每一次推送的时候发送新的内容。尽管你不需要进行 Git 提交或者推送来和服务器同步(用户可以使用直接使用 `rsync`),但是我发现对于艺术性内容的改变,提交是有用的。这将会把艺术家及其数字资产集成到工作流的其余部分中,并提供有关项目进度和速度的有用元数据。
|
||||
|
||||
### 其他选择
|
||||
|
||||
如果 Git-portal 对你而言太过简单,还有一些用于 Git 管理大型文件的其他选择。[Git 大文件存储][9](LFS)是一个名为 git-media 的停工项目的分支,这个分支由 GitHub 维护和支持。它需要特殊的命令(例如 `git lfs track` 来保护大型文件不被 Git 追踪)并且需要用户维护一个 `.gitattributes` 文件来更新哪些存储库中的文件被 LFS 追踪。对于大文件而言,它**仅**支持 HTTP 和 HTTPS 远程主机。所以你必须配置 LFS 服务器,才能使得用户可以通过 HTTP 而不是 SSH 或 `rsync` 来进行鉴权。
|
||||
|
||||
另一个相对 LFS 更灵活的选择是 [git-annex][10]。你可以在我的文章 [管理 Git 中大二进制 blob][11] 中了解更多(忽略其中 git-media 这个已经废弃项目的章节,因为其灵活性没有被它的继任者 Git LFS 延续下来)。Git-annex 是一个灵活且优雅的解决方案。它拥有一个细腻的系统来用于添加、删除、移动存储库中的大型文件。因为它灵活且强大,有很多新的命令和规则需要进行学习,所以建议看一下它的[文档][12]。
|
||||
|
||||
然而,如果你的需求很简单,你可能更加喜欢整合已有技术来进行简单且明显任务的解决方案,则 Git-portal 可能是对于工作而言比较合适的工具。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/4/manage-multimedia-files-git
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[svtter](https://github.com/svtter)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/video_editing_folder_music_wave_play.png?itok=-J9rs-My (video editing dashboard)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/git-velocity.jpg (Graphic showing relationship between art assets and Git)
|
||||
[3]: http://gitlab.com/slackermedia/git-portal.git
|
||||
[4]: https://www.apress.com/gp/book/9781484241691
|
||||
[5]: http://mixedsignals.ml
|
||||
[6]: mailto:git@gitdawg.com
|
||||
[7]: mailto:seth@example.com
|
||||
[8]: https://opensource.com/article/19/4/file-sharing-git
|
||||
[9]: https://git-lfs.github.com/
|
||||
[10]: https://git-annex.branchable.com/
|
||||
[11]: https://opensource.com/life/16/8/how-manage-binary-blobs-git-part-7
|
||||
[12]: https://git-annex.branchable.com/walkthrough/
|
@ -0,0 +1,208 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11881-1.html)
|
||||
[#]: subject: (How to Go About Linux Boot Time Optimisation)
|
||||
[#]: via: (https://opensourceforu.com/2019/10/how-to-go-about-linux-boot-time-optimisation/)
|
||||
[#]: author: (B Thangaraju https://opensourceforu.com/author/b-thangaraju/)
|
||||
|
||||
如何进行 Linux 启动时间优化
|
||||
======
|
||||
|
||||
![][2]
|
||||
|
||||
> 快速启动嵌入式设备或电信设备,对于时间要求紧迫的应用程序是至关重要的,并且在改善用户体验方面也起着非常重要的作用。这个文章给予一些关于如何增强任意设备的启动时间的重要技巧。
|
||||
|
||||
快速启动或快速重启在各种情况下起着至关重要的作用。为了保持所有服务的高可用性和更好的性能,嵌入式设备的快速启动至关重要。设想有一台运行着没有启用快速启动的 Linux 操作系统的电信设备,所有依赖于这个特殊嵌入式设备的系统、服务和用户可能会受到影响。这些设备维持其服务的高可用性是非常重要的,为此,快速启动和重启起着至关重要的作用。
|
||||
|
||||
一台电信设备的一次小故障或关机,即使只是几秒钟,都可能会对无数互联网上的用户造成破坏。因此,对于很多对时间要求严格的设备和电信设备来说,在它们的设备中加入快速启动的功能以帮助它们快速恢复工作是非常重要的。让我们从图 1 中理解 Linux 启动过程。
|
||||
|
||||
![图 1:启动过程][3]
|
||||
|
||||
### 监视工具和启动过程
|
||||
|
||||
在对机器做出更改之前,用户应注意许多因素。其中包括计算机的当前启动速度,以及占用资源并增加启动时间的服务、进程或应用程序。
|
||||
|
||||
#### 启动图
|
||||
|
||||
为监视启动速度和在启动期间启动的各种服务,用户可以使用下面的命令来安装:
|
||||
|
||||
```
|
||||
sudo apt-get install pybootchartgui
|
||||
```
|
||||
|
||||
你每次启动时,启动图会在日志中保存一个 png 文件,使用户能够查看该 png 文件来理解系统的启动过程和服务。为此,使用下面的命令:
|
||||
|
||||
```
|
||||
cd /var/log/bootchart
|
||||
```
|
||||
|
||||
用户可能需要一个应用程序来查看 png 文件。Feh 是一个面向控制台用户的 X11 图像查看器。不像大多数其它的图像查看器,它没有一个精致的图形用户界面,但它只用来显示图片。Feh 可以用于查看 png 文件。你可以使用下面的命令来安装它:
|
||||
|
||||
```
|
||||
sudo apt-get install feh
|
||||
```
|
||||
|
||||
你可以使用 `feh xxxx.png` 来查看 png 文件。
|
||||
|
||||
|
||||
![图 2:启动图][4]
|
||||
|
||||
图 2 显示了一个正在查看的引导图 png 文件。
|
||||
|
||||
#### systemd-analyze
|
||||
|
||||
但是,对于 Ubuntu 15.10 以后的版本不再需要引导图。为获取关于启动速度的简短信息,使用下面的命令:
|
||||
|
||||
```
|
||||
systemd-analyze
|
||||
```
|
||||
|
||||
![图 3:systemd-analyze 的输出][5]
|
||||
|
||||
图表 3 显示命令 `systemd-analyze` 的输出。
|
||||
|
||||
命令 `systemd-analyze blame` 用于根据初始化所用的时间打印所有正在运行的单元的列表。这个信息是非常有用的,可用于优化启动时间。`systemd-analyze blame` 不会显示服务类型为简单(`Type=simple`)的服务,因为 systemd 认为这些服务应是立即启动的;因此,无法测量初始化的延迟。
|
||||
|
||||
![图 4:systemd-analyze blame 的输出][6]
|
||||
|
||||
图 4 显示 `systemd-analyze blame` 的输出。
|
||||
|
||||
下面的命令打印时间关键的服务单元的树形链条:
|
||||
|
||||
```
|
||||
command systemd-analyze critical-chain
|
||||
```
|
||||
|
||||
图 5 显示命令 `systemd-analyze critical-chain` 的输出。
|
||||
|
||||
![图 5:systemd-analyze critical-chain 的输出][7]
|
||||
|
||||
### 减少启动时间的步骤
|
||||
|
||||
下面显示的是一些可以减少启动时间的各种步骤。
|
||||
|
||||
#### BUM(启动管理器)
|
||||
|
||||
BUM 是一个运行级配置编辑器,允许在系统启动或重启时配置初始化服务。它显示了可以在启动时启动的每个服务的列表。用户可以打开和关闭各个服务。BUM 有一个非常清晰的图形用户界面,并且非常容易使用。
|
||||
|
||||
在 Ubuntu 14.04 中,BUM 可以使用下面的命令安装:
|
||||
|
||||
```
|
||||
sudo apt-get install bum
|
||||
```
|
||||
|
||||
为在 15.10 以后的版本中安装它,从链接 http://apt.ubuntu.com/p/bum 下载软件包。
|
||||
|
||||
以基本的服务开始,禁用扫描仪和打印机相关的服务。如果你没有使用蓝牙和其它不想要的设备和服务,你也可以禁用它们中一些。我强烈建议你在禁用相关的服务前学习服务的基础知识,因为这可能会影响计算机或操作系统。图 6 显示 BUM 的图形用户界面。
|
||||
|
||||
![图 6:BUM][8]
|
||||
|
||||
#### 编辑 rc 文件
|
||||
|
||||
要编辑 rc 文件,你需要转到 rc 目录。这可以使用下面的命令来做到:
|
||||
|
||||
```
|
||||
cd /etc/init.d
|
||||
```
|
||||
|
||||
然而,访问 `init.d` 需要 root 用户权限,该目录基本上包含的是开始/停止脚本,这些脚本用于在系统运行时或启动期间控制(开始、停止、重新加载、启动启动)守护进程。
|
||||
|
||||
在 `init.d` 目录中的 `rc` 文件被称为<ruby>运行控制<rt>run control</rt></ruby>脚本。在启动期间,`init` 执行 `rc` 脚本并发挥它的作用。为改善启动速度,我们可以更改 `rc` 文件。使用任意的文件编辑器打开 `rc` 文件(当你在 `init.d` 目录中时)。
|
||||
|
||||
例如,通过输入 `vim rc` ,你可以更改 `CONCURRENCY=none` 为 `CONCURRENCY=shell`。后者允许某些启动脚本同时执行,而不是依序执行。
|
||||
|
||||
在最新版本的内核中,该值应该被更改为 `CONCURRENCY=makefile`。
|
||||
|
||||
图 7 和图 8 显示编辑 `rc` 文件前后的启动时间比较。可以注意到启动速度有所提高。在编辑 `rc` 文件前的启动时间是 50.98 秒,然而在对 `rc` 文件进行更改后的启动时间是 23.85 秒。
|
||||
|
||||
但是,上面提及的更改方法在 Ubuntu 15.10 以后的操作系统上不工作,因为使用最新内核的操作系统使用 systemd 文件,而不再是 `init.d` 文件。
|
||||
|
||||
![图 7:对 rc 文件进行更改之前的启动速度][9]
|
||||
|
||||
![图 8:对 rc 文件进行更改之后的启动速度][10]
|
||||
|
||||
#### E4rat
|
||||
|
||||
E4rat 代表 e4 <ruby>减少访问时间<rt>reduced access time</rt></ruby>(仅在 ext4 文件系统的情况下)。它是由 Andreas Rid 和 Gundolf Kiefer 开发的一个项目。E4rat 是一个通过碎片整理来帮助快速启动的应用程序。它还会加速应用程序的启动。E4rat 使用物理文件的重新分配来消除寻道时间和旋转延迟,因而达到较高的磁盘传输速度。
|
||||
|
||||
E4rat 可以 .deb 软件包形式获得,你可以从它的官方网站 http://e4rat.sourceforge.net/ 下载。
|
||||
|
||||
Ubuntu 默认安装的 ureadahead 软件包与 e4rat 冲突。因此必须使用下面的命令安装这几个软件包:
|
||||
|
||||
```
|
||||
sudo dpkg purge ureadahead ubuntu-minimal
|
||||
```
|
||||
|
||||
现在使用下面的命令来安装 e4rat 的依赖关系:
|
||||
|
||||
```
|
||||
sudo apt-get install libblkid1 e2fslibs
|
||||
```
|
||||
|
||||
打开下载的 .deb 文件,并安装它。现在需要恰当地收集启动数据来使 e4rat 工作。
|
||||
|
||||
遵循下面所给的步骤来使 e4rat 正确地运行并提高启动速度。
|
||||
|
||||
* 在启动期间访问 Grub 菜单。这可以在系统启动时通过按住 `shift` 按键来完成。
|
||||
* 选择通常用于启动的选项(内核版本),并按 `e`。
|
||||
* 查找以 `linux /boot/vmlinuz` 开头的行,并在该行的末尾添加下面的代码(在句子的最后一个字母后按空格键):`init=/sbin/e4rat-collect or try - quiet splash vt.handsoff =7 init=/sbin/e4rat-collect
|
||||
`。
|
||||
* 现在,按 `Ctrl+x` 来继续启动。这可以让 e4rat 在启动后收集数据。在这台机器上工作,并在接下来的两分钟时间内打开并关闭应用程序。
|
||||
* 通过转到 e4rat 文件夹,并使用下面的命令来访问日志文件:`cd /var/log/e4rat`。
|
||||
* 如果你没有找到任何日志文件,重复上面的过程。一旦日志文件就绪,再次访问 Grub 菜单,并对你的选项按 `e`。
|
||||
* 在你之前已经编辑过的同一行的末尾输入 `single`。这可以让你访问命令行。如果出现其它菜单,选择恢复正常启动(Resume normal boot)。如果你不知为何不能进入命令提示符,按 `Ctrl+Alt+F1` 组合键。
|
||||
* 在你看到登录提示后,输入你的登录信息。
|
||||
* 现在输入下面的命令:`sudo e4rat-realloc /var/lib/e4rat/startup.log`。此过程需要一段时间,具体取决于机器的磁盘速度。
|
||||
* 现在使用下面的命令来重启你的机器:`sudo shutdown -r now`。
|
||||
* 现在,我们需要配置 Grub 来在每次启动时运行 e4rat。
|
||||
* 使用任意的编辑器访问 grub 文件。例如,`gksu gedit /etc/default/grub`。
|
||||
* 查找以 `GRUB CMDLINE LINUX DEFAULT=` 开头的一行,并在引号之间和任何选项之前添加下面的行:`init=/sbin/e4rat-preload 18`。
|
||||
* 它应该看起来像这样:`GRUB CMDLINE LINUX DEFAULT = init=/sbin/e4rat- preload quiet splash`。
|
||||
* 保存并关闭 Grub 菜单,并使用 `sudo update-grub` 更新 Grub 。
|
||||
* 重启系统,你将发现启动速度有明显变化。
|
||||
|
||||
图 9 和图 10 显示在安装 e4rat 前后的启动时间之间的差异。可注意到启动速度的提高。在使用 e4rat 前启动所用时间是 22.32 秒,然而在使用 e4rat 后启动所用时间是 9.065 秒。
|
||||
|
||||
![图 9:使用 e4rat 之前的启动速度][11]
|
||||
|
||||
![图 10:使用 e4rat 之后的启动速度][12]
|
||||
|
||||
### 一些易做的调整
|
||||
|
||||
使用很小的调整也可以达到良好的启动速度,下面列出其中两个。
|
||||
|
||||
#### SSD
|
||||
|
||||
使用固态设备而不是普通的硬盘或者其它的存储设备将肯定会改善启动速度。SSD 也有助于加快文件传输和运行应用程序方面的速度。
|
||||
|
||||
#### 禁用图形用户界面
|
||||
|
||||
图形用户界面、桌面图形和窗口动画占用大量的资源。禁用图形用户界面是获得良好的启动速度的另一个好方法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensourceforu.com/2019/10/how-to-go-about-linux-boot-time-optimisation/
|
||||
|
||||
作者:[B Thangaraju][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensourceforu.com/author/b-thangaraju/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/10/Screenshot-from-2019-10-07-13-16-32.png?&ssl=1 (Screenshot from 2019-10-07 13-16-32)
|
||||
[2]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/10/Screenshot-from-2019-10-07-13-16-32.png?fit=700%2C499&ssl=1
|
||||
[3]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-1.png?ssl=1
|
||||
[4]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-2.png?ssl=1
|
||||
[5]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-3.png?ssl=1
|
||||
[6]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-4.png?ssl=1
|
||||
[7]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-5.png?ssl=1
|
||||
[8]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-6.png?ssl=1
|
||||
[9]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-7.png?ssl=1
|
||||
[10]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-8.png?ssl=1
|
||||
[11]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-9.png?ssl=1
|
||||
[12]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/10/fig-10.png?ssl=1
|
@ -1,49 +1,45 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11870-1.html)
|
||||
[#]: subject: (8 Commands to Check Memory Usage on Linux)
|
||||
[#]: via: (https://www.2daygeek.com/linux-commands-check-memory-usage/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
8 Commands to Check Memory Usage on Linux
|
||||
检查 Linux 中内存使用情况的 8 条命令
|
||||
======
|
||||
|
||||
Linux is not like Windows and you will not get a GUI always, especially in a server environment.
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/09/121112mg0jigxtcc5xr8or.jpg)
|
||||
|
||||
As a Linux administrator, it is important to know how to check your available and used resources, such as memory, CPU, disk space, etc.
|
||||
Linux 并不像 Windows,你经常不会有图形界面可供使用,特别是在服务器环境中。
|
||||
|
||||
If there are any applications that use too much resources on the system to run your system at the optimum level you need to find and fix.
|
||||
作为一名 Linux 管理员,知道如何获取当前可用的和已经使用的资源情况,比如内存、CPU、磁盘等,是相当重要的。如果某一应用在你的系统上占用了太多的资源,导致你的系统无法达到最优状态,那么你需要找到并修正它。
|
||||
|
||||
If you want to **[find out the top 10 memory (RAM) consumption processes in Linux][1]**, go to the following article.
|
||||
如果你想找到消耗内存前十名的进程,你需要去阅读这篇文章:[如何在 Linux 中找出内存消耗最大的进程][1]。
|
||||
|
||||
In Linux, there are commands for everything, so use the corresponding commands.
|
||||
在 Linux 中,命令能做任何事,所以使用相关命令吧。在这篇教程中,我们将会给你展示 8 个有用的命令来即查看在 Linux 系统中内存的使用情况,包括 RAM 和交换分区。
|
||||
|
||||
In this tutorial, we will show you eight powerful commands to check memory usage on a Linux system, including RAM and swap.
|
||||
创建交换分区在 Linux 系统中是非常重要的,如果你想了解如何创建,可以去阅读这篇文章:[在 Linux 系统上创建交换分区][2]。
|
||||
|
||||
**[Creating swap space on a Linux system][2]** is very important.
|
||||
下面的命令可以帮助你以不同的方式查看 Linux 内存使用情况。
|
||||
|
||||
The following commands can help you check memory usage in Linux in different ways.
|
||||
* `free` 命令
|
||||
* `/proc/meminfo` 文件
|
||||
* `vmstat` 命令
|
||||
* `ps_mem` 命令
|
||||
* `smem` 命令
|
||||
* `top` 命令
|
||||
* `htop` 命令
|
||||
* `glances` 命令
|
||||
|
||||
* free Command
|
||||
* /proc/meminfo File
|
||||
* vmstat Command
|
||||
* ps_mem Command
|
||||
* smem Command
|
||||
* top Command
|
||||
* htop Command
|
||||
* glances Command
|
||||
### 1)如何使用 free 命令查看 Linux 内存使用情况
|
||||
|
||||
[free 命令][3] 是被 Linux 管理员广泛使用的主要命令。但是它提供的信息比 `/proc/meminfo` 文件少。
|
||||
|
||||
`free` 命令会分别展示物理内存和交换分区内存中已使用的和未使用的数量,以及内核使用的缓冲区和缓存。
|
||||
|
||||
### 1) How to Check Memory Usage on Linux Using the free Command
|
||||
|
||||
**[Free command][3]** is the most powerful command widely used by the Linux administrator. But it provides very little information compared to the “/proc/meminfo” file.
|
||||
|
||||
Free command displays the total amount of free and used physical and swap memory on the system, as well as buffers and caches used by the kernel.
|
||||
|
||||
These information is gathered from the “/proc/meminfo” file.
|
||||
这些信息都是从 `/proc/meminfo` 文件中获取的。
|
||||
|
||||
```
|
||||
# free -m
|
||||
@ -52,24 +48,18 @@ Mem: 15867 9199 1702 3315 4965 3039
|
||||
Swap: 17454 666 16788
|
||||
```
|
||||
|
||||
* **total:** Total installed memory
|
||||
* **used:** Memory is currently in use by running processes (used= total – free – buff/cache)
|
||||
* **free:** Unused memory (free= total – used – buff/cache)
|
||||
* **shared:** Memory shared between two or more processes (multiple processes)
|
||||
* **buffers:** Memory reserved by the kernel to hold a process queue request.
|
||||
* **cache:** Size of the page cache that holds recently used files in RAM
|
||||
* **buff/cache:** Buffers + Cache
|
||||
* **available:** Estimation of how much memory is available for starting new applications, without swapping.
|
||||
* `total`:总的内存量
|
||||
* `used`:被当前运行中的进程使用的内存量(`used` = `total` – `free` – `buff/cache`)
|
||||
* `free`: 未被使用的内存量(`free` = `total` – `used` – `buff/cache`)
|
||||
* `shared`: 在两个或多个进程之间共享的内存量
|
||||
* `buffers`: 内存中保留用于内核记录进程队列请求的内存量
|
||||
* `cache`: 在 RAM 中存储最近使用过的文件的页缓冲大小
|
||||
* `buff/cache`: 缓冲区和缓存总的使用内存量
|
||||
* `available`: 可用于启动新应用的可用内存量(不含交换分区)
|
||||
|
||||
### 2) 如何使用 /proc/meminfo 文件查看 Linux 内存使用情况
|
||||
|
||||
|
||||
### 2) How to Check Memory Usage on Linux Using the /proc/meminfo File
|
||||
|
||||
The “/proc/meminfo” file is a virtual file that contains various real-time information about memory usage.
|
||||
|
||||
It shows memory stats in kilobytes, most of which are somewhat difficult to understand.
|
||||
|
||||
However it contains useful information about memory usage.
|
||||
`/proc/meminfo` 文件是一个包含了多种内存使用的实时信息的虚拟文件。它展示内存状态单位使用的是 kB,其中大部分属性都难以理解。然而它也包含了内存使用情况的有用信息。
|
||||
|
||||
```
|
||||
# cat /proc/meminfo
|
||||
@ -124,13 +114,11 @@ DirectMap2M: 14493696 kB
|
||||
DirectMap1G: 2097152 kB
|
||||
```
|
||||
|
||||
### 3) How to Check Memory Usage on Linux Using the vmstat Command
|
||||
### 3) 如何使用 vmstat 命令查看 Linux 内存使用情况
|
||||
|
||||
The **[vmstat command][4]** is another useful tool for reporting virtual memory statistics.
|
||||
[vmstat 命令][4] 是另一个报告虚拟内存统计信息的有用工具。
|
||||
|
||||
vmstat reports information about processes, memory, paging, block IO, traps, disks, and cpu functionality.
|
||||
|
||||
vmstat does not require special permissions, and it can help identify system bottlenecks.
|
||||
`vmstat` 报告的信息包括:进程、内存、页面映射、块 I/O、陷阱、磁盘和 CPU 特性信息。`vmstat` 不需要特殊的权限,并且它可以帮助诊断系统瓶颈。
|
||||
|
||||
```
|
||||
# vmstat
|
||||
@ -140,58 +128,35 @@ procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
|
||||
1 0 682060 1769324 234188 4853500 0 3 25 91 31 16 34 13 52 0 0
|
||||
```
|
||||
|
||||
If you want to understand this in detail, read the field description below.
|
||||
如果你想详细了解每一项的含义,阅读下面的描述。
|
||||
|
||||
**Procs**
|
||||
* `procs`:进程
|
||||
* `r`: 可以运行的进程数目(正在运行或等待运行)
|
||||
* `b`: 处于不可中断睡眠中的进程数目
|
||||
* `memory`:内存
|
||||
* `swpd`: 使用的虚拟内存数量
|
||||
* `free`: 空闲的内存数量
|
||||
* `buff`: 用作缓冲区内存的数量
|
||||
* `cache`: 用作缓存内存的数量
|
||||
* `inact`: 不活动的内存数量(使用 `-a` 选项)
|
||||
* `active`: 活动的内存数量(使用 `-a` 选项)
|
||||
* `Swap`:交换分区
|
||||
* `si`: 每秒从磁盘交换的内存数量
|
||||
* `so`: 每秒交换到磁盘的内存数量
|
||||
* `IO`:输入输出
|
||||
* `bi`: 从一个块设备中收到的块(块/秒)
|
||||
* `bo`: 发送到一个块设备的块(块/秒)
|
||||
* `System`:系统
|
||||
* `in`: 每秒的中断次数,包括时钟。
|
||||
* `cs`: 每秒的上下文切换次数。
|
||||
* `CPU`:下面这些是在总的 CPU 时间占的百分比
|
||||
* `us`: 花费在非内核代码上的时间占比(包括用户时间,调度时间)
|
||||
* `sy`: 花费在内核代码上的时间占比 (系统时间)
|
||||
* `id`: 花费在闲置的时间占比。在 Linux 2.5.41 之前,包括 I/O 等待时间
|
||||
* `wa`: 花费在 I/O 等待上的时间占比。在 Linux 2.5.41 之前,包括在空闲时间中
|
||||
* `st`: 被虚拟机偷走的时间占比。在 Linux 2.6.11 之前,这部分称为 unknown
|
||||
|
||||
* **r:** The number of runnable processes (running or waiting for run time).
|
||||
* **b:** The number of processes in uninterruptible sleep.
|
||||
|
||||
|
||||
|
||||
**Memory**
|
||||
|
||||
* **swpd:** the amount of virtual memory used.
|
||||
* **free:** the amount of idle memory.
|
||||
* **buff:** the amount of memory used as buffers.
|
||||
* **cache:** the amount of memory used as cache.
|
||||
* **inact:** the amount of inactive memory. (-a option)
|
||||
* **active:** the amount of active memory. (-a option)
|
||||
|
||||
|
||||
|
||||
**Swap**
|
||||
|
||||
* **si:** Amount of memory swapped in from disk (/s).
|
||||
* **so:** Amount of memory swapped to disk (/s).
|
||||
|
||||
|
||||
|
||||
**IO**
|
||||
|
||||
* **bi:** Blocks received from a block device (blocks/s).
|
||||
* **bo:** Blocks sent to a block device (blocks/s).
|
||||
|
||||
|
||||
|
||||
**System**
|
||||
|
||||
* **in:** The number of interrupts per second, including the clock.
|
||||
* **cs:** The number of context switches per second.
|
||||
|
||||
|
||||
|
||||
**CPU : These are percentages of total CPU time.**
|
||||
|
||||
* **us:** Time spent running non-kernel code. (user time, including nice time)
|
||||
* **sy:** Time spent running kernel code. (system time)
|
||||
* **id:** Time spent idle. Prior to Linux 2.5.41, this includes IO-wait time.
|
||||
* **wa:** Time spent waiting for IO. Prior to Linux 2.5.41, included in idle.
|
||||
* **st:** Time stolen from a virtual machine. Prior to Linux 2.6.11, unknown.
|
||||
|
||||
|
||||
|
||||
Run the following command for detailed information.
|
||||
运行下面的命令查看详细的信息。
|
||||
|
||||
```
|
||||
# vmstat -s
|
||||
@ -223,16 +188,13 @@ Run the following command for detailed information.
|
||||
1577163147 boot time
|
||||
3318 forks
|
||||
```
|
||||
### 4) 如何使用 ps_mem 命令查看 Linux 内存使用情况
|
||||
|
||||
### 4) How to Check Memory Usage on Linux Using the ps_mem Command
|
||||
[ps_mem][5] 是一个用来查看当前内存使用情况的简单的 Python 脚本。该工具可以确定每个程序使用了多少内存(不是每个进程)。
|
||||
|
||||
**[ps_mem][5]** is a simple Python script that allows you to get core memory usage accurately for a program in Linux.
|
||||
该工具采用如下的方法计算每个程序使用内存:总的使用 = 程序进程私有的内存 + 程序进程共享的内存。
|
||||
|
||||
This can determine how much RAM is used per program (not per process).
|
||||
|
||||
It calculates the total amount of memory used per program, total = sum (private RAM for program processes) + sum (shared RAM for program processes).
|
||||
|
||||
The shared RAM is problematic to calculate, and the tool automatically selects the most accurate method available for the running kernel.
|
||||
计算共享内存是存在不足之处的,该工具可以为运行中的内核自动选择最准确的方法。
|
||||
|
||||
```
|
||||
# ps_mem
|
||||
@ -285,15 +247,13 @@ The shared RAM is problematic to calculate, and the tool automatically selects t
|
||||
==================================
|
||||
```
|
||||
|
||||
### 5) How to Check Memory Usage on Linux Using the smem Command
|
||||
### 5)如何使用 smem 命令查看 Linux 内存使用情况
|
||||
|
||||
**[smem][6]** is a tool that can provide numerous reports of memory usage on Linux systems. Unlike existing tools, smem can report Proportional Set Size (PSS), Unique Set Size (USS) and Resident Set Size (RSS).
|
||||
[smem][6] 是一个可以为 Linux 系统提供多种内存使用情况报告的工具。不同于现有的工具,`smem` 可以报告<ruby>比例集大小<rt>Proportional Set Size</rt></ruby>(PSS)、<ruby>唯一集大小<rt>Unique Set Size</rt></ruby>(USS)和<ruby>驻留集大小<rt>Resident Set Size</rt></ruby>(RSS)。
|
||||
|
||||
Proportional Set Size (PSS): refers to the amount of memory used by libraries and applications in the virtual memory system.
|
||||
|
||||
Unique Set Size (USS) : Unshared memory is reported as USS (Unique Set Size).
|
||||
|
||||
Resident Set Size (RSS) : The standard measure of physical memory (it typically shared among multiple applications) usage known as resident set size (RSS) will significantly overestimate memory usage.
|
||||
- 比例集大小(PSS):库和应用在虚拟内存系统中的使用量。
|
||||
- 唯一集大小(USS):其报告的是非共享内存。
|
||||
- 驻留集大小(RSS):物理内存(通常多进程共享)使用情况,其通常高于内存使用量。
|
||||
|
||||
```
|
||||
# smem -tk
|
||||
@ -336,13 +296,11 @@ Resident Set Size (RSS) : The standard measure of physical memory (it typically
|
||||
90 1 0 4.8G 5.2G 8.0G
|
||||
```
|
||||
|
||||
### 6) How to Check Memory Usage on Linux Using the top Command
|
||||
### 6) 如何使用 top 命令查看 Linux 内存使用情况
|
||||
|
||||
**[top command][7]** is one of the most frequently used commands by Linux administrators to understand and view the resource usage for a process on a Linux system.
|
||||
[top 命令][7] 是一个 Linux 系统的管理员最常使用的用于查看进程的资源使用情况的命令。
|
||||
|
||||
It displays the total memory of the system, current memory usage, free memory and total memory used by the buffers.
|
||||
|
||||
In addition, it displays total swap memory, current swap usage, free swap memory, and total cached memory by the system.
|
||||
该命令会展示了系统总的内存量、当前内存使用量、空闲内存量和缓冲区使用的内存总量。此外,该命令还会展示总的交换空间内存量、当前交换空间的内存使用量、空闲的交换空间内存量和缓存使用的内存总量。
|
||||
|
||||
```
|
||||
# top -b | head -10
|
||||
@ -368,27 +326,25 @@ KiB Swap: 17873388 total, 17873388 free, 0 used. 9179772 avail Mem
|
||||
2174 daygeek 20 2466680 122196 78604 S 0.8 0.8 0:17.75 WebExtensi+
|
||||
```
|
||||
|
||||
### 7) How to Check Memory Usage on Linux Using the htop Command
|
||||
### 7) 如何使用 htop 命令查看 Linux 内存使用情况
|
||||
|
||||
The **[htop command][8]** is an interactive process viewer for Linux/Unix systems. It is a text-mode application and requires the ncurses library, it was developed by Hisham.
|
||||
[htop 命令][8] 是一个可交互的 Linux/Unix 系统进程查看器。它是一个文本模式应用,且使用它需要 Hisham 开发的 ncurses 库。
|
||||
|
||||
It is designed as an alternative to the top command.
|
||||
该名令的设计目的使用来代替 `top` 命令。该命令与 `top` 命令很相似,但是其允许你可以垂直地或者水平地的滚动以便可以查看系统中所有的进程情况。
|
||||
|
||||
This is similar to the top command, but allows you to scroll vertically and horizontally to see all the processes running the system.
|
||||
`htop` 命令拥有不同的颜色,这个额外的优点当你在追踪系统性能情况时十分有用。
|
||||
|
||||
htop comes with Visual Colors, which have added benefits and are very evident when it comes to tracking system performance.
|
||||
此外,你可以自由地执行与进程相关的任务,比如杀死进程或者改变进程的优先级而不需要其进程号(PID)。
|
||||
|
||||
You are free to carry out any tasks related to processes, such as process killing and renicing without entering their PIDs.
|
||||
![][10]
|
||||
|
||||
[![][9]][10]
|
||||
### 8)如何使用 glances 命令查看 Linux 内存使用情况
|
||||
|
||||
### 8) How to Check Memory Usage on Linux Using the glances Command
|
||||
[Glances][11] 是一个 Python 编写的跨平台的系统监视工具。
|
||||
|
||||
**[Glances][11]** is a cross-platform system monitoring tool written in Python.
|
||||
你可以在一个地方查看所有信息,比如:CPU 使用情况、内存使用情况、正在运行的进程、网络接口、磁盘 I/O、RAID、传感器、文件系统信息、Docker、系统信息、运行时间等等。
|
||||
|
||||
You can see all information in one place such as CPU usage, Memory usage, running process, Network interface, Disk I/O, Raid, Sensors, Filesystem info, Docker, System info, Uptime, etc,.
|
||||
|
||||
![][9]
|
||||
![][12]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -396,21 +352,22 @@ via: https://www.2daygeek.com/linux-commands-check-memory-usage/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.2daygeek.com/author/magesh/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.2daygeek.com/how-to-find-high-cpu-consumption-processes-in-linux/
|
||||
[2]: https://www.2daygeek.com/add-extend-increase-swap-space-memory-file-partition-linux/
|
||||
[3]: https://www.2daygeek.com/free-command-to-check-memory-usage-statistics-in-linux/
|
||||
[4]: https://www.2daygeek.com/linux-vmstat-command-examples-tool-report-virtual-memory-statistics/
|
||||
[5]: https://www.2daygeek.com/ps_mem-report-core-memory-usage-accurately-in-linux/
|
||||
[6]: https://www.2daygeek.com/smem-linux-memory-usage-statistics-reporting-tool/
|
||||
[1]: https://linux.cn/article-11542-1.html
|
||||
[2]: https://linux.cn/article-9579-1.html
|
||||
[3]: https://linux.cn/article-8314-1.html
|
||||
[4]: https://linux.cn/article-8157-1.html
|
||||
[5]: https://linux.cn/article-8639-1.html
|
||||
[6]: https://linux.cn/article-7681-1.html
|
||||
[7]: https://www.2daygeek.com/linux-top-command-linux-system-performance-monitoring-tool/
|
||||
[8]: https://www.2daygeek.com/linux-htop-command-linux-system-performance-resource-monitoring-tool/
|
||||
[9]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[10]: https://www.2daygeek.com/wp-content/uploads/2019/12/linux-commands-check-memory-usage-2.jpg
|
||||
[11]: https://www.2daygeek.com/linux-glances-advanced-real-time-linux-system-performance-monitoring-tool/
|
||||
[12]: https://www.2daygeek.com/wp-content/uploads/2019/12/linux-commands-check-memory-usage-3.jpg
|
@ -0,0 +1,57 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Morisun029)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11875-1.html)
|
||||
[#]: subject: (Top CI/CD resources to set you up for success)
|
||||
[#]: via: (https://opensource.com/article/19/12/cicd-resources)
|
||||
[#]: author: (Jessica Cherry https://opensource.com/users/jrepka)
|
||||
|
||||
顶级 CI / CD 资源,助你成功
|
||||
======
|
||||
|
||||
> 随着企业期望实现无缝、灵活和可扩展的部署,持续集成和持续部署成为 2019 年的关键主题。
|
||||
|
||||
![Plumbing tubes in many directions][1]
|
||||
|
||||
对于 CI/CD 和 DevOps 来说,2019 年是非常棒的一年。Opensource.com 的作者分享了他们专注于无缝、灵活和可扩展部署时是如何朝着敏捷和 scrum 方向发展的。以下是我们 2019 年发布的 CI/CD 文章中的一些重要文章。
|
||||
|
||||
### 学习和提高你的 CI/CD 技能
|
||||
|
||||
我们最喜欢的一些文章集中在 CI/CD 的实操经验上,并涵盖了许多方面。通常以 [Jenkins][2] 管道开始,Bryant Son 的文章《[用 Jenkins 构建 CI/CD 管道][3]》将为你提供足够的经验,以开始构建你的第一个管道。Daniel Oh 在《[用 DevOps 管道进行自动验收测试][4]》一文中,提供了有关验收测试的重要信息,包括可用于自行测试的各种 CI/CD 应用程序。我写的《[安全扫描 DevOps 管道][5]》非常简短,其中简要介绍了如何使用 Jenkins 平台在管道中设置安全性。
|
||||
|
||||
### 交付工作流程
|
||||
|
||||
正如 Jithin Emmanuel 在《[Screwdriver:一个用于持续交付的可扩展构建平台][6]》中分享的,在学习如何使用和提高你的 CI/CD 技能方面,工作流程很重要,特别是当涉及到管道时。Emily Burns 在《[为什么 Spinnaker 对 CI/CD 很重要][7]》中解释了灵活地使用 CI/CD 工作流程准确构建所需内容的原因。Willy-Peter Schaub 还盛赞了为所有产品创建统一管道的想法,以便《[在一个 CI/CD 管道中一致地构建每个产品][8]》。这些文章将让你很好地了解在团队成员加入工作流程后会发生什么情况。
|
||||
|
||||
### CI/CD 如何影响企业
|
||||
|
||||
2019 年也是认识到 CI/CD 的业务影响以及它是如何影响日常运营的一年。Agnieszka Gancarczyk 分享了 Red Hat 《[小型 Scrum vs. 大型 Scrum][9]》的调查结果, 包括受访者对 Scrum、敏捷运动及对团队的影响的不同看法。Will Kelly 的《[持续部署如何影响整个组织][10]》,也提及了开放式沟通的重要性。Daniel Oh 也在《[DevOps 团队必备的 3 种指标仪表板][11]》中强调了指标和可观测性的重要性。最后是 Ann Marie Fred 的精彩文章《[不在生产环境中测试?要在生产环境中测试!][12]》详细说明了在验收测试前在生产环境中测试的重要性。
|
||||
|
||||
感谢许多贡献者在 2019 年与 Opensource 的读者分享他们的见解,我期望在 2020 年里从他们那里了解更多有关 CI/CD 发展的信息。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/cicd-resources
|
||||
|
||||
作者:[Jessica Cherry][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Morisun029](https://github.com/Morisun029)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jrepka
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/plumbing_pipes_tutorial_how_behind_scenes.png?itok=F2Z8OJV1 (Plumbing tubes in many directions)
|
||||
[2]: https://jenkins.io/
|
||||
[3]: https://linux.cn/article-11546-1.html
|
||||
[4]: https://opensource.com/article/19/4/devops-pipeline-acceptance-testing
|
||||
[5]: https://opensource.com/article/19/7/security-scanning-your-devops-pipeline
|
||||
[6]: https://opensource.com/article/19/3/screwdriver-cicd
|
||||
[7]: https://opensource.com/article/19/8/why-spinnaker-matters-cicd
|
||||
[8]: https://opensource.com/article/19/7/cicd-pipeline-rule-them-all
|
||||
[9]: https://opensource.com/article/19/3/small-scale-scrum-vs-large-scale-scrum
|
||||
[10]: https://opensource.com/article/19/7/organizational-impact-continuous-deployment
|
||||
[11]: https://linux.cn/article-11183-1.html
|
||||
[12]: https://opensource.com/article/19/5/dont-test-production
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11795-1.html)
|
||||
[#]: subject: (Run a server with Git)
|
||||
[#]: via: (https://opensource.com/article/19/4/server-administration-git)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth/users/seth)
|
||||
@ -10,37 +10,37 @@
|
||||
使用 Git 来管理 Git 服务器
|
||||
======
|
||||
|
||||
> 借助 Gitolite,你可以使用 Git 来管理 Git 服务器。在我们的系列中了解这些鲜为人知的 Git 用途。
|
||||
> 借助 Gitolite,你可以使用 Git 来管理 Git 服务器。在我们的系列文章中了解这些鲜为人知的 Git 用途。
|
||||
|
||||
![computer servers processing data][1]
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/18/132045yrr1pb9n497tfbiy.png)
|
||||
|
||||
正如我在系列文章中演示的那样,[Git][2] 除了跟踪源代码外,还可以做很多事情。信不信由你,Git 甚至可以管理你的 Git 服务器,因此你可以或多或少地使用 Git 本身运行 Git 服务器。
|
||||
正如我在系列文章中演示的那样,[Git][2] 除了跟踪源代码外,还可以做很多事情。信不信由你,Git 甚至可以管理你的 Git 服务器,因此你可以或多或少地使用 Git 本身来运行 Git 服务器。
|
||||
|
||||
当然,这涉及除日常使用 Git 之外的许多组件,其中最重要的是 [Gitolite][3],该后端应用程序可以管理你使用 Git 的每个细小的配置。Gitolite 的优点在于,由于它使用 Git 作为其前端接口,因此很容易将 Git 服务器管理集成到其他基于 Git 的工作流中。Gitolite 可以精确控制谁可以访问你服务器上的特定存储库以及他们具有哪些权限。你可以使用常规的 Linux 系统工具自行管理此类事务,但是如果在六个用户中只有一个或两个以上的仓库,则需要大量的工作。
|
||||
当然,这涉及除日常使用 Git 之外的许多组件,其中最重要的是 [Gitolite][3],该后端应用程序可以管理你使用 Git 的每个细微的配置。Gitolite 的优点在于,由于它使用 Git 作为其前端接口,因此很容易将 Git 服务器管理集成到其他基于 Git 的工作流中。Gitolite 可以精确控制谁可以访问你服务器上的特定存储库以及他们具有哪些权限。你可以使用常规的 Linux 系统工具自行管理此类事务,但是如果有好几个用户和不止一两个仓库,则需要大量的工作。
|
||||
|
||||
Gitolite 的开发人员做了艰苦的工作,使你可以轻松地为许多用户提供对你的 Git 服务器的访问权,而又不让他们访问你的整个环境 —— 而这一切,你可以使用 Git 来完成全部工作。
|
||||
|
||||
Gitolite 并`不是` 图形化的管理员和用户面板。优秀的 [Gitea][4] 项目可提供这种经验,但是本文重点介绍 Gitolite 的简单优雅和令人舒适的熟悉感。
|
||||
Gitolite 并**不是**图形化的管理员和用户面板。优秀的 [Gitea][4] 项目可提供这种体验,但是本文重点介绍 Gitolite 的简单优雅和令人舒适的熟悉感。
|
||||
|
||||
### 安装 Gitolite
|
||||
|
||||
假设你的 Git 服务器运行 Linux,则可以使用包管理器安装 Gitolite(在 CentOS 和 RHEL 上为 `yum`,在 Debian 和 Ubuntu 上为 `apt`,在 OpenSUSE 上为 `zypper` 等)。例如,在 RHEL 上:
|
||||
假设你的 Git 服务器运行在 Linux 上,则可以使用包管理器安装 Gitolite(在 CentOS 和 RHEL 上为 `yum`,在 Debian 和 Ubuntu 上为 `apt`,在 OpenSUSE 上为 `zypper` 等)。例如,在 RHEL 上:
|
||||
|
||||
```
|
||||
$ sudo yum install gitolite3
|
||||
```
|
||||
|
||||
许多发行版的存储库仍提供的是旧版本的 Gitolite,但当前版本为版本 3。
|
||||
许多发行版的存储库提供的仍是旧版本的 Gitolite,但最新版本为版本 3。
|
||||
|
||||
你必须具有对服务器的无密码 SSH 访问权限。如果愿意,你可以使用密码登录服务器,但是 Gitolite 依赖于 SSH 密钥,因此必须配置使用密钥登录的选项。如果你不知道如何配置服务器以进行无密码 SSH 访问,请首先学习如何进行操作(Steve Ovens 的 Ansible 文章的[设置 SSH 密钥身份验证][5]部分对此进行了很好的说明)。这是加强服务器管理的安全以及运行 Gitolite 的重要组成部分。
|
||||
|
||||
### 配置 Git 用户
|
||||
|
||||
如果没有 Gitolite,则如果某人请求访问你在服务器上托管的 Git 存储库,则必须向该人提供用户帐户。Git 提供了一个特殊的外壳,即 `git-shell`,这是一个仅执行 Git 任务的特别特定的 shell。这可以让你有个只能通过非常受限的 Shell 环境的过滤器来访问服务器的用户。
|
||||
如果没有 Gitolite,则如果某人请求访问你在服务器上托管的 Git 存储库时,则必须向该人提供用户帐户。Git 提供了一个特殊的外壳,即 `git-shell`,这是一个仅执行 Git 任务的特别的特定 shell。这可以让你有个只能通过非常受限的 Shell 环境来过滤访问你的服务器的用户。
|
||||
|
||||
该解决方案可行,但通常意味着用户可以访问服务器上的所有存储库,除非你具有用于组权限的良好模式,并在创建新存储库时严格保持这些权限。这种方式还需要在系统级别进行大量手动配置,这通常是为特定级别的系统管理员保留的区域,而不一定是通常负责 Git 存储库的人员。
|
||||
这个解决方案是一个办法,但通常意味着用户可以访问服务器上的所有存储库,除非你具有用于组权限的良好模式,并在创建新存储库时严格遵循这些权限。这种方式还需要在系统级别进行大量手动配置,这通常是只有特定级别的系统管理员才能做的工作,而不一定是通常负责 Git 存储库的人员。
|
||||
|
||||
Gitolite 通过为需要访问任何存储库的每个人指定一个用户名来完全回避此问题。 默认情况下,用户名是 `git`,并且由于 Gitolite 的文档假定使用的是它,因此在学习该工具时保留它是一个很好的默认设置。对于曾经使用过 GitLab 或 GitHub 或任何其他 Git 托管服务的人来说,这也是一个众所周知的约定。
|
||||
Gitolite 通过为需要访问任何存储库的每个人指定一个用户名来完全回避此问题。默认情况下,该用户名是 `git`,并且由于 Gitolite 的文档中假定使用的是它,因此在学习该工具时保留它是一个很好的默认设置。对于曾经使用过 GitLab 或 GitHub 或任何其他 Git 托管服务的人来说,这也是一个众所周知的约定。
|
||||
|
||||
Gitolite 将此用户称为**托管用户**。在服务器上创建一个帐户以充当托管用户(我习惯使用 `git`,因为这是惯例):
|
||||
|
||||
@ -48,7 +48,7 @@ Gitolite 将此用户称为**托管用户**。在服务器上创建一个帐户
|
||||
$ sudo adduser --create-home git
|
||||
```
|
||||
|
||||
为了控制该 `git` 用户帐户,该帐户必须具有属于你的有效 SSH 公钥。你应该已经进行了设置,因此复制你的公钥(**不是你的私钥**)添加到 `git` 用户的家目录中:
|
||||
为了控制该 `git` 用户帐户,该帐户必须具有属于你的有效 SSH 公钥。你应该已经进行了设置,因此复制你的公钥(**而不是你的私钥**)添加到 `git` 用户的家目录中:
|
||||
|
||||
```
|
||||
$ sudo cp ~/.ssh/id_ed25519.pub /home/git/
|
||||
@ -62,11 +62,11 @@ $ sudo su - git
|
||||
$ gitolite setup --pubkey id_ed25519.pub
|
||||
```
|
||||
|
||||
安装脚本运行后,`git` 的家用户目录将有一个 `repository` 目录,该目录(目前)包含文件 `git-admin.git` 和 `testing.git`。这就是该服务器所需的全部设置,现在请登出 `git` 用户。
|
||||
安装脚本运行后,`git` 的家用户目录将有一个 `repository` 目录,该目录(目前)包含存储库 `git-admin.git` 和 `testing.git`。这就是该服务器所需的全部设置,现在请登出 `git` 用户。
|
||||
|
||||
### 使用 Gitolite
|
||||
|
||||
管理 Gitolite 就是编辑 Git 存储库中的文本文件,尤其是 `gitolite-admin.git`。你不会通过 SSH 进入服务器来进行 Git 管理,并且 Gitolite 也建议你不要这样尝试。你和你的用户存储在 Gitolite 服务器上的存储库是个**裸**存储库,因此最好不要使用它们。
|
||||
管理 Gitolite 就是编辑 Git 存储库中的文本文件,尤其是 `gitolite-admin.git` 中的。你不会通过 SSH 进入服务器来进行 Git 管理,并且 Gitolite 也建议你不要这样尝试。在 Gitolite 服务器上存储你和你的用户的存储库是个**裸**存储库,因此最好不要使用它们。
|
||||
|
||||
```
|
||||
$ git clone git@example.com:gitolite-admin.git gitolite-admin.git
|
||||
@ -76,7 +76,7 @@ conf
|
||||
keydir
|
||||
```
|
||||
|
||||
该存储库中的 `conf` 目录包含一个名为 `gitolite.conf` 的文件。在文本编辑器中打开它,或使用`cat`查看其内容:
|
||||
该存储库中的 `conf` 目录包含一个名为 `gitolite.conf` 的文件。在文本编辑器中打开它,或使用 `cat` 查看其内容:
|
||||
|
||||
```
|
||||
repo gitolite-admin
|
||||
@ -86,15 +86,15 @@ repo testing
|
||||
RW+ = @all
|
||||
```
|
||||
|
||||
你可能对该配置文件的功能有所了解:`gitolite-admin` 代表此存储库,并且 `id_ed25519` 密钥的所有者具有读取、写入和 Git 管理权限。换句话说,不是将用户映射到普通的本地 Unix 用户(因为所有用户都使用 `git` 用户托管用户身份),而是将用户映射到 `keydir` 目录中列出的 SSH 密钥。
|
||||
你可能对该配置文件的功能有所了解:`gitolite-admin` 代表此存储库,并且 `id_ed25519` 密钥的所有者具有读取、写入和管理 Git 的权限。换句话说,不是将用户映射到普通的本地 Unix 用户(因为所有用户都使用 `git` 用户托管用户身份),而是将用户映射到 `keydir` 目录中列出的 SSH 密钥。
|
||||
|
||||
`testing.git` 存储库使用特殊组符号为访问服务器的每个人提供了全部权限。
|
||||
|
||||
#### 添加用户
|
||||
|
||||
如果要向 Git 服务器添加一个名为 `alice` 的用户,Alice 必须向你发送她的 SSH 公钥。Gitolite 使用 `.pub` 扩展名左边的任何内容作为该 Git 用户的标识符。不要使用默认的密钥名称值,而是给密钥指定一个指示密钥所有者的名称。如果用户有多个密钥(例如,一个用于笔记本电脑,一个用于台式机),则可以使用子目录来避免文件名冲突。例如,Alice 在笔记本电脑上使用的密钥可能是默认的 `id_rsa.pub`,因此将其重命名为`alice.pub` 或类似名称(或让用户根据其计算机上的本地用户帐户来命名密钥),然后将其放入 `gitolite-admin.git/keydir/work/laptop/` 目录中。如果她从她的桌面发送了另一个密钥,命名为 `alice.pub`(与上一个相同),然后将其添加到 `keydir/home/desktop/` 中。另一个密钥可能放到 `keydir/home/desktop/` 中,依此类推。Gitolite 递归地在 `keydir` 中搜索与存储库“用户”匹配的 `.pub` 文件,并将所有匹配项视为相同的身份。
|
||||
如果要向 Git 服务器添加一个名为 `alice` 的用户,Alice 必须向你发送她的 SSH 公钥。Gitolite 使用文件名的 `.pub` 扩展名左边的任何内容作为该 Git 用户的标识符。不要使用默认的密钥名称值,而是给密钥指定一个指示密钥所有者的名称。如果用户有多个密钥(例如,一个用于笔记本电脑,一个用于台式机),则可以使用子目录来避免文件名冲突。例如,Alice 在笔记本电脑上使用的密钥可能是默认的 `id_rsa.pub`,因此将其重命名为`alice.pub` 或类似名称(或让用户根据其计算机上的本地用户帐户来命名密钥),然后将其放入 `gitolite-admin.git/keydir/work/laptop/` 目录中。如果她从她的桌面计算机发送了另一个密钥,命名为 `alice.pub`(与上一个相同),然后将其添加到 `keydir/home/desktop/` 中。另一个密钥可能放到 `keydir/home/desktop/` 中,依此类推。Gitolite 递归地在 `keydir` 中搜索与存储库“用户”相匹配的 `.pub` 文件,并将所有匹配项视为相同的身份。
|
||||
|
||||
当你将密钥添加到 `keydir` 目录时,必须将它们提交回服务器。这是一件很容易忘记的事情,这里有一个使用自动化的 Git 应用程序(例如 [Sparkleshare] [7])的真正的理由,因此任何更改都将立即提交给你的 Gitolite 管理员。第一次忘记提交和推送,在浪费了三个小时的时间以及用户的故障排除时间之后,你会发现 Gitolite 是使用 Sparkleshare 的完美理由。
|
||||
当你将密钥添加到 `keydir` 目录时,必须将它们提交回服务器。这是一件很容易忘记的事情,这里有一个使用自动化的 Git 应用程序(例如 [Sparkleshare][7])的真正的理由,因此任何更改都将立即提交给你的 Gitolite 管理员。第一次忘记提交和推送,在浪费了三个小时的你和你的用户的故障排除时间之后,你会发现 Gitolite 是使用 Sparkleshare 的完美理由。
|
||||
|
||||
```
|
||||
$ git add keydir
|
||||
@ -106,10 +106,10 @@ $ git push origin HEAD
|
||||
|
||||
#### 设置权限
|
||||
|
||||
与用户一样,目录权限和组也是从你可能习惯的的常规 Unix 工具中抽象出来的(或可从在线信息查找)。在`gitolite-admin.git/conf` 目录中的 `gitolite.conf` 文件中授予对项目的权限。权限分为四个级别:
|
||||
与用户一样,目录权限和组也是从你可能习惯的的常规 Unix 工具中抽象出来的(或可从在线信息查找)。在 `gitolite-admin.git/conf` 目录中的 `gitolite.conf` 文件中授予对项目的权限。权限分为四个级别:
|
||||
|
||||
* `R` 允许只读。在存储库上具有 `R` 权限的用户可以克隆它,仅此而已。
|
||||
* `RW` 允许用户执行分支的快进推送、创建新分支和创建新标签。对于大多数用户来说,这个或多或少感觉就像一个“普通”的 Git 存储库。
|
||||
* `RW` 允许用户执行分支的快进推送、创建新分支和创建新标签。对于大多数用户来说,这个基本上就像是一个“普通”的 Git 存储库。
|
||||
* `RW+` 允许可能具有破坏性的 Git 动作。用户可以执行常规的快进推送、回滚推送、变基以及删除分支和标签。你可能想要或不希望将其授予项目中的所有贡献者。
|
||||
* `-` 明确拒绝访问存储库。这与未在存储库的配置中列出的用户相同。
|
||||
|
||||
@ -126,7 +126,7 @@ repo widgets
|
||||
RW+ = alice
|
||||
```
|
||||
|
||||
现在,Alice(也仅 Alice 一个人)就可以克隆该存储库:
|
||||
现在,Alice(也仅有 Alice 一个人)可以克隆该存储库:
|
||||
|
||||
```
|
||||
[alice]$ git clone git@example.com:widgets.git
|
||||
@ -188,7 +188,7 @@ repo foo/CREATOR/[a-z]..*
|
||||
R = READERS
|
||||
```
|
||||
|
||||
第一行定义了一组用户:该组称为 `@managers`,其中包含用户 `alice` 和 `bob`。下一行设置了通配符允许创建尚不存在的存储库,放在名为 `foo` 的目录下的创建存储库的用户名的子目录中。例如:
|
||||
第一行定义了一组用户:该组称为 `@managers`,其中包含用户 `alice` 和 `bob`。下一行设置了通配符允许创建尚不存在的存储库,放在名为 `foo` 的目录下的创建该存储库的用户名的子目录中。例如:
|
||||
|
||||
```
|
||||
[alice]$ git clone git@example.com:foo/alice/cool-app.git
|
||||
@ -197,11 +197,11 @@ Initialized empty Git repository in /home/git/repositories/foo/alice/cool-app.gi
|
||||
warning: You appear to have cloned an empty repository.
|
||||
```
|
||||
|
||||
野生仓库的创建者可以使用一些机制来定义谁可以读取和写入其存储库,但是他们是被限定范围的。在大多数情况下,Gitolite 假定由一组特定的用户来管理项目权限。一种解决方案是使用 Git 挂钩授予所有用户对 `gitolite-admin` 的访问权限,以要求管理者批准将更改合并到 master 分支中。
|
||||
野生仓库的创建者可以使用一些机制来定义谁可以读取和写入其存储库,但是他们是有范围限定的。在大多数情况下,Gitolite 假定由一组特定的用户来管理项目权限。一种解决方案是使用 Git 挂钩来授予所有用户对 `gitolite-admin` 的访问权限,以要求管理者批准将更改合并到 master 分支中。
|
||||
|
||||
### 了解更多
|
||||
|
||||
Gitolite 具有比此介绍性文章涵盖的更多功能,因此请尝试一下。其[文档][8]非常出色,一旦你通读了它,就可以自定义 Gitolite 服务器,以向用户提供你喜欢的任何级别的控制。Gitolite 是一种维护成本低、简单的系统,你可以安装、设置它,然后基本上就可以将其忘却。
|
||||
Gitolite 具有比此介绍性文章所涵盖的更多功能,因此请尝试一下。其[文档][8]非常出色,一旦你通读了它,就可以自定义 Gitolite 服务器,以向用户提供你喜欢的任何级别的控制。Gitolite 是一种维护成本低、简单的系统,你可以安装、设置它,然后基本上就可以将其忘却。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -210,7 +210,7 @@ via: https://opensource.com/article/19/4/server-administration-git
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,333 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11810-1.html)
|
||||
[#]: subject: (Getting started with OpenSSL: Cryptography basics)
|
||||
[#]: via: (https://opensource.com/article/19/6/cryptography-basics-openssl-part-1)
|
||||
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu/users/akritiko/users/clhermansen)
|
||||
|
||||
OpenSSL 入门:密码学基础知识
|
||||
======
|
||||
|
||||
> 想要入门密码学的基础知识,尤其是有关 OpenSSL 的入门知识吗?继续阅读。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/23/142249fpnhyqz9y2cz1exe.jpg)
|
||||
|
||||
本文是使用 [OpenSSL][2] 的密码学基础知识的两篇文章中的第一篇,OpenSSL 是在 Linux 和其他系统上流行的生产级库和工具包。(要安装 OpenSSL 的最新版本,请参阅[这里][3]。)OpenSSL 实用程序可在命令行使用,程序也可以调用 OpenSSL 库中的函数。本文的示例程序使用的是 C 语言,即 OpenSSL 库的源语言。
|
||||
|
||||
本系列的两篇文章涵盖了加密哈希、数字签名、加密和解密以及数字证书。你可以从[我的网站][4]的 ZIP 文件中找到这些代码和命令行示例。
|
||||
|
||||
让我们首先回顾一下 OpenSSL 名称中的 SSL。
|
||||
|
||||
### OpenSSL 简史
|
||||
|
||||
<ruby>[安全套接字层][5]<rt>Secure Socket Layer</rt></ruby>(SSL)是 Netscape 在 1995 年发布的一种加密协议。该协议层可以位于 HTTP 之上,从而为 HTTPS 提供了 S:<ruby>安全<rt>secure</rt></ruby>。SSL 协议提供了各种安全服务,其中包括两项在 HTTPS 中至关重要的服务:
|
||||
|
||||
* <ruby>对等身份验证<rt>Peer authentication</rt></ruby>(也称为相互质询):连接的每一边都对另一边的身份进行身份验证。如果 Alice 和 Bob 要通过 SSL 交换消息,则每个人首先验证彼此的身份。
|
||||
* <ruby>机密性<rt>Confidentiality</rt></ruby>:发送者在通过通道发送消息之前先对其进行加密。然后,接收者解密每个接收到的消息。此过程可保护网络对话。即使窃听者 Eve 截获了从 Alice 到 Bob 的加密消息(即*中间人*攻击),Eve 会发现他无法在计算上解密此消息。
|
||||
|
||||
反过来,这两个关键 SSL 服务与其他不太受关注的服务相关联。例如,SSL 支持消息完整性,从而确保接收到的消息与发送的消息相同。此功能是通过哈希函数实现的,哈希函数也随 OpenSSL 工具箱一起提供。
|
||||
|
||||
SSL 有多个版本(例如 SSLv2 和 SSLv3),并且在 1999 年出现了一个基于 SSLv3 的类似协议<ruby>传输层安全性<rt>Transport Layer Security</rt></ruby>(TLS)。TLSv1 和 SSLv3 相似,但不足以相互配合工作。不过,通常将 SSL/TLS 称为同一协议。例如,即使正在使用的是 TLS(而非 SSL),OpenSSL 函数也经常在名称中包含 SSL。此外,调用 OpenSSL 命令行实用程序以 `openssl` 开始。
|
||||
|
||||
除了 man 页面之外,OpenSSL 的文档是零零散散的,鉴于 OpenSSL 工具包很大,这些页面很难以查找使用。命令行和代码示例可以将主要主题集中起来。让我们从一个熟悉的示例开始(使用 HTTPS 访问网站),然后使用该示例来选出我们感兴趣的加密部分进行讲述。
|
||||
|
||||
### 一个 HTTPS 客户端
|
||||
|
||||
此处显示的 `client` 程序通过 HTTPS 连接到 Google:
|
||||
|
||||
```
|
||||
/* compilation: gcc -o client client.c -lssl -lcrypto */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/bio.h> /* BasicInput/Output streams */
|
||||
#include <openssl/err.h> /* errors */
|
||||
#include <openssl/ssl.h> /* core library */
|
||||
#define BuffSize 1024
|
||||
|
||||
void report_and_exit(const char* msg) {
|
||||
perror(msg);
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void init_ssl() {
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
}
|
||||
|
||||
void cleanup(SSL_CTX* ctx, BIO* bio) {
|
||||
SSL_CTX_free(ctx);
|
||||
BIO_free_all(bio);
|
||||
}
|
||||
|
||||
void secure_connect(const char* hostname) {
|
||||
char name[BuffSize];
|
||||
char request[BuffSize];
|
||||
char response[BuffSize];
|
||||
|
||||
const SSL_METHOD* method = TLSv1_2_client_method();
|
||||
if (NULL == method) report_and_exit("TLSv1_2_client_method...");
|
||||
|
||||
SSL_CTX* ctx = SSL_CTX_new(method);
|
||||
if (NULL == ctx) report_and_exit("SSL_CTX_new...");
|
||||
|
||||
BIO* bio = BIO_new_ssl_connect(ctx);
|
||||
if (NULL == bio) report_and_exit("BIO_new_ssl_connect...");
|
||||
|
||||
SSL* ssl = NULL;
|
||||
|
||||
/* 链路 bio 通道,SSL 会话和服务器端点 */
|
||||
|
||||
sprintf(name, "%s:%s", hostname, "https");
|
||||
BIO_get_ssl(bio, &ssl); /* 会话 */
|
||||
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* 鲁棒性 */
|
||||
BIO_set_conn_hostname(bio, name); /* 准备连接 */
|
||||
|
||||
/* 尝试连接 */
|
||||
if (BIO_do_connect(bio) <= 0) {
|
||||
cleanup(ctx, bio);
|
||||
report_and_exit("BIO_do_connect...");
|
||||
}
|
||||
|
||||
/* 验证信任库,检查证书 */
|
||||
if (!SSL_CTX_load_verify_locations(ctx,
|
||||
"/etc/ssl/certs/ca-certificates.crt", /* 信任库 */
|
||||
"/etc/ssl/certs/")) /* 其它信任库 */
|
||||
report_and_exit("SSL_CTX_load_verify_locations...");
|
||||
|
||||
long verify_flag = SSL_get_verify_result(ssl);
|
||||
if (verify_flag != X509_V_OK)
|
||||
fprintf(stderr,
|
||||
"##### Certificate verification error (%i) but continuing...\n",
|
||||
(int) verify_flag);
|
||||
|
||||
/* 获取主页作为示例数据 */
|
||||
sprintf(request,
|
||||
"GET / HTTP/1.1\x0D\x0AHost: %s\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A",
|
||||
hostname);
|
||||
BIO_puts(bio, request);
|
||||
|
||||
/* 从服务器读取 HTTP 响应并打印到输出 */
|
||||
while (1) {
|
||||
memset(response, '\0', sizeof(response));
|
||||
int n = BIO_read(bio, response, BuffSize);
|
||||
if (n <= 0) break; /* 0 代表流结束,< 0 代表有错误 */
|
||||
puts(response);
|
||||
}
|
||||
|
||||
cleanup(ctx, bio);
|
||||
}
|
||||
|
||||
int main() {
|
||||
init_ssl();
|
||||
|
||||
const char* hostname = "www.google.com:443";
|
||||
fprintf(stderr, "Trying an HTTPS connection to %s...\n", hostname);
|
||||
secure_connect(hostname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
可以从命令行编译和执行该程序(请注意 `-lssl` 和 `-lcrypto` 中的小写字母 `L`):
|
||||
|
||||
```
|
||||
gcc -o client client.c -lssl -lcrypto
|
||||
```
|
||||
|
||||
该程序尝试打开与网站 [www.google.com][13] 的安全连接。在与 Google Web 服务器的 TLS 握手过程中,`client` 程序会收到一个或多个数字证书,该程序会尝试对其进行验证(但在我的系统上失败了)。尽管如此,`client` 程序仍继续通过安全通道获取 Google 主页。该程序取决于前面提到的安全工件,尽管在上述代码中只着重突出了数字证书。但其它工件仍在幕后发挥作用,稍后将对它们进行详细说明。
|
||||
|
||||
通常,打开 HTTP(非安全)通道的 C 或 C++ 的客户端程序将使用诸如*文件描述符*或*网络套接字*之类的结构,它们是两个进程(例如,这个 `client` 程序和 Google Web 服务器)之间连接的端点。另一方面,文件描述符是一个非负整数值,用于在程序中标识该程序打开的任何文件类的结构。这样的程序还将使用一种结构来指定有关 Web 服务器地址的详细信息。
|
||||
|
||||
这些相对较低级别的结构不会出现在客户端程序中,因为 OpenSSL 库会将套接字基础设施和地址规范等封装在更高层面的安全结构中。其结果是一个简单的 API。下面首先看一下 `client` 程序示例中的安全性详细信息。
|
||||
|
||||
* 该程序首先加载相关的 OpenSSL 库,我的函数 `init_ssl` 中对 OpenSSL 进行了两次调用:
|
||||
|
||||
```
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
```
|
||||
* 下一个初始化步骤尝试获取安全*上下文*,这是建立和维护通往 Web 服务器的安全通道所需的信息框架。如对 OpenSSL 库函数的调用所示,在示例中使用了 TLS 1.2:
|
||||
|
||||
```
|
||||
const SSL_METHOD* method = TLSv1_2_client_method(); /* TLS 1.2 */
|
||||
```
|
||||
|
||||
如果调用成功,则将 `method` 指针被传递给库函数,该函数创建类型为 `SSL_CTX` 的上下文:
|
||||
|
||||
```
|
||||
SSL_CTX* ctx = SSL_CTX_new(method);
|
||||
```
|
||||
|
||||
`client` 程序会检查每个关键的库调用的错误,如果其中一个调用失败,则程序终止。
|
||||
* 现在还有另外两个 OpenSSL 工件也在发挥作用:SSL 类型的安全会话,从头到尾管理安全连接;以及类型为 BIO(<ruby>基本输入/输出<rt>Basic Input/Output</rt></ruby>)的安全流,用于与 Web 服务器进行通信。BIO 流是通过以下调用生成的:
|
||||
|
||||
```
|
||||
BIO* bio = BIO_new_ssl_connect(ctx);
|
||||
```
|
||||
|
||||
请注意,这个最重要的上下文是其参数。`BIO` 类型是 C 语言中 `FILE` 类型的 OpenSSL 封装器。此封装器可保护 `client` 程序与 Google 的网络服务器之间的输入和输出流的安全。
|
||||
* 有了 `SSL_CTX` 和 `BIO`,然后程序在 SSL 会话中将它们组合在一起。三个库调用可以完成工作:
|
||||
|
||||
```
|
||||
BIO_get_ssl(bio, &ssl); /* 会话 */
|
||||
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* 鲁棒性 */
|
||||
BIO_set_conn_hostname(bio, name); /* 准备连接 */
|
||||
```
|
||||
|
||||
安全连接本身是通过以下调用建立的:
|
||||
|
||||
```
|
||||
BIO_do_connect(bio);
|
||||
```
|
||||
|
||||
如果最后一个调用不成功,则 `client` 程序终止;否则,该连接已准备就绪,可以支持 `client` 程序与 Google Web 服务器之间的机密对话。
|
||||
|
||||
在与 Web 服务器握手期间,`client` 程序会接收一个或多个数字证书,以认证服务器的身份。但是,`client` 程序不会发送自己的证书,这意味着这个身份验证是单向的。(Web 服务器通常配置为**不**需要客户端证书)尽管对 Web 服务器证书的验证失败,但 `client` 程序仍通过了连接到 Web 服务器的安全通道继续获取 Google 主页。
|
||||
|
||||
为什么验证 Google 证书的尝试会失败?典型的 OpenSSL 安装目录为 `/etc/ssl/certs`,其中包含 `ca-certificates.crt` 文件。该目录和文件包含着 OpenSSL 自带的数字证书,以此构成<ruby>信任库<rt>truststore</rt></ruby>。可以根据需要更新信任库,尤其是可以包括新信任的证书,并删除不再受信任的证书。
|
||||
|
||||
`client` 程序从 Google Web 服务器收到了三个证书,但是我的计算机上的 OpenSSL 信任库并不包含完全匹配的证书。如目前所写,`client` 程序不会通过例如验证 Google 证书上的数字签名(一个用来证明该证书的签名)来解决此问题。如果该签名是受信任的,则包含该签名的证书也应受信任。尽管如此,`client` 程序仍继续获取页面,然后打印出 Google 的主页。下一节将更详细地介绍这些。
|
||||
|
||||
### 客户端程序中隐藏的安全性
|
||||
|
||||
让我们从客户端示例中可见的安全工件(数字证书)开始,然后考虑其他安全工件如何与之相关。数字证书的主要格式标准是 X509,生产级的证书由诸如 [Verisign][14] 的<ruby>证书颁发机构<rt>Certificate Authority</rt></ruby>(CA)颁发。
|
||||
|
||||
数字证书中包含各种信息(例如,激活日期和失效日期以及所有者的域名),也包括发行者的身份和*数字签名*(这是加密过的*加密哈希*值)。证书还具有未加密的哈希值,用作其标识*指纹*。
|
||||
|
||||
哈希值来自将任意数量的二进制位映射到固定长度的摘要。这些位代表什么(会计报告、小说或数字电影)无关紧要。例如,<ruby>消息摘要版本 5<rt>Message Digest version 5</rt></ruby>(MD5)哈希算法将任意长度的输入位映射到 128 位哈希值,而 SHA1(<ruby>安全哈希算法版本 1<rt>Secure Hash Algorithm version 1</rt></ruby>)算法将输入位映射到 160 位哈希值。不同的输入位会导致不同的(实际上在统计学上是唯一的)哈希值。下一篇文章将会进行更详细的介绍,并着重介绍什么使哈希函数具有加密功能。
|
||||
|
||||
数字证书的类型有所不同(例如根证书、中间证书和最终实体证书),并形成了反映这些证书类型的层次结构。顾名思义,*根*证书位于层次结构的顶部,其下的证书继承了根证书所具有的信任。OpenSSL 库和大多数现代编程语言都具有 X509 数据类型以及处理此类证书的函数。来自 Google 的证书具有 X509 格式,`client` 程序会检查该证书是否为 `X509_V_OK`。
|
||||
|
||||
X509 证书基于<ruby>公共密钥基础结构<rt>public-key infrastructure</rt></ruby>(PKI),其中包括的算法(RSA 是占主导地位的算法)用于生成*密钥对*:公共密钥及其配对的私有密钥。公钥是一种身份:[Amazon][15] 的公钥对其进行标识,而我的公钥对我进行标识。私钥应由其所有者负责保密。
|
||||
|
||||
成对出现的密钥具有标准用途。可以使用公钥对消息进行加密,然后可以使用同一个密钥对中的私钥对消息进行解密。私钥也可以用于对文档或其他电子工件(例如程序或电子邮件)进行签名,然后可以使用该对密钥中的公钥来验证签名。以下两个示例补充了一些细节。
|
||||
|
||||
在第一个示例中,Alice 将她的公钥分发给全世界,包括 Bob。然后,Bob 用 Alice 的公钥加密邮件,然后将加密的邮件发送给 Alice。用 Alice 的公钥加密的邮件将可以用她的私钥解密(假设是她自己的私钥),如下所示:
|
||||
|
||||
```
|
||||
+------------------+ encrypted msg +-------------------+
|
||||
Bob's msg--->|Alice's public key|--------------->|Alice's private key|---> Bob's msg
|
||||
+------------------+ +-------------------+
|
||||
```
|
||||
|
||||
理论上可以在没有 Alice 的私钥的情况下解密消息,但在实际情况中,如果使用像 RSA 这样的加密密钥对系统,则在计算上做不到。
|
||||
|
||||
现在,第二个示例,请对文档签名以证明其真实性。签名算法使用密钥对中的私钥来处理要签名的文档的加密哈希:
|
||||
|
||||
```
|
||||
+-------------------+
|
||||
Hash of document--->|Alice's private key|--->Alice's digital signature of the document
|
||||
+-------------------+
|
||||
```
|
||||
|
||||
假设 Alice 以数字方式签署了发送给 Bob 的合同。然后,Bob 可以使用 Alice 密钥对中的公钥来验证签名:
|
||||
|
||||
```
|
||||
+------------------+
|
||||
Alice's digital signature of the document--->|Alice's public key|--->verified or not
|
||||
+------------------+
|
||||
```
|
||||
|
||||
假若没有 Alice 的私钥,就无法轻松伪造 Alice 的签名:因此,Alice 有必要保密她的私钥。
|
||||
|
||||
在 `client` 程序中,除了数字证书以外,这些安全性都没有明确展示。下一篇文章使用使用 OpenSSL 实用程序和库函数的示例填充更多详细的信息。
|
||||
|
||||
### 命令行的 OpenSSL
|
||||
|
||||
同时,让我们看一下 OpenSSL 命令行实用程序:特别是在 TLS 握手期间检查来自 Web 服务器的证书的实用程序。调用 OpenSSL 实用程序可以使用 `openssl` 命令,然后添加参数和标志的组合以指定所需的操作。
|
||||
|
||||
看看以下命令:
|
||||
|
||||
```
|
||||
openssl list-cipher-algorithms
|
||||
```
|
||||
|
||||
该输出是组成<ruby>加密算法套件<rt>cipher suite<rt></ruby>的相关算法的列表。下面是列表的开头,加了澄清首字母缩写词的注释:
|
||||
|
||||
```
|
||||
AES-128-CBC ## Advanced Encryption Standard, Cipher Block Chaining
|
||||
AES-128-CBC-HMAC-SHA1 ## Hash-based Message Authentication Code with SHA1 hashes
|
||||
AES-128-CBC-HMAC-SHA256 ## ditto, but SHA256 rather than SHA1
|
||||
...
|
||||
```
|
||||
|
||||
下一条命令使用参数 `s_client` 将打开到 [www.google.com][13] 的安全连接,并在屏幕上显示有关此连接的所有信息:
|
||||
|
||||
```
|
||||
openssl s_client -connect www.google.com:443 -showcerts
|
||||
```
|
||||
|
||||
端口号 443 是 Web 服务器用于接收 HTTPS(而不是 HTTP 连接)的标准端口号。(对于 HTTP,标准端口为 80)Web 地址 www.google.com:443 也出现在 `client` 程序的代码中。如果尝试连接成功,则将显示来自 Google 的三个数字证书以及有关安全会话、正在使用的加密算法套件以及相关项目的信息。例如,这是开头的部分输出,它声明*证书链*即将到来。证书的编码为 base64:
|
||||
|
||||
|
||||
```
|
||||
Certificate chain
|
||||
0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
|
||||
i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEijCCA3KgAwIBAgIQdCea9tmy/T6rK/dDD1isujANBgkqhkiG9w0BAQsFADBU
|
||||
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUw
|
||||
...
|
||||
```
|
||||
|
||||
诸如 Google 之类的主要网站通常会发送多个证书进行身份验证。
|
||||
|
||||
输出以有关 TLS 会话的摘要信息结尾,包括加密算法套件的详细信息:
|
||||
|
||||
```
|
||||
SSL-Session:
|
||||
Protocol : TLSv1.2
|
||||
Cipher : ECDHE-RSA-AES128-GCM-SHA256
|
||||
Session-ID: A2BBF0E4991E6BBBC318774EEE37CFCB23095CC7640FFC752448D07C7F438573
|
||||
...
|
||||
```
|
||||
|
||||
`client` 程序中使用了协议 TLS 1.2,`Session-ID` 唯一地标识了 `openssl` 实用程序和 Google Web 服务器之间的连接。`Cipher` 条目可以按以下方式进行解析:
|
||||
|
||||
* `ECDHE`(<ruby>椭圆曲线 Diffie-Hellman(临时)<rt>Elliptic Curve Diffie Hellman Ephemeral</rt></ruby>)是一种用于管理 TLS 握手的高效的有效算法。尤其是,ECDHE 通过确保连接双方(例如,`client` 程序和 Google Web 服务器)使用相同的加密/解密密钥(称为*会话密钥*)来解决“密钥分发问题”。后续文章会深入探讨该细节。
|
||||
* `RSA`(Rivest Shamir Adleman)是主要的公共密钥密码系统,并以 1970 年代末首次描述了该系统的三位学者的名字命名。这个正在使用的密钥对是使用 RSA 算法生成的。
|
||||
* `AES128`(<ruby>高级加密标准<rt>Advanced Encryption Standard</rt></ruby>)是一种<ruby>块式加密算法<rt>block cipher</rt></ruby>,用于加密和解密<ruby>位块<rt>blocks of bits</rt></ruby>。(另一种算法是<ruby>流式加密算法<rt>stream cipher</rt></ruby>,它一次加密和解密一个位。)这个加密算法是对称加密算法,因为使用同一个密钥进行加密和解密,这首先引起了密钥分发问题。AES 支持 128(此处使用)、192 和 256 位的密钥大小:密钥越大,安全性越好。
|
||||
|
||||
通常,像 AES 这样的对称加密系统的密钥大小要小于像 RSA 这样的非对称(基于密钥对)系统的密钥大小。例如,1024 位 RSA 密钥相对较小,而 256 位密钥则当前是 AES 最大的密钥。
|
||||
* `GCM`(<ruby>伽罗瓦计数器模式<rt>Galois Counter Mode</rt></ruby>)处理在安全对话期间重复应用的加密算法(在这种情况下为 AES128)。AES128 块的大小仅为 128 位,安全对话很可能包含从一侧到另一侧的多个 AES128 块。GCM 非常有效,通常与 AES128 搭配使用。
|
||||
* `SHA256`(<ruby>256 位安全哈希算法<rt>Secure Hash Algorithm 256 bits</rt></ruby>)是我们正在使用的加密哈希算法。生成的哈希值的大小为 256 位,尽管使用 SHA 甚至可以更大。
|
||||
|
||||
加密算法套件正在不断发展中。例如,不久前,Google 使用 RC4 流加密算法(RSA 的 Ron Rivest 后来开发的 Ron's Cipher 版本 4)。 RC4 现在有已知的漏洞,这大概部分导致了 Google 转换为 AES128。
|
||||
|
||||
### 总结
|
||||
|
||||
我们通过安全的 C Web 客户端和各种命令行示例对 OpenSSL 做了首次了解,使一些需要进一步阐明的主题脱颖而出。[下一篇文章会详细介绍][17],从加密散列开始,到对数字证书如何应对密钥分发挑战为结束的更全面讨论。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/6/cryptography-basics-openssl-part-1
|
||||
|
||||
作者:[Marty Kalin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mkalindepauledu/users/akritiko/users/clhermansen
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUSINESS_3reasons.png?itok=k6F3-BqA (A lock on the side of a building)
|
||||
[2]: https://www.openssl.org/
|
||||
[3]: https://www.howtoforge.com/tutorial/how-to-install-openssl-from-source-on-linux/
|
||||
[4]: http://condor.depaul.edu/mkalin
|
||||
[5]: https://en.wikipedia.org/wiki/Transport_Layer_Security
|
||||
[6]: https://en.wikipedia.org/wiki/Netscape
|
||||
[7]: http://www.opengroup.org/onlinepubs/009695399/functions/perror.html
|
||||
[8]: http://www.opengroup.org/onlinepubs/009695399/functions/exit.html
|
||||
[9]: http://www.opengroup.org/onlinepubs/009695399/functions/sprintf.html
|
||||
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html
|
||||
[11]: http://www.opengroup.org/onlinepubs/009695399/functions/memset.html
|
||||
[12]: http://www.opengroup.org/onlinepubs/009695399/functions/puts.html
|
||||
[13]: http://www.google.com
|
||||
[14]: https://www.verisign.com
|
||||
[15]: https://www.amazon.com
|
||||
[16]: http://www.google.com:443
|
||||
[17]: https://opensource.com/article/19/6/cryptography-basics-openssl-part-2
|
@ -0,0 +1,107 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11822-1.html)
|
||||
[#]: subject: (How the Linux screen tool can save your tasks – and your sanity – if SSH is interrupted)
|
||||
[#]: via: (https://www.networkworld.com/article/3441777/how-the-linux-screen-tool-can-save-your-tasks-and-your-sanity-if-ssh-is-interrupted.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
如果 SSH 被中断,Linux screen 工具如何拯救你的任务以及理智
|
||||
======
|
||||
|
||||
> 当你需要确保长时间运行的任务不会在 SSH 会话中断时被杀死时,Linux screen 命令可以成为救生员。以下是使用方法。
|
||||
|
||||
![](https://images.idgesg.net/images/article/2019/09/working_w_screen-shs-100812448-large.jpg)
|
||||
|
||||
如果因 SSH 会话断开而不得不重启一个耗时的进程,那么你可能会很高兴了解一个有趣的工具,可以用来避免此问题:`screen` 工具。
|
||||
|
||||
`screen` 是一个终端多路复用器,它使你可以在单个 SSH 会话中运行多个终端会话,并随时从它们之中脱离或重新接驳。做到这一点的过程非常简单,仅涉及少数命令。
|
||||
|
||||
要启动 `screen` 会话,只需在 SSH 会话中键入 `screen`。 然后,你可以开始启动需要长时间运行的进程,并在适当的时候键入 `Ctrl + A Ctrl + D` 从会话中脱离,然后键入 `screen -r` 重新接驳。
|
||||
|
||||
如果你要运行多个 `screen` 会话,更好的选择是为每个会话指定一个有意义的名称,以帮助你记住正在处理的任务。使用这种方法,你可以在启动每个会话时使用如下命令命名:
|
||||
|
||||
```
|
||||
$ screen -S slow-build
|
||||
```
|
||||
|
||||
一旦运行了多个会话,要重新接驳到一个会话,需要从列表中选择它。在以下命令中,我们列出了当前正在运行的会话,然后再重新接驳其中一个。请注意,一开始这两个会话都被标记为已脱离。
|
||||
|
||||
```
|
||||
$ screen -ls
|
||||
There are screens on:
|
||||
6617.check-backups (09/26/2019 04:35:30 PM) (Detached)
|
||||
1946.slow-build (09/26/2019 02:51:50 PM) (Detached)
|
||||
2 Sockets in /run/screen/S-shs
|
||||
```
|
||||
|
||||
然后,重新接驳到该会话要求你提供分配给会话的名称。例如:
|
||||
|
||||
```
|
||||
$ screen -r slow-build
|
||||
```
|
||||
|
||||
在脱离的会话中,保持运行状态的进程会继续进行处理,而你可以执行其他工作。如果你使用这些 `screen` 会话之一来查询 `screen` 会话情况,可以看到当前重新接驳的会话再次显示为 `Attached`。
|
||||
|
||||
```
|
||||
$ screen -ls
|
||||
There are screens on:
|
||||
6617.check-backups (09/26/2019 04:35:30 PM) (Attached)
|
||||
1946.slow-build (09/26/2019 02:51:50 PM) (Detached)
|
||||
2 Sockets in /run/screen/S-shs.
|
||||
```
|
||||
|
||||
你可以使用 `-version` 选项查询正在运行的 `screen` 版本。
|
||||
|
||||
```
|
||||
$ screen -version
|
||||
Screen version 4.06.02 (GNU) 23-Oct-17
|
||||
```
|
||||
|
||||
### 安装 screen
|
||||
|
||||
如果 `which screen` 未在屏幕上提供信息,则可能你的系统上未安装该工具。
|
||||
|
||||
```
|
||||
$ which screen
|
||||
/usr/bin/screen
|
||||
```
|
||||
|
||||
如果你需要安装它,则以下命令之一可能适合你的系统:
|
||||
|
||||
```
|
||||
sudo apt install screen
|
||||
sudo yum install screen
|
||||
```
|
||||
|
||||
当你需要运行耗时的进程时,如果你的 SSH 会话由于某种原因断开连接,则可能会中断这个耗时的进程,那么 `screen` 工具就会派上用场。而且,如你所见,它非常易于使用和管理。
|
||||
|
||||
以下是上面使用的命令的摘要:
|
||||
|
||||
```
|
||||
screen -S <process description> 开始会话
|
||||
Ctrl+A Ctrl+D 从会话中脱离
|
||||
screen -ls 列出会话
|
||||
screen -r <process description> 重新接驳会话
|
||||
```
|
||||
|
||||
尽管还有更多关于 `screen` 的知识,包括可以在 `screen` 会话之间进行操作的其他方式,但这已经足够帮助你开始使用这个便捷的工具了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3441777/how-the-linux-screen-tool-can-save-your-tasks-and-your-sanity-if-ssh-is-interrupted.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][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.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.youtube.com/playlist?list=PL7D2RMSmRO9J8OTpjFECi8DJiTQdd4hua
|
||||
[2]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE20773&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[3]: https://www.facebook.com/NetworkWorld/
|
||||
[4]: https://www.linkedin.com/company/network-world
|
61
published/202001/20191015 How GNOME uses Git.md
Normal file
61
published/202001/20191015 How GNOME uses Git.md
Normal file
@ -0,0 +1,61 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11806-1.html)
|
||||
[#]: subject: (How GNOME uses Git)
|
||||
[#]: via: (https://opensource.com/article/19/10/how-gnome-uses-git)
|
||||
[#]: author: (Molly de Blanc https://opensource.com/users/mollydb)
|
||||
|
||||
一个非技术人员对 GNOME 项目使用 GitLab 的感受
|
||||
======
|
||||
|
||||
> 将 GNOME 项目集中在 GitLab 上的决定为整个社区(不只是开发人员)带来了好处。
|
||||
|
||||
![red panda][1]
|
||||
|
||||
“您的 GitLab 是什么?”这是我在 [GNOME 基金会][2]工作的第一天被问到的第一个问题之一,该基金会是支持 GNOME 项目(包括[桌面环境][3]、[GTK][4] 和 [GStreamer][5])的非盈利组织。此人问的是我在 [GNOME 的 GitLab 实例][6]上的用户名。我在 GNOME 期间,经常有人要求我提供我的 GitLab。
|
||||
|
||||
我们使用 GitLab 进行几乎所有操作。通常情况下,我会收到一些<ruby>提案<rt>issue</rt></ruby>和参考错误报告,有时还需要修改文件。我不是以开发人员或系统管理员的身份进行此操作的。我参与了“参与度、包容性和多样性(I&D)”团队。我为 GNOME 朋友们撰写新闻通讯,并采访该项目的贡献者。我为 GNOME 活动提供赞助。我不写代码,但我每天都使用 GitLab。
|
||||
|
||||
在过去的二十年中,GNOME 项目的管理采用了各种方式。该项目的不同部分使用不同的系统来跟踪代码更改、协作以及作为项目和社交空间共享信息。但是,该项目决定,它需要更加地一体化,这从构思到完成大约花费了一年的时间。
|
||||
|
||||
GNOME 希望切换到单个工具供整个社区使用的原因很多。外部项目与 GNOME 息息相关,并为它们提供更简单的与资源交互的方式对于项目至关重要,无论是支持社区还是发展生态系统。我们还希望更好地跟踪 GNOME 的指标,即贡献者的数量、贡献的类型和数量以及项目不同部分的开发进度。
|
||||
|
||||
当需要选择一种协作工具时,我们考虑了我们需要的东西。最重要的要求之一是它必须由 GNOME 社区托管。由第三方托管并不是一种选择,因此像 GitHub 和 Atlassian 这样的服务就不在考虑之中。而且,当然了,它必须是自由软件。很快,唯一真正的竞争者出现了,它就是 GitLab。我们希望确保进行贡献很容易。GitLab 具有诸如单点登录的功能,该功能允许人们使用 GitHub、Google、GitLab.com 和 GNOME 帐户登录。
|
||||
|
||||
我们认为 GitLab 是一条出路,我们开始从许多工具迁移到单个工具。GNOME 董事会成员 [Carlos Soriano][7] 领导这项改变。在 GitLab 和 GNOME 社区的大力支持下,我们于 2018 年 5 月完成了该过程。
|
||||
|
||||
人们非常希望迁移到 GitLab 有助于社区的发展,并使贡献更加容易。由于 GNOME 以前使用了许多不同的工具,包括 Bugzilla 和 CGit,因此很难定量地评估这次切换对贡献量的影响。但是,我们可以更清楚地跟踪一些统计数据,例如在 2018 年 6 月至 2018 年 11 月之间关闭了近 10,000 个提案,合并了 7,085 个合并请求。人们感到社区在发展壮大,越来越受欢迎,而且贡献实际上也更加容易。
|
||||
|
||||
人们因不同的原因而开始使用自由软件,重要的是,可以通过为需要软件的人提供更好的资源和更多的支持来公平竞争。Git 作为一种工具已被广泛使用,并且越来越多的人使用这些技能来参与到自由软件当中。自托管的 GitLab 提供了将 Git 的熟悉度与 GitLab 提供的功能丰富、用户友好的环境相结合的绝佳机会。
|
||||
|
||||
切换到 GitLab 已经一年多了,变化确实很明显。持续集成(CI)为开发带来了巨大的好处,并且已经完全集成到 GNOME 的几乎每个部分当中。不进行代码开发的团队也转而使用 GitLab 生态系统进行工作。无论是使用问题跟踪来管理分配的任务,还是使用版本控制来共享和管理资产,就连“参与度、包容性和多样性(I&D)”这样的团队都已经使用了 GitLab。
|
||||
|
||||
一个社区,即使是一个正在开发的自由软件,也很难适应新技术或新工具。在类似 GNOME 的情况下,这尤其困难,该项目[最近已经 22 岁了] [8]。像 GNOME 这样经过了 20 多年建设的项目,太多的人和组织使用了太多的部件,但迁移工作之所以能实现,这要归功于 GNOME 社区的辛勤工作和 GitLab 的慷慨帮助。
|
||||
|
||||
在为使用 Git 进行版本控制的项目工作时,我发现很方便。这是一个令人感觉舒适和熟悉的系统,是一个在工作场所和爱好项目之间保持一致的工具。作为 GNOME 社区的新成员,能够参与并使用 GitLab 真是太好了。作为社区建设者,看到这样结果是令人鼓舞的:越来越多的相关项目加入并进入生态系统;新的贡献者和社区成员对该项目做出了首次贡献;以及增强了衡量我们正在做的工作以了解其成功和成功的能力。
|
||||
|
||||
如此多的做着完全不同的事情(例如他们正在从事的不同工作以及所使用的不同技能)的团队同意汇集在一个工具上(尤其是被认为是跨开源的标准工具),这一点很棒。作为 GNOME 的贡献者,我真的非常感谢我们使用了 GitLab。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/how-gnome-uses-git
|
||||
|
||||
作者:[Molly de Blanc][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mollydb
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/redpanda_firefox_pet_animal.jpg?itok=aSpKsyna (red panda)
|
||||
[2]: https://www.gnome.org/foundation/
|
||||
[3]: https://gnome.org/
|
||||
[4]: https://www.gtk.org/
|
||||
[5]: https://gstreamer.freedesktop.org/
|
||||
[6]: https://gitlab.gnome.org/
|
||||
[7]: https://twitter.com/csoriano1618?lang=en
|
||||
[8]: https://opensource.com/article/19/8/poll-favorite-gnome-version
|
@ -0,0 +1,62 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (alim0x)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11831-1.html)
|
||||
[#]: subject: (My Linux story: Learning Linux in the 90s)
|
||||
[#]: via: (https://opensource.com/article/19/11/learning-linux-90s)
|
||||
[#]: author: (Mike Harris https://opensource.com/users/mharris)
|
||||
|
||||
我的 Linux 故事:在 90 年代学习 Linux
|
||||
======
|
||||
|
||||
> 这是一个关于我如何在 WiFi 时代之前学习 Linux 的故事,那时的发行版还以 CD 的形式出现。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/29/213829t00wmwu2w0z502zg.jpg)
|
||||
|
||||
大部分人可能不记得 1996 年时计算产业或日常生活世界的样子。但我很清楚地记得那一年。我那时候是堪萨斯中部一所高中的二年级学生,那是我的自由与开源软件(FOSS)旅程的开端。
|
||||
|
||||
我从这里开始进步。我在 1996 年之前就开始对计算机感兴趣。我在我家的第一台 Apple ][e 上启蒙成长,然后多年之后是 IBM Personal System/2。(是的,在这过程中有一些代际的跨越。)IBM PS/2 有一个非常激动人心的特性:一个 1200 波特的 Hayes 调制解调器。
|
||||
|
||||
我不记得是怎样了,但在那不久之前,我得到了一个本地 [BBS][2] 的电话号码。一旦我拨号进去,我可以得到本地的一些其他 BBS 的列表,我的网络探险就此开始了。
|
||||
|
||||
在 1995 年,[足够幸运][3]的人拥有了家庭互联网连接,每月可以使用不到 30 分钟。那时的互联网不像我们现代的服务那样,通过卫星、光纤、有线电视同轴电缆或任何版本的铜线提供。大多数家庭通过一个调制解调器拨号,它连接到他们的电话线上。(这时离移动电话无处不在的时代还早得很,大多数人只有一部家庭电话。)尽管这还要取决你所在的位置,但我不认为那时有很多独立的互联网服务提供商(ISP),所以大多数人从仅有的几家大公司获得服务,包括 America Online,CompuServe 以及 Prodigy。
|
||||
|
||||
你能获取到的服务速率非常低,甚至在拨号上网革命性地达到了顶峰的 56K,你也只能期望得到最高 3.5Kbps 的速率。如果你想要尝试 Linux,下载一个 200MB 到 800MB 的 ISO 镜像或(更加切合实际的)一套软盘镜像要贡献出时间、决心,以及减少电话的使用。
|
||||
|
||||
我走了一条简单一点的路:在 1996 年,我从一家主要的 Linux 发行商订购了一套 “tri-Linux” CD 集。这些光盘提供了三个发行版,我的这套包含了 Debian 1.1(Debian 的第一个稳定版本)、Red Hat Linux 3.0.3 以及 Slackware 3.1(代号 Slackware '96)。据我回忆,这些光盘是从一家叫做 [Linux Systems Labs][4] 的在线商店购买的。这家在线商店如今已经不存在了,但在 90 年代和 00 年代早期,这样的发行商很常见。这些是多光盘 Linux 套件。这是 1998 年的一套光盘,你可以了解到他们都包含了什么:
|
||||
|
||||
![A tri-linux CD set][5]
|
||||
|
||||
![A tri-linux CD set][6]
|
||||
|
||||
在 1996 年夏天一个命中注定般的日子,那时我住在堪萨斯一个新的并且相对较为乡村的城市,我做出了安装并使用 Linux 的第一次尝试。在 1996 年的整个夏天,我尝试了那套三张 Linux CD 套件里的全部三个发行版。他们都在我母亲的老 Pentium 75MHz 电脑上完美运行。
|
||||
|
||||
我最终选择了 [Slackware][7] 3.1 作为我的首选发行版,相比其它发行版可能更多的是因为它的终端的外观,这是决定选择一个发行版前需要考虑的重要因素。
|
||||
|
||||
我将系统设置完毕并运行了起来。我连接到一家 “不太知名的” ISP(一家这个区域的本地服务商),通过我家的第二条电话线拨号(为了满足我的所有互联网使用而订购)。那就像在天堂一样。我有一台完美运行的双系统(Microsoft Windows 95 和 Slackware 3.1)电脑。我依然拨号进入我所知道和喜爱的 BBS,游玩在线 BBS 游戏,比如 Trade Wars、Usurper 以及 Legend of the Red Dragon。
|
||||
|
||||
我能够记得在 EFNet(IRC)上 #Linux 频道上渡过的日子,帮助其他用户,回答他们的 Linux 问题以及和版主们互动。
|
||||
|
||||
在我第一次在家尝试使用 Linux 系统的 20 多年后,已经是我进入作为 Red Hat 顾问的第五年,我仍然在使用 Linux(现在是 Fedora)作为我的日常系统,并且依然在 IRC 上帮助想要使用 Linux 的人们。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/learning-linux-90s
|
||||
|
||||
作者:[Mike Harris][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/mharris
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bus-cloud.png?itok=vz0PIDDS (Sky with clouds and grass)
|
||||
[2]: https://en.wikipedia.org/wiki/Bulletin_board_system
|
||||
[3]: https://en.wikipedia.org/wiki/Global_Internet_usage#Internet_users
|
||||
[4]: https://web.archive.org/web/19961221003003/http://lsl.com/
|
||||
[5]: https://opensource.com/sites/default/files/20191026_142009.jpg (A tri-linux CD set)
|
||||
[6]: https://opensource.com/sites/default/files/20191026_142020.jpg (A tri-linux CD set)
|
||||
[7]: http://slackware.com
|
@ -1,34 +1,33 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (cycoe)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11790-1.html)
|
||||
[#]: subject: (Add jumping to your Python platformer game)
|
||||
[#]: via: (https://opensource.com/article/19/12/jumping-python-platformer-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
为你的 Python 平台类游戏添加跳跃功能
|
||||
======
|
||||
在本期使用 Python Pygame 模块编写视频游戏中,学会如何使用跳跃来对抗重力。
|
||||
![游戏厅中的游戏][1]
|
||||
|
||||
> 在本期使用 Python Pygame 模块编写视频游戏中,学会如何使用跳跃来对抗重力。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/16/214917c8mxn82fot82fx88.jpg)
|
||||
|
||||
在本系列的 [前一篇文章][2] 中,你已经模拟了重力。但现在,你需要赋予你的角色跳跃的能力来对抗重力。
|
||||
|
||||
跳跃是对重力作用的暂时延缓。在这一小段时间里,你是向_上_跳,而不是被重力拉着向下落。但你一旦到达了跳跃的最高点,重力就会重新发挥作用,将你拉回地面。
|
||||
跳跃是对重力作用的暂时延缓。在这一小段时间里,你是向*上*跳,而不是被重力拉着向下落。但你一旦到达了跳跃的最高点,重力就会重新发挥作用,将你拉回地面。
|
||||
|
||||
在代码中,跳跃被表示为变量。首先,你需要为玩家对象建立一个变量,使得 Python 能够跟踪对象是否正在跳跃中。一旦玩家对象开始跳跃,他就会再次受到重力的作用,并被拉回最近的物体。
|
||||
在代码中,这种变化被表示为变量。首先,你需要为玩家精灵建立一个变量,使得 Python 能够跟踪该精灵是否正在跳跃中。一旦玩家精灵开始跳跃,他就会再次受到重力的作用,并被拉回最近的物体。
|
||||
|
||||
### 设置跳跃状态变量
|
||||
|
||||
你需要为你的 Player 类添加两个新变量:
|
||||
你需要为你的 `Player` 类添加两个新变量:
|
||||
|
||||
* 一个是为了跟踪你的角色是否正在跳跃中,可通过你的玩家对象是否站在坚实的地面来确定
|
||||
* 一个是为了跟踪你的角色是否正在跳跃中,可通过你的玩家精灵是否站在坚实的地面来确定
|
||||
* 一个是为了将玩家带回地面
|
||||
|
||||
|
||||
|
||||
将如下两个变量添加到你的 **Player** 类中。在下方的代码中,注释前的部分用于提示上下文,因此只需要添加最后两行:
|
||||
|
||||
将如下两个变量添加到你的 `Player` 类中。在下方的代码中,注释前的部分用于提示上下文,因此只需要添加最后两行:
|
||||
|
||||
```
|
||||
self.movex = 0
|
||||
@ -40,16 +39,15 @@
|
||||
self.jump_delta = 6
|
||||
```
|
||||
|
||||
第一个变量 **collide_delta** 被设为 0 是因为在正常状态下,玩家对象没有处在跳跃中的状态。另一个变量 **jump_delta** 被设为 6,是为了防止对象在第一次进入游戏世界时就发生反弹(实际上就是跳跃)。当你完成了本篇文章的示例,尝试把该变量设为 0 看看会发生什么。
|
||||
第一个变量 `collide_delta` 被设为 0 是因为在正常状态下,玩家精灵没有处在跳跃中的状态。另一个变量 `jump_delta` 被设为 6,是为了防止精灵在第一次进入游戏世界时就发生反弹(实际上就是跳跃)。当你完成了本篇文章的示例,尝试把该变量设为 0 看看会发生什么。
|
||||
|
||||
### 跳跃中的碰撞
|
||||
|
||||
如果你是跳到一个蹦床上,那你的跳跃一定非常优美。但是如果你是跳向一面墙会发生什么呢?(千万不要去尝试!)不管你的起跳多么令人印象深刻,当你撞到比你更大更硬的物体时,你都会立马停下。(译注:原理参考动量守恒定律)
|
||||
如果你是跳到一个蹦床上,那你的跳跃一定非常优美。但是如果你是跳向一面墙会发生什么呢?(千万不要去尝试!)不管你的起跳多么令人印象深刻,当你撞到比你更大更硬的物体时,你都会立马停下。(LCTT 译注:原理参考动量守恒定律)
|
||||
|
||||
为了在你的视频游戏中模拟这一点,你需要在你的玩家对象与地面等东西发生碰撞时,将 **self.collide_delta** 变量设为 0。如果你的 **self.collide_delta** 不是 0 而是其它的什么值,那么你的玩家就会发生跳跃,并且当你的玩家与墙或者地面发生碰撞时无法跳跃。
|
||||
|
||||
在你的 **Player** 类的 **update** 方法中,将地面碰撞相关代码块修改为如下所示:
|
||||
为了在你的视频游戏中模拟这一点,你需要在你的玩家精灵与地面等东西发生碰撞时,将 `self.collide_delta` 变量设为 0。如果你的 `self.collide_delta` 不是 0 而是其它的什么值,那么你的玩家就会发生跳跃,并且当你的玩家与墙或者地面发生碰撞时无法跳跃。
|
||||
|
||||
在你的 `Player` 类的 `update` 方法中,将地面碰撞相关代码块修改为如下所示:
|
||||
|
||||
```
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
@ -57,42 +55,40 @@
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty-ty
|
||||
self.collide_delta = 0 # 停止跳跃
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
```
|
||||
|
||||
这段代码块检查了地面对象和玩家对象之间发生的碰撞。当发生碰撞时,它会将玩家 Y 方向的坐标值设置为游戏窗口的高度减去一个瓷贴的高度再减去另一个瓷贴的高度。以此保证了玩家对象是站在地面**上**,而不是嵌在地面里。同时它也将 **self.collide_delta** 设为 0,使得程序能够知道玩家未处在跳跃中。除此之外,它将 **self.movey** 设为 0,使得程序能够知道玩家当前未受到重力的牵引作用(这是游戏物理引擎的奇怪之处,一旦玩家落地,也就没有必要继续将玩家拉向地面)。
|
||||
这段代码块检查了地面精灵和玩家精灵之间发生的碰撞。当发生碰撞时,它会将玩家 Y 方向的坐标值设置为游戏窗口的高度减去一个瓷砖的高度再减去另一个瓷砖的高度。以此保证了玩家精灵是站在地面*上*,而不是嵌在地面里。同时它也将 `self.collide_delta` 设为 0,使得程序能够知道玩家未处在跳跃中。除此之外,它将 `self.movey` 设为 0,使得程序能够知道玩家当前未受到重力的牵引作用(这是游戏物理引擎的奇怪之处,一旦玩家落地,也就没有必要继续将玩家拉向地面)。
|
||||
|
||||
此处 **if** 语句用来检测玩家是否已经落到地面之_下_,如果是,那就扣除一点生命值作为惩罚。此处假定了你希望当你的玩家落到地图之外时失去生命值。这个设定不是必需的,它只是平台类游戏的一种惯例。更有可能的是,你希望这个事件能够触发另一些事件,或者说是一种能够让你的现实世界玩家沉迷于让对象掉到屏幕之外的东西。一种简单的恢复方式是在玩家对象掉落到地图之外时,将 **self.rect.y** 重新设置为 0,这样它就会在地图上方重新生成,并落到坚实的地面上。
|
||||
此处 `if` 语句用来检测玩家是否已经落到地面之*下*,如果是,那就扣除一点生命值作为惩罚。此处假定了你希望当你的玩家落到地图之外时失去生命值。这个设定不是必需的,它只是平台类游戏的一种惯例。更有可能的是,你希望这个事件能够触发另一些事件,或者说是一种能够让你的现实世界玩家沉迷于让精灵掉到屏幕之外的东西。一种简单的恢复方式是在玩家精灵掉落到地图之外时,将 `self.rect.y` 重新设置为 0,这样它就会在地图上方重新生成,并落到坚实的地面上。
|
||||
|
||||
### 撞向地面
|
||||
|
||||
模拟的重力使你玩家的 Y 坐标不断增大(译注:此处原文中为 0,但在 Pygame 中越靠下方 Y 坐标应越大)。要实现跳跃,完成如下代码使你的玩家对象离开地面,飞向空中。
|
||||
|
||||
在你的 **Player** 类的 **update** 方法中,添加如下代码来暂时延缓重力的作用:
|
||||
模拟的重力使你玩家的 Y 坐标不断增大(LCTT 译注:此处原文中为 0,但在 Pygame 中越靠下方 Y 坐标应越大)。要实现跳跃,完成如下代码使你的玩家精灵离开地面,飞向空中。
|
||||
|
||||
在你的 `Player` 类的 `update` 方法中,添加如下代码来暂时延缓重力的作用:
|
||||
|
||||
```
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
self.jump_delta = 6*2
|
||||
self.movey -= 33 # 跳跃的高度
|
||||
self.collide_delta += 6
|
||||
self.jump_delta += 6
|
||||
```
|
||||
|
||||
根据此代码所示,跳跃使玩家对象向空中移动了 33 个像素。此处是_负_ 33 是因为在 Pygame 中,越小的数代表距离屏幕顶端越近。
|
||||
根据此代码所示,跳跃使玩家精灵向空中移动了 33 个像素。此处是*负* 33 是因为在 Pygame 中,越小的数代表距离屏幕顶端越近。
|
||||
|
||||
不过此事件视条件而定,只有当 **self.collide_delta** 小于 6(缺省值定义在你 **Player** 类的 **init** 方法中)并且 **self.jump_delta** 也于 6 的时候才会发生。此条件能够保证直到玩家碰到一个平台,才能触发另一次跳跃。换言之,它能够阻止空中二段跳。
|
||||
不过此事件视条件而定,只有当 `self.collide_delta` 小于 6(缺省值定义在你 `Player` 类的 `init` 方法中)并且 `self.jump_delta` 也于 6 的时候才会发生。此条件能够保证直到玩家碰到一个平台,才能触发另一次跳跃。换言之,它能够阻止空中二段跳。
|
||||
|
||||
在某些特殊条件下,你可能不想阻止空中二段跳,或者说你允许玩家进行空中二段跳。举个栗子,如果玩家获得了某个战利品,那么在他被敌人攻击到之前,都能够拥有空中二段跳的能力。
|
||||
|
||||
当你完成本篇文章中的示例,尝试将 **self.collide_delta** 和 **self.jump_delta** 设置为 0,从而获得百分之百的几率触发空中二段跳。
|
||||
当你完成本篇文章中的示例,尝试将 `self.collide_delta` 和 `self.jump_delta` 设置为 0,从而获得百分之百的几率触发空中二段跳。
|
||||
|
||||
### 在平台上着陆
|
||||
|
||||
目前你已经定义了再玩家对象摔落地面时的抵抗重力条件,但此时你的游戏代码仍保持平台与地面置于不同的列表中(就像本文中做的很多其他选择一样,这个设定并不是必需的,你可以尝试将地面作为另一种平台)。为了允许玩家对象站在平台之上,你必须像检测地面碰撞一样,检测玩家对象与平台对象之间的碰撞。将如下代码放于你的 **update** 方法中:
|
||||
|
||||
目前你已经定义了在玩家精灵摔落地面时的抵抗重力条件,但此时你的游戏代码仍保持平台与地面置于不同的列表中(就像本文中做的很多其他选择一样,这个设定并不是必需的,你可以尝试将地面作为另一种平台)。为了允许玩家精灵站在平台之上,你必须像检测地面碰撞一样,检测玩家精灵与平台精灵之间的碰撞。将如下代码放于你的 `update` 方法中:
|
||||
|
||||
```
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
@ -103,27 +99,26 @@
|
||||
|
||||
但此处还有一点需要考虑:平台悬在空中,也就意味着玩家可以通过从上面或者从下面接触平台来与之互动。
|
||||
|
||||
确定平台如何与玩家互动取决于你,阻止玩家从下方到达平台也并不稀奇。将如下代码加到上方的代码块中,使得平台表现得像天花板或者说是藤架。只有在玩家对象跳得比平台上沿更高时才能跳到平台上,但会阻止玩家从平台下方跳上来:
|
||||
|
||||
确定平台如何与玩家互动取决于你,阻止玩家从下方到达平台也并不稀奇。将如下代码加到上方的代码块中,使得平台表现得像天花板或者说是藤架。只有在玩家精灵跳得比平台上沿更高时才能跳到平台上,但会阻止玩家从平台下方跳上来:
|
||||
|
||||
```
|
||||
if self.rect.y > p.rect.y:
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
```
|
||||
|
||||
此处 **if** 语句代码块的第一个子句阻止玩家对象从平台正下方跳到平台上。如果它检测到玩家对象的坐标比平台更大(在 Pygame 中,坐标更大意味着在屏幕的更下方),那么将玩家对象新的 Y 坐标设置为当前平台的 Y 坐标加上一个瓷贴的高度。实际效果就是保证玩家对象距离平台一个瓷贴的高度,防止其从下方穿过平台。
|
||||
此处 `if` 语句代码块的第一个子句阻止玩家精灵从平台正下方跳到平台上。如果它检测到玩家精灵的坐标比平台更大(在 Pygame 中,坐标更大意味着在屏幕的更下方),那么将玩家精灵新的 Y 坐标设置为当前平台的 Y 坐标加上一个瓷砖的高度。实际效果就是保证玩家精灵距离平台一个瓷砖的高度,防止其从下方穿过平台。
|
||||
|
||||
**else** 子句做了相反的事情。当程序运行到此处时,如果玩家对象的 Y 坐标_不_比平台的更大,意味着玩家对象是从空中落下(不论是由于玩家刚刚从此处生成,或者是玩家执行了跳跃)。在这种情况下,玩家对象的 Y 坐标被设为平台的 Y 坐标减去一个瓷贴的高度(切记,在 Pygame 中更小的 Y 坐标代表在屏幕上的更高处)。这样就能保证玩家在平台_上_,除非他从平台上跳下来或者走下来。
|
||||
`else` 子句做了相反的事情。当程序运行到此处时,如果玩家精灵的 Y 坐标*不*比平台的更大,意味着玩家精灵是从空中落下(不论是由于玩家刚刚从此处生成,或者是玩家执行了跳跃)。在这种情况下,玩家精灵的 Y 坐标被设为平台的 Y 坐标减去一个瓷砖的高度(切记,在 Pygame 中更小的 Y 坐标代表在屏幕上的更高处)。这样就能保证玩家在平台*上*,除非他从平台上跳下来或者走下来。
|
||||
|
||||
你也可以尝试其他的方式来处理玩家与平台之间的互动。举个栗子,也许玩家对象被设定为处在平台的“前面”,他能够无障碍地跳跃穿过平台并站在上面。或者你可以设计一种平台会减缓而又不完全阻止玩家的跳跃过程。甚至你可以通过将不同平台分到不同列表中来混合搭配使用。
|
||||
你也可以尝试其他的方式来处理玩家与平台之间的互动。举个栗子,也许玩家精灵被设定为处在平台的“前面”,他能够无障碍地跳跃穿过平台并站在上面。或者你可以设计一种平台会减缓而又不完全阻止玩家的跳跃过程。甚至你可以通过将不同平台分到不同列表中来混合搭配使用。
|
||||
|
||||
### 触发一次跳跃
|
||||
|
||||
目前为此,你的代码已经模拟了所有必需的跳跃条件,但仍缺少一个跳跃触发器。你的玩家对象的 **self.jump_delta** 初始值被设置为 6,只有当它比 6 小时才会触发更新跳跃的代码。
|
||||
目前为此,你的代码已经模拟了所有必需的跳跃条件,但仍缺少一个跳跃触发器。你的玩家精灵的 `self.jump_delta` 初始值被设置为 6,只有当它比 6 小的时候才会触发更新跳跃的代码。
|
||||
|
||||
为跳跃变量设置一个新的设置方法,在你的 **Player** 类中创建一个 **jump** 方法,并将 **self.jump_delta** 设为小于 6 的值。通过使玩家对象向空中移动 33 个像素,来暂时减缓重力的作用。
|
||||
为跳跃变量设置一个新的设置方法,在你的 `Player` 类中创建一个 `jump` 方法,并将 `self.jump_delta` 设为小于 6 的值。通过使玩家精灵向空中移动 33 个像素,来暂时减缓重力的作用。
|
||||
|
||||
|
||||
```
|
||||
@ -131,25 +126,24 @@
|
||||
self.jump_delta = 0
|
||||
```
|
||||
|
||||
不管你相信与否,这就是 **jump** 方法的全部。剩余的部分在 **update** 方法中,你已经在前面实现了相关代码。
|
||||
不管你相信与否,这就是 `jump` 方法的全部。剩余的部分在 `update` 方法中,你已经在前面实现了相关代码。
|
||||
|
||||
要使你游戏中的跳跃功能生效,还有最后一件事情要做。如果你想不起来是什么,运行游戏并观察跳跃是如何生效的。
|
||||
|
||||
问题就在于你的主循环中没有调用 **jump** 方法。先前你已经为该方法创建了一个按键占位符,现在,跳跃键所做的就是将 **jump** 打印到终端。
|
||||
问题就在于你的主循环中没有调用 `jump` 方法。先前你已经为该方法创建了一个按键占位符,现在,跳跃键所做的就是将 `jump` 打印到终端。
|
||||
|
||||
### 调用 jump 方法
|
||||
|
||||
在你的主循环中,将_上_方向键的效果从打印一条调试语句,改为调用 **jump** 方法。
|
||||
|
||||
注意此处,与 **update** 方法类似,**jump** 方法也需要检测碰撞,因此你需要告诉它使用哪个 **plat_list**。
|
||||
在你的主循环中,将*上*方向键的效果从打印一条调试语句,改为调用 `jump` 方法。
|
||||
|
||||
注意此处,与 `update` 方法类似,`jump` 方法也需要检测碰撞,因此你需要告诉它使用哪个 `plat_list`。
|
||||
|
||||
```
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(plat_list)
|
||||
```
|
||||
|
||||
如果你倾向于使用空格键作为跳跃键,使用 **pygame.K_SPACE** 替代 **pygame.K_UP** 作为按键。另一种选择,你可以同时使用两种方式(使用单独的 **if** 语句),给玩家多一种选择。
|
||||
如果你倾向于使用空格键作为跳跃键,使用 `pygame.K_SPACE` 替代 `pygame.K_UP` 作为按键。另一种选择,你可以同时使用两种方式(使用单独的 `if` 语句),给玩家多一种选择。
|
||||
|
||||
现在来尝试你的游戏吧!在下一篇文章中,你将让你的游戏卷动起来。
|
||||
|
||||
@ -157,7 +151,6 @@
|
||||
|
||||
以下是目前为止的所有代码:
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# draw a world
|
||||
@ -220,7 +213,7 @@ class Player(pygame.sprite.Sprite):
|
||||
def gravity(self):
|
||||
self.movey += 3.2 # how fast player falls
|
||||
|
||||
if self.rect.y > worldy and self.movey >= 0:
|
||||
if self.rect.y > worldy and self.movey >= 0:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty
|
||||
|
||||
@ -233,23 +226,23 @@ class Player(pygame.sprite.Sprite):
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
更新对象位置
|
||||
更新精灵位置
|
||||
'''
|
||||
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
|
||||
# 向左移动
|
||||
if self.movex < 0:
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# 向右移动
|
||||
if self.movex > 0:
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
|
||||
@ -263,7 +256,7 @@ class Player(pygame.sprite.Sprite):
|
||||
for p in plat_hit_list:
|
||||
self.collide_delta = 0 # stop jumping
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
@ -273,11 +266,11 @@ class Player(pygame.sprite.Sprite):
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty-ty
|
||||
self.collide_delta = 0 # stop jumping
|
||||
if self.rect.y > g.rect.y:
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
self.jump_delta = 6*2
|
||||
self.movey -= 33 # how high to jump
|
||||
self.collide_delta += 6
|
||||
@ -308,22 +301,22 @@ class Enemy(pygame.sprite.Sprite):
|
||||
|
||||
self.movey += 3.2
|
||||
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
self.rect.x += speed
|
||||
elif self.counter >= distance and self.counter <= distance*2:
|
||||
elif self.counter >= distance and self.counter <= distance*2:
|
||||
self.rect.x -= speed
|
||||
else:
|
||||
self.counter = 0
|
||||
|
||||
self.counter += 1
|
||||
|
||||
if not self.rect.y >= worldy-ty-ty:
|
||||
if not self.rect.y >= worldy-ty-ty:
|
||||
self.rect.y += self.movey
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
@ -352,7 +345,7 @@ class Level():
|
||||
ground_list = pygame.sprite.Group()
|
||||
i=0
|
||||
if lvl == 1:
|
||||
while i < len(gloc):
|
||||
while i < len(gloc):
|
||||
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
|
||||
ground_list.add(ground)
|
||||
i=i+1
|
||||
@ -371,9 +364,9 @@ class Level():
|
||||
ploc.append((300,worldy-ty-256,3))
|
||||
ploc.append((500,worldy-ty-128,4))
|
||||
|
||||
while i < len(ploc):
|
||||
while i < len(ploc):
|
||||
j=0
|
||||
while j <= ploc[i][2]:
|
||||
while j <= ploc[i][2]:
|
||||
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
|
||||
plat_list.add(plat)
|
||||
j=j+1
|
||||
@ -417,11 +410,11 @@ eloc = []
|
||||
eloc = [200,20]
|
||||
gloc = []
|
||||
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
|
||||
tx = 64 # 瓷贴尺寸
|
||||
ty = 64 # 瓷贴尺寸
|
||||
tx = 64 # 瓷砖尺寸
|
||||
ty = 64 # 瓷砖尺寸
|
||||
|
||||
i=0
|
||||
while i <= (worldx/tx)+tx:
|
||||
while i <= (worldx/tx)+tx:
|
||||
gloc.append(i*tx)
|
||||
i=i+1
|
||||
|
||||
@ -482,9 +475,8 @@ while main == True:
|
||||
* [如何在你的 Python 游戏中添加一个玩家][8]
|
||||
* [用 Pygame 使你的游戏角色移动起来][9]
|
||||
* [如何向你的 Python 游戏中添加一个敌人][10]
|
||||
* [在你的 Python 游戏中模拟重力][2]
|
||||
|
||||
|
||||
* [在 Pygame 游戏中放置平台][11]
|
||||
* [在你的 Python 游戏中模拟引力][2]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -493,19 +485,20 @@ via: https://opensource.com/article/19/12/jumping-python-platformer-game
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[cycoe](https://github.com/cycoe)
|
||||
校对:[校对者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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/arcade_game_gaming.jpg?itok=84Rjk_32 (Arcade games)
|
||||
[2]: https://opensource.com/article/19/11/simulate-gravity-python
|
||||
[2]: https://linux.cn/article-11780-1.html
|
||||
[3]: https://opensource.com/sites/default/files/uploads/pygame-jump.jpg (Pygame platformer)
|
||||
[4]: https://www.python.org/
|
||||
[5]: https://www.pygame.org/
|
||||
[6]: https://opensource.com/article/17/10/python-101
|
||||
[7]: https://opensource.com/article/17/12/game-framework-python
|
||||
[8]: https://opensource.com/article/17/12/game-python-add-a-player
|
||||
[9]: https://opensource.com/article/17/12/game-python-moving-player
|
||||
[10]: https://opensource.com/article/18/5/pygame-enemy
|
||||
[6]: https://linux.cn/article-9071-1.html
|
||||
[7]: https://linux.cn/article-10850-1.html
|
||||
[8]: https://linux.cn/article-10858-1.html
|
||||
[9]: https://linux.cn/article-10874-1.html
|
||||
[10]: https://linux.cn/article-10883-1.html
|
||||
[11]: https://linux.cn/article-10902-1.html
|
@ -0,0 +1,73 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11814-1.html)
|
||||
[#]: subject: (What's your favorite terminal emulator?)
|
||||
[#]: via: (https://opensource.com/article/19/12/favorite-terminal-emulator)
|
||||
[#]: author: (Opensource.com https://opensource.com/users/admin)
|
||||
|
||||
你最喜欢的终端模拟器是什么?
|
||||
======
|
||||
|
||||
> 我们让社区讲述他们在终端仿真器方面的经验。以下是我们收到的一些回复。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/24/000846qsmpz7s7spig77qg.jpg)
|
||||
|
||||
终端仿真器的偏好可以说明一个人的工作流程。无鼠标操作能力是否必须具备?你想要标签页还是窗口?对于终端仿真器你还有什么选择的原因?是否有酷的因素?欢迎参加调查或给我们留下评论,告诉我们你最喜欢的终端模拟器。你尝试过多少种终端仿真器呢?
|
||||
|
||||
我们让社区讲述他们在终端仿真器方面的经验。以下是我们收到的一些回复。
|
||||
|
||||
“我最喜欢的终端仿真器是用 Powerline 定制的 Tilix。我喜欢它支持在一个窗口中打开多个终端。” —Dan Arel
|
||||
|
||||
“[urxvt][2]。它可以通过文件简单配置,轻巧,并且在大多数程序包管理器存储库中都很容易找到。” —Brian Tomlinson
|
||||
|
||||
“即使我不再使用 GNOME,gnome-terminal 仍然是我的首选。:)” —Justin W. Flory
|
||||
|
||||
“现在 FC31 上的 Terminator。我刚刚开始使用它,我喜欢它的分屏功能,对我来说感觉很轻巧。我正在研究它的插件。” —Marc Maxwell
|
||||
|
||||
“不久前,我切换到了 Tilix,它完成了我需要终端执行的所有工作。:) 多个窗格、通知,很精简,用来运行我的 tmux 会话很棒。” —Kevin Fenzi
|
||||
|
||||
“alacritty。它针对速度进行了优化,是用 Rust 实现的,并且具有很多常规功能,但是老实说,我只关心一个功能:可配置的字形间距,使我可以进一步压缩字体。” —Alexander Sosedkin
|
||||
|
||||
“我是个老古板:KDE Konsole。如果是远程会话,请使用 tmux。” —Marcin Juszkiewicz
|
||||
|
||||
“在 macOS 上用 iTerm2。是的,它是开源的。:-) 在 Linux 上是 Terminator。” —Patrick Mullins
|
||||
|
||||
“我现在已经使用 alacritty 一两年了,但是最近我在全屏模式下使用 cool-retro-term,因为我必须运行一个输出内容有很多的脚本,而它看起来很酷,让我感觉很酷。这对我很重要。” —Nick Childers
|
||||
|
||||
“我喜欢 Tilix,部分是因为它擅长免打扰(我通常全屏运行它,里面是 tmux),而且还提供自定义热链接支持:在我的终端中,像 ‘rhbz#1234’ 之类的文本是将我带到 Bugzilla 的热链接。类似的还有 LaunchPad 提案,OpenStack 的 Gerrit 更改 ID 等。” —Lars Kellogg-Stedman
|
||||
|
||||
“Eterm,在使用 Vintage 配置文件的 cool-retro-term 中,演示效果也最好。” —Ivan Horvath
|
||||
|
||||
“Tilix +1。这是 GNOME 用户最好的选择,我是这么觉得的!” —Eric Rich
|
||||
|
||||
“urxvt。快速、小型、可配置、可通过 Perl 插件扩展,这使其可以无鼠标操作。” —Roman Dobosz
|
||||
|
||||
“Konsole 是最好的,也是 KDE 项目中我唯一使用的应用程序。所有搜索结果都高亮显示是一个杀手级功能,据我所知没有任何其它 Linux 终端有这个功能(如果能证明我错了,那我也很高兴)。最适合搜索编译错误和输出日志。” —Jan Horak
|
||||
|
||||
“我过去经常使用 Terminator。现在我在 Tilix 中克隆了它的主题(深色主题),而感受一样好。它可以在选项卡之间轻松移动。就是这样。” —Alberto Fanjul Alonso
|
||||
|
||||
“我开始使用的是 Terminator,自从差不多过去这三年,我已经完全切换到 Tilix。” —Mike Harris
|
||||
|
||||
“我使用下拉式终端 X。这是 GNOME 3 的一个非常简单的扩展,使我始终可以通过一个按键(对于我来说是`F12`)拉出一个终端。它还支持制表符,这正是我所需要的。 ” —Germán Pulido
|
||||
|
||||
“xfce4-terminal:支持 Wayland、缩放、无边框、无标题栏、无滚动条 —— 这就是我在 tmux 之外全部想要的终端仿真器的功能。我希望我的终端仿真器可以尽可能多地使用屏幕空间,我通常在 tmux 窗格中并排放着编辑器(Vim)和 repl。” —Martin Kourim
|
||||
|
||||
“别问,问就是 Fish ! ;-)” —Eric Schabell
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/favorite-terminal-emulator
|
||||
|
||||
作者:[Opensource.com][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/admin
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/osdc_terminals_0.png?itok=XwIRERsn (Terminal window with green text)
|
||||
[2]: https://opensource.com/article/19/10/why-use-rxvt-terminal
|
@ -0,0 +1,467 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11819-1.html)
|
||||
[#]: subject: (Enable your Python game player to run forward and backward)
|
||||
[#]: via: (https://opensource.com/article/19/12/python-platformer-game-run)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
使你的 Python 游戏玩家能够向前和向后跑
|
||||
======
|
||||
> 使用 Pygame 模块来使你的 Python 平台开启侧滚效果,来让你的玩家自由奔跑。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/25/220636x5mabbl47xvtsk55.jpg)
|
||||
|
||||
这是仍在进行中的关于使用 Pygame 模块来在 Python 3 中在创建电脑游戏的第九部分。先前的文章是:
|
||||
|
||||
* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][2]
|
||||
* [使用 Python 和 Pygame 模块构建一个游戏框架][3]
|
||||
* [如何在你的 Python 游戏中添加一个玩家][4]
|
||||
* [用 Pygame 使你的游戏角色移动起来][5]
|
||||
* [如何向你的 Python 游戏中添加一个敌人][6]
|
||||
* [在 Pygame 游戏中放置平台][12]
|
||||
* [在你的 Python 游戏中模拟引力][7]
|
||||
* [为你的 Python 平台类游戏添加跳跃功能][8]
|
||||
|
||||
在这一系列关于使用 [Pygame][10] 模块来在 [Python 3][9] 中创建电脑游戏的先前文章中,你已经设计了你的关卡设计布局,但是你的关卡的一些部分可能已近超出你的屏幕的可视区域。在平台类游戏中,这个问题的普遍解决方案是,像术语“<ruby>侧滚<rt>side-scroller</rt></ruby>”表明的一样,滚动。
|
||||
|
||||
滚动的关键是当玩家精灵接近屏的幕边缘时,使在玩家精灵周围的平台移动。这样给予一种错觉,屏幕是一个在游戏世界中穿梭追拍的"摄像机"。
|
||||
|
||||
这个滚动技巧需要两个在屏幕边缘的绝对区域,在绝对区域内的点处,在世界滚动期间,你的化身静止不动。
|
||||
|
||||
### 在侧滚动条中放置卷轴
|
||||
|
||||
如果你希望你的玩家能够后退,你需要一个触发点来向前和向后。这两个点仅仅是两个变量。设置它们各个距各个屏幕边缘大约 100 或 200 像素。在你的设置部分中创建变量。在下面的代码中,前两行用于上下文说明,所以仅需要添加这行后的代码:
|
||||
|
||||
```
|
||||
player_list.add(player)
|
||||
steps = 10
|
||||
forwardX = 600
|
||||
backwardX = 230
|
||||
```
|
||||
|
||||
在主循环中,查看你的玩家精灵是否在 `forwardx` 或 `backwardx` 滚动点处。如果是这样,向左或向右移动使用的平台,取决于世界是向前或向后移动。在下面的代码中,代码的最后三行仅供你参考:
|
||||
|
||||
```
|
||||
# scroll the world forward
|
||||
if player.rect.x >= forwardx:
|
||||
scroll = player.rect.x - forwardx
|
||||
player.rect.x = forwardx
|
||||
for p in plat_list:
|
||||
p.rect.x -= scroll
|
||||
|
||||
# scroll the world backward
|
||||
if player.rect.x <= backwardx:
|
||||
scroll = backwardx - player.rect.x
|
||||
player.rect.x = backwardx
|
||||
for p in plat_list:
|
||||
p.rect.x += scroll
|
||||
|
||||
## scrolling code above
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.gravity() # check gravity
|
||||
player.update()
|
||||
```
|
||||
|
||||
启动你的游戏,并尝试它。
|
||||
|
||||
![Scrolling the world in Pygame][11]
|
||||
|
||||
滚动像预期的一样工作,但是你可能注意到一个发生的小问题,当你滚动你的玩家和非玩家精灵周围的世界时:敌人精灵不随同世界滚动。除非你要你的敌人精灵要无休止地追逐你的玩家,你需要修改敌人代码,以便当你的玩家快速撤退时,敌人被留在后面。
|
||||
|
||||
### 敌人卷轴
|
||||
|
||||
在你的主循环中,你必须对卷轴平台为你的敌人的位置的应用相同的规则。因为你的游戏世界将(很可能)有不止一个敌人在其中,该规则应该被应用于你的敌人列表,而不是一个单独的敌人精灵。这是分组类似元素到列表中的优点之一。
|
||||
|
||||
前两行用于上下文注释,所以只需添加这两行后面的代码到你的主循环中:
|
||||
|
||||
```
|
||||
# scroll the world forward
|
||||
if player.rect.x >= forwardx:
|
||||
scroll = player.rect.x - forwardx
|
||||
player.rect.x = forwardx
|
||||
for p in plat_list:
|
||||
p.rect.x -= scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x -= scroll
|
||||
```
|
||||
|
||||
来滚向另一个方向:
|
||||
|
||||
```
|
||||
# scroll the world backward
|
||||
if player.rect.x <= backwardx:
|
||||
scroll = backwardx - player.rect.x
|
||||
player.rect.x = backwardx
|
||||
for p in plat_list:
|
||||
p.rect.x += scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x += scroll
|
||||
```
|
||||
|
||||
再次启动游戏,看看发生什么。
|
||||
|
||||
这里是到目前为止你已经为这个 Python 平台所写所有的代码:
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# draw a world
|
||||
# add a player and player control
|
||||
# add player movement
|
||||
# add enemy and basic collision
|
||||
# add platform
|
||||
# add gravity
|
||||
# add jumping
|
||||
# add scrolling
|
||||
|
||||
# GNU All-Permissive License
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
import pygame
|
||||
import sys
|
||||
import os
|
||||
|
||||
'''
|
||||
Objects
|
||||
'''
|
||||
|
||||
class Platform(pygame.sprite.Sprite):
|
||||
# x location, y location, img width, img height, img file
|
||||
def __init__(self,xloc,yloc,imgw,imgh,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img)).convert()
|
||||
self.image.convert_alpha()
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.y = yloc
|
||||
self.rect.x = xloc
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn a player
|
||||
'''
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.collide_delta = 0
|
||||
self.jump_delta = 6
|
||||
self.score = 1
|
||||
self.images = []
|
||||
for i in range(1,9):
|
||||
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def jump(self,platform_list):
|
||||
self.jump_delta = 0
|
||||
|
||||
def gravity(self):
|
||||
self.movey += 3.2 # how fast player falls
|
||||
|
||||
if self.rect.y > worldy and self.movey >= 0:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty
|
||||
|
||||
def control(self,x,y):
|
||||
'''
|
||||
control player movement
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
Update sprite position
|
||||
'''
|
||||
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
|
||||
# moving left
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# moving right
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
|
||||
# collisions
|
||||
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
|
||||
for enemy in enemy_hit_list:
|
||||
self.health -= 1
|
||||
#print(self.health)
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.collide_delta = 0 # stop jumping
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty-ty
|
||||
self.collide_delta = 0 # stop jumping
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
self.jump_delta = 6*2
|
||||
self.movey -= 33 # how high to jump
|
||||
self.collide_delta += 6
|
||||
self.jump_delta += 6
|
||||
|
||||
class Enemy(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn an enemy
|
||||
'''
|
||||
def __init__(self,x,y,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img))
|
||||
self.movey = 0
|
||||
#self.image.convert_alpha()
|
||||
#self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.counter = 0
|
||||
|
||||
|
||||
def move(self):
|
||||
'''
|
||||
enemy movement
|
||||
'''
|
||||
distance = 80
|
||||
speed = 8
|
||||
|
||||
self.movey += 3.2
|
||||
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
self.rect.x += speed
|
||||
elif self.counter >= distance and self.counter <= distance*2:
|
||||
self.rect.x -= speed
|
||||
else:
|
||||
self.counter = 0
|
||||
|
||||
self.counter += 1
|
||||
|
||||
if not self.rect.y >= worldy-ty-ty:
|
||||
self.rect.y += self.movey
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.rect.y = worldy-ty-ty
|
||||
|
||||
|
||||
class Level():
|
||||
def bad(lvl,eloc):
|
||||
if lvl == 1:
|
||||
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
|
||||
enemy_list = pygame.sprite.Group() # create enemy group
|
||||
enemy_list.add(enemy) # add enemy to group
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return enemy_list
|
||||
|
||||
def loot(lvl,lloc):
|
||||
print(lvl)
|
||||
|
||||
def ground(lvl,gloc,tx,ty):
|
||||
ground_list = pygame.sprite.Group()
|
||||
i=0
|
||||
if lvl == 1:
|
||||
while i < len(gloc):
|
||||
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
|
||||
ground_list.add(ground)
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return ground_list
|
||||
|
||||
def platform(lvl,tx,ty):
|
||||
plat_list = pygame.sprite.Group()
|
||||
ploc = []
|
||||
i=0
|
||||
if lvl == 1:
|
||||
ploc.append((0,worldy-ty-128,3))
|
||||
ploc.append((300,worldy-ty-256,3))
|
||||
ploc.append((500,worldy-ty-128,4))
|
||||
|
||||
while i < len(ploc):
|
||||
j=0
|
||||
while j <= ploc[i][2]:
|
||||
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
|
||||
plat_list.add(plat)
|
||||
j=j+1
|
||||
print('run' + str(i) + str(ploc[i]))
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return plat_list
|
||||
|
||||
'''
|
||||
Setup
|
||||
'''
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
|
||||
fps = 40 # frame rate
|
||||
ani = 4 # animation cycles
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
main = True
|
||||
|
||||
BLUE = (25,25,200)
|
||||
BLACK = (23,23,23 )
|
||||
WHITE = (254,254,254)
|
||||
ALPHA = (0,255,0)
|
||||
|
||||
world = pygame.display.set_mode([worldx,worldy])
|
||||
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
|
||||
backdropbox = world.get_rect()
|
||||
player = Player() # spawn player
|
||||
player.rect.x = 0
|
||||
player.rect.y = 0
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10
|
||||
forwardx = 600
|
||||
backwardx = 230
|
||||
|
||||
eloc = []
|
||||
eloc = [200,20]
|
||||
gloc = []
|
||||
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
|
||||
tx = 64 #tile size
|
||||
ty = 64 #tile size
|
||||
|
||||
i=0
|
||||
while i <= (worldx/tx)+tx:
|
||||
gloc.append(i*tx)
|
||||
i=i+1
|
||||
|
||||
enemy_list = Level.bad( 1, eloc )
|
||||
ground_list = Level.ground( 1,gloc,tx,ty )
|
||||
plat_list = Level.platform( 1,tx,ty )
|
||||
|
||||
'''
|
||||
Main loop
|
||||
'''
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print("LEFT")
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print("RIGHT")
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(plat_list)
|
||||
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
|
||||
# scroll the world forward
|
||||
if player.rect.x >= forwardx:
|
||||
scroll = player.rect.x - forwardx
|
||||
player.rect.x = forwardx
|
||||
for p in plat_list:
|
||||
p.rect.x -= scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x -= scroll
|
||||
|
||||
# scroll the world backward
|
||||
if player.rect.x <= backwardx:
|
||||
scroll = backwardx - player.rect.x
|
||||
player.rect.x = backwardx
|
||||
for p in plat_list:
|
||||
p.rect.x += scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x += scroll
|
||||
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.gravity() # check gravity
|
||||
player.update()
|
||||
player_list.draw(world) #refresh player position
|
||||
enemy_list.draw(world) # refresh enemies
|
||||
ground_list.draw(world) # refresh enemies
|
||||
plat_list.draw(world) # refresh platforms
|
||||
for e in enemy_list:
|
||||
e.move()
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/python-platformer-game-run
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/open_gaming_games_roundup_news.png?itok=KM0ViL0f (Gaming artifacts with joystick, GameBoy, paddle)
|
||||
[2]: https://linux.cn/article-9071-1.html
|
||||
[3]: https://linux.cn/article-10850-1.html
|
||||
[4]: https://linux.cn/article-10858-1.html
|
||||
[5]: https://linux.cn/article-10874-1.html
|
||||
[6]: https://linux.cn/article-10883-1.html
|
||||
[7]: https://linux.cn/article-11780-1.html
|
||||
[8]: https://linux.cn/article-11790-1.html
|
||||
[9]: https://www.python.org/
|
||||
[10]: https://www.pygame.org/news
|
||||
[11]: https://opensource.com/sites/default/files/uploads/pygame-scroll.jpg (Scrolling the world in Pygame)
|
||||
[12]:https://linux.cn/article-10902-1.html
|
@ -0,0 +1,139 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11799-1.html)
|
||||
[#]: subject: (How to Add Border Around Text in GIMP)
|
||||
[#]: via: (https://itsfoss.com/gimp-text-outline/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
在 GIMP 中如何在文本周围添加边框
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/19/230506fzkyktqglfcyzkuh.jpg)
|
||||
|
||||
这个简单的教程介绍了在 [GIMP][1] 中显示文本的轮廓的步骤。文本轮廓可以帮助你在其它颜色下高亮显示该文本。
|
||||
|
||||
![Outlined Text created in GIMP][2]
|
||||
|
||||
让我们看看如何在你的文本周围添加一个边框。
|
||||
|
||||
### 在 GIMP 中添加文本轮廓
|
||||
|
||||
整个过程可以用这些简单的步骤描述:
|
||||
|
||||
* 创建文本,并复制它的轮廓路径
|
||||
* 添加一层新的透明层,并添加轮廓路径到透明层中
|
||||
* 更改轮廓的大小,给它添加一种不同的颜色
|
||||
|
||||
这就是全部的东西。不用担心,我将使用适当地截图详细的展示每个步骤。按照这个教程,你应该能够为文本添加轮廓,即使你在此之前从未使用过 GIMP 。
|
||||
|
||||
仅需要确保你已经 [在 Linux 上安装 GIMP][3],或者也可以使用的其它任何操作系统。
|
||||
|
||||
这篇教程在 GIMP 2.10 版本下演示。
|
||||
|
||||
#### 步骤 1: 创建你的主要文本,并复制它的轮廓
|
||||
|
||||
打开 GIMP ,并通过转到 “菜单 -> 文件 -> 新建” 来创建一个新的文件。你应该可以使用 `Ctrl+N` 键盘快捷键。
|
||||
|
||||
![Create New File][4]
|
||||
|
||||
你可以在这里选择画布的大小。你也可以选择要白色背景或一种透明背景。它在 “高级选项 -> 颜色” 配置文件下。
|
||||
|
||||
我选择默认的白色背景。它在以后能够更改。
|
||||
|
||||
现在从左边栏的工具箱中选择文本工具。
|
||||
|
||||
![Adding text in GIMP][5]
|
||||
|
||||
写你想要的文本。你可以根据你的选择以更改文本的字体、大小和对齐方式。我保持这篇文章的文本的默认左对齐。
|
||||
|
||||
我故意为文本选择一种浅色,以便难于阅读。在这篇教程中我将添加一个深色轮廓到这个浅色的文本。
|
||||
|
||||
![Text added in GIMP][6]
|
||||
|
||||
当你写完文本后,右键文本框并选择 “文本的路径” 。
|
||||
|
||||
![Right click on the text box and select ‘Path from Text’][7]
|
||||
|
||||
#### 步骤 2: 添加一个带有文本轮廓的透明层
|
||||
|
||||
现在,转到顶部菜单,转到“层”,并添加一个新层。
|
||||
|
||||
![Use Shift+Ctrl+N to add a new layer][8]
|
||||
|
||||
确保添加新层为透明的。你可以给它一个合适的名称,像“文本大纲”。单击确定来添加这个透明层。
|
||||
|
||||
![Add a transparent layer][9]
|
||||
|
||||
再次转到菜单,这次转到 “选择” ,并单击 “来自路径” 。你将看到你的文本应该被高亮显示。
|
||||
|
||||
![Go to Select and choose From Path][10]
|
||||
|
||||
总的来说,你只创建了一个透明层,它有像你的原文一样相同的文本(但是透明)。现在你需要做的是在这个层上增加文本的大小。
|
||||
|
||||
#### 步骤 3: 通过增加它的大小和更改它的颜色来添加文本轮廓
|
||||
|
||||
为此,再次在菜单中转到 “选择” ,这次选择 “增加”。这将允许增大透明层上的文本的大小。
|
||||
|
||||
![Grow the selection on the additional layer][11]
|
||||
|
||||
以 5 或 10 像素增加,或者你喜欢的任意像素。
|
||||
|
||||
![Grow it by 5 or 10 pixel][12]
|
||||
|
||||
你选择需要做是使用一种你选择的颜色来填充这个扩大的选择区。因为我的原文是浅色,在这里我将为轮廓使用背景色。
|
||||
|
||||
如果尚未选择的话,先选择你的主图像层。这些层在右侧栏中可视。然后转到工具箱并选择油漆桶工具。为你的轮廓选择想要的颜色。
|
||||
|
||||
选择使用该工具来填充黑色到你的选择区。记住。你填充文本外部的轮廓,而不是文本本身。
|
||||
|
||||
![Fill the outline of the text with a different color][13]
|
||||
|
||||
在这里你完成了很多。使用 `Ctrl+Shift+A` 来取消你当前的选择区。
|
||||
|
||||
![Outline added to the text][14]
|
||||
|
||||
如此,你现在已经在 GIMP 中成功地添加轮廓到你的文本。它是在白色背景中,如果你想要一个透明背景,只需要在右侧栏的图层菜单中删除背景层。
|
||||
|
||||
![Remove the white background layer if you want a transparent background][15]
|
||||
|
||||
如果你对结果感到满意,保存文件未 PNG 文件(来保留透明背景),或你喜欢的任何文件格式。
|
||||
|
||||
### 你使它工作了吗?
|
||||
|
||||
就这样。这就是你在 GIMP 中为添加一个文本轮廓而需要做的全部工作。
|
||||
|
||||
我希望你发现这个 GIMP 教程有帮助。你可能想查看另一个 [关于在 GIMP 中添加一个水印的简单教程][16]。
|
||||
|
||||
如果你有问题或建议,请在下面自由留言。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/gimp-text-outline/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.gimp.org/
|
||||
[2]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/12/outlined_text_GIMP.png?ssl=1
|
||||
[3]: https://itsfoss.com/gimp-2-10-release/
|
||||
[4]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2019/12/create_outline_text_gimp_1.jpeg?ssl=1
|
||||
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_2.jpg?ssl=1
|
||||
[6]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp-3.jpg?ssl=1
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_4.jpg?ssl=1
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_5.jpg?ssl=1
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_6.jpg?ssl=1
|
||||
[10]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_7.jpg?ssl=1
|
||||
[11]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_8.jpg?ssl=1
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_9.jpg?ssl=1
|
||||
[13]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_10.jpg?ssl=1
|
||||
[14]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_11.jpg?ssl=1
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/12/outline_text_gimp_12.jpg?ssl=1
|
||||
[16]: https://itsfoss.com/add-watermark-gimp-linux/
|
@ -0,0 +1,69 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Morisun029)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11803-1.html)
|
||||
[#]: subject: (4 ways to volunteer this holiday season)
|
||||
[#]: via: (https://opensource.com/article/19/12/ways-volunteer)
|
||||
[#]: author: (John Jones https://opensource.com/users/johnjones4)
|
||||
|
||||
假期志愿服务的 4 种方式
|
||||
======
|
||||
|
||||
> 想要洒播些节日的快乐吗?为开源组织做贡献,帮助有需要的社区。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/20/223730f7983z8atxp1tf4l.jpg)
|
||||
|
||||
当领导者们配置人员和资源以做出积极改变时,就会产生社会影响。但是,许多社会努力都缺乏能够为这些改变者提供服务的技术资源。然而,有些组织通过将想要做出改变的开发人员与迫切需要更好技术的社区和非营利组织联系起来,来促进技术进步。这些组织通常为特定的受众提供服务,并招募特定种类的技术人员,它们有一个共同点:开源。
|
||||
|
||||
作为开发人员,我们出于各种原因试图加入开源社区。有些是为了专业发展,有些是为了能够与广阔的网络上令人印象深刻的技术人员合作,还有其他人则是因为他们清楚自己的贡献对于项目的成功的必要性。为什么不将你作为开发人员的才华投入到需要它的地方,而同时又为开源组织做贡献呢?以下组织是实现此目标的一些主要事例。
|
||||
|
||||
### Code for America
|
||||
|
||||
“Code for America” 是在数字时代,政府如何依靠人民为人民服务的一个例子。通过其 Brigade Network,该组织在美国各个城市中组织了一个由志愿程序员、数据科学家、相关公民和设计师组成的全国联盟。这些本地分支机构定期举行聚会,向社区开放。这样既可以向小组推出新项目,又可以协调正在进行的工作。为了使志愿者与项目相匹配,该网站经常列出项目所需的特定技能,例如数据分析、内容创建和JavaScript。同时,Brigade 网站也会关注当地问题,分享自然灾害等共同经验,这些都可以促进成员之间的合作。例如,新奥尔良、休斯敦和坦帕湾团队合作开发了一个飓风响应网站,当灾难发生时,该网站可以快速响应不同的城市灾难情况。
|
||||
|
||||
想要加入该组织,请访问 [该网站][2] 获取 70 多个 Brigade 的清单,以及个人加入组织的指南。
|
||||
|
||||
### Code for Change
|
||||
|
||||
“Code for Change” 显示了即使在高中时期,也可以为社会做贡献。印第安纳波利斯的一群高中开发爱好者成立了自己的俱乐部,他们通过创建针对社区问题的开源软件解决方案来回馈当地组织。“Code for Change” 鼓励当地组织提出项目构想,学生团体加入并开发完全自由和开源的解决方案。该小组已经开发了诸如“蓝宝石”之类的项目,该项目优化了当地难民组织的志愿者管理系统,并建立了民权委员会的投诉表格,方便公民就他们所关心的问题在网上发表意见。
|
||||
|
||||
有关如何在你自己的社区中创建 “Code for Change”,[访问他们的网站][3]。
|
||||
|
||||
### Python for Good/Ruby for Good
|
||||
|
||||
“Python for Good” 和 “Ruby for Good” 是在俄勒冈州波特兰市和弗吉尼亚州费尔法克斯市举办的双年展活动,该活动将人们聚集在一起,为各自的社区开发和制定解决方案。
|
||||
|
||||
在周末,人们聚在一起聆听当地非营利组织的建议,并通过构建开源解决方案来解决他们的问题。 2017 年,“Ruby For Good” 参与者创建了 “Justice for Juniors”,该计划指导当前和以前被监禁的年轻人,并将他们重新融入社区。参与者还创建了 “Diaperbase”,这是一种库存管理系统,为美国各地的<ruby>尿布库<rt>diaper bank</rt></ruby>所使用。这些活动的主要目标之一是将看似不同的行业和思维方式的组织和个人聚集在一起,以谋求共同利益。公司可以赞助活动,非营利组织可以提交项目构想,各种技能的人都可以注册参加活动并做出贡献。通过两岸(美国大西洋和太平洋东西海岸)的努力,“Ruby for Good” 和 “Python for Good” 一直恪守“使世界变得更好”的座右铭。
|
||||
|
||||
“[Ruby for Good][4]” 在夏天举行,举办地点在弗吉尼亚州费尔法克斯的乔治•梅森大学。
|
||||
|
||||
### Social Coder
|
||||
|
||||
英国的 Ed Guiness 创建了 “Social Coder”,将志愿者和慈善机构召集在一起,为六大洲的非营利组织创建和使用开源项目。“Social Coder” 积极招募来自世界各地的熟练 IT 志愿者,并将其与通过 Social Coder 注册的慈善机构和非营利组织进行匹配。项目范围从简单的网站更新到整个移动应用程序的开发。
|
||||
|
||||
例如,PHASE Worldwide 是一个在尼泊尔支持工作的小型非政府组织,因为 “Social Coder”,它获得了利用开源技术的关键支持和专业知识。
|
||||
|
||||
有许多慈善机构已经与英国的 “Social Coder”进行了合作,也欢迎其它国家的组织加入。通过他们的网站,个人可以注册为社会软件项目工作,找到寻求帮助的组织和慈善机构。
|
||||
|
||||
对 “Social Coder” 的志愿服务感兴趣的个人可以 [在此][5]注册.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/ways-volunteer
|
||||
|
||||
作者:[John Jones][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Morisun029](https://github.com/Morisun029)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/johnjones4
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_gift_giveaway_box_520x292.png?itok=w1YQhNH1 (Gift box opens with colors coming out)
|
||||
[2]: https://brigade.codeforamerica.org/
|
||||
[3]: http://codeforchange.herokuapp.com/
|
||||
[4]: https://rubyforgood.org/
|
||||
[5]: https://socialcoder.org/Home/Programmer
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (chen-ni)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11791-1.html)
|
||||
[#]: subject: (Explained! Why Your Distribution Still Using an ‘Outdated’ Linux Kernel?)
|
||||
[#]: via: (https://itsfoss.com/why-distros-use-old-kernel/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
@ -10,7 +10,9 @@
|
||||
为什么你的发行版仍然在使用“过时的”Linux 内核?
|
||||
======
|
||||
|
||||
[检查一下你的系统所使用的 Linux 内核版本][1],你十有八九会发现,按照 Linux 内核官网提供的信息,该内核版本已经达到使用寿命终期了。
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/16/225806jbqyacu3loolobae.png)
|
||||
|
||||
[检查一下你的系统所使用的 Linux 内核版本][1],你十有八九会发现,按照 Linux 内核官网提供的信息,该内核版本已经达到使用寿命终期(EOL)了。
|
||||
|
||||
一个软件一旦达到了使用寿命终期,那么就意味着它再也不会得到 bug 修复和维护了。
|
||||
|
||||
@ -18,11 +20,11 @@
|
||||
|
||||
下面将逐一解答这些问题。
|
||||
|
||||
总结
|
||||
|
||||
上游内核维护与你的发行版的内核维护是两个不同的概念。
|
||||
|
||||
例如,根据 Linux 内核官网,Linux 内核 4.15 版本可能已经达到使用寿命终期了,但是在 2023 年 4 月之前,Ubuntu 18.04 长期维护版本将会继续使用这个版本,并通过向后移植安全补丁和修复 bug 来提供维护。
|
||||
> **总结**
|
||||
>
|
||||
> 上游内核维护与你的发行版的内核维护是两个不同的概念。
|
||||
>
|
||||
> 例如,根据 Linux 内核官网,Linux 内核 4.15 版本可能已经达到使用寿命终期了,但是在 2023 年 4 月之前,Ubuntu 18.04 长期维护版本将会继续使用这个版本,并通过向后移植安全补丁和修复 bug 来提供维护。
|
||||
|
||||
### 检查 Linux 内核版本,以及是否达到使用寿命终期
|
||||
|
||||
@ -35,13 +37,11 @@ uname -r
|
||||
我使用的是 Ubuntu 18.04,输出的 Linux 内核版本如下:
|
||||
|
||||
```
|
||||
[email protected]:~$ uname -r
|
||||
abhishek@itsfoss:~$ uname -r
|
||||
5.0.0-37-generic
|
||||
```
|
||||
|
||||
接下来,可以到 Linux 内核官网上看看哪些 Linux 内核版本仍然在维护状态。在网站主页上就可以看到相关信息。
|
||||
|
||||
[Linux 内核官网][2]
|
||||
接下来,可以到 [Linux 内核官网][2]上看看哪些 Linux 内核版本仍然在维护状态。在网站主页上就可以看到相关信息。
|
||||
|
||||
你看到的内核版本状态应该类似于下图:
|
||||
|
||||
@ -53,7 +53,7 @@ uname -r
|
||||
|
||||
不幸的是,Linux 内核的生命周期没有任何规律可循。不是说常规的内核稳定发布版可以得到 X 月的维护、长期维护版本(LTS)可以得到 Y 年的维护。没有这回事。
|
||||
|
||||
根据实际需求,可能会存在内核的多个 LTS 版本,其使用寿命终期各不相同。在[这个页面][5]上可以查到这些 LTS 版本的相关信息,包括推定的使用寿命终期。
|
||||
根据实际需求,可能会存在内核的多个 LTS 版本,其使用寿命终期各不相同。在[这个页面][5]上可以查到这些 LTS 版本的相关信息,包括计划的使用寿命终期。
|
||||
|
||||
那么问题来了:既然 Linux 内核官网上明确表示 5.0 版本的内核已经达到了使用寿命终期,Ubuntu 为什么还在提供这个内核版本呢?
|
||||
|
||||
@ -63,11 +63,11 @@ uname -r
|
||||
|
||||
你是否想过,为什么 Ubuntu/Debian/Fedora 等发行版被称为 Linux “发行版”?这是因为,它们“发行” Linux 内核。
|
||||
|
||||
这些发行版会对 Linux 内核进行不同的修改,并添加各种 GUI 元素(包括桌面环境,显示服务器等)以及软件,然后再呈现给用户。
|
||||
这些发行版会对 Linux 内核进行不同的修改,并添加各种 GUI 元素(包括桌面环境、显示服务器等)以及软件,然后再呈现给用户。
|
||||
|
||||
按照通常的工作流,Linux 发行版会选择一个内核,提供给其用户,然后在接下来的几个月、几年中,甚至是达到内核的使用寿命终期之后,仍然会继续使用该内核。
|
||||
|
||||
这样能够保障安全吗?其实是可以的,因为 _**发行版会通过向后移植全部的重要修补来维护内核**_。
|
||||
这样能够保障安全吗?其实是可以的,因为 **发行版会通过向后移植全部的重要修补来维护内核**。
|
||||
|
||||
换句话说,你的 Linux 发行版会确保 Linux 内核没有漏洞和 bug,并且已经通过向后移植获得了重要的新特性。在“过时的旧版本 Linux 内核”上,其实有着数以千计的改动。
|
||||
|
||||
@ -83,13 +83,13 @@ uname -r
|
||||
|
||||
新的 Linux 内核稳定版本每隔 2 到 3 个月发布一次,有不少用户跃跃欲试。
|
||||
|
||||
实话说,除非有十分充分的理由,否则不应该使用最新版本的稳定内核。你使用的发行版并不会提供这个选项,你也不能指望通过在键盘上敲出“_sudo apt give-me-the-latest-stable-kernel_”解决问题。
|
||||
实话说,除非有十分充分的理由,否则不应该使用最新版本的稳定内核。你使用的发行版并不会提供这个选项,你也不能指望通过在键盘上敲出 `sudo apt give-me-the-latest-stable-kernel` 解决问题。
|
||||
|
||||
此外,手动[安装主流 Linux 内核版本][8]本身就是一个挑战。即使安装成功,之后每次发布 bug 修复的时候,负责更新内核的就会是你了。此外,当新内核达到使用寿命终期之后,你就有责任将它升级到更新的内核版本了。和常规的[Ubuntu 更新][9]不同,内核升级无法通过 apt upgrade 完成。
|
||||
此外,手动[安装主流 Linux 内核版本][8]本身就是一个挑战。即使安装成功,之后每次发布 bug 修复的时候,负责更新内核的就会是你了。此外,当新内核达到使用寿命终期之后,你就有责任将它升级到更新的内核版本了。和常规的 [Ubuntu 更新][9]不同,内核升级无法通过 `apt upgrade` 完成。
|
||||
|
||||
同样需要记住的是,切换到主流内核之后,可能就无法使用你的发行版提供的一些驱动程序和补丁了。
|
||||
|
||||
正如 [Greg Kroah-Hartman][10]所言,“_**你能使用的最好的内核,就是别人在维护的内核。**_”除了你的 Linux 发行版之外,又有谁更胜任这份工作呢!
|
||||
正如 [Greg Kroah-Hartman][10]所言,“**你能使用的最好的内核,就是别人在维护的内核。**”除了你的 Linux 发行版之外,又有谁更胜任这份工作呢!
|
||||
|
||||
希望你对这个主题已经有了更好的理解。下回发现你的系统正在使用的内核版本已经达到使用寿命终期的时候,希望你不会感到惊慌失措。
|
||||
|
||||
@ -102,7 +102,7 @@ via: https://itsfoss.com/why-distros-use-old-kernel/
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[chen-ni](https://github.com/chen-ni)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,64 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (algzjh)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11816-1.html)
|
||||
[#]: subject: (The best resources for agile software development)
|
||||
[#]: via: (https://opensource.com/article/19/12/agile-resources)
|
||||
[#]: author: (Leigh Griffin https://opensource.com/users/lgriffin)
|
||||
|
||||
敏捷软件开发的最佳资源
|
||||
======
|
||||
|
||||
> 请阅读我们的热门文章,这些文章着重讨论了敏捷的过去、现在和未来。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/25/121308jrs4speu2y09u09e.jpg)
|
||||
|
||||
对于 Opensource.com 上的敏捷主题来说,2019 年是非常棒的一年。随着 2020 年的到来,我们回顾了我们读者所读的与敏捷相关的热门文章。
|
||||
|
||||
### 小规模 Scrum 指南
|
||||
|
||||
Opensource.com 关于[小规模 Scrum][2] 的指南(我曾参与合著)由六部分组成,为小型团队提供了关于如何将敏捷引入到他们的工作中的建议。在官方的 [Scrum 指南][3]的概述中,传统的 Scrum 框架推荐至少三个人来实现,以充分发挥其潜力。但是,它并没有为一两个人的团队如何成功遵循 Scrum 提供指导。我们的六部分系列旨在规范化小规模的 Scrum,并检验我们在现实世界中使用它的经验。该系列受到了读者的热烈欢迎,以至于这六篇文章占据了前 10 名文章的 60%。因此,如果你还没有阅读的话,一定要从我们的[小规模 Scrum 介绍页面][2]下载。
|
||||
|
||||
### 全面的敏捷项目管理指南
|
||||
|
||||
遵循传统项目管理方法的团队最初对敏捷持怀疑态度,现在已经热衷于敏捷的工作方式。目前,敏捷已被接受,并且一种更加灵活的混合风格已经找到了归宿。Matt Shealy 撰写的[有关敏捷项目管理的综合指南][4]涵盖了敏捷项目管理的 12 条指导原则,对于希望为其项目带来敏捷性的传统项目经理而言,它是完美的选择。
|
||||
|
||||
### 成为出色的敏捷开发人员的 4 个步骤
|
||||
|
||||
DevOps 文化已经出现在许多现代软件团队中,这些团队采用了敏捷软件开发原则,利用了最先进的工具和自动化技术。但是,这种机械的敏捷方法并不能保证开发人员在日常工作中遵循敏捷实践。Daniel Oh 在[成为出色的敏捷开发人员的 4 个步骤][5]中给出了一些很棒的技巧,通过关注设计思维,使用可预测的方法,以质量为中心并不断学习和探索来提高你的敏捷性。用你的敏捷工具补充这些方法将形成非常灵活和强大的敏捷开发人员。
|
||||
|
||||
### Scrum 和 kanban:哪种敏捷框架更好?
|
||||
|
||||
对于以敏捷方式运行的团队来说,Scrum 和 kanban 是两种最流行的方法。在 “[Scrum 与 kanban:哪种敏捷框架更好?][6]” 中,Taz Brown 探索了两者的历史和目的。在阅读本文时,我想起一句名言:“如果你的工具箱里只有锤子,那么所有问题看起来都像钉子。”知道何时使用 kanban 以及何时使用 Scrum 非常重要,本文有助于说明两者都有一席之地,这取决于你的团队、挑战和目标。
|
||||
|
||||
### 开发人员对敏捷发表意见的 4 种方式
|
||||
|
||||
当采用敏捷的话题出现时,开发人员常常会担心自己会被强加上一种工作风格。在“[开发人员对敏捷发表意见的 4 种方式][7]”中,[Clément Verna][8] 着眼于开发人员通过帮助确定敏捷在其团队中的表现形式来颠覆这种说法的方法。检查敏捷的起源和基础是一个很好的起点,但是真正的价值在于拥有可帮助指导你的过程的指标。知道你将面临什么样的挑战会给你的前进提供坚实的基础。根据经验进行决策不仅可以增强团队的能力,还可以使他们对整个过程有一种主人翁意识。Verna 的文章还探讨了将人置于过程之上并作为一个团队来实现目标的重要性。
|
||||
|
||||
### 敏捷的现在和未来
|
||||
|
||||
今年,Opensource.com 的作者围绕敏捷的过去、现在以及未来可能会是什么样子进行了大量的讨论。感谢他们所有人,请一定于 2020 年在这里分享[你自己的敏捷故事][9]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/agile-resources
|
||||
|
||||
作者:[Leigh Griffin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[algzjh](https://github.com/algzjh)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/lgriffin
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/collab-team-pair-programming-code-keyboard2.png?itok=WnKfsl-G "Women programming"
|
||||
[2]: https://opensource.com/downloads/small-scale-scrum
|
||||
[3]: https://scrumguides.org/scrum-guide.html
|
||||
[4]: https://opensource.com/article/19/8/guide-agile-project-management
|
||||
[5]: https://opensource.com/article/19/2/steps-agile-developer
|
||||
[6]: https://opensource.com/article/19/8/scrum-vs-kanban
|
||||
[7]: https://opensource.com/article/19/10/ways-developers-what-agile
|
||||
[8]: https://twitter.com/clemsverna
|
||||
[9]: https://opensource.com/how-submit-article
|
@ -0,0 +1,525 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (heguangzhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11828-1.html)
|
||||
[#]: subject: (Put some loot in your Python platformer game)
|
||||
[#]: via: (https://opensource.com/article/20/1/loot-python-platformer-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
在你的 Python 平台类游戏中放一些奖励
|
||||
======
|
||||
|
||||
> 这部分是关于在使用 Python 的 Pygame 模块开发的视频游戏总给你的玩家提供收集的宝物和经验值的内容。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/29/131158jkwnhgd1nnawzn86.jpg)
|
||||
|
||||
这是正在进行的关于使用 [Python 3][2] 的 [Pygame][3] 模块创建视频游戏的系列文章的第十部分。以前的文章有:
|
||||
|
||||
* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][4]
|
||||
* [使用 Python 和 Pygame 模块构建一个游戏框架][5]
|
||||
* [如何在你的 Python 游戏中添加一个玩家][6]
|
||||
* [用 Pygame 使你的游戏角色移动起来][7]
|
||||
* [如何向你的 Python 游戏中添加一个敌人][8]
|
||||
* [在 Pygame 游戏中放置平台][13]
|
||||
* [在你的 Python 游戏中模拟引力][9]
|
||||
* [为你的 Python 平台类游戏添加跳跃功能][10]
|
||||
* [使你的 Python 游戏玩家能够向前和向后跑][11]
|
||||
|
||||
如果你已经阅读了本系列的前几篇文章,那么你已经了解了编写游戏的所有基础知识。现在你可以在这些基础上,创造一个全功能的游戏。当你第一次学习时,遵循本系列代码示例,这样的“用例”是有帮助的,但是,用例也会约束你。现在是时候运用你学到的知识,以新的方式应用它们了。
|
||||
|
||||
如果说,说起来容易做起来难,这篇文章展示了一个如何将你已经了解的内容用于新目的的例子中。具体来说,就是它涵盖了如何使用你以前的课程中已经了解到的来实现奖励系统。
|
||||
|
||||
在大多数电子游戏中,你有机会在游戏世界中获得“奖励”或收集到宝物和其他物品。奖励通常会增加你的分数或者你的生命值,或者为你的下一次任务提供信息。
|
||||
|
||||
游戏中包含的奖励类似于编程平台。像平台一样,奖励没有用户控制,随着游戏世界的滚动进行,并且必须检查与玩家的碰撞。
|
||||
|
||||
### 创建奖励函数
|
||||
|
||||
奖励和平台非常相似,你甚至不需要一个奖励的类。你可以重用 `Platform` 类,并将结果称为“奖励”。
|
||||
|
||||
由于奖励类型和位置可能因关卡不同而不同,如果你还没有,请在你的 `Level` 中创建一个名为 `loot` 的新函数。因为奖励物品不是平台,你也必须创建一个新的 `loot_list` 组,然后添加奖励物品。与平台、地面和敌人一样,该组用于检查玩家碰撞:
|
||||
|
||||
```
|
||||
def loot(lvl,lloc):
|
||||
if lvl == 1:
|
||||
loot_list = pygame.sprite.Group()
|
||||
loot = Platform(300,ty*7,tx,ty, 'loot_1.png')
|
||||
loot_list.add(loot)
|
||||
|
||||
if lvl == 2:
|
||||
print(lvl)
|
||||
|
||||
return loot_list
|
||||
```
|
||||
|
||||
你可以随意添加任意数量的奖励对象;记住把每一个都加到你的奖励清单上。`Platform` 类的参数是奖励图标的 X 位置、Y 位置、宽度和高度(通常让你的奖励精灵保持和所有其他方块一样的大小最为简单),以及你想要用作的奖励的图片。奖励的放置可以和贴图平台一样复杂,所以使用创建关卡时需要的关卡设计文档。
|
||||
|
||||
在脚本的设置部分调用新的奖励函数。在下面的代码中,前三行是上下文,所以只需添加第四行:
|
||||
|
||||
```
|
||||
enemy_list = Level.bad( 1, eloc )
|
||||
ground_list = Level.ground( 1,gloc,tx,ty )
|
||||
plat_list = Level.platform( 1,tx,ty )
|
||||
loot_list = Level.loot(1,tx,ty)
|
||||
```
|
||||
|
||||
正如你现在所知道的,除非你把它包含在你的主循环中,否则奖励不会被显示到屏幕上。将下面代码示例的最后一行添加到循环中:
|
||||
|
||||
```
|
||||
enemy_list.draw(world)
|
||||
ground_list.draw(world)
|
||||
plat_list.draw(world)
|
||||
loot_list.draw(world)
|
||||
```
|
||||
|
||||
启动你的游戏看看会发生什么。
|
||||
|
||||
![Loot in Python platformer][12]
|
||||
|
||||
你的奖励将会显示出来,但是当你的玩家碰到它们时,它们不会做任何事情,当你的玩家经过它们时,它们也不会滚动。接下来解决这些问题。
|
||||
|
||||
### 滚动奖励
|
||||
|
||||
像平台一样,当玩家在游戏世界中移动时,奖励必须滚动。逻辑与平台滚动相同。要向前滚动奖励物品,添加最后两行:
|
||||
|
||||
```
|
||||
for e in enemy_list:
|
||||
e.rect.x -= scroll
|
||||
for l in loot_list:
|
||||
l.rect.x -= scroll
|
||||
```
|
||||
|
||||
要向后滚动,请添加最后两行:
|
||||
|
||||
```
|
||||
for e in enemy_list:
|
||||
e.rect.x += scroll
|
||||
for l in loot_list:
|
||||
l.rect.x += scroll
|
||||
```
|
||||
|
||||
再次启动你的游戏,看看你的奖励物品现在表现得像在游戏世界里一样了,而不是仅仅画在上面。
|
||||
|
||||
### 检测碰撞
|
||||
|
||||
就像平台和敌人一样,你可以检查奖励物品和玩家之间的碰撞。逻辑与其他碰撞相同,除了撞击不会(必然)影响重力或生命值。取而代之的是,命中会导致奖励物品会消失并增加玩家的分数。
|
||||
|
||||
当你的玩家触摸到一个奖励对象时,你可以从 `loot_list` 中移除该对象。这意味着当你的主循环在 `loot_list` 中重绘所有奖励物品时,它不会重绘那个特定的对象,所以看起来玩家已经获得了奖励物品。
|
||||
|
||||
在 `Player` 类的 `update` 函数中的平台碰撞检测之上添加以下代码(最后一行仅用于上下文):
|
||||
|
||||
```
|
||||
loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
|
||||
for loot in loot_hit_list:
|
||||
loot_list.remove(loot)
|
||||
self.score += 1
|
||||
print(self.score)
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
```
|
||||
|
||||
当碰撞发生时,你不仅要把奖励从它的组中移除,还要给你的玩家一个分数提升。你还没有创建分数变量,所以请将它添加到你的玩家属性中,该属性是在 `Player` 类的 `__init__` 函数中创建的。在下面的代码中,前两行是上下文,所以只需添加分数变量:
|
||||
|
||||
```
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.score = 0
|
||||
```
|
||||
|
||||
当在主循环中调用 `update` 函数时,需要包括 `loot_list`:
|
||||
|
||||
```
|
||||
player.gravity()
|
||||
player.update()
|
||||
```
|
||||
|
||||
如你所见,你已经掌握了所有的基本知识。你现在要做的就是用新的方式使用你所知道的。
|
||||
|
||||
在下一篇文章中还有一些提示,但是与此同时,用你学到的知识来制作一些简单的单关卡游戏。限制你试图创造的东西的范围是很重要的,这样你就不会埋没自己。这也使得最终的成品看起来和感觉上更容易完成。
|
||||
|
||||
以下是迄今为止你为这个 Python 平台编写的所有代码:
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# draw a world
|
||||
# add a player and player control
|
||||
# add player movement
|
||||
# add enemy and basic collision
|
||||
# add platform
|
||||
# add gravity
|
||||
# add jumping
|
||||
# add scrolling
|
||||
|
||||
# GNU All-Permissive License
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
import pygame
|
||||
import sys
|
||||
import os
|
||||
|
||||
'''
|
||||
Objects
|
||||
'''
|
||||
|
||||
class Platform(pygame.sprite.Sprite):
|
||||
# x location, y location, img width, img height, img file
|
||||
def __init__(self,xloc,yloc,imgw,imgh,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img)).convert()
|
||||
self.image.convert_alpha()
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.y = yloc
|
||||
self.rect.x = xloc
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn a player
|
||||
'''
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.collide_delta = 0
|
||||
self.jump_delta = 6
|
||||
self.score = 1
|
||||
self.images = []
|
||||
for i in range(1,9):
|
||||
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def jump(self,platform_list):
|
||||
self.jump_delta = 0
|
||||
|
||||
def gravity(self):
|
||||
self.movey += 3.2 # how fast player falls
|
||||
|
||||
if self.rect.y > worldy and self.movey >= 0:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty
|
||||
|
||||
def control(self,x,y):
|
||||
'''
|
||||
control player movement
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
Update sprite position
|
||||
'''
|
||||
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
|
||||
# moving left
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# moving right
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
|
||||
# collisions
|
||||
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
|
||||
for enemy in enemy_hit_list:
|
||||
self.health -= 1
|
||||
#print(self.health)
|
||||
|
||||
loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
|
||||
for loot in loot_hit_list:
|
||||
loot_list.remove(loot)
|
||||
self.score += 1
|
||||
print(self.score)
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.collide_delta = 0 # stop jumping
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty-ty
|
||||
self.collide_delta = 0 # stop jumping
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
self.jump_delta = 6*2
|
||||
self.movey -= 33 # how high to jump
|
||||
self.collide_delta += 6
|
||||
self.jump_delta += 6
|
||||
|
||||
class Enemy(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn an enemy
|
||||
'''
|
||||
def __init__(self,x,y,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img))
|
||||
self.movey = 0
|
||||
#self.image.convert_alpha()
|
||||
#self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.counter = 0
|
||||
|
||||
|
||||
def move(self):
|
||||
'''
|
||||
enemy movement
|
||||
'''
|
||||
distance = 80
|
||||
speed = 8
|
||||
|
||||
self.movey += 3.2
|
||||
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
self.rect.x += speed
|
||||
elif self.counter >= distance and self.counter <= distance*2:
|
||||
self.rect.x -= speed
|
||||
else:
|
||||
self.counter = 0
|
||||
|
||||
self.counter += 1
|
||||
|
||||
if not self.rect.y >= worldy-ty-ty:
|
||||
self.rect.y += self.movey
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.rect.y = worldy-ty-ty
|
||||
|
||||
|
||||
class Level():
|
||||
def bad(lvl,eloc):
|
||||
if lvl == 1:
|
||||
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
|
||||
enemy_list = pygame.sprite.Group() # create enemy group
|
||||
enemy_list.add(enemy) # add enemy to group
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return enemy_list
|
||||
|
||||
def loot(lvl,tx,ty):
|
||||
if lvl == 1:
|
||||
loot_list = pygame.sprite.Group()
|
||||
loot = Platform(200,ty*7,tx,ty, 'loot_1.png')
|
||||
loot_list.add(loot)
|
||||
|
||||
if lvl == 2:
|
||||
print(lvl)
|
||||
|
||||
return loot_list
|
||||
|
||||
def ground(lvl,gloc,tx,ty):
|
||||
ground_list = pygame.sprite.Group()
|
||||
i=0
|
||||
if lvl == 1:
|
||||
while i < len(gloc):
|
||||
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
|
||||
ground_list.add(ground)
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return ground_list
|
||||
|
||||
def platform(lvl,tx,ty):
|
||||
plat_list = pygame.sprite.Group()
|
||||
ploc = []
|
||||
i=0
|
||||
if lvl == 1:
|
||||
ploc.append((20,worldy-ty-128,3))
|
||||
ploc.append((300,worldy-ty-256,3))
|
||||
ploc.append((500,worldy-ty-128,4))
|
||||
|
||||
while i < len(ploc):
|
||||
j=0
|
||||
while j <= ploc[i][2]:
|
||||
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
|
||||
plat_list.add(plat)
|
||||
j=j+1
|
||||
print('run' + str(i) + str(ploc[i]))
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return plat_list
|
||||
|
||||
'''
|
||||
Setup
|
||||
'''
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
|
||||
fps = 40 # frame rate
|
||||
ani = 4 # animation cycles
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
main = True
|
||||
|
||||
BLUE = (25,25,200)
|
||||
BLACK = (23,23,23 )
|
||||
WHITE = (254,254,254)
|
||||
ALPHA = (0,255,0)
|
||||
|
||||
world = pygame.display.set_mode([worldx,worldy])
|
||||
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
|
||||
backdropbox = world.get_rect()
|
||||
player = Player() # spawn player
|
||||
player.rect.x = 0
|
||||
player.rect.y = 0
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10
|
||||
forwardx = 600
|
||||
backwardx = 230
|
||||
|
||||
eloc = []
|
||||
eloc = [200,20]
|
||||
gloc = []
|
||||
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
|
||||
tx = 64 #tile size
|
||||
ty = 64 #tile size
|
||||
|
||||
i=0
|
||||
while i <= (worldx/tx)+tx:
|
||||
gloc.append(i*tx)
|
||||
i=i+1
|
||||
|
||||
enemy_list = Level.bad( 1, eloc )
|
||||
ground_list = Level.ground( 1,gloc,tx,ty )
|
||||
plat_list = Level.platform( 1,tx,ty )
|
||||
loot_list = Level.loot(1,tx,ty)
|
||||
|
||||
'''
|
||||
Main loop
|
||||
'''
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print("LEFT")
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print("RIGHT")
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(plat_list)
|
||||
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
|
||||
# scroll the world forward
|
||||
if player.rect.x >= forwardx:
|
||||
scroll = player.rect.x - forwardx
|
||||
player.rect.x = forwardx
|
||||
for p in plat_list:
|
||||
p.rect.x -= scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x -= scroll
|
||||
for l in loot_list:
|
||||
l.rect.x -= scroll
|
||||
|
||||
# scroll the world backward
|
||||
if player.rect.x <= backwardx:
|
||||
scroll = backwardx - player.rect.x
|
||||
player.rect.x = backwardx
|
||||
for p in plat_list:
|
||||
p.rect.x += scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x += scroll
|
||||
for l in loot_list:
|
||||
l.rect.x += scroll
|
||||
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.gravity() # check gravity
|
||||
player.update()
|
||||
player_list.draw(world) #refresh player position
|
||||
enemy_list.draw(world) # refresh enemies
|
||||
ground_list.draw(world) # refresh enemies
|
||||
plat_list.draw(world) # refresh platforms
|
||||
loot_list.draw(world) # refresh loot
|
||||
|
||||
for e in enemy_list:
|
||||
e.move()
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/loot-python-platformer-game
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[heguangzhi](https://github.com/heguangzhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUS_lovemoneyglory2.png?itok=AvneLxFp (Hearts, stars, and dollar signs)
|
||||
[2]: https://www.python.org/
|
||||
[3]: https://www.pygame.org/news
|
||||
[4]: https://linux.cn/article-9071-1.html
|
||||
[5]: https://linux.cn/article-10850-1.html
|
||||
[6]: https://linux.cn/article-10858-1.html
|
||||
[7]: https://linux.cn/article-10874-1.html
|
||||
[8]: https://linux.cn/article-10883-1.html
|
||||
[9]: https://linux.cn/article-11780-1.html
|
||||
[10]: https://linux.cn/article-11790-1.html
|
||||
[11]: https://linux.cn/article-11819-1.html
|
||||
[12]: https://opensource.com/sites/default/files/uploads/pygame-loot.jpg (Loot in Python platformer)
|
||||
[13]: https://linux.cn/article-10902-1.html
|
@ -0,0 +1,168 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (laingke)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11832-1.html)
|
||||
[#]: subject: (Introducing the guide to inter-process communication in Linux)
|
||||
[#]: via: (https://opensource.com/article/20/1/inter-process-communication-linux)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
免费电子书《Linux 进程间通信指南》介绍
|
||||
======
|
||||
|
||||
> 这本免费的电子书使经验丰富的程序员更深入了解 Linux 中进程间通信(IPC)的核心概念和机制。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/30/115631jthl0h61zhhmwpv1.jpeg)
|
||||
|
||||
让一个软件过程与另一个软件过程进行对话是一个微妙的平衡行为。但是,它对于应用程序而言可能是至关重要的功能,因此这是任何从事复杂项目的程序员都必须解决的问题。你的应用程序是否需要启动由其它软件处理的工作;监视外设或网络上正在执行的操作;或者检测来自其它来源的信号,当你的软件需要依赖其自身代码之外的东西来知道下一步做什么或什么时候做时,你就需要考虑<ruby>进程间通信<rt>inter-process communication</rt></ruby>(IPC)。
|
||||
|
||||
这在 Unix 操作系统上已经由来已久了,这可能是因为人们早期预期软件会来自各种来源。按照相同的传统,Linux 提供了一些同样的 IPC 接口和一些新接口。Linux 内核具有多种 IPC 方法,[util-linux 包][2]包含了 `ipcmk`、`ipcrm`、`ipcs` 和 `lsipc` 命令,用于监视和管理 IPC 消息。
|
||||
|
||||
### 显示进程间通信信息
|
||||
|
||||
在尝试 IPC 之前,你应该知道系统上已经有哪些 IPC 设施。`lsipc` 命令提供了该信息。
|
||||
|
||||
```
|
||||
RESOURCE DESCRIPTION LIMIT USED USE%
|
||||
MSGMNI Number of message queues 32000 0 0.00%
|
||||
MSGMAX Max size of message (byt.. 8192 - -
|
||||
MSGMNB Default max size of queue 16384 - -
|
||||
SHMMNI Shared memory segments 4096 79 1.93%
|
||||
SHMALL Shared memory pages 184[...] 25452 0.00%
|
||||
SHMMAX Max size of shared memory 18446744073692774399
|
||||
SHMMIN Min size of shared memory 1 - -
|
||||
SEMMNI Number of semaphore ident 32000 0 0.00%
|
||||
SEMMNS Total number of semaphore 1024000.. 0 0.00%
|
||||
SEMMSL Max semaphores per semap 32000 - -
|
||||
SEMOPM Max number of operations p 500 - -
|
||||
SEMVMX Semaphore max value 32767 - -
|
||||
```
|
||||
|
||||
你可能注意到,这个示例清单包含三种不同类型的 IPC 机制,每种机制在 Linux 内核中都是可用的:消息(MSG)、共享内存(SHM)和信号量(SEM)。你可以用 `ipcs` 命令查看每个子系统的当前活动:
|
||||
|
||||
```
|
||||
$ ipcs
|
||||
|
||||
------ Message Queues Creators/Owners ---
|
||||
msqid perms cuid cgid [...]
|
||||
|
||||
------ Shared Memory Segment Creators/Owners
|
||||
shmid perms cuid cgid [...]
|
||||
557056 700 seth users [...]
|
||||
3571713 700 seth users [...]
|
||||
2654210 600 seth users [...]
|
||||
2457603 700 seth users [...]
|
||||
|
||||
------ Semaphore Arrays Creators/Owners ---
|
||||
semid perms cuid cgid [...]
|
||||
```
|
||||
|
||||
这表明当前没有消息或信号量阵列,但是使用了一些共享内存段。
|
||||
|
||||
你可以在系统上执行一个简单的示例,这样就可以看到正在工作的系统之一。它涉及到一些 C 代码,所以你必须在系统上有构建工具。必须安装这些软件包才能从源代码构建软件,这些软件包的名称取决于发行版,因此请参考文档以获取详细信息。例如,在基于 Debian 的发行版上,你可以在 wiki 的[构建教程][3]部分了解构建需求,而在基于 Fedora 的发行版上,你可以参考该文档的[从源代码安装软件][4]部分。
|
||||
|
||||
### 创建一个消息队列
|
||||
|
||||
你的系统已经有一个默认的消息队列,但是你可以使用 `ipcmk` 命令创建你自己的消息队列:
|
||||
|
||||
```
|
||||
$ ipcmk --queue
|
||||
Message queue id: 32764
|
||||
```
|
||||
|
||||
编写一个简单的 IPC 消息发送器,为了简单,在队列 ID 中硬编码:
|
||||
|
||||
```
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
struct msgbuffer {
|
||||
char text[24];
|
||||
} message;
|
||||
|
||||
int main() {
|
||||
int msqid = 32764;
|
||||
strcpy(message.text,"opensource.com");
|
||||
msgsnd(msqid, &message, sizeof(message), 0);
|
||||
printf("Message: %s\n",message.text);
|
||||
printf("Queue: %d\n",msqid);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
编译该应用程序并运行:
|
||||
|
||||
```
|
||||
$ gcc msgsend.c -o msg.bin
|
||||
$ ./msg.bin
|
||||
Message: opensource.com
|
||||
Queue: 32769
|
||||
```
|
||||
|
||||
你刚刚向你的消息队列发送了一条消息。你可以使用 `ipcs` 命令验证这一点,可以使用 `——queue` 选项将输出限制到该消息队列:
|
||||
|
||||
```
|
||||
$ ipcs -q
|
||||
|
||||
------ Message Queues --------
|
||||
key msqid owner perms used-bytes messages
|
||||
0x7b341ab9 0 seth 666 0 0
|
||||
0x72bd8410 32764 seth 644 24 1
|
||||
```
|
||||
|
||||
你也可以检索这些消息:
|
||||
|
||||
```
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct msgbuffer {
|
||||
char text[24];
|
||||
} message;
|
||||
|
||||
int main() {
|
||||
int msqid = 32764;
|
||||
msgrcv(msqid, &message, sizeof(message),0,0);
|
||||
printf("\nQueue: %d\n",msqid);
|
||||
printf("Got this message: %s\n", message.text);
|
||||
msgctl(msqid,IPC_RMID,NULL);
|
||||
return 0;
|
||||
```
|
||||
|
||||
编译并运行:
|
||||
|
||||
```
|
||||
$ gcc get.c -o get.bin
|
||||
$ ./get.bin
|
||||
|
||||
Queue: 32764
|
||||
Got this message: opensource.com
|
||||
```
|
||||
|
||||
### 下载这本电子书
|
||||
|
||||
这只是 Marty Kalin 的《[Linux 进程间通信指南][5]》中课程的一个例子,可从 Opensource.com 下载的这本最新免费(且 CC 授权)的电子书。在短短的几节课中,你将从消息队列、共享内存和信号量、套接字、信号等中了解 IPC 的 POSIX 方法。认真阅读 Marty 的书,你将成为一个博识的程序员。而这不仅适用于经验丰富的编码人员,如果你编写的只是 shell 脚本,那么你将拥有有关管道(命名和未命名)和共享文件的大量实践知识,以及使用共享文件或外部消息队列时需要了解的重要概念。
|
||||
|
||||
如果你对制作具有动态和具有系统感知的优秀软件感兴趣,那么你需要了解 IPC。让[这本书][5]做你的向导。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/inter-process-communication-linux
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[laingke](https://github.com/laingke)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coverimage_inter-process_communication_linux_520x292.png?itok=hPoen7oI (Inter-process Communication in Linux)
|
||||
[2]: https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/
|
||||
[3]: https://wiki.debian.org/BuildingTutorial
|
||||
[4]: https://docs.pagure.org/docs-fedora/installing-software-from-source.html
|
||||
[5]: https://opensource.com/downloads/guide-inter-process-communication-linux
|
@ -1,20 +1,22 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11788-1.html)
|
||||
[#]: subject: (How to write a Python web API with Pyramid and Cornice)
|
||||
[#]: via: (https://opensource.com/article/20/1/python-web-api-pyramid-cornice)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
如何使用 Pyramid 和 Cornice 编写 Python Web API
|
||||
======
|
||||
使用 Pyramid 和 Cornice 构建可扩展的 RESTful Web 服务。
|
||||
![Searching for code][1]
|
||||
|
||||
[Python][2] 是一种高级的,面向对象的编程语言,它以其简单的语法而闻名。它一直是构建 RESTful API 的顶级编程语言之一。
|
||||
> 使用 Pyramid 和 Cornice 构建和描述可扩展的 RESTful Web 服务。
|
||||
|
||||
[Pyramid][3] 是一个 Python Web 框架,旨在随着应用的扩展而扩展:这对于简单的应用来说很简单,对于大型、复杂的应用也可以做到。Pyramid 为 PyPI (Python 软件包索引)提供了强大的支持。[Cornice][4] 提供了使用 Pyramid 构建 RESTful Web 服务的助手。
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/16/120352fcgeeccvfgt8sfvc.jpg)
|
||||
|
||||
[Python][2] 是一种高级的、面向对象的编程语言,它以其简单的语法而闻名。它一直是构建 RESTful API 的顶级编程语言之一。
|
||||
|
||||
[Pyramid][3] 是一个 Python Web 框架,旨在随着应用的扩展而扩展:这可以让简单的应用很简单,也可以增长为大型、复杂的应用。此外,Pyramid 为 PyPI (Python 软件包索引)提供了强大的支持。[Cornice][4] 为使用 Pyramid 构建和描述 RESTful Web 服务提供了助力。
|
||||
|
||||
本文将使用 Web 服务的例子来获取名人名言,来展示如何使用这些工具。
|
||||
|
||||
@ -22,7 +24,6 @@
|
||||
|
||||
首先为你的应用创建一个虚拟环境,并创建一个文件来保存代码:
|
||||
|
||||
|
||||
```
|
||||
$ mkdir tutorial
|
||||
$ cd tutorial
|
||||
@ -36,7 +37,6 @@ $ source env/bin/activate
|
||||
|
||||
使用以下命令导入这些模块:
|
||||
|
||||
|
||||
```
|
||||
from pyramid.config import Configurator
|
||||
from cornice import Service
|
||||
@ -44,8 +44,7 @@ from cornice import Service
|
||||
|
||||
### 定义服务
|
||||
|
||||
将引用服务定义为 **Service** 对象:
|
||||
|
||||
将引用服务定义为 `Service` 对象:
|
||||
|
||||
```
|
||||
QUOTES = Service(name='quotes',
|
||||
@ -55,8 +54,7 @@ QUOTES = Service(name='quotes',
|
||||
|
||||
### 编写引用逻辑
|
||||
|
||||
到目前为止,这仅支持 **GET** 获取名言。用 **QUOTES.get** 装饰函数。这是将逻辑绑定到 REST 服务的方法:
|
||||
|
||||
到目前为止,这仅支持获取名言。用 `QUOTES.get` 装饰函数。这是将逻辑绑定到 REST 服务的方法:
|
||||
|
||||
```
|
||||
@QUOTES.get()
|
||||
@ -72,14 +70,13 @@ def get_quote(request):
|
||||
}
|
||||
```
|
||||
|
||||
请注意,与其他框架不同,装饰器_不能_更改 **get_quote** 函数。如果导入此模块,你仍然可以定期调用该函数并检查结果。
|
||||
请注意,与其他框架不同,装饰器*不会*更改 `get_quote` 函数。如果导入此模块,你仍然可以定期调用该函数并检查结果。
|
||||
|
||||
在为 Pyramid RESTful 服务编写单元测试时,这很有用。
|
||||
|
||||
### 定义应用对象
|
||||
|
||||
最后,使用 **scan** 查找所有修饰的函数并将其添加到配置中:
|
||||
|
||||
最后,使用 `scan` 查找所有修饰的函数并将其添加到配置中:
|
||||
|
||||
```
|
||||
with Configurator() as config:
|
||||
@ -94,14 +91,12 @@ with Configurator() as config:
|
||||
|
||||
我使用 Twisted 的 WSGI 服务器运行该应用,但是如果需要,你可以使用任何其他 [WSGI][5] 服务器,例如 Gunicorn 或 uWSGI。
|
||||
|
||||
|
||||
```
|
||||
`(env)$ python -m twisted web --wsgi=main.application`
|
||||
(env)$ python -m twisted web --wsgi=main.application
|
||||
```
|
||||
|
||||
默认情况下,Twisted 的 WSGI 服务器运行在端口 8080 上。你可以使用 [HTTPie][6] 测试该服务:
|
||||
|
||||
|
||||
```
|
||||
(env) $ pip install httpie
|
||||
...
|
||||
@ -130,7 +125,7 @@ X-Content-Type-Options: nosniff
|
||||
|
||||
### 为什么要使用 Pyramid?
|
||||
|
||||
Pyramid 不是最受欢迎的框架,但它已在 [PyPI][7] 等一些引人注目的项目中使用。我喜欢 Pyramid,因为它是认真对待单元测试的框架之一:因为装饰器不会修改函数并且没有线程局部变量,所以可以直接从单元测试中调用函数。例如,需要访问数据库的函数将从通过 **request.config** 传递的 **request.config** 对象中获取它。这允许单元测试人员将模拟(或真实)数据库对象放入请求中,而不用仔细设置全局变量,线程局部变量或其他特定于框架的东西。
|
||||
Pyramid 并不是最受欢迎的框架,但它已在 [PyPI][7] 等一些引人注目的项目中使用。我喜欢 Pyramid,因为它是认真对待单元测试的框架之一:因为装饰器不会修改函数并且没有线程局部变量,所以可以直接从单元测试中调用函数。例如,需要访问数据库的函数将从通过 `request.config` 传递的 `request.config` 对象中获取它。这允许单元测试人员将模拟(或真实)数据库对象放入请求中,而不用仔细设置全局变量、线程局部变量或其他特定于框架的东西。
|
||||
|
||||
如果你正在寻找一个经过测试的库来构建你接下来的 API,请尝试使用 Pyramid。你不会失望的。
|
||||
|
||||
@ -140,8 +135,8 @@ via: https://opensource.com/article/20/1/python-web-api-pyramid-cornice
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,18 +1,20 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11784-1.html)
|
||||
[#]: subject: (Generating numeric sequences with the Linux seq command)
|
||||
[#]: via: (https://www.networkworld.com/article/3511954/generating-numeric-sequences-with-the-linux-seq-command.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
使用 Linux seq 命令生成数字序列
|
||||
======
|
||||
Linux seq 命令可以以闪电般的速度生成数字列表。它易于使用而且灵活。
|
||||
[Jamie][1] [(CC BY 2.0)][2]
|
||||
|
||||
在 Linux 中生成数字列表的最简单方法之一是使用 **seq**(sequence)命令。最简单的形式是,**seq** 接收一个数字,并输出从 1 到该数字的列表。例如:
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/15/112717drpb9nuwss84xebu.jpg)
|
||||
|
||||
> Linux 的 seq 命令可以以闪电般的速度生成数字列表,而且它也易于使用而且灵活。
|
||||
|
||||
在 Linux 中生成数字列表的最简单方法之一是使用 `seq`(<ruby>系列<rt>sequence</rt></ruby>)命令。其最简单的形式是,`seq` 接收一个数字参数,并输出从 1 到该数字的列表。例如:
|
||||
|
||||
```
|
||||
$ seq 5
|
||||
@ -23,7 +25,7 @@ $ seq 5
|
||||
5
|
||||
```
|
||||
|
||||
除非另有指定,否则 **seq** 始终以 1 开头。你可以在最终数字前面插上不同数字开始。
|
||||
除非另有指定,否则 `seq` 始终以 1 开头。你可以在最终数字前面插上不同数字开始一个序列。
|
||||
|
||||
```
|
||||
$ seq 3 5
|
||||
@ -34,7 +36,7 @@ $ seq 3 5
|
||||
|
||||
### 指定增量
|
||||
|
||||
你还可以指定增量。假设你要列出 3 的倍数。指定起点(在此示例中为第一个 3 ),增量(第二个 3)和终点(18)。
|
||||
你还可以指定增量步幅。假设你要列出 3 的倍数。指定起点(在此示例中为第一个 3 ),增量(第二个 3)和终点(18)。
|
||||
|
||||
```
|
||||
$ seq 3 3 18
|
||||
@ -58,9 +60,7 @@ $ seq 18 -3 3
|
||||
3
|
||||
```
|
||||
|
||||
**seq** 命令也非常快。你或许可以在 10 秒内生成一百万个数字的列表。
|
||||
|
||||
Advertisement
|
||||
`seq` 命令也非常快。你或许可以在 10 秒内生成一百万个数字的列表。
|
||||
|
||||
```
|
||||
$ time seq 1000000
|
||||
@ -78,9 +78,9 @@ user 0m0.020s
|
||||
sys 0m0.899s
|
||||
```
|
||||
|
||||
## 使用分隔符
|
||||
### 使用分隔符
|
||||
|
||||
另一个非常有用的选项是使用分隔符。你可以插入逗号,冒号或其他一些字符,而不是在每行上列出单个数字。-s 选项后跟要使用的字符。
|
||||
另一个非常有用的选项是使用分隔符。你可以插入逗号、冒号或其他一些字符,而不是在每行上列出单个数字。`-s` 选项后跟要使用的字符。
|
||||
|
||||
```
|
||||
$ seq -s: 3 3 18
|
||||
@ -96,21 +96,21 @@ $ seq -s' ' 3 3 18
|
||||
|
||||
### 开始数学运算
|
||||
|
||||
从生成数字序列到进行数学运算似乎是一个巨大的飞跃,但是有了正确的分隔符,**seq** 可以轻松地传递给 **bc** 进行计算。例如:
|
||||
从生成数字序列到进行数学运算似乎是一个巨大的飞跃,但是有了正确的分隔符,`seq` 可以轻松地传递给 `bc` 进行计算。例如:
|
||||
|
||||
```
|
||||
$ seq -s* 5 | bc
|
||||
120
|
||||
```
|
||||
|
||||
该命令中发生了什么?让我们来看看。首先,**seq** 生成一个数字列表,并使用 \* 作为分隔符。
|
||||
该命令中发生了什么?让我们来看看。首先,`seq` 生成一个数字列表,并使用 `*` 作为分隔符。
|
||||
|
||||
```
|
||||
$ seq -s* 5
|
||||
1*2*3*4*5
|
||||
```
|
||||
|
||||
然后,它将字符串传递给计算器 (**bc**),计算器立即将数字相乘。你可以在不到一秒的时间内进行相当广泛的计算。
|
||||
然后,它将字符串传递给计算器(`bc`),计算器立即将数字相乘。你可以在不到一秒的时间内进行相当庞大的计算。
|
||||
|
||||
```
|
||||
$ time seq -s* 117 | bc
|
||||
@ -125,15 +125,13 @@ sys 0m0.000s
|
||||
|
||||
### 局限性
|
||||
|
||||
你只能选择一个分隔符,因此计算将非常有限。单独使用 **bc** 可进行更复杂的数学运算。此外,**seq** 仅适用于数字。要生成单个字母序列,请改用如下命令:
|
||||
你只能选择一个分隔符,因此计算将非常有限。而单独使用 `bc` 可进行更复杂的数学运算。此外,`seq` 仅适用于数字。要生成单个字母的序列,请改用如下命令:
|
||||
|
||||
```
|
||||
$ echo {a..g}
|
||||
a b c d e f g
|
||||
```
|
||||
|
||||
加入 [Facebook][5] 和 [LinkedIn][6] 上的 Network World 社区,评论热门主题。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3511954/generating-numeric-sequences-with-the-linux-seq-command.html
|
||||
@ -141,7 +139,7 @@ via: https://www.networkworld.com/article/3511954/generating-numeric-sequences-w
|
||||
作者:[Sandra Henry-Stocker][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/) 荣誉推出
|
||||
|
@ -0,0 +1,126 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (heguangzhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11786-1.html)
|
||||
[#]: subject: (How piwheels will save Raspberry Pi users time in 2020)
|
||||
[#]: via: (https://opensource.com/article/20/1/piwheels)
|
||||
[#]: author: (Ben Nuttall https://opensource.com/users/bennuttall)
|
||||
|
||||
piwheels 是如何为树莓派用户节省时间的
|
||||
======
|
||||
|
||||
> 通过为树莓派提供预编译的 Python 包,piwheels 项目为用户节省了大量的时间和精力。
|
||||
|
||||
![rainbow colors on pinwheels in the sun][1]
|
||||
|
||||
piwheels 自动为 Python 包索引 [PiPi][2] 上的所有项目构建 Python wheels(预编译的 Python包),并使用了树莓派硬件以确保其兼容性。这意味着,当树莓派用户想要使用 `pip` 安装一个 Python 库时,他们会得到一个现成编译好的版本,并保证可以在树莓派上良好的工作。这使得树莓派用户更容易入门并开始他们的项目。
|
||||
|
||||
![Piwheels logo][3]
|
||||
|
||||
当我在 2018 年 10 月写 [piwheels:为树莓派提供快速 Python 包安装][4]时,那时 piwheels 项目已经有一年了,并且已经证明了其为树莓派用户节省大量时间和精力。但当这个项目进入第二年时,它为树莓派提供了预编译的 Python 包做了更多工作。
|
||||
|
||||
![Raspberry Pi 4][5]
|
||||
|
||||
### 它是怎么工作的
|
||||
|
||||
树莓派的主要操作系统 [Raspbian][6] 预配置使用了 piwheels,所以用户不需要做任何特殊的事情就可以使用 piwheels。
|
||||
|
||||
配置文件(在 `/etc/pip.conf`)告诉 `pip` 使用 [piwheels.org][7] 作*附加索引*,因此 `pip` 会首先查找 PyPI,然后查找 piwheels。piwheels 的网站被托管在一个树莓派 3 上,该项目构建的所有 wheels 都托管在该树莓派上。它每月提供 100 多万个软件包——这对于一台 35 美元的电脑来说还真不赖!
|
||||
|
||||
除了提供网站服务的主树莓派以外,piwheels 项目还使用其他七个树莓派来构建软件包。其中一些运行 Raspbian Jessie,为 Python 3.4 构建 wheels;另外一些运行 Raspbian Stretch 为 Python 3.5 构建;还有一些运行 Raspbian Buster 为 Python 3.7 构建。该项目通常不支持其他 Python 版本。还有一个“合适的服务器”——一台运行 Postgres 数据库的虚拟机。由于树莓派 3 只有 1GB 的内存,所以(非常大的)数据库不能在其上很好地运行,所以我们把它移到了虚拟机上。带 4GB 内存的树莓派 4 可能是合用的,所以我们将来可能会用到它。
|
||||
|
||||
这些树莓派都在“派云”中的 IPv6 网络上——这是一项由总部位于剑桥的托管公司 [Mythic Beasts][8] 提供的卓越服务。
|
||||
|
||||
![Mythic Beasts hosting service][9]
|
||||
|
||||
### 下载和统计趋势
|
||||
|
||||
每次下载 piwheels 文件时,它都会记录在数据库中。这提供了对什么包最受欢迎以及人们使用什么 Python 版本和操作系统的统计。我们没有太多来自用户代理的信息,但是因为树莓派 1/Zero 的架构显示为 “armv6”,树莓派 2/3/4 显示为 “armv7”,所以我们可以将它们区分开来。
|
||||
|
||||
截至 2019 年 12 月中旬,从 piwheels 下载的软件包超过 1400 万个,仅 2019 年就有近 900 万个。
|
||||
|
||||
自项目开始以来最受欢迎的 10 个软件包是:
|
||||
|
||||
1. [pycparser][10](821,060 个下载)
|
||||
2. [PyYAML][11](366,979 个下载)
|
||||
3. [numpy][12](354,531 个下载)
|
||||
4. [cffi][13](336,982 个下载)
|
||||
5. [MarkupSafe][14](318,878 个下载)
|
||||
6. [future][15](282,349 个下载)
|
||||
7. [aiohttp][16](277,046 个下载)
|
||||
8. [cryptography][17](276,167 个下载)
|
||||
9. [home-assistant-frontend][18](266,667 个下载)
|
||||
10. [multidict][19](256,185 个下载)
|
||||
|
||||
请注意,许多纯 Python 包,如 [urllib3][20],都是作为 PyPI 上的 wheels 提供的;因为这些是跨平台兼容的,所以通常不会从 piwheels 下载,因为 PyPI 优先。
|
||||
|
||||
随着时间的推移,我们也看到了使用哪些 Python 版本的趋势。这里显示了 Raspbian Buster 发布时从 3.5 版快速升级到了 Python 3.7:
|
||||
|
||||
![Data from piwheels on Python versions used over time][21]
|
||||
|
||||
你可以在我们的这篇 [统计博文][22] 看到更多的统计趋势。
|
||||
|
||||
### 节省的时间
|
||||
|
||||
每个包构建都被记录在数据库中,并且每个下载也被存储。交叉引用下载数和构建时间显示了节省了多少时间。一个例子是 numpy —— 最新版本大约需要 11 分钟来构建。
|
||||
|
||||
迄今为止,piwheels 项目已经为用户节省了总计超过 165 年的构建时间。按照目前的使用率,piwheels 项目每天可以节省 200 多天。
|
||||
|
||||
除了节省构建时间,拥有预编译的 wheels 也意味着人们不必安装各种开发工具来构建包。一些包需要其他 apt 包来访问共享库。弄清楚你需要哪一个可能会很痛苦,所以我们也让这一步变得容易了。首先,我们找到了这个过程,[在博客上记录了这个过程][23]。然后,我们将这个逻辑添加到构建过程中,这样当构建一个 wheels 时,它的依赖关系会被自动计算并添加到包的项目页面中:
|
||||
|
||||
![numpy dependencies][24]
|
||||
|
||||
### piwheels 的下一步是什么?
|
||||
|
||||
今年,我们推出了项目页面(例如,[numpy][25]),这是一种非常有用的方式,可以让人们以人类可读的方式查找项目信息。它们还使人们更容易报告问题,例如 piwheels 中缺少一个项目,或者他们下载的包有问题。
|
||||
|
||||
2020 年初,我们计划对 piwheels 项目进行一些升级,以启用新的 JSON 应用编程接口,这样你就可以自动检查哪些版本可用,查找项目的依赖关系,等等。
|
||||
|
||||
下一次 Debian/Raspbian 升级要到 2021 年年中才会发生,所以在那之前我们不会开始为任何新的 Python 版本构建 wheels。
|
||||
|
||||
你可以在这个项目的[博客][26]上读到更多关于 piwheels 的信息,我将在 2020 年初在那里发表一篇 2019 年的综述。你也可以在推特上关注 [@piwheels][27],在那里你可以看到每日和每月的统计数据以及任何达到的里程碑。
|
||||
|
||||
当然,piwheels 是一个开源项目,你可以在 [GitHub][28] 上看到整个项目源代码。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/piwheels
|
||||
|
||||
作者:[Ben Nuttall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[heguangzhi](https://github.com/heguangzhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/bennuttall
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rainbow-pinwheel-piwheel-diversity-inclusion.png?itok=di41Wd3V (rainbow colors on pinwheels in the sun)
|
||||
[2]: https://pypi.org/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/piwheels.png (Piwheels logo)
|
||||
[4]: https://opensource.com/article/18/10/piwheels-python-raspberrypi
|
||||
[5]: https://opensource.com/sites/default/files/uploads/raspberry-pi-4_0.jpg (Raspberry Pi 4)
|
||||
[6]: https://www.raspberrypi.org/downloads/raspbian/
|
||||
[7]: http://piwheels.org
|
||||
[8]: https://www.mythic-beasts.com/order/rpi
|
||||
[9]: https://opensource.com/sites/default/files/uploads/pi-cloud.png (Mythic Beasts hosting service)
|
||||
[10]: https://www.piwheels.org/project/pycparser
|
||||
[11]: https://www.piwheels.org/project/PyYAML
|
||||
[12]: https://www.piwheels.org/project/numpy
|
||||
[13]: https://www.piwheels.org/project/cffi
|
||||
[14]: https://www.piwheels.org/project/MarkupSafe
|
||||
[15]: https://www.piwheels.org/project/future
|
||||
[16]: https://www.piwheels.org/project/aiohttp
|
||||
[17]: https://www.piwheels.org/project/cryptography
|
||||
[18]: https://www.piwheels.org/project/home-assistant-frontend
|
||||
[19]: https://www.piwheels.org/project/multidict
|
||||
[20]: https://piwheels.org/project/urllib3/
|
||||
[21]: https://opensource.com/sites/default/files/uploads/pyvers2019.png (Data from piwheels on Python versions used over time)
|
||||
[22]: https://blog.piwheels.org/piwheels-stats-for-2019/
|
||||
[23]: https://blog.piwheels.org/how-to-work-out-the-missing-dependencies-for-a-python-package/
|
||||
[24]: https://opensource.com/sites/default/files/uploads/numpy-deps.png (numpy dependencies)
|
||||
[25]: https://www.piwheels.org/project/numpy/
|
||||
[26]: https://blog.piwheels.org/
|
||||
[27]: https://twitter.com/piwheels
|
||||
[28]: https://github.com/piwheels/
|
@ -0,0 +1,85 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11809-1.html)
|
||||
[#]: subject: (How to setup multiple monitors in sway)
|
||||
[#]: via: (https://fedoramagazine.org/how-to-setup-multiple-monitors-in-sway/)
|
||||
[#]: author: (arte219 https://fedoramagazine.org/author/arte219/)
|
||||
|
||||
如何在 Sway 中设置多个显示器
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Sway 是一种平铺式 Wayland 合成器,具有与 [i3 X11 窗口管理器][2]相同的功能、外观和工作流程。由于 Sway 使用 Wayland 而不是 X11,因此就不能一如既往地使用设置 X11 的工具。这包括 `xrandr` 之类的工具,这些工具在 X11 窗口管理器或桌面中用于设置显示器。这就是为什么必须通过编辑 Sway 配置文件来设置显示器的原因,这就是本文的目的。
|
||||
|
||||
### 获取你的显示器 ID
|
||||
|
||||
首先,你必须获得 Sway 用来指代显示器的名称。你可以通过运行以下命令进行操作:
|
||||
|
||||
```
|
||||
$ swaymsg -t get_outputs
|
||||
```
|
||||
|
||||
你将获得所有显示器的相关信息,每个显示器都用空行分隔。
|
||||
|
||||
你必须查看每个部分的第一行,以及 `Output` 之后的内容。例如,当你看到 `Output DVI-D-1 'Philips Consumer Electronics Company'` 之类的行时,则该输出 ID 为 `DVI-D-1`。注意这些 ID 及其所属的物理监视器。
|
||||
|
||||
### 编辑配置文件
|
||||
|
||||
如果你之前没有编辑过 Sway 配置文件,则必须通过运行以下命令将其复制到主目录中:
|
||||
|
||||
```
|
||||
cp -r /etc/sway/config ~/.config/sway/config
|
||||
```
|
||||
|
||||
现在,默认配置文件位于 `~/.config/sway` 中,名为 `config`。你可以使用任何文本编辑器进行编辑。
|
||||
|
||||
现在你需要做一点数学。想象有一个网格,其原点在左上角。X 和 Y 坐标的单位是像素。Y 轴反转。这意味着,例如,如果你从原点开始,向右移动 100 像素,向下移动 80 像素,则坐标将为 `(100, 80)`。
|
||||
|
||||
你必须计算最终显示在此网格上的位置。显示器的位置由左上方的像素指定。例如,如果我们要使用名称为“HDMI1”且分辨率为 1920×1080 的显示器,并在其右侧使用名称为 “eDP1” 且分辨率为 1600×900 的笔记本电脑显示器,则必须在配置文件中键入 :
|
||||
|
||||
```
|
||||
output HDMI1 pos 0 0
|
||||
output eDP1 pos 1920 0
|
||||
```
|
||||
|
||||
你还可以使用 `res` 选项手动指定分辨率:
|
||||
|
||||
```
|
||||
output HDMI1 pos 0 0 res 1920x1080
|
||||
output eDP1 pos 1920 0 res 1600x900
|
||||
```
|
||||
|
||||
### 将工作空间绑定到显示器上
|
||||
|
||||
与多个监视器一起使用 Sway 在工作区管理中可能会有些棘手。幸运的是,你可以将工作区绑定到特定的显示器上,因此你可以轻松地切换到该显示器并更有效地使用它。只需通过配置文件中的 `workspace` 命令即可完成。例如,如果要绑定工作区 1 和 2 到显示器 “DVI-D-1”,绑定工作区 8 和 9 到显示器 “HDMI-A-1”,则可以使用以下方法:
|
||||
|
||||
```
|
||||
workspace 1 output DVI-D-1
|
||||
workspace 2 output DVI-D-1
|
||||
```
|
||||
|
||||
```
|
||||
workspace 8 output HDMI-A-1
|
||||
workspace 9 output HDMI-A-1
|
||||
```
|
||||
|
||||
就是这样。这就在 Sway 中多显示器设置的基础知识。可以在 <https://github.com/swaywm/sway/wiki#Wiki#Multihead> 中找到更详细的指南。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/how-to-setup-multiple-monitors-in-sway/
|
||||
|
||||
作者:[arte219][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://fedoramagazine.org/author/arte219/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/01/sway-multiple-monitors-816x345.png
|
||||
[2]: https://fedoramagazine.org/getting-started-i3-window-manager/
|
@ -1,61 +1,60 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qianmingtian)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11787-1.html)
|
||||
[#]: subject: (Huawei’s Linux Distribution openEuler is Available Now!)
|
||||
[#]: via: (https://itsfoss.com/openeuler/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
华为的linux发行版 openEuler 可以使用了!
|
||||
外媒:华为的 Linux 发行版 openEuler 可以使用了!
|
||||
======
|
||||
|
||||
华为提供了一个基于 CentOS 的企业 Linux 发行版 EulerOS 。最近,华为发布了一个名为 [openEuler][1] 的 EulerOS 社区版。
|
||||
> 华为提供了一个基于 CentOS 的企业级 Linux 发行版 EulerOS。最近,华为发布了一个名为 [openEuler][1] 的 EulerOS 社区版。
|
||||
|
||||
openEuler 的源代码也被发布了。你在微软旗下的 GitHub 上找不到它——源代码可以在 [Gitee][2] 找到,这是一个中文的 [GitHub 的替代品][3] 。
|
||||
openEuler 的源代码也一同发布了。你在微软旗下的 GitHub 上找不到它——源代码可以在 [Gitee][2] 找到,这是一个中文的 [GitHub 的替代品][3]。
|
||||
|
||||
它有两个独立的存储库,一个用于存储[源代码][2],另一个作为[包源][4] 存储有助于构建操作系统的软件包。
|
||||
它有两个独立的存储库,一个用于存储[源代码][2];另一个作为[软件包的源代码][4],存储有助于构建该操作系统的软件包。
|
||||
|
||||
![][5]
|
||||
![][5]
|
||||
|
||||
openuler 基础架构团队分享了他们使源代码可用的经验:
|
||||
openEuler 基础架构团队分享了他们使源代码可用的经验:
|
||||
|
||||
>我们现在很兴奋。很难想象我们会管理成千上万的仓库。为了确保它们能被成功地编译,我们要感谢所有参与贡献的人。
|
||||
> 我们现在很兴奋。很难想象我们会管理成千上万的仓库。为了确保它们能被成功地编译,我们要感谢所有参与贡献的人。
|
||||
|
||||
### openEuler 是基于 CentOS 的 Linux 发行版
|
||||
|
||||
与 EulerOS 一样,openEuler OS 也是基于 [CentOS][6],但华为技术有限公司为企业应用进一步开发了该操作系统。
|
||||
|
||||
它是为 ARM64 架构的服务器量身定做的,同时华为声称已经做了一些改变来提高其性能。你可以在[华为发展博客][7]上了解更多。
|
||||
它是为 ARM64 架构的服务器量身定做的,同时华为声称已经做了一些改变来提高其性能。你可以在[华为开发博客][7]上了解更多。
|
||||
|
||||
![][8]
|
||||
|
||||
|
||||
目前,根据 openEuler 的官方声明,有 50 多名贡献者为 openEuler 贡献了近 600 个提交。
|
||||
|
||||
贡献者使源代码对社区可用成为可能。
|
||||
贡献者们使源代码对社区可用成为可能。
|
||||
|
||||
值得注意的是,存储库还包括两个与之相关的新项目(或子项目),[iSulad][9] 和 **A-Tune**。
|
||||
值得注意的是,存储库还包括两个与之相关的新项目(或子项目),[iSulad][9] 和 A-Tune。
|
||||
|
||||
A-Tune 是一个基于 AI 的操作系统调优软件, iSulad 是一个轻量级的容器运行时守护进程,如[Gitee][2]中提到的那样,它是为物联网和云基础设施设计的。
|
||||
A-Tune 是一个基于 AI 的操作系统调优软件,iSulad 是一个轻量级的容器运行时守护进程,如在 [Gitee][2] 中提到的那样,它是为物联网和云基础设施设计的。
|
||||
|
||||
另外,官方的[公告][10]提到,这些系统是在华为云上通过脚本自动化构建的。这确实十分有趣。
|
||||
另外,官方的[公告][10]提到,这些系统是在华为云上通过脚本自动构建的。这确实十分有趣。
|
||||
|
||||
### 下载 openEuler
|
||||
|
||||
![][11]
|
||||
|
||||
到目前为止,你找不到它的英文文档,所以你必须等待或选择通过[文档][12]帮助他们。
|
||||
到目前为止,你找不到它的英文文档,所以你必须等待或选择通过(贡献)[文档][12]来帮助他们。
|
||||
|
||||
你可以直接从它的[官方网站][13]下载 ISO 来测试它:
|
||||
|
||||
[下载 openEuler ][13]
|
||||
- [下载 openEuler ][13]
|
||||
|
||||
### 你认为华为的 openEuler 怎么样?
|
||||
|
||||
据 cnTechPost 报道,华为曾宣布 EulerOS 将以新名字 openEuler 成为开源软件。
|
||||
|
||||
目前还不清楚 openEuler 是否会取代 EulerOS ,或者两者会像 CentOS (社区版)和 Red Hat (商业版)一样同时存在。
|
||||
目前还不清楚 openEuler 是否会取代 EulerOS ,或者两者会像 CentOS(社区版)和 Red Hat(商业版)一样同时存在。
|
||||
|
||||
我还没有测试过它,所以我不能说 openEuler 是否适合英文用户。
|
||||
|
||||
@ -68,7 +67,7 @@ via: https://itsfoss.com/openeuler/
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qianmingtian][c]
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,65 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11793-1.html)
|
||||
[#]: subject: (Sync files across multiple devices with Syncthing)
|
||||
[#]: via: (https://opensource.com/article/20/1/sync-files-syncthing)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 Syncthing 在多个设备间同步文件
|
||||
======
|
||||
|
||||
> 2020 年,在我们的 20 个使用开源提升生产力的系列文章中,首先了解如何使用 Syncthing 同步文件。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/18/123416rebvs7sjwm6c889y.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 Synthing 同步文件
|
||||
|
||||
设置新机器很麻烦。我们都有在机器之间复制的“标准设置”。多年来,我使用了很多方法来使它们在计算机之间同步。在过去(这会告诉你我年纪有多大了),曾经是软盘、然后是 Zip 磁盘、U 盘、SCP、Rsync、Dropbox、ownCloud,你想到的都试过。但这些似乎对我都不够好。
|
||||
|
||||
然后我偶然发现了 [Syncthing][2]。
|
||||
|
||||
![syncthing console][3]
|
||||
|
||||
Syncthing 是一个轻量级的点对点文件同步系统。你不需要为服务付费,也不需要第三方服务器,而且速度很快。以我的经验,比文件同步中的许多“大牌”要快得多。
|
||||
|
||||
Syncthing 可在 Linux、MacOS、Windows 和多种 BSD 中使用。还有一个 Android 应用(但尚无官方 iOS 版本)。以上所有终端都有方便的图形化前端(尽管我不会在这里介绍)。在 Linux 上,大多数发行版都有可用的软件包,因此安装非常简单。
|
||||
|
||||
![Installing Syncthing on Ubuntu][4]
|
||||
|
||||
首次启动 Syncthing 时,它将启动 Web 浏览器以配置守护程序。第一台计算机上没有太多要做,但是这是一个很好的机会来介绍一下用户界面 (UI)。最重要的是在右上方的 “Actions” 菜单下的 “System ID”。
|
||||
|
||||
![Machine ID][5]
|
||||
|
||||
设置第一台计算机后,请在第二台计算机上重复安装。在 UI 中,右下方将显示一个按钮,名为 “Add Remote Device”。单击该按钮,你将会看到一个要求输入 “Device ID and a Name” 的框。从第一台计算机上复制并粘贴 “Device ID”,然后单击 “Save”。
|
||||
|
||||
你应该会在第一台上看到一个请求添加第二台的弹出窗口。接受后,新机器将显示在第一台机器的右下角。与第二台计算机共享默认目录。单击 “Default Folder”,然后单击 “Edit” 按钮。弹出窗口的顶部有四个链接。单击 “Sharing”,然后选择第二台计算机。单击 “Save”,然后查看第二台计算机。你会看到一个接受共享目录的提示。接受后,它将开始在两台计算机之间同步文件。
|
||||
|
||||
![Sharing a directory in Syncthing][6]
|
||||
|
||||
测试从一台计算机上复制文件到默认目录(“/你的家目录/Share”)。它应该很快会在另一台上出现。
|
||||
|
||||
你可以根据需要添加任意数量的目录,这非常方便。如你在第一张图中所看到的,我有一个用于保存配置的 `myconfigs` 文件夹。当我买了一台新机器时,我只需安装 Syncthing,如果我在一台机器上调整了配置,我不必更新所有,它会自动更新。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/sync-files-syncthing
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/files_documents_paper_folder.png?itok=eIJWac15 (Files in a folder)
|
||||
[2]: https://syncthing.net/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_1-1.png (syncthing console)
|
||||
[4]: https://opensource.com/sites/default/files/uploads/productivity_1-2.png (Installing Syncthing on Ubuntu)
|
||||
[5]: https://opensource.com/sites/default/files/uploads/productivity_1-3.png (Machine ID)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_1-4.png (Sharing a directory in Syncthing)
|
@ -0,0 +1,59 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11796-1.html)
|
||||
[#]: subject: (Use Stow for configuration management of multiple machines)
|
||||
[#]: via: (https://opensource.com/article/20/1/configuration-management-stow)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 Stow 管理多台机器配置
|
||||
======
|
||||
> 2020 年,在我们的 20 个使用开源提升生产力的系列文章中,让我们了解如何使用 Stow 跨机器管理配置。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/18/141330jdcjalqzjal84a03.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 Stow 管理符号链接
|
||||
|
||||
昨天,我解释了如何使用 [Syncthing][2] 在多台计算机上保持文件同步。但是,这只是我用来保持配置一致性的工具之一。还有另一个表面上看起来更简单的工具:[Stow][3]。
|
||||
|
||||
![Stow help screen][4]
|
||||
|
||||
Stow 管理符号链接。默认情况下,它会链接目录到上一级目录。还有设置源和目标目录的选项,但我通常不使用它们。
|
||||
|
||||
正如我在 Syncthing 的[文章][5] 中提到的,我使用 Syncthing 来保持 `myconfigs` 目录在我所有的计算机上一致。`myconfigs` 目录下面有多个子目录。每个子目录包含我经常使用的应用之一的配置文件。
|
||||
|
||||
![myconfigs directory][6]
|
||||
|
||||
在每台计算机上,我进入 `myconfigs` 目录,并运行 `stow -S <目录名称>` 以将目录中的文件符号链接到我的家目录。例如,在 `vim` 目录下,我有 `.vimrc` 和 `.vim` 目录。在每台机器上,我运行 `stow -S vim` 来创建符号链接 `~/.vimrc` 和 `~/.vim`。当我在一台计算机上更改 Vim 配置时,它会应用到我的所有机器上。
|
||||
|
||||
然而,有时候,我需要一些特定于机器的配置,这就是为什么我有如 `msmtp-personal` 和 `msmtp-elastic`(我的雇主)这样的目录。由于我的 `msmtp` SMTP 客户端需要知道要中继电子邮件服务器,并且每个服务器都有不同的设置和凭据,我会使用 `-D` 标志来取消链接,接着链接另外一个。
|
||||
|
||||
![Unstow one, stow the other][7]
|
||||
|
||||
有时我要给配置添加文件。为此,有一个 `-R` 选项来“重新链接”。例如,我喜欢在图形化 Vim 中使用一种与控制台不同的特定字体。除了标准 `.vimrc` 文件,`.gvimrc` 文件能让我设置特定于图形化版本的选项。当我第一次设置它时,我移动 `~/.gvimrc` 到 `~/myconfigs/vim` 中,然后运行 `stow -R vim`,它取消链接并重新链接该目录中的所有内容。
|
||||
|
||||
Stow 让我使用一个简单的命令行在多种配置之间切换,并且,结合 Syncthing,我可以确保无论我身在何处或在哪里进行更改,我都有我喜欢的工具的设置。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/configuration-management-stow
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_keyboard_laptop_development_code_woman.png?itok=vbYz6jjb (A person programming)
|
||||
[2]: https://syncthing.net/
|
||||
[3]: https://www.gnu.org/software/stow/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/productivity_2-1.png (Stow help screen)
|
||||
[5]: https://linux.cn/article-11793-1.html
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_2-2.png (myconfigs directory)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/productivity_2-3.png (Unstow one, stow the other)
|
@ -0,0 +1,78 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11804-1.html)
|
||||
[#]: subject: (Keep your email in sync with OfflineIMAP)
|
||||
[#]: via: (https://opensource.com/article/20/1/sync-email-offlineimap)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 OfflineIMAP 同步邮件
|
||||
======
|
||||
|
||||
> 将邮件镜像保存到本地是整理消息的第一步。在我们的 20 个使用开源提升生产力的系列的第三篇文章中了解该如何做。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/20/235324nbgfyuwl98syowta.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 OfflineIMAP 在本地同步你的邮件
|
||||
|
||||
我与邮件之间存在爱恨交织的关系。我喜欢它让我与世界各地的人交流的方式。但是,像你们中的许多人一样,我收到过很多邮件,许多是来自邮件列表的,但也有很多垃圾邮件、广告等。这些积累了很多。
|
||||
|
||||
![The OfflineIMAP "blinkenlights" UI][2]
|
||||
|
||||
我尝试过的大多数工具(除了大型邮件服务商外)都可以很好地处理大量邮件,它们都有一个共同点:它们都依赖于以 [Maildir][3] 格式存储的本地邮件副本。这其中最有用的是 [OfflineIMAP][4]。OfflineIMAP 是将 IMAP 邮箱镜像到本地 Maildir 文件夹树的 Python 脚本。我用它来创建邮件的本地副本并使其保持同步。大多数 Linux 发行版都包含它,并且可以通过 Python 的 pip 包管理器获得。
|
||||
|
||||
示例的最小配置文件是一个很好的模板。首先将其复制到 `~/.offlineimaprc`。我的看起来像这样:
|
||||
|
||||
```
|
||||
[general]
|
||||
accounts = LocalSync
|
||||
ui=Quiet
|
||||
autorefresh=30
|
||||
|
||||
[Account LocalSync]
|
||||
localrepository = LocalMail
|
||||
remoterepository = MirrorIMAP
|
||||
|
||||
[Repository MirrorIMAP]
|
||||
type = IMAP
|
||||
remotehost = my.mail.server
|
||||
remoteuser = myusername
|
||||
remotepass = mypassword
|
||||
auth_mechanisms = LOGIN
|
||||
createfolder = true
|
||||
ssl = yes
|
||||
sslcacertfile = OS-DEFAULT
|
||||
|
||||
[Repository LocalMail]
|
||||
type = Maildir
|
||||
localfolders = ~/Maildir
|
||||
sep = .
|
||||
createfolder = true
|
||||
```
|
||||
|
||||
我的配置要做的是定义两个仓库:远程 IMAP 服务器和本地 Maildir 文件夹。还有一个**帐户**,告诉 OfflineIMAP 运行时要同步什么。你可以定义链接到不同仓库的多个帐户。除了本地复制外,这还允许你从一台 IMAP 服务器复制到另一台作为备份。
|
||||
|
||||
如果你有很多邮件,那么首次运行 OfflineIMAP 将花费一些时间。但是完成后,下次会花*少得多*的时间。你也可以将 OfflineIMAP 作为 cron 任务(我的偏好)或作为守护程序在仓库之间不断进行同步。其文档涵盖了所有这些内容以及 Gmail 等高级配置选项。
|
||||
|
||||
现在,我的邮件已在本地复制,并有多种工具用来加快搜索、归档和管理邮件的速度。这些我明天再说。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/sync-email-offlineimap
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/newsletter_email_mail_web_browser.jpg?itok=Lo91H9UH (email or newsletters via inbox and browser)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/productivity_3-1.png (The OfflineIMAP "blinkenlights" UI)
|
||||
[3]: https://en.wikipedia.org/wiki/Maildir
|
||||
[4]: http://www.offlineimap.org/
|
@ -0,0 +1,296 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11800-1.html)
|
||||
[#]: subject: (setV: A Bash function to maintain Python virtual environments)
|
||||
[#]: via: (https://opensource.com/article/20/1/setv-bash-function)
|
||||
[#]: author: (Sachin Patil https://opensource.com/users/psachin)
|
||||
|
||||
setV:一个管理 Python 虚拟环境的 Bash 函数
|
||||
======
|
||||
|
||||
> 了解一下 setV,它是一个轻量级的 Python 虚拟环境管理器,是 virtualenvwrapper 的替代产品。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/19/234306tvvg5ffwakrzr5vv.jpg)
|
||||
|
||||
这一年多来,我的 [bash_scripts][3] 项目中悄悄隐藏这 [setV][2],但现在是时候该公开了。setV 是一个 Bash 函数,我可以用它代替 [virtualenvwrapper][4]。它提供了使你能够执行以下操作的基本功能:
|
||||
|
||||
* 默认使用 Python 3
|
||||
* 创建一个新的虚拟环境
|
||||
* 使用带有 `-p`(或 `--python`)的自定义 Python 路径来创建新的虚拟环境
|
||||
* 删除现有的虚拟环境
|
||||
* 列出所有现有的虚拟环境
|
||||
* 使用制表符补全(以防你忘记虚拟环境名称)
|
||||
|
||||
### 安装
|
||||
|
||||
要安装 setV,请下载该脚本:
|
||||
|
||||
```
|
||||
curl https://gitlab.com/psachin/setV/raw/master/install.sh
|
||||
```
|
||||
|
||||
审核一下脚本,然后运行它:
|
||||
|
||||
```
|
||||
sh ./install.sh
|
||||
```
|
||||
|
||||
当安装 setV 时,安装脚本会要求你引入(`source`)一下 `~/.bashrc` 或 `~/.bash_profile` 的配置,根据你的喜好选择一个。
|
||||
|
||||
### 用法
|
||||
|
||||
基本的命令格式是 `setv`。
|
||||
|
||||
#### 创建虚拟环境
|
||||
|
||||
```
|
||||
setv --new rango # setv -n rango
|
||||
|
||||
# 或使用定制的 Python 路径
|
||||
setv --new --python /opt/python/python3 rango # setv -n -p /opt/python/python3 rango
|
||||
```
|
||||
|
||||
#### 激活已有的虚拟环境
|
||||
|
||||
```
|
||||
setv VIRTUAL_ENVIRONMENT_NAME
|
||||
```
|
||||
|
||||
```
|
||||
# 示例
|
||||
setv rango
|
||||
```
|
||||
|
||||
#### 列出所有的虚拟环境
|
||||
|
||||
```
|
||||
setv --list
|
||||
# 或
|
||||
setv [TAB] [TAB]
|
||||
```
|
||||
|
||||
#### 删除虚拟环境
|
||||
|
||||
```
|
||||
setv --delete rango
|
||||
```
|
||||
|
||||
#### 切换到另外一个虚拟环境
|
||||
|
||||
```
|
||||
# 假设你现在在 'rango',切换到 'tango'
|
||||
setv tango
|
||||
```
|
||||
|
||||
#### 制表符补完
|
||||
|
||||
如果你不完全记得虚拟环境的名称,则 Bash 式的制表符补全也可以适用于虚拟环境名称。
|
||||
|
||||
### 参与其中
|
||||
|
||||
setV 在 GNU [GPLv3][5]下开源,欢迎贡献。要了解更多信息,请访问它的 GitLab 存储库中的 setV 的 [README][6] 的贡献部分。
|
||||
|
||||
### setV 脚本
|
||||
|
||||
```
|
||||
#!/usr/bin/env bash
|
||||
# setV - A Lightweight Python virtual environment manager.
|
||||
# Author: Sachin (psachin) <iclcoolster@gmail.com>
|
||||
# Author's URL: https://psachin.gitlab.io/about
|
||||
#
|
||||
# License: GNU GPL v3, See LICENSE file
|
||||
#
|
||||
# Configure(Optional):
|
||||
# Set `SETV_VIRTUAL_DIR_PATH` value to your virtual environments
|
||||
# directory-path. By default it is set to '~/virtualenvs/'
|
||||
#
|
||||
# Usage:
|
||||
# Manual install: Added below line to your .bashrc or any local rc script():
|
||||
# ---
|
||||
# source /path/to/virtual.sh
|
||||
# ---
|
||||
#
|
||||
# Now you can 'activate' the virtual environment by typing
|
||||
# $ setv <YOUR VIRTUAL ENVIRONMENT NAME>
|
||||
#
|
||||
# For example:
|
||||
# $ setv rango
|
||||
#
|
||||
# or type:
|
||||
# setv [TAB] [TAB] (to list all virtual envs)
|
||||
#
|
||||
# To list all your virtual environments:
|
||||
# $ setv --list
|
||||
#
|
||||
# To create new virtual environment:
|
||||
# $ setv --new new_virtualenv_name
|
||||
#
|
||||
# To delete existing virtual environment:
|
||||
# $ setv --delete existing_virtualenv_name
|
||||
#
|
||||
# To deactivate, type:
|
||||
# $ deactivate
|
||||
|
||||
# Path to virtual environment directory
|
||||
SETV_VIRTUAL_DIR_PATH="$HOME/virtualenvs/"
|
||||
# Default python version to use. This decides whether to use `virtualenv` or `python3 -m venv`
|
||||
SETV_PYTHON_VERSION=3 # Defaults to Python3
|
||||
SETV_PY_PATH=$(which python${SETV_PYTHON_VERSION})
|
||||
|
||||
function _setvcomplete_()
|
||||
{
|
||||
# Bash-autocompletion.
|
||||
# This ensures Tab-auto-completions work for virtual environment names.
|
||||
local cmd="${1##*/}" # to handle command(s).
|
||||
# Not necessary as such. 'setv' is the only command
|
||||
|
||||
local word=${COMP_WORDS[COMP_CWORD]} # Words thats being completed
|
||||
local xpat='${word}' # Filter pattern. Include
|
||||
# only words in variable '$names'
|
||||
local names=$(ls -l "${SETV_VIRTUAL_DIR_PATH}" | egrep '^d' | awk -F " " '{print $NF}') # Virtual environment names
|
||||
|
||||
COMPREPLY=($(compgen -W "$names" -X "$xpat" -- "$word")) # compgen generates the results
|
||||
}
|
||||
|
||||
function _setv_help_() {
|
||||
# Echo help/usage message
|
||||
echo "Usage: setv [OPTIONS] [NAME]"
|
||||
echo Positional argument:
|
||||
echo -e "NAME Activate virtual env."
|
||||
echo Optional arguments:
|
||||
echo -e "-l, --list List all Virtual Envs."
|
||||
echo -e "-n, --new NAME Create a new Python Virtual Env."
|
||||
echo -e "-d, --delete NAME Delete existing Python Virtual Env."
|
||||
echo -e "-p, --python PATH Python binary path."
|
||||
}
|
||||
|
||||
function _setv_custom_python_path()
|
||||
{
|
||||
if [ -f "${1}" ];
|
||||
then
|
||||
if [ "`expr $1 : '.*python\([2,3]\)'`" = "3" ];
|
||||
then
|
||||
SETV_PYTHON_VERSION=3
|
||||
else
|
||||
SETV_PYTHON_VERSION=2
|
||||
fi
|
||||
SETV_PY_PATH=${1}
|
||||
_setv_create $2
|
||||
else
|
||||
echo "Error: Path ${1} does not exist!"
|
||||
fi
|
||||
}
|
||||
|
||||
function _setv_create()
|
||||
{
|
||||
# Creates new virtual environment if ran with -n|--new flag
|
||||
if [ -z ${1} ];
|
||||
then
|
||||
echo "You need to pass virtual environment name"
|
||||
_setv_help_
|
||||
else
|
||||
echo "Creating new virtual environment with the name: $1"
|
||||
|
||||
if [ ${SETV_PYTHON_VERSION} -eq 3 ];
|
||||
then
|
||||
${SETV_PY_PATH} -m venv ${SETV_VIRTUAL_DIR_PATH}${1}
|
||||
else
|
||||
virtualenv -p ${SETV_PY_PATH} ${SETV_VIRTUAL_DIR_PATH}${1}
|
||||
fi
|
||||
|
||||
echo "You can now activate the Python virtual environment by typing: setv ${1}"
|
||||
fi
|
||||
}
|
||||
|
||||
function _setv_delete()
|
||||
{
|
||||
# Deletes virtual environment if ran with -d|--delete flag
|
||||
# TODO: Refactor
|
||||
if [ -z ${1} ];
|
||||
then
|
||||
echo "You need to pass virtual environment name"
|
||||
_setv_help_
|
||||
else
|
||||
if [ -d ${SETV_VIRTUAL_DIR_PATH}${1} ];
|
||||
then
|
||||
read -p "Really delete this virtual environment(Y/N)? " yes_no
|
||||
case $yes_no in
|
||||
Y|y) rm -rvf ${SETV_VIRTUAL_DIR_PATH}${1};;
|
||||
N|n) echo "Leaving the virtual environment as it is.";;
|
||||
*) echo "You need to enter either Y/y or N/n"
|
||||
esac
|
||||
else
|
||||
echo "Error: No virtual environment found by the name: ${1}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function _setv_list()
|
||||
{
|
||||
# Lists all virtual environments if ran with -l|--list flag
|
||||
echo -e "List of virtual environments you have under ${SETV_VIRTUAL_DIR_PATH}:\n"
|
||||
for virt in $(ls -l "${SETV_VIRTUAL_DIR_PATH}" | egrep '^d' | awk -F " " '{print $NF}')
|
||||
do
|
||||
echo ${virt}
|
||||
done
|
||||
}
|
||||
|
||||
function setv() {
|
||||
# Main function
|
||||
if [ $# -eq 0 ];
|
||||
then
|
||||
_setv_help_
|
||||
elif [ $# -le 3 ];
|
||||
then
|
||||
case "${1}" in
|
||||
-n|--new) _setv_create ${2};;
|
||||
-d|--delete) _setv_delete ${2};;
|
||||
-l|--list) _setv_list;;
|
||||
*) if [ -d ${SETV_VIRTUAL_DIR_PATH}${1} ];
|
||||
then
|
||||
# Activate the virtual environment
|
||||
source ${SETV_VIRTUAL_DIR_PATH}${1}/bin/activate
|
||||
else
|
||||
# Else throw an error message
|
||||
echo "Sorry, you don't have any virtual environment with the name: ${1}"
|
||||
_setv_help_
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
elif [ $# -le 5 ];
|
||||
then
|
||||
case "${2}" in
|
||||
-p|--python) _setv_custom_python_path ${3} ${4};;
|
||||
*) _setv_help_;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# Calls bash-complete. The compgen command accepts most of the same
|
||||
# options that complete does but it generates results rather than just
|
||||
# storing the rules for future use.
|
||||
complete -F _setvcomplete_ setv
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/setv-bash-function
|
||||
|
||||
作者:[Sachin Patil][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/psachin
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_laptop_hack_work.png?itok=aSpcWkcl (Coding on a computer)
|
||||
[2]: https://gitlab.com/psachin/setV
|
||||
[3]: https://github.com/psachin/bash_scripts
|
||||
[4]: https://virtualenvwrapper.readthedocs.org/
|
||||
[5]: https://gitlab.com/psachin/setV/blob/master/LICENSE
|
||||
[6]: https://gitlab.com/psachin/setV/blob/master/ReadMe.org
|
||||
[7]: mailto:iclcoolster@gmail.com
|
109
published/202001/20200114 Organize your email with Notmuch.md
Normal file
109
published/202001/20200114 Organize your email with Notmuch.md
Normal file
@ -0,0 +1,109 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11807-1.html)
|
||||
[#]: subject: (Organize your email with Notmuch)
|
||||
[#]: via: (https://opensource.com/article/20/1/organize-email-notmuch)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 Notmuch 组织你的邮件
|
||||
======
|
||||
|
||||
> Notmuch 可以索引、标记和排序电子邮件。在我们的 20 个使用开源提升生产力的系列的第四篇文章中了解该如何使用它。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/22/112231xg5dgv6f6g5a1iv1.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 用 Notmuch 为你的邮件建立索引
|
||||
|
||||
昨天,我谈到了如何使用 OfflineIMAP [将我的邮件同步][2]到本地计算机。今天,我将讨论如何在阅读之前预处理所有邮件。
|
||||
|
||||
![Notmuch][3]
|
||||
|
||||
[Maildir][4] 可能是最有用的邮件存储格式之一。有很多工具可以帮助你管理邮件。我经常使用一个名为 [Notmuch][5] 的小程序,它能索引、标记和搜索邮件。Notmuch 配合其他几个程序一起使用可以使处理大量邮件更加容易。
|
||||
|
||||
大多数 Linux 发行版都包含 Notmuch,你也可以在 MacOS 上获得它。Windows 用户可以通过 Linux 的 Windows 子系统([WSL][6])访问它,但可能需要进行一些其他调整。
|
||||
|
||||
![Notmuch's first run][7]
|
||||
|
||||
Notmuch 首次运行时,它将询问你一些问题,并在家目录中创建 `.notmuch-config` 文件。接下来,运行 `notmuch new` 来索引并标记所有邮件。你可以使用 `notmuch search tag:new` 进行验证,它会找到所有带有 `new` 标签的消息。这可能会有很多邮件,因为 Notmuch 使用 `new` 标签来指示新邮件,因此你需要对其进行清理。
|
||||
|
||||
运行 `notmuch search tag:unread` 来查找未读消息,这会减少很多邮件。要从你已阅读的消息中删除 `new` 标签,请运行 `notmuch tag -new not tag:unread`,它将搜索所有没有 `unread` 标签的消息,并从其中删除 `new` 标签。现在,当你运行 `notmuch search tag:new` 时,它将仅显示未读邮件。
|
||||
|
||||
但是,批量标记消息可能更有用,因为在每次运行时手动更新标记可能非常繁琐。`--batch` 命令行选项告诉 Notmuch 读取多行命令并执行它们。还有一个 `--input=filename` 选项,该选项从文件中读取命令并应用它们。我有一个名为 `tagmail.notmuch` 的文件,用于给“新”邮件添加标签;它看起来像这样:
|
||||
|
||||
```
|
||||
# Manage sent, spam, and trash folders
|
||||
-unread -new folder:Trash
|
||||
-unread -new folder:Spam
|
||||
-unread -new folder:Sent
|
||||
|
||||
# Note mail sent specifically to me (excluding bug mail)
|
||||
+to-me to:kevin at sonney.com and tag:new and not tag:to-me
|
||||
|
||||
# And note all mail sent from me
|
||||
+sent from:kevin at sonney.com and tag:new and not tag:sent
|
||||
|
||||
# Remove the new tag from messages
|
||||
-new tag:new
|
||||
```
|
||||
|
||||
我可以在运行 `notmuch new` 后运行 `notmuch tag --input=tagmail.notmuch` 批量处理我的邮件,之后我也可以搜索这些标签。
|
||||
|
||||
Notmuch 还支持 `pre-new` 和 `post-new` 钩子。这些脚本存放在 `Maildir/.notmuch/hooks` 中,它们定义了在使用 `notmuch new` 索引新邮件之前(`pre-new`)和之后(`post-new`)要做的操作。在昨天的文章中,我谈到了使用 [OfflineIMAP][8] 同步来自 IMAP 服务器的邮件。从 `pre-new` 钩子运行它非常容易:
|
||||
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
# Remove the new tag from messages that are still tagged as new
|
||||
notmuch tag -new tag:new
|
||||
|
||||
# Sync mail messages
|
||||
offlineimap -a LocalSync -u quiet
|
||||
```
|
||||
|
||||
你还可以使用可以操作 Notmuch 数据库的 Python 应用 [afew][9],来为你标记*邮件列表*和*垃圾邮件*。你可以用类似的方法在 `post-new` 钩子中使用 `afew`:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
# tag with my custom tags
|
||||
notmuch tag --input=~/tagmail.notmuch
|
||||
|
||||
# Run afew to tag new mail
|
||||
afew -t -n
|
||||
```
|
||||
|
||||
我建议你在使用 `afew` 标记邮件时,不要使用 `[ListMailsFilter]`,因为某些邮件处理程序会在邮件中添加模糊或者彻头彻尾是垃圾的列表标头(我说的就是你 Google)。
|
||||
|
||||
![alot email client][10]
|
||||
|
||||
此时,任何支持 Notmuch 或 Maildir 的邮件阅读器都可以读取我的邮件。有时,我会使用 [alot][11](一个 Notmuch 特定的客户端)在控制台中阅读邮件,但是它不像其他邮件阅读器那么美观。
|
||||
|
||||
在接下来的几天,我将向你展示其他一些邮件客户端,它们可能会与你在使用的工具集成在一起。同时,请查看可与 Maildir 邮箱一起使用的其他工具。你可能会发现我没发现的好东西。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/organize-email-notmuch
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/files_documents_organize_letter.png?itok=GTtiiabr (Filing cabinet for organization)
|
||||
[2]: https://linux.cn/article-11804-1.html
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_4-1.png (Notmuch)
|
||||
[4]: https://en.wikipedia.org/wiki/Maildir
|
||||
[5]: https://notmuchmail.org/
|
||||
[6]: https://docs.microsoft.com/en-us/windows/wsl/install-win10
|
||||
[7]: https://opensource.com/sites/default/files/uploads/productivity_4-2.png (Notmuch's first run)
|
||||
[8]: http://www.offlineimap.org/
|
||||
[9]: https://afew.readthedocs.io/en/latest/index.html
|
||||
[10]: https://opensource.com/sites/default/files/uploads/productivity_4-3.png (alot email client)
|
||||
[11]: https://github.com/pazz/alot
|
510
published/202001/20200115 6 handy Bash scripts for Git.md
Normal file
510
published/202001/20200115 6 handy Bash scripts for Git.md
Normal file
@ -0,0 +1,510 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11797-1.html)
|
||||
[#]: subject: (6 handy Bash scripts for Git)
|
||||
[#]: via: (https://opensource.com/article/20/1/bash-scripts-git)
|
||||
[#]: author: (Bob Peterson https://opensource.com/users/bobpeterson)
|
||||
|
||||
6 个方便的 Git 脚本
|
||||
======
|
||||
|
||||
> 当使用 Git 存储库时,这六个 Bash 脚本将使你的生活更轻松。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/18/231713jegbk8fyek798gxb.jpg)
|
||||
|
||||
我编写了许多 Bash 脚本,这些脚本使我在使用 Git 存储库时工作更加轻松。我的许多同事说没有必要:我所做的一切都可以用 Git 命令完成。虽然这可能是正确的,但我发现脚本远比尝试找出适当的 Git 命令来执行我想要的操作更加方便。
|
||||
|
||||
### 1、gitlog
|
||||
|
||||
`gitlog` 打印针对 master 分支的当前补丁的简短列表。它从最旧到最新打印它们,并显示作者和描述,其中 `H` 代表 `HEAD`,`^` 代表 `HEAD^`,`2` 代表 `HEAD~2`,依此类推。例如:
|
||||
|
||||
```
|
||||
$ gitlog
|
||||
-----------------------[ recovery25 ]-----------------------
|
||||
(snip)
|
||||
11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errors
|
||||
10 9b3c4e6efb10 Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode
|
||||
9 d2e8c22be39b Bob Peterson gfs2: Do proper error checking for go_sync family of glops
|
||||
8 9563e31f8bfd Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwrite
|
||||
7 ebac7a38036c Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backing
|
||||
6 f703a3c27874 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency
|
||||
5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
|
||||
4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite
|
||||
3 4525c2f5b46f Bob Peterson Rafael Aquini's slab instrumentation
|
||||
2 a06a5b7dea02 Bob Peterson GFS2: Add go_get_holdtime to gl_ops
|
||||
^ 8ba93c796d5c Bob Peterson gfs2: introduce new function remaining_hold_time and use it in dq
|
||||
H e8b5ff851bb9 Bob Peterson gfs2: Allow rgrps to have a minimum hold time
|
||||
```
|
||||
|
||||
如果我想查看其他分支上有哪些补丁,可以指定一个替代分支:
|
||||
|
||||
```
|
||||
$ gitlog recovery24
|
||||
```
|
||||
|
||||
### 2、gitlog.id
|
||||
|
||||
`gitlog.id` 只是打印出补丁的 SHA1 ID:
|
||||
|
||||
```
|
||||
$ gitlog.id
|
||||
-----------------------[ recovery25 ]-----------------------
|
||||
56908eeb6940 2ca4a6b628a1 fc64ad5d99fe 02031a00a251 f6f38da7dd18 d8546e8f0023 fc3cc1f98f6b 12c3e0cb3523 76cce178b134 6fc1dce3ab9c 1b681ab074ca 26fed8de719b 802ff51a5670 49f67a512d8c f04f20193bbb 5f6afe809d23 2030521dc70e dada79b3be94 9b19a1e08161 78a035041d3e f03da011cae2 0d2b2e068fcd 2449976aa133 57dfb5e12ccd 53abedfdcf72 6fbdda3474b3 49544a547188 187032f7a63c 6f75dae23d93 95fc2a261b00 ebfb14ded191 f653ee9e414a 0e2911cb8111 73968b76e2e3 8a3e4cb5e92c a5f2da803b5b 7c9ef68388ed 71ca19d0cba8 340d27a33895 9b3c4e6efb10 d2e8c22be39b 9563e31f8bfd ebac7a38036c f703a3c27874 a3e86d2ef30e da3c604755b0 4525c2f5b46f a06a5b7dea02 8ba93c796d5c e8b5ff851bb9
|
||||
```
|
||||
|
||||
同样,它假定是当前分支,但是如果需要,我可以指定其他分支。
|
||||
|
||||
### 3、gitlog.id2
|
||||
|
||||
`gitlog.id2` 与 `gitlog.id` 相同,但顶部没有显示分支的行。这对于从一个分支挑选所有补丁到当前分支很方便:
|
||||
|
||||
```
|
||||
$ # 创建一个新分支
|
||||
$ git branch --track origin/master
|
||||
$ # 检出刚刚创建的新分支
|
||||
$ git checkout recovery26
|
||||
$ # 从旧的分支挑选所有补丁到新分支
|
||||
$ for i in `gitlog.id2 recovery25` ; do git cherry-pick $i ;done
|
||||
```
|
||||
|
||||
### 4、gitlog.grep
|
||||
|
||||
`gitlog.grep` 会在该补丁集合中寻找一个字符串。例如,如果我发现一个错误并想修复引用了函数 `inode_go_sync` 的补丁,我可以简单地执行以下操作:
|
||||
|
||||
```
|
||||
$ gitlog.grep inode_go_sync
|
||||
-----------------------[ recovery25 - 50 patches ]-----------------------
|
||||
(snip)
|
||||
11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errors
|
||||
10 9b3c4e6efb10 Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode
|
||||
9 d2e8c22be39b Bob Peterson gfs2: Do proper error checking for go_sync family of glops
|
||||
152:-static void inode_go_sync(struct gfs2_glock *gl)
|
||||
153:+static int inode_go_sync(struct gfs2_glock *gl)
|
||||
163:@@ -296,6 +302,7 @@ static void inode_go_sync(struct gfs2_glock *gl)
|
||||
8 9563e31f8bfd Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwrite
|
||||
7 ebac7a38036c Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backing
|
||||
6 f703a3c27874 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency
|
||||
5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
|
||||
4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite
|
||||
3 4525c2f5b46f Bob Peterson Rafael Aquini's slab instrumentation
|
||||
2 a06a5b7dea02 Bob Peterson GFS2: Add go_get_holdtime to gl_ops
|
||||
^ 8ba93c796d5c Bob Peterson gfs2: introduce new function remaining_hold_time and use it in dq
|
||||
H e8b5ff851bb9 Bob Peterson gfs2: Allow rgrps to have a minimum hold time
|
||||
```
|
||||
|
||||
因此,现在我知道补丁 `HEAD~9` 是需要修复的补丁。我使用 `git rebase -i HEAD~10` 编辑补丁 9,`git commit -a --amend`,然后 `git rebase --continue` 以进行必要的调整。
|
||||
|
||||
### 5、gitbranchcmp3
|
||||
|
||||
`gitbranchcmp3` 使我可以将当前分支与另一个分支进行比较,因此我可以将较旧版本的补丁与我的较新版本进行比较,并快速查看已更改和未更改的内容。它生成一个比较脚本(使用了 KDE 工具 [Kompare][2],该工具也可在 GNOME3 上使用)以比较不太相同的补丁。如果除行号外没有其他差异,则打印 `[SAME]`。如果仅存在注释差异,则打印 `[same]`(小写)。例如:
|
||||
|
||||
```
|
||||
$ gitbranchcmp3 recovery24
|
||||
Branch recovery24 has 47 patches
|
||||
Branch recovery25 has 50 patches
|
||||
|
||||
(snip)
|
||||
38 87eb6901607a 340d27a33895 [same] gfs2: drain the ail2 list after io errors
|
||||
39 90fefb577a26 9b3c4e6efb10 [same] gfs2: clean up iopen glock mess in gfs2_create_inode
|
||||
40 ba3ae06b8b0e d2e8c22be39b [same] gfs2: Do proper error checking for go_sync family of glops
|
||||
41 2ab662294329 9563e31f8bfd [SAME] gfs2: use page_offset in gfs2_page_mkwrite
|
||||
42 0adc6d817b7a ebac7a38036c [SAME] gfs2: don't use buffer_heads in gfs2_allocate_page_backing
|
||||
43 55ef1f8d0be8 f703a3c27874 [SAME] gfs2: Improve mmap write vs. punch_hole consistency
|
||||
44 de57c2f72570 a3e86d2ef30e [SAME] gfs2: Multi-block allocations in gfs2_page_mkwrite
|
||||
45 7c5305fbd68a da3c604755b0 [SAME] gfs2: Fix end-of-file handling in gfs2_page_mkwrite
|
||||
46 162524005151 4525c2f5b46f [SAME] Rafael Aquini's slab instrumentation
|
||||
47 a06a5b7dea02 [ ] GFS2: Add go_get_holdtime to gl_ops
|
||||
48 8ba93c796d5c [ ] gfs2: introduce new function remaining_hold_time and use it in dq
|
||||
49 e8b5ff851bb9 [ ] gfs2: Allow rgrps to have a minimum hold time
|
||||
|
||||
Missing from recovery25:
|
||||
The missing:
|
||||
Compare script generated at: /tmp/compare_mismatches.sh
|
||||
```
|
||||
|
||||
### 6、gitlog.find
|
||||
|
||||
最后,我有一个 `gitlog.find` 脚本,可以帮助我识别补丁程序的上游版本在哪里以及每个补丁的当前状态。它通过匹配补丁说明来实现。它还会生成一个比较脚本(再次使用了 Kompare),以将当前补丁与上游对应补丁进行比较:
|
||||
|
||||
```
|
||||
$ gitlog.find
|
||||
-----------------------[ recovery25 - 50 patches ]-----------------------
|
||||
(snip)
|
||||
11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errors
|
||||
lo 5bcb9be74b2a Bob Peterson gfs2: drain the ail2 list after io errors
|
||||
10 9b3c4e6efb10 Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode
|
||||
fn 2c47c1be51fb Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode
|
||||
9 d2e8c22be39b Bob Peterson gfs2: Do proper error checking for go_sync family of glops
|
||||
lo feb7ea639472 Bob Peterson gfs2: Do proper error checking for go_sync family of glops
|
||||
8 9563e31f8bfd Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwrite
|
||||
ms f3915f83e84c Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwrite
|
||||
7 ebac7a38036c Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backing
|
||||
ms 35af80aef99b Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backing
|
||||
6 f703a3c27874 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency
|
||||
fn 39c3a948ecf6 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency
|
||||
5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
|
||||
fn f53056c43063 Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
|
||||
4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite
|
||||
fn 184b4e60853d Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite
|
||||
3 4525c2f5b46f Bob Peterson Rafael Aquini's slab instrumentation
|
||||
Not found upstream
|
||||
2 a06a5b7dea02 Bob Peterson GFS2: Add go_get_holdtime to gl_ops
|
||||
Not found upstream
|
||||
^ 8ba93c796d5c Bob Peterson gfs2: introduce new function remaining_hold_time and use it in dq
|
||||
Not found upstream
|
||||
H e8b5ff851bb9 Bob Peterson gfs2: Allow rgrps to have a minimum hold time
|
||||
Not found upstream
|
||||
Compare script generated: /tmp/compare_upstream.sh
|
||||
```
|
||||
|
||||
补丁显示为两行,第一行是你当前的修补程序,然后是相应的上游补丁,以及 2 个字符的缩写,以指示其上游状态:
|
||||
|
||||
* `lo` 表示补丁仅在本地(`local`)上游 Git 存储库中(即尚未推送到上游)。
|
||||
* `ms` 表示补丁位于 Linus Torvald 的主(`master`)分支中。
|
||||
* `fn` 意味着补丁被推送到我的 “for-next” 开发分支,用于下一个上游合并窗口。
|
||||
|
||||
我的一些脚本根据我通常使用 Git 的方式做出假设。例如,当搜索上游补丁时,它使用我众所周知的 Git 树的位置。因此,你需要调整或改进它们以适合你的条件。`gitlog.find` 脚本旨在仅定位 [GFS2][3] 和 [DLM][4] 补丁,因此,除非你是 GFS2 开发人员,否则你需要针对你感兴趣的组件对其进行自定义。
|
||||
|
||||
### 源代码
|
||||
|
||||
以下是这些脚本的源代码。
|
||||
|
||||
#### 1、gitlog
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
branch=$1
|
||||
|
||||
if test "x$branch" = x; then
|
||||
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
|
||||
fi
|
||||
|
||||
patches=0
|
||||
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
|
||||
LIST=`git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '`
|
||||
for i in $LIST; do patches=$(echo $patches + 1 | bc);done
|
||||
|
||||
if [[ $branch =~ .*for-next.* ]]
|
||||
then
|
||||
start=HEAD
|
||||
# start=origin/for-next
|
||||
else
|
||||
start=origin/master
|
||||
fi
|
||||
|
||||
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
|
||||
/usr/bin/echo "-----------------------[" $branch "]-----------------------"
|
||||
patches=$(echo $patches - 1 | bc);
|
||||
for i in $LIST; do
|
||||
if [ $patches -eq 1 ]; then
|
||||
cnt=" ^"
|
||||
elif [ $patches -eq 0 ]; then
|
||||
cnt=" H"
|
||||
else
|
||||
if [ $patches -lt 10 ]; then
|
||||
cnt=" $patches"
|
||||
else
|
||||
cnt="$patches"
|
||||
fi
|
||||
fi
|
||||
/usr/bin/git show --abbrev-commit -s --pretty=format:"$cnt %h %<|(32)%an %s %n" $i
|
||||
patches=$(echo $patches - 1 | bc)
|
||||
done
|
||||
#git log --reverse --abbrev-commit --pretty=format:"%h %<|(32)%an %s" $tracking..$branch
|
||||
#git log --reverse --abbrev-commit --pretty=format:"%h %<|(32)%an %s" ^origin/master ^linux-gfs2/for-next $branch
|
||||
```
|
||||
|
||||
#### 2、gitlog.id
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
branch=$1
|
||||
|
||||
if test "x$branch" = x; then
|
||||
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
|
||||
fi
|
||||
|
||||
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
|
||||
/usr/bin/echo "-----------------------[" $branch "]-----------------------"
|
||||
git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
|
||||
```
|
||||
|
||||
#### 3、gitlog.id2
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
branch=$1
|
||||
|
||||
if test "x$branch" = x; then
|
||||
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
|
||||
fi
|
||||
|
||||
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
|
||||
```
|
||||
|
||||
#### 4、gitlog.grep
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
param1=$1
|
||||
param2=$2
|
||||
|
||||
if test "x$param2" = x; then
|
||||
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
|
||||
string=$param1
|
||||
else
|
||||
branch=$param1
|
||||
string=$param2
|
||||
fi
|
||||
|
||||
patches=0
|
||||
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
|
||||
LIST=`git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '`
|
||||
for i in $LIST; do patches=$(echo $patches + 1 | bc);done
|
||||
/usr/bin/echo "-----------------------[" $branch "-" $patches "patches ]-----------------------"
|
||||
patches=$(echo $patches - 1 | bc);
|
||||
for i in $LIST; do
|
||||
if [ $patches -eq 1 ]; then
|
||||
cnt=" ^"
|
||||
elif [ $patches -eq 0 ]; then
|
||||
cnt=" H"
|
||||
else
|
||||
if [ $patches -lt 10 ]; then
|
||||
cnt=" $patches"
|
||||
else
|
||||
cnt="$patches"
|
||||
fi
|
||||
fi
|
||||
/usr/bin/git show --abbrev-commit -s --pretty=format:"$cnt %h %<|(32)%an %s" $i
|
||||
/usr/bin/git show --pretty=email --patch-with-stat $i | grep -n "$string"
|
||||
patches=$(echo $patches - 1 | bc)
|
||||
done
|
||||
```
|
||||
|
||||
#### 5、gitbranchcmp3
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
#
|
||||
# gitbranchcmp3 <old branch> [<new_branch>]
|
||||
#
|
||||
oldbranch=$1
|
||||
newbranch=$2
|
||||
script=/tmp/compare_mismatches.sh
|
||||
|
||||
/usr/bin/rm -f $script
|
||||
echo "#!/bin/bash" > $script
|
||||
/usr/bin/chmod 755 $script
|
||||
echo "# Generated by gitbranchcmp3.sh" >> $script
|
||||
echo "# Run this script to compare the mismatched patches" >> $script
|
||||
echo " " >> $script
|
||||
echo "function compare_them()" >> $script
|
||||
echo "{" >> $script
|
||||
echo " git show --pretty=email --patch-with-stat \$1 > /tmp/gronk1" >> $script
|
||||
echo " git show --pretty=email --patch-with-stat \$2 > /tmp/gronk2" >> $script
|
||||
echo " kompare /tmp/gronk1 /tmp/gronk2" >> $script
|
||||
echo "}" >> $script
|
||||
echo " " >> $script
|
||||
|
||||
if test "x$newbranch" = x; then
|
||||
newbranch=`git branch -a | grep "*" | cut -d ' ' -f2`
|
||||
fi
|
||||
|
||||
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
|
||||
declare -a oldsha1s=(`git log --reverse --abbrev-commit --pretty=oneline $tracking..$oldbranch | cut -d ' ' -f1 |paste -s -d ' '`)
|
||||
declare -a newsha1s=(`git log --reverse --abbrev-commit --pretty=oneline $tracking..$newbranch | cut -d ' ' -f1 |paste -s -d ' '`)
|
||||
|
||||
#echo "old: " $oldsha1s
|
||||
oldcount=${#oldsha1s[@]}
|
||||
echo "Branch $oldbranch has $oldcount patches"
|
||||
oldcount=$(echo $oldcount - 1 | bc)
|
||||
#for o in `seq 0 ${#oldsha1s[@]}`; do
|
||||
# echo -n ${oldsha1s[$o]} " "
|
||||
# desc=`git show $i | head -5 | tail -1|cut -b5-`
|
||||
#done
|
||||
|
||||
#echo "new: " $newsha1s
|
||||
newcount=${#newsha1s[@]}
|
||||
echo "Branch $newbranch has $newcount patches"
|
||||
newcount=$(echo $newcount - 1 | bc)
|
||||
#for o in `seq 0 ${#newsha1s[@]}`; do
|
||||
# echo -n ${newsha1s[$o]} " "
|
||||
# desc=`git show $i | head -5 | tail -1|cut -b5-`
|
||||
#done
|
||||
echo
|
||||
|
||||
for new in `seq 0 $newcount`; do
|
||||
newsha=${newsha1s[$new]}
|
||||
newdesc=`git show $newsha | head -5 | tail -1|cut -b5-`
|
||||
oldsha=" "
|
||||
same="[ ]"
|
||||
for old in `seq 0 $oldcount`; do
|
||||
if test "${oldsha1s[$old]}" = "match"; then
|
||||
continue;
|
||||
fi
|
||||
olddesc=`git show ${oldsha1s[$old]} | head -5 | tail -1|cut -b5-`
|
||||
if test "$olddesc" = "$newdesc" ; then
|
||||
oldsha=${oldsha1s[$old]}
|
||||
#echo $oldsha
|
||||
git show $oldsha |tail -n +2 |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk1
|
||||
git show $newsha |tail -n +2 |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk2
|
||||
diff /tmp/gronk1 /tmp/gronk2 &> /dev/null
|
||||
if [ $? -eq 0 ] ;then
|
||||
# No differences
|
||||
same="[SAME]"
|
||||
oldsha1s[$old]="match"
|
||||
break
|
||||
fi
|
||||
git show $oldsha |sed -n '/diff/,$p' |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk1
|
||||
git show $newsha |sed -n '/diff/,$p' |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk2
|
||||
diff /tmp/gronk1 /tmp/gronk2 &> /dev/null
|
||||
if [ $? -eq 0 ] ;then
|
||||
# Differences in comments only
|
||||
same="[same]"
|
||||
oldsha1s[$old]="match"
|
||||
break
|
||||
fi
|
||||
oldsha1s[$old]="match"
|
||||
echo "compare_them $oldsha $newsha" >> $script
|
||||
fi
|
||||
done
|
||||
echo "$new $oldsha $newsha $same $newdesc"
|
||||
done
|
||||
|
||||
echo
|
||||
echo "Missing from $newbranch:"
|
||||
the_missing=""
|
||||
# Now run through the olds we haven't matched up
|
||||
for old in `seq 0 $oldcount`; do
|
||||
if test ${oldsha1s[$old]} != "match"; then
|
||||
olddesc=`git show ${oldsha1s[$old]} | head -5 | tail -1|cut -b5-`
|
||||
echo "${oldsha1s[$old]} $olddesc"
|
||||
the_missing=`echo "$the_missing ${oldsha1s[$old]}"`
|
||||
fi
|
||||
done
|
||||
|
||||
echo "The missing: " $the_missing
|
||||
echo "Compare script generated at: $script"
|
||||
#git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
|
||||
```
|
||||
|
||||
#### 6、gitlog.find
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
#
|
||||
# Find the upstream equivalent patch
|
||||
#
|
||||
# gitlog.find
|
||||
#
|
||||
cwd=$PWD
|
||||
param1=$1
|
||||
ubranch=$2
|
||||
patches=0
|
||||
script=/tmp/compare_upstream.sh
|
||||
echo "#!/bin/bash" > $script
|
||||
/usr/bin/chmod 755 $script
|
||||
echo "# Generated by gitbranchcmp3.sh" >> $script
|
||||
echo "# Run this script to compare the mismatched patches" >> $script
|
||||
echo " " >> $script
|
||||
echo "function compare_them()" >> $script
|
||||
echo "{" >> $script
|
||||
echo " cwd=$PWD" >> $script
|
||||
echo " git show --pretty=email --patch-with-stat \$2 > /tmp/gronk2" >> $script
|
||||
echo " cd ~/linux.git/fs/gfs2" >> $script
|
||||
echo " git show --pretty=email --patch-with-stat \$1 > /tmp/gronk1" >> $script
|
||||
echo " cd $cwd" >> $script
|
||||
echo " kompare /tmp/gronk1 /tmp/gronk2" >> $script
|
||||
echo "}" >> $script
|
||||
echo " " >> $script
|
||||
|
||||
#echo "Gathering upstream patch info. Please wait."
|
||||
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
|
||||
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
|
||||
cd ~/linux.git
|
||||
if test "X${ubranch}" = "X"; then
|
||||
ubranch=`git branch -a | grep "*" | cut -d ' ' -f2`
|
||||
fi
|
||||
utracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
|
||||
#
|
||||
# gather a list of gfs2 patches from master just in case we can't find it
|
||||
#
|
||||
#git log --abbrev-commit --pretty=format:" %h %<|(32)%an %s" master |grep -i -e "gfs2" -e "dlm" > /tmp/gronk
|
||||
git log --reverse --abbrev-commit --pretty=format:"ms %h %<|(32)%an %s" master fs/gfs2/ > /tmp/gronk.gfs2
|
||||
# ms = in Linus's master
|
||||
git log --reverse --abbrev-commit --pretty=format:"ms %h %<|(32)%an %s" master fs/dlm/ > /tmp/gronk.dlm
|
||||
|
||||
cd $cwd
|
||||
LIST=`git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '`
|
||||
for i in $LIST; do patches=$(echo $patches + 1 | bc);done
|
||||
/usr/bin/echo "-----------------------[" $branch "-" $patches "patches ]-----------------------"
|
||||
patches=$(echo $patches - 1 | bc);
|
||||
for i in $LIST; do
|
||||
if [ $patches -eq 1 ]; then
|
||||
cnt=" ^"
|
||||
elif [ $patches -eq 0 ]; then
|
||||
cnt=" H"
|
||||
else
|
||||
if [ $patches -lt 10 ]; then
|
||||
cnt=" $patches"
|
||||
else
|
||||
cnt="$patches"
|
||||
fi
|
||||
fi
|
||||
/usr/bin/git show --abbrev-commit -s --pretty=format:"$cnt %h %<|(32)%an %s" $i
|
||||
desc=`/usr/bin/git show --abbrev-commit -s --pretty=format:"%s" $i`
|
||||
cd ~/linux.git
|
||||
cmp=1
|
||||
up_eq=`git log --reverse --abbrev-commit --pretty=format:"lo %h %<|(32)%an %s" $utracking..$ubranch | grep "$desc"`
|
||||
# lo = in local for-next
|
||||
if test "X$up_eq" = "X"; then
|
||||
up_eq=`git log --reverse --abbrev-commit --pretty=format:"fn %h %<|(32)%an %s" master..$utracking | grep "$desc"`
|
||||
# fn = in for-next for next merge window
|
||||
if test "X$up_eq" = "X"; then
|
||||
up_eq=`grep "$desc" /tmp/gronk.gfs2`
|
||||
if test "X$up_eq" = "X"; then
|
||||
up_eq=`grep "$desc" /tmp/gronk.dlm`
|
||||
if test "X$up_eq" = "X"; then
|
||||
up_eq=" Not found upstream"
|
||||
cmp=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo "$up_eq"
|
||||
if [ $cmp -eq 1 ] ; then
|
||||
UP_SHA1=`echo $up_eq|cut -d' ' -f2`
|
||||
echo "compare_them $UP_SHA1 $i" >> $script
|
||||
fi
|
||||
cd $cwd
|
||||
patches=$(echo $patches - 1 | bc)
|
||||
done
|
||||
echo "Compare script generated: $script"
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/bash-scripts-git
|
||||
|
||||
作者:[Bob Peterson][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/bobpeterson
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003588_01_rd3os.combacktoschoolseriesk12_rh_021x_0.png?itok=fvorN0e- (Digital hand surrounding by objects, bike, light bulb, graphs)
|
||||
[2]: https://kde.org/applications/development/org.kde.kompare
|
||||
[3]: https://en.wikipedia.org/wiki/GFS2
|
||||
[4]: https://en.wikipedia.org/wiki/Distributed_lock_manager
|
@ -0,0 +1,106 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11812-1.html)
|
||||
[#]: subject: (Organize and sync your calendar with khal and vdirsyncer)
|
||||
[#]: via: (https://opensource.com/article/20/1/open-source-calendar)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 khal 和 vdirsyncer 组织和同步你的日历
|
||||
======
|
||||
|
||||
> 保存和共享日历可能会有点麻烦。在我们的 20 个使用开源提升生产力的系列的第五篇文章中了解如何让它更简单。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/23/150009wsr3d5ovg4g1vzws.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 khal 和 vdirsyncer 跟踪你的日程
|
||||
|
||||
处理日历很*麻烦*,要找到好的工具总是很困难的。但是自从我去年将日历列为[我的“失败"之一][2]以来,我已经取得了一些进步。
|
||||
|
||||
目前使用日历最困难的是一直需要以某种方式在线共享。两种最受欢迎的在线日历是 Google Calendar 和 Microsoft Outlook/Exchange。两者都在公司环境中大量使用,这意味着我的日历必须支持其中之一或者两个。
|
||||
|
||||
![khal calendar][3]
|
||||
|
||||
[Khal][4] 是基于控制台的日历,可以读取和写入 VCalendar 文件。它配置相当容易,但是不支持与其他应用同步。
|
||||
|
||||
幸运的是,khal 能与 [vdirsyncer][5] 一起使用,它是一个漂亮的命令行程序,可以将在线日历(和联系人,我将在另一篇文章中讨论)同步到本地磁盘。是的,它还可以上传新事件。
|
||||
|
||||
![vdirsyncer][6]
|
||||
|
||||
Vdirsyncer 是个 Python 3 程序,可以通过软件包管理器或 `pip` 安装。它可以同步 CalDAV、VCalendar/iCalendar、Google Calendar 和目录中的本地文件。由于我使用 Google Calendar,尽管这不是最简单的设置,我也将以它为例。
|
||||
|
||||
在 vdirsyncer 中设置 Google Calendar 是[有文档参考的][7],所以这里我不再赘述。重要的是确保设置你的同步对,将 Google Calendar 设置为冲突解决的“赢家”。也就是说,如果同一事件有两个更新,那么需要知道哪个更新优先。类似这样做:
|
||||
|
||||
```
|
||||
[general]
|
||||
status_path = "~/.calendars/status"
|
||||
|
||||
[pair personal_sync]
|
||||
a = "personal"
|
||||
b = "personallocal"
|
||||
collections = ["from a", "from b"]
|
||||
conflict_resolution = "a wins"
|
||||
metadata = ["color"]
|
||||
|
||||
[storage personal]
|
||||
type = "google_calendar"
|
||||
token_file = "~/.vdirsyncer/google_calendar_token"
|
||||
client_id = "google_client_id"
|
||||
client_secret = "google_client_secret"
|
||||
|
||||
[storage personallocal]
|
||||
type = "filesystem"
|
||||
path = "~/.calendars/Personal"
|
||||
fileext = ".ics"
|
||||
```
|
||||
|
||||
在第一次 vdirsyncer 同步之后,你将在存储路径中看到一系列目录。每个文件夹都将包含多个文件,日历中的每个事件都是一个文件。下一步是导入 khal。首先运行 `khal configure` 进行初始设置。
|
||||
|
||||
![Configuring khal][8]
|
||||
|
||||
现在,运行 `khal interactive` 将显示本文开头的界面。输入 `n` 将打开“新事件”对话框。这里要注意的一件事:日历的名称与 vdirsyncer 创建的目录匹配,但是你可以更改 khal 配置文件来指定更清晰的名称。根据条目所在的日历,向条目添加颜色还可以帮助你确定日历内容:
|
||||
|
||||
```
|
||||
[calendars]
|
||||
[[personal]]
|
||||
path = ~/.calendars/Personal/kevin@sonney.com/
|
||||
color = light magenta
|
||||
[[holidays]]
|
||||
path = ~/.calendars/Personal/cln2stbjc4hmgrrcd5i62ua0ctp6utbg5pr2sor1dhimsp31e8n6errfctm6abj3dtmg@virtual/
|
||||
color = light blue
|
||||
[[birthdays]]
|
||||
path = ~/.calendars/Personal/c5i68sj5edpm4rrfdchm6rreehgm6t3j81jn4rrle0n7cbj3c5m6arj4c5p2sprfdtjmop9ecdnmq@virtual/
|
||||
color = brown
|
||||
```
|
||||
|
||||
现在,当你运行 `khal interactive` 时,每个日历将被着色以区别于其他日历,并且当你添加新条目时,它将有更具描述性的名称。
|
||||
|
||||
![Adding a new calendar entry][9]
|
||||
|
||||
设置有些麻烦,但是完成后,khal 和 vdirsyncer 可以一起为你提供一种简便的方法来管理日历事件并使它们与你的在线服务保持同步。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/open-source-calendar
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/calendar.jpg?itok=jEKbhvDT (Calendar close up snapshot)
|
||||
[2]: https://opensource.com/article/19/1/productivity-tool-wish-list
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_5-1.png (khal calendar)
|
||||
[4]: https://khal.readthedocs.io/en/v0.9.2/index.html
|
||||
[5]: https://github.com/pimutils/vdirsyncer
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_5-2.png (vdirsyncer)
|
||||
[7]: https://vdirsyncer.pimutils.org/en/stable/config.html#google
|
||||
[8]: https://opensource.com/sites/default/files/uploads/productivity_5-3.png (Configuring khal)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/productivity_5-4.png
|
@ -0,0 +1,169 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11837-1.html)
|
||||
[#]: subject: (Root User in Ubuntu: Important Things You Should Know)
|
||||
[#]: via: (https://itsfoss.com/root-user-ubuntu/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
Ubuntu 中的 root 用户:你应该知道的重要事情
|
||||
======
|
||||
|
||||
![][5]
|
||||
|
||||
当你刚开始使用 Linux 时,你将发现与 Windows 的很多不同。其中一个“不同的东西”是 root 用户的概念。
|
||||
|
||||
在这个初学者系列中,我将解释几个关于 Ubuntu 的 root 用户的重要的东西。
|
||||
|
||||
**请记住,尽管我正在从 Ubuntu 用户的角度编写这篇文章,它应该对大多数的 Linux 发行版也是有效的。**
|
||||
|
||||
你将在这篇文章中学到下面的内容:
|
||||
|
||||
* 为什么在 Ubuntu 中禁用 root 用户
|
||||
* 像 root 用户一样使用命
|
||||
* 切换为 root 用户
|
||||
* 解锁 root 用户
|
||||
|
||||
### 什么是 root 用户?为什么它在 Ubuntu 中被锁定?
|
||||
|
||||
在 Linux 中,有一个称为 [root][6] 的超级用户。这是超级管理员账号,它可以做任何事以及使用系统的一切东西。它可以在你的 Linux 系统上访问任何文件和运行任何命令。
|
||||
|
||||
能力越大,责任越大。root 用户给予你完全控制系统的能力,因此,它应该被谨慎地使用。root 用户可以访问系统文件,运行更改系统配置的命令。因此,一个错误的命令可能会破坏系统。
|
||||
|
||||
这就是为什么 [Ubuntu][7] 和其它基于 Ubuntu 的发行版默认锁定 root 用户,以从意外的灾难中挽救你的原因。
|
||||
|
||||
对于你的日常任务,像移动你家目录中的文件,从互联网下载文件,创建文档等等,你不需要拥有 root 权限。
|
||||
|
||||
**打个比方来更好地理解它。假设你想要切一个水果,你可以使用一把厨房用刀。假设你想要砍一颗树,你就得使用一把锯子。现在,你可以使用锯子来切水果,但是那不明智,不是吗?**_
|
||||
|
||||
这意味着,你不能是 Ubuntu 中 root 用户或者不能使用 root 权限来使用系统吗?不,你仍然可以在 `sudo` 的帮助下来拥有 root 权限来访问(在下一节中解释)。
|
||||
|
||||
> **要点:** 使用于常规任务,root 用户权限太过强大。这就是为什么不建议一直使用 root 用户。你仍然可以使用 root 用户来运行特殊的命令。
|
||||
|
||||
### 如何在 Ubuntu 中像 root 用户一样运行命令?
|
||||
|
||||
![Image Credit: xkcd][8]
|
||||
|
||||
对于一些系统的特殊任务来说,你将需要 root 权限。例如。如果你想[通过命令行更新 Ubuntu][9],你不能作为一个常规用户运行该命令。它将给出权限被拒绝的错误。
|
||||
|
||||
```
|
||||
apt update
|
||||
Reading package lists... Done
|
||||
E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
|
||||
E: Unable to lock directory /var/lib/apt/lists/
|
||||
W: Problem unlinking the file /var/cache/apt/pkgcache.bin - RemoveCaches (13: Permission denied)
|
||||
W: Problem unlinking the file /var/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied)
|
||||
```
|
||||
|
||||
那么,你如何像 root 用户一样运行命令?简单的答案是,在命令前添加 `sudo`,来像 root 用户一样运行。
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
```
|
||||
|
||||
Ubuntu 和很多其它的 Linux 发行版使用一个被称为 `sudo` 的特殊程序机制。`sudo` 是一个以 root 用户(或其它用户)来控制运行命令访问的程序。
|
||||
|
||||
实际上,`sudo` 是一个非常多用途的工具。它可以配置为允许一个用户像 root 用户一样来运行所有的命令,或者仅仅一些命令。你也可以配置为无需密码即可使用 sudo 运行命令。这个主题内容比较丰富,也许我将在另一篇文章中详细讨论它。
|
||||
|
||||
就目前而言,你应该知道[当你安装 Ubuntu 时][10],你必须创建一个用户账号。这个用户账号在你系统上以管理员身份来工作,并且按照 Ubuntu 中的默认 sudo 策略,它可以在你的系统上使用 root 用户权限来运行任何命令。
|
||||
|
||||
`sudo` 的问题是,运行 **sudo 不需要 root 用户密码,而是需要用户自己的密码**。
|
||||
|
||||
并且这就是为什么当你使用 `sudo` 运行一个命令,会要求输入正在运行 `sudo` 命令的用户的密码的原因:
|
||||
|
||||
```
|
||||
[email protected]:~$ sudo apt update
|
||||
[sudo] password for abhishek:
|
||||
```
|
||||
|
||||
正如你在上面示例中所见 `abhishek` 在尝试使用 `sudo` 来运行 `apt update` 命令,系统要求输入 `abhishek` 的密码。
|
||||
|
||||
**如果你对 Linux 完全不熟悉,当你在终端中开始输入密码时,你可能会惊讶,在屏幕上什么都没有发生。这是十分正常的,因为作为默认的安全功能,在屏幕上什么都不会显示。甚至星号(`*`)都没有。输入你的密码并按回车键。**
|
||||
|
||||
> **要点:**为在 Ubuntu 中像 root 用户一样运行命令,在命令前添加 `sudo`。 当被要求输入密码时,输入你的账户的密码。当你在屏幕上输入密码时,什么都看不到。请继续输入密码,并按回车键。
|
||||
|
||||
### 如何在 Ubuntu 中成为 root 用户?
|
||||
|
||||
你可以使用 `sudo` 来像 root 用户一样运行命令。但是,在某些情况下,你必须以 root 用户身份来运行一些命令,而你总是忘了在命令前添加 `sudo`,那么你可以临时切换为 root 用户。
|
||||
|
||||
`sudo` 命令允许你来模拟一个 root 用户登录的 shell ,使用这个命令:
|
||||
|
||||
```
|
||||
sudo -i
|
||||
```
|
||||
|
||||
```
|
||||
[email protected]:~$ sudo -i
|
||||
[sudo] password for abhishek:
|
||||
[email protected]:~# whoami
|
||||
root
|
||||
[email protected]:~#
|
||||
```
|
||||
|
||||
你将注意到,当你切换为 root 用户时,shell 命令提示符从 `$`(美元符号)更改为 `#`(英镑符号)。我开个(拙劣的)玩笑,英镑比美元强大。
|
||||
|
||||
**虽然我已经向你显示如何成为 root 用户,但是我必须警告你,你应该避免作为 root 用户使用系统。毕竟它有阻拦你使用 root 用户的原因。**
|
||||
|
||||
另外一种临时切换为 root 用户的方法是使用 `su` 命令:
|
||||
|
||||
```
|
||||
sudo su
|
||||
```
|
||||
|
||||
如果你尝试使用不带有的 `sudo` 的 `su` 命令,你将遇到 “su authentication failure” 错误。
|
||||
|
||||
你可以使用 `exit` 命令来恢复为正常用户。
|
||||
|
||||
```
|
||||
exit
|
||||
```
|
||||
|
||||
### 如何在 Ubuntu 中启用 root 用户?
|
||||
|
||||
现在你知道,root 用户在基于 Ubuntu 发行版中是默认锁定的。
|
||||
|
||||
Linux 给予你在系统上想做什么就做什么的自由。解锁 root 用户就是这些自由之一。
|
||||
|
||||
如果出于某些原因,你决定启用 root 用户,你可以通过为其设置一个密码来做到:
|
||||
|
||||
```
|
||||
sudo passwd root
|
||||
```
|
||||
|
||||
再强调一次,不建议使用 root 用户,并且我也不鼓励你在桌面上这样做。如果你忘记了密码,你将不能再次[在 Ubuntu 中更改 root 用户密码][11]。(LCTT 译注:可以通过单用户模式修改。)
|
||||
|
||||
你可以通过移除密码来再次锁定 root 用户:
|
||||
|
||||
```
|
||||
sudo passwd -dl root
|
||||
```
|
||||
|
||||
### 最后…
|
||||
|
||||
我希望你现在对 root 概念理解得更好一点。如果你仍然有些关于它的困惑和问题,请在评论中让我知道。我将尝试回答你的问题,并且也可能更新这篇文章。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/root-user-ubuntu/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: tmp.IrHYJBAqVn#what-is-root
|
||||
[2]: tmp.IrHYJBAqVn#run-command-as-root
|
||||
[3]: tmp.IrHYJBAqVn#become-root
|
||||
[4]: tmp.IrHYJBAqVn#enable-root
|
||||
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/root_user_ubuntu.png?ssl=1
|
||||
[6]: http://www.linfo.org/root.html
|
||||
[7]: https://ubuntu.com/
|
||||
[8]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/sudo_sandwich.png?ssl=1
|
||||
[9]: https://itsfoss.com/update-ubuntu/
|
||||
[10]: https://itsfoss.com/install-ubuntu/
|
||||
[11]: https://itsfoss.com/how-to-hack-ubuntu-password/
|
@ -0,0 +1,87 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (laingke)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11823-1.html)
|
||||
[#]: subject: (Why everyone is talking about WebAssembly)
|
||||
[#]: via: (https://opensource.com/article/20/1/webassembly)
|
||||
[#]: author: (Mike Bursell https://opensource.com/users/mikecamel)
|
||||
|
||||
为什么每个人都在谈论 WebAssembly
|
||||
======
|
||||
|
||||
> 了解有关在 Web 浏览器中运行任何代码的最新方法的更多信息。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/27/125343ch0hxdfbzibrihfn.jpg)
|
||||
|
||||
如果你还没有听说过 [WebAssembly][2],那么你很快就会知道。这是业界最保密的秘密之一,但它无处不在。所有主流的浏览器都支持它,并且它也将在服务器端使用。它很快,它能用于游戏编程。这是主要的国际网络标准组织万维网联盟(W3C)的一个开放标准。
|
||||
|
||||
你可能会说:“哇,这听起来像是我应该学习编程的东西!”你可能是对的,但也是错的。你不需要用 WebAssembly 编程。让我们花一些时间来学习这种通常被缩写为“Wasm”的技术。
|
||||
|
||||
### 它从哪里来?
|
||||
|
||||
大约十年前,人们越来越认识到,广泛使用的 JavaScript 不够快速,无法满足许多目的。JavaScript 无疑是成功和方便的。它可以在任何浏览器中运行,并启用了今天我们认为理所当然的动态网页类型。但这是一种高级语言,在设计时并没有考虑到计算密集型工作负载。
|
||||
|
||||
然而,尽管负责主流 web 浏览器的工程师们对性能问题的看法大体一致,但他们对如何解决这个问题却意见不一。出现了两个阵营,谷歌开始了它的<ruby>原生客户端<rt>Native Client</rt></ruby>项目,后来又推出了<ruby>可移植原生客户端<rt>Portable Native Client</rt></ruby>变体,着重于允许用 C/C++ 编写的游戏和其它软件在 Chrome 的一个安全隔间中运行。与此同时,Mozilla 赢得了微软对 asm.js 的支持。该方法更新了浏览器,因此它可以非常快速地运行 JavaScript 指令的低级子集(有另一个项目可以将 C/C++ 代码转换为这些指令)。
|
||||
|
||||
由于这两个阵营都没有得到广泛采用,各方在 2015 年同意围绕一种称为 WebAssembly 的新标准,以 asm.js 所采用的基本方法为基础,联合起来。[如 CNET 的 Stephen Shankland 当时所写][3],“在当今的 Web 上,浏览器的 JavaScript 将这些指令转换为机器代码。但是,通过 WebAssembly,程序员可以在此过程的早期阶段完成很多工作,从而生成介于两种状态之间的程序。这使浏览器摆脱了创建机器代码的繁琐工作,但也实现了 Web 的承诺 —— 该软件将在具有浏览器的任何设备上运行,而无需考虑基础硬件的细节。”
|
||||
|
||||
在 2017 年,Mozilla 宣布了它的最小可行的产品(MVP),并使其脱离预览版阶段。到该年年底,所有主流的浏览器都采用了它。[2019 年 12 月][4],WebAssembly 工作组发布了三个 W3C 推荐的 WebAssembly 规范。
|
||||
|
||||
WebAssembly 定义了一种可执行程序的可移植二进制代码格式、相应的文本汇编语言以及用于促进此类程序与其宿主环境之间的交互接口。WebAssembly 代码在低级虚拟机中运行,这个可运行于许多微处理器之上的虚拟机可模仿这些处理器的功能。通过即时(JIT)编译或解释,WebAssembly 引擎可以以近乎原生平台编译代码的速度执行。
|
||||
|
||||
### 为什么现在感兴趣?
|
||||
|
||||
当然,最近对 WebAssembly 感兴趣的部分原因是最初希望在浏览器中运行更多计算密集型代码。尤其是笔记本电脑用户,越来越多的时间都花在浏览器上(或者,对于 Chromebook 用户来说,基本上是所有时间)。这种趋势已经迫切需要消除在浏览器中运行各种应用程序的障碍。这些障碍之一通常是性能的某些方面,这正是 WebAssembly 及其前身最初旨在解决的问题。
|
||||
|
||||
但是,WebAssembly 并不仅仅适用于浏览器。在 2019 年,[Mozilla 宣布了一个名为 WASI][5](<ruby>WebAssembly 系统接口<rt>WebAssembly System Interface</rt></ruby>)的项目,以标准化 WebAssembly 代码如何与浏览器上下文之外的操作系统进行交互。通过将浏览器对 WebAssembly 和 WASI 的支持结合在一起,编译后的二进制文件将能够以接近原生的速度,跨不同的设备和操作系统在浏览器内外运行。
|
||||
|
||||
WebAssembly 的低开销立即使它可以在浏览器之外使用,但这无疑是赌注;显然,还有其它不会引入性能瓶颈的运行应用程序的方法。为什么要专门使用 WebAssembly?
|
||||
|
||||
一个重要的原因是它的可移植性。如今,像 C++ 和 Rust 这样的广泛使用的编译语言可能是与 WebAssembly 关联最紧密的语言。但是,[各种各样的其他语言][6]可以编译为 WebAssembly 或拥有它们的 WebAssembly 虚拟机。此外,尽管 WebAssembly 为其执行环境[假定了某些先决条件][7],但它被设计为在各种操作系统和指令集体系结构上有效执行。因此,WebAssembly 代码可以使用多种语言编写,并可以在多种操作系统和处理器类型上运行。
|
||||
|
||||
另一个 WebAssembly 优势源于这样一个事实:代码在虚拟机中运行。因此,每个 WebAssembly 模块都在沙盒环境中执行,并使用故障隔离技术将其与宿主机运行时环境分开。这意味着,对于其它部分而言,应用程序独立于其宿主机环境的其余部分执行,如果不调用适当的 API,就无法摆脱沙箱。
|
||||
|
||||
### WebAssembly 现状
|
||||
|
||||
这一切在实践中意味着什么?
|
||||
|
||||
如今在运作中的 WebAssembly 的一个例子是 [Enarx][8]。
|
||||
|
||||
Enarx 是一个提供硬件独立性的项目,可使用<ruby>受信任的执行环境<rt>Trusted Execution Environments</rt></ruby>(TEE)保护应用程序的安全。Enarx 使你可以安全地将编译为 WebAssembly 的应用程序始终交付到云服务商,并远程执行它。正如 Red Hat 安全工程师 [Nathaniel McCallum 指出的那样][9]:“我们这样做的方式是,我们将你的应用程序作为输入,并使用远程硬件执行认证过程。我们使用加密技术验证了远程硬件实际上是它声称的硬件。最终的结果不仅是我们对硬件的信任度提高了;它也是一个会话密钥,我们可以使用它将加密的代码和数据传递到我们刚刚要求加密验证的环境中。”
|
||||
|
||||
另一个例子是 OPA,<ruby>开放策略代理<rt>Open Policy Agent</rt></ruby>,它[发布][10]于 2019 年 11 月,你可以[编译][11]他们的策略定义语言 Rego 为 WebAssembly。Rego 允许你编写逻辑来搜索和组合来自不同来源的 JSON/YAML 数据,以询问诸如“是否允许使用此 API?”之类的问题。
|
||||
|
||||
OPA 已被用于支持策略的软件,包括但不限于 Kubernetes。使用 OPA 之类的工具来简化策略[被认为是在各种不同环境中正确保护 Kubernetes 部署的重要步骤][12]。WebAssembly 的可移植性和内置的安全功能非常适合这些工具。
|
||||
|
||||
我们的最后一个例子是 [Unity][13]。还记得我们在文章开头提到过 WebAssembly 可用于游戏吗?好吧,跨平台游戏引擎 Unity 是 WebAssembly 的较早采用者,它提供了在浏览器中运行的 Wasm 的首个演示品,并且自 2018 年 8 月以来,[已将 WebAssembly][14]用作 Unity WebGL 构建目标的输出目标。
|
||||
|
||||
这些只是 WebAssembly 已经开始产生影响的几种方式。你可以在 <https://webassembly.org/> 上查找更多信息并了解 Wasm 的所有最新信息。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/webassembly
|
||||
|
||||
作者:[Mike Bursell][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[laingke](https://github.com/laingke)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mikecamel
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_web_internet_website.png?itok=g5B_Bw62 (Digital creative of a browser on the internet)
|
||||
[2]: https://opensource.com/article/19/8/webassembly-speed-code-reuse
|
||||
[3]: https://www.cnet.com/news/the-secret-alliance-that-could-give-the-web-a-massive-speed-boost/
|
||||
[4]: https://www.w3.org/blog/news/archives/8123
|
||||
[5]: https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/
|
||||
[6]: https://github.com/appcypher/awesome-wasm-langs
|
||||
[7]: https://webassembly.org/docs/portability/
|
||||
[8]: https://enarx.io
|
||||
[9]: https://enterprisersproject.com/article/2019/9/application-security-4-facts-confidential-computing-consortium
|
||||
[10]: https://blog.openpolicyagent.org/tagged/webassembly
|
||||
[11]: https://github.com/open-policy-agent/opa/tree/master/wasm
|
||||
[12]: https://enterprisersproject.com/article/2019/11/kubernetes-reality-check-3-takeaways-kubecon
|
||||
[13]: https://opensource.com/article/20/1/www.unity.com
|
||||
[14]: https://blogs.unity3d.com/2018/08/15/webassembly-is-here/
|
@ -0,0 +1,141 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11834-1.html)
|
||||
[#]: subject: (3 open source tools to manage your contacts)
|
||||
[#]: via: (https://opensource.com/article/20/1/sync-contacts-locally)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
用于联系人管理的三个开源工具
|
||||
======
|
||||
|
||||
> 通过将联系人同步到本地从而更快访问它。在我们的 20 个使用开源提升生产力的系列的第六篇文章中了解该如何做。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/30/194811bbtt449zfr9zppb3.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 用于联系人管理的开源工具
|
||||
|
||||
在本系列之前的文章中,我解释了如何在本地同步你的[邮件][2]和[日历][3]。希望这些加速了你访问邮件和日历。现在,我将讨论联系人同步,你可以给他们发送邮件和日历邀请。
|
||||
|
||||
![abook][4]
|
||||
|
||||
我目前收集了很多邮件地址。管理这些数据可能有点麻烦。有基于 Web 的服务,但它们不如本地副本快。
|
||||
|
||||
几天前,我谈到了用于管理日历的 [vdirsyncer][5]。vdirsyncer 还使用 CardDAV 协议处理联系人。vdirsyncer 除了可以使用**文件系统**存储日历外,还支持通过 **google_contacts** 和 **carddav** 进行联系人同步,但 `fileext` 设置会被更改,因此你无法在日历文件中存储联系人。
|
||||
|
||||
我在配置文件添加了一块配置,并从 Google 镜像了我的联系人。设置它需要额外的步骤。从 Google 镜像完成后,配置非常简单:
|
||||
|
||||
```
|
||||
[pair address_sync]
|
||||
a = "googlecard"
|
||||
b = "localcard"
|
||||
collections = ["from a", "from b"]
|
||||
conflict_resolution = "a wins"
|
||||
|
||||
[storage googlecard]
|
||||
type = "google_contacts"
|
||||
token_file = "~/.vdirsyncer/google_token"
|
||||
client_id = "my_client_id"
|
||||
client_secret = "my_client_secret"
|
||||
|
||||
[storage localcard]
|
||||
type = "filesystem"
|
||||
path = "~/.calendars/Addresses/"
|
||||
fileext = ".vcf"
|
||||
```
|
||||
|
||||
现在,当我运行 `vdirsyncer discover` 时,它会找到我的 Google 联系人,并且 `vdirsyncer sync` 将它们复制到我的本地计算机。但同样,这只进行到一半。现在我想查看和使用联系人。需要 [khard][6] 和 [abook][7]。
|
||||
|
||||
![khard search][8]
|
||||
|
||||
为什么选择两个应用?因为每个都有它自己的使用场景,在这里,越多越好。khard 用于管理地址,类似于 [khal][9] 用于管理日历条目。如果你的发行版附带了旧版本,你可能需要通过 `pip` 安装最新版本。安装 khard 后,你需要创建 `~/.config/khard/khard.conf`,因为 khard 没有与 khal 那样漂亮的配置向导。我的看起来像这样:
|
||||
|
||||
```
|
||||
[addressbooks]
|
||||
[[addresses]]
|
||||
path = ~/.calendars/Addresses/default/
|
||||
|
||||
[general]
|
||||
debug = no
|
||||
default_action = list
|
||||
editor = vim, -i, NONE
|
||||
merge_editor = vimdiff
|
||||
|
||||
[contact table]
|
||||
display = first_name
|
||||
group_by_addressbook = no
|
||||
reverse = no
|
||||
show_nicknames = yes
|
||||
show_uids = no
|
||||
sort = last_name
|
||||
localize_dates = yes
|
||||
|
||||
[vcard]
|
||||
preferred_version = 3.0
|
||||
search_in_source_files = yes
|
||||
skip_unparsable = no
|
||||
```
|
||||
|
||||
这会定义源通讯簿(并给它一个友好的名称)、显示内容和联系人编辑程序。运行 `khard list` 将列出所有条目,`khard list <some@email.adr>` 可以搜索特定条目。如果要添加或编辑条目,`add` 和 `edit` 命令将使用相同的基本模板打开配置的编辑器,唯一的区别是 `add` 命令的模板将为空。
|
||||
|
||||
![editing in khard][11]
|
||||
|
||||
abook 需要你导入和导出 VCF 文件,但它为查找提供了一些不错的功能。要将文件转换为 abook 格式,请先安装 abook 并创建 `~/.abook` 默认目录。然后让 abook 解析所有文件,并将它们放入 `~/.abook/addresses` 文件中:
|
||||
|
||||
```
|
||||
apt install abook
|
||||
ls ~/.calendars/Addresses/default/* | xargs cat | abook --convert --informat vcard --outformat abook > ~/.abook/addresses
|
||||
```
|
||||
|
||||
现在运行 `abook`,你将有一个非常漂亮的 UI 来浏览、搜索和编辑条目。将它们导出到单个文件有点痛苦,所以我用 khard 进行大部分编辑,并有一个 cron 任务将它们导入到 abook 中。
|
||||
|
||||
abook 还可在命令行中搜索,并有大量有关将其与邮件客户端集成的文档。例如,你可以在 `.config/alot/config` 文件中添加一些信息,从而在 [Nmuch][12] 的邮件客户端 [alot][13] 中使用 abook 查询联系人:
|
||||
|
||||
```
|
||||
[accounts]
|
||||
[[Personal]]
|
||||
realname = Kevin Sonney
|
||||
address = kevin@sonney.com
|
||||
alias_regexp = kevin\+.+@sonney.com
|
||||
gpg_key = 7BB612C9
|
||||
sendmail_command = msmtp --account=Personal -t
|
||||
# ~ expansion works
|
||||
sent_box = maildir://~/Maildir/Sent
|
||||
draft_box = maildir://~/Maildir/Drafts
|
||||
[[[abook]]]
|
||||
type = abook
|
||||
```
|
||||
|
||||
这样你就可以在邮件和日历中快速查找联系人了!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/sync-contacts-locally
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/talk_chat_team_mobile_desktop.png?itok=d7sRtKfQ (Team communication, chat)
|
||||
[2]: https://linux.cn/article-11804-1.html
|
||||
[3]: https://linux.cn/article-11812-1.html
|
||||
[4]: https://opensource.com/sites/default/files/uploads/productivity_6-1.png (abook)
|
||||
[5]: https://github.com/pimutils/vdirsyncer
|
||||
[6]: https://github.com/scheibler/khard
|
||||
[7]: http://abook.sourceforge.net/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/productivity_6-2.png (khard search)
|
||||
[9]: https://khal.readthedocs.io/en/v0.9.2/index.html
|
||||
[10]: mailto:some@email.adr
|
||||
[11]: https://opensource.com/sites/default/files/uploads/productivity_6-3.png (editing in khard)
|
||||
[12]: https://opensource.com/article/20/1/organize-email-notmuch
|
||||
[13]: https://github.com/pazz/alot
|
||||
[14]: mailto:kevin@sonney.com
|
||||
[15]: mailto:+.+@sonney.com
|
@ -0,0 +1,477 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11825-1.html)
|
||||
[#]: subject: (C vs. Rust: Which to choose for programming hardware abstractions)
|
||||
[#]: via: (https://opensource.com/article/20/1/c-vs-rust-abstractions)
|
||||
[#]: author: (Dan Pittman https://opensource.com/users/dan-pittman)
|
||||
|
||||
C 还是 Rust:选择哪个用于硬件抽象编程
|
||||
======
|
||||
|
||||
> 在 Rust 中使用类型级编程可以使硬件抽象更加安全。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/28/123350k2w4mr3tp7crd4m2.jpg)
|
||||
|
||||
Rust 是一种日益流行的编程语言,被视为硬件接口的最佳选择。通常会将其与 C 的抽象级别相比较。本文介绍了 Rust 如何通过多种方式处理按位运算,并提供了既安全又易于使用的解决方案。
|
||||
|
||||
语言 | 诞生于 | 官方描述 | 总览
|
||||
---|---|---|---
|
||||
C | 1972 年 | C 是一种通用编程语言,具有表达式简约、现代的控制流和数据结构,以及丰富的运算符集等特点。(来源:[CS 基础知识] [2])| C 是(一种)命令式语言,旨在以相对简单的方式进行编译,从而提供对内存的低级访问。(来源:[W3schools.in] [3])
|
||||
Rust | 2010 年 | 一种赋予所有人构建可靠、高效的软件的能力的语言(来源:[Rust 网站] [4])| Rust 是一种专注于安全性(尤其是安全并发性)的多范式系统编程语言。(来源:[维基百科] [5])
|
||||
|
||||
### 在 C 语言中对寄存器值进行按位运算
|
||||
|
||||
在系统编程领域,你可能经常需要编写硬件驱动程序或直接与内存映射设备进行交互,而这些交互几乎总是通过硬件提供的内存映射寄存器来完成的。通常,你通过对某些固定宽度的数字类型进行按位运算来与这些寄存器进行交互。
|
||||
|
||||
例如,假设一个 8 位寄存器具有三个字段:
|
||||
|
||||
```
|
||||
+----------+------+-----------+---------+
|
||||
| (unused) | Kind | Interrupt | Enabled |
|
||||
+----------+------+-----------+---------+
|
||||
5-7 2-4 1 0
|
||||
```
|
||||
|
||||
字段名称下方的数字规定了该字段在寄存器中使用的位。要启用该寄存器,你将写入值 `1`(以二进制表示为 `0000_0001`)来设置 `Enabled` 字段的位。但是,通常情况下,你也不想干扰寄存器中的现有配置。假设你要在设备上启用中断功能,但也要确保设备保持启用状态。为此,必须将 `Interrupt` 字段的值与 `Enabled` 字段的值结合起来。你可以通过按位操作来做到这一点:
|
||||
|
||||
```
|
||||
1 | (1 << 1)
|
||||
```
|
||||
|
||||
通过将 1 和 2(`1` 左移一位得到)进行“或”(`|`)运算得到二进制值 `0000_0011` 。你可以将其写入寄存器,使其保持启用状态,但也启用中断功能。
|
||||
|
||||
你的头脑中要记住很多事情,特别是当你要在一个完整的系统上和可能有数百个之多的寄存器打交道时。在实践上,你可以使用助记符来执行此操作,助记符可跟踪字段在寄存器中的位置以及字段的宽度(即它的上边界是什么)
|
||||
|
||||
下面是这些助记符之一的示例。它们是 C 语言的宏,用右侧的代码替换它们的出现的地方。这是上面列出的寄存器的简写。`&` 的左侧是该字段的起始位置,而右侧则限制该字段所占的位:
|
||||
|
||||
```
|
||||
#define REG_ENABLED_FIELD(x) (x << 0) & 1
|
||||
#define REG_INTERRUPT_FIELD(x) (x << 1) & 2
|
||||
#define REG_KIND_FIELD(x) (x << 2) & (7 << 2)
|
||||
```
|
||||
|
||||
然后,你可以使用这些来抽象化寄存器值的操作,如下所示:
|
||||
|
||||
```
|
||||
void set_reg_val(reg* u8, val u8);
|
||||
|
||||
fn enable_reg_with_interrupt(reg* u8) {
|
||||
set_reg_val(reg, REG_ENABLED_FIELD(1) | REG_INTERRUPT_FIELD(1));
|
||||
}
|
||||
```
|
||||
|
||||
这就是现在的做法。实际上,这就是大多数驱动程序在 Linux 内核中的使用方式。
|
||||
|
||||
有没有更好的办法?如果能够基于对现代编程语言研究得出新的类型系统,就可能能够获得安全性和可表达性的好处。也就是说,如何使用更丰富、更具表现力的类型系统来使此过程更安全、更持久?
|
||||
|
||||
### 在 Rust 语言中对寄存器值进行按位运算
|
||||
|
||||
继续用上面的寄存器作为例子:
|
||||
|
||||
```
|
||||
+----------+------+-----------+---------+
|
||||
| (unused) | Kind | Interrupt | Enabled |
|
||||
+----------+------+-----------+---------+
|
||||
5-7 2-4 1 0
|
||||
```
|
||||
|
||||
你想如何用 Rust 类型来表示它呢?
|
||||
|
||||
你将以类似的方式开始,为每个字段的*偏移*定义常量(即,距最低有效位有多远)及其掩码。*掩码*是一个值,其二进制表示形式可用于更新或读取寄存器内部的字段:
|
||||
|
||||
```
|
||||
const ENABLED_MASK: u8 = 1;
|
||||
const ENABLED_OFFSET: u8 = 0;
|
||||
|
||||
const INTERRUPT_MASK: u8 = 2;
|
||||
const INTERRUPT_OFFSET: u8 = 1;
|
||||
|
||||
const KIND_MASK: u8 = 7 << 2;
|
||||
const KIND_OFFSET: u8 = 2;
|
||||
```
|
||||
|
||||
接下来,你将声明一个 `Field` 类型并进行操作,将给定值转换为与其位置相关的值,以供在寄存器内使用:
|
||||
|
||||
```
|
||||
struct Field {
|
||||
value: u8,
|
||||
}
|
||||
|
||||
impl Field {
|
||||
fn new(mask: u8, offset: u8, val: u8) -> Self {
|
||||
Field {
|
||||
value: (val << offset) & mask,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
最后,你将使用一个 `Register` 类型,该类型会封装一个与你的寄存器宽度匹配的数字类型。 `Register` 具有 `update` 函数,可使用给定字段来更新寄存器:
|
||||
|
||||
```
|
||||
struct Register(u8);
|
||||
|
||||
impl Register {
|
||||
fn update(&mut self, val: Field) {
|
||||
self.0 = self.0 | field.value;
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_register(&mut reg) {
|
||||
reg.update(Field::new(ENABLED_MASK, ENABLED_OFFSET, 1));
|
||||
}
|
||||
```
|
||||
|
||||
使用 Rust,你可以使用数据结构来表示字段,将它们与特定的寄存器联系起来,并在与硬件交互时提供简洁明了的工效。这个例子使用了 Rust 提供的最基本的功能。无论如何,添加的结构都会减轻上述 C 示例中的某些晦涩的地方。现在,字段是个带有名字的事物,而不是从模糊的按位运算符派生而来的数字,并且寄存器是具有状态的类型 —— 这在硬件上多了一层抽象。
|
||||
|
||||
### 一个易用的 Rust 实现
|
||||
|
||||
用 Rust 重写的第一个版本很好,但是并不理想。你必须记住要带上掩码和偏移量,并且要手工进行临时计算,这容易出错。人类不擅长精确且重复的任务 —— 我们往往会感到疲劳或失去专注力,这会导致错误。一次一个寄存器地手动记录掩码和偏移量几乎可以肯定会以糟糕的结局而告终。这是最好留给机器的任务。
|
||||
|
||||
其次,从结构上进行思考:如果有一种方法可以让字段的类型携带掩码和偏移信息呢?如果可以在编译时就发现硬件寄存器的访问和交互的实现代码中存在错误,而不是在运行时才发现,该怎么办?也许你可以依靠一种在编译时解决问题的常用策略,例如类型。
|
||||
|
||||
你可以使用 [typenum][6] 来修改前面的示例,该库在类型级别提供数字和算术。在这里,你将使用掩码和偏移量对 `Field` 类型进行参数化,使其可用于任何 `Field` 实例,而无需将其包括在调用处:
|
||||
|
||||
```
|
||||
#[macro_use]
|
||||
extern crate typenum;
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use typenum::*;
|
||||
|
||||
// Now we'll add Mask and Offset to Field's type
|
||||
struct Field<Mask: Unsigned, Offset: Unsigned> {
|
||||
value: u8,
|
||||
_mask: PhantomData<Mask>,
|
||||
_offset: PhantomData<Offset>,
|
||||
}
|
||||
|
||||
// We can use type aliases to give meaningful names to
|
||||
// our fields (and not have to remember their offsets and masks).
|
||||
type RegEnabled = Field<U1, U0>;
|
||||
type RegInterrupt = Field<U2, U1>;
|
||||
type RegKind = Field<op!(U7 << U2), U2>;
|
||||
```
|
||||
|
||||
现在,当重新访问 `Field` 的构造函数时,你可以忽略掩码和偏移量参数,因为类型中包含该信息:
|
||||
|
||||
```
|
||||
impl<Mask: Unsigned, Offset: Unsigned> Field<Mask, Offset> {
|
||||
fn new(val: u8) -> Self {
|
||||
Field {
|
||||
value: (val << Offset::U8) & Mask::U8,
|
||||
_mask: PhantomData,
|
||||
_offset: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// And to enable our register...
|
||||
fn enable_register(&mut reg) {
|
||||
reg.update(RegEnabled::new(1));
|
||||
}
|
||||
```
|
||||
|
||||
看起来不错,但是……如果你在给定的值是否*适合*该字段方面犯了错误,会发生什么?考虑一个简单的输入错误,你在其中放置了 `10` 而不是 `1`:
|
||||
|
||||
```
|
||||
fn enable_register(&mut reg) {
|
||||
reg.update(RegEnabled::new(10));
|
||||
}
|
||||
```
|
||||
|
||||
在上面的代码中,预期结果是什么?好吧,代码会将启用位设置为 0,因为 `10&1 = 0`。那真不幸;最好在尝试写入之前知道你要写入字段的值是否适合该字段。事实上,我认为截掉错误字段值的高位是一种 1*未定义的行为*(哈)。
|
||||
|
||||
### 出于安全考虑使用 Rust
|
||||
|
||||
如何以一般方式检查字段的值是否适合其规定的位置?需要更多类型级别的数字!
|
||||
|
||||
你可以在 `Field` 中添加 `Width` 参数,并使用它来验证给定的值是否适合该字段:
|
||||
|
||||
```
|
||||
struct Field<Width: Unsigned, Mask: Unsigned, Offset: Unsigned> {
|
||||
value: u8,
|
||||
_mask: PhantomData<Mask>,
|
||||
_offset: PhantomData<Offset>,
|
||||
_width: PhantomData<Width>,
|
||||
}
|
||||
|
||||
type RegEnabled = Field<U1,U1, U0>;
|
||||
type RegInterrupt = Field<U1, U2, U1>;
|
||||
type RegKind = Field<U3, op!(U7 << U2), U2>;
|
||||
|
||||
impl<Width: Unsigned, Mask: Unsigned, Offset: Unsigned> Field<Width, Mask, Offset> {
|
||||
fn new(val: u8) -> Option<Self> {
|
||||
if val <= (1 << Width::U8) - 1 {
|
||||
Some(Field {
|
||||
value: (val << Offset::U8) & Mask::U8,
|
||||
_mask: PhantomData,
|
||||
_offset: PhantomData,
|
||||
_width: PhantomData,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
现在,只有给定值适合时,你才能构造一个 `Field` !否则,你将得到 `None` 信号,该信号指示发生了错误,而不是截掉该值的高位并静默写入意外的值。
|
||||
|
||||
但是请注意,这将在运行时环境中引发错误。但是,我们事先知道我们想写入的值,还记得吗?鉴于此,我们可以教编译器完全拒绝具有无效字段值的程序 —— 我们不必等到运行它!
|
||||
|
||||
这次,你将向 `new` 的新实现 `new_checked` 中添加一个特征绑定(`where` 子句),该函数要求输入值小于或等于给定字段用 `Width` 所能容纳的最大可能值:
|
||||
|
||||
```
|
||||
struct Field<Width: Unsigned, Mask: Unsigned, Offset: Unsigned> {
|
||||
value: u8,
|
||||
_mask: PhantomData<Mask>,
|
||||
_offset: PhantomData<Offset>,
|
||||
_width: PhantomData<Width>,
|
||||
}
|
||||
|
||||
type RegEnabled = Field<U1, U1, U0>;
|
||||
type RegInterrupt = Field<U1, U2, U1>;
|
||||
type RegKind = Field<U3, op!(U7 << U2), U2>;
|
||||
|
||||
impl<Width: Unsigned, Mask: Unsigned, Offset: Unsigned> Field<Width, Mask, Offset> {
|
||||
const fn new_checked<V: Unsigned>() -> Self
|
||||
where
|
||||
V: IsLessOrEqual<op!((U1 << Width) - U1), Output = True>,
|
||||
{
|
||||
Field {
|
||||
value: (V::U8 << Offset::U8) & Mask::U8,
|
||||
_mask: PhantomData,
|
||||
_offset: PhantomData,
|
||||
_width: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
只有拥有此属性的数字才实现此特征,因此,如果使用不适合的数字,它将无法编译。让我们看一看!
|
||||
|
||||
```
|
||||
fn enable_register(&mut reg) {
|
||||
reg.update(RegEnabled::new_checked::<U10>());
|
||||
}
|
||||
12 | reg.update(RegEnabled::new_checked::<U10>());
|
||||
| ^^^^^^^^^^^^^^^^ expected struct `typenum::B0`, found struct `typenum::B1`
|
||||
|
|
||||
= note: expected type `typenum::B0`
|
||||
found type `typenum::B1`
|
||||
```
|
||||
|
||||
`new_checked` 将无法生成一个程序,因为该字段的值有错误的高位。你的输入错误不会在运行时环境中才爆炸,因为你永远无法获得一个可以运行的工件。
|
||||
|
||||
就使内存映射的硬件进行交互的安全性而言,你已经接近 Rust 的极致。但是,你在 C 的第一个示例中所写的内容比最终得到的一锅粥的类型参数更简洁。当你谈论潜在可能有数百甚至数千个寄存器时,这样做是否容易处理?
|
||||
|
||||
### 让 Rust 恰到好处:既安全又方便使用
|
||||
|
||||
早些时候,我认为手工计算掩码有问题,但我又做了同样有问题的事情 —— 尽管是在类型级别。虽然使用这种方法很不错,但要达到编写任何代码的地步,则需要大量样板和手动转录(我在这里谈论的是类型的同义词)。
|
||||
|
||||
我们的团队想要像 [TockOS mmio 寄存器][7]之类的东西,而以最少的手动转录生成类型安全的实现。我们得出的结果是一个宏,该宏生成必要的样板以获得类似 Tock 的 API 以及基于类型的边界检查。要使用它,请写下一些有关寄存器的信息,其字段、宽度和偏移量以及可选的[枚举][8]类的值(你应该为字段可能具有的值赋予“含义”):
|
||||
|
||||
```
|
||||
register! {
|
||||
// The register's name
|
||||
Status,
|
||||
// The type which represents the whole register.
|
||||
u8,
|
||||
// The register's mode, ReadOnly, ReadWrite, or WriteOnly.
|
||||
RW,
|
||||
// And the fields in this register.
|
||||
Fields [
|
||||
On WIDTH(U1) OFFSET(U0),
|
||||
Dead WIDTH(U1) OFFSET(U1),
|
||||
Color WIDTH(U3) OFFSET(U2) [
|
||||
Red = U1,
|
||||
Blue = U2,
|
||||
Green = U3,
|
||||
Yellow = U4
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
由此,你可以生成寄存器和字段类型,如上例所示,其中索引:`Width`、`Mask` 和 `Offset` 是从一个字段定义的 `WIDTH` 和 `OFFSET` 部分的输入值派生的。另外,请注意,所有这些数字都是 “类型数字”;它们将直接进入你的 `Field` 定义!
|
||||
|
||||
生成的代码通过为寄存器及字段指定名称来为寄存器及其相关字段提供名称空间。这很绕口,看起来是这样的:
|
||||
|
||||
```
|
||||
mod Status {
|
||||
struct Register(u8);
|
||||
mod On {
|
||||
struct Field; // There is of course more to this definition
|
||||
}
|
||||
mod Dead {
|
||||
struct Field;
|
||||
}
|
||||
mod Color {
|
||||
struct Field;
|
||||
pub const Red: Field = Field::<U1>new();
|
||||
// &c.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
生成的 API 包含名义上期望的读取和写入的原语,以获取原始寄存器的值,但它也有办法获取单个字段的值、执行集合操作以及确定是否设置了任何(或全部)位集合的方法。你可以阅读[完整生成的 API][9]上的文档。
|
||||
|
||||
### 粗略检查
|
||||
|
||||
将这些定义用于实际设备会是什么样?代码中是否会充斥着类型参数,从而掩盖了视图中的实际逻辑?
|
||||
|
||||
不会!通过使用类型同义词和类型推断,你实际上根本不必考虑程序的类型层面部分。你可以直接与硬件交互,并自动获得与边界相关的保证。
|
||||
|
||||
这是一个 [UART][10] 寄存器块的示例。我会跳过寄存器本身的声明,因为包括在这里就太多了。而是从寄存器“块”开始,然后帮助编译器知道如何从指向该块开头的指针中查找寄存器。我们通过实现 `Deref` 和 `DerefMut` 来做到这一点:
|
||||
|
||||
```
|
||||
#[repr(C)]
|
||||
pub struct UartBlock {
|
||||
rx: UartRX::Register,
|
||||
_padding1: [u32; 15],
|
||||
tx: UartTX::Register,
|
||||
_padding2: [u32; 15],
|
||||
control1: UartControl1::Register,
|
||||
}
|
||||
|
||||
pub struct Regs {
|
||||
addr: usize,
|
||||
}
|
||||
|
||||
impl Deref for Regs {
|
||||
type Target = UartBlock;
|
||||
|
||||
fn deref(&self) -> &UartBlock {
|
||||
unsafe { &*(self.addr as *const UartBlock) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Regs {
|
||||
fn deref_mut(&mut self) -> &mut UartBlock {
|
||||
unsafe { &mut *(self.addr as *mut UartBlock) }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
一旦到位,使用这些寄存器就像 `read()` 和 `modify()` 一样简单:
|
||||
|
||||
```
|
||||
fn main() {
|
||||
// A pretend register block.
|
||||
let mut x = [0_u32; 33];
|
||||
|
||||
let mut regs = Regs {
|
||||
// Some shenanigans to get at `x` as though it were a
|
||||
// pointer. Normally you'd be given some address like
|
||||
// `0xDEADBEEF` over which you'd instantiate a `Regs`.
|
||||
addr: &mut x as *mut [u32; 33] as usize,
|
||||
};
|
||||
|
||||
assert_eq!(regs.rx.read(), 0);
|
||||
|
||||
regs.control1
|
||||
.modify(UartControl1::Enable::Set + UartControl1::RecvReadyInterrupt::Set);
|
||||
|
||||
// The first bit and the 10th bit should be set.
|
||||
assert_eq!(regs.control1.read(), 0b_10_0000_0001);
|
||||
}
|
||||
```
|
||||
|
||||
当我们使用运行时值时,我们使用如前所述的**选项**。这里我使用的是 `unwrap`,但是在一个输入未知的真实程序中,你可能想检查一下从新调用中返回的**某些东西**: [^1] [^2]
|
||||
|
||||
```
|
||||
fn main() {
|
||||
// A pretend register block.
|
||||
let mut x = [0_u32; 33];
|
||||
|
||||
let mut regs = Regs {
|
||||
// Some shenanigans to get at `x` as though it were a
|
||||
// pointer. Normally you'd be given some address like
|
||||
// `0xDEADBEEF` over which you'd instantiate a `Regs`.
|
||||
addr: &mut x as *mut [u32; 33] as usize,
|
||||
};
|
||||
|
||||
let input = regs.rx.get_field(UartRX::Data::Field::Read).unwrap();
|
||||
regs.tx.modify(UartTX::Data::Field::new(input).unwrap());
|
||||
}
|
||||
```
|
||||
|
||||
### 解码失败条件
|
||||
|
||||
根据你的个人痛苦忍耐程度,你可能已经注意到这些错误几乎是无法理解的。看一下我所说的不那么微妙的提醒:
|
||||
|
||||
```
|
||||
error[E0271]: type mismatch resolving `<typenum::UInt<typenum::UInt<typenum::UInt<typenum::UInt<typenum::UInt<typenum::UTerm, typenum::B1>, typenum::B0>, typenum::B1>, typenum::B0>, typenum::B0> as typenum::IsLessOrEqual<typenum::UInt<typenum::UInt<typenum::UInt<typenum::UInt<typenum::UTerm, typenum::B1>, typenum::B0>, typenum::B1>, typenum::B0>>>::Output == typenum::B1`
|
||||
--> src/main.rs:12:5
|
||||
|
|
||||
12 | less_than_ten::<U20>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^ expected struct `typenum::B0`, found struct `typenum::B1`
|
||||
|
|
||||
= note: expected type `typenum::B0`
|
||||
found type `typenum::B1`
|
||||
```
|
||||
|
||||
`expected struct typenum::B0, found struct typenum::B1` 部分是有意义的,但是 ` typenum::UInt<typenum::UInt, typenum::UInt...` 到底是什么呢?好吧,`typenum` 将数字表示为二进制 [cons][13] 单元!像这样的错误使操作变得很困难,尤其是当你将多个这些类型级别的数字限制在狭窄的范围内时,你很难知道它在说哪个数字。当然,除非你一眼就能将巴洛克式二进制表示形式转换为十进制表示形式。
|
||||
|
||||
在第 U100 次试图从这个混乱中破译出某些含义之后,我们的一个队友简直《<ruby>疯了,地狱了,不要再忍受了<rt>Mad As Hell And Wasn't Going To Take It Anymore</rt></ruby>》,并做了一个小工具 `tnfilt`,从这种命名空间的二进制 cons 单元的痛苦中解脱出来。`tnfilt` 将 cons 单元格式的表示法替换为可让人看懂的十进制数字。我们认为其他人也会遇到类似的困难,所以我们分享了 [tnfilt][14]。你可以像这样使用它:
|
||||
|
||||
```
|
||||
$ cargo build 2>&1 | tnfilt
|
||||
```
|
||||
|
||||
它将上面的输出转换为如下所示:
|
||||
|
||||
```
|
||||
error[E0271]: type mismatch resolving `<U20 as typenum::IsLessOrEqual<U10>>::Output == typenum::B1`
|
||||
```
|
||||
|
||||
现在*这*才有意义!
|
||||
|
||||
### 结论
|
||||
|
||||
当在软件与硬件进行交互时,普遍使用内存映射寄存器,并且有无数种方法来描述这些交互,每种方法在易用性和安全性上都有不同的权衡。我们发现使用类型级编程来取得内存映射寄存器交互的编译时检查可以为我们提供制作更安全软件的必要信息。该代码可在 [bounded-registers][15] crate(Rust 包)中找到。
|
||||
|
||||
我们的团队从安全性较高的一面开始,然后尝试找出如何将易用性滑块移近易用端。从这些雄心壮志中,“边界寄存器”就诞生了,我们在 Auxon 公司的冒险中遇到内存映射设备的任何时候都可以使用它。
|
||||
|
||||
* * *
|
||||
|
||||
[^1]: 从技术上讲,从定义上看,从寄存器字段读取的值只能在规定的范围内,但是我们当中没有一个人生活在一个纯净的世界中,而且你永远都不知道外部系统发挥作用时会发生什么。你是在这里接受硬件之神的命令,因此与其强迫你进入“可能的恐慌”状态,还不如给你提供处理“这将永远不会发生”的机会。
|
||||
[^2]: `get_field` 看起来有点奇怪。我正在专门查看 `Field::Read` 部分。`Field` 是一种类型,你需要该类型的实例才能传递给 `get_field`。更干净的 API 可能类似于:`regs.rx.get_field::<UartRx::Data::Field>();` 但是请记住,`Field` 是一种具有固定的宽度、偏移量等索引的类型的同义词。要像这样对 `get_field` 进行参数化,你需要使用更高级的类型。
|
||||
|
||||
* * *
|
||||
|
||||
此内容最初发布在 [Auxon Engineering 博客][16]上,并经许可进行编辑和重新发布。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/c-vs-rust-abstractions
|
||||
|
||||
作者:[Dan Pittman][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dan-pittman
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/tools_hardware_purple.png?itok=3NdVoYhl (Tools illustration)
|
||||
[2]: https://cs-fundamentals.com/c-programming/history-of-c-programming-language.php
|
||||
[3]: https://www.w3schools.in/c-tutorial/history-of-c/
|
||||
[4]: https://www.rust-lang.org/
|
||||
[5]: https://en.wikipedia.org/wiki/Rust_(programming_language)
|
||||
[6]: https://docs.rs/crate/typenum
|
||||
[7]: https://docs.rs/tock-registers/0.3.0/tock_registers/
|
||||
[8]: https://en.wikipedia.org/wiki/Enumerated_type
|
||||
[9]: https://github.com/auxoncorp/bounded-registers#the-register-api
|
||||
[10]: https://en.wikipedia.org/wiki/Universal_asynchronous_receiver-transmitter
|
||||
[11]: tmp.shpxgDsodx#1
|
||||
[12]: tmp.shpxgDsodx#2
|
||||
[13]: https://en.wikipedia.org/wiki/Cons
|
||||
[14]: https://github.com/auxoncorp/tnfilt
|
||||
[15]: https://crates.io/crates/bounded-registers
|
||||
[16]: https://blog.auxon.io/2019/10/25/type-level-registers/
|
@ -0,0 +1,106 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11835-1.html)
|
||||
[#]: subject: (Get started with this open source to-do list manager)
|
||||
[#]: via: (https://opensource.com/article/20/1/open-source-to-do-list)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
开始使用开源待办事项清单管理器
|
||||
======
|
||||
|
||||
> 待办事项清单是跟踪任务列表的强大方法。在我们的 20 个使用开源提升生产力的系列的第七篇文章中了解如何使用它。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/31/111103kmv55ploshuso4ot.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 todo 跟踪任务
|
||||
|
||||
任务管理和待办事项清单是我非常喜欢0的东西。我是一位生产效率的狂热粉丝(以至于我为此做了一个[播客][2]),我尝试了各种不同的应用。我甚至为此[做了演讲][3]并[写了些文章][4]。因此,当我谈到提高工作效率时,肯定会出现任务管理和待办事项清单工具。
|
||||
|
||||
![Getting fancy with Todo.txt][5]
|
||||
|
||||
说实话,由于简单、跨平台且易于同步,用 [todo.txt][6] 肯定不会错。它是我不断反复提到的两个待办事项清单以及任务管理应用之一(另一个是 [Org 模式][7])。让我反复使用它的原因是它简单、可移植、易于理解,并且有许多很好的附加组件,并且当一台机器有附加组件,而另一台没有,也不会破坏它。由于它是一个 Bash shell 脚本,我还没发现一个无法支持它的系统。
|
||||
|
||||
#### 设置 todo.txt
|
||||
|
||||
首先,你需要安装基本 shell 脚本并将默认配置文件复制到 `~/.todo` 目录:
|
||||
|
||||
```
|
||||
git clone https://github.com/todotxt/todo.txt-cli.git
|
||||
cd todo.txt-cli
|
||||
make
|
||||
sudo make install
|
||||
mkdir ~/.todo
|
||||
cp todo.cfg ~/.todo/config
|
||||
```
|
||||
|
||||
接下来,设置配置文件。一般,我想取消对颜色设置的注释,但必须马上设置的是 `TODO_DIR` 变量:
|
||||
|
||||
```
|
||||
export TODO_DIR="$HOME/.todo"
|
||||
```
|
||||
|
||||
#### 添加待办事件
|
||||
|
||||
要添加第一个待办事件,只需输入 `todo.sh add <NewTodo>` 就能添加。这还将在 `$HOME/.todo/` 中创建三个文件:`todo.txt`、`done.txt` 和 `reports.txt`。
|
||||
|
||||
添加几个项目后,运行 `todo.sh ls` 查看你的待办事项。
|
||||
|
||||
![Basic todo.txt list][8]
|
||||
|
||||
#### 管理任务
|
||||
|
||||
你可以通过给项目设置优先级来稍微改善它。要向项目添加优先级,运行 `todo.sh pri # A`。数字是列表中任务的数量,而字母 `A` 是优先级。你可以将优先级设置为从 A 到 Z,因为这是它的排序方式。
|
||||
|
||||
要完成任务,运行 `todo.sh do #` 来标记项目已完成并将它移动到 `done.txt`。运行 `todo.sh report` 会向 `report.txt` 写入已完成和未完成项的数量。
|
||||
|
||||
所有这三个文件的格式都有详细的说明,因此你可以使用你的文本编辑器修改。`todo.txt` 的基本格式是:
|
||||
|
||||
```
|
||||
(Priority) YYYY-MM-DD Task
|
||||
```
|
||||
|
||||
该日期表示任务的到期日期(如果已设置)。手动编辑文件时,只需在任务前面加一个 `x` 来标记为已完成。运行 `todo.sh archive` 会将这些项目移动到 `done.txt`,你可以编辑该文本文件,并在有时间时将已完成的项目归档。
|
||||
|
||||
#### 设置重复任务
|
||||
|
||||
我有很多重复的任务,我需要以每天/周/月来计划。
|
||||
|
||||
![Recurring tasks with the ice_recur add-on][9]
|
||||
|
||||
这就是 `todo.txt` 的灵活性所在。通过在 `~/.todo.actions.d/` 中使用[附加组件][10],你可以添加命令并扩展基本 `todo.sh` 的功能。附加组件基本上是实现特定命令的脚本。对于重复执行的任务,插件 [ice_recur][11] 应该符合要求。按照其页面上的说明操作,你可以设置任务以非常灵活的方式重复执行。
|
||||
|
||||
![Todour on MacOS][12]
|
||||
|
||||
在该[附加组件目录][10]中有很多附加组件,包括同步到某些云服务,也有链接到桌面或移动端应用的组件,这样你可以随时看到待办列表。
|
||||
|
||||
我只是简单介绍了这个代办事项清单功能,请花点时间深入了解这个工具的强大!它确实可以帮助我每天完成任务。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/open-source-to-do-list
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/checklist_todo_clock_time_team.png?itok=1z528Q0y (Team checklist)
|
||||
[2]: https://productivityalchemy.com/
|
||||
[3]: https://www.slideshare.net/AllThingsOpen/getting-to-done-on-the-command-line
|
||||
[4]: https://opensource.com/article/18/2/getting-to-done-agile-linux-command-line
|
||||
[5]: https://opensource.com/sites/default/files/uploads/productivity_7-1.png
|
||||
[6]: http://todotxt.org/
|
||||
[7]: https://orgmode.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/productivity_7-2.png (Basic todo.txt list)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/productivity_7-3.png (Recurring tasks with the ice_recur add-on)
|
||||
[10]: https://github.com/todotxt/todo.txt-cli/wiki/Todo.sh-Add-on-Directory
|
||||
[11]: https://github.com/rlpowell/todo-text-stuff
|
||||
[12]: https://opensource.com/sites/default/files/uploads/productivity_7-4.png (Todour on MacOS)
|
@ -0,0 +1,112 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (FSSlc)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11813-1.html)
|
||||
[#]: subject: (Locking and unlocking accounts on Linux systems)
|
||||
[#]: via: (https://www.networkworld.com/article/3513982/locking-and-unlocking-accounts-on-linux-systems.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
在 Linux 系统中禁用与解禁用户的账号
|
||||
======
|
||||
|
||||
> 总有这样的时候:有时你需要禁用某位 Linux 用户的账号,有时你还需要反过来解禁用户的账号。
|
||||
本文将介绍一些管理用户访问的命令,并介绍它们背后的原理。
|
||||
|
||||
![](https://images.idgesg.net/images/article/2019/10/cso_cybersecurity_mysterious_padlock_complex_circuits_gold_by_sqback_gettyimages-1177918748_2400x1600-100813830-large.jpg)
|
||||
|
||||
假如你正管理着一台 [Linux][1] 系统,那么很有可能将遇到需要禁用一个账号的情况。可能是某人已经换了职位,他们是否还需要该账号仍是个问题;或许有理由相信再次使用该账号并没有大碍。不管上述哪种情况,知晓如何禁用账号并解禁账号都是你需要知道的知识。
|
||||
|
||||
需要你记住的一件重要的事是尽管有多种方法来禁用账号,但它们并不都达到相同的效果。假如用户使用公钥/私钥来使用该账号而不是使用密码来访问,那么你使用的某些命令来阻止用户获取该账号或许将不会生效。
|
||||
|
||||
### 使用 passwd 来禁用一个账号
|
||||
|
||||
最为简单的用来禁用一个账号的方法是使用 `passwd -l` 命令。例如:
|
||||
|
||||
```
|
||||
$ sudo passwd -l tadpole
|
||||
```
|
||||
|
||||
上面这个命令的效果是在加密后的密码文件 `/etc/shadow` 中,用户对应的那一行的最前面加上一个 `!` 符号。这样就足够阻止用户使用密码来访问账号了。
|
||||
|
||||
在没有使用上述命令前,加密后的密码行如下所示(请注意第一个字符):
|
||||
|
||||
```
|
||||
$6$IC6icrWlNhndMFj6$Jj14Regv3b2EdK.8iLjSeO893fFig75f32rpWpbKPNz7g/eqeaPCnXl3iQ7RFIN0BGC0E91sghFdX2eWTe2ET0:18184:0:99999:7:::
|
||||
```
|
||||
|
||||
而禁用该账号后,这一行将变为:
|
||||
|
||||
```
|
||||
!$6$IC6icrWlNhndMFj6$Jj14Regv3b2EdK.8iLjSeO893fFig75f32rpWpbKPNz7g/eqeaPCnXl3iQ7RFIN0BGC0E91sghFdX2eWTe2ET0:18184:0:99999:7:::
|
||||
```
|
||||
|
||||
在 tadpole 下一次尝试登录时,他可能会使用他原有的密码来尝试多次登录,但就是无法再登录成功了。另一方面,你则可以使用下面的命令来查看他这个账号的状态(`-S` = status):
|
||||
|
||||
```
|
||||
$ sudo passwd -S tadpole
|
||||
tadpole L 10/15/2019 0 99999 7 -1
|
||||
```
|
||||
|
||||
第二项的 `L` 告诉你这个账号已经被禁用了。在该账号被禁用前,这一项应该是 `P`。如果显示的是 `NP` 则意味着该账号还没有设置密码。
|
||||
|
||||
命令 `usermod -L` 也具有相同的效果(添加 `!` 来禁用账号的使用)。
|
||||
|
||||
使用这种方法来禁用某个账号的一个好处是当需要解禁某个账号时非常容易。只需要使用一个文本编辑器或者使用 `passwd -u` 命令来执行相反的操作,即将添加的 `!` 移除即可。
|
||||
|
||||
```
|
||||
$ sudo passwd -u tadpole
|
||||
passwd: password expiry information changed.
|
||||
```
|
||||
|
||||
但使用这种方式的问题是如果用户使用公钥/私钥对的方式来访问他/她的账号,这种方式将不能阻止他们使用该账号。
|
||||
|
||||
### 使用 chage 命令来禁用账号
|
||||
|
||||
另一种禁用用户账号的方法是使用 `chage` 命令,它可以帮助管理用户账号的过期日期。
|
||||
|
||||
```
|
||||
$ sudu chage -E0 tadpole
|
||||
$ sudo passwd -S tadpole
|
||||
tadpole P 10/15/2019 0 99999 7 -1
|
||||
```
|
||||
|
||||
`chage` 命令将会稍微修改 `/etc/shadow` 文件。在这个使用 `:` 来分隔的文件(下面将进行展示)中,某行的第 8 项将被设置为 `0`(先前为空),这就意味着这个账号已经过期了。`chage` 命令会追踪密码更改期间的天数,通过选项也可以提供账号过期信息。第 8 项如果是 0 则意味着这个账号在 1970 年 1 月 1 日后的一天过期,当使用上面显示的那个命令时可以用来禁用账号。
|
||||
|
||||
```
|
||||
$ sudo grep tadpole /etc/shadow | fold
|
||||
tadpole:$6$IC6icrWlNhndMFj6$Jj14Regv3b2EdK.8iLjSeO893fFig75f32rpWpbKPNz7g/eqeaPC
|
||||
nXl3iQ7RFIN0BGC0E91sghFdX2eWTe2ET0:18184:0:99999:7::0:
|
||||
^
|
||||
|
|
||||
+--- days until expiration
|
||||
```
|
||||
|
||||
为了执行相反的操作,你可以简单地使用下面的命令将放置在 `/etc/shadow` 文件中的 `0` 移除掉:
|
||||
|
||||
```
|
||||
% sudo chage -E-1 tadpole
|
||||
```
|
||||
|
||||
一旦一个账号使用这种方式被禁用,即便是无密码的 [SSH][4] 登录也不能再访问该账号了。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3513982/locking-and-unlocking-accounts-on-linux-systems.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[FSSlc](https://github.com/FSSlc)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.networkworld.com/article/3215226/what-is-linux-uses-featres-products-operating-systems.html
|
||||
[2]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE21620&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[3]: https://www.youtube.com/playlist?list=PL7D2RMSmRO9J8OTpjFECi8DJiTQdd4hua
|
||||
[4]: https://www.networkworld.com/article/3441777/how-the-linux-screen-tool-can-save-your-tasks-and-your-sanity-if-ssh-is-interrupted.html
|
||||
[5]: https://www.facebook.com/NetworkWorld/
|
||||
[6]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,57 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11817-1.html)
|
||||
[#]: subject: (What's your favorite Linux terminal trick?)
|
||||
[#]: via: (https://opensource.com/article/20/1/linux-terminal-trick)
|
||||
[#]: author: (Opensource.com https://opensource.com/users/admin)
|
||||
|
||||
你有什么喜欢的 Linux 终端技巧?
|
||||
======
|
||||
|
||||
> 告诉我们你最喜欢的终端技巧,无论是提高生产率的快捷方式还是有趣的彩蛋。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/25/135858accxc70tfxuifxx1.jpg)
|
||||
|
||||
新年伊始始终是评估提高效率的新方法的好时机。许多人尝试使用新的生产力工具,或者想找出如何优化其最常用的流程。终端是一个需要评估的领域,尤其是在开源世界中,有无数种方法可以通过快捷键和命令使终端上的生活更加高效(又有趣!)。
|
||||
|
||||
我们向作者们询问了他们最喜欢的终端技巧。他们分享了一些节省时间的技巧,甚至还有一个有趣的终端彩蛋。你会采用这些键盘快捷键或命令行技巧吗?你有喜欢分享的最爱吗?请发表评论来告诉我们。
|
||||
|
||||
“我找不出哪个是我最喜欢的;每天我都会使用这三个:
|
||||
|
||||
* `Ctrl + L` 来清除屏幕(而不是键入 `clear`)。
|
||||
* `sudo !!` 以 `sudo` 特权运行先前的命令。
|
||||
* `grep -Ev '^#|^$' <file>` 将显示文件内容,不带注释或空行。” —Mars Toktonaliev
|
||||
|
||||
“对我来说,如果我正在使用终端文本编辑器,并且希望将其丢开,以便可以快速执行其他操作,则可以使用 `Ctrl + Z` 将其放到后台,接着执行我需要做的一切,然后用 `fg` 将其带回前台。有时我也会对 `top` 或 `htop` 做同样的事情。我可以将其丢到后台,并在我想检查当前性能时随时将其带回前台。我不会将通常很快能完成的任务在前后台之间切换,它确实可以增强终端上的多任务处理能力。” —Jay LaCroix
|
||||
|
||||
“我经常在某一天在终端中做很多相同的事情,有两件事是每天都不变的:
|
||||
|
||||
* `Ctrl + R` 反向搜索我的 Bash 历史记录以查找我已经运行并且希望再次执行的命令。
|
||||
* 插入号(`^`)替换是最好的,因为我经常做诸如 `sudo dnf search <package name>` 之类的事情,然后,如果我以这种方式找到合适的软件包,则执行 `^search^install` 来重新运行该命令,以 `install` 替换 `search`。
|
||||
|
||||
这些东西肯定是很基本的,但是对我来说却节省了时间。” —Steve Morris
|
||||
|
||||
“我的炫酷终端技巧不是我在终端上执行的操作,而是我使用的终端。有时候我只是想要使用 Apple II 或旧式琥珀色终端的感觉,那我就启动了 Cool-Retro-Term。它的截屏可以在这个[网站][2]上找到。” —Jim Hall
|
||||
|
||||
“可能是用 `ssh -X` 来在其他计算机上运行图形程序。(在某些终端仿真器上,例如 gnome-terminal)用 `C-S c` 和 `C-S v` 复制/粘贴。我不确定这是否有价值(因为它有趣的是以 ssh 启动的图形化)。最近,我需要登录另一台计算机,但是我的孩子们可以在笔记本电脑的大屏幕上看到它。这个[链接][3]向我展示了一些我从未见过的内容:通过局域网从我的笔记本电脑上镜像来自另一台计算机屏幕上的活动会话(`x11vnc -desktop`),并能够同时从两台计算机上进行控制。” —Kyle R. Conway
|
||||
|
||||
“你可以安装 `sl`(`$ sudo apt install sl` 或 `$ sudo dnf install sl`),并且当在 Bash 中输入命令 `sl` 时,一个基于文本的蒸汽机车就会在显示屏上移动。” —Don Watkins
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/linux-terminal-trick
|
||||
|
||||
作者:[Opensource.com][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/admin
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/terminal_command_linux_desktop_code.jpg?itok=p5sQ6ODE (Terminal command prompt on orange background)
|
||||
[2]: https://github.com/Swordfish90/cool-retro-term
|
||||
[3]: https://elinux.org/Screen_Casting_on_a_Raspberry_Pi
|
@ -0,0 +1,202 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (laingke)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11830-1.html)
|
||||
[#]: subject: (Setting up passwordless Linux logins using public/private keys)
|
||||
[#]: via: (https://www.networkworld.com/article/3514607/setting-up-passwordless-linux-logins-using-publicprivate-keys.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
使用公钥/私钥对设定免密的 Linux 登录方式
|
||||
======
|
||||
|
||||
> 使用一组公钥/私钥对让你不需要密码登录到远程 Linux 系统或使用 ssh 运行命令,这会非常方便,但是设置过程有点复杂。下面是帮助你的方法和脚本。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202001/29/141343ldps4muy4kp64k4l.jpg)
|
||||
|
||||
在 [Linux][1] 系统上设置一个允许你无需密码即可远程登录或运行命令的帐户并不难,但是要使它正常工作,你还需要掌握一些繁琐的细节。在本文,我们将完成整个过程,然后给出一个可以帮助处理琐碎细节的脚本。
|
||||
|
||||
设置好之后,如果希望在脚本中运行 `ssh` 命令,尤其是希望配置自动运行的命令,那么免密访问特别有用。
|
||||
|
||||
需要注意的是,你不需要在两个系统上使用相同的用户帐户。实际上,你可以把公用密钥用于系统上的多个帐户或多个系统上的不同帐户。
|
||||
|
||||
设置方法如下。
|
||||
|
||||
### 在哪个系统上启动?
|
||||
|
||||
首先,你需要从要发出命令的系统上着手。那就是你用来创建 `ssh` 密钥的系统。你还需要可以访问远程系统上的帐户并在其上运行这些命令。
|
||||
|
||||
为了使角色清晰明了,我们将场景中的第一个系统称为 “boss”,因为它将发出要在另一个系统上运行的命令。
|
||||
|
||||
因此,命令提示符如下:
|
||||
|
||||
```
|
||||
boss$
|
||||
```
|
||||
|
||||
如果你还没有在 boss 系统上为你的帐户设置公钥/私钥对,请使用如下所示的命令创建一个密钥对。注意,你可以在各种加密算法之间进行选择。(一般使用 RSA 或 DSA。)注意,要在不输入密码的情况下访问系统,你需要在下面的对话框中的两个提示符出不输入密码。
|
||||
|
||||
如果你已经有一个与此帐户关联的公钥/私钥对,请跳过此步骤。
|
||||
|
||||
```
|
||||
boss$ ssh-keygen -t rsa
|
||||
Generating public/private rsa key pair.
|
||||
Enter file in which to save the key (/home/myself/.ssh/id_rsa):
|
||||
Enter passphrase (empty for no passphrase): <== 按下回车键即可
|
||||
Enter same passphrase again: <== 按下回车键即可
|
||||
Your identification has been saved in /home/myself/.ssh/id_rsa.
|
||||
Your public key has been saved in /home/myself/.ssh/id_rsa.pub.
|
||||
The key fingerprint is:
|
||||
SHA256:1zz6pZcMjA1av8iyojqo6NVYgTl1+cc+N43kIwGKOUI myself@boss
|
||||
The key's randomart image is:
|
||||
+---[RSA 3072]----+
|
||||
| . .. |
|
||||
| E+ .. . |
|
||||
| .+ .o + o |
|
||||
| ..+.. .o* . |
|
||||
| ... So+*B o |
|
||||
| + ...==B . |
|
||||
| . o . ....++. |
|
||||
|o o . . o..o+ |
|
||||
|=..o.. ..o o. |
|
||||
+----[SHA256]-----+
|
||||
```
|
||||
|
||||
上面显示的命令将创建公钥和私钥。其中公钥用于加密,私钥用于解密。因此,这些密钥之间的关系是关键的,私有密钥**绝不**应该被共享。相反,它应该保存在 boss 系统的 `.ssh` 文件夹中。
|
||||
|
||||
注意,在创建时,你的公钥和私钥将会保存在 `.ssh` 文件夹中。
|
||||
|
||||
下一步是将**公钥**复制到你希望从 boss 系统免密访问的系统。你可以使用 `scp` 命令来完成此操作,但此时你仍然需要输入密码。在本例中,该系统称为 “target”。
|
||||
|
||||
```
|
||||
boss$ scp .ssh/id_rsa.pub myacct@target:/home/myaccount
|
||||
myacct@target's password:
|
||||
```
|
||||
|
||||
你需要安装公钥在 target 系统(将运行命令的系统)上。如果你没有 `.ssh` 目录(例如,你从未在该系统上使用过 `ssh`),运行这样的命令将为你设置一个目录:
|
||||
|
||||
```
|
||||
target$ ssh localhost date
|
||||
target$ ls -la .ssh
|
||||
total 12
|
||||
drwx------ 2 myacct myacct 4096 Jan 19 11:48 .
|
||||
drwxr-xr-x 6 myacct myacct 4096 Jan 19 11:49 ..
|
||||
-rw-r--r-- 1 myacct myacct 222 Jan 19 11:48 known_hosts
|
||||
```
|
||||
|
||||
仍然在目标系统上,你需要将从“boss”系统传输的公钥添加到 `.ssh/authorized_keys` 文件中。如果该文件已经存在,使用下面的命令将把它添加到文件的末尾;如果文件不存在,则创建该文件并添加密钥。
|
||||
|
||||
```
|
||||
target$ cat id_rsa.pub >> .ssh/authorized_keys
|
||||
```
|
||||
|
||||
下一步,你需要确保你的 `authorized_keys` 文件权限为 600。如果还不是,执行命令 `chmod 600 .ssh/authorized_keys`。
|
||||
|
||||
```
|
||||
target$ ls -l authorized_keys
|
||||
-rw------- 1 myself myself 569 Jan 19 12:10 authorized_keys
|
||||
```
|
||||
|
||||
还要检查目标系统上 `.ssh` 目录的权限是否设置为 700。如果需要,执行 `chmod 700 .ssh` 命令修改权限。
|
||||
|
||||
```
|
||||
target$ ls -ld .ssh
|
||||
drwx------ 2 myacct myacct 4096 Jan 14 15:54 .ssh
|
||||
```
|
||||
|
||||
此时,你应该能够从 boss 系统远程免密运行命令到目标系统。除非目标系统上的目标用户帐户拥有与你试图连接的用户和主机相同的旧公钥,否则这应该可以工作。如果是这样,你应该删除早期的(并冲突的)条目。
|
||||
|
||||
### 使用脚本
|
||||
|
||||
使用脚本可以使某些工作变得更加容易。但是,在下面的示例脚本中,你会遇到的一个烦人的问题是,在配置免密访问权限之前,你必须多次输入目标用户的密码。一种选择是将脚本分为两部分——需要在 boss 系统上运行的命令和需要在 target 系统上运行的命令。
|
||||
|
||||
这是“一步到位”版本的脚本:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
# NOTE: This script requires that you have the password for the remote acct
|
||||
# in order to set up password-free access using your public key
|
||||
|
||||
LOC=`hostname` # the local system from which you want to run commands from
|
||||
# wo a password
|
||||
|
||||
# get target system and account
|
||||
echo -n "target system> "
|
||||
read REM
|
||||
echo -n "target user> "
|
||||
read user
|
||||
|
||||
# create a key pair if no public key exists
|
||||
if [ ! -f ~/.ssh/id_rsa.pub ]; then
|
||||
ssh-keygen -t rsa
|
||||
fi
|
||||
|
||||
# ensure a .ssh directory exists in the remote account
|
||||
echo checking for .ssh directory on remote system
|
||||
ssh $user@$REM "if [ ! -d /home/$user/.ssh ]; then mkdir /home/$user/.ssh; fi"
|
||||
|
||||
# share the public key (using local hostname)
|
||||
echo copying the public key
|
||||
scp ~/.ssh/id_rsa.pub $user@$REM:/home/$user/$user-$LOC.pub
|
||||
|
||||
# put the public key into the proper location
|
||||
echo adding key to authorized_keys
|
||||
ssh $user@$REM "cat /home/$user/$user-$LOC.pub >> /home/$user/.ssh/authorized_ke
|
||||
ys"
|
||||
|
||||
# set permissions on authorized_keys and .ssh (might be OK already)
|
||||
echo setting permissions
|
||||
ssh $user@$REM "chmod 600 ~/.ssh/authorized_keys"
|
||||
ssh $user@$REM "chmod 700 ~/.ssh"
|
||||
|
||||
# try it out -- should NOT ask for a password
|
||||
echo testing -- if no password is requested, you are all set
|
||||
ssh $user@$REM /bin/hostname
|
||||
```
|
||||
|
||||
脚本已经配置为在你每次必须输入密码时告诉你它正在做什么。交互看起来是这样的:
|
||||
|
||||
```
|
||||
$ ./rem_login_setup
|
||||
target system> fruitfly
|
||||
target user> lola
|
||||
checking for .ssh directory on remote system
|
||||
lola@fruitfly's password:
|
||||
copying the public key
|
||||
lola@fruitfly's password:
|
||||
id_rsa.pub 100% 567 219.1KB/s 00:00
|
||||
adding key to authorized_keys
|
||||
lola@fruitfly's password:
|
||||
setting permissions
|
||||
lola@fruitfly's password:
|
||||
testing -- if no password is requested, you are all set
|
||||
fruitfly
|
||||
```
|
||||
|
||||
在上面的场景之后,你就可以像这样登录到 lola 的帐户:
|
||||
|
||||
```
|
||||
$ ssh lola@fruitfly
|
||||
[lola@fruitfly ~]$
|
||||
```
|
||||
|
||||
一旦设置了免密登录,你就可以不需要键入密码从 boss 系统登录到 target 系统,并且运行任意的 `ssh` 命令。以这种免密的方式运行并不意味着你的帐户不安全。然而,根据 target 系统的性质,保护你在 boss 系统上的密码可能变得更加重要。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3514607/setting-up-passwordless-linux-logins-using-publicprivate-keys.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[laingke](https://github.com/laingke)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.networkworld.com/article/3215226/what-is-linux-uses-featres-products-operating-systems.html
|
||||
[2]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE21620&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[3]: https://www.networkworld.com/article/3143050/linux/linux-hardening-a-15-step-checklist-for-a-secure-linux-server.html#tk.nww-fsb
|
||||
[4]: https://www.facebook.com/NetworkWorld/
|
||||
[5]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,165 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11827-1.html)
|
||||
[#]: subject: (Wine 5.0 is Released! Here’s How to Install it)
|
||||
[#]: via: (https://itsfoss.com/wine-5-release/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Wine 5.0 发布了!
|
||||
======
|
||||
|
||||
> Wine 的一个新的主要版本发布了。使用 Wine 5.0,在 Linux 上运行 Windows 应用程序和游戏的体验得到进一步改进。
|
||||
|
||||
通过一些努力,你可以使用 Wine [在 Linux 上运行 Windows 应用程序][1]。当你必须使用一个仅在 Windows 上可用的软件时,Wine 是一个可以尝试的工具。它支持许多这样的软件。
|
||||
|
||||
Wine 的一个新的主要发布版本已经降临,即 Wine 5.0,几乎距它的 4.0 发布一年之后。
|
||||
|
||||
Wine 5.0 发布版本引进了几个主要特性和很多显著的更改/改进。在这篇文章中,我将重点介绍新的特性是什么,并且也将提到安装说明。
|
||||
|
||||
### 在 Wine 5.0 中有什么新的特性?
|
||||
|
||||
![][2]
|
||||
|
||||
如他们的[官方声明][3]所述,这是 5.0 发布版本中的关键更改:
|
||||
|
||||
* PE 格式的内置模块。
|
||||
* 支持多显示器。
|
||||
* 重新实现了 XAudio2。
|
||||
* 支持 Vulkan 1.1。
|
||||
* 支持微软安装程序(MSI)补丁文件。
|
||||
* 性能提升。
|
||||
|
||||
因此,随着 Vulkan 1.1 和对多显示器的支持 —— Wine 5.0 发布版本是一件大事。
|
||||
|
||||
除了上面强调的这些关键内容以外,在新的版本中包含成千上万的更改/改进中,你还可以期待对控制器的支持更好。
|
||||
|
||||
值得注意的是,此版本特别纪念了 **Józef Kucia**(vkd3d 项目的首席开发人员)。
|
||||
|
||||
他们也已经在[发布说明][4]中提到这一点:
|
||||
|
||||
> 这个发布版本特别纪念了 Józef Kucia,他于 2019 年 8 月去世,年仅 30 岁。Józef 是 Wine 的 Direct3D 实现的一个主要贡献者,并且是 vkd3d 项目的首席开发人员。我们都非常怀念他的技能和友善。
|
||||
|
||||
### 如何在 Ubuntu 和 Linux Mint 上安装 Wine 5.0
|
||||
|
||||
> 注意:
|
||||
|
||||
> 如果你在以前安装过 Wine,你应该将其完全移除,以(如你希望的)避免一些冲突。此外,WineHQ 存储库的密钥最近已被更改,针对你的 Linux 发行版的更多的操作指南,你可以参考它的[下载页面][5]。
|
||||
|
||||
Wine 5.0 的源码可在它的[官方网站][3]上获得。为了使其工作,你可以阅读更多关于[构建 Wine][6] 的信息。基于 Arch 的用户应该很快就会得到它。
|
||||
|
||||
在这里,我将向你展示在 Ubuntu 和其它基于 Ubuntu 的发行版上安装 Wine 5.0 的步骤。请耐心,并按照步骤一步一步安装和使用 Wine。这里涉及几个步骤。
|
||||
|
||||
请记住,Wine 安装了太多软件包。你会看到大量的软件包列表,下载大小约为 1.3 GB。
|
||||
|
||||
### 在 Ubuntu 上安装 Wine 5.0(不适用于 Linux Mint)
|
||||
|
||||
首先,使用这个命令来移除现存的 Wine:
|
||||
|
||||
```
|
||||
sudo apt remove winehq-stable wine-stable wine1.6 wine-mono wine-geco winetricks
|
||||
```
|
||||
|
||||
然后确保添加 32 位体系结构支持:
|
||||
|
||||
```
|
||||
sudo dpkg --add-architecture i386
|
||||
```
|
||||
|
||||
下载并添加官方 Wine 存储库密钥:
|
||||
|
||||
```
|
||||
wget -qO - https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add -
|
||||
```
|
||||
|
||||
现在,接下来的步骤需要添加存储库,为此, 你需要首先[知道你的 Ubuntu 版本][7]。
|
||||
|
||||
对于 **Ubuntu 18.04 和 19.04**,用这个 PPA 添加 FAudio 依赖, **Ubuntu 19.10** 不需要它:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:cybermax-dexter/sdl2-backport
|
||||
```
|
||||
|
||||
现在使用此命令添加存储库:
|
||||
|
||||
```
|
||||
sudo apt-add-repository "deb https://dl.winehq.org/wine-builds/ubuntu $(lsb_release -cs) main"
|
||||
```
|
||||
|
||||
现在你已经添加了正确的存储库,可以使用以下命令安装 Wine 5.0:
|
||||
|
||||
```
|
||||
sudo apt update && sudo apt install --install-recommends winehq-stable
|
||||
```
|
||||
|
||||
请注意,尽管[在软件包列表中将 Wine 5 列为稳定版][8],但你仍可能会看到 winehq-stable 的 wine 4.0.3。也许它不会传播到所有地理位置。从今天早上开始,我可以看到 Wine 5.0。
|
||||
|
||||
### 在 Linux Mint 19.1、19.2 和 19.3 中安装 Wine 5.0
|
||||
|
||||
正如一些读者通知我的那样,[apt-add 存储库命令][9]不适用于 Linux Mint 19.x 系列。
|
||||
|
||||
这是添加自定义存储库的另一种方法。你必须执行与 Ubuntu 相同的步骤。如删除现存的 Wine 包:
|
||||
|
||||
```
|
||||
sudo apt remove winehq-stable wine-stable wine1.6 wine-mono wine-geco winetricks
|
||||
```
|
||||
|
||||
添加 32 位支持:
|
||||
|
||||
```
|
||||
sudo dpkg --add-architecture i386
|
||||
```
|
||||
|
||||
然后添加 GPG 密钥:
|
||||
|
||||
```
|
||||
wget -qO - https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add -
|
||||
```
|
||||
|
||||
添加 FAudio 依赖:
|
||||
|
||||
```
|
||||
sudo add-apt-repository ppa:cybermax-dexter/sdl2-backport
|
||||
```
|
||||
|
||||
现在为 Wine 存储库创建一个新条目:
|
||||
|
||||
```
|
||||
sudo sh -c "echo 'deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main' >> /etc/apt/sources.list.d/winehq.list"
|
||||
```
|
||||
|
||||
更新软件包列表并安装Wine:
|
||||
|
||||
```
|
||||
sudo apt update && sudo apt install --install-recommends winehq-stable
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
你尝试过最新的 Wine 5.0 发布版本吗?如果是的话,在运行中你看到什么改进?
|
||||
|
||||
在下面的评论区域,让我知道你对新的发布版本的看法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/wine-5-release/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/use-windows-applications-linux/
|
||||
[2]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/wine_5.png?ssl=1
|
||||
[3]: https://www.winehq.org/news/2020012101
|
||||
[4]: https://www.winehq.org/announce/5.0
|
||||
[5]: https://wiki.winehq.org/Download
|
||||
[6]: https://wiki.winehq.org/Building_Wine
|
||||
[7]: https://itsfoss.com/how-to-know-ubuntu-unity-version/
|
||||
[8]: https://dl.winehq.org/wine-builds/ubuntu/dists/bionic/main/binary-amd64/
|
||||
[9]: https://itsfoss.com/add-apt-repository-command-not-found/
|
@ -0,0 +1,456 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (laingke)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11857-1.html)
|
||||
[#]: subject: (Data streaming and functional programming in Java)
|
||||
[#]: via: (https://opensource.com/article/20/1/javastream)
|
||||
[#]: author: (Marty Kalin https://opensource.com/users/mkalindepauledu)
|
||||
|
||||
Java 中的数据流和函数式编程
|
||||
======
|
||||
|
||||
> 学习如何使用 Java 8 中的流 API 和函数式编程结构。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/06/002505flazlb4cg4aavvb4.jpg)
|
||||
|
||||
当 Java SE 8(又名核心 Java 8)在 2014 年被推出时,它引入了一些更改,从根本上影响了用它进行的编程。这些更改中有两个紧密相连的部分:流 API 和函数式编程构造。本文使用代码示例,从基础到高级特性,介绍每个部分并说明它们之间的相互作用。
|
||||
|
||||
### 基础特性
|
||||
|
||||
流 API 是在数据序列中迭代元素的简洁而高级的方法。包 `java.util.stream` 和 `java.util.function` 包含了用于流 API 和相关函数式编程构造的新库。当然,代码示例胜过千言万语。
|
||||
|
||||
下面的代码段用大约 2,000 个随机整数值填充了一个 `List`:
|
||||
|
||||
```
|
||||
Random rand = new Random2();
|
||||
List<Integer> list = new ArrayList<Integer>(); // 空 list
|
||||
for (int i = 0; i < 2048; i++) list.add(rand.nextInt()); // 填充它
|
||||
```
|
||||
|
||||
另外用一个 `for` 循环可用于遍历填充列表,以将偶数值收集到另一个列表中。
|
||||
|
||||
流 API 提供了一种更简洁的方法来执行此操作:
|
||||
|
||||
```
|
||||
List <Integer> evens = list
|
||||
.stream() // 流化 list
|
||||
.filter(n -> (n & 0x1) == 0) // 过滤出奇数值
|
||||
.collect(Collectors.toList()); // 收集偶数值
|
||||
```
|
||||
|
||||
这个例子有三个来自流 API 的函数:
|
||||
|
||||
- `stream` 函数可以将**集合**转换为流,而流是一个每次可访问一个值的传送带。流化是惰性的(因此也是高效的),因为值是根据需要产生的,而不是一次性产生的。
|
||||
- `filter` 函数确定哪些流的值(如果有的话)通过了处理管道中的下一个阶段,即 `collect` 阶段。`filter` 函数是 <ruby>高阶的<rt>higher-order</rt></ruby>,因为它的参数是一个函数 —— 在这个例子中是一个 lambda 表达式,它是一个未命名的函数,并且是 Java 新的函数式编程结构的核心。
|
||||
|
||||
lambda 语法与传统的 Java 完全不同:
|
||||
|
||||
```
|
||||
n -> (n & 0x1) == 0
|
||||
```
|
||||
|
||||
箭头(一个减号后面紧跟着一个大于号)将左边的参数列表与右边的函数体分隔开。参数 `n` 虽未明确类型,但也可以明确。在任何情况下,编译器都会发现 `n` 是个 `Integer`。如果有多个参数,这些参数将被括在括号中,并用逗号分隔。
|
||||
|
||||
在本例中,函数体检查一个整数的最低位(最右)是否为零,这用来表示偶数。过滤器应返回一个布尔值。尽管可以,但该函数的主体中没有显式的 `return`。如果主体没有显式的 `return`,则主体的最后一个表达式即是返回值。在这个例子中,主体按照 lambda 编程的思想编写,由一个简单的布尔表达式 `(n & 0x1) == 0` 组成。
|
||||
|
||||
- `collect` 函数将偶数值收集到引用为 `evens` 的列表中。如下例所示,`collect` 函数是线程安全的,因此,即使在多个线程之间共享了过滤操作,该函数也可以正常工作。
|
||||
|
||||
### 方便的功能和轻松实现多线程
|
||||
|
||||
在生产环境中,数据流的源可能是文件或网络连接。为了学习流 API, Java 提供了诸如 `IntStream` 这样的类型,它可以用各种类型的元素生成流。这里有一个 `IntStream` 的例子:
|
||||
|
||||
```
|
||||
IntStream // 整型流
|
||||
.range(1, 2048) // 生成此范围内的整型流
|
||||
.parallel() // 为多个线程分区数据
|
||||
.filter(i -> ((i & 0x1) > 0)) // 奇偶校验 - 只允许奇数通过
|
||||
.forEach(System.out::println); // 打印每个值
|
||||
```
|
||||
|
||||
`IntStream` 类型包括一个 `range` 函数,该函数在指定的范围内生成一个整数值流,在本例中,以 1 为增量,从 1 递增到 2048。`parallel` 函数自动划分该工作到多个线程中,在各个线程中进行过滤和打印。(线程数通常与主机系统上的 CPU 数量匹配。)函数 `forEach` 参数是一个*方法引用*,在本例中是对封装在 `System.out` 中的 `println` 方法的引用,方法输出类型为 `PrintStream`。方法和构造器引用的语法将在稍后讨论。
|
||||
|
||||
由于具有多线程,因此整数值整体上以任意顺序打印,但在给定线程中是按顺序打印的。例如,如果线程 T1 打印 409 和 411,那么 T1 将按照顺序 409-411 打印,但是其它某个线程可能会预先打印 2045。`parallel` 调用后面的线程是并发执行的,因此它们的输出顺序是不确定的。
|
||||
|
||||
### map/reduce 模式
|
||||
|
||||
*map/reduce* 模式在处理大型数据集方面变得很流行。一个 map/reduce 宏操作由两个微操作构成。首先,将数据分散(<ruby>映射<rt>mapped</rt></ruby>)到各个工作程序中,然后将单独的结果收集在一起 —— 也可能收集统计起来成为一个值,即<ruby>归约<rt>reduction</rt></ruby>。归约可以采用不同的形式,如以下示例所示。
|
||||
|
||||
下面 `Number` 类的实例用 `EVEN` 或 `ODD` 表示有奇偶校验的整数值:
|
||||
|
||||
```
|
||||
public class Number {
|
||||
enum Parity { EVEN, ODD }
|
||||
private int value;
|
||||
public Number(int n) { setValue(n); }
|
||||
public void setValue(int value) { this.value = value; }
|
||||
public int getValue() { return this.value; }
|
||||
public Parity getParity() {
|
||||
return ((value & 0x1) == 0) ? Parity.EVEN : Parity.ODD;
|
||||
}
|
||||
public void dump() {
|
||||
System.out.format("Value: %2d (parity: %s)\n", getValue(),
|
||||
(getParity() == Parity.ODD ? "odd" : "even"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
下面的代码演示了用 `Number` 流进行 map/reduce 的情形,从而表明流 API 不仅可以处理 `int` 和 `float` 等基本类型,还可以处理程序员自定义的类类型。
|
||||
|
||||
在下面的代码段中,使用了 `parallelStream` 而不是 `stream` 函数对随机整数值列表进行流化处理。与前面介绍的 `parallel` 函数一样,`parallelStream` 变体也可以自动执行多线程。
|
||||
|
||||
```
|
||||
final int howMany = 200;
|
||||
Random r = new Random();
|
||||
Number[] nums = new Number[howMany];
|
||||
for (int i = 0; i < howMany; i++) nums[i] = new Number(r.nextInt(100));
|
||||
List<Number> listOfNums = Arrays.asList(nums); // 将数组转化为 list
|
||||
|
||||
Integer sum4All = listOfNums
|
||||
.parallelStream() // 自动执行多线程
|
||||
.mapToInt(Number::getValue) // 使用方法引用,而不是 lambda
|
||||
.sum(); // 将流值计算出和值
|
||||
System.out.println("The sum of the randomly generated values is: " + sum4All);
|
||||
```
|
||||
|
||||
高阶的 `mapToInt` 函数可以接受一个 lambda 作为参数,但在本例中,它接受一个方法引用,即 `Number::getValue`。`getValue` 方法不需要参数,它返回给定的 `Number` 实例的 `int` 值。语法并不复杂:类名 `Number` 后跟一个双冒号和方法名。回想一下先前的例子 `System.out::println`,它在 `System` 类中的 `static` 属性 `out` 后面有一个双冒号。
|
||||
|
||||
方法引用 `Number::getValue` 可以用下面的 lambda 表达式替换。参数 `n` 是流中的 `Number` 实例中的之一:
|
||||
|
||||
```
|
||||
mapToInt(n -> n.getValue())
|
||||
```
|
||||
|
||||
通常,lambda 表达式和方法引用是可互换的:如果像 `mapToInt` 这样的高阶函数可以采用一种形式作为参数,那么这个函数也可以采用另一种形式。这两个函数式编程结构具有相同的目的 —— 对作为参数传入的数据执行一些自定义操作。在两者之间进行选择通常是为了方便。例如,lambda 可以在没有封装类的情况下编写,而方法则不能。我的习惯是使用 lambda,除非已经有了适当的封装方法。
|
||||
|
||||
当前示例末尾的 `sum` 函数通过结合来自 `parallelStream` 线程的部分和,以线程安全的方式进行归约。但是,程序员有责任确保在 `parallelStream` 调用引发的多线程过程中,程序员自己的函数调用(在本例中为 `getValue`)是线程安全的。
|
||||
|
||||
最后一点值得强调。lambda 语法鼓励编写<ruby>纯函数<rt>pure function</rt></ruby>,即函数的返回值仅取决于传入的参数(如果有);纯函数没有副作用,例如更新一个类中的 `static` 字段。因此,纯函数是线程安全的,并且如果传递给高阶函数的函数参数(例如 `filter` 和 `map` )是纯函数,则流 API 效果最佳。
|
||||
|
||||
对于更细粒度的控制,有另一个流 API 函数,名为 `reduce`,可用于对 `Number` 流中的值求和:
|
||||
|
||||
```
|
||||
Integer sum4AllHarder = listOfNums
|
||||
.parallelStream() // 多线程
|
||||
.map(Number::getValue) // 每个 Number 的值
|
||||
.reduce(0, (sofar, next) -> sofar + next); // 求和
|
||||
```
|
||||
|
||||
此版本的 `reduce` 函数带有两个参数,第二个参数是一个函数:
|
||||
|
||||
- 第一个参数(在这种情况下为零)是*特征*值,该值用作求和操作的初始值,并且在求和过程中流结束时用作默认值。
|
||||
- 第二个参数是*累加器*,在本例中,这个 lambda 表达式有两个参数:第一个参数(`sofar`)是正在运行的和,第二个参数(`next`)是来自流的下一个值。运行的和以及下一个值相加,然后更新累加器。请记住,由于开始时调用了 `parallelStream`,因此 `map` 和 `reduce` 函数现在都在多线程上下文中执行。
|
||||
|
||||
在到目前为止的示例中,流值被收集,然后被规约,但是,通常情况下,流 API 中的 `Collectors` 可以累积值,而不需要将它们规约到单个值。正如下一个代码段所示,收集活动可以生成任意丰富的数据结构。该示例使用与前面示例相同的 `listOfNums`:
|
||||
|
||||
```
|
||||
Map<Number.Parity, List<Number>> numMap = listOfNums
|
||||
.parallelStream()
|
||||
.collect(Collectors.groupingBy(Number::getParity));
|
||||
|
||||
List<Number> evens = numMap.get(Number.Parity.EVEN);
|
||||
List<Number> odds = numMap.get(Number.Parity.ODD);
|
||||
```
|
||||
|
||||
第一行中的 `numMap` 指的是一个 `Map`,它的键是一个 `Number` 奇偶校验位(`ODD` 或 `EVEN`),其值是一个具有指定奇偶校验位值的 `Number` 实例的 `List`。同样,通过 `parallelStream` 调用进行多线程处理,然后 `collect` 调用(以线程安全的方式)将部分结果组装到 `numMap` 引用的 `Map` 中。然后,在 `numMap` 上调用 `get` 方法两次,一次获取 `evens`,第二次获取 `odds`。
|
||||
|
||||
实用函数 `dumpList` 再次使用来自流 API 的高阶 `forEach` 函数:
|
||||
|
||||
```
|
||||
private void dumpList(String msg, List<Number> list) {
|
||||
System.out.println("\n" + msg);
|
||||
list.stream().forEach(n -> n.dump()); // 或者使用 forEach(Number::dump)
|
||||
}
|
||||
```
|
||||
|
||||
这是示例运行中程序输出的一部分:
|
||||
|
||||
```
|
||||
The sum of the randomly generated values is: 3322
|
||||
The sum again, using a different method: 3322
|
||||
|
||||
Evens:
|
||||
|
||||
Value: 72 (parity: even)
|
||||
Value: 54 (parity: even)
|
||||
...
|
||||
Value: 92 (parity: even)
|
||||
|
||||
Odds:
|
||||
|
||||
Value: 35 (parity: odd)
|
||||
Value: 37 (parity: odd)
|
||||
...
|
||||
Value: 41 (parity: odd)
|
||||
```
|
||||
|
||||
### 用于代码简化的函数式结构
|
||||
|
||||
函数式结构(如方法引用和 lambda 表达式)非常适合在流 API 中使用。这些构造代表了 Java 中对高阶函数的主要简化。即使在糟糕的过去,Java 也通过 `Method` 和 `Constructor` 类型在技术上支持高阶函数,这些类型的实例可以作为参数传递给其它函数。由于其复杂性,这些类型在生产级 Java 中很少使用。例如,调用 `Method` 需要对象引用(如果方法是非**静态**的)或至少一个类标识符(如果方法是**静态**的)。然后,被调用的 `Method` 的参数作为**对象**实例传递给它,如果没有发生多态(那会出现另一种复杂性!),则可能需要显式向下转换。相比之下,lambda 和方法引用很容易作为参数传递给其它函数。
|
||||
|
||||
但是,新的函数式结构在流 API 之外具有其它用途。考虑一个 Java GUI 程序,该程序带有一个供用户按下的按钮,例如,按下以获取当前时间。按钮按下的事件处理程序可能编写如下:
|
||||
|
||||
```
|
||||
JButton updateCurrentTime = new JButton("Update current time");
|
||||
updateCurrentTime.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
currentTime.setText(new Date().toString());
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
这个简短的代码段很难解释。关注第二行,其中方法 `addActionListener` 的参数开始如下:
|
||||
|
||||
```
|
||||
new ActionListener() {
|
||||
```
|
||||
|
||||
这似乎是错误的,因为 `ActionListener` 是一个**抽象**接口,而**抽象**类型不能通过调用 `new` 实例化。但是,事实证明,还有其它一些实例被实例化了:一个实现此接口的未命名内部类。如果上面的代码封装在名为 `OldJava` 的类中,则该未命名的内部类将被编译为 `OldJava$1.class`。`actionPerformed` 方法在这个未命名的内部类中被重写。
|
||||
|
||||
现在考虑使用新的函数式结构进行这个令人耳目一新的更改:
|
||||
|
||||
```
|
||||
updateCurrentTime.addActionListener(e -> currentTime.setText(new Date().toString()));
|
||||
```
|
||||
|
||||
lambda 表达式中的参数 `e` 是一个 `ActionEvent` 实例,而 lambda 的主体是对按钮上的 `setText` 的简单调用。
|
||||
|
||||
### 函数式接口和函数组合
|
||||
|
||||
到目前为止,使用的 lambda 已经写好了。但是,为了方便起见,我们可以像引用封装方法一样引用 lambda 表达式。以下一系列简短示例说明了这一点。
|
||||
|
||||
考虑以下接口定义:
|
||||
|
||||
```
|
||||
@FunctionalInterface // 可选,通常省略
|
||||
interface BinaryIntOp {
|
||||
abstract int compute(int arg1, int arg2); // abstract 声明可以被删除
|
||||
}
|
||||
```
|
||||
|
||||
注释 `@FunctionalInterface` 适用于声明*唯一*抽象方法的任何接口;在本例中,这个抽象接口是 `compute`。一些标准接口,(例如具有唯一声明方法 `run` 的 `Runnable` 接口)同样符合这个要求。在此示例中,`compute` 是已声明的方法。该接口可用作引用声明中的目标类型:
|
||||
|
||||
```
|
||||
BinaryIntOp div = (arg1, arg2) -> arg1 / arg2;
|
||||
div.compute(12, 3); // 4
|
||||
```
|
||||
|
||||
包 `java.util.function` 提供各种函数式接口。以下是一些示例。
|
||||
|
||||
下面的代码段介绍了参数化的 `Predicate` 函数式接口。在此示例中,带有参数 `String` 的 `Predicate<String>` 类型可以引用具有 `String` 参数的 lambda 表达式或诸如 `isEmpty` 之类的 `String` 方法。通常情况下,Predicate 是一个返回布尔值的函数。
|
||||
|
||||
```
|
||||
Predicate<String> pred = String::isEmpty; // String 方法的 predicate 声明
|
||||
String[] strings = {"one", "two", "", "three", "four"};
|
||||
Arrays.asList(strings)
|
||||
.stream()
|
||||
.filter(pred) // 过滤掉非空字符串
|
||||
.forEach(System.out::println); // 只打印空字符串
|
||||
```
|
||||
|
||||
在字符串长度为零的情况下,`isEmpty` Predicate 判定结果为 `true`。 因此,只有空字符串才能进入管道的 `forEach` 阶段。
|
||||
|
||||
下一段代码将演示如何将简单的 lambda 或方法引用组合成更丰富的 lambda 或方法引用。考虑这一系列对 `IntUnaryOperator` 类型的引用的赋值,它接受一个整型参数并返回一个整型值:
|
||||
|
||||
```
|
||||
IntUnaryOperator doubled = n -> n * 2;
|
||||
IntUnaryOperator tripled = n -> n * 3;
|
||||
IntUnaryOperator squared = n -> n * n;
|
||||
```
|
||||
|
||||
`IntUnaryOperator` 是一个 `FunctionalInterface`,其唯一声明的方法为 `applyAsInt`。现在可以单独使用或以各种组合形式使用这三个引用 `doubled`、`tripled` 和 `squared`:
|
||||
|
||||
```
|
||||
int arg = 5;
|
||||
doubled.applyAsInt(arg); // 10
|
||||
tripled.applyAsInt(arg); // 15
|
||||
squared.applyAsInt(arg); // 25
|
||||
```
|
||||
|
||||
以下是一些函数组合的样例:
|
||||
|
||||
```
|
||||
int arg = 5;
|
||||
doubled.compose(squared).applyAsInt(arg); // 5 求 2 次方后乘 2:50
|
||||
tripled.compose(doubled).applyAsInt(arg); // 5 乘 2 后再乘 3:30
|
||||
doubled.andThen(squared).applyAsInt(arg); // 5 乘 2 后求 2 次方:100
|
||||
squared.andThen(tripled).applyAsInt(arg); // 5 求 2 次方后乘 3:75
|
||||
```
|
||||
|
||||
函数组合可以直接使用 lambda 表达式实现,但是引用使代码更简洁。
|
||||
|
||||
### 构造器引用
|
||||
|
||||
构造器引用是另一种函数式编程构造,而这些引用在比 lambda 和方法引用更微妙的上下文中非常有用。再一次重申,代码示例似乎是最好的解释方式。
|
||||
|
||||
考虑这个 [POJO][13] 类:
|
||||
|
||||
```
|
||||
public class BedRocker { // 基岩的居民
|
||||
private String name;
|
||||
public BedRocker(String name) { this.name = name; }
|
||||
public String getName() { return this.name; }
|
||||
public void dump() { System.out.println(getName()); }
|
||||
}
|
||||
```
|
||||
|
||||
该类只有一个构造函数,它需要一个 `String` 参数。给定一个名字数组,目标是生成一个 `BedRocker` 元素数组,每个名字代表一个元素。下面是使用了函数式结构的代码段:
|
||||
|
||||
```
|
||||
String[] names = {"Fred", "Wilma", "Peebles", "Dino", "Baby Puss"};
|
||||
|
||||
Stream<BedRocker> bedrockers = Arrays.asList(names).stream().map(BedRocker::new);
|
||||
BedRocker[] arrayBR = bedrockers.toArray(BedRocker[]::new);
|
||||
|
||||
Arrays.asList(arrayBR).stream().forEach(BedRocker::dump);
|
||||
```
|
||||
|
||||
在较高的层次上,这个代码段将名字转换为 `BedRocker` 数组元素。具体来说,代码如下所示。`Stream` 接口(在包 `java.util.stream` 中)可以被参数化,而在本例中,生成了一个名为 `bedrockers` 的 `BedRocker` 流。
|
||||
|
||||
`Arrays.asList` 实用程序再次用于流化一个数组 `names`,然后将流的每一项传递给 `map` 函数,该函数的参数现在是构造器引用 `BedRocker::new`。这个构造器引用通过在每次调用时生成和初始化一个 `BedRocker` 实例来充当一个对象工厂。在第二行执行之后,名为 `bedrockers` 的流由五项 `BedRocker` 组成。
|
||||
|
||||
这个例子可以通过关注高阶 `map` 函数来进一步阐明。在通常情况下,一个映射将一个类型的值(例如,一个 `int`)转换为另一个*相同*类型的值(例如,一个整数的后继):
|
||||
|
||||
```
|
||||
map(n -> n + 1) // 将 n 映射到其后继
|
||||
```
|
||||
|
||||
然而,在 `BedRocker` 这个例子中,转换更加戏剧化,因为一个类型的值(代表一个名字的 `String`)被映射到一个*不同*类型的值,在这个例子中,就是一个 `BedRocker` 实例,这个字符串就是它的名字。转换是通过一个构造器调用来完成的,它是由构造器引用来实现的:
|
||||
|
||||
```
|
||||
map(BedRocker::new) // 将 String 映射到 BedRocker
|
||||
```
|
||||
|
||||
传递给构造器的值是 `names` 数组中的其中一项。
|
||||
|
||||
此代码示例的第二行还演示了一个你目前已经非常熟悉的转换:先将数组先转换成 `List`,然后再转换成 `Stream`:
|
||||
|
||||
```
|
||||
Stream<BedRocker> bedrockers = Arrays.asList(names).stream().map(BedRocker::new);
|
||||
```
|
||||
|
||||
第三行则是另一种方式 —— 流 `bedrockers` 通过使用*数组*构造器引用 `BedRocker[]::new` 调用 `toArray` 方法:
|
||||
|
||||
```
|
||||
BedRocker[ ] arrayBR = bedrockers.toArray(BedRocker[]::new);
|
||||
```
|
||||
|
||||
该构造器引用不会创建单个 `BedRocker` 实例,而是创建这些实例的整个数组:该构造器引用现在为 `BedRocker[]:new`,而不是 `BedRocker::new`。为了进行确认,将 `arrayBR` 转换为 `List`,再次对其进行流式处理,以便可以使用 `forEach` 来打印 `BedRocker` 的名字。
|
||||
|
||||
```
|
||||
Fred
|
||||
Wilma
|
||||
Peebles
|
||||
Dino
|
||||
Baby Puss
|
||||
```
|
||||
|
||||
该示例对数据结构的微妙转换仅用几行代码即可完成,从而突出了可以将 lambda,方法引用或构造器引用作为参数的各种高阶函数的功能。
|
||||
|
||||
### <ruby>柯里化<rt>Currying</rt></ruby>
|
||||
|
||||
*柯里化*函数是指减少函数执行任何工作所需的显式参数的数量(通常减少到一个)。(该术语是为了纪念逻辑学家 Haskell Curry。)一般来说,函数的参数越少,调用起来就越容易,也更健壮。(回想一下一些需要半打左右参数的噩梦般的函数!)因此,应将柯里化视为简化函数调用的一种尝试。`java.util.function` 包中的接口类型适合于柯里化,如以下示例所示。
|
||||
|
||||
引用的 `IntBinaryOperator` 接口类型是为函数接受两个整型参数,并返回一个整型值:
|
||||
|
||||
```
|
||||
IntBinaryOperator mult2 = (n1, n2) -> n1 * n2;
|
||||
mult2.applyAsInt(10, 20); // 200
|
||||
mult2.applyAsInt(10, 30); // 300
|
||||
```
|
||||
|
||||
引用 `mult2` 强调了需要两个显式参数,在本例中是 10 和 20。
|
||||
|
||||
前面介绍的 `IntUnaryOperator` 比 `IntBinaryOperator` 简单,因为前者只需要一个参数,而后者则需要两个参数。两者均返回整数值。因此,目标是将名为 `mult2` 的两个参数 `IntBinraryOperator` 柯里化成一个单一的 `IntUnaryOperator` 版本 `curriedMult2`。
|
||||
|
||||
考虑 `IntFunction<R>` 类型。此类型的函数采用整型参数,并返回类型为 `R` 的结果,该结果可以是另一个函数 —— 更准确地说,是 `IntBinaryOperator`。让一个 lambda 返回另一个 lambda 很简单:
|
||||
|
||||
```
|
||||
arg1 -> (arg2 -> arg1 * arg2) // 括号可以省略
|
||||
```
|
||||
|
||||
完整的 lambda 以 `arg1` 开头,而该 lambda 的主体以及返回的值是另一个以 `arg2` 开头的 lambda。返回的 lambda 仅接受一个参数(`arg2`),但返回了两个数字的乘积(`arg1` 和 `arg2`)。下面的概述,再加上代码,应该可以更好地进行说明。
|
||||
|
||||
以下是如何柯里化 `mult2` 的概述:
|
||||
|
||||
- 类型为 `IntFunction<IntUnaryOperator>` 的 lambda 被写入并调用,其整型值为 10。返回的 `IntUnaryOperator` 缓存了值 10,因此变成了已柯里化版本的 `mult2`,在本例中为 `curriedMult2`。
|
||||
- 然后使用单个显式参数(例如,20)调用 `curriedMult2` 函数,该参数与缓存的参数(在本例中为 10)相乘以生成返回的乘积。。
|
||||
|
||||
这是代码的详细信息:
|
||||
|
||||
```
|
||||
// 创建一个接受一个参数 n1 并返回一个单参数 n2 -> n1 * n2 的函数,该函数返回一个(n1 * n2 乘积的)整型数。
|
||||
IntFunction<IntUnaryOperator> curriedMult2Maker = n1 -> (n2 -> n1 * n2);
|
||||
```
|
||||
|
||||
调用 `curriedMult2Maker` 生成所需的 `IntUnaryOperator` 函数:
|
||||
|
||||
```
|
||||
// 使用 curriedMult2Maker 获取已柯里化版本的 mult2。
|
||||
// 参数 10 是上面的 lambda 的 n1。
|
||||
IntUnaryOperator curriedMult2 = curriedMult2Maker2.apply(10);
|
||||
```
|
||||
|
||||
值 `10` 现在缓存在 `curriedMult2` 函数中,以便 `curriedMult2` 调用中的显式整型参数乘以 10:
|
||||
|
||||
```
|
||||
curriedMult2.applyAsInt(20); // 200 = 10 * 20
|
||||
curriedMult2.applyAsInt(80); // 800 = 10 * 80
|
||||
```
|
||||
|
||||
缓存的值可以随意更改:
|
||||
|
||||
```
|
||||
curriedMult2 = curriedMult2Maker.apply(50); // 缓存 50
|
||||
curriedMult2.applyAsInt(101); // 5050 = 101 * 50
|
||||
```
|
||||
|
||||
当然,可以通过这种方式创建多个已柯里化版本的 `mult2`,每个版本都有一个 `IntUnaryOperator`。
|
||||
|
||||
柯里化充分利用了 lambda 的强大功能:可以很容易地编写 lambda 表达式来返回需要的任何类型的值,包括另一个 lambda。
|
||||
|
||||
### 总结
|
||||
|
||||
Java 仍然是基于类的面向对象的编程语言。但是,借助流 API 及其支持的函数式构造,Java 向函数式语言(例如 Lisp)迈出了决定性的(同时也是受欢迎的)一步。结果是 Java 更适合处理现代编程中常见的海量数据流。在函数式方向上的这一步还使以在前面的代码示例中突出显示的管道的方式编写清晰简洁的 Java 代码更加容易:
|
||||
|
||||
```
|
||||
dataStream
|
||||
.parallelStream() // 多线程以提高效率
|
||||
.filter(...) // 阶段 1
|
||||
.map(...) // 阶段 2
|
||||
.filter(...) // 阶段 3
|
||||
...
|
||||
.collect(...); // 或者,也可以进行归约:阶段 N
|
||||
```
|
||||
|
||||
自动多线程,以 `parallel` 和 `parallelStream` 调用为例,建立在 Java 的 fork/join 框架上,该框架支持 <ruby>任务窃取<rt>task stealing</rt></ruby> 以提高效率。假设 `parallelStream` 调用后面的线程池由八个线程组成,并且 `dataStream` 被八种方式分区。某个线程(例如,T1)可能比另一个线程(例如,T7)工作更快,这意味着应该将 T7 的某些任务移到 T1 的工作队列中。这会在运行时自动发生。
|
||||
|
||||
在这个简单的多线程世界中,程序员的主要职责是编写线程安全函数,这些函数作为参数传递给在流 API 中占主导地位的高阶函数。尤其是 lambda 鼓励编写纯函数(因此是线程安全的)函数。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/javastream
|
||||
|
||||
作者:[Marty Kalin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[laingke](https://github.com/laingke)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mkalindepauledu
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/features_solutions_command_data.png?itok=4_VQN3RK (computer screen )
|
||||
[2]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+random
|
||||
[3]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+list
|
||||
[4]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+system
|
||||
[5]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+number
|
||||
[6]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+arrays
|
||||
[7]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+integer
|
||||
[8]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+string
|
||||
[9]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+jbutton
|
||||
[10]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+actionlistener
|
||||
[11]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+actionevent
|
||||
[12]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+date
|
||||
[13]: https://en.wikipedia.org/wiki/Plain_old_Java_object
|
626
published/20200103 Add scorekeeping to your Python game.md
Normal file
626
published/20200103 Add scorekeeping to your Python game.md
Normal file
@ -0,0 +1,626 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11839-1.html)
|
||||
[#]: subject: (Add scorekeeping to your Python game)
|
||||
[#]: via: (https://opensource.com/article/20/1/add-scorekeeping-your-python-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
添加计分到你的 Python 游戏
|
||||
======
|
||||
|
||||
> 在本系列的第十一篇有关使用 Python Pygame 模块进行编程的文章中,显示玩家获得战利品或受到伤害时的得分。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/01/154838led0y08y2aqetz1q.jpg)
|
||||
|
||||
这是仍在进行中的关于使用 [Pygame][3] 模块来在 [Python 3][2] 在创建电脑游戏的第十一部分。先前的文章是:
|
||||
|
||||
* [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][4]
|
||||
* [使用 Python 和 Pygame 模块构建一个游戏框架][5]
|
||||
* [如何在你的 Python 游戏中添加一个玩家][6]
|
||||
* [用 Pygame 使你的游戏角色移动起来][7]
|
||||
* [如何向你的 Python 游戏中添加一个敌人][8]
|
||||
* [在 Pygame 游戏中放置平台][19]
|
||||
* [在你的 Python 游戏中模拟引力][9]
|
||||
* [为你的 Python 平台类游戏添加跳跃功能][10]
|
||||
* [使你的 Python 游戏玩家能够向前和向后跑][11]
|
||||
* [在你的 Python 平台类游戏中放一些奖励][12]
|
||||
|
||||
如果你已经跟随这一系列很久,那么已经学习了使用 Python 创建一个视频游戏所需的所有基本语法和模式。然而,它仍然缺少一个至关重要的组成部分。这一组成部分不仅仅对用 Python 编程游戏重要;不管你探究哪个计算机分支,你都必需精通:作为一个程序员,通过阅读一种语言的或库的文档来学习新的技巧。
|
||||
|
||||
幸运的是,你正在阅读本文的事实表明你熟悉文档。为了使你的平台类游戏更加美观,在这篇文章中,你将在游戏屏幕上添加得分和生命值显示。不过,教你如何找到一个库的功能以及如何使用这些新的功能的这节课程并没有多神秘。
|
||||
|
||||
### 在 Pygame 中显示得分
|
||||
|
||||
现在,既然你有了可以被玩家收集的奖励,那就有充分的理由来记录分数,以便你的玩家看到他们收集了多少奖励。你也可以跟踪玩家的生命值,以便当他们被敌人击中时会有相应结果。
|
||||
|
||||
你已经有了跟踪分数和生命值的变量,但是这一切都发生在后台。这篇文章教你在游戏期间在游戏屏幕上以你选择的一种字体来显示这些统计数字。
|
||||
|
||||
### 阅读文档
|
||||
|
||||
大多数 Python 模块都有文档,即使那些没有文档的模块,也能通过 Python 的帮助功能来进行最小的文档化。[Pygame 的主页面][13] 链接了它的文档。不过,Pygame 是一个带有很多文档的大模块,并且它的文档不像在 Opensource.com 上的文章一样,以同样易理解的(和友好的、易解释的、有用的)叙述风格来撰写的。它们是技术文档,并且列出在模块中可用的每个类和函数,各自要求的输入类型等等。如果你不适应参考代码组件描述,这可能会令人不知所措。
|
||||
|
||||
在烦恼于库的文档前,第一件要做的事,就是来想想你正在尝试达到的目标。在这种情况下,你想在屏幕上显示玩家的得分和生命值。
|
||||
|
||||
在你确定你需要的结果后,想想它需要什么的组件。你可以从变量和函数的方面考虑这一点,或者,如果你还没有自然地想到这一点,你可以进行一般性思考。你可能意识到需要一些文本来显示一个分数,你希望 Pygame 在屏幕上绘制这些文本。如果你仔细思考,你可能会意识到它与在屏幕上渲染一个玩家、奖励或一个平台并多么大的不同。
|
||||
|
||||
从技术上讲,你*可以*使用数字图形,并让 Pygame 显示这些数字图形。它不是达到你目标的最容易的方法,但是如果它是你唯一知道的方法,那么它是一个有效的方法。不过,如果你参考 Pygame 的文档,你看到列出的模块之一是 `font`,这是 Pygame 使得在屏幕上来使打印文本像输入文字一样容易的方法。
|
||||
|
||||
### 解密技术文档
|
||||
|
||||
`font` 文档页面以 `pygame.font.init()` 开始,它列出了用于初始化字体模块的函数。它由 `pygame.init()` 自动地调用,你已经在代码中调用了它。再强调一次,从技术上讲,你已经到达一个*足够好*的点。虽然你尚不知道*如何做*,你知道你*能够*使用 `pygame.font` 函数来在屏幕上打印文本。
|
||||
|
||||
然而,如果你阅读更多一些,你会找到这里还有一种更好的方法来打印字体。`pygame.freetype` 模块在文档中的描述方式如下:
|
||||
|
||||
> `pygame.freetype` 模块是 `pygame.fontpygame` 模块的一个替代品,用于加载和渲染字体。它有原函数的所有功能,外加很多新的功能。
|
||||
|
||||
在 `pygame.freetype` 文档页面的下方,有一些示例代码:
|
||||
|
||||
```
|
||||
import pygame
|
||||
import pygame.freetype
|
||||
```
|
||||
|
||||
你的代码应该已经导入了 Pygame,不过,请修改你的 `import` 语句以包含 Freetype 模块:
|
||||
|
||||
```
|
||||
import pygame
|
||||
import sys
|
||||
import os
|
||||
import pygame.freetype
|
||||
```
|
||||
|
||||
### 在 Pygame 中使用字体
|
||||
|
||||
从 `font` 模块的描述中可以看出,显然 Pygame 使用一种字体(不管它的你提供的或内置到 Pygame 的默认字体)在屏幕上渲染字体。滚动浏览 `pygame.freetype` 文档来找到 `pygame.freetype.Font` 函数:
|
||||
|
||||
```
|
||||
pygame.freetype.Font
|
||||
从支持的字体文件中创建一个新的字体实例。
|
||||
|
||||
Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font
|
||||
|
||||
pygame.freetype.Font.name
|
||||
符合规则的字体名称。
|
||||
|
||||
pygame.freetype.Font.path
|
||||
字体文件路径。
|
||||
|
||||
pygame.freetype.Font.size
|
||||
在渲染中使用的默认点大小
|
||||
```
|
||||
|
||||
这描述了如何在 Pygame 中构建一个字体“对象”。把屏幕上的一个简单对象视为一些代码属性的组合对你来说可能不太自然,但是这与你构建英雄和敌人精灵的方式非常类似。你需要一个字体文件,而不是一个图像文件。在你有一个字体文件后,你可以在你的代码中使用 `pygame.freetype.Font` 函数来创建一个字体对象,然后使用该对象来在屏幕上渲染文本。
|
||||
|
||||
因为并不是世界上的每个人的电脑上都有完全一样的字体,因此将你选择的字体与你的游戏捆绑在一起是很重要的。要捆绑字体,首先在你的游戏文件夹中创建一个新的目录,放在你为图像而创建的文件目录旁边。称其为 `fonts` 。
|
||||
|
||||
即使你的计算机操作系统随附了几种字体,但是将这些字体给予其他人是非法的。这看起来很奇怪,但法律就是这样运作的。如果想与你的游戏一起随附一种字体,你必需找到一种开源或知识共享的字体,以允许你随游戏一起提供该字体。
|
||||
|
||||
专门提供自由和合法字体的网站包括:
|
||||
|
||||
* [Font Library][14]
|
||||
* [Font Squirrel][15]
|
||||
* [League of Moveable Type][16]
|
||||
|
||||
当你找到你喜欢的字体后,下载下来。解压缩 ZIP 或 [TAR][17] 文件,并移动 `.ttf` 或 `.otf` 文件到你的项目目录下的 `fonts` 文件夹中。
|
||||
|
||||
你没有安装字体到你的计算机上。你只是放置字体到你游戏的 `fonts` 文件夹中,以便 Pygame 可以使用它。如果你想,你*可以*在你的计算机上安装该字体,但是没有必要。重要的是将字体放在你的游戏目录中,这样 Pygame 可以“描绘”字体到屏幕上。
|
||||
|
||||
如果字体文件的名称复杂且带有空格或特殊字符,只需要重新命名它即可。文件名称是完全任意的,并且对你来说,文件名称越简单,越容易将其键入你的代码中。
|
||||
|
||||
现在告诉 Pygame 你的字体。从文档中你知道,当你至少提供了字体文件路径给 `pygame.freetype.Font` 时(文档明确指出所有其余属性都是可选的),你将在返回中获得一个字体对象:
|
||||
|
||||
```
|
||||
Font(file, size=0, font_index=0, resolution=0, ucs4=False) -> Font
|
||||
```
|
||||
|
||||
创建一个称为 `myfont` 的新变量来充当你在游戏中字体,并放置 `Font` 函数的结果到这个变量中。这个示例中使用 `amazdoom.ttf` 字体,但是你可以使用任何你想使用的字体。在你的设置部分放置这些代码:
|
||||
|
||||
```
|
||||
font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"fonts","amazdoom.ttf")
|
||||
font_size = tx
|
||||
myfont = pygame.freetype.Font(font_path, font_size)
|
||||
```
|
||||
|
||||
### 在 Pygame 中显示文本
|
||||
|
||||
现在你已经创建一个字体对象,你需要一个函数来绘制你想绘制到屏幕上的文本。这和你在你的游戏中绘制背景和平台是相同的原理。
|
||||
|
||||
首先,创建一个函数,并使用 `myfont` 对象来创建一些文本,设置颜色为某些 RGB 值。这必须是一个全局函数;它不属于任何具体的类:
|
||||
|
||||
```
|
||||
def stats(score,health):
|
||||
myfont.render_to(world, (4, 4), "Score:"+str(score), WHITE, None, size=64)
|
||||
myfont.render_to(world, (4, 72), "Health:"+str(health), WHITE, None, size=64)
|
||||
```
|
||||
|
||||
当然,你此刻已经知道,如果它不在主循环中,你的游戏将不会发生任何事,所以在文件的底部添加一个对你的 `stats` 函数的调用:
|
||||
|
||||
```
|
||||
for e in enemy_list:
|
||||
e.move()
|
||||
stats(player.score,player.health) # draw text
|
||||
pygame.display.flip()
|
||||
```
|
||||
|
||||
尝试你的游戏。
|
||||
|
||||
当玩家收集奖励品时,得分会上升。当玩家被敌人击中时,生命值下降。成功!
|
||||
|
||||
![Keeping score in Pygame][18]
|
||||
|
||||
不过,这里有一个问题。当一个玩家被敌人击中时,健康度会*一路*下降,这是不公平的。你刚刚发现一个非致命的错误。非致命的错误是这些在应用程序中小问题,(通常)不会阻止应用程序启动或甚至导致停止工作,但是它们要么没有意义,要么会惹恼用户。这里是如何解决这个问题的方法。
|
||||
|
||||
### 修复生命值计数
|
||||
|
||||
当前生命值系统的问题是,敌人接触玩家时,Pygame 时钟的每一次滴答,健康度都会减少。这意味着一个缓慢移动的敌人可能在一次遭遇中将一个玩家降低健康度至 -200 ,这不公平。当然,你可以给你的玩家一个 10000 的起始健康度得分,而不用担心它;这可以工作,并且可能没有人会注意。但是这里有一个更好的方法。
|
||||
|
||||
当前,你的代码侦查出一个玩家和一个敌人发生碰撞的时候。生命值问题的修复是检测*两个*独立的事件:什么时候玩家和敌人碰撞,并且,在它们碰撞后,什么时候它们*停止*碰撞。
|
||||
|
||||
首先,在你的玩家类中,创建一个变量来代表玩家和敌人碰撞在一起:
|
||||
|
||||
```
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.damage = 0
|
||||
```
|
||||
|
||||
在你的 `Player` 类的 `update` 函数中,*移除*这块代码块:
|
||||
|
||||
```
|
||||
for enemy in enemy_hit_list:
|
||||
self.health -= 1
|
||||
#print(self.health)
|
||||
```
|
||||
|
||||
并且在它的位置,只要玩家当前没有被击中,检查碰撞:
|
||||
|
||||
```
|
||||
if self.damage == 0:
|
||||
for enemy in enemy_hit_list:
|
||||
if not self.rect.contains(enemy):
|
||||
self.damage = self.rect.colliderect(enemy)
|
||||
```
|
||||
|
||||
你可能会在你删除的语句块和你刚刚添加的语句块之间看到相似之处。它们都在做相同的工作,但是新的代码更复杂。最重要的是,只有当玩家*当前*没有被击中时,新的代码才运行。这意味着,当一个玩家和敌人碰撞时,这些代码运行一次,而不是像以前那样一直发生碰撞。
|
||||
|
||||
新的代码使用两个新的 Pygame 函数。`self.rect.contains` 函数检查一个敌人当前是否在玩家的边界框内,并且当它是 `true` 时, `self.rect.colliderect` 设置你的新的 `self.damage` 变量为 1,而不管它多少次是 `true` 。
|
||||
|
||||
现在,即使被一个敌人击中 3 秒,对 Pygame 来说仍然看作一次击中。
|
||||
|
||||
我通过通读 Pygame 的文档而发现了这些函数。你没有必要一次阅读完全部的文档,并且你也没有必要阅读每个函数的每个单词。不过,花费时间在你正在使用的新的库或模块的文档上是很重要的;否则,你极有可能在重新发明轮子。不要花费一个下午的时间来尝试修改拼接一个解决方案到一些东西,而这些东西已经被你正在使用的框架的所解决。阅读文档,知悉函数,并从别人的工作中获益!
|
||||
|
||||
最后,添加另一个代码语句块来侦查出什么时候玩家和敌人不再接触。然后直到那时,才从玩家减少一个生命值。
|
||||
|
||||
```
|
||||
if self.damage == 1:
|
||||
idx = self.rect.collidelist(enemy_hit_list)
|
||||
if idx == -1:
|
||||
self.damage = 0 # set damage back to 0
|
||||
self.health -= 1 # subtract 1 hp
|
||||
```
|
||||
|
||||
注意,*只有*当玩家被击中时,这个新的代码才会被触发。这意味着,在你的玩家在你的游戏世界正在探索或收集奖励时,这个代码不会运行。它仅当 `self.damage` 变量被激活时运行。
|
||||
|
||||
当代码运行时,它使用 `self.rect.collidelist` 来查看玩家是否*仍然*接触在你敌人列表中的敌人(当其未侦查到碰撞时,`collidelist` 返回 -1)。在它没有接触敌人时,是该处理 `self.damage` 的时机:通过设置 `self.damage` 变量回到 0 来使其无效,并减少一点生命值。
|
||||
|
||||
现在尝试你的游戏。
|
||||
|
||||
### 得分反应
|
||||
|
||||
现在,你有一个来让你的玩家知道它们分数和生命值的方法,当你的玩家达到某些里程碑时,你可以确保某些事件发生。例如,也许这里有一个特殊的恢复一些生命值的奖励项目。也许一个到达 0 生命值的玩家不得不从一个关卡的起始位置重新开始。
|
||||
|
||||
你可以在你的代码中检查这些事件,并且相应地操纵你的游戏世界。你已经知道该怎么做,所以请浏览文档来寻找新的技巧,并且独立地尝试这些技巧。
|
||||
|
||||
这里是到目前为止所有的代码:
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# draw a world
|
||||
# add a player and player control
|
||||
# add player movement
|
||||
# add enemy and basic collision
|
||||
# add platform
|
||||
# add gravity
|
||||
# add jumping
|
||||
# add scrolling
|
||||
# add loot
|
||||
# add score
|
||||
|
||||
# GNU All-Permissive License
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
import pygame
|
||||
import sys
|
||||
import os
|
||||
import pygame.freetype
|
||||
|
||||
'''
|
||||
Objects
|
||||
'''
|
||||
|
||||
class Platform(pygame.sprite.Sprite):
|
||||
# x location, y location, img width, img height, img file
|
||||
def __init__(self,xloc,yloc,imgw,imgh,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img)).convert()
|
||||
self.image.convert_alpha()
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.y = yloc
|
||||
self.rect.x = xloc
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn a player
|
||||
'''
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.damage = 0
|
||||
self.collide_delta = 0
|
||||
self.jump_delta = 6
|
||||
self.score = 1
|
||||
self.images = []
|
||||
for i in range(1,9):
|
||||
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def jump(self,platform_list):
|
||||
self.jump_delta = 0
|
||||
|
||||
def gravity(self):
|
||||
self.movey += 3.2 # how fast player falls
|
||||
|
||||
if self.rect.y > worldy and self.movey >= 0:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty
|
||||
|
||||
def control(self,x,y):
|
||||
'''
|
||||
control player movement
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
Update sprite position
|
||||
'''
|
||||
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
|
||||
# moving left
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# moving right
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
|
||||
# collisions
|
||||
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
|
||||
if self.damage == 0:
|
||||
for enemy in enemy_hit_list:
|
||||
if not self.rect.contains(enemy):
|
||||
self.damage = self.rect.colliderect(enemy)
|
||||
|
||||
if self.damage == 1:
|
||||
idx = self.rect.collidelist(enemy_hit_list)
|
||||
if idx == -1:
|
||||
self.damage = 0 # set damage back to 0
|
||||
self.health -= 1 # subtract 1 hp
|
||||
|
||||
loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
|
||||
for loot in loot_hit_list:
|
||||
loot_list.remove(loot)
|
||||
self.score += 1
|
||||
print(self.score)
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.collide_delta = 0 # stop jumping
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty-ty
|
||||
self.collide_delta = 0 # stop jumping
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
self.jump_delta = 6*2
|
||||
self.movey -= 33 # how high to jump
|
||||
self.collide_delta += 6
|
||||
self.jump_delta += 6
|
||||
|
||||
class Enemy(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn an enemy
|
||||
'''
|
||||
def __init__(self,x,y,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img))
|
||||
self.movey = 0
|
||||
#self.image.convert_alpha()
|
||||
#self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.counter = 0
|
||||
|
||||
|
||||
def move(self):
|
||||
'''
|
||||
enemy movement
|
||||
'''
|
||||
distance = 80
|
||||
speed = 8
|
||||
|
||||
self.movey += 3.2
|
||||
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
self.rect.x += speed
|
||||
elif self.counter >= distance and self.counter <= distance*2:
|
||||
self.rect.x -= speed
|
||||
else:
|
||||
self.counter = 0
|
||||
|
||||
self.counter += 1
|
||||
|
||||
if not self.rect.y >= worldy-ty-ty:
|
||||
self.rect.y += self.movey
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.rect.y = worldy-ty-ty
|
||||
|
||||
|
||||
class Level():
|
||||
def bad(lvl,eloc):
|
||||
if lvl == 1:
|
||||
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
|
||||
enemy_list = pygame.sprite.Group() # create enemy group
|
||||
enemy_list.add(enemy) # add enemy to group
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return enemy_list
|
||||
|
||||
def loot(lvl,tx,ty):
|
||||
if lvl == 1:
|
||||
loot_list = pygame.sprite.Group()
|
||||
loot = Platform(200,ty*7,tx,ty, 'loot_1.png')
|
||||
loot_list.add(loot)
|
||||
|
||||
if lvl == 2:
|
||||
print(lvl)
|
||||
|
||||
return loot_list
|
||||
|
||||
def ground(lvl,gloc,tx,ty):
|
||||
ground_list = pygame.sprite.Group()
|
||||
i=0
|
||||
if lvl == 1:
|
||||
while i < len(gloc):
|
||||
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
|
||||
ground_list.add(ground)
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return ground_list
|
||||
|
||||
def platform(lvl,tx,ty):
|
||||
plat_list = pygame.sprite.Group()
|
||||
ploc = []
|
||||
i=0
|
||||
if lvl == 1:
|
||||
ploc.append((20,worldy-ty-128,3))
|
||||
ploc.append((300,worldy-ty-256,3))
|
||||
ploc.append((500,worldy-ty-128,4))
|
||||
|
||||
while i < len(ploc):
|
||||
j=0
|
||||
while j <= ploc[i][2]:
|
||||
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
|
||||
plat_list.add(plat)
|
||||
j=j+1
|
||||
print('run' + str(i) + str(ploc[i]))
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return plat_list
|
||||
|
||||
def stats(score,health):
|
||||
myfont.render_to(world, (4, 4), "Score:"+str(score), SNOWGRAY, None, size=64)
|
||||
myfont.render_to(world, (4, 72), "Health:"+str(health), SNOWGRAY, None, size=64)
|
||||
|
||||
'''
|
||||
Setup
|
||||
'''
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
|
||||
fps = 40 # frame rate
|
||||
ani = 4 # animation cycles
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
main = True
|
||||
|
||||
BLUE = (25,25,200)
|
||||
BLACK = (23,23,23 )
|
||||
WHITE = (254,254,254)
|
||||
SNOWGRAY = (137,164,166)
|
||||
ALPHA = (0,255,0)
|
||||
|
||||
world = pygame.display.set_mode([worldx,worldy])
|
||||
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
|
||||
backdropbox = world.get_rect()
|
||||
player = Player() # spawn player
|
||||
player.rect.x = 0
|
||||
player.rect.y = 0
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10
|
||||
forwardx = 600
|
||||
backwardx = 230
|
||||
|
||||
eloc = []
|
||||
eloc = [200,20]
|
||||
gloc = []
|
||||
tx = 64 #tile size
|
||||
ty = 64 #tile size
|
||||
|
||||
font_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),"fonts","amazdoom.ttf")
|
||||
font_size = tx
|
||||
myfont = pygame.freetype.Font(font_path, font_size)
|
||||
|
||||
i=0
|
||||
while i <= (worldx/tx)+tx:
|
||||
gloc.append(i*tx)
|
||||
i=i+1
|
||||
|
||||
enemy_list = Level.bad( 1, eloc )
|
||||
ground_list = Level.ground( 1,gloc,tx,ty )
|
||||
plat_list = Level.platform( 1,tx,ty )
|
||||
loot_list = Level.loot(1,tx,ty)
|
||||
|
||||
'''
|
||||
Main loop
|
||||
'''
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print("LEFT")
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print("RIGHT")
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(plat_list)
|
||||
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
|
||||
# scroll the world forward
|
||||
if player.rect.x >= forwardx:
|
||||
scroll = player.rect.x - forwardx
|
||||
player.rect.x = forwardx
|
||||
for p in plat_list:
|
||||
p.rect.x -= scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x -= scroll
|
||||
for l in loot_list:
|
||||
|
||||
l.rect.x -= scroll
|
||||
|
||||
# scroll the world backward
|
||||
if player.rect.x <= backwardx:
|
||||
scroll = backwardx - player.rect.x
|
||||
player.rect.x = backwardx
|
||||
for p in plat_list:
|
||||
p.rect.x += scroll
|
||||
for e in enemy_list:
|
||||
e.rect.x += scroll
|
||||
for l in loot_list:
|
||||
l.rect.x += scroll
|
||||
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.gravity() # check gravity
|
||||
player.update()
|
||||
player_list.draw(world) #refresh player position
|
||||
enemy_list.draw(world) # refresh enemies
|
||||
ground_list.draw(world) # refresh enemies
|
||||
plat_list.draw(world) # refresh platforms
|
||||
loot_list.draw(world) # refresh loot
|
||||
for e in enemy_list:
|
||||
e.move()
|
||||
stats(player.score,player.health) # draw text
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/add-scorekeeping-your-python-game
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/LAW_maze.png?itok=mZ5LP4-X (connecting yellow dots in a maze)
|
||||
[2]: https://www.python.org/
|
||||
[3]: https://www.pygame.org/news
|
||||
[4]: https://linux.cn/article-9071-1.html
|
||||
[5]: https://linux.cn/article-10850-1.html
|
||||
[6]: https://linux.cn/article-10858-1.html
|
||||
[7]: https://linux.cn/article-10874-1.html
|
||||
[8]: https://linux.cn/article-10883-1.html
|
||||
[9]: https://linux.cn/article-11780-1.html
|
||||
[10]: https://linux.cn/article-11790-1.html
|
||||
[11]: https://linux.cn/article-11819-1.html
|
||||
[12]: https://linux.cn/article-11828-1.html
|
||||
[13]: http://pygame.org/news
|
||||
[14]: https://fontlibrary.org/
|
||||
[15]: https://www.fontsquirrel.com/
|
||||
[16]: https://www.theleagueofmoveabletype.com/
|
||||
[17]: https://opensource.com/article/17/7/how-unzip-targz-file
|
||||
[18]: https://opensource.com/sites/default/files/uploads/pygame-score.jpg (Keeping score in Pygame)
|
||||
[19]: https://linux.cn/article-10902-1.html
|
135
published/20200109 My favorite Bash hacks.md
Normal file
135
published/20200109 My favorite Bash hacks.md
Normal file
@ -0,0 +1,135 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11841-1.html)
|
||||
[#]: subject: (My favorite Bash hacks)
|
||||
[#]: via: (https://opensource.com/article/20/1/bash-scripts-aliases)
|
||||
[#]: author: (Katie McLaughlin https://opensource.com/users/glasnt)
|
||||
|
||||
我珍藏的 Bash 秘籍
|
||||
======
|
||||
|
||||
> 通过别名和其他捷径来提高你经常忘记的那些事情的效率。
|
||||
|
||||
![bash logo on green background][1]
|
||||
|
||||
要是你整天使用计算机,如果能找到需要重复执行的命令并记下它们以便以后轻松使用那就太棒了。它们全都呆在那里,藏在 `~/.bashrc` 中(或 [zsh 用户][2]的 `~/.zshrc` 中),等待着改善你的生活!
|
||||
|
||||
在本文中,我分享了我最喜欢的这些助手命令,对于我经常遗忘的事情,它们很有用,也希望这可以帮助到你,以及为你解决一些经常头疼的问题。
|
||||
|
||||
### 完事吱一声
|
||||
|
||||
当我执行一个需要长时间运行的命令时,我经常采用多任务的方式,然后就必须回头去检查该操作是否已完成。然而通过有用的 `say` 命令,现在就不用再这样了(这是在 MacOS 上;请根据你的本地环境更改为等效的方式):
|
||||
|
||||
```
|
||||
function looooooooong {
|
||||
START=$(date +%s.%N)
|
||||
$*
|
||||
EXIT_CODE=$?
|
||||
END=$(date +%s.%N)
|
||||
DIFF=$(echo "$END - $START" | bc)
|
||||
RES=$(python -c "diff = $DIFF; min = int(diff / 60); print('%s min' % min)")
|
||||
result="$1 completed in $RES, exit code $EXIT_CODE."
|
||||
echo -e "\n⏰ $result"
|
||||
( say -r 250 $result 2>&1 > /dev/null & )
|
||||
}
|
||||
```
|
||||
|
||||
这个命令会记录命令的开始和结束时间,计算所需的分钟数,并“说”出调用的命令、花费的时间和退出码。当简单的控制台铃声无法使用时,我发现这个超级有用。
|
||||
|
||||
### 安装小助手
|
||||
|
||||
我在小时候就开始使用 Ubuntu,而我需要学习的第一件事就是如何安装软件包。我曾经首先添加的别名之一是它的助手(根据当天的流行梗命名的):
|
||||
|
||||
```
|
||||
alias canhas="sudo apt-get install -y"
|
||||
```
|
||||
|
||||
### GPG 签名
|
||||
|
||||
有时候,我必须在没有 GPG 扩展程序或应用程序的情况下给电子邮件签署 [GPG][3] 签名,我会跳到命令行并使用以下令人讨厌的别名:
|
||||
|
||||
```
|
||||
alias gibson="gpg --encrypt --sign --armor"
|
||||
alias ungibson="gpg --decrypt"
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
Docker 的子命令很多,但是 Docker compose 的更多。我曾经使用这些别名来将 `--rm` 标志丢到脑后,但是现在不再使用这些有用的别名了:
|
||||
|
||||
```
|
||||
alias dc="docker-compose"
|
||||
alias dcr="docker-compose run --rm"
|
||||
alias dcb="docker-compose run --rm --build"
|
||||
```
|
||||
|
||||
### Google Cloud 的 gcurl 助手
|
||||
|
||||
对于我来说,Google Cloud 是一个相对较新的东西,而它有[极多的文档][4]。`gcurl` 是一个别名,可确保在用带有身份验证标头的本地 `curl` 命令连接 Google Cloud API 时,可以获得所有正确的标头。
|
||||
|
||||
### Git 和 ~/.gitignore
|
||||
|
||||
我工作中用 Git 很多,因此我有一个专门的部分来介绍 Git 助手。
|
||||
|
||||
我最有用的助手之一是我用来克隆 GitHub 存储库的。你不必运行:
|
||||
|
||||
```
|
||||
git clone git@github.com:org/repo /Users/glasnt/git/org/repo
|
||||
```
|
||||
|
||||
我设置了一个克隆函数:
|
||||
|
||||
```
|
||||
clone(){
|
||||
echo Cloning $1 to ~/git/$1
|
||||
cd ~/git
|
||||
git clone git@github.com:$1 $1
|
||||
cd $1
|
||||
}
|
||||
```
|
||||
|
||||
即使每次进入 `~/.bashrc` 文件看到这个时,我总是会忘记和傻笑,我也有一个“刷新上游”命令:
|
||||
|
||||
```
|
||||
alias yoink="git checkout master && git fetch upstream master && git merge upstream/master"
|
||||
```
|
||||
|
||||
给 Git 一族的另一个助手是全局忽略文件。在你的 `git config --global --list` 中,你应该看到一个 `core.excludesfile`。如果没有,请[创建一个][6],然后将你总是放到各个 `.gitignore` 文件中的内容填满它。作为 MacOS 上的 Python 开发人员,对我来说,这些内容是:
|
||||
|
||||
```
|
||||
.DS_Store # macOS clutter
|
||||
venv/ # I never want to commit my virtualenv
|
||||
*.egg-info/* # ... nor any locally compiled packages
|
||||
__pycache__ # ... or source
|
||||
*.swp # ... nor any files open in vim
|
||||
```
|
||||
|
||||
你可以在 [Gitignore.io][7] 或 GitHub 上的 [Gitignore 存储库][8]上找到其他建议。
|
||||
|
||||
### 轮到你了
|
||||
|
||||
你最喜欢的助手命令是什么?请在评论中分享。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/bash-scripts-aliases
|
||||
|
||||
作者:[Katie McLaughlin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/glasnt
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bash_command_line.png?itok=k4z94W2U (bash logo on green background)
|
||||
[2]: https://opensource.com/article/19/9/getting-started-zsh
|
||||
[3]: https://gnupg.org/
|
||||
[4]: https://cloud.google.com/service-infrastructure/docs/service-control/getting-started
|
||||
[5]: mailto:git@github.com
|
||||
[6]: https://help.github.com/en/github/using-git/ignoring-files#create-a-global-gitignore
|
||||
[7]: https://www.gitignore.io/
|
||||
[8]: https://github.com/github/gitignore
|
65
published/20200109 What-s HTTPS for secure computing.md
Normal file
65
published/20200109 What-s HTTPS for secure computing.md
Normal file
@ -0,0 +1,65 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (hopefully2333)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11877-1.html)
|
||||
[#]: subject: (What's HTTPS for secure computing?)
|
||||
[#]: via: (https://opensource.com/article/20/1/confidential-computing)
|
||||
[#]: author: (Mike Bursell https://opensource.com/users/mikecamel)
|
||||
|
||||
用于安全计算的 HTTPS 是什么?
|
||||
======
|
||||
|
||||
> 在默认的情况下,网站的安全性还不足够。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/11/123552rqncn4c7474j44jq.jpg)
|
||||
|
||||
在过去的几年里,寻找一个只以 “http://...” 开头的网站变得越来越难,这是因为业界终于意识到,网络安全“是件事”,同时也是因为客户端和服务端之间建立和使用 https 连接变得更加容易了。类似的转变可能正以不同的方式发生在云计算、边缘计算、物联网、区块链,人工智能、机器学习等领域。长久以来,我们都知道我们应该对存储的静态数据和在网络中传输的数据进行加密,但是在使用和处理数据的时候对它进行加密是困难且昂贵的。可信计算(使用例如<ruby>受信任的执行环境<rt>Trusted Execution Environments</rt></ruby> TEEs 这样的硬件功能来提供数据和算法这种类型的保护)可以保护主机系统中的或者易受攻击的环境中的数据。
|
||||
|
||||
关于 [TEEs][2],当然,还有我和 Nathaniel McCallum 共同创立的 [Enarx 项目][3],我已经写了几次文章(参见《[给每个人的 Enarx(一个任务)][4]》 和 《[Enarx 迈向多平台][5]》)。Enarx 使用 TEEs 来提供独立于平台和语言的部署平台,以此来让你能够安全地将敏感应用或者敏感组件(例如微服务)部署在你不信任的主机上。当然,Enarx 是完全开源的(顺便提一下,我们使用的是 Apache 2.0 许可证)。能够在你不信任的主机上运行工作负载,这是可信计算的承诺,它扩展了使用静态敏感数据和传输中数据的常规做法:
|
||||
|
||||
* **存储**:你要加密你的静态数据,因为你不完全信任你的基础存储架构。
|
||||
* **网络**:你要加密你正在传输中的数据,因为你不完全信任你的基础网络架构。
|
||||
* **计算**:你要加密你正在使用中的数据,因为你不完全信任你的基础计算架构。
|
||||
|
||||
关于信任,我有非常多的话想说,而且,上述说法里的单词“**完全**”是很重要的(在重新读我写的这篇文章的时候,我新加了这个单词)。不论哪种情况,你必须在一定程度上信任你的基础设施,无论是传递你的数据包还是存储你的数据块,例如,对于计算基础架构,你必须要去信任 CPU 和与之关联的固件,这是因为如果你不信任他们,你就无法真正地进行计算(现在有一些诸如<ruby>同态加密<rt>homomorphic encryption</rt></ruby>一类的技术,这些技术正在开始提供一些可能性,但是它们依然有限,这些技术还不够成熟)。
|
||||
|
||||
考虑到发现的一些 CPU 安全性问题,是否应该完全信任 CPU 有时自然会产生疑问,以及它们是否在针对其所在的主机的物理攻击中具有完全的安全性。
|
||||
|
||||
这两个问题的回答都是“不”,但是在考虑到大规模可用性和普遍推广的成本,这已经是我们当前拥有的最好的技术了。为了解决第二个问题,没有人去假装这项技术(或者任何的其他技术)是完全安全的:我们需要做的是思考我们的[威胁模型][6]并确定这个情况下的 TEEs 是否为我们的特殊需求提供了足够的安全防护。关于第一个问题,Enarx 采用的模型是在部署时就对你是否信任一个特定的 CPU 组做出决定。举个例子,如果供应商 Q 的 R 代芯片被发现有漏洞,可以很简单地说“我拒绝将我的工作内容部署到 Q 的 R 代芯片上去,但是仍然可以部署到 Q 的 S 型号、T 型号和 U 型号的芯片以及任何 P、M 和 N 供应商的任何芯片上去。”
|
||||
|
||||
我认为这里发生了三处改变,这些改变引起了人们现在对<ruby>机密计算<rt>confidential computing</rt></ruby>的兴趣和采用。
|
||||
|
||||
1. **硬件可用**:只是在过去的 6 到 12 个月里,支持 TEEs 的硬件才开始变得广泛可用,这会儿市场上的主要例子是 Intel 的 SGX 和 AMD 的 SEV。我们期望在未来可以看到支持 TEE 的硬件的其他例子。
|
||||
2. **行业就绪**:就像上云越来越多地被接受作为应用程序部署的模型,监管机构和立法机构也在提高各类组织保护其管理的数据的要求。组织开始呼吁在不受信任的主机运行敏感程序(或者是处理敏感数据的应用程序)的方法,更确切地说,是在无法完全信任且带有敏感数据的主机上运行的方法。这不足为奇:如果芯片制造商看不到这项技术的市场,他们就不会投太多的钱在这项技术上。Linux 基金会的[机密计算联盟(CCC)][7]的成立就是业界对如何寻找使用加密计算的通用模型并且鼓励开源项目使用这些技术感兴趣的案例。(红帽发起的 Enarx 是一个 CCC 项目。)
|
||||
3. **开放源码**:就像区块链一样,机密计算是使用开源绝对明智的技术之一。如果你要运行敏感程序,你需要去信任正在为你运行的程序。不仅仅是 CPU 和固件,同样还有在 TEE 内执行你的工作负载的框架。可以很好地说,“我不信任主机机器和它上面的软件栈,所以我打算使用 TEE,”但是如果你不够了解 TEE 软件环境,那你就是将一种软件不透明换成另外一种。TEEs 的开源支持将允许你或者社区(实际上是你与社区)以一种专有软件不可能实现的方式来检查和审计你所运行的程序。这就是为什么 CCC 位于 Linux 基金会旗下(这个基金会致力于开放式开发模型)并鼓励 TEE 相关的软件项目加入且成为开源项目(如果它们还没有成为开源)。
|
||||
|
||||
我认为,在过去的 15 到 20 年里,硬件可用、行业就绪和开放源码已成为推动技术改变的驱动力。区块链、人工智能、云计算、<ruby>大规模计算<rt>webscale computing</rt></ruby>、大数据和互联网商务都是这三个点同时发挥作用的例子,并且在业界带来了巨大的改变。
|
||||
|
||||
在一般情况下,安全是我们这数十年来听到的一种承诺,并且其仍然未被实现。老实说,我不确定它未来会不会实现。但是随着新技术的到来,特定用例的安全变得越来越实用和无处不在,并且在业内受到越来越多的期待。这样看起来,机密计算似乎已准备好成为成为下一个重大变化 —— 而你,我亲爱的读者,可以一起来加入到这场革命(毕竟它是开源的)。
|
||||
|
||||
这篇文章最初是发布在 Alice, Eve, and Bob 上的,这是得到了作者许可的重发。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/confidential-computing
|
||||
|
||||
作者:[Mike Bursell][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://opensource.com/users/mikecamel
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/secure_https_url_browser.jpg?itok=OaPuqBkG (Secure https browser)
|
||||
[2]: https://aliceevebob.com/2019/02/26/oh-how-i-love-my-tee-or-do-i/
|
||||
[3]: https://enarx.io/
|
||||
[4]: https://aliceevebob.com/2019/08/20/enarx-for-everyone-a-quest/
|
||||
[5]: https://aliceevebob.com/2019/10/29/enarx-goes-multi-platform/
|
||||
[6]: https://aliceevebob.com/2018/02/20/there-are-no-absolutes-in-security/
|
||||
[7]: https://confidentialcomputing.io/
|
||||
[8]: tmp.VEZpFGxsLv#1
|
||||
[9]: https://aliceevebob.com/2019/12/03/confidential-computing-the-new-https/
|
104
published/20200112 What I learned going from prison to Python.md
Normal file
104
published/20200112 What I learned going from prison to Python.md
Normal file
@ -0,0 +1,104 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (heguangzhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11893-1.html)
|
||||
[#]: subject: (What I learned going from prison to Python)
|
||||
[#]: via: (https://opensource.com/article/20/1/prison-to-python)
|
||||
[#]: author: (Shadeed "Sha" Wallace-Stepter https://opensource.com/users/shastepter)
|
||||
|
||||
从监狱到 Python
|
||||
======
|
||||
|
||||
> 入狱后,开源编程是如何提供机会的。
|
||||
|
||||
![书架上的编程书籍][1]
|
||||
|
||||
不到一年前,我还在圣昆廷州立监狱服刑,我是无期徒刑。
|
||||
|
||||
我高三的时候,我抢劫了一个人并向他开了枪。现在,我经过一段时间才意识到并承认自己做错了,这是在经历了陪审团审判并看到我的行为带来的恶果后,我知道需要改变自己,我也确实做到了。尽管我对我的行为表示懊悔,但我毕竟开枪打了一个人,并差点杀了他。做这样的事是有后果的,这是理所当然的。所以在我 18 岁的时候,我被判了终身监禁。
|
||||
|
||||
监狱是一个非常可怕的地方;我是不推荐你去的。但是我必须去,所以我去了。我不告诉你具体的细节,但你可以放心,这是一个没有太多动机去改变的地方,许多人在这里养成的坏习惯比他们过去在别处养成的更多。
|
||||
|
||||
我是幸运儿之一。当我在服刑的时候,发生了一些不同寻常的事情。我开始想象自己出狱后的的未来,虽然在这之前,我还是已经在那里度过了我整个成年生活。
|
||||
|
||||
现在你想想:我是黑人,只受过高中教育。我没有工作经历,如果我离开监狱,在被释放前,我还是一个被定罪的重罪犯。当每个雇主看到我的简历,都不会有“我需要雇用这个人”想法,我认为是正常的。
|
||||
|
||||
我不知道我的选择是什么,但我已经下定决心了。我需要做些活下去的事情,并且这和我入狱前的生活一点也不像。
|
||||
|
||||
### Python 之路
|
||||
|
||||
最终,我被关在了圣昆廷州立监狱,我不知道我为何幸运地被关在那里。圣昆廷提供了几个自助和教育编程项目。这些[改造机会][2]帮助囚犯使他们拥有在获释后避免再次犯罪的技能。
|
||||
|
||||
作为其中一个编程项目的一部分,2017 年我通过圣昆廷媒体项目认识了[杰西卡·麦凯拉][3]。杰西卡是编程语言 [Python][4] 的爱好者,她开始向我推荐 Python 有多棒,以及它是刚起步的人学习的完美语言。这就是故事变得比小说更精彩的地方。
|
||||
|
||||
> 感谢 [@northbaypython][5] 让 [@ShaStepter][6] 和我重复 [@pycon][7] 的主题演讲,让他们被录制下来。我很荣幸与大家分享:
|
||||
>
|
||||
> 从监狱到 Pythone: https://t.co/rcumoAgZHm
|
||||
>
|
||||
> 大规模裁员:如果我们不雇佣被判重罪的人,谁会呢? https://t.co/fENDUFdxfX
|
||||
>
|
||||
> [pic.Twitter.com/kpjo8d3ul6][8]
|
||||
>
|
||||
> —杰西卡·麦凯拉(@jessicamckellar)[2019 年 11 月 5 日][9]
|
||||
|
||||
杰西卡向我介绍了一些 Python 视频教程,这些教程是她为一家名叫 [O’Reilly Media][10] 的公司做的,课程是在线的,如果我能接触到它们,那该有多好呀。不幸的是,在监狱里上网是不可能的。但是,我遇到了一个叫 Tim O’Reilly 的人,他最近刚来到圣昆廷。在他访问之后,Tim 从他的公司 O’Reilly Media 公司向监狱的编程班捐赠了大量内容。最终,我拿到了一款平板电脑,上面有杰西卡的 Python 教程,并学会了如何使用这些 Python 教程进行编码。
|
||||
|
||||
真是难以置信。背景和生活与我完全不同的陌生人把这些联系在一起,让我学会了编码。
|
||||
|
||||
### 对 Python 社区的热爱
|
||||
|
||||
在这之后,我开始经常和杰西卡见面,她开始告诉我关于开源社区的情况。我了解到,从根本上说,开源社区就是关于伙伴关系和协作的社区。之所以如此有效,是因为没有人被排除在外。
|
||||
|
||||
对我来说,一个努力寻找自己定位的人,我所看到的是一种非常基本的爱——通过合作和接受的爱,通过接触的爱,通过包容的爱。我渴望成为其中的一部分。所以我继续学习 Python,不幸的是,我无法获得更多的教程,但是我能够从开源社区收集的大量书面知识中获益。我读一切提到 Python 的东西,从平装本到晦涩难懂的杂志文章,我使用平板电脑来解决我读到的 Python 问题。
|
||||
|
||||
我对 Python 和编程的热情不是我的许多同龄人所共有的。除了监狱编程课上的极少数人之外,我认识的其他人都没有提到过编程;一般囚犯都不知道。我认为这是因为有过监禁经历的人无法接触编程,尤其是如果你是有色人种。
|
||||
|
||||
### 监狱外的 Python 生活
|
||||
|
||||
然而,在 2018 年 8 月 17 日,我得到了生命中的惊喜。时任州长的杰里·布朗将我 27 年的刑期减刑,在服刑将近 19 年后,我被释放出狱了。
|
||||
|
||||
但现实情况是,这也是为什么我认为编程和开源社区如此有价值。我是一名 37 岁的黑人罪犯,没有工作经历,刚刚在监狱服刑 18 年。我有犯罪史,并且现存偏见导致没有多少职业适合我。但是编程是少数例外之一。
|
||||
|
||||
现在,监禁后重返社会的人们迫切需要包容,但当谈及工作场所的多样性以及对多样性的需求时,你真的听不到这个群体被提及或包容。
|
||||
|
||||
> 还有什么:
|
||||
>
|
||||
> 1、背景调查:询问他们在你的公司是如何使用的。
|
||||
>
|
||||
> 2、初级角色:删除虚假的、不必要的先决条件,这些条件将排除有记录的合格人员。
|
||||
>
|
||||
> 3、积极拓展:与当地再就业项目合作,创建招聘渠道。
|
||||
>
|
||||
> [pic.twitter.com/WnzdEUTuxr][11]
|
||||
>
|
||||
> —杰西卡·麦凯拉(@jessicamckellar)[2019 年 5 月 12 日][12]
|
||||
|
||||
|
||||
因此,我想谦卑地挑战开源社区的所有程序员和成员,让他们围绕包容和多样性展开思考。今天,我自豪地站在你们面前,代表一个大多数人都没有想到的群体——以前被监禁的人。但是我们存在,我们渴望证明我们的价值,最重要的是,我们期待被接受。当我们重返社会时,许多挑战等待着我们,我请求你们允许我们有机会展示我们的价值。欢迎我们,接受我们,最重要的是,包容我们。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/prison-to-python
|
||||
|
||||
作者:[Shadeed "Sha" Wallace-Stepter][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[heguangzhi](https://github.com/heguangzhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/shastepter
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/books_programming_languages.jpg?itok=KJcdnXM2 (Programming books on a shelf)
|
||||
[2]: https://www.dailycal.org/2019/02/27/san-quentin-rehabilitation-programs-offer-inmates-education-a-voice/
|
||||
[3]: https://twitter.com/jessicamckellar?lang=en
|
||||
[4]: https://www.python.org/
|
||||
[5]: https://twitter.com/northbaypython?ref_src=twsrc%5Etfw
|
||||
[6]: https://twitter.com/ShaStepter?ref_src=twsrc%5Etfw
|
||||
[7]: https://twitter.com/pycon?ref_src=twsrc%5Etfw
|
||||
[8]: https://t.co/Kpjo8d3ul6
|
||||
[9]: https://twitter.com/jessicamckellar/status/1191601209917837312?ref_src=twsrc%5Etfw
|
||||
[10]: http://shop.oreilly.com/product/110000448.do
|
||||
[11]: https://t.co/WnzdEUTuxr
|
||||
[12]: https://twitter.com/jessicamckellar/status/1127640222504636416?ref_src=twsrc%5Etfw
|
@ -0,0 +1,172 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Morisun029)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11886-1.html)
|
||||
[#]: subject: (Use this Python script to find bugs in your Overcloud)
|
||||
[#]: via: (https://opensource.com/article/20/1/logtool-root-cause-identification)
|
||||
[#]: author: (Arkady Shtempler https://opensource.com/users/ashtempl)
|
||||
|
||||
用 Python 脚本发现 OpenStack Overcloud 中的问题
|
||||
======
|
||||
|
||||
> LogTool 是一组 Python 脚本,可帮助你找出 Overcloud 节点中问题的根本原因。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/12/211455woy57xx5q19cx175.jpg)
|
||||
|
||||
OpenStack 在其 Overcloud 节点和 Undercloud 主机上存储和管理了一堆日志文件。因此,使用 OSP 日志文件来排查遇到的问题并不是一件容易的事,尤其在你甚至都不知道是什么原因导致问题时。
|
||||
|
||||
如果你正处于这种情况,那么 [LogTool][2] 可以使你的生活变得更加轻松!它会为你节省本需要人工排查问题所需的时间和精力。LogTool 基于模糊字符串匹配算法,可提供过去发生的所有唯一错误和警告信息。你可以根据日志中的时间戳导出特定时间段(例如 10 分钟前、一个小时前、一天前等)的这些信息。
|
||||
|
||||
LogTool 是一组 Python 脚本,其主要模块 `PyTool.py` 在 Undercloud 主机上执行。某些操作模式使用直接在 Overcloud 节点上执行的其他脚本,例如从 Overcloud 日志中导出错误和警告信息。
|
||||
|
||||
LogTool 支持 Python 2 和 Python 3,你可以根据需要更改工作目录:[LogTool_Python2][3] or [LogTool_Python3][4]。
|
||||
|
||||
### 操作方式
|
||||
|
||||
#### 1、从 Overcloud 日志中导出错误和警告信息
|
||||
|
||||
此模式用于从过去发生的 Overcloud 节点中提取 **错误** 和 **警告** 信息。作为用户,系统将提示你提供“开始时间”和“调试级别”,以用于提取错误或警告消息。例如,如果在过去 10 分钟内出了问题,你则可以只提取该时间段内的错误和警告消息。
|
||||
|
||||
此操作模式将为每个 Overcloud 节点生成一个包含结果文件的目录。结果文件是经过压缩的简单文本文件(`*.gz`),以减少从 Overcloud 节点下载所需的时间。将压缩文件转换为常规文本文件,可以使用 `zcat` 或类似工具。此外,Vi 的某些版本和 Emacs 的任何最新版本均支持读取压缩数据。结果文件分为几部分,并在底部包含目录。
|
||||
|
||||
LogTool 可以即时检测两种日志文件:标准和非标准。在标准文件中,每条日志行都有一个已知的和已定义的结构:时间戳、调试级别、信息等等。在非标准文件中,日志的结构未知。例如,它可能是第三方的日志。在目录中,你可以找到每个部分的“名称 --> 行号”例如:
|
||||
|
||||
* **原始数据 - 从标准 OSP 日志中提取的错误/警告消息:** 这部分包含所有提取的错误/警告消息,没有任何修改或更改。这些消息是 LogTool 用于模糊匹配分析的原始数据。
|
||||
* **统计信息 - 每个标准 OSP 日志的错误/警告信息数量:** 在此部分,你将找到每个标准日志文件的错误和警告数量。这些信息可以帮助你了解用于排查问题根本原因的潜在组件。
|
||||
* **统计信息 - 每个标准 OSP 日志文件的唯一消息:** 这部分提供指定时间戳内的唯一的错误和警告消息。有关每个唯一错误或警告的更多详细信息,请在“原始数据”部分中查找相同的消息。
|
||||
* **统计信息 - 每个非标准日志文件在任意时间的唯一消息:** 此部分包含非标准日志文件中的唯一消息。遗憾的是,LogTool 无法像标准日志文件那样的处理方式处理这些日志文件。因此,在你提取“特定时间”的日志信息时会被忽略,你会看到过去创建的所有唯一的错误/警告消息。因此,首先,向下滚动到结果文件底部的目录并查看其部分-使用目录中的行索引跳到相关部分,其中第 3、4 和 5 行的信息最重要。
|
||||
|
||||
#### 2、从 Overcloud 节点下载所有日志
|
||||
|
||||
所有 Overcloud 节点的日志将被压缩并下载到 Undercloud 主机上的本地目录。
|
||||
|
||||
#### 3、所有 Overcloud 日志中搜索字符串
|
||||
|
||||
该模式“grep”(搜索)由用户在所有 Overcloud 日志上提供的字符串。例如,你可能希望查看特定请求的所有日志消息,例如,“Create VM”的失败的请求 ID。
|
||||
|
||||
#### 4、检查 Overcloud 上当前的 CPU、RAM 和磁盘使用情况
|
||||
|
||||
该模式显示每个 Overcloud 节点上的当前 CPU、RAM 和磁盘信息。
|
||||
|
||||
#### 5、执行用户脚本
|
||||
|
||||
该模式使用户可以在 Overcloud 节点上运行自己的脚本。例如,假设 Overcloud 部署失败,你就需要在每个控制器节点上执行相同的过程来修复该问题。你可以实现“替代方法”脚本,并使用此模式在控制器上运行它。
|
||||
|
||||
#### 6、仅按给定的时间戳下载相关日志
|
||||
|
||||
此模式仅下载 Overcloud 上 “给定的时间戳”的“上次修改时间”的日志。例如,如果 10 分钟前出现错误,则与旧日志文件就没有关系,因此无需下载。此外,你不能(或不应)在某些错误报告工具中附加大文件,因此此模式可能有助于编写错误报告。
|
||||
|
||||
#### 7、从 Undercloud 日志中导出错误和警告信息
|
||||
|
||||
这与上面的模式 1 相同。
|
||||
|
||||
#### 8、在 Overcloud 上检查不正常的 docker
|
||||
|
||||
此模式用于在节点上搜索不正常的 Docker。
|
||||
|
||||
#### 9、下载 OSP 日志并在本地运行 LogTool
|
||||
|
||||
此模式允许你从 Jenkins 或 Log Storage 下载 OSP 日志(例如,`cougar11.scl.lab.tlv.redhat.com`),并在本地分析。
|
||||
|
||||
#### 10、在 Undercloud 上分析部署日志
|
||||
|
||||
此模式可以帮助你了解 Overcloud 或 Undercloud 部署过程中出了什么问题。例如,在`overcloud_deploy.sh` 脚本中,使用 `--log` 选项时会生成部署日志;此类日志的问题是“不友好”,你很难理解是什么出了问题,尤其是当详细程度设置为 `vv` 或更高时,使得日志中的数据难以读取。此模式提供有关所有失败任务的详细信息。
|
||||
|
||||
#### 11、分析 Gerrit(Zuul)失败的日志
|
||||
|
||||
此模式用于分析 Gerrit(Zuul)日志文件。它会自动从远程 Gerrit 门下载所有文件(HTTP 下载)并在本地进行分析。
|
||||
|
||||
### 安装
|
||||
|
||||
GitHub 上有 LogTool,使用以下命令将其克隆到你的 Undercloud 主机:
|
||||
|
||||
```
|
||||
git clone https://github.com/zahlabut/LogTool.git
|
||||
```
|
||||
|
||||
该工具还使用了一些外部 Python 模块:
|
||||
|
||||
#### Paramiko
|
||||
|
||||
默认情况下,SSH 模块通常会安装在 Undercloud 上。使用以下命令来验证是否已安装:
|
||||
|
||||
```
|
||||
ls -a /usr/lib/python2.7/site-packages | grep paramiko
|
||||
```
|
||||
|
||||
如果需要安装模块,请在 Undercloud 上执行以下命令:
|
||||
|
||||
```
|
||||
sudo easy_install pip
|
||||
sudo pip install paramiko==2.1.1
|
||||
```
|
||||
|
||||
#### BeautifulSoup
|
||||
|
||||
此 HTML 解析器模块仅在使用 HTTP 下载日志文件的模式下使用。它用于解析 Artifacts HTML 页面以获取其中的所有链接。安装 BeautifulSoup,请输入以下命令:
|
||||
|
||||
```
|
||||
pip install beautifulsoup4
|
||||
```
|
||||
|
||||
你还可以通过执行以下命令使用 [requirements.txt][6] 文件安装所有必需的模块:
|
||||
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 配置
|
||||
|
||||
所有必需的参数都直接在 `PyTool.py` 脚本中设置。默认值为:
|
||||
|
||||
```
|
||||
overcloud_logs_dir = '/var/log/containers'
|
||||
overcloud_ssh_user = 'heat-admin'
|
||||
overcloud_ssh_key = '/home/stack/.ssh/id_rsa'
|
||||
undercloud_logs_dir ='/var/log/containers'
|
||||
source_rc_file_path='/home/stack/'
|
||||
```
|
||||
|
||||
### 用法
|
||||
|
||||
此工具是交互式的,因此要启动它,只需输入:
|
||||
|
||||
```
|
||||
cd LogTool
|
||||
python PyTool.py
|
||||
```
|
||||
|
||||
### 排除 LogTool 故障
|
||||
|
||||
|
||||
在运行时会创建两个日志文件:`Error.log` 和 `Runtime.log`。请在你要打开的问题的描述中添加两者的内容。
|
||||
|
||||
### 局限性
|
||||
|
||||
LogTool 进行硬编码以处理最大 500 MB 的文件。
|
||||
|
||||
### LogTool_Python3 脚本
|
||||
|
||||
在 [github.com/zahlabut/LogTool][2] 获取。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/logtool-root-cause-identification
|
||||
|
||||
作者:[Arkady Shtempler][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Morisun029](https://github.com/译者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ashtempl
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/search_find_code_python_programming.png?itok=ynSL8XRV (Searching for code)
|
||||
[2]: https://github.com/zahlabut/LogTool
|
||||
[3]: https://github.com/zahlabut/LogTool/tree/master/LogTool_Python2
|
||||
[4]: https://github.com/zahlabut/LogTool/tree/master/LogTool_Python3
|
||||
[5]: https://opensource.com/article/19/2/getting-started-cat-command
|
||||
[6]: https://github.com/zahlabut/LogTool/blob/master/LogTool_Python3/requirements.txt
|
@ -0,0 +1,76 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11846-1.html)
|
||||
[#]: subject: (Keep a journal of your activities with this Python program)
|
||||
[#]: via: (https://opensource.com/article/20/1/python-journal)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用这个 Python 程序记录你的活动
|
||||
======
|
||||
|
||||
> jrnl 可以创建可搜索、带时间戳、可导出、加密的(如果需要)的日常活动日志。在我们的 20 个使用开源提升生产力的系列的第八篇文章中了解更多。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/03/105455tx03zo2pu7woyusp.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 jrnl 记录日志
|
||||
|
||||
在我的公司,许多人会在下班之前在 Slack 上发送一个“一天结束”的状态。在有着许多项目和全球化的团队里,这是一个分享你已完成、未完成以及你需要哪些帮助的一个很好的方式。但有时候我太忙了,以至于我忘了做了什么。这时候就需要记录日志了。
|
||||
|
||||
![jrnl][2]
|
||||
|
||||
打开一个文本编辑器并在你做一些事的时候添加一行很容易。但是在需要找出你在什么时候做的笔记,或者要快速提取相关的行时会有挑战。幸运的是,[jrnl][3] 可以提供帮助。
|
||||
|
||||
jrnl 能让你在命令行中快速输入条目、搜索过去的条目并导出为 HTML 和 Markdown 等富文本格式。你可以有多个日志,这意味着你可以将工作条目与私有条目分开。它将条目存储为纯文本,因此即使 jrnl 停止工作,数据也不会丢失。
|
||||
|
||||
由于 jrnl 是一个 Python 程序,最简单的安装方法是使用 `pip3 install jrnl`。这将确保你获得最新和最好的版本。第一次运行它会询问一些问题,接下来就能正常使用。
|
||||
|
||||
![jrnl's first run][4]
|
||||
|
||||
现在,每当你需要做笔记或记录日志时,只需输入 `jrnl <some text>`,它将带有时间戳的记录保存到默认文件中。你可以使用 `jrnl -on YYYY-MM-DD` 搜索特定日期条目,`jrnl -from YYYY-MM-DD` 搜索在那日期之后的条目,以及用 `jrnl -to YYYY-MM-DD` 搜索到那日期的条目。搜索词可以与 `-and` 参数结合使用,允许像 `jrnl -from 2019-01-01 -and -to 2019-12-31` 这类搜索。
|
||||
|
||||
你还可以使用 `--edit` 标志编辑日志中的条目。开始之前,通过编辑文件 `~/.config/jrnl/jrnl.yaml` 来设置默认编辑器。你还可以指定日志使用什么文件、用于标签的特殊字符以及一些其他选项。现在,重要的是设置编辑器。我使用 Vim,jrnl 的文档中有一些使用其他编辑器如 VSCode 和 Sublime Text 的[有用提示][5]。
|
||||
|
||||
![Example jrnl config file][6]
|
||||
|
||||
jrnl 还可以加密日志文件。通过设置全局 `encrypt` 变量,你将告诉 jrnl 加密你定义的所有日志。还可在配置文件中的针对文件设置 `encrypt: true` 来加密文件。
|
||||
|
||||
```
|
||||
journals:
|
||||
default: ~/journals/journal.txt
|
||||
work: ~/journals/work.txt
|
||||
private:
|
||||
journal: ~/journals/private.txt
|
||||
encrypt: true
|
||||
```
|
||||
|
||||
如果日志尚未加密,系统将提示你输入在对它进行任何操作的密码。日志文件将加密保存在磁盘上,以免受窥探。[jrnl 文档][7] 中包含其工作原理、使用哪些加密方式等的更多信息。
|
||||
|
||||
![Encrypted jrnl file][8]
|
||||
|
||||
日志记录帮助我记住什么时候做了什么事,并在我需要的时候能够找到它。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/python-journal
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/notebook-writing-pen.jpg?itok=uA3dCfu_ (Writing in a notebook)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/productivity_8-1.png (jrnl)
|
||||
[3]: https://jrnl.sh/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/productivity_8-2.png (jrnl's first run)
|
||||
[5]: https://jrnl.sh/recipes/#external-editors
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_8-3.png (Example jrnl config file)
|
||||
[7]: https://jrnl.sh/encryption/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/productivity_8-4.png (Encrypted jrnl file)
|
@ -0,0 +1,128 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11838-1.html)
|
||||
[#]: subject: (How to Set or Change Timezone in Ubuntu Linux [Beginner’s Tip])
|
||||
[#]: via: (https://itsfoss.com/change-timezone-ubuntu/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
如何在 Ubuntu Linux 中设置或更改时区
|
||||
======
|
||||
|
||||
[你安装 Ubuntu 时][1],它会要求你设置时区。如果你选择一个错误的时区,或者你移动到世界的一些其它地方,你可以很容易地在以后更改它。
|
||||
|
||||
### 如何在 Ubuntu 和其它 Linux 发行版中更改时区
|
||||
|
||||
这里有两种方法来更改 Ubuntu 中的时区。你可以使用图形化设置或在终端中使用 `timedatectl` 命令。你也可以直接更改 `/etc/timezone` 文件,但是我不建议这样做。
|
||||
|
||||
在这篇初学者教程中,我将向你展示图形化和终端两种方法:
|
||||
|
||||
* [通过 GUI 更改 Ubuntu 中的时区][2] (适合桌面用户)
|
||||
* [通过命令行更改 Ubuntu 中的时区][3] (桌面和服务器都工作)
|
||||
|
||||
![][4]
|
||||
|
||||
#### 方法 1: 通过终端更改 Ubuntu 时区
|
||||
|
||||
[Ubuntu][5] 或一些使用 systemd 的其它发行版可以在 Linux 终端中使用 `timedatectl` 命令来设置时区。
|
||||
|
||||
你可以使用没有任何参数的 `timedatectl` 命令来检查当前是日期和时区设置:
|
||||
|
||||
```
|
||||
[email protected]:~$ timedatectl
|
||||
Local time: Sat 2020-01-18 17:39:52 IST
|
||||
Universal time: Sat 2020-01-18 12:09:52 UTC
|
||||
RTC time: Sat 2020-01-18 12:09:52
|
||||
Time zone: Asia/Kolkata (IST, +0530)
|
||||
System clock synchronized: yes
|
||||
systemd-timesyncd.service active: yes
|
||||
RTC in local TZ: no
|
||||
```
|
||||
|
||||
正如你在上面的输出中所看,我的系统使用 Asia/Kolkata 。它也告诉我现在比世界时早 5 小时 30 分钟。
|
||||
|
||||
为在 Linux 中设置时区,你需要知道准确的时区。你必需使用时区的正确的格式 (时区格式是洲/城市)。
|
||||
|
||||
为获取时区列表,使用 `timedatectl` 命令的 `list-timezones` 参数:
|
||||
|
||||
```
|
||||
timedatectl list-timezones
|
||||
```
|
||||
|
||||
它将向你显示大量可用的时区列表。
|
||||
|
||||
![Timezones List][6]
|
||||
|
||||
你可以使用向上箭头和向下箭头或 `PgUp` 和 `PgDown` 键来在页面之间移动。
|
||||
|
||||
你也可以 `grep` 输出,并搜索你的时区。例如,假如你正在寻找欧洲的时区,你可以使用:
|
||||
|
||||
```
|
||||
timedatectl list-timezones | grep -i europe
|
||||
```
|
||||
|
||||
比方说,你想设置时区为巴黎。在这里,使用的时区值的 Europe/Paris :
|
||||
|
||||
```
|
||||
timedatectl set-timezone Europe/Paris
|
||||
```
|
||||
|
||||
它虽然不显示任何成功信息,但是时区会立即更改。你不需要重新启动或注销。
|
||||
|
||||
记住,虽然你不需要成为 root 用户并对命令使用 `sudo`,但是你的账户仍然需要拥有管理器权限来更改时区。
|
||||
|
||||
你可以使用 [date 命令][7] 来验证更改的时间好时区:
|
||||
|
||||
```
|
||||
[email protected]:~$ date
|
||||
Sat Jan 18 13:56:26 CET 2020
|
||||
```
|
||||
|
||||
#### 方法 2: 通过 GUI 更改 Ubuntu 时区
|
||||
|
||||
按下 `super` 键 (Windows 键) ,并搜索设置:
|
||||
|
||||
![Applications Menu Settings][8]
|
||||
|
||||
在左侧边栏中,向下滚动一点,查看详细信息:
|
||||
|
||||
![Go to Settings -> Details][9]
|
||||
|
||||
在详细信息中,你将在左侧边栏中找到“日期和时间”。在这里,你应该关闭自动时区选项(如果它已经被启用),然后在时区上单击:
|
||||
|
||||
![In Details -> Date & Time, turn off the Automatic Time Zone][10]
|
||||
|
||||
当你单击时区时,它将打开一个交互式地图,你可以在你选择的地理位置上单击,关闭窗口。
|
||||
|
||||
![Select a timezone][11]
|
||||
|
||||
在选择新的时区后,除了关闭这个地图后,你不必做任何事情。不需要注销或 [关闭 Ubuntu][12]。
|
||||
|
||||
我希望这篇快速教程能帮助你在 Ubuntu 和其它 Linux 发行版中更改时区。如果你有问题或建议,请告诉我。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/change-timezone-ubuntu/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[robsean](https://github.com/robsean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/install-ubuntu/
|
||||
[2]: tmp.bHvVztzy6d#change-timezone-gui
|
||||
[3]: tmp.bHvVztzy6d#change-timezone-command-line
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/Ubuntu_Change-_Time_Zone.png?ssl=1
|
||||
[5]: https://ubuntu.com/
|
||||
[6]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/timezones_in_ubuntu.jpg?ssl=1
|
||||
[7]: https://linuxhandbook.com/date-command/
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/08/applications_menu_settings.jpg?ssl=1
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/settings_detail_ubuntu.jpg?ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/change_timezone_in_ubuntu.jpg?ssl=1
|
||||
[11]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/change_timezone_in_ubuntu_2.jpg?ssl=1
|
||||
[12]: https://itsfoss.com/schedule-shutdown-ubuntu/
|
104
published/20200119 One open source chat tool to rule them all.md
Normal file
104
published/20200119 One open source chat tool to rule them all.md
Normal file
@ -0,0 +1,104 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11856-1.html)
|
||||
[#]: subject: (One open source chat tool to rule them all)
|
||||
[#]: via: (https://opensource.com/article/20/1/open-source-chat-tool)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
一个通过 IRC 管理所有聊天的开源聊天工具
|
||||
======
|
||||
|
||||
> BitlBee 将多个聊天应用集合到一个界面中。在我们的 20 个使用开源提升生产力的系列的第九篇文章中了解如何设置和使用 BitlBee。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/05/123636dw8uw34mbkqzmw84.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 将所有聊天都放到 BitlBee 中
|
||||
|
||||
即时消息和聊天已经成为网络世界的主要内容。如果你像我一样,你可能打开五六个不同的应用与你的朋友、同事和其他人交谈。关注所有聊天真的很痛苦。谢天谢地,你可以使用一个应用(好吧,是两个)将这些聊天整个到一个地方。
|
||||
|
||||
![BitlBee on XChat][2]
|
||||
|
||||
[BitlBee][3] 是作为服务运行的应用,它可以将标准的 IRC 客户端与大量的消息服务进行桥接。而且,由于它本质上是 IRC 服务器,因此你可以选择很多客户端。
|
||||
|
||||
BitlBee 几乎包含在所有 Linux 发行版中。在 Ubuntu 上安装(我选择的 Linux 桌面),类似这样:
|
||||
|
||||
```
|
||||
sudo apt install bitlbee-libpurple
|
||||
```
|
||||
|
||||
在其他发行版上,包名可能略有不同,但搜索 “bitlbee” 应该就能看到。
|
||||
|
||||
你会注意到我用的 libpurple 版的 BitlBee。这个版本能让我使用 [libpurple][4] 即时消息库中提供的所有协议,该库最初是为 [Pidgin][5] 开发的。
|
||||
|
||||
安装完成后,服务应会自动启动。现在,使用一个 IRC 客户端(图片中为 [XChat][6]),我可以连接到端口 6667(标准 IRC 端口)上的服务。
|
||||
|
||||
![Initial BitlBee connection][7]
|
||||
|
||||
你将自动连接到控制频道 &bitlbee。此频道对于你是独一无二的,在多用户系统上每个人都有一个自己的。在这里你可以配置该服务。
|
||||
|
||||
在控制频道中输入 `help`,你可以随时获得完整的文档。浏览它,然后使用 `register` 命令在服务器上注册帐户。
|
||||
|
||||
```
|
||||
register <mypassword>
|
||||
```
|
||||
|
||||
现在,你在服务器上所做的任何配置更改(IM 帐户、设置等)都将在输入 `save` 时保存。每当你连接时,使用 `identify <mypassword>` 连接到你的帐户并加载这些设置。
|
||||
|
||||
![purple settings][8]
|
||||
|
||||
命令 `help purple` 将显示 libpurple 提供的所有可用协议。例如,我安装了 [telegram-purple][9] 包,它增加了连接到 Telegram 的能力。我可以使用 `account add` 命令将我的电话号码作为帐户添加。
|
||||
|
||||
```
|
||||
account add telegram +15555555
|
||||
```
|
||||
|
||||
BitlBee 将显示它已添加帐户。你可以使用 `account list` 列出你的帐户。因为我只有一个帐户,我可以通过 `account 0 on` 登录,它会进行 Telegram 登录,列出我所有的朋友和聊天,接下来就能正常聊天了。
|
||||
|
||||
但是,对于 Slack 这个最常见的聊天系统之一呢?你可以安装 [slack-libpurple][10] 插件,并且对 Slack 执行同样的操作。如果你不愿意编译和安装这些,这可能不适合你。
|
||||
|
||||
按照插件页面上的说明操作,安装后重新启动 BitlBee 服务。现在,当你运行 `help purple` 时,应该会列出 Slack。像其他协议一样添加一个 Slack 帐户。
|
||||
|
||||
```
|
||||
account add slack ksonney@myslack.slack.com
|
||||
account 1 set password my_legcay_API_token
|
||||
account 1 on
|
||||
```
|
||||
|
||||
你知道么,你已经连接到 Slack 中,你可以通过 `chat add` 命令添加你感兴趣的 Slack 频道。比如:
|
||||
|
||||
```
|
||||
chat add 1 happyparty
|
||||
```
|
||||
|
||||
将 Slack 频道 happyparty 添加为本地频道 #happyparty。现在可以使用标准 IRC `/join` 命令访问该频道。这很酷。
|
||||
|
||||
BitlBee 和 IRC 客户端帮助我的(大部分)聊天和即时消息保存在一个地方,并减少了我的分心,因为我不再需要查找并切换到任何一个刚刚找我的应用上。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/open-source-chat-tool
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/laptop_screen_desk_work_chat_text.png?itok=UXqIDRDD (Person using a laptop)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/productivity_9-1.png (BitlBee on XChat)
|
||||
[3]: https://www.bitlbee.org/
|
||||
[4]: https://developer.pidgin.im/wiki/WhatIsLibpurple
|
||||
[5]: http://pidgin.im/
|
||||
[6]: http://xchat.org/
|
||||
[7]: https://opensource.com/sites/default/files/uploads/productivity_9-2.png (Initial BitlBee connection)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/productivity_9-3.png (purple settings)
|
||||
[9]: https://github.com/majn/telegram-purple
|
||||
[10]: https://github.com/dylex/slack-libpurple
|
||||
[11]: mailto:ksonney@myslack.slack.com
|
@ -0,0 +1,65 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11858-1.html)
|
||||
[#]: subject: (Use this Twitter client for Linux to tweet from the terminal)
|
||||
[#]: via: (https://opensource.com/article/20/1/tweet-terminal-rainbow-stream)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用这个 Twitter 客户端在 Linux 终端中发推特
|
||||
======
|
||||
|
||||
> 在我们的 20 个使用开源提升生产力的系列的第十篇文章中,使用 Rainbow Stream 跟上你的 Twitter 流而无需离开终端。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/06/113720bwi55j7xcccwwwi0.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 通过 Rainbow Stream 跟上Twitter
|
||||
|
||||
我喜欢社交网络和微博。它快速、简单,还有我可以与世界分享我的想法。当然,缺点是几乎所有非 Windows 的桌面客户端都对是网站的封装。[Twitter][2] 有很多客户端,但我真正想要的是轻量、易于使用,最重要的是吸引人的客户端。
|
||||
|
||||
![Rainbow Stream for Twitter][3]
|
||||
|
||||
[Rainbow Stream][4] 是好看的 Twitter 客户端之一。它简单易用,并且可以通过 `pip3 install rainbowstream` 快速安装。第一次运行时,它将打开浏览器窗口,并让你通过 Twitter 授权。完成后,你将回到命令行,你的 Twitter 时间线将开始滚动。
|
||||
|
||||
![Rainbow Stream first run][5]
|
||||
|
||||
要了解的最重要的命令是 `p` 暂停推流、`r` 继续推流、`h` 得到帮助,以及 `t` 发布新的推文。例如,`h tweets` 将提供发送和回复推文的所有选项。另一个有用的帮助页面是 `h messages`,它提供了处理直接消息的命令,这是我妻子和我经常使用的东西。还有很多其他命令,我会回头获得很多帮助。
|
||||
|
||||
随着时间线的滚动,你可以看到它有完整的 UTF-8 支持,并以正确的字体显示推文被转推以及喜欢的次数,图标和 emoji 也能正确显示。
|
||||
|
||||
![Kill this love][6]
|
||||
|
||||
关于 Rainbow Stream 的*最好*功能之一就是你不必放弃照片和图像。默认情况下,此功能是关闭的,但是你可以使用 `config` 命令尝试它。
|
||||
|
||||
```
|
||||
config IMAGE_ON_TERM = true
|
||||
```
|
||||
|
||||
此命令将任何图像渲染为 ASCII 艺术。如果你有大量照片流,它可能会有点多,但是我喜欢。它有非常复古的 1990 年代 BBS 感觉,我也确实喜欢 1990 年代的 BBS 场景。
|
||||
|
||||
你还可以使用 Rainbow Stream 管理列表、屏蔽某人、拉黑某人、关注、取消关注以及 Twitter API 的所有其他功能。它还支持主题,因此你可以用喜欢的颜色方案自定义流。
|
||||
|
||||
当我正在工作并且不想在浏览器上打开另一个选项卡时,Rainbow Stream 让我可以留在终端中。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/tweet-terminal-rainbow-stream
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/talk_chat_communication_team.png?itok=CYfZ_gE7 (Chat bubbles)
|
||||
[2]: https://twitter.com/home
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_10-1.png (Rainbow Stream for Twitter)
|
||||
[4]: https://rainbowstream.readthedocs.io/en/latest/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/productivity_10-2.png (Rainbow Stream first run)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/day10-image3_1.png (Kill this love)
|
63
published/20200121 Read Reddit from the Linux terminal.md
Normal file
63
published/20200121 Read Reddit from the Linux terminal.md
Normal file
@ -0,0 +1,63 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11869-1.html)
|
||||
[#]: subject: (Read Reddit from the Linux terminal)
|
||||
[#]: via: (https://opensource.com/article/20/1/open-source-reddit-client)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
在 Linux 终端中阅读 Reddit
|
||||
======
|
||||
|
||||
> 在我们的 20 个使用开源提升生产力的系列的第十一篇文章中使用 Reddit 客户端 Tuir 在工作中短暂休息一下。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/09/104113w1ytjmlv1jly0j1t.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 Tuir 阅读 Reddit
|
||||
|
||||
短暂休息对于保持生产力很重要。我休息时喜欢去的地方之一是 [Reddit][2],如果你愿意,这可能是一个很好的资源。我在那里发现了各种有关 DevOps、生产力、Emacs、鸡和 ChromeOS 项目的文章。这些讨论可能很有价值。我还关注了一些只有动物图片的子板,因为我喜欢动物(而不只是鸡)照片,有时经过长时间的工作后,我真正需要的是小猫照片。
|
||||
|
||||
![/r/emacs in Tuir][3]
|
||||
|
||||
当我阅读 Reddit(不仅仅是看动物宝宝的图片)时,我使用 [Tuir][4](Reddit 终端 UI)。Tuir 是功能齐全的 Reddit 客户端,可以在运行 Python 的任何系统上运行。安装是通过 `pip` 完成的,非常简单。
|
||||
|
||||
首次运行时,Tuir 会进入 Reddit 默认文章列表。屏幕的顶部和底部有列出不同命令的栏。顶部栏显示你在 Reddit 上的位置,第二行显示根据 Reddit “Hot/New/Controversial” 等类别筛选的命令。按下筛选器前面的数字触发筛选。
|
||||
|
||||
![Filtering by Reddit's "top" category][5]
|
||||
|
||||
你可以使用箭头键或 `j`、`k`、`h` 和 `l` 键浏览列表,这与 Vi/Vim 使用的键相同。底部栏有用于应用导航的命令。如果要跳转到另一个子板,只需按 `/` 键打开提示,然后输入你要进入的子板名称。
|
||||
|
||||
![Logging in][6]
|
||||
|
||||
某些东西除非你登录,否则无法访问。如果你尝试执行需要登录的操作,那么 Tuir 就会提示你,例如发布新文章 (`c`)或赞成/反对 (`a` 和 `z`)。要登录,请按 `u` 键。这将打开浏览器以通过 OAuth2 登录,Tuir 将保存令牌。之后,你的用户名应出现在屏幕的右上方。
|
||||
|
||||
Tuir 还可以打开浏览器来查看图像、加载链接等。稍作调整,它甚至可以在终端中显示图像(尽管我没有让它可以正常工作)。
|
||||
|
||||
总的来说,我对 Tuir 在我需要休息时能快速跟上 Reddit 感到很满意。
|
||||
|
||||
Tuir 是现已淘汰的 [RTV][7] 的两个分叉之一。另一个是 [TTRV][8],它还无法通过 `pip` 安装,但功能相同。我期待看到它们随着时间的推移脱颖而出。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/open-source-reddit-client
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_web_internet_website.png?itok=g5B_Bw62 (Digital creative of a browser on the internet)
|
||||
[2]: https://www.reddit.com/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_11-1.png (/r/emacs in Tuir)
|
||||
[4]: https://gitlab.com/ajak/tuir
|
||||
[5]: https://opensource.com/sites/default/files/uploads/productivity_11-2.png (Filtering by Reddit's "top" category)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_11-3.png (Logging in)
|
||||
[7]: https://github.com/michael-lazar/rtv
|
||||
[8]: https://github.com/tildeclub/ttrv
|
@ -0,0 +1,72 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11876-1.html)
|
||||
[#]: subject: (Get your RSS feeds and podcasts in one place with this open source tool)
|
||||
[#]: via: (https://opensource.com/article/20/1/open-source-rss-feed-reader)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用此开源工具在一起收取你的 RSS 订阅源和播客
|
||||
======
|
||||
|
||||
> 在我们的 20 个使用开源提升生产力的系列的第十二篇文章中使用 Newsboat 收取你的新闻 RSS 源和播客。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/10/162526wv5jdl0m12sw10md.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 Newsboat 访问你的 RSS 源和播客
|
||||
|
||||
RSS 新闻源是了解各个网站最新消息的非常方便的方法。除了 Opensource.com,我还会关注 [SysAdvent][2] sysadmin 年度工具,还有一些我最喜欢的作者以及一些网络漫画。RSS 阅读器可以让我“批处理”阅读内容,因此,我每天不会在不同的网站上花费很多时间。
|
||||
|
||||
![Newsboat][3]
|
||||
|
||||
[Newsboat][4] 是一个基于终端的 RSS 订阅源阅读器,外观感觉很像电子邮件程序 [Mutt][5]。它使阅读新闻变得容易,并有许多不错的功能。
|
||||
|
||||
安装 Newsboat 非常容易,因为它包含在大多数发行版(以及 MacOS 上的 Homebrew)中。安装后,只需在 `~/.newsboat/urls` 中添加订阅源。如果你是从其他阅读器迁移而来,并有导出的 OPML 文件,那么可以使用以下方式导入:
|
||||
|
||||
```
|
||||
newsboat -i </path/to/my/feeds.opml>
|
||||
```
|
||||
|
||||
添加订阅源后,Newsboat 的界面非常熟悉,特别是如果你使用过 Mutt。你可以使用箭头键上下滚动,使用 `r` 检查某个源中是否有新项目,使用 `R` 检查所有源中是否有新项目,按回车打开订阅源,并选择要阅读的文章。
|
||||
|
||||
![Newsboat article list][6]
|
||||
|
||||
但是,你不仅限于本地 URL 列表。Newsboat 还是 [Tiny Tiny RSS][7]、ownCloud 和 Nextcloud News 等新闻阅读服务以及一些 Google Reader 后续产品的客户端。[Newsboat 的文档][8]中涵盖了有关此的详细信息以及其他许多配置选项。
|
||||
|
||||
![Reading an article in Newsboat][9]
|
||||
|
||||
#### 播客
|
||||
|
||||
Newsboat 还通过 Podboat 提供了[播客支持][10],Podboat 是一个附带的应用,它可帮助下载和排队播客节目。在 Newsboat 中查看播客源时,按下 `e` 将节目添加到你的下载队列中。所有信息将保存在 `~/.newsboat` 目录中的队列文件中。Podboat 读取此队列并将节目下载到本地磁盘。你可以在 Podboat 的用户界面(外观和行为类似于 Newsboat)执行此操作,也可以使用 `podboat -a` 让 Podboat 下载所有内容。作为播客人和播客听众,我认为这*真的*很方便。
|
||||
|
||||
![Podboat][11]
|
||||
|
||||
总体而言,Newsboat 有一些非常好的功能,并且是一些基于 Web 或桌面应用的不错的轻量级替代方案。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/open-source-rss-feed-reader
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/ship_captain_devops_kubernetes_steer.png?itok=LAHfIpek (Ship captain sailing the Kubernetes seas)
|
||||
[2]: https://sysadvent.blogspot.com/
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_12-1.png (Newsboat)
|
||||
[4]: https://newsboat.org
|
||||
[5]: http://mutt.org/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/productivity_12-2.png (Newsboat article list)
|
||||
[7]: https://tt-rss.org/
|
||||
[8]: https://newsboat.org/releases/2.18/docs/newsboat.html
|
||||
[9]: https://opensource.com/sites/default/files/uploads/productivity_12-3.png (Reading an article in Newsboat)
|
||||
[10]: https://newsboat.org/releases/2.18/docs/newsboat.html#_podcast_support
|
||||
[11]: https://opensource.com/sites/default/files/uploads/productivity_12-4.png (Podboat)
|
105
published/20200123 How to stop typosquatting attacks.md
Normal file
105
published/20200123 How to stop typosquatting attacks.md
Normal file
@ -0,0 +1,105 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11899-1.html)
|
||||
[#]: subject: (How to stop typosquatting attacks)
|
||||
[#]: via: (https://opensource.com/article/20/1/stop-typosquatting-attacks)
|
||||
[#]: author: (Sam Bocetta https://opensource.com/users/sambocetta)
|
||||
|
||||
如何防范误植攻击
|
||||
======
|
||||
|
||||
> <ruby>误植<rt>Typosquatting</rt></ruby>是一种引诱用户将敏感数据泄露给不法分子的方式,针对这种攻击方式,我们很有必要了解如何保护我们的组织、我们的开源项目以及我们自己。
|
||||
|
||||
![Gears above purple clouds][1]
|
||||
|
||||
除了常规手段以外,网络罪犯还会利用社会工程的方式,试图让安全意识较弱的人泄露私人信息或是有价值的证书。很多[网络钓鱼骗局][2]的实质都是攻击者伪装成信誉良好的公司或组织,然后借此大规模传播病毒或恶意软件。
|
||||
|
||||
<ruby>[误植][3]<rt>Typosquatting</rt></ruby>就是其中一个常用的手法。它是一种社会工程学的攻击方式,通过使用一些合法网站的错误拼写的 URL 以引诱用户访问恶意网站,这样的做法既使真正的原网站遭受声誉上的损害,又诱使用户向这些恶意网站提交个人敏感信息。因此,网站的管理人员和用户双方都应该意识到这个问题带来的风险,并采取措施加以保护。
|
||||
|
||||
一些由广大开发者在公共代码库中维护的开源软件通常都被认为具有安全上的优势,但当面临社会工程学攻击或恶意软件植入时,开源软件也需要注意以免受到伤害。
|
||||
|
||||
下面就来关注一下误植攻击的发展趋势,以及这种攻击方式在未来可能对开源软件造成的影响。
|
||||
|
||||
### 什么是误植?
|
||||
|
||||
误植是一种非常特殊的网络犯罪形式,其背后通常是一个更大的网络钓鱼骗局。不法分子首先会购买和注册域名,而他们注册的域名通常是一个常用网站的错误拼写形式,例如在正确拼写的基础上添加一个额外的元音字母,又或者是将字母“i”替换成字母“l”。对于同一个正常域名,不法分子通常会注册数十个拼写错误的变体域名。
|
||||
|
||||
用户一旦访问这样的域名,不法分子的目的就已经成功了一半。为此,他们会通过电子邮件的方式,诱导用户访问这样的伪造域名。伪造域名指向的页面中,通常都带有一个简单的登录界面,还会附上熟悉的被模仿网站的徽标,尽可能让用户认为自己访问的是真实的网站。
|
||||
|
||||
如果用户没有识破这一个骗局,在页面中提交了诸如银行卡号、用户名、密码等敏感信息,这些数据就会被不法分子所完全掌控。进一步来看,如果这个用户在其它网站也使用了相同的用户名和密码,那就有同样受到波及的风险。受害者最终可能会面临身份被盗、信用记录被破坏等危险。
|
||||
|
||||
### 最近的一些案例
|
||||
|
||||
从网站的所有方来看,遭到误植攻击可能会带来一场公关危机。尽管网站域名的所有者没有参与到犯罪当中,但这会被认为是一次管理上的失职,因为域名所有者有主动防御误植攻击的责任,以避免这一类欺诈事件的发生。
|
||||
|
||||
在几年之前就发生过[一起案件][4],很多健康保险客户收到了一封指向 we11point.com 的钓鱼电子邮件,其中 URL 里正确的字母“l”被换成了数字“1”,从而导致一批用户成为了这一次攻击的受害者。
|
||||
|
||||
最初,与特定国家/地区相关的顶级域名是不允许随意注册的。但后来国际域名规则中放开这一限制之后,又兴起了一波新的误植攻击。例如最常见的一种手法就是注册一个与 .com 域名类似的 .om 域名,一旦在输入 URL 时不慎遗漏了字母 c 就会给不法分子带来可乘之机。
|
||||
|
||||
### 网站如何防范误植攻击
|
||||
|
||||
对于一个公司来说,最好的策略就是永远比误植攻击采取早一步的行动。
|
||||
|
||||
也就是说,在注册域名的时候,不仅要注册自己商标名称的域名,最好还要同时注册可能由于拼写错误产生的其它域名。当然,没有太大必要把可能导致错误的所有顶级域名都注册掉,但至少要把可能导致错误的一些一级域名抢注下来。
|
||||
|
||||
如果你有让用户跳转到一个第三方网站的需求,务必要让用户从你的官方网站上进行跳转,而不应该通过类似群发邮件的方式向用户告知 URL。因此,必须明确一个策略:在与用户通信交流时,不将用户引导到官方网站以外的地方去。在这样的情况下,如果有不法分子试图以你公司的名义发布虚假消息,用户将会从带有异样的页面或 URL 上有所察觉。
|
||||
|
||||
你可以使用类似 [DNS Twist][5] 的开源工具来扫描公司正在使用的域名,它可以确定是否有相似的域名已被注册,从而暴露潜在的误植攻击。DNS Twist 可以在 Linux 系统上通过一系列的 shell 命令来运行。
|
||||
|
||||
还有一些网络提供商(ISP)会将防护误植攻击作为他们网络产品的一部分。这就相当于一层额外的保护,如果用户不慎输入了带有拼写错误的 URL,就会被提示该页面已经被阻止并重定向到正确的域名。
|
||||
|
||||
如果你是系统管理员,还可以考虑运行一个自建的 [DNS 服务器][6],以便通过黑名单的机制禁止对某些域名的访问。
|
||||
|
||||
你还可以密切监控网站的访问流量,如果来自某个特定地区的用户被集体重定向到了虚假的站点,那么访问量将会发生骤降。这也是一个有效监控误植攻击的角度。
|
||||
|
||||
防范误植攻击与防范其它网络攻击一样需要保持警惕。所有用户都希望网站的所有者能够扫除那些与正主类似的假冒站点,如果这项工作没有做好,用户的信任对你的信任程度就会每况愈下。
|
||||
|
||||
### 误植对开源软件的影响
|
||||
|
||||
因为开源项目的源代码是公开的,所以其中大部分项目都会进行安全和渗透测试。但错误是不可能完全避免的,如果你参与了开源项目,还是有需要注意的地方。
|
||||
|
||||
当你收到一个不明来源的<ruby>合并请求<rt>Merge Request</rt></ruby>或补丁时,必须在合并之前仔细检查,尤其是相关代码涉及到网络层面的时候。不要屈服于只测试构建的诱惑; 一定要进行严格的检查和测试,以确保没有恶意代码混入正常的代码当中。
|
||||
|
||||
同时,还要严格按照正确的方法使用域名,避免不法分子创建仿冒的下载站点并提供带有恶意代码的软件。可以通过如下所示的方法使用数字签名来确保你的软件没有被篡改:
|
||||
|
||||
```
|
||||
gpg --armor --detach-sig \
|
||||
--output advent-gnome.sig \
|
||||
example-0.0.1.tar.xz
|
||||
```
|
||||
|
||||
同时给出你提供的文件的校验和:
|
||||
|
||||
```
|
||||
sha256sum example-0.0.1.tar.xz > example-0.0.1.txt
|
||||
```
|
||||
|
||||
无论你的用户会不会去用上这些安全措施,你也应该提供这些必要的信息。因为只要有那么一个人留意到签名有异样,就能为你敲响警钟。
|
||||
|
||||
### 总结
|
||||
|
||||
人类犯错在所难免。世界上数百万人输入同一个网址时,总会有人出现拼写的错误。不法分子也正是抓住了这个漏洞才得以实施误植攻击。
|
||||
|
||||
用抢注域名的方式去完全根治误植攻击也是不太现实的,我们更应该关注这种攻击的传播方式以减轻它对我们的影响。最好的保护就是和用户之间建立信任,并积极检测误植攻击的潜在风险。作为开源社区,我们更应该团结起来一起应对误植攻击。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/stop-typosquatting-attacks
|
||||
|
||||
作者:[Sam Bocetta][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[HankChow](https://github.com/HankChow)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/sambocetta
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/chaos_engineer_monster_scary_devops_gear_kubernetes.png?itok=GPYLvfVh (Gears above purple clouds)
|
||||
[2]: https://www.cloudberrylab.com/resources/guides/types-of-phishing/
|
||||
[3]: https://en.wikipedia.org/wiki/Typosquatting
|
||||
[4]: https://www.menlosecurity.com/blog/-a-new-approach-to-end-typosquatting
|
||||
[5]: https://github.com/elceef/dnstwist
|
||||
[6]: https://opensource.com/article/17/4/build-your-own-name-server
|
@ -0,0 +1,99 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11879-1.html)
|
||||
[#]: subject: (Use this open source tool to get your local weather forecast)
|
||||
[#]: via: (https://opensource.com/article/20/1/open-source-weather-forecast)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用这个开源工具获取本地天气预报
|
||||
======
|
||||
|
||||
> 在我们的 20 个使用开源提升生产力的系列的第十三篇文章中使用 wego 来了解出门前你是否要需要外套、雨伞或者防晒霜。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/11/140842a8qwomfeg9mwegg8.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 wego 了解天气
|
||||
|
||||
过去十年我对我的职业最满意的地方之一是大多数时候是远程工作。尽管现实情况是我很多时候是在家里办公,但我可以在世界上任何地方工作。缺点是,离家时我会根据天气做出一些决定。在我居住的地方,“晴朗”可以表示从“酷热”、“低于零度”到“一小时内会小雨”。能够了解实际情况和快速预测非常有用。
|
||||
|
||||
![Wego][2]
|
||||
|
||||
[Wego][3] 是用 Go 编写的程序,可以获取并显示你的当地天气。如果你愿意,它甚至可以用闪亮的 ASCII 艺术效果进行渲染。
|
||||
|
||||
要安装 `wego`,你需要确保在系统上安装了[Go][4]。之后,你可以使用 `go get` 命令获取最新版本。你可能还想将 `~/go/bin` 目录添加到路径中:
|
||||
|
||||
```
|
||||
go get -u github.com/schachmat/wego
|
||||
export PATH=~/go/bin:$PATH
|
||||
wego
|
||||
```
|
||||
|
||||
首次运行时,`wego` 会报告缺失 API 密钥。现在你需要决定一个后端。默认后端是 [Forecast.io][5],它是 [Dark Sky][6]的一部分。`wego` 还支持 [OpenWeatherMap][7] 和 [WorldWeatherOnline][8]。我更喜欢 OpenWeatherMap,因此我将在此向你展示如何设置。
|
||||
|
||||
你需要在 OpenWeatherMap 中[注册 API 密钥][9]。注册是免费的,尽管免费的 API 密钥限制了一天可以查询的数量,但这对于普通用户来说应该没问题。得到 API 密钥后,将它放到 `~/.wegorc` 文件中。现在可以填写你的位置、语言以及使用公制、英制(英国/美国)还是国际单位制(SI)。OpenWeatherMap 可通过名称、邮政编码、坐标和 ID 确定位置,这是我喜欢它的原因之一。
|
||||
|
||||
```
|
||||
# wego configuration for OEM
|
||||
aat-coords=false
|
||||
aat-monochrome=false
|
||||
backend=openweathermap
|
||||
days=3
|
||||
forecast-lang=en
|
||||
frontend=ascii-art-table
|
||||
jsn-no-indent=false
|
||||
location=Pittsboro
|
||||
owm-api-key=XXXXXXXXXXXXXXXXXXXXX
|
||||
owm-debug=false
|
||||
owm-lang=en
|
||||
units=imperial
|
||||
```
|
||||
|
||||
现在,在命令行运行 `wego` 将显示接下来三天的当地天气。
|
||||
|
||||
`wego` 还可以输出 JSON 以便程序使用,还可显示 emoji。你可以使用 `-f` 参数或在 `.wegorc` 文件中指定前端。
|
||||
|
||||
![Wego at login][10]
|
||||
|
||||
如果你想在每次打开 shell 或登录主机时查看天气,只需将 wego 添加到 `~/.bashrc`(我这里是 `~/.zshrc`)即可。
|
||||
|
||||
[wttr.in][11] 项目是 wego 上的基于 Web 的封装。它提供了一些其他显示选项,并且可以在同名网站上看到。关于 wttr.in 的一件很酷的事情是,你可以使用 `curl` 获取一行天气信息。我有一个名为 `get_wttr` 的 shell 函数,用于获取当前简化的预报信息。
|
||||
|
||||
```
|
||||
get_wttr() {
|
||||
curl -s "wttr.in/Pittsboro?format=3"
|
||||
}
|
||||
```
|
||||
|
||||
![weather tool for productivity][12]
|
||||
|
||||
现在,在我离开家之前,我就可以通过命令行快速简单地获取我是否需要外套、雨伞或者防晒霜了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/open-source-weather-forecast
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bus-cloud.png?itok=vz0PIDDS (Sky with clouds and grass)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/productivity_13-1.png (Wego)
|
||||
[3]: https://github.com/schachmat/wego
|
||||
[4]: https://golang.org/doc/install
|
||||
[5]: https://forecast.io
|
||||
[6]: https://darksky.net
|
||||
[7]: https://openweathermap.org/
|
||||
[8]: https://www.worldweatheronline.com/
|
||||
[9]: https://openweathermap.org/api
|
||||
[10]: https://opensource.com/sites/default/files/uploads/productivity_13-2.png (Wego at login)
|
||||
[11]: https://github.com/chubin/wttr.in
|
||||
[12]: https://opensource.com/sites/default/files/uploads/day13-image3.png (weather tool for productivity)
|
147
published/20200124 3 handy command-line internet speed tests.md
Normal file
147
published/20200124 3 handy command-line internet speed tests.md
Normal file
@ -0,0 +1,147 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11882-1.html)
|
||||
[#]: subject: (3 handy command-line internet speed tests)
|
||||
[#]: via: (https://opensource.com/article/20/1/internet-speed-tests)
|
||||
[#]: author: (Ben Nuttall https://opensource.com/users/bennuttall)
|
||||
|
||||
3 个方便的命令行网速测试工具
|
||||
======
|
||||
|
||||
> 用这三个开源工具检查你的互联网和局域网速度。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/12/115915kk6hkax1vparkuvk.jpg)
|
||||
|
||||
能够验证网络连接速度使您可以控制计算机。 使您可以在命令行中检查互联网和网络速度的三个开源工具是 Speedtest、Fast 和 iPerf。
|
||||
|
||||
### Speedtest
|
||||
|
||||
[Speedtest][2] 是一个旧宠。它用 Python 实现,并打包在 Apt 中,也可用 `pip` 安装。你可以将它作为命令行工具或在 Python 脚本中使用。
|
||||
|
||||
使用以下命令安装:
|
||||
|
||||
```
|
||||
sudo apt install speedtest-cli
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```
|
||||
sudo pip3 install speedtest-cli
|
||||
```
|
||||
|
||||
然后使用命令 `speedtest` 运行它:
|
||||
|
||||
```
|
||||
$ speedtest
|
||||
Retrieving speedtest.net configuration...
|
||||
Testing from CenturyLink (65.128.194.58)...
|
||||
Retrieving speedtest.net server list...
|
||||
Selecting best server based on ping...
|
||||
Hosted by CenturyLink (Cambridge, UK) [20.49 km]: 31.566 ms
|
||||
Testing download speed................................................................................
|
||||
Download: 68.62 Mbit/s
|
||||
Testing upload speed......................................................................................................
|
||||
Upload: 10.93 Mbit/s
|
||||
```
|
||||
|
||||
它给你提供了互联网上传和下载的网速。它快速而且可脚本调用,因此你可以定期运行它,并将输出保存到文件或数据库中,以记录一段时间内的网络速度。
|
||||
|
||||
### Fast
|
||||
|
||||
[Fast][3] 是 Netflix 提供的服务。它的网址是 [Fast.com][4],同时它有一个可通过 `npm` 安装的命令行工具:
|
||||
|
||||
```
|
||||
npm install --global fast-cli
|
||||
```
|
||||
|
||||
网站和命令行程序都提供了相同的基本界面:它是一个尽可能简单的速度测试:
|
||||
|
||||
```
|
||||
$ fast
|
||||
|
||||
82 Mbps ↓
|
||||
```
|
||||
|
||||
该命令返回你的网络下载速度。要获取上传速度,请使用 `-u` 标志:
|
||||
|
||||
```
|
||||
$ fast -u
|
||||
|
||||
⠧ 80 Mbps ↓ / 8.2 Mbps ↑
|
||||
```
|
||||
|
||||
### iPerf
|
||||
|
||||
[iPerf][5] 测试的是局域网速度(而不是像前两个工具一样测试互联网速度)的好方法。Debian、Raspbian 和 Ubuntu 用户可以使用 apt 安装它:
|
||||
|
||||
```
|
||||
sudo apt install iperf
|
||||
```
|
||||
|
||||
它还可用于 Mac 和 Windows。
|
||||
|
||||
安装完成后,你需要在同一网络上的两台计算机上使用它(两台都必须安装 iPerf)。指定其中一台作为服务器。
|
||||
|
||||
获取服务端计算机的 IP 地址:
|
||||
|
||||
```
|
||||
ip addr show | grep inet.*brd
|
||||
```
|
||||
|
||||
你的本地 IP 地址(假设为 IPv4 本地网络)以 `192.168` 或 `10` 开头。记下 IP 地址,以便可以在另一台计算机(指定为客户端的计算机)上使用它。
|
||||
|
||||
在服务端启动 `iperf`:
|
||||
|
||||
```
|
||||
iperf -s
|
||||
```
|
||||
|
||||
它会等待来自客户端的传入连接。将另一台计算机作为为客户端并运行此命令,将示例中的 IP 替换为服务端计算机的 IP:
|
||||
|
||||
```
|
||||
iperf -c 192.168.1.2
|
||||
```
|
||||
|
||||
![iPerf][6]
|
||||
|
||||
只需几秒钟即可完成测试,然后返回传输大小和计算出的带宽。我使用家用服务器作为服务端,在 PC 和笔记本电脑上进行了一些测试。我最近在房屋周围安装了六类线以太网,因此我的有线连接速度达到 1Gbps,但 WiFi 连接速度却低得多。
|
||||
|
||||
![iPerf][7]
|
||||
|
||||
你可能注意到它记录到 16Gbps。那是我使用服务器进行自我测试,因此它只是在测试写入磁盘的速度。该服务器具有仅 16 Gbps 的硬盘驱动器,但是我的台式机有 46Gbps,另外我的(较新的)笔记本超过了 60Gbps,因为它们都有固态硬盘。
|
||||
|
||||
![iPerf][8]
|
||||
|
||||
### 总结
|
||||
|
||||
通过这些工具来了解你的网络速度是一项非常简单的任务。如果你更喜欢脚本或者在命令行中运行,上面的任何一个都能满足你。如果你要了解点对点的指标,iPerf 能满足你。
|
||||
|
||||
你还使用其他哪些工具来衡量家庭网络?在评论中分享你的评论。
|
||||
|
||||
本文最初发表在 Ben Nuttall 的 [Tooling blog][9] 上,并获准在此使用。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/internet-speed-tests
|
||||
|
||||
作者:[Ben Nuttall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/bennuttall
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/train-plane-speed-big-machine.png?itok=f377dXKs (Old train)
|
||||
[2]: https://github.com/sivel/speedtest-cli
|
||||
[3]: https://github.com/sindresorhus/fast-cli
|
||||
[4]: https://fast.com/
|
||||
[5]: https://iperf.fr/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/iperf.png (iPerf)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/iperf2.png (iPerf)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/iperf3.png (iPerf)
|
||||
[9]: https://tooling.bennuttall.com/command-line-speedtest-tools/
|
@ -0,0 +1,111 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11892-1.html)
|
||||
[#]: subject: (Run multiple consoles at once with this open source window environment)
|
||||
[#]: via: (https://opensource.com/article/20/1/multiple-consoles-twin)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用开源窗口环境 twin 一次运行多个控制台
|
||||
======
|
||||
|
||||
> 在我们的 20 个使用开源提升生产力的系列的第十四篇文章中用 twin 模拟了老式的 DESQview 体验。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/14/193658tlbyft0lbu44f0s3.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 通过 twin 克服“一个屏幕,一个应用程序”的限制
|
||||
|
||||
还有人记得 [DESQview][2] 吗?我们在 Windows、Linux 和 MacOS 中理所当然地可以在屏幕上同时运行多个程序,而 DESQview 赋予了 DOS 同样的功能。在我运营拨号 BBS 服务的初期,DESQview 是必需的,它使我能够让 BBS 在后台运行,同时在前台进行其他操作。例如,当有人拨打电话时,我可能正在开发新功能或设置新的外部程序而不会影响他们的体验。后来,在我早期做支持工作的时候,我可以同时运行我的工作电子邮件([MHS 上的 DaVinci 电子邮件][3])、支持单据系统和其他 DOS 程序。这是令人吃惊的!
|
||||
|
||||
![twin][4]
|
||||
|
||||
从那时起,运行多个控制台应用程序的功能已经发展了很多。但是 [tmux][5] 和 [Screen][6] 等应用仍然遵循“一个屏幕,一个应用”的显示方式。好吧,是的,tmux 具有屏幕拆分和窗格,但是不像 DESQview 那样具有将窗口“浮动”在其他窗口上的功能,就我个人而言,我怀念那个功能。
|
||||
|
||||
让我们来看看 [twin][7](文本模式窗口环境)。我认为,这个相对年轻的项目是 DESQview 的精神继任者。它支持控制台和图形环境,并具有与会话脱离和重新接驳的功能。设置起来并不是那么容易,但是它可以在大多数现代操作系统上运行。
|
||||
|
||||
Twin 是从源代码安装的(现在是这样)。但是首先,你需要安装所需的开发库。库名称将因操作系统而异。 以下示例显示了在我的 Ubuntu 19.10 系统中的情况。一旦安装了依赖库,请从 Git 中检出 twin 源代码,并运行 `./configure` 和 `make`,它们应自动检测所有内容并构建 twin:
|
||||
|
||||
```
|
||||
sudo apt install libx11-dev libxpm-dev libncurses-dev zlib1g-dev libgpm-dev
|
||||
git clone git@github.com:cosmos72/twin.git
|
||||
cd twin
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
注意:如果要在 MacOS 或 BSD 上进行编译,则需要在运行 `make` 之前在文件 `include/Tw/autoconf.h` 和 `include/twautoconf.h` 中注释掉 `#define socklen_t int`。这个问题应该在 [twin #57][9] 解决了。
|
||||
|
||||
![twin text mode][10]
|
||||
|
||||
第一次调用 twin 是一个挑战。你需要通过 `--hw` 参数告诉它正在使用哪种显示。例如,要启动文本模式的 twin,请输入 `twin --hw=tty,TERM=linux`。这里指定的 `TERM` 变量替代了你当前 Shell 中终端变量。要启动图形版本,运行 `twin --hw=X@$DISPLAY`。在 Linux 上,twin 一般都“可以正常工作”,而在 MacOS 上,Twin 基本是只能在终端上使用。
|
||||
|
||||
*真正*的乐趣是可以通过 `twattach` 和 `twdisplay` 命令接驳到正在运行的会话的功能。它们使你可以接驳到其他正在运行的 twin 会话。例如,在 Mac 上,我可以运行以下命令以接驳到演示机器上运行的 twin 会话:
|
||||
|
||||
```
|
||||
twdisplay --twin@20days2020.local:0 --hw=tty,TERM=linux
|
||||
```
|
||||
|
||||
![remote twin session][11]
|
||||
|
||||
通过多做一些工作,你还可以将其用作登录外壳,以代替控制台上的 [getty][12]。这需要 gdm 鼠标守护程序、twdm 应用程序(包括)和一些额外的配置。在使用 systemd 的系统上,首先安装并启用 gdm(如果尚未安装),然后使用 `systemctl` 为控制台(我使用 tty6)创建一个覆盖。这些命令必须以 root 用户身份运行;在 Ubuntu 上,它们看起来像这样:
|
||||
|
||||
```
|
||||
apt install gdm
|
||||
systemctl enable gdm
|
||||
systemctl start gdm
|
||||
systemctl edit getty@tty6
|
||||
```
|
||||
|
||||
`systemctl edit getty@tty6` 命令将打开一个名为 `override.conf` 的空文件。它可以定义 systemd 服务设置以覆盖 tty6 的默认设置。将内容更新为:
|
||||
|
||||
```
|
||||
[service]
|
||||
ExecStart=
|
||||
ExecStart=-/usr/local/sbin/twdm --hw=tty@/dev/tty6,TERM=linux
|
||||
StandardInput=tty
|
||||
StandardOutput=tty
|
||||
```
|
||||
|
||||
现在,重新加载 systemd 并重新启动 tty6 以获得 twin 登录提示界面:
|
||||
|
||||
```
|
||||
systemctl daemon-reload
|
||||
systemctl restart getty@tty6
|
||||
```
|
||||
|
||||
![twin][13]
|
||||
|
||||
这将为登录的用户启动一个 twin 会话。我不建议在多用户系统中使用此会话,但是对于个人桌面来说,这是很酷的。并且,通过使用 `twattach` 和 `twdisplay`,你可以从本地 GUI 或远程桌面访问该会话。
|
||||
|
||||
我认为 twin 真是太酷了。它还有一些细节不够完善,但是基本功能都已经有了,并且有一些非常好的文档。另外,它也使我可以在现代操作系统上稍解对 DESQview 式的体验的渴望。我希望随着时间的推移它会有所改进,希望你和我一样喜欢它。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/multiple-consoles-twin
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_web_internet_website.png?itok=g5B_Bw62 (Digital creative of a browser on the internet)
|
||||
[2]: https://en.wikipedia.org/wiki/DESQview
|
||||
[3]: https://en.wikipedia.org/wiki/Message_Handling_System
|
||||
[4]: https://opensource.com/sites/default/files/uploads/productivity_14-1.png (twin)
|
||||
[5]: https://github.com/tmux/tmux/wiki
|
||||
[6]: https://www.gnu.org/software/screen/
|
||||
[7]: https://github.com/cosmos72/twin
|
||||
[8]: mailto:git@github.com
|
||||
[9]: https://github.com/cosmos72/twin/issues/57
|
||||
[10]: https://opensource.com/sites/default/files/uploads/productivity_14-2.png (twin text mode)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/productivity_14-3.png (remote twin session)
|
||||
[12]: https://en.wikipedia.org/wiki/Getty_(Unix)
|
||||
[13]: https://opensource.com/sites/default/files/uploads/productivity_14-4.png (twin)
|
@ -0,0 +1,117 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11900-1.html)
|
||||
[#]: subject: (Use tmux to create the console of your dreams)
|
||||
[#]: via: (https://opensource.com/article/20/1/tmux-console)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 tmux 创建你的梦想主控台
|
||||
======
|
||||
|
||||
> 使用 tmux 可以做很多事情,尤其是在将 tmuxinator 添加到其中时。在我们的二十篇系列文章的第十五期中查看它们,以在 2020 年实现开源生产力的提高。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/16/220832bd4l1ag4tlqxlpr4.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 使用 tmux 和 tmuxinator 全部放到主控台上
|
||||
|
||||
到目前为止,在本系列文章中,我已经撰写了有关单个应用程序和工具的文章。从今天开始,我将把它们放在一起进行全面设置以简化操作。让我们从命令行开始。为什么使用命令行?简而言之,在命令行上工作可以使我能够从运行 SSH 的任何位置访问许多这些工具和功能。我可以 SSH 进入我的一台个人计算机,并在工作计算机上运行与我的个人计算机上所使用的相同设置。我要使用的主要工具是 [tmux][2]。
|
||||
|
||||
大多数人都只使用了 tmux 非常基础的功能,比如说在远程服务器上打开 tmux,然后启动进程,也许还会打开第二个会话以查看日志文件或调试信息,然后断开连接并在稍后返回。但是其实你可以使用 tmux 做很多工作。
|
||||
|
||||
![tmux][3]
|
||||
|
||||
首先,如果你有一个已有的 tmux 配置文件,请对其进行备份。tmux 的配置文件是 `~/.tmux.conf`。将其移动到另一个目录,例如 `~/tmp`。现在,用 Git 克隆 [Oh My Tmux][4] 项目。从该克隆目录中将 `.tmux.conf` 符号链接到你的家目录,并复制该克隆目录中的 `.tmux.conf.local` 文件到家目录中以进行调整:
|
||||
|
||||
```
|
||||
cd ~
|
||||
mkdir ~/tmp
|
||||
mv ~/.tmux.conf ~/tmp/
|
||||
git clone https://github.com/gpakosz/.tmux.git
|
||||
ln -s ~/.tmux/.tmux.conf ./
|
||||
cp ~/.tmux/.tmux.conf.local ./
|
||||
```
|
||||
|
||||
`.tmux.conf.local` 文件包含了本地设置和覆盖的设置。例如,我稍微更改了默认颜色,然后启用了 [Powerline][5] 分隔线。下面的代码段仅显示了我更改过的内容:
|
||||
|
||||
```
|
||||
tmux_conf_theme_24b_colour=true
|
||||
tmux_conf_theme_focused_pane_bg='default'
|
||||
tmux_conf_theme_pane_border_style=fat
|
||||
tmux_conf_theme_left_separator_main='\uE0B0'
|
||||
tmux_conf_theme_left_separator_sub='\uE0B1'
|
||||
tmux_conf_theme_right_separator_main='\uE0B2'
|
||||
tmux_conf_theme_right_separator_sub='\uE0B3'
|
||||
#tmux_conf_battery_bar_symbol_full='◼'
|
||||
#tmux_conf_battery_bar_symbol_empty='◻'
|
||||
tmux_conf_battery_bar_symbol_full='♥'
|
||||
tmux_conf_battery_bar_symbol_empty='·'
|
||||
tmux_conf_copy_to_os_clipboard=true
|
||||
set -g mouse on
|
||||
```
|
||||
|
||||
请注意,你不需要安装 Powerline,你只需要支持 Powerline 符号的字体即可。我在与控制台相关的所有内容中几乎都使用 [Hack Nerd Font][6],因为它易于阅读并且具有许多有用的额外符号。你还会注意到,我打开了操作系统剪贴板支持和鼠标支持。
|
||||
|
||||
现在,当 tmux 启动时,底部的状态栏会以吸引人的颜色提供更多信息。`Ctrl` + `b` 仍然是输入命令的 “引导” 键,但其他一些进行了更改。现在水平拆分(顶部/底部)窗格为 `Ctrl` + `b` + `-`,垂直拆分为 `Ctrl` + `b` + `_`。启用鼠标模式后,你可以单击以在窗格之间切换,并拖动分隔线以调整其大小。打开新窗口仍然是 `Ctrl` + `b` + `n`,你现在可以单击底部栏上的窗口名称在它们之间进行切换。同样,`Ctrl` + `b` + `e` 将打开 `.tmux.conf.local` 文件以进行编辑。退出编辑器时,tmux 将重新加载配置,而不会重新加载其他任何内容。这很有用。
|
||||
|
||||
到目前为止,我仅对功能和视觉显示进行了一些简单的更改,并增加了鼠标支持。现在,我将它设置为以一种有意义的方式启动我想要的应用程序,而不必每次都重新定位和调整它们的大小。为此,我将使用 [tmuxinator][7]。tmuxinator 是 tmux 的启动器,它允许你指定和管理布局以及使用 YAML 文件自动启动应用程序。要使用它,请启动 tmux 并创建要在其中运行程序的窗格。然后,使用 `Ctrl` + `b` + `n` 打开一个新窗口,并执行 `tmux list-windows`。你将获得有关布局的详细信息。
|
||||
|
||||
![tmux layout information][8]
|
||||
|
||||
请注意上面代码中的第一行,我在其中设置了四个窗格,每个窗格中都有一个应用程序。保存运行时的输出以供以后使用。现在,运行 `tmuxinator new 20days` 以创建名为 “20days” 的布局。这将显示一个带有默认布局文件的文本编辑器。它包含很多有用的内容,我建议你阅读所有选项。首先输入上方的布局信息以及所需的应用程序:
|
||||
|
||||
```
|
||||
# /Users/ksonney/.config/tmuxinator/20days.yml
|
||||
name: 20days
|
||||
root: ~/
|
||||
windows:
|
||||
- mail:
|
||||
layout: d9da,208x60,0,0[208x26,0,0{104x26,0,0,0,103x26,105,0,5},208x33,0,27{104x33,0,27,1,103x33,105,27,4}]] @0
|
||||
panes:
|
||||
- alot
|
||||
- abook
|
||||
- ikhal
|
||||
- todo.sh ls +20days
|
||||
```
|
||||
|
||||
注意空格缩进!与 Python 代码一样,空格和缩进关系到文件的解释方式。保存该文件,然后运行 `tmuxinator 20days`。你应该会得到四个窗格,分别是 [alot][9] 邮件程序、[abook][10]、ikhal(交互式 [khal][11] 的快捷方式)以及 [todo.txt][12] 中带有 “+20days” 标签的任何内容。
|
||||
|
||||
![sample layout launched by tmuxinator][13]
|
||||
|
||||
你还会注意到,底部栏上的窗口标记为 “Mail”。你可以单击该名称(以及其他命名的窗口)以跳到该视图。漂亮吧?我在同一个文件中还设置了名为 “Social” 的第二个窗口,包括 [Tuir][14]、[Newsboat][15]、连接到 [BitlBee][16] 的 IRC 客户端和 [Rainbow Stream][17]。
|
||||
|
||||
tmux 是我跟踪所有事情的生产力动力之源,有了 tmuxinator,我不必在不断调整大小、放置和启动我的应用程序上费心。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/tmux-console
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coffee_tea_laptop_computer_work_desk.png?itok=D5yMx_Dr (Person drinking a hat drink at the computer)
|
||||
[2]: https://github.com/tmux/tmux
|
||||
[3]: https://opensource.com/sites/default/files/uploads/productivity_15-1.png (tumux)
|
||||
[4]: https://github.com/gpakosz/.tmux
|
||||
[5]: https://github.com/powerline/powerline
|
||||
[6]: https://www.nerdfonts.com/
|
||||
[7]: https://github.com/tmuxinator/tmuxinator
|
||||
[8]: https://opensource.com/sites/default/files/uploads/productivity_15-2.png (tmux layout information)
|
||||
[9]: https://opensource.com/article/20/1/organize-email-notmuch
|
||||
[10]: https://opensource.com/article/20/1/sync-contacts-locally
|
||||
[11]: https://opensource.com/article/20/1/open-source-calendar
|
||||
[12]: https://opensource.com/article/20/1/open-source-to-do-list
|
||||
[13]: https://opensource.com/sites/default/files/uploads/productivity_15-3.png (sample layout launched by tmuxinator)
|
||||
[14]: https://opensource.com/article/20/1/open-source-reddit-client
|
||||
[15]: https://opensource.com/article/20/1/open-source-rss-feed-reader
|
||||
[16]: https://opensource.com/article/20/1/open-source-chat-tool
|
||||
[17]: https://opensource.com/article/20/1/tweet-terminal-rainbow-stream
|
@ -0,0 +1,113 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11908-1.html)
|
||||
[#]: subject: (Use Vim to send email and check your calendar)
|
||||
[#]: via: (https://opensource.com/article/20/1/vim-email-calendar)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 Vim 发送邮件和检查日历
|
||||
======
|
||||
|
||||
> 在 2020 年用开源实现更高生产力的二十种方式的第十六篇文章中,直接通过文本编辑器管理你的电子邮件和日历。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/19/185842eyz2znxx1yc2ctnc.jpg)
|
||||
|
||||
去年,我在 19 天里给你介绍了 19 个新(对你而言)的生产力工具。今年,我换了一种方式:使用你在使用或者还没使用的工具,构建一个使你可以在新一年更加高效的环境。
|
||||
|
||||
### 用 Vim 做(几乎)所有事情,第一部分
|
||||
|
||||
我经常使用两个文本编辑器 —— [Vim][2] 和 [Emacs][3]。为什么两者都用呢?它们有不同的使用场景,在本系列的后续几篇文章中,我将讨论其中的一些用例。
|
||||
|
||||
![][4]
|
||||
|
||||
好吧,为什么要在 Vim 中执行所有操作?因为如果有一个应用程序是我可以访问的每台计算机上都有的,那就是 Vim。如果你像我一样,可能已经在 Vim 中打发了很多时光。那么,为什么不将其用于**所有事情**呢?
|
||||
|
||||
但是,在此之前,你需要做一些事情。首先是确保你的 Vim 具有 Ruby 支持。你可以使用 `vim --version | grep ruby`。如果结果不是 `+ruby`,则需要解决这个问题。这可能有点麻烦,你应该查看发行版的文档以获取正确的软件包。在 MacOS 上,用的是官方的 MacVim(不是 Brew 发行的),在大多数 Linux 发行版中,用的是 vim-nox 或 vim-gtk,而不是 vim-gtk3。
|
||||
|
||||
我使用 [Pathogen][5] 自动加载插件和捆绑软件。如果你使用 [Vundle][6] 或其他 Vim 软件包管理器,则需要调整以下命令才能使用它。
|
||||
|
||||
#### 在 Vim 中管理你的邮件
|
||||
|
||||
使 Vim 在你的生产力计划中发挥更大作用的一个很好的起点是使用它通过 [Notmuch] [7] 发送和接收电子邮件,和使用 [abook] [8] 访问你的联系人列表。你需要为此安装一些东西。下面的所有示例代码都运行在 Ubuntu 上,因此如果你使用其他发行版,则需要对此进行调整。通过以下步骤进行设置:
|
||||
|
||||
```
|
||||
sudo apt install notmuch-vim ruby-mail
|
||||
curl -o ~/.vim/plugin/abook --create-dirs https://raw.githubusercontent.com/dcbaker/vim-abook/master/plugin/abook.vim
|
||||
```
|
||||
|
||||
到目前为止,一切都很顺利。现在启动 Vim 并执行 `:NotMuch`。由于是用较旧版本的邮件库 `notmuch-vim` 编写的,可能会出现一些警告,但总的来说,Vim 现在将成为功能齐全的 Notmuch 邮件客户端。
|
||||
|
||||
![Reading Mail in Vim][9]
|
||||
|
||||
如果要搜索特定标签,请输入 `\t`,输入标签名称,然后按回车。这将拉出一个带有该标签的所有消息的列表。`\s` 组合键会弹出 `Search:` 提示符,可以对 Notmuch 数据库进行全面搜索。使用箭头键浏览消息列表,按回车键显示所选项目,然后输入 `\q` 退出当前视图。
|
||||
|
||||
要撰写邮件,请使用 `\c` 按键。你将看到一条空白消息。这是 `abook.vim` 插件发挥作用的位置。按下 `Esc` 并输入 `:AbookQuery <SomeName>`,其中 `<SomeName>` 是你要查找的名称或电子邮件地址的一部分。你将在 abook 数据库中找到与你的搜索匹配的条目列表。通过键入你想要的地址的编号,将其添加到电子邮件的地址行中。完成电子邮件的键入和编辑,按 `Esc` 退出编辑模式,然后输入 `,s` 发送。
|
||||
|
||||
如果要在 `:NotMuch` 启动时更改默认文件夹视图,则可以将变量 `g:notmuch_folders` 添加到你的 `.vimrc` 文件中:
|
||||
|
||||
```
|
||||
let g:notmuch_folders = [
|
||||
\ [ 'new', 'tag:inbox and tag:unread' ],
|
||||
\ [ 'inbox', 'tag:inbox' ],
|
||||
\ [ 'unread', 'tag:unread' ],
|
||||
\ [ 'News', 'tag:@sanenews' ],
|
||||
\ [ 'Later', 'tag:@sanelater' ],
|
||||
\ [ 'Patreon', 'tag:@patreon' ],
|
||||
\ [ 'LivestockConservancy', 'tag:livestock-conservancy' ],
|
||||
\ ]
|
||||
```
|
||||
|
||||
Notmuch 插件的文档中涵盖了更多设置,包括设置标签键和使用其它的邮件程序。
|
||||
|
||||
#### 在 Vim 中查询日历
|
||||
|
||||
![][10]
|
||||
|
||||
遗憾的是,似乎没有使用 vCalendar 或 iCalendar 格式的 Vim 日历程序。有个 [Calendar.vim][11],做得很好。设置 Vim 通过以下方式访问你的日历:
|
||||
|
||||
```
|
||||
cd ~/.vim/bundle
|
||||
git clone git@github.com:itchyny/calendar.vim.git
|
||||
```
|
||||
|
||||
现在,你可以通过输入 `:Calendar` 在 Vim 中查看日历。你可以使用 `<` 和 `>` 键在年、月、周、日和时钟视图之间切换。如果要从一个特定的视图开始,请使用 `-view=` 标志告诉它你希望看到哪个视图。你也可以在任何视图中定位日期。例如,如果我想查看 2020 年 7 月 4 日这一周的情况,请输入 `:Calendar -view week 7 4 2020`。它的帮助信息非常好,可以使用 `?` 键参看。
|
||||
|
||||
![][13]
|
||||
|
||||
Calendar.vim 还支持 Google Calendar(我需要),但是在 2019 年 12 月,Google 禁用了它的访问权限。作者已在 [GitHub 上的这个提案][14]中发布了一种变通方法。
|
||||
|
||||
这样你就在 Vim 中有了这些:你的邮件、地址簿和日历。但是这些还没有完成; 下一篇你将在 Vim 上做更多的事情!
|
||||
|
||||
Vim 为作家提供了很多好处,无论他们是否具有技术意识。
|
||||
|
||||
需要保持时间表正确吗?了解如何使用这些免费的开源软件来做到这一点。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/vim-email-calendar
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/calendar.jpg?itok=jEKbhvDT (Calendar close up snapshot)
|
||||
[2]: https://www.vim.org/
|
||||
[3]: https://www.gnu.org/software/emacs/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/day16-image1.png
|
||||
[5]: https://github.com/tpope/vim-pathogen
|
||||
[6]: https://github.com/VundleVim/Vundle.vim
|
||||
[7]: https://opensource.com/article/20/1/organize-email-notmuch
|
||||
[8]: https://opensource.com/article/20/1/sync-contacts-locally
|
||||
[9]: https://opensource.com/sites/default/files/uploads/productivity_16-2.png (Reading Mail in Vim)
|
||||
[10]: https://opensource.com/sites/default/files/uploads/day16-image3.png
|
||||
[11]: https://github.com/itchyny/calendar.vim
|
||||
[12]: mailto:git@github.com
|
||||
[13]: https://opensource.com/sites/default/files/uploads/day16-image4.png
|
||||
[14]: https://github.com/itchyny/calendar.vim/issues/156
|
@ -0,0 +1,56 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (LazyWolfLin)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11867-1.html)
|
||||
[#]: subject: (What's your favorite Linux distribution?)
|
||||
[#]: via: (https://opensource.com/article/20/1/favorite-linux-distribution)
|
||||
[#]: author: (Opensource.com https://opensource.com/users/admin)
|
||||
|
||||
你最喜欢哪个 Linux 发行版?
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/08/004438ei1y4pp44pw4xy3w.jpg)
|
||||
|
||||
你最喜欢哪个 Linux 发行版?虽然有所变化,但现在仍有数百种 [Linux 发行版][2]保持活跃且运作良好。发行版、包管理器和桌面的组合为 Linux 用户创建了无数客制化系统环境。
|
||||
|
||||
我们询问了社区的作者们,哪个是他们的最爱以及原因。尽管回答中存在一些共性(由于各种原因,Fedora 和 Ubuntu 是最受欢迎的选择),但我们也听到一些惊奇的回答。以下是他们的一些回答:
|
||||
|
||||
> “我使用 Fedora 发行版!我喜欢这样的社区,成员们共同创建一个令人惊叹的操作系统,展现了开源软件世界最伟大的造物。”——Matthew Miller
|
||||
|
||||
> “我在家中使用 Arch。作为一名游戏玩家,我希望可以轻松使用最新版本的 Wine 和 GFX 驱动,同时最大限度地掌控我的系统。所以我选择一个滚动升级并且每个包都保持领先的发行版。”——Aimi Hobson
|
||||
|
||||
> “NixOS,在业余爱好者市场中没有比这更合适的。”——Alexander Sosedkin
|
||||
|
||||
> “我用过每个 Fedora 版本作为我的工作系统。这意味着我从第一个版本开始使用。从前,我问自己是否会忘记我使用的是哪一个版本。而这一天已经到来了,是从什么时候开始忘记了的呢?”——Hugh Brock
|
||||
|
||||
> “通常,在我的家里和办公室里都有运行 Ubuntu、CentOS 和 Fedora 的机器。我依赖这些发行版来完成各种工作。Fedora 速度很快,而且可以获取最新版本的应用和库。Ubuntu 有大型社区支持,可以轻松使用。CentOS 则当我们需要稳如磐石的服务器平台时。”——Steve Morris
|
||||
|
||||
> “我最喜欢?对于社区以及如何为发行版构建软件包(从源码构建而非二进制文件),我选择 Fedora。对于可用包的范围和包的定义和开发,我选择 Debian。对于文档,我选择 Arch。对于新手的提问,我以前会推荐 Ubuntu,而现在会推荐 Fedora。”——Al Stone
|
||||
|
||||
* * *
|
||||
|
||||
自从 2014 以来,我们一直向社区提出这一问题。除了 2015 年 PCLinuxOS 出乎意料的领先,Ubuntu 往往每年都获得粉丝们的青睐。其他受欢迎的竞争者还包括 Fedora、Debian、Mint 和 Arch。在新的十年里,哪个发行版更吸引你?如果我们的投票列表中没有你最喜欢的选择,请在评论中告诉我们。
|
||||
|
||||
下面是过去七年来你最喜欢的 Linux 发行版投票的总览。你可以在我们去年的年刊《[Opensource.com 上的十年最佳][3]》中看到它。[点击这里][3]下载完整版电子书!
|
||||
|
||||
![Poll results for favorite Linux distribution through the years][4]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/1/favorite-linux-distribution
|
||||
|
||||
作者:[Opensource.com][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[LazyWolfLin](https://github.com/LazyWolfLin)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/admin
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/yearbook-haff-rx-linux-file-lead_0.png?itok=-i0NNfDC (Hand putting a Linux file folder into a drawer)
|
||||
[2]: https://distrowatch.com/
|
||||
[3]: https://opensource.com/downloads/2019-yearbook-special-edition
|
||||
[4]: https://opensource.com/sites/default/files/pictures/linux-distributions-through-the-years.jpg (favorite Linux distribution through the years)
|
||||
[5]: https://opensource.com/article/20/1/favorite-linux-distribution
|
@ -0,0 +1,101 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11863-1.html)
|
||||
[#]: subject: (4 cool new projects to try in COPR for January 2020)
|
||||
[#]: via: (https://fedoramagazine.org/4-cool-new-projects-to-try-in-copr-for-january-2020/)
|
||||
[#]: author: (Dominik Turecek https://fedoramagazine.org/author/dturecek/)
|
||||
|
||||
COPR 仓库中 4 个很酷的新项目(2020.01)
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
COPR 是个人软件仓库[集合][2],它不在 Fedora 中。这是因为某些软件不符合轻松打包的标准;或者它可能不符合其他 Fedora 标准,尽管它是自由而开源的。COPR 可以在 Fedora 套件之外提供这些项目。COPR 中的软件不受 Fedora 基础设施的支持,或者是由项目自己背书的。但是,这是一种尝试新的或实验性的软件的一种巧妙的方式。
|
||||
|
||||
本文介绍了 COPR 中一些有趣的新项目。如果你第一次使用 COPR,请参阅 [COPR 用户文档][3]。
|
||||
|
||||
### Contrast
|
||||
|
||||
[Contrast][4] 是一款小应用,用于检查两种颜色之间的对比度并确定其是否满足 [WCAG][5] 中指定的要求。可以使用十六进制 RGB 代码或使用颜色选择器选择颜色。除了显示对比度之外,Contrast 还以选定的颜色为背景上显示短文本来显示比较。
|
||||
|
||||
![][6]
|
||||
|
||||
#### 安装说明
|
||||
|
||||
[仓库][7]当前为 Fedora 31 和 Rawhide 提供了 Contrast。要安装 Contrast,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable atim/contrast
|
||||
sudo dnf install contrast
|
||||
```
|
||||
|
||||
### Pamixer
|
||||
|
||||
[Pamixer][8] 是一个使用 PulseAudio 调整和监控声音设备音量的命令行工具。你可以显示设备的当前音量并直接增加/减小它,或静音/取消静音。Pamixer 可以列出所有源和接收器。
|
||||
|
||||
#### 安装说明
|
||||
|
||||
[仓库][7]当前为 Fedora 31 和 Rawhide 提供了 Pamixer。要安装 Pamixer,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable opuk/pamixer
|
||||
sudo dnf install pamixer
|
||||
```
|
||||
|
||||
### PhotoFlare
|
||||
|
||||
[PhotoFlare][10] 是一款图像编辑器。它有简单且布局合理的用户界面,其中的大多数功能都可在工具栏中使用。尽管它不支持使用图层,但 PhotoFlare 提供了诸如各种颜色调整、图像变换、滤镜、画笔和自动裁剪等功能。此外,PhotoFlare 可以批量编辑图片,来对所有图片应用相同的滤镜和转换,并将结果保存在指定目录中。
|
||||
|
||||
![][11]
|
||||
|
||||
#### 安装说明
|
||||
|
||||
[仓库][7]当前为 Fedora 31 提供了 PhotoFlare。要安装 PhotoFlare,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable adriend/photoflare
|
||||
sudo dnf install photoflare
|
||||
```
|
||||
|
||||
### Tdiff
|
||||
|
||||
[Tdiff][13] 是用于比较两个文件树的命令行工具。除了显示某些文件或目录仅存在于一棵树中之外,tdiff 还显示文件大小、类型和内容,所有者用户和组 ID、权限、修改时间等方面的差异。
|
||||
|
||||
#### 安装说明
|
||||
|
||||
[仓库][7]当前为 Fedora 29-31、Rawhide、EPEL 6-8 和其他发行版提供了 tdiff。要安装 tdiff,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable fif/tdiff
|
||||
sudo dnf install tdiff
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/4-cool-new-projects-to-try-in-copr-for-january-2020/
|
||||
|
||||
作者:[Dominik Turecek][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/dturecek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2017/08/4-copr-945x400.jpg
|
||||
[2]: https://copr.fedorainfracloud.org/
|
||||
[3]: https://docs.pagure.org/copr.copr/user_documentation.html#
|
||||
[4]: https://gitlab.gnome.org/World/design/contrast
|
||||
[5]: https://www.w3.org/WAI/standards-guidelines/wcag/
|
||||
[6]: https://fedoramagazine.org/wp-content/uploads/2020/01/contrast-screenshot.png
|
||||
[7]: https://copr.fedorainfracloud.org/coprs/atim/contrast/
|
||||
[8]: https://github.com/cdemoulins/pamixer
|
||||
[9]: https://copr.fedorainfracloud.org/coprs/opuk/pamixer/
|
||||
[10]: https://photoflare.io/
|
||||
[11]: https://fedoramagazine.org/wp-content/uploads/2020/01/photoflare-screenshot.png
|
||||
[12]: https://copr.fedorainfracloud.org/coprs/adriend/photoflare/
|
||||
[13]: https://github.com/F-i-f/tdiff
|
||||
[14]: https://copr.fedorainfracloud.org/coprs/fif/tdiff/
|
@ -0,0 +1,113 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11896-1.html)
|
||||
[#]: subject: (Joplin: The True Open Source Evernote Alternative)
|
||||
[#]: via: (https://itsfoss.com/joplin/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
Joplin:真正的 Evernote 开源替代品
|
||||
======
|
||||
|
||||
> Joplin 是一个开源笔记记录和待办应用。你可以将笔记组织到笔记本中并标记它们。Joplin 还提供网络剪贴板来保存来自互联网的文章。
|
||||
|
||||
### Joplin:开源笔记管理器
|
||||
|
||||
![][4]
|
||||
|
||||
如果你喜欢 [Evernote][2],那么你不会不太适应这个开源软件 [Joplin][3]。
|
||||
|
||||
Joplin 是一个优秀的开源笔记应用,拥有丰富的功能。你可以记笔记、记录待办事项并且通过和 Dropbox 和 NextCloud 等云服务链接来跨设备同步笔记。同步过程通过端到端加密保护。
|
||||
|
||||
Joplin 还有一个 Web 剪贴板,能让你将网页另存为笔记。这个网络剪贴板可用于 Firefox 和 Chrome/Chromium 浏览器。
|
||||
|
||||
Joplin 可以导入 enex 格式的 Evernote 文件,这让从 Evernote 切换变得容易。
|
||||
|
||||
因为数据自行保存,所以你可以用 Joplin 格式或者原始格式导出所有文件。
|
||||
|
||||
### Joplin 的功能
|
||||
|
||||
![][1]
|
||||
|
||||
以下是 Joplin 的所有功能列表:
|
||||
|
||||
* 将笔记保存到笔记本和子笔记本中,以便更好地组织
|
||||
* 创建待办事项清单
|
||||
* 可以标记和搜索笔记
|
||||
* 离线优先,因此即使没有互联网连接,所有数据始终在设备上可用
|
||||
* Markdown 笔记支持图片、数学符号和复选框
|
||||
* 支持附件
|
||||
* 可在桌面、移动设备和终端(CLI)使用
|
||||
* 可在 Firefox 和 Chrome 使用[网页剪切板][5]
|
||||
* 端到端加密
|
||||
* 保留笔记历史
|
||||
* 根据名称、时间等对笔记进行排序
|
||||
* 可与 [Nextcloud][7]、Dropbox、WebDAV 和 OneDrive 等各种[云服务][6]同步
|
||||
* 从 Evernote 导入文件
|
||||
* 导出 JEX 文件(Joplin 导出格式)和原始文件
|
||||
* 支持笔记、待办事项、标签和笔记本
|
||||
* 任意跳转功能
|
||||
* 支持移动设备和桌面应用通知
|
||||
* 地理位置支持
|
||||
* 支持多种语言
|
||||
* 外部编辑器支持:在 Joplin 中一键用你最喜欢的编辑器打开笔记
|
||||
|
||||
### 在 Linux 和其它平台上安装 Joplin
|
||||
|
||||
![][10]
|
||||
|
||||
[Joplin][11] 是一个跨平台应用,可用于 Linux、macOS 和 Windows。在移动设备上,你可以[获取 APK 文件][12]将其安装在 Android 和基于 Android 的 ROM 上。你也可以[从谷歌 Play 商店下载][13]。
|
||||
|
||||
在 Linux 中,你可以获取 Joplin 的 [AppImage][14] 文件,并作为可执行文件运行。你需要为下载的文件授予执行权限。
|
||||
|
||||
- [下载 Joplin][15]
|
||||
|
||||
### 体验 Joplin
|
||||
|
||||
Joplin 中的笔记使用 Markdown,但你不需要了解它。编辑器的顶部面板能让你以图形方式选择项目符号、标题、图像、链接等。
|
||||
|
||||
虽然 Joplin 提供了许多有趣的功能,但你需要自己去尝试。例如,默认情况下未启用 Web 剪切板,我需要发现如何打开它。
|
||||
|
||||
你需要从桌面应用启用剪切板。在顶部菜单中,进入 “Tools->Options”。你可以在此处找到 Web 剪切板选项:
|
||||
|
||||
![Enable Web Clipper from the desktop application first][16]
|
||||
|
||||
它的 Web 剪切板不如 Evernote 的 Web 剪切板聪明,后者可以以图形方式剪辑网页文章的一部分。但是,也足够了。
|
||||
|
||||
这是一个在活跃开发中的开源软件,我希望它随着时间的推移得到更多的改进。
|
||||
|
||||
### 总结
|
||||
|
||||
如果你正在寻找一个不错的拥有 Web 剪切板的笔记应用,你可以试试 Joplin。如果你喜欢它,并将继续使用,尝试通过捐赠或改进代码和文档来帮助 Joplin 开发。我以 FOSS 的名义[捐赠][17]了 25 欧。
|
||||
|
||||
如果你曾经使用过 Joplin,或者仍在使用它,你对此的体验如何?如果你用的是其他笔记应用,你会切换到 Joplin 么?欢迎分享你的观点。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/joplin/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_logo.png?ssl=1
|
||||
[2]: https://evernote.com/
|
||||
[3]: https://joplinapp.org/
|
||||
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_featured.jpg?ssl=1
|
||||
[5]: https://joplinapp.org/clipper/
|
||||
[6]: https://itsfoss.com/cloud-services-linux/
|
||||
[7]: https://nextcloud.com/
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_ubuntu.jpg?ssl=1
|
||||
[11]: https://github.com/laurent22/joplin
|
||||
[12]: https://itsfoss.com/download-apk-ubuntu/
|
||||
[13]: https://play.google.com/store/apps/details?id=net.cozic.joplin&hl=en_US
|
||||
[14]: https://itsfoss.com/use-appimage-linux/
|
||||
[15]: https://github.com/laurent22/joplin/releases
|
||||
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/joplin_web_clipper.jpg?ssl=1
|
||||
[17]: https://itsfoss.com/donations-foss/
|
@ -0,0 +1,189 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11849-1.html)
|
||||
[#]: subject: (Showing memory usage in Linux by process and user)
|
||||
[#]: via: (https://www.networkworld.com/article/3516319/showing-memory-usage-in-linux-by-process-and-user.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
查看 Linux 系统中进程和用户的内存使用情况
|
||||
======
|
||||
|
||||
> 有一些命令可以用来检查 Linux 系统中的内存使用情况,下面是一些更好的命令。
|
||||
|
||||
![Fancycrave][1]
|
||||
|
||||
有许多工具可以查看 Linux 系统中的内存使用情况。一些命令被广泛使用,比如 `free`、`ps`。而另一些命令允许通过多种方式展示系统的性能统计信息,比如 `top`。在这篇文章中,我们将介绍一些命令以帮助你确定当前占用着最多内存资源的用户或者进程。
|
||||
|
||||
下面是一些按照进程查看内存使用情况的命令:
|
||||
|
||||
### 按照进程查看内存使用情况
|
||||
|
||||
#### 使用 top
|
||||
|
||||
`top` 是最好的查看内存使用情况的命令之一。为了查看哪个进程使用着最多的内存,一个简单的办法就是启动 `top`,然后按下 `shift+m`,这样便可以查看按照内存占用百分比从高到底排列的进程。当你按下了 `shift+m` ,你的 `top` 应该会得到类似于下面这样的输出结果:
|
||||
|
||||
```
|
||||
$top
|
||||
top - 09:39:34 up 5 days, 3 min, 3 users, load average: 4.77, 4.43, 3.72
|
||||
Tasks: 251 total, 3 running, 247 sleeping, 1 stopped, 0 zombie
|
||||
%Cpu(s): 50.6 us, 35.9 sy, 0.0 ni, 13.4 id, 0.2 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
MiB Mem : 5944.4 total, 128.9 free, 2509.3 used, 3306.2 buff/cache
|
||||
MiB Swap: 2048.0 total, 2045.7 free, 2.2 used. 3053.5 avail Mem
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
400 nemo 20 0 3309580 550188 168372 S 0.3 9.0 1:33.27 Web Content
|
||||
32469 nemo 20 0 3492840 447372 163296 S 7.3 7.3 3:55.60 firefox
|
||||
32542 nemo 20 0 2845732 433388 140984 S 6.0 7.1 4:11.16 Web Content
|
||||
342 nemo 20 0 2848520 352288 118972 S 10.3 5.8 4:04.89 Web Content
|
||||
2389 nemo 20 0 1774412 236700 90044 S 39.7 3.9 9:32.64 vlc
|
||||
29527 nemo 20 0 2735792 225980 84744 S 9.6 3.7 3:02.35 gnome-shell
|
||||
30497 nemo 30 10 1088476 159636 88884 S 0.0 2.6 0:11.99 update-manager
|
||||
30058 nemo 20 0 1089464 140952 33128 S 0.0 2.3 0:04.58 gnome-software
|
||||
32533 nemo 20 0 2389088 104712 79544 S 0.0 1.7 0:01.43 WebExtensions
|
||||
2256 nemo 20 0 1217884 103424 31304 T 0.0 1.7 0:00.28 vlc
|
||||
1713 nemo 20 0 2374396 79588 61452 S 0.0 1.3 0:00.49 Web Content
|
||||
29306 nemo 20 0 389668 74376 54340 S 2.3 1.2 0:57.25 Xorg
|
||||
32739 nemo 20 0 289528 58900 34480 S 1.0 1.0 1:04.08 RDD Process
|
||||
29732 nemo 20 0 789196 57724 42428 S 0.0 0.9 0:00.38 evolution-alarm
|
||||
2373 root 20 0 150408 57000 9924 S 0.3 0.9 10:15.35 nessusd
|
||||
```
|
||||
|
||||
注意 `%MEM` 排序。列表的大小取决于你的窗口大小,但是占据着最多的内存的进程将会显示在列表的顶端。
|
||||
|
||||
#### 使用 ps
|
||||
|
||||
`ps` 命令中的一列用来展示每个进程的内存使用情况。为了展示和查看哪个进程使用着最多的内存,你可以将 `ps` 命令的结果传递给 `sort` 命令。下面是一个有用的示例:
|
||||
|
||||
```
|
||||
$ ps aux | sort -rnk 4 | head -5
|
||||
nemo 400 3.4 9.2 3309580 563336 ? Sl 08:59 1:36 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -prefsLen 9086 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 32469 8.2 7.7 3492840 469516 ? Sl 08:54 4:15 /usr/lib/firefox/firefox -new-window
|
||||
nemo 32542 8.9 7.6 2875428 462720 ? Sl 08:55 4:36 /usr/lib/firefox/firefox -contentproc -childID 2 -isForBrowser -prefsLen 1 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 342 9.9 5.9 2854664 363528 ? Sl 08:59 4:44 /usr/lib/firefox/firefox -contentproc -childID 5 -isForBrowser -prefsLen 8763 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 2389 39.5 3.8 1774412 236116 pts/1 Sl+ 09:15 12:21 vlc videos/edge_computing.mp4
|
||||
```
|
||||
|
||||
在上面的例子中(文中已截断),`sort` 命令使用了 `-r` 选项(反转)、`-n` 选项(数字值)、`-k` 选项(关键字),使 `sort` 命令对 `ps` 命令的结果按照第四列(内存使用情况)中的数字逆序进行排列并输出。如果我们首先显示 `ps` 命令的标题,那么将会便于查看。
|
||||
|
||||
```
|
||||
$ ps aux | head -1; ps aux | sort -rnk 4 | head -5
|
||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
||||
nemo 400 3.4 9.2 3309580 563336 ? Sl 08:59 1:36 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -prefsLen 9086 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 32469 8.2 7.7 3492840 469516 ? Sl 08:54 4:15 /usr/lib/firefox/firefox -new-window
|
||||
nemo 32542 8.9 7.6 2875428 462720 ? Sl 08:55 4:36 /usr/lib/firefox/firefox -contentproc -childID 2 -isForBrowser -prefsLen 1 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 342 9.9 5.9 2854664 363528 ? Sl 08:59 4:44 /usr/lib/firefox/firefox -contentproc -childID 5 -isForBrowser -prefsLen 8763 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 2389 39.5 3.8 1774412 236116 pts/1 Sl+ 09:15 12:21 vlc videos/edge_computing.mp4
|
||||
```
|
||||
|
||||
如果你喜欢这个命令,你可以用下面的命令为他指定一个别名,如果你想一直使用它,不要忘记把该命令添加到你的 `~/.bashrc` 文件中。
|
||||
|
||||
```
|
||||
$ alias mem-by-proc="ps aux | head -1; ps aux | sort -rnk 4"
|
||||
```
|
||||
|
||||
下面是一些根据用户查看内存使用情况的命令:
|
||||
|
||||
### 按用户查看内存使用情况
|
||||
|
||||
#### 使用 top
|
||||
|
||||
按照用户检查内存使用情况会更复杂一些,因为你需要找到一种方法把用户所拥有的所有进程统计为单一的内存使用量。
|
||||
|
||||
如果你只想查看单个用户进程使用情况,`top` 命令可以采用与上文中同样的方法进行使用。只需要添加 `-U` 选项并在其后面指定你要查看的用户名,然后按下 `shift+m` 便可以按照内存使用有多到少进行查看。
|
||||
|
||||
```
|
||||
$ top -U nemo
|
||||
top - 10:16:33 up 5 days, 40 min, 3 users, load average: 1.91, 1.82, 2.15
|
||||
Tasks: 253 total, 2 running, 250 sleeping, 1 stopped, 0 zombie
|
||||
%Cpu(s): 28.5 us, 36.8 sy, 0.0 ni, 34.4 id, 0.3 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
MiB Mem : 5944.4 total, 224.1 free, 2752.9 used, 2967.4 buff/cache
|
||||
MiB Swap: 2048.0 total, 2042.7 free, 5.2 used. 2812.0 avail Mem
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
400 nemo 20 0 3315724 623748 165440 S 1.0 10.2 1:48.78 Web Content
|
||||
32469 nemo 20 0 3629380 607492 161688 S 2.3 10.0 6:06.89 firefox
|
||||
32542 nemo 20 0 2886700 404980 136648 S 5.6 6.7 6:50.01 Web Content
|
||||
342 nemo 20 0 2922248 375784 116096 S 19.5 6.2 8:16.07 Web Content
|
||||
2389 nemo 20 0 1762960 234644 87452 S 0.0 3.9 13:57.53 vlc
|
||||
29527 nemo 20 0 2736924 227260 86092 S 0.0 3.7 4:09.11 gnome-shell
|
||||
30497 nemo 30 10 1088476 156372 85620 S 0.0 2.6 0:11.99 update-manager
|
||||
30058 nemo 20 0 1089464 138160 30336 S 0.0 2.3 0:04.62 gnome-software
|
||||
32533 nemo 20 0 2389088 102532 76808 S 0.0 1.7 0:01.79 WebExtensions
|
||||
```
|
||||
|
||||
#### 使用 ps
|
||||
|
||||
你依旧可以使用 `ps` 命令通过内存使用情况来排列某个用户的进程。在这个例子中,我们将使用 `grep` 命令来筛选得到某个用户的所有进程。
|
||||
|
||||
```
|
||||
$ ps aux | head -1; ps aux | grep ^nemo| sort -rnk 4 | more
|
||||
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
||||
nemo 32469 7.1 11.5 3724364 701388 ? Sl 08:54 7:21 /usr/lib/firefox/firefox -new-window
|
||||
nemo 400 2.0 8.9 3308556 543232 ? Sl 08:59 2:01 /usr/lib/firefox/firefox -contentproc -childID 6 -isForBrowser -prefsLen 9086 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni/usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 32542 7.9 7.1 2903084 436196 ? Sl 08:55 8:07 /usr/lib/firefox/firefox -contentproc -childID 2 -isForBrowser -prefsLen 1 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 342 10.8 7.0 2941056 426484 ? Rl 08:59 10:45 /usr/lib/firefox/firefox -contentproc -childID 5 -isForBrowser -prefsLen 8763 -prefMapSize 210653 -parentBuildID 20200107212822 -greomni /usr/lib/firefox/omni.ja -appomni /usr/lib/firefox/browser/omni.ja -appdir /usr/lib/firefox/browser 32469 true tab
|
||||
nemo 2389 16.9 3.8 1762960 234644 pts/1 Sl+ 09:15 13:57 vlc videos/edge_computing.mp4
|
||||
nemo 29527 3.9 3.7 2736924 227448 ? Ssl 08:50 4:11 /usr/bin/gnome-shell
|
||||
```
|
||||
### 使用 ps 和其他命令的搭配
|
||||
|
||||
如果你想比较某个用户与其他用户内存使用情况将会比较复杂。在这种情况中,创建并排序一个按照用户总的内存使用量是一个不错的方法,但是它需要做一些更多的工作,并涉及到许多命令。在下面的脚本中,我们使用 `ps aux | grep -v COMMAND | awk '{print $1}' | sort -u` 命令得到了用户列表。其中包含了系统用户比如 `syslog`。我们对每个任务使用 `awk` 命令以收集每个用户总的内存使用情况。在最后一步中,我们展示每个用户总的内存使用量(按照从大到小的顺序)。
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
stats=””
|
||||
echo "% user"
|
||||
echo "============"
|
||||
|
||||
# collect the data
|
||||
for user in `ps aux | grep -v COMMAND | awk '{print $1}' | sort -u`
|
||||
do
|
||||
stats="$stats\n`ps aux | egrep ^$user | awk 'BEGIN{total=0}; \
|
||||
{total += $4};END{print total,$1}'`"
|
||||
done
|
||||
|
||||
# sort data numerically (largest first)
|
||||
echo -e $stats | grep -v ^$ | sort -rn | head
|
||||
```
|
||||
|
||||
这个脚本的输出可能如下:
|
||||
|
||||
```
|
||||
$ ./show_user_mem_usage
|
||||
% user
|
||||
============
|
||||
69.6 nemo
|
||||
5.8 root
|
||||
0.5 www-data
|
||||
0.3 shs
|
||||
0.2 whoopsie
|
||||
0.2 systemd+
|
||||
0.2 colord
|
||||
0.2 clamav
|
||||
0 syslog
|
||||
0 rtkit
|
||||
```
|
||||
|
||||
在 Linux 有许多方法可以报告内存使用情况。可以通过一些用心设计的工具和命令,来查看并获得某个进程或者用户占用着最多的内存。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3516319/showing-memory-usage-in-linux-by-process-and-user.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://images.idgesg.net/images/article/2018/06/chips_processors_memory_cards_by_fancycrave_cc0_via_unsplash_1200x800-100760955-large.jpg
|
||||
[2]: https://creativecommons.org/publicdomain/zero/1.0/
|
||||
[3]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE21620&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[4]: https://www.facebook.com/NetworkWorld/
|
||||
[5]: https://www.linkedin.com/company/network-world
|
87
published/20200131 Intro to the Linux command line.md
Normal file
87
published/20200131 Intro to the Linux command line.md
Normal file
@ -0,0 +1,87 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qianmingtian)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11864-1.html)
|
||||
[#]: subject: (Intro to the Linux command line)
|
||||
[#]: via: (https://www.networkworld.com/article/3518440/intro-to-the-linux-command-line.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
Linux 命令行简介
|
||||
======
|
||||
|
||||
> 下面是一些针对刚开始使用 Linux 命令行的人的热身练习。警告:它可能会上瘾。
|
||||
|
||||
![](https://images.idgesg.net/images/article/2020/01/cmd_linux-control_linux-logo_-100828420-large.jpg)
|
||||
|
||||
如果你是 Linux 新手,或者从来没有花时间研究过命令行,你可能不会理解为什么这么多 Linux 爱好者坐在舒适的桌面前兴奋地输入命令来使用大量工具和应用。在这篇文章中,我们将快速浏览一下命令行的奇妙之处,看看能否让你着迷。
|
||||
|
||||
首先,要使用命令行,你必须打开一个命令工具(也称为“命令提示符”)。如何做到这一点将取决于你运行的 Linux 版本。例如,在 RedHat 上,你可能会在屏幕顶部看到一个 “Activities” 选项卡,它将打开一个选项列表和一个用于输入命令的小窗口(类似 “cmd” 为你打开的窗口)。在 Ubuntu 和其他一些版本中,你可能会在屏幕左侧看到一个小的终端图标。在许多系统上,你可以同时按 `Ctrl+Alt+t` 键打开命令窗口。
|
||||
|
||||
如果你使用 PuTTY 之类的工具登录 Linux 系统,你会发现自己已经处于命令行界面。
|
||||
|
||||
一旦你得到你的命令行窗口,你会发现自己坐在一个提示符面前。它可能只是一个 `$` 或者像 `user@system:~$` 这样的东西,但它意味着系统已经准备好为你运行命令了。
|
||||
|
||||
一旦你走到这一步,就应该开始输入命令了。下面是一些要首先尝试的命令,以及这里是一些特别有用的命令的 [PDF][4] 和适合打印和做成卡片的双面命令手册。
|
||||
|
||||
|
||||
| 命令 | 用途 |
|
||||
|---|---|
|
||||
| `pwd` | 显示我在文件系统中的位置(在最初进入系统时运行将显示主目录) |
|
||||
| `ls` | 列出我的文件 |
|
||||
| `ls -a` | 列出我更多的文件(包括隐藏文件) |
|
||||
| `ls -al` | 列出我的文件,并且包含很多详细信息(包括日期、文件大小和权限) |
|
||||
| `who` | 告诉我谁登录了(如果只有你,不要失望) |
|
||||
| `date` | 日期提醒我今天是星期几(也显示时间) |
|
||||
| `ps` | 列出我正在运行的进程(可能只是你的 shell 和 `ps` 命令) |
|
||||
|
||||
一旦你从命令行角度习惯了 Linux 主目录之后,就可以开始探索了。也许你会准备好使用以下命令在文件系统中闲逛:
|
||||
|
||||
| 命令 | 用途 |
|
||||
|---|---|
|
||||
| `cd /tmp` | 移动到其他文件夹(本例中,打开 `/tmp` 文件夹) |
|
||||
| `ls` | 列出当前位置的文件 |
|
||||
| `cd` | 回到主目录(不带参数的 `cd` 总是能将你带回到主目录) |
|
||||
| `cat .bashrc` | 显示文件的内容(本例中显示 `.bashrc` 文件的内容) |
|
||||
| `history` | 显示最近执行的命令 |
|
||||
| `echo hello` | 跟自己说 “hello” |
|
||||
| `cal` | 显示当前月份的日历 |
|
||||
|
||||
要了解为什么高级 Linux 用户如此喜欢命令行,你将需要尝试其他一些功能,例如重定向和管道。“重定向”是当你获取命令的输出并将其放到文件中而不是在屏幕上显示时。“管道”是指你将一个命令的输出发送给另一条将以某种方式对其进行操作的命令。这是可以尝试的命令:
|
||||
|
||||
| 命令 | 用途 |
|
||||
|---|---|
|
||||
| `echo "echo hello" > tryme` | 创建一个新的文件并将 “echo hello” 写入该文件 |
|
||||
| `chmod 700 tryme` | 使新建的文件可执行 |
|
||||
| `tryme` | 运行新文件(它应当运行文件中包含的命令并且显示 “hello” )|
|
||||
| `ps aux` | 显示所有运行中的程序 |
|
||||
| `ps aux | grep $USER` | 显示所有运行中的程序,但是限制输出的内容包含你的用户名 |
|
||||
| `echo $USER` | 使用环境变量显示你的用户名 |
|
||||
| `whoami` | 使用命令显示你的用户名 |
|
||||
| `who | wc -l` | 计数所有当前登录的用户数目 |
|
||||
|
||||
### 总结
|
||||
|
||||
一旦你习惯了基本命令,就可以探索其他命令并尝试编写脚本。 你可能会发现 Linux 比你想象的要强大并且好用得多.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3518440/intro-to-the-linux-command-line.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qianmingtian][c]
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[c]: https://github.com/qianmingtian
|
||||
[1]: https://commons.wikimedia.org/wiki/File:Tux.svg
|
||||
[2]: https://creativecommons.org/publicdomain/zero/1.0/
|
||||
[3]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE21620&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[4]: https://www.networkworld.com/article/3391029/must-know-linux-commands.html
|
||||
[5]: https://www.networkworld.com/newsletters/signup.html
|
||||
[6]: https://www.facebook.com/NetworkWorld/
|
||||
[7]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,96 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (LazyWolfLin)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11853-1.html)
|
||||
[#]: subject: (4 Key Changes to Look Out for in Linux Kernel 5.6)
|
||||
[#]: via: (https://itsfoss.com/linux-kernel-5-6/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
四大亮点带你看 Linux 内核 5.6
|
||||
======
|
||||
|
||||
当我们还在体验 Linux 5.5 稳定发行版带来更好的硬件支持时,Linux 5.6 已经来了。
|
||||
|
||||
说实话,Linux 5.6 比 5.5 更令人兴奋。即使即将发布的 Ubuntu 20.04 LTS 发行版将自带 Linux 5.5,你也需要切实了解一下 Linux 5.6 内核为我们提供了什么。
|
||||
|
||||
我将在本文中重点介绍 Linux 5.6 发布版中值得期待的关键更改和功能:
|
||||
|
||||
### Linux 5.6 功能亮点
|
||||
|
||||
![][1]
|
||||
|
||||
当 Linux 5.6 有新消息时,我会努力更新这份功能列表。但现在让我们先看一下当前已知的内容:
|
||||
|
||||
#### 1、支持 WireGuard
|
||||
|
||||
WireGuard 将被添加到 Linux 5.6,出于各种原因的考虑它可能将取代 [OpenVPN][2]。
|
||||
|
||||
你可以在官网上进一步了解 [WireGuard][3] 的优点。当然,如果你使用过它,那你可能已经知道它比 OpenVPN 更好的原因。
|
||||
|
||||
同样,[Ubuntu 20.04 LTS 将支持 WireGuard][4]。
|
||||
|
||||
#### 2、支持 USB4
|
||||
|
||||
Linux 5.6 也将支持 **USB4**。
|
||||
|
||||
如果你不了解 USB 4.0 (USB4),你可以阅读这份[文档][5]。
|
||||
|
||||
根据文档,“USB4 将使 USB 的最大带宽增大一倍并支持<ruby>多并发数据和显示协议<rt>multiple simultaneous data and display protocols</rt></ruby>。”
|
||||
|
||||
另外,虽然我们都知道 USB4 基于 Thunderbolt 接口协议,但它将向后兼容 USB 2.0、USB 3.0 以及 Thunderbolt 3,这将是一个好消息。
|
||||
|
||||
#### 3、使用 LZO/LZ4 压缩 F2FS 数据
|
||||
|
||||
Linux 5.6 也将支持使用 LZO/LZ4 算法压缩 F2FS 数据。
|
||||
|
||||
换句话说,这只是 Linux 文件系统的一种新压缩技术,你可以选择待定的文件扩展技术。
|
||||
|
||||
#### 4、解决 32 位系统的 2038 年问题
|
||||
|
||||
Unix 和 Linux 将时间值以 32 位有符号整数格式存储,其最大值为 2147483647。时间值如果超过这个数值则将由于整数溢出而存储为负数。
|
||||
|
||||
这意味着对于 32 位系统,时间值不能超过 1970 年 1 月 1 日后的 2147483647 秒。也就是说,在 UTC 时间 2038 年 1 月 19 日 03:14:07 时,由于整数溢出,时间将显示为 1901 年 12 月 13 日而不是 2038 年 1 月 19 日。
|
||||
|
||||
Linux kernel 5.6 解决了这个问题,因此 32 位系统也可以运行到 2038 年以后。
|
||||
|
||||
#### 5、改进硬件支持
|
||||
|
||||
很显然,在下一个发布版中,硬件支持也将继续提升。而支持新式无线外设的计划也同样是优先的。
|
||||
|
||||
新内核中将增加对 MX Master 3 鼠标以及罗技其他无线产品的支持。
|
||||
|
||||
除了罗技的产品外,你还可以期待获得许多不同硬件的支持(包括对 AMD GPU、NVIDIA GPU 和 Intel Tiger Lake 芯片组的支持)。
|
||||
|
||||
#### 6、其他更新
|
||||
|
||||
此外,Linux 5.6 中除了上述主要的新增功能或支持外,下一个内核版本也将进行其他一些改进:
|
||||
|
||||
* 改进 AMD Zen 的温度/功率报告
|
||||
* 修复华硕飞行堡垒系列笔记本中 AMD CPU 过热
|
||||
* 开源支持 NVIDIA RTX 2000 图灵系列显卡
|
||||
* 内建 FSCRYPT 加密
|
||||
|
||||
[Phoronix][6] 跟踪了 Linux 5.6 带来的许多技术性更改。因此,如果你好奇 Linux 5.6 所涉及的全部更改,则可以亲自了解一下。
|
||||
|
||||
现在你已经了解了 Linux 5.6 发布版带来的新功能,对此有什么看法呢?在下方评论中留下你的看法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/linux-kernel-5-6/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[LazyWolfLin](https://github.com/LazyWolfLin)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/linux-kernel-5.6.jpg?ssl=1
|
||||
[2]: https://openvpn.net/
|
||||
[3]: https://www.wireguard.com/
|
||||
[4]: https://www.phoronix.com/scan.php?page=news_item&px=Ubuntu-20.04-Adds-WireGuard
|
||||
[5]: https://www.usb.org/sites/default/files/2019-09/USB-IF_USB4%20spec%20announcement_FINAL.pdf
|
||||
[6]: https://www.phoronix.com/scan.php?page=news_item&px=Linux-5.6-Spectacular
|
@ -0,0 +1,83 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qianmingtian)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11902-1.html)
|
||||
[#]: subject: (Give an old MacBook new life with Linux)
|
||||
[#]: via: (https://opensource.com/article/20/2/macbook-linux-elementary)
|
||||
[#]: author: (Don Watkins https://opensource.com/users/don-watkins)
|
||||
|
||||
用 Linux 让旧 MacBook 焕发新生
|
||||
======
|
||||
|
||||
> Elementary OS 的最新版本 Hera 是一个令人印象深刻的平台,它可以让过时的 MacBook 得以重生。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/18/113614k2jx6ju7uuu0alhk.png)
|
||||
|
||||
当我安装苹果的 [MacOS Mojave][2] 时,它使我以前可靠的 MacBook Air 慢得像爬一样。我的计算机发售于 2015 年,具有 4 GB 内存、i5 处理器和 Broadcom 4360 无线卡,但是对于我的日常使用来说,Mojava 有点过分了,它不能和 [GnuCash][3] 一起工作,这激起了我重返 Linux 的欲望。我很高兴能重返,但是我深感遗憾的是,我的这台出色的 MacBook 被闲置了。
|
||||
|
||||
我在 MacBook Air 上尝试了几种 Linux 发行版,但总会有缺陷。有时是无线网卡;还有一次,它缺少对触摸板的支持。看了一些不错的评论后,我决定尝试 [Elementary OS][4] 5.0(Juno)。我用 USB [制作了启动盘][5],并将其插入 MacBook Air 。我来到了一个<ruby>现场<rt>live</rt></ruby>桌面,并且操作系统识别出了我的 Broadcom 无线芯片组 —— 我认为这可能行得通!
|
||||
|
||||
我喜欢在 Elementary OS 中看到的内容。它的 [Pantheon][6] 桌面真的很棒,并且其外观和使用起来的感觉对 Apple 用户来说很熟悉 —— 它的显示屏底部有一个扩展坞,并带有一些指向常用应用程序的图标。我对我之前期待的预览感到满意,所以我决定安装它,然后我的无线设备消失了。真的很令人失望。我真的很喜欢 Elementary OS ,但是没有无线网络是不行的。
|
||||
|
||||
时间快进到 2019 年 12 月,当我在 [Linux4Everyone][7] 播客上听到有关 Elementary 最新版本 v.5.1(Hera) 使 MacBook 复活的评论时,我决定用 Hera 再试一次。我下载了 ISO ,创建了可启动驱动器,将其插入电脑,这次操作系统识别了我的无线网卡。我可以在上面工作了。
|
||||
|
||||
![运行 Hera 的 MacBook Air][8]
|
||||
|
||||
我非常高兴我轻巧又功能强大的 MacBook Air 通过 Linux 焕然一新。我一直在更详细地研究 Elementary OS,我可以告诉你我印象深刻的东西。
|
||||
|
||||
### Elementary OS 的功能
|
||||
|
||||
根据 [Elementary 的博客][9],“新设计的登录和锁定屏幕问候语看起来更清晰、效果更好,并且修复了以前问候语中报告的许多问题,包括输入焦点问题,HiDPI 问题和更好的本地化。Hera 的新设计是为了响应来自 Juno 的用户反馈,并启用了一些不错的新功能。”
|
||||
|
||||
“不错的新功能”是在轻描淡写 —— Elementary OS 拥有我见过的最佳设计的 Linux 用户界面之一。默认情况下,系统上的“系统设置”图标位于扩展坞上。更改设置很容易,很快我就按照自己的喜好配置了系统。我需要的文字大小比默认值大,辅助功能是易于使用的,允许我设置大文字和高对比度。我还可以使用较大的图标和其他选项来调整扩展坞。
|
||||
|
||||
![Elementary OS 的设置界面][10]
|
||||
|
||||
按下 Mac 的 Command 键将弹出一个键盘快捷键列表,这对新用户非常有帮助。
|
||||
|
||||
![Elementary OS 的键盘快捷键][11]
|
||||
|
||||
Elementary OS 附带的 [Epiphany][12] Web 浏览器,我发现它非常易于使用。它与 Chrome、Chromium 或 Firefox 略有不同,但它已经绰绰有余。
|
||||
|
||||
对于注重安全的用户(我们应该都是),Elementary OS 的安全和隐私设置提供了多个选项,包括防火墙、历史记录、锁定,临时和垃圾文件的自动删除以及用于位置服务开/关的开关。
|
||||
|
||||
![Elementary OS 的隐私与安全][13]
|
||||
|
||||
### 有关 Elementray OS 的更多信息
|
||||
|
||||
Elementary OS 最初于 2011 年发布,其最新版本 Hera 于 2019 年 12 月 3 日发布。 Elementary 的联合创始人兼 CXO 的 [Cassidy James Blaede][14] 是操作系统的 UX 架构师。 Cassidy 喜欢使用开放技术来设计和构建有用、可用和令人愉悦的数字产品。
|
||||
|
||||
Elementary OS 具有出色的用户[文档][15],其代码(在 GPL 3.0 下许可)可在 [GitHub][16] 上获得。Elementary OS 鼓励参与该项目,因此请务必伸出援手并[加入社区][17]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/2/macbook-linux-elementary
|
||||
|
||||
作者:[Don Watkins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qianmingtian][c]
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/don-watkins
|
||||
[b]: https://github.com/lujun9972
|
||||
[c]: https://github.com/qianmingtian
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coffee_cafe_brew_laptop_desktop.jpg?itok=G-n1o1-o (Coffee and laptop)
|
||||
[2]: https://en.wikipedia.org/wiki/MacOS_Mojave
|
||||
[3]: https://www.gnucash.org/
|
||||
[4]: https://elementary.io/
|
||||
[5]: https://opensource.com/life/14/10/test-drive-linux-nothing-flash-drive
|
||||
[6]: https://opensource.com/article/19/12/pantheon-linux-desktop
|
||||
[7]: https://www.linux4everyone.com/20-macbook-pro-elementary-os
|
||||
[8]: https://opensource.com/sites/default/files/uploads/macbookair_hera.png (MacBook Air with Hera)
|
||||
[9]: https://blog.elementary.io/introducing-elementary-os-5-1-hera/
|
||||
[10]: https://opensource.com/sites/default/files/uploads/elementaryos_settings.png (Elementary OS's Settings screen)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/elementaryos_keyboardshortcuts.png (Elementary OS's Keyboard shortcuts)
|
||||
[12]: https://en.wikipedia.org/wiki/GNOME_Web
|
||||
[13]: https://opensource.com/sites/default/files/uploads/elementaryos_privacy-security.png (Elementary OS's Privacy and Security screen)
|
||||
[14]: https://github.com/cassidyjames
|
||||
[15]: https://elementary.io/docs/learning-the-basics#learning-the-basics
|
||||
[16]: https://github.com/elementary
|
||||
[17]: https://elementary.io/get-involved
|
@ -0,0 +1,76 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11866-1.html)
|
||||
[#]: subject: (Ubuntu 19.04 Has Reached End of Life! Existing Users Must Upgrade to Ubuntu 19.10)
|
||||
[#]: via: (https://itsfoss.com/ubuntu-19-04-end-of-life/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
Ubuntu 19.04 已经到期!现有用户必须升级到 Ubuntu 19.10
|
||||
======
|
||||
|
||||
> Ubuntu 19.04 已在 2020 年 1 月 23 日到期,这意味着运行 Ubuntu 19.04 的系统将不再会接收到安全和维护更新,因此将使其容易受到攻击。
|
||||
|
||||
![][1]
|
||||
|
||||
[Ubuntu 19.04][2] 发布于 2019 年 4 月 18 日。由于它不是长期支持(LTS)版本,因此只有 9 个月的支持。完成它的发行周期后,Ubuntu 19.04 于 2020 年 1 月 23 日到期。
|
||||
|
||||
Ubuntu 19.04 带来了一些视觉和性能方面的改进,为时尚和美观的 Ubuntu 外观铺平了道路。与其他常规 Ubuntu 版本一样,它的生命周期为 9 个月。它如今结束了。
|
||||
|
||||
### Ubuntu 19.04 终止了吗?这是什么意思?
|
||||
|
||||
EOL(End of life)是指在某个日期之后操作系统版本将无法获得更新。你可能已经知道 Ubuntu(或其他操作系统)提供了安全性和维护升级,以使你的系统免受网络攻击。当发行版到期后,操作系统将停止接收这些重要更新。
|
||||
|
||||
如果你的操作系统版本到期后继续使用该系统,那么系统将容易受到网络和恶意软件的攻击。不仅如此。在 Ubuntu 中,你使用 APT 从软件中心下载的应用也不会更新。实际上,你将不再能够[使用 apt-get 命令安装新软件][3](如果不是立即,那就是逐渐地)。
|
||||
|
||||
### 所有 Ubuntu 19.04 用户必须升级到 Ubuntu 19.10
|
||||
|
||||
从 2020 年 1 月 23 日开始,Ubuntu 19.04 将停止接收更新。你必须升级到 2020 年 7 月之前受支持的 Ubuntu 19.10。这也适用于其他[官方 Ubuntu 衍生版][4],例如 Lubuntu、Xubuntu、Kubuntu 等。
|
||||
|
||||
你可以在“设置 -> 细节” 或使用如下命令来[检查你的 Ubuntu 版本][9]:
|
||||
|
||||
```
|
||||
lsb_release -a
|
||||
```
|
||||
|
||||
#### 如何升级到 Ubuntu 19.10?
|
||||
|
||||
值得庆幸的是,Ubuntu 提供了简单的方法来将现有系统升级到新版本。实际上,Ubuntu 还会提示你有新的 Ubuntu 版本可用,你应该升级到该版本。
|
||||
|
||||
![Existing Ubuntu 19.04 should see a message to upgrade to Ubuntu 19.10][5]
|
||||
|
||||
如果你的互联网连接良好,那么可以使用[和更新 Ubuntu 一样的 Software Updater 工具][6]。在上图中,你只需单击 “Upgrade” 按钮并按照说明进行操作。我已经编写了有关使用此方法[升级到 Ubuntu 18.04][7]的文章。
|
||||
|
||||
如果你没有良好的互联网连接,那么有一种临时方案。在外部磁盘上备份家目录或重要数据。
|
||||
|
||||
然后,制作一个 Ubuntu 19.10 的 Live USB。下载 Ubuntu 19.10 ISO,并使用 Ubuntu 系统上已安装的启动磁盘创建器从该 ISO 创建 Live USB。
|
||||
|
||||
从该 Live USB 引导,然后继续“安装” Ubuntu 19.10。在安装过程中,你应该看到一个删除 Ubuntu 19.04 并将其替换为 Ubuntu 19.10 的选项。选择此选项,然后像重新[安装 Ubuntu][8]一样进行下去。
|
||||
|
||||
#### 你是否仍在使用 Ubuntu 19.04、18.10、17.10 或其他不受支持的版本?
|
||||
|
||||
你应该注意,目前仅 Ubuntu 16.04、18.04 和 19.10(或更高版本)版本还受支持。如果你运行的不是这些 Ubuntu 版本,那么你必须升级到较新版本。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/ubuntu-19-04-end-of-life/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/abhishek/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/End-of-Life-Ubuntu-19.04.png?ssl=1
|
||||
[2]: https://itsfoss.com/ubuntu-19-04-release/
|
||||
[3]: https://itsfoss.com/apt-get-linux-guide/
|
||||
[4]: https://itsfoss.com/which-ubuntu-install/
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/02/ubuntu_19_04_end_of_life.jpg?ssl=1
|
||||
[6]: https://itsfoss.com/update-ubuntu/
|
||||
[7]: https://itsfoss.com/upgrade-ubuntu-version/
|
||||
[8]: https://itsfoss.com/install-ubuntu/
|
||||
[9]: https://itsfoss.com/how-to-know-ubuntu-unity-version/
|
96
published/20200205 Getting started with GnuCash.md
Normal file
96
published/20200205 Getting started with GnuCash.md
Normal file
@ -0,0 +1,96 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11895-1.html)
|
||||
[#]: subject: (Getting started with GnuCash)
|
||||
[#]: via: (https://opensource.com/article/20/2/gnucash)
|
||||
[#]: author: (Don Watkins https://opensource.com/users/don-watkins)
|
||||
|
||||
开始使用 GnuCash
|
||||
======
|
||||
|
||||
> 使用 GnuCash 管理你的个人或小型企业会计。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/15/124236wz5e0z5vq7571qby.jpg)
|
||||
|
||||
在过去的四年里,我一直在用 [GnuCash][2] 来管理我的个人财务,我对此非常满意。这个开源(GPL v3)项目自 1998 年首次发布以来一直成长和改进,2019 年 12 月发布的最新版本 3.8 增加了许多改进和 bug 修复。
|
||||
|
||||
GnuCash 可在 Windows、MacOS 和 Linux 中使用。它实现了一个复式记账系统,并可以导入各种流行的开放和专有文件格式,包括 QIF、QFX、OFX、CSV 等。这使得从其他财务应用转换(包括 Quicken)而来很容易,它是为取代这些而出现的。
|
||||
|
||||
借助 GnuCash,你可以跟踪个人财务状况以及小型企业会计和开票。它没有集成的工资系统。根据文档,你可以在 GnuCash 中跟踪工资支出,但你必须在该软件外计算税金和扣减。
|
||||
|
||||
### 安装
|
||||
|
||||
要在 Linux 上安装 GnuCash:
|
||||
|
||||
* 在 Red Hat、CentOS 或 Fedora 中: `$ sudo dnf install gnucash`
|
||||
* 在 Debian、Ubuntu 或 Pop_OS 中: `$ sudo apt install gnucash`
|
||||
|
||||
你也可以从 [Flathub][3] 安装它,我在运行 Elementary OS 的笔记本上使用它。(本文中的所有截图都来自此次安装)。
|
||||
|
||||
### 设置
|
||||
|
||||
安装并启动程序后,你将看到一个欢迎屏幕,该页面提供了创建新账户集、导入 QIF 文件或打开新用户教程的选项。
|
||||
|
||||
![GnuCash Welcome screen][4]
|
||||
|
||||
#### 个人账户
|
||||
|
||||
如果你选择第一个选项(正如我所做的那样),GnuCash 会打开一个页面帮你起步。它收集初始数据并设置账户首选项,例如账户类型和名称、商业数据(例如,税号)和首选货币。
|
||||
|
||||
![GnuCash new account setup][5]
|
||||
|
||||
GnuCash 支持个人银行账户、商业账户、汽车贷款、CD 和货币市场账户、儿童保育账户等。
|
||||
|
||||
例如,首先创建一个简单的支票簿。你可以输入账户的初始余额或以多种格式导入现有账户数据。
|
||||
|
||||
![GnuCash import data][6]
|
||||
|
||||
#### 开票
|
||||
|
||||
GnuCash 还支持小型企业功能,包括客户、供应商和开票。要创建发票,请在 “Business -> Invoice” 中输入数据。
|
||||
|
||||
![GnuCash create invoice][7]
|
||||
|
||||
然后,你可以将发票打印在纸上,也可以将其导出到 PDF 并通过电子邮件发送给你的客户。
|
||||
|
||||
![GnuCash invoice][8]
|
||||
|
||||
### 获取帮助
|
||||
|
||||
如果你有任何疑问,它有一个优秀的帮助,你可在菜单栏的右侧获取指导。
|
||||
|
||||
![GnuCash help][9]
|
||||
|
||||
该项目的网站包含许多有用的信息的链接,例如 GnuCash [功能][10]的概述。GnuCash 还提供了[详细的文档][11],可供下载和离线阅读,它还有一个 [wiki][12],为用户和开发人员提供了有用的信息。
|
||||
|
||||
你可以在项目的 [GitHub][13] 仓库中找到其他文件和文档。GnuCash 项目由志愿者驱动。如果你想参与,请查看项目的 wiki 上的 [Getting involved][14] 部分。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/2/gnucash
|
||||
|
||||
作者:[Don Watkins][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/don-watkins
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/osdc_whitehurst_money.png?itok=ls-SOzM0 (A dollar sign in a network)
|
||||
[2]: https://www.gnucash.org/
|
||||
[3]: https://flathub.org/apps/details/org.gnucash.GnuCash
|
||||
[4]: https://opensource.com/sites/default/files/images/gnucash_welcome.png (GnuCash Welcome screen)
|
||||
[5]: https://opensource.com/sites/default/files/uploads/gnucash_newaccountsetup.png (GnuCash new account setup)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/gnucash_importdata.png (GnuCash import data)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/gnucash_enter-invoice.png (GnuCash create invoice)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/gnucash_invoice.png (GnuCash invoice)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/gnucash_help.png (GnuCash help)
|
||||
[10]: https://www.gnucash.org/features.phtml
|
||||
[11]: https://www.gnucash.org/docs/v3/C/gnucash-help.pdf
|
||||
[12]: https://wiki.gnucash.org/wiki/GnuCash
|
||||
[13]: https://github.com/Gnucash
|
||||
[14]: https://wiki.gnucash.org/wiki/GnuCash#Getting_involved_in_the_GnuCash_project
|
218
published/20200206 3 ways to use PostgreSQL commands.md
Normal file
218
published/20200206 3 ways to use PostgreSQL commands.md
Normal file
@ -0,0 +1,218 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Morisun029)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11904-1.html)
|
||||
[#]: subject: (3 ways to use PostgreSQL commands)
|
||||
[#]: via: (https://opensource.com/article/20/2/postgresql-commands)
|
||||
[#]: author: (Greg Pittman https://opensource.com/users/greg-p)
|
||||
|
||||
3 种使用 PostgreSQL 命令的方式
|
||||
======
|
||||
|
||||
> 无论你需要的东西简单(如一个购物清单)亦或复杂(如色卡生成器) ,PostgreSQL 命令都能使它变得容易起来。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202002/18/124003twk7fryz2krw2r39.jpg)
|
||||
|
||||
在 [PostgreSQL 入门][2]一文中, 我解释了如何安装、设置和开始使用这个开源数据库软件。不过,使用 [PostgreSQL][3] 中的命令可以做更多事情。
|
||||
|
||||
例如,我使用 Postgres 来跟踪我的杂货店购物清单。我的大多数杂货店购物是在家里进行的,而且每周进行一次大批量的采购。我去几个不同的地方购买清单上的东西,因为每家商店都提供特定的选品或质量,亦或更好的价格。最初,我制作了一个 HTML 表单页面来管理我的购物清单,但这样无法保存我的输入内容。因此,在想到要购买的物品时我必须马上列出全部清单,然后到采购时我常常会忘记一些我需要或想要的东西。
|
||||
|
||||
相反,使用 PostgreSQL,当我想到需要的物品时,我可以随时输入,并在购物前打印出来。你也可以这样做。
|
||||
|
||||
### 创建一个简单的购物清单
|
||||
|
||||
首先,输入 `psql` 命令进入数据库,然后用下面的命令创建一个表:
|
||||
|
||||
```
|
||||
Create table groc (item varchar(20), comment varchar(10));
|
||||
```
|
||||
|
||||
输入如下命令在清单中加入商品:
|
||||
|
||||
```
|
||||
insert into groc values ('milk', 'K');
|
||||
insert into groc values ('bananas', 'KW');
|
||||
```
|
||||
|
||||
括号中有两个信息(逗号隔开):前面是你需要买的东西,后面字母代表你要购买的地点以及哪些东西是你每周通常都要买的(`W`)。
|
||||
|
||||
因为 `psql` 有历史记录,你可以按向上键在括号内编辑信息,而无需输入商品的整行信息。
|
||||
|
||||
在输入一小部分商品后,输入下面命令来检查前面的输入内容。
|
||||
|
||||
```
|
||||
Select * from groc order by comment;
|
||||
|
||||
item | comment
|
||||
----------------+---------
|
||||
ground coffee | H
|
||||
butter | K
|
||||
chips | K
|
||||
steak | K
|
||||
milk | K
|
||||
bananas | KW
|
||||
raisin bran | KW
|
||||
raclette | L
|
||||
goat cheese | L
|
||||
onion | P
|
||||
oranges | P
|
||||
potatoes | P
|
||||
spinach | PW
|
||||
broccoli | PW
|
||||
asparagus | PW
|
||||
cucumber | PW
|
||||
sugarsnap peas | PW
|
||||
salmon | S
|
||||
(18 rows)
|
||||
```
|
||||
|
||||
此命令按 `comment` 列对结果进行排序,以便按购买地点对商品进行分组,从而使你的购物更加方便。
|
||||
|
||||
使用 `W` 来指明你每周要买的东西,当你要清除表单为下周的列表做准备时,你可以将每周的商品保留在购物清单上。输入:
|
||||
|
||||
```
|
||||
delete from groc where comment not like '%W';
|
||||
```
|
||||
|
||||
注意,在 PostgreSQL 中 `%` 表示通配符(而非星号)。所以,要保存输入内容,需要输入:
|
||||
|
||||
```
|
||||
delete from groc where item like 'goat%';
|
||||
```
|
||||
|
||||
不能使用 `item = 'goat%'`,这样没用。
|
||||
|
||||
在购物时,用以下命令输出清单并打印或发送到你的手机:
|
||||
|
||||
```
|
||||
\o groclist.txt
|
||||
select * from groc order by comment;
|
||||
\o
|
||||
```
|
||||
|
||||
最后一个命令 `\o` 后面没有任何内容,将重置输出到命令行。否则,所有的输出会继续输出到你创建的杂货店购物文件 `groclist.txt` 中。
|
||||
|
||||
### 分析复杂的表
|
||||
|
||||
这个逐项列表对于数据量小的表来说没有问题,但是对于数据量大的表呢?几年前,我帮 [FreieFarbe.de][4] 的团队从 HLC 调色板中创建一个自由色的色样册。事实上,任何能想象到的打印色都可按色调、亮度、浓度(饱和度)来规定。最终结果是 [HLC Color Atlas][5],下面是我们如何实现的。
|
||||
|
||||
该团队向我发送了具有颜色规范的文件,因此我可以编写可与 Scribus 配合使用的 Python 脚本,以轻松生成色样册。一个例子像这样开始:
|
||||
|
||||
```
|
||||
HLC, C, M, Y, K
|
||||
H010_L15_C010, 0.5, 49.1, 0.1, 84.5
|
||||
H010_L15_C020, 0.0, 79.7, 15.1, 78.9
|
||||
H010_L25_C010, 6.1, 38.3, 0.0, 72.5
|
||||
H010_L25_C020, 0.0, 61.8, 10.6, 67.9
|
||||
H010_L25_C030, 0.0, 79.5, 18.5, 62.7
|
||||
H010_L25_C040, 0.4, 94.2, 17.3, 56.5
|
||||
H010_L25_C050, 0.0, 100.0, 15.1, 50.6
|
||||
H010_L35_C010, 6.1, 32.1, 0.0, 61.8
|
||||
H010_L35_C020, 0.0, 51.7, 8.4, 57.5
|
||||
H010_L35_C030, 0.0, 68.5, 17.1, 52.5
|
||||
H010_L35_C040, 0.0, 81.2, 22.0, 46.2
|
||||
H010_L35_C050, 0.0, 91.9, 20.4, 39.3
|
||||
H010_L35_C060, 0.1, 100.0, 17.3, 31.5
|
||||
H010_L45_C010, 4.3, 27.4, 0.1, 51.3
|
||||
```
|
||||
|
||||
这与原始数据相比,稍有修改,原始数据用制表符分隔。我将其转换成 CSV 格式(用逗号分割值),我更喜欢其与 Python 一起使用(CSV 文也很有用,因为它可轻松导入到电子表格程序中)。
|
||||
|
||||
在每一行中,第一项是颜色名称,其后是其 C、M、Y 和 K 颜色值。 该文件包含 1,793 种颜色,我想要一种分析信息的方法,以了解这些值的范围。这就是 PostgreSQL 发挥作用的地方。我不想手动输入所有数据 —— 我认为输入过程中我不可能不出错,而且令人头痛。幸运的是,PostgreSQL 为此提供了一个命令。
|
||||
|
||||
首先用以下命令创建数据库:
|
||||
|
||||
```
|
||||
Create table hlc_cmyk (color varchar(40), c decimal, m decimal, y decimal, k decimal);
|
||||
```
|
||||
|
||||
然后通过以下命令引入数据:
|
||||
|
||||
```
|
||||
\copy hlc_cmyk from '/home/gregp/HLC_Atlas_CMYK_SampleData.csv' with (header, format CSV);
|
||||
```
|
||||
|
||||
开头有反斜杠,是因为使用纯 `copy` 命令的权限仅限于 root 用户和 Postgres 的超级用户。在括号中,`header` 表示第一行包含标题,应忽略,`CSV` 表示文件格式为 CSV。请注意,在此方法中,颜色名称不需要用括号括起来。
|
||||
|
||||
如果操作成功,会看到 `COPY NNNN`,其中 N 表示插入到表中的行数。
|
||||
|
||||
最后,可以用下列命令查询:
|
||||
|
||||
```
|
||||
select * from hlc_cmyk;
|
||||
|
||||
color | c | m | y | k
|
||||
---------------+-------+-------+-------+------
|
||||
H010_L15_C010 | 0.5 | 49.1 | 0.1 | 84.5
|
||||
H010_L15_C020 | 0.0 | 79.7 | 15.1 | 78.9
|
||||
H010_L25_C010 | 6.1 | 38.3 | 0.0 | 72.5
|
||||
H010_L25_C020 | 0.0 | 61.8 | 10.6 | 67.9
|
||||
H010_L25_C030 | 0.0 | 79.5 | 18.5 | 62.7
|
||||
H010_L25_C040 | 0.4 | 94.2 | 17.3 | 56.5
|
||||
H010_L25_C050 | 0.0 | 100.0 | 15.1 | 50.6
|
||||
H010_L35_C010 | 6.1 | 32.1 | 0.0 | 61.8
|
||||
H010_L35_C020 | 0.0 | 51.7 | 8.4 | 57.5
|
||||
H010_L35_C030 | 0.0 | 68.5 | 17.1 | 52.5
|
||||
```
|
||||
|
||||
|
||||
所有的 1,793 行数据都是这样的。回想起来,我不能说此查询对于 HLC 和 Scribus 任务是绝对必要的,但是它减轻了我对该项目的一些担忧。
|
||||
|
||||
为了生成 HLC 色谱,我使用 Scribus 为色板页面中的 13,000 多种颜色自动创建了颜色图表。
|
||||
|
||||
我可以使用 `copy` 命令输出数据:
|
||||
|
||||
```
|
||||
\copy hlc_cmyk to '/home/gregp/hlc_cmyk_backup.csv' with (header, format CSV);
|
||||
```
|
||||
|
||||
我还可以使用 `where` 子句根据某些值来限制输出。
|
||||
|
||||
例如,以下命令将仅发送以 `H10` 开头的色调值。
|
||||
|
||||
```
|
||||
\copy hlc_cmyk to '/home/gregp/hlc_cmyk_backup.csv' with (header, format CSV) where color like 'H10%';
|
||||
```
|
||||
|
||||
### 备份或传输数据库或表
|
||||
|
||||
我在此要提到的最后一个命令是 `pg_dump`,它用于备份 PostgreSQL 数据库,并在 `psql` 控制台之外运行。 例如:
|
||||
|
||||
```
|
||||
pg_dump gregp -t hlc_cmyk > hlc.out
|
||||
pg_dump gregp > dball.out
|
||||
```
|
||||
|
||||
第一行是导出 `hlc_cmyk` 表及其结构。第二行将转储 `gregp` 数据库中的所有表。这对于备份或传输数据库或表非常有用。
|
||||
|
||||
要将数据库或表传输到另一台电脑(查看 [PostgreSQL 入门][2]那篇文章获取详细信息),首先在要转入的电脑上创建一个数据库,然后执行相反的操作。
|
||||
|
||||
```
|
||||
psql -d gregp -f dball.out
|
||||
```
|
||||
|
||||
一步创建所有表并输入数据。
|
||||
|
||||
### 总结
|
||||
|
||||
在本文中,我们了解了如何使用 `WHERE` 参数限制操作,以及如何使用 PostgreSQL 通配符 `%`。我们还了解了如何将大批量数据加载到表中,然后将部分或全部表数据输出到文件,甚至是将整个数据库及其所有单个表输出。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/2/postgresql-commands
|
||||
|
||||
作者:[Greg Pittman][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Morisun029](https://github.com/Morisun029)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/greg-p
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/todo_checklist_team_metrics_report.png?itok=oB5uQbzf (Team checklist and to dos)
|
||||
[2]: https://linux.cn/article-11593-1.html
|
||||
[3]: https://www.postgresql.org/
|
||||
[4]: http://freiefarbe.de
|
||||
[5]: https://www.freiefarbe.de/en/thema-farbe/hlc-colour-atlas/
|
@ -0,0 +1,186 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11884-1.html)
|
||||
[#]: subject: (Best Open Source eCommerce Platforms to Build Online Shopping Websites)
|
||||
[#]: via: (https://itsfoss.com/open-source-ecommerce/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
7 个可用于自建电商站点的开源解决方案
|
||||
======
|
||||
|
||||
在[之前的文章][1]中,我介绍过一些开源<ruby>内容管理系统<rt>Content Management System</rt></ruby>(CMS),顾名思义,这些 CMS 平台更适用于以内容为主的站点。
|
||||
|
||||
那如果想要建立自己的线上购物站点呢?我们正好还有一些优秀的开源电商解决方案,可以自行部署在自己的 Linux 服务器上。
|
||||
|
||||
这些电商解决方案是专为搭建线上购物站点设计的,因此都集成了库存管理、商品列表、购物车、下单、愿望清单以及支付这些必需的基础功能。
|
||||
|
||||
但请注意,这篇文章并不会进行深入介绍。因此,我建议最好广泛试用其中的多个产品,以便进一步的了解和比较。
|
||||
|
||||
### 优秀的开源电商解决方案
|
||||
|
||||
![][2]
|
||||
|
||||
开源电商解决方案种类繁多,一些缺乏维护的都会被我们忽略掉,以免搭建出来的站点因维护不及时而受到影响。
|
||||
|
||||
另外,以下的列表排名不分先后。
|
||||
|
||||
#### 1、nopCommerce
|
||||
|
||||
![][3]
|
||||
|
||||
nopCommerce 是基于 [ASP.NET Core][4] 的自由开源的电商解决方案。如果你要找的是基于 PHP 的解决方案,可以跳过这一节了。
|
||||
|
||||
nopCommerce 的管理面板界面具有简洁易用的特点,如果你还使用过 OpenCart,就可能会感到似曾相识(我不是在抱怨)。在默认情况下,它就已经自带了很多基本的功能,同时还为移动端用户提供了响应式的设计。
|
||||
|
||||
你可以在其[官方商店][5]中获取到一些兼容的界面主题和应用扩展,还可以选择付费的支持服务。
|
||||
|
||||
在开始使用前,你可以从 nopCommerce 的[官方网站][6]下载源代码包,然后进行自定义配置和部署;也可以直接下载完整的软件包快速安装到 web 服务器上。详细信息可以查阅 nopCommerce 的 [GitHub 页面][7]或官方网站。
|
||||
|
||||
- [nopCommerce][8]
|
||||
|
||||
#### 2、OpenCart
|
||||
|
||||
![][9]
|
||||
|
||||
OpenCart 是一个基于 PHP 的非常流行的电商解决方案,就我个人而言,我曾为一个项目用过它,并且体验非常好,如果不是最好的话。
|
||||
|
||||
或许你会觉得它维护得不是很频繁,但实际上使用 OpenCart 的开发者并不在少数。你可以获得许多受支持的扩展并将它们的功能加入到 OpenCart 中。
|
||||
|
||||
OpenCart 不一定是适合所有人的“现代”电商解决方案,但如果你需要的只是一个基于 PHP 的开源解决方案,OpenCart 是个值得一试的选择。在大多数具有一键式应用程序安装支持的网络托管平台中,应该可以安装 OpenCart。想要了解更多,可以查阅 OpenCart 的官方网站或 [GitHub 页面][10]。
|
||||
|
||||
- [OpenCart][11]
|
||||
|
||||
#### 3、PrestaShop
|
||||
|
||||
![][12]
|
||||
|
||||
PrestaShop 也是一个可以尝试的开源电商解决方案。
|
||||
|
||||
PrestaShop 是一个积极维护下的开源解决方案,它的官方商店中也有额外提供主题和扩展。与 OpenCart 不同,在托管服务平台上,你可能找不到一键安装的 PrestaShop。但不需要担心,从官方网站下载下来之后,它的部署过程也并不复杂。如果你需要帮助,也可以参考 PrestaShop 的[安装指南][15]。
|
||||
|
||||
PrestaShop 的特点就是配置丰富和易于使用,我发现很多其它用户也在用它,你也不妨试用一下。
|
||||
|
||||
你也可以在 PrestaShop 的 [GitHub 页面][16]查阅到更多相关内容。
|
||||
|
||||
- [PrestaShop][17]
|
||||
|
||||
#### 4、WooCommerce
|
||||
|
||||
![][18]
|
||||
|
||||
如果你想用 [WordPress][19] 来搭建电商站点,不妨使用 WooCommerce。
|
||||
|
||||
从技术上来说,这种方式其实是搭建一个 WordPress 应用,然后把 WooCommerce 作为一个插件或扩展以实现电商站点所需要的功能。很多 web 开发者都知道如何使用 WordPress,因此 WooCommerce 的学习成本不会很高。
|
||||
|
||||
WordPress 作为目前最好的开源站点项目之一,对大部分人来说都不会有太高的门槛。它具有易用、稳定的特点,同时还支持大量的扩展插件。
|
||||
|
||||
WooCommerce 的灵活性也是一大亮点,在它的线上商店提供了许多设计和扩展可供选择。你也可以到它的 [GitHub 页面][20]查看相关介绍。
|
||||
|
||||
- [WooCommerce][21]
|
||||
|
||||
#### 5、Zen Cart
|
||||
|
||||
![][22]
|
||||
|
||||
这或许是一个稍显古老的电商解决方案,但同时也是最好的开源解决方案之一。如果你喜欢老式风格的模板(主要基于 HTML),而且只需要一些基础性的扩展,那你也可以尝试使用 Zen Cart。
|
||||
|
||||
就我个人而言,我不建议把 Zen Cart 用在一个新项目当中。但考虑到它仍然是一个活跃更新中的解决方案,如果你喜欢的话,也不妨用它来进行试验。
|
||||
|
||||
你也可以在 [SourceForge][23] 找到 Zen Cart 这个项目。
|
||||
|
||||
- [Zen Cart][24]
|
||||
|
||||
#### 6、Magento
|
||||
|
||||
![Image Credits: Magestore][25]
|
||||
|
||||
Magento 是 Abode 旗下的开源电商解决方案,从某种角度来说,可能比 WordPress 表现得更为优秀。
|
||||
|
||||
Magento 完全是作为电商应用程序而生的,因此你会发现它的很多基础功能都非常好用,甚至还提供了高级的定制。
|
||||
|
||||
但如果你使用的是 Magento 的开源版,可能会接触不到托管版的一些高级功能,两个版本的差异,可以在[官方文档][26]中查看到。如果你使用托管版,还可以选择相关的托管支持服务。
|
||||
|
||||
想要了解更多,可以查看 Magento 的 [GitHub 页面][27]。
|
||||
|
||||
- [Magento][28]
|
||||
|
||||
#### 7、Drupal
|
||||
|
||||
![Drupal][29]
|
||||
|
||||
Drupal 是一个适用于创建电商站点的开源 CMS 解决方案。
|
||||
|
||||
我没有使用过 Drupal,因此我不太确定它用起来是否足够灵活。但从它的官方网站上来看,它提供的扩展模块和主题列表,足以让你轻松完成一个电商站点需要做的任何事情。
|
||||
|
||||
跟 WordPress 类似,Drupal 在服务器上的部署并不复杂,不妨看看它的使用效果。在它的[下载页面][30]可以查看这个项目以及下载最新的版本。
|
||||
|
||||
- [Drupal][31]
|
||||
|
||||
#### 8、Odoo eCommerce
|
||||
|
||||
![Odoo Ecommerce Platform][32]
|
||||
|
||||
如果你还不知道,Odoo 提供了一套开源商务应用程序。他们还提供了[开源会计软件][33]和 CRM 解决方案,我们将会在单独的列表中进行介绍。
|
||||
|
||||
对于电子商务门户,你可以根据需要使用其在线拖放生成器自定义网站。你也可以推广该网站。除了简单的主题安装和自定义选项之外,你还可以利用 HTML/CSS 在一定程度上手动自定义外观。
|
||||
|
||||
你也可以查看其 [GitHub][34] 页面以进一步了解它。
|
||||
|
||||
- [Odoo eCommerce][35]
|
||||
|
||||
### 总结
|
||||
|
||||
我敢肯定还有更多的开源电子商务平台,但是,我现在还没有遇到比我上面列出的更好的东西。
|
||||
|
||||
如果你还有其它值得一提的产品,可以在评论区发表。也欢迎在评论区分享你对开源电商解决方案的经验和想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/open-source-ecommerce/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[HankChow](https://github.com/HankChow)
|
||||
校对:[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/open-source-cms/
|
||||
[2]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/02/open-source-eCommerce.png?ssl=1
|
||||
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/nopCommerce.png?ssl=1
|
||||
[4]: https://en.wikipedia.org/wiki/ASP.NET_Core
|
||||
[5]: https://www.nopcommerce.com/marketplace
|
||||
[6]: https://www.nopcommerce.com/download-nopcommerce
|
||||
[7]: https://github.com/nopSolutions/nopCommerce
|
||||
[8]: https://www.nopcommerce.com/
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/opencart.jpg?ssl=1
|
||||
[10]: https://github.com/opencart/opencart
|
||||
[11]: https://www.opencart.com/
|
||||
[12]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/prestashop.jpg?ssl=1
|
||||
[13]: https://addons.prestashop.com/en/3-templates-prestashop
|
||||
[14]: https://addons.prestashop.com/en/
|
||||
[15]: http://doc.prestashop.com/display/PS17/Installing+PrestaShop
|
||||
[16]: https://github.com/PrestaShop/PrestaShop
|
||||
[17]: https://www.prestashop.com/en
|
||||
[18]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/01/woocommerce.jpg?ssl=1
|
||||
[19]: https://wordpress.org/
|
||||
[20]: https://github.com/woocommerce/woocommerce
|
||||
[21]: https://woocommerce.com/
|
||||
[22]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/Zen-cart.jpg?ssl=1
|
||||
[23]: https://sourceforge.net/projects/zencart/
|
||||
[24]: https://www.zen-cart.com/
|
||||
[25]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/01/magento.jpg?ssl=1
|
||||
[26]: https://magento.com/compare-open-source-and-magento-commerce
|
||||
[27]: https://github.com/magento
|
||||
[28]: https://magento.com/
|
||||
[29]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/01/drupal.png?ssl=1
|
||||
[30]: https://www.drupal.org/project/drupal
|
||||
[31]: https://www.drupal.org/industries/ecommerce
|
||||
[32]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/02/odoo-ecommerce-platform.jpg?w=800&ssl=1
|
||||
[33]: https://itsfoss.com/open-source-accounting-software/
|
||||
[34]: https://github.com/odoo/odoo
|
||||
[35]: https://www.odoo.com/page/open-source-ecommerce
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user