mirror of
https://github.com/LCTT/TranslateProject.git
synced 2026-08-23 04:03:29 +08:00
Merge branch 'master' of https://github.com/LCTT/TranslateProject into translating
This commit is contained in:
71
published/20180306 Exploring free and open web fonts.md
Normal file
71
published/20180306 Exploring free and open web fonts.md
Normal file
@@ -0,0 +1,71 @@
|
||||
探索自由而开放的 Web 字体
|
||||
======
|
||||
|
||||
> 谷歌字体和开放字体库中的免费 Web 字体已经改变了游戏规则,但仅在有限的范围内。
|
||||
|
||||

|
||||
|
||||
毫无疑问,近些年来互联网的面貌已经被开源字体所改变。早在 2010 年之前,你在 Web 浏览器上几乎只能看到微软制作的通常“Web 安全”的[核心字体][1]。但这一年(2010)正好是好几轮技术革新开始的见证之年:<ruby>[Web 开放字体格式][2]<rt>Web Open Font Format</rt></ruby>(WOFF)的引入为通过 HTTP 有效地传输字体文件提供了一个开放的标准,以及像[谷歌字体][3]和<ruby>[开放字体库][4]<rt>Open Font Library</rt></ruby>这样的 Web 字体服务的推出,使得 Web 内容发布者可以在开源许可证之下免费使用海量的字体库。
|
||||
|
||||
这些事件对 Web 排版的积极影响再夸大都不过分。但是要将 Web 开放字体的成功与整个开源排版等同起来,并得到结论——挑战已经远离了我们,困难悉数被解决了——却很容易。然而事实并非如此,如果你很关注字体,那么好消息是你有好多机会参与到对这些字体的改进工作当中去。
|
||||
|
||||
对新手来说,至关重要的是必须要意识到谷歌字体和开放字体库提供了专用的服务(为网页提供字体),而没有为其他使用情况制定字体解决方案。这不是服务方面的缺点,这只是意味着我们必须去开发其它的解决方案。
|
||||
|
||||
需要解决的问题还非常多。可能最明显的例子就是给 Linux 桌面计算机的其他软件安装字体所遇到的尴尬情况。你可以通过任何一种服务下载任何一种 Web 字体,但是你得到的只是一个最普通的压缩包文件,里面有一些 TTF 或 OTF 二进制文件和一个普通文本文件的许可证。接下来会发生什么完完全全需要你去猜。
|
||||
|
||||
大部分用户很快学会了“正确”的步骤就是手动地复制这些字体二进制文件到他们硬盘里几个特殊文件夹里的某一个里。但是这样做只能使这个文件对操作系统可见。它并不能为用户体验带来什么提升。再强调一遍,这不是 Web 字体服务的缺陷,相反它佐证了对于关于服务到哪里停止和需要在其他方面做更多工作的观点。
|
||||
|
||||
在用户视角来说,一个巨大的提升可能就是在“只是下载”这个阶段,操作系统或者桌面环境变得更智能。系统或桌面环境不仅会把字体文件安装到正确的位置上,更重要的是,当用户选择要在一个项目中使用的字体时,它会自己添加用户所需要的重要的元数据。
|
||||
|
||||
这些附加信息包含的内容与它如何呈现给用户与另一个挑战有关:与其它操作系统相比,在 Linux 环境管理一个字体库显然不那么令人满意。字体管理器总是时不时的出现一下(例如 [GTK+ 字体管理器][5],这是最近的一个例子),但是它们很少变得流行起来。我一直在思考一大堆这些软件让人失望的方面。一个核心的原因是它们把自己局限于只展示内嵌在二进制字体文件内的信息:基本字符集的覆盖、粗细/宽度和斜率的设定,内置的许可证和版权说明等等。
|
||||
|
||||
但是除了这些内嵌数据中的内容,在选择字体的过程中还涉及很多决策。严肃的字体用户,像信息设计者、杂志文章作者,或者书籍美工设计者,他们的字体选择是根据每一份文件的要求和需求做出的。这当然包含了许可证信息,但它还包含了更多,像关于设计师和厂商的信息、潮流风格的趋势,或者字体在使用中的细节。
|
||||
|
||||
举个例子,如果你的文档包含了英语和阿拉伯文,你多半想要拉丁文和阿拉伯文的字体由同时熟悉这两种<ruby>字母系统<rt>script</rt></ruby>的设计师所设计。否则,你将浪费一大堆时间来微调字体大小和行间距来使两种字母系统良好地结合在一起。你可能从经验中学到,某些设计师或字体厂商比其他人更善于多种字母系统设计。或许和你职业相关的是今天的时尚杂志几乎无一例外的采用 “[Didone][6]”风格的字体,“[Didone][6]”是指一种两百多年前最先被 [Firmin Didot][7] 和 [Giambattista Bodoni][8] 设计出来的超高反差的字体风格。这种字体恰好就是现在的潮流。
|
||||
|
||||
但是像 Didone、Didot 或 Bodoni 这些术语都不可能会出现在二进制文件的内置数据当中,你也不容易判断拉丁文和阿拉伯文是否相得益彰或其它关于字体的历史背景。这些信息有可能出现在补充的材料中,类似某种字形样本或字体文件中,如果这些东西存在的话。
|
||||
|
||||
<ruby>字形样本<rt>specimen</rt></ruby>是一份设计好的文档(一般是 PDF),它展示了这种字体的使用情况,而且包括了背景信息。字形样本经常在挑选字体时充当市场营销和外观样例的双重角色。一份精心设计的样本展示了字体在实际应用中的情况和在自动生成的字符表中所不能体现的风格。字形样本文件也有可能包含了一些其他重要信息,比如怎样激活字体的 OpenType 特性、提供的数学表达式或古体字,或者它在支持的多种语言上的风格变化。在字体管理应用程序中向用户提供此类材料,对于帮助用户找到适合其项目需求的字体将大有帮助。
|
||||
|
||||
当然,如果我们希望一个字体管理软件能够处理文件和样本问题,我们也必须仔细观察一下各种发行版提供的字体包所随附的内容。Linux 的用户刚开始只有自动安装的那几种字体,并且发行版存储库提供的包是大部分用户除了下载通用的压缩包档案之外的唯一字体来源。这些包往往非常的“简陋”。商业字体总的来说都包含了样本、文档,还有其他的支持项目,然而开源字体往往没有这些配套文件。
|
||||
|
||||
也有一些优秀的开放字体提供了高质量的样本和文档(例如 [SIL Gentium][9] 和 [Bungee][10] 是两种差异明显但是都有效的方案),但是它们几乎不涉足下游的打包工作链。我们显然可以做的更好一些。
|
||||
|
||||
要在系统的字体交互方面提供更丰富的用户体验上面还存在一些技术问题。一方面,[AppStream][11] 的元数据标准定义了一些字体文件特有的参数,但是到现在为止,这些参数没有包含样本、设计师/厂商和其他相关细节的任何信息。另外一个例子,[SPDX][13](<ruby>软件包数据交换<rt>Software Package Data Exchange</rt></ruby>)格式也没有包含太多用于分发字体的软件许可证(及许可证变体)。
|
||||
|
||||
最后,就像任何一个唱片爱好者都会告诉你的,一个不允许你编辑和完善你的 MP3 曲库中的 ID3 信息的音乐播放器很快就会变得令人失望(LCTT 译注:ID3 信息是 MP3 文件头部的元信息,用于存储歌曲信息)。你想要处理标签里的错误、想要添加注释和专辑封面之类的信息,本质上,这就是完善你的音乐库。同样,你可能也想要让你的本地字体库也保持在一个方便使用的状态。
|
||||
|
||||
但是改动字体文件的内置数据一直有所忌讳,因为字体往往是被内置或附加到其他文件里的。如果你随意改变了字体二进制文件中的字段,然后将其与你的演示文稿一起重新分发,那么下载这些演示文稿的任何人最终都会得到错误的元数据,但这个错误不是他们自己造成的。所以任何一个要改善字体管理体验的人都要想明白如何从策略上解决对内置或外置的字体元数据的重复修改。
|
||||
|
||||
除了技术角度之外,丰富的字体管理经验也是一项设计挑战。就像我在前面说的一样,有几种开放字体也带了良好的样本和精心编写的文档。但是更多的字体包这两者都没有,还有大量的更老的字体包已经没有人维护了。这很可能意味着大部分开放字体包想要获得样本和证明文件的唯一办法就是让社区去创建它们。
|
||||
|
||||
也许这是一个很高的要求。但是开源设计社区现在比以往任何时候都要庞大,它是整个自由开源软件运动中的一个高度活跃的组成部分。所以谁知道呢,也许明年这个时候会发现,在 Linux 桌面系统查找、下载和使用字体会变成一种完全不同的体验。
|
||||
|
||||
在这一连串关于现代 Linux 用户的文字设计上的挑战的思考中包含了打包、文档设计,甚至有可能需要在桌面环境加入不少新的软件部分。此外还有其他一系列的东西也需要考虑。其共通性就是在 Web 字体服务不可及的地方,事情就会变得更加困难。
|
||||
|
||||
从我的视角来看,最好的消息是现在比起以前有更多的人对这个话题感兴趣。我认为我们要感谢像谷歌字体和开放字体库这样的 Web 字体服务巨头让开放字体得到了更高的关注。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/webfonts
|
||||
|
||||
作者:[Nathan Willis][a]
|
||||
译者:[Fisherman110](https://github.com/Fisherman110)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/n8willis
|
||||
[1]:https://en.wikipedia.org/wiki/Core_fonts_for_the_Web
|
||||
[2]:https://en.wikipedia.org/wiki/Web_Open_Font_Format
|
||||
[3]:https://fonts.google.com/
|
||||
[4]:https://fontlibrary.org/
|
||||
[5]:https://fontmanager.github.io/
|
||||
[6]:https://en.wikipedia.org/wiki/Didone_(typography)
|
||||
[7]:https://en.wikipedia.org/wiki/Firmin_Didot
|
||||
[8]:https://en.wikipedia.org/wiki/Giambattista_Bodoni
|
||||
[9]:https://software.sil.org/gentium/
|
||||
[10]:https://djr.com/bungee/
|
||||
[11]:https://www.freedesktop.org/wiki/Distributions/AppStream/
|
||||
[12]:https://www.freedesktop.org/software/appstream/docs/sect-Metadata-Fonts.html
|
||||
[13]:https://spdx.org/
|
||||
@@ -1,28 +1,28 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11968-1.html)
|
||||
[#]: subject: (How to set up your own fast, private open source mesh network)
|
||||
[#]: via: (https://opensource.com/article/20/2/mesh-network-freemesh)
|
||||
[#]: author: (Spencer Thomason https://opensource.com/users/spencerthomason)
|
||||
|
||||
如何建立自己的快速、私有的开源网状网络
|
||||
如何建立自己的快速、私有的开源网状网络(mesh)
|
||||
======
|
||||
|
||||
> 只需要不到 10 分钟的安装时间,就可以用 FreeMesh 搭建一个经济实惠、性能卓越、尊重隐私的网格系统。
|
||||
|
||||
![people on top of a connected globe][1]
|
||||

|
||||
|
||||
[FreeMesh][2] 系统有望为大众带来完全开源的<ruby>网格网络<rt>mesh network</rt></ruby>。我最近有机会进行了测试;它安装迅速,性能非常好 —— 特别是相对它的价格而言。
|
||||
[FreeMesh][2] 系统有望为大众带来完全开源的<ruby>网状网络<rt>mesh network</rt></ruby>(LCTT 译注:也称之为“多跳网络”)。我最近有机会对它进行了测试;它安装迅速,性能非常好 —— 特别是相对它的价格而言。
|
||||
|
||||
### 为什么要网格化和开源?
|
||||
|
||||
使用开源的原因很简单:隐私。有了 FreeMesh,你的数据就是你自己的。它不会跟踪或收集数据。不相信吗?毕竟,你可以轻松检查 —— 它是开源的!而其它大型高科技企业集团提供的一些流行的网格解决方案,你是否相信它们会保护你的数据?
|
||||
使用开源的原因很简单:隐私。有了 FreeMesh,你的数据就是你自己的。它不会跟踪或收集数据。不相信吗?毕竟,你可以轻松检查 —— 它是开源的!而其它大型高科技企业集团提供的一些流行的网状网络解决方案,你是否相信它们会保护你的数据?
|
||||
|
||||
另一个重要因素:更新。FreeMesh 表示,它将致力于定期发布安全性和性能更新。从现在起到 10 年后呢?使用开放源代码解决方案,你可以根据需要自由地更新产品。
|
||||
另一个重要因素:更新。FreeMesh 表示,它将致力于定期发布安全性和性能更新。从现在起到 10 年后呢?使用开源解决方案,你可以根据需要自由地更新产品。
|
||||
|
||||
那么为什么要用网格呢?在网状网络中,多个无线路由器一起工作以广播单个超大型的无线网络。网状网络中的每个路由器都可与其他路由器智能地通信,以便为你的数据提供最佳的“路径”。FreeMesh 网站上的以下图片突出显示了使用单个无线路由器和网状网络之间的区别。 红色网络表示单个无线路由器,绿色网络是网状网络。
|
||||
那么为什么要用网状网络呢?在网状网络中,多个无线路由器一起工作以广播单个超大型的无线网络。网状网络中的每个路由器都可与其他路由器智能地通信,以便为你的数据提供最佳的“路径”。FreeMesh 网站上的以下图片突出显示了使用单个无线路由器和网状网络之间的区别。红色网络表示单个无线路由器,绿色网络是网状网络。
|
||||
|
||||
![单路由器网络] [3]
|
||||
|
||||
@@ -52,7 +52,7 @@ FreeMesh 路由器的一些规格非常好:
|
||||
|
||||
![FreeMesh 设置步骤 1][8]
|
||||
|
||||
2、等待约 30 至 60 秒。设置完成后,节点将闪烁其 LED。
|
||||
2、等待约 30 至 60 秒。设置完成后,节点的 LED 将会闪烁。
|
||||
|
||||
![FreeMesh 设置步骤 2][9]
|
||||
|
||||
@@ -74,7 +74,7 @@ FreeMesh 是开箱即用的,它由 OpenWRT 和 LuCI 组合而成。它具有
|
||||
|
||||
设置完 FreeMesh 系统后,我将节点移动到了房屋周围的各个地方。我使用 [iPerf][13] 测试带宽,它达到了约 150Mbps。WiFi 可能会受到许多环境变量的影响,因此你的结果可能会有所不同。节点与主路由器之间的距离在带宽中也有很大的影响。
|
||||
|
||||
但是,网状网络的真正优势不是高峰速度,而是整个空间的平均速度要好得多。即使在我家很远的地方,我仍然能够流媒体播放视频并正常工作。我甚至可以在后院工作。在出门之前,我只是将一个节点重新放在窗口前面而已。
|
||||
但是,网状网络的真正优势不是高峰速度,而是整个空间的平均速度要好得多。即使在我家很远的地方,我仍然能够用流媒体播放视频并正常工作。我甚至可以在后院工作。在出门之前,我只是将一个节点重新放在窗口前面而已。
|
||||
|
||||
### 结论
|
||||
|
||||
@@ -91,7 +91,7 @@ via: https://opensource.com/article/20/2/mesh-network-freemesh
|
||||
作者:[Spencer Thomason][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/) 荣誉推出
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11967-1.html)
|
||||
[#]: subject: (PHP Development on Fedora with Eclipse)
|
||||
[#]: via: (https://fedoramagazine.org/php-development-on-fedora-with-eclipse/)
|
||||
[#]: author: (Mehdi Haghgoo https://fedoramagazine.org/author/powergame/)
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
![][1]
|
||||
|
||||
[Eclipse][2] 是由 Eclipse 基金会开发的功能全面的免费开源 IDE。自 2001 年以来一直存在。你可以在此 IDE 中编写从 C/C++ 和 Java 到 PHP、Python、HTML、JavaScript、Kotlin 等。
|
||||
[Eclipse][2] 是由 Eclipse 基金会开发的功能全面的自由开源 IDE。它诞生于 2001 年。你可以在此 IDE 中编写各种程序,从 C/C++ 和 Java 到 PHP,乃至于 Python、HTML、JavaScript、Kotlin 等等。
|
||||
|
||||
### 安装
|
||||
|
||||
@@ -36,15 +36,15 @@ sudo dnf install eclipse-pdt
|
||||
|
||||
### 示例项目
|
||||
|
||||
现在已经安装了 IDE,让我们创建一个简单的 PHP 项目。进入 _File →New → Project_。在出现的对话框中,选择 _PHP project_。输入项目的名称。你可能还需要更改其他一些选项,例如更改项目的默认位置,启用 JavaScript 以及更改 PHP 版本。请看以下截图。
|
||||
现在已经安装了 IDE,让我们创建一个简单的 PHP 项目。进入 “File →New → Project”。在出现的对话框中,选择 “PHP project”。输入项目的名称。你可能还需要更改其他一些选项,例如更改项目的默认位置,启用 JavaScript 以及更改 PHP 版本。请看以下截图。
|
||||
|
||||
![Create A New PHP Project in Eclipse][3]
|
||||
|
||||
你可以单击 _Finish_ 按钮创建项目,或按 _Next_ 配置其他选项,例如添加包含和构建路径。在大多数情况下,你无需更改这些设置。
|
||||
你可以单击 “Finish” 按钮创建项目,或按 “Next” 配置其他选项,例如添加包含和构建路径。在大多数情况下,你无需更改这些设置。
|
||||
|
||||
创建项目后,右键单击项目文件夹,然后选择 _New→PHP File_ 将新的 PHP 文件添加到项目。在本教程中,我将其命名为 _index.php_,这是每个 PHP 项目中公认的默认文件。
|
||||
创建项目后,右键单击项目文件夹,然后选择 “New→PHP File” 将新的 PHP 文件添加到项目。在本教程中,我将其命名为 `index.php`,这是每个 PHP 项目中公认的默认文件。
|
||||
|
||||
![][4]
|
||||
![add a new PHP file][4]
|
||||
|
||||
接着在新文件中添加代码。
|
||||
|
||||
@@ -52,9 +52,9 @@ sudo dnf install eclipse-pdt
|
||||
|
||||
在上面的例子中,我在同一页面上使用了 CSS、JavaScript 和 PHP 标记,主要是为了展示 IDE 能够支持所有这些标记。
|
||||
|
||||
页面完成后,你可以将文件移至 Web 服务器文档根目录或在项目目录中创建一个开发 PHP 服务器来查看输出。
|
||||
页面完成后,你可以将文件移至 Web 服务器文档根目录或在项目目录中创建一个 PHP 开发服务器来查看输出。
|
||||
|
||||
借助 Eclipse 中的内置终端,我们可以直接在 IDE 中启动 PHP 开发服务器。只需单击工具栏上的终端图标(![Terminal Icon][6]),然后单击 _OK_。在新终端中,进入项目目录,然后运行以下命令:
|
||||
借助 Eclipse 中的内置终端,我们可以直接在 IDE 中启动 PHP 开发服务器。只需单击工具栏上的终端图标(![Terminal Icon][6]),然后单击 “OK”。在新终端中,进入项目目录,然后运行以下命令:
|
||||
|
||||
```
|
||||
php -S localhost:8080 -t . index.php
|
||||
@@ -73,7 +73,7 @@ via: https://fedoramagazine.org/php-development-on-fedora-with-eclipse/
|
||||
作者:[Mehdi Haghgoo][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,236 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (heguangzhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11966-1.html)
|
||||
[#]: subject: (How to find what you’re looking for on Linux with find)
|
||||
[#]: via: (https://www.networkworld.com/article/3527420/how-to-find-what-you-re-looking-for-on-linux-with-find.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
通过 find 命令找到你要找的东西
|
||||
======
|
||||
|
||||
> find 命令有巨多的选项可以帮助你准确定位你在 Linux 系统上需要寻找的文件。这篇文章讨论了一系列非常有用的选项。
|
||||
|
||||

|
||||
|
||||
在 Linux 系统上有许多用于查找文件的命令,而你在使用它们时也有巨多的选项可以使用。
|
||||
|
||||
例如,你不仅可以通过文件的名称来查找文件,还可以通过文件的所有者或者组、它们的创建时间、大小、分配的权限、最后一次访问它们的时间、关联的信息节点,甚至是文件是否属于系统上不再存在的帐户或组等等来查找文件。
|
||||
|
||||
你还可以指定搜索从哪里开始,搜索应该深入到文件系统的什么位置,以及搜索结果将告诉你它所找到的文件的数量。
|
||||
|
||||
而所有这些要求都可以通过 `find` 命令来处理。
|
||||
|
||||
下面提供了根据这些要求查找文件的示例。在某些命令中,错误(例如试图列出你没有读取权限的文件)输出将被发送到 `/dev/null`,以便我们不必查看它。或者,我们可以简单地以 root 身份运行以避免这个问题。
|
||||
|
||||
请记住,还有更多的其他选项。这篇文章涵盖了很多内容,但并不是 `find` 命令帮助你定位查找文件的所有方式。
|
||||
|
||||
### 选择起点
|
||||
|
||||
使用 `find`,你可以选择一个起点或从你所在的位置开始。要选择的搜索的起点,请在单词 `find` 后输入它。例如,`find /usr` 或 `find ./bin` 将在 `/usr` 目录或当前位置下的 `bin` 目录开始搜索,而 `find ~` 将在你的主目录中开始搜索,即使你当前位于当前文件系统中的其他位置。
|
||||
|
||||
### 选择你要找的
|
||||
|
||||
最常用的搜索策略之一是按名称搜索文件。这需要使用 `-name` 选项。
|
||||
|
||||
默认情况下,`find` 会显示找到的文件的完整路径。如果你在命令中添加 `-print`,你会看到同样的结果。如果你想查看与文件相关的详细信息—-例如:文件的长度、权限等,你需要在你的 `find` 命令的末尾添加 `-ls` 参数。
|
||||
|
||||
```
|
||||
$ find ~/bin -name tryme
|
||||
/home/shs/bin/tryme
|
||||
$ find ~/bin -name tryme -print
|
||||
/home/shs/bin/tryme
|
||||
$ find ~/bin -name tryme -ls
|
||||
917528 4 -rwx------ 1 shs shs 139 Apr 8 2019 /home/shs/bin/tryme
|
||||
```
|
||||
|
||||
你也可以使用子字符串来查找文件。例如,如果你将上面示例中的 `tryme` 替换为 `try*`,你将会找到所有名称以 `try` 开头的文件。(LCTT 译注:如果要使用通配符 `*` ,请将搜索字符串放到单引号或双引号内,以避免通配符被 shell 所解释)
|
||||
|
||||
按名称查找文件可能是 `find` 命令最典型的用法,不过还有很多其他的方式来查找文件,并且有这样做的需要。下面的部分展示了如何使用其他可用的方式。
|
||||
|
||||
此外,当按文件大小、组、索引节点等条件来搜索文件时,你需要确认找到的文件与你要查找的文件是否相匹配。使用 `-ls` 选项来显示细节是非常有用。
|
||||
|
||||
### 通过大小查找文件
|
||||
|
||||
按大小查找文件需要使用 `-size` 选项并且对相应规范使用一点技巧。例如,如果你指定 `-size 189b`,你将找到 189 个块大小的文件,而不是 189 个字节。(LCTT 译注:如果不跟上单位,默认单位是 `b`。一个块是 512 个字节大小,不足或正好 512 个字节将占据一个块。)对于字节,你需要使用 `--size 189c`(字符)。而且,如果你指定 `--size 200w` ,你将会找到 200 个“<ruby>字<rt>word</rt></ruby>”的文件——以“双字节增量”为单位的字,而不是“我们互相谈论的那些事情”中的单词。你还可以通过以千字节(`k`)、兆字节(`M`)和千兆字节(`G`)为单位提供大小来查找文件。(LCTT 译注:乃至还有 `T`、`P`)
|
||||
|
||||
大多数情况下,Linux 用户会搜索比选定大小要大的文件。例如,要查找大于 1 千兆字节的文件,你可以使用这样的命令,其中 `+1G` 表示“大于 1 千兆字节”:
|
||||
|
||||
```
|
||||
$ find -size +1G -ls 2>/dev/null
|
||||
787715 1053976 -rw-rw-r-- 1 shs shs 1079263432 Dec 21 2018 ./backup.zip
|
||||
801834 1052556 -rw-rw-r-- 1 shs shs 1077809525 Dec 21 2018 ./2019/hold.zip
|
||||
```
|
||||
|
||||
### 通过索引节点号查找文件
|
||||
|
||||
你可以通过用于维护文件元数据(即除文件内容和文件名之外的所有内容)的索引节点来查找文件。
|
||||
|
||||
```
|
||||
$ find -inum 919674 -ls 2>/dev/null
|
||||
919674 4 -rw-rw-r-- 1 shs shs 512 Dec 27 15:25 ./bin/my.log
|
||||
```
|
||||
|
||||
### 查找具有特定文件所有者或组的文件
|
||||
|
||||
按所有者或组查找文件也非常简单。这里我们使用 `sudo` 来解决权限问题。
|
||||
|
||||
```
|
||||
$ sudo find /home -user nemo -name "*.png" -ls
|
||||
1705219 4 drwxr-xr-x 2 nemo nemo 4096 Jan 28 08:50 /home/nemo/Pictures/me.png
|
||||
```
|
||||
|
||||
在下面这个命令中,我们寻找一个被称为 `admins` 的多用户组拥有的文件。
|
||||
|
||||
```
|
||||
# find /tmp -group admins -ls
|
||||
262199 4 -rwxr-x--- 1 dory admins 27 Feb 16 18:57 /tmp/testscript
|
||||
```
|
||||
|
||||
### 查找没有所有者或组的文件
|
||||
|
||||
你可以使用如下命令所示的 `-nouser` 选项来查找不属于当前系统上的任何用户的文件。
|
||||
|
||||
```
|
||||
# find /tmp -nouser -ls
|
||||
262204 4 -rwx------ 1 1016 1016 17 Feb 17 16:42 /tmp/hello
|
||||
```
|
||||
|
||||
请注意,该列表显示了旧用户的 UID 和 GID,这清楚地表明该用户未在系统上定义。这种命令将查找帐户已从系统中删除的用户创建在主目录之外的文件,或者在用户帐户被删除后而未被删除的主目录中创建的文件。类似地,`-nogroup` 选项也会找到这样的文件,尤其是当这些用户是相关组的唯一成员时。
|
||||
|
||||
### 按上次更新时间查找文件
|
||||
|
||||
在此命令中,我们在特定用户的主目录中查找过去 24 小时内更新过的文件。`sudo` 用于搜索另一个用户的主目录。
|
||||
|
||||
```
|
||||
$ sudo find /home/nemo -mtime -1
|
||||
/home/nemo
|
||||
/home/nemo/snap/cheat
|
||||
/home/nemo/tryme
|
||||
```
|
||||
|
||||
### 按上次更改权限的时间查找文件
|
||||
|
||||
`-ctime` 选项可以帮助你查找在某个参考时间范围内状态(如权限)发生更改的文件。以下是查找在最后一天内权限发生更改的文件的示例:
|
||||
|
||||
```
|
||||
$ find . -ctime -1 -ls
|
||||
787987 4 -rwxr-xr-x 1 shs shs 189 Feb 11 07:31 ./tryme
|
||||
```
|
||||
|
||||
请记住,显示的日期和时间只反映了对文件内容进行的最后更新。你需要使用像 `stat` 这样的命令来查看与文件相关联的三个状态(文件创建、修改和状态更改)。
|
||||
|
||||
### 按上次访问的时间查找文件
|
||||
|
||||
在这个命令中,我们使用 `-atime` 选项查找在过去两天内访问过的本地 pdf 文件。
|
||||
|
||||
```
|
||||
$ find -name "*.pdf" -atime -2
|
||||
./Wingding_Invites.pdf
|
||||
```
|
||||
|
||||
### 根据文件相对于另一个文件的时间来查找文件
|
||||
|
||||
你可以使用 `-newer` 选项来查找比其他文件更新的文件。
|
||||
|
||||
```
|
||||
$ find . -newer dig1 -ls
|
||||
786434 68 drwxr-xr-x 67 shs shs 69632 Feb 16 19:05 .
|
||||
1064442 4 drwxr-xr-x 5 shs shs 4096 Feb 16 11:06 ./snap/cheat
|
||||
791846 4 -rw-rw-r-- 1 shs shs 649 Feb 13 14:26 ./dig
|
||||
```
|
||||
|
||||
没有相应的 `-older` 选项,但是你可以用 `! -newer` (即更旧)得到类似的结果,它们基本上一样。
|
||||
|
||||
### 按类型查找文件
|
||||
|
||||
通过文件类型找到一个文件,你有很多选项——常规文件、目录、块和字符文件等等。以下是文件类型选项列表:
|
||||
|
||||
```
|
||||
b 块特殊文件(缓冲的)
|
||||
c 字符特殊文件(无缓冲的)
|
||||
d 目录
|
||||
p 命名管道(FIFO)
|
||||
f 常规文件
|
||||
l 符号链接
|
||||
s 套接字
|
||||
```
|
||||
|
||||
这里有一个寻找符号链接的例子:
|
||||
|
||||
```
|
||||
$ find . -type l -ls
|
||||
805717 0 lrwxrwxrwx 1 shs shs 11 Apr 10 2019 ./volcano -> volcano.pdf
|
||||
918552 0 lrwxrwxrwx 1 shs shs 1 Jun 16 2018 ./letter -> pers/letter2mom
|
||||
```
|
||||
|
||||
### 限制查找的深度
|
||||
|
||||
`-mindepth` 和 `-maxdepth` 选项控制在文件系统中搜索的深度(从当前位置或起始点开始)。
|
||||
|
||||
```
|
||||
$ find -maxdepth 3 -name "*loop"
|
||||
./bin/save/oldloop
|
||||
./bin/long-loop
|
||||
./private/loop
|
||||
```
|
||||
|
||||
### 查找空文件
|
||||
|
||||
在这个命令中,我们寻找空文件,但不进入目录及其子目录。
|
||||
|
||||
```
|
||||
$ find . -maxdepth 2 -empty -type f -ls
|
||||
917517 0 -rw-rw-r-- 1 shs shs 0 Sep 23 11:00 ./complaints/newfile
|
||||
792050 0 -rw-rw-r-- 1 shs shs 0 Oct 4 19:02 ./junk
|
||||
```
|
||||
|
||||
### 按权限查找文件
|
||||
|
||||
你可以使用 `-perm` 选项查找具有特定权限集的文件。在下面的示例中,我们只查找常规文件(`-type f`),以避免看到符号链接,默认情况下符号链接被赋予了这种权限,即使它们所引用的文件是受限的。
|
||||
|
||||
```
|
||||
$ find -perm 777 -type f -ls
|
||||
find: ‘./.dbus’: Permission denied
|
||||
798748 4 -rwxrwxrwx 1 shs shs 15 Mar 28 2019 ./runme
|
||||
```
|
||||
|
||||
### 使用查找来帮助你删除文件
|
||||
|
||||
如果使用如下命令,你可以使用 `find` 命令定位并删除文件:
|
||||
|
||||
```
|
||||
$ find . -name runme -exec rm {} \;
|
||||
```
|
||||
|
||||
`{}` 代表根据搜索条件找到的每个文件的名称。
|
||||
|
||||
一个非常有用的选项是将 `-exec` 替换为 `-ok`。当你这样做时,`find` 会在删除任何文件之前要求确认。
|
||||
|
||||
```
|
||||
$ find . -name runme -ok rm -rf {} \;
|
||||
< rm ... ./bin/runme > ?
|
||||
```
|
||||
|
||||
删除文件并不是 `-ok` 和 `-exec` 能为你做的唯一事情。例如,你可以复制、重命名或移动文件。
|
||||
|
||||
确实有很多选择可以有效地使用 `find` 命令,毫无疑问还有一些在本文中没有涉及到。我希望你已经找到一些新的,特别有帮助的。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3527420/how-to-find-what-you-re-looking-for-on-linux-with-find.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][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://www.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.networkworld.com/newsletters/signup.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.facebook.com/NetworkWorld/
|
||||
[4]: https://www.linkedin.com/company/network-world
|
||||
@@ -1,31 +1,31 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11970-1.html)
|
||||
[#]: subject: (Use logzero for simple logging in Python)
|
||||
[#]: via: (https://opensource.com/article/20/2/logzero-python)
|
||||
[#]: author: (Ben Nuttall https://opensource.com/users/bennuttall)
|
||||
|
||||
使用 logzero 在 Python 中进行简单日志记录
|
||||
======
|
||||
一个方便的日志库快速入门,来帮助你掌握这个重要的编程概念。
|
||||
![Snake charmer cartoon with a yellow snake and a blue snake][1]
|
||||
|
||||
logzero 库使日志记录就像打印语句一样容易,是简单性的杰出代表。我不确定 logzero 的名称是否要与 pygame-zero、GPIO Zero 和 guizero 这样的 “zero 样板库”契合,但是肯定属于该类别。它是一个 Python 库,使得日志记录变得简单明了。
|
||||
> 快速了解一个方便的日志库,来帮助你掌握这个重要的编程概念。
|
||||
|
||||
你可以使用它的基本日志记录到标准输出,就像你可以使用 print 来获得信息和调试一样,它还有学习更高级日志记录(例如记录到文件)的平滑学习曲线。
|
||||

|
||||
|
||||
logzero 库使日志记录就像打印语句一样容易,是简单性的杰出代表。我不确定 logzero 的名称是否要与 pygame-zero、GPIO Zero 和 guizero 这样的 “zero 样板库”契合,但是肯定属于该类别。它是一个 Python 库,可以使日志记录变得简单明了。
|
||||
|
||||
你可以使用它基本的记录到标准输出的日志记录,就像你可以使用 print 来获得信息和调试一样,学习它的更高级日志记录(例如记录到文件)的学习曲线也很平滑。
|
||||
|
||||
首先,使用 pip 安装 logzero:
|
||||
|
||||
|
||||
```
|
||||
`$ sudo pip3 install logzero`
|
||||
$ sudo pip3 install logzero
|
||||
```
|
||||
|
||||
在 Python 文件中,导入 logger 并尝试以下一个或所有日志实例:
|
||||
|
||||
|
||||
```
|
||||
from logzero import logger
|
||||
|
||||
@@ -39,14 +39,13 @@ logger.error("error")
|
||||
|
||||
![Python, Raspberry Pi: import logger][2]
|
||||
|
||||
因此现在不要再使用 **print** 来了解发生了什么,而应使用有相关日志级别的 logger。
|
||||
因此现在不要再使用 `print` 来了解发生了什么,而应使用有相关日志级别的日志器。
|
||||
|
||||
### 在 Python 中将日志写入文件
|
||||
|
||||
如果你阅读至此,并会在你写代码时做一点改变,这对我就足够了。如果你要了解更多,请继续阅读!
|
||||
|
||||
写到**标准输出**对于测试新程序不错,但是仅当你登录到运行脚本的计算机时才有用。在很多时候,你需要远程执行代码并在事后查看错误。这种情况下,记录到文件很有帮助。让我们尝试一下:
|
||||
|
||||
写到标准输出对于测试新程序不错,但是仅当你登录到运行脚本的计算机时才有用。在很多时候,你需要远程执行代码并在事后查看错误。这种情况下,记录到文件很有帮助。让我们尝试一下:
|
||||
|
||||
```
|
||||
from logzero import logger, logfile
|
||||
@@ -54,32 +53,28 @@ from logzero import logger, logfile
|
||||
logfile('/home/pi/test.log')
|
||||
```
|
||||
|
||||
现在,你的日志条目将记录到文件 **test.log** 中。记住确保[脚本有权限] [3]写入该文件及其目录结构。
|
||||
现在,你的日志条目将记录到文件 `test.log` 中。记住确保[脚本有权限][3]写入该文件及其目录结构。
|
||||
|
||||
你也可以指定更多选项:
|
||||
|
||||
|
||||
```
|
||||
`logfile(’/home/pi/test.log’, maxBytes=1e6, backupCount=3)`
|
||||
logfile('/home/pi/test.log', maxBytes=1e6, backupCount=3)
|
||||
```
|
||||
|
||||
现在,当提供给 **logfile** 文件达到 1MB(10^6 字节)时,它将通过 **test.log.1**、**test.log.2** 等文件轮询写入。这种行为可以避免系统打开和关闭大量 I/O 密集的日志文件,以至于系统无法打开和关闭。你或许还要记录到 **/var/log**。假设你使用的是 Linux,那么创建一个目录并将用户设为所有者,以便可以写入该目录:
|
||||
|
||||
现在,当提供给 `test.log` 文件的数据达到 1MB(10^6 字节)时,它将通过 `test.log.1`、`test.log.2` 等文件轮替写入。这种行为可以避免系统打开和关闭大量 I/O 密集的日志文件,以至于系统无法打开和关闭。更专业一点,你或许还要记录到 `/var/log`。假设你使用的是 Linux,那么创建一个目录并将用户设为所有者,以便可以写入该目录:
|
||||
|
||||
```
|
||||
$ sudo mkdir /var/log/test
|
||||
$ sudo chown pi /var/log/test
|
||||
```
|
||||
|
||||
然后在你的 Python 代码中,更改 **logfile** 路径:
|
||||
|
||||
然后在你的 Python 代码中,更改 `logfile` 路径:
|
||||
|
||||
```
|
||||
`logfile(’/var/log/test/test.log’, maxBytes=1e6, backupCount=3)`
|
||||
logfile('/var/log/test/test.log', maxBytes=1e6, backupCount=3)
|
||||
```
|
||||
|
||||
当要在 **logfile** 中捕获异常时,可以使用 **logging.exception**:。
|
||||
|
||||
当要在 `logfile` 中捕获异常时,可以使用 `logging.exception`:
|
||||
|
||||
```
|
||||
try:
|
||||
@@ -88,8 +83,7 @@ except Exception as e:
|
||||
logger.exception(e)
|
||||
```
|
||||
|
||||
这将输出(在 b 为零的情况下):
|
||||
|
||||
这将输出(在 `b` 为零的情况下):
|
||||
|
||||
```
|
||||
[E 190422 23:41:59 test:9] division by zero
|
||||
@@ -99,8 +93,7 @@ except Exception as e:
|
||||
ZeroDivisionError: division by zero
|
||||
```
|
||||
|
||||
你会得到日志,还有完整回溯。另外,你可以使用 **logging.error** 并隐藏回溯:
|
||||
|
||||
你会得到日志,还有完整回溯。另外,你可以使用 `logging.error` 并隐藏回溯:
|
||||
|
||||
```
|
||||
try:
|
||||
@@ -111,28 +104,20 @@ except Exception as e:
|
||||
|
||||
现在,将产生更简洁的结果:
|
||||
|
||||
|
||||
```
|
||||
`[E 190423 00:04:16 test:9] ZeroDivisionError: division by zero`
|
||||
[E 190423 00:04:16 test:9] ZeroDivisionError: division by zero
|
||||
```
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
* * *
|
||||
|
||||
**![Logging output][4]**
|
||||
![Logging output][4]
|
||||
|
||||
你可以在 [logzero.readthedocs.io] [5] 中阅读更多选项。
|
||||
|
||||
### logzero 为教育而生
|
||||
|
||||
对于新手程序员来说,日志记录可能是一个具有挑战性的概念。大多数框架依赖于流控制和大量变量操作来生成有意义的日志,但是 logzero不同。由于它的语法类似于 print 语句,因此它在教育上很成功,因为它无需解释其他概念。在你的下个项目中试试它。
|
||||
对于新手程序员来说,日志记录可能是一个具有挑战性的概念。大多数框架依赖于流控制和大量变量操作来生成有意义的日志,但是 logzero 不同。由于它的语法类似于 `print` 语句,因此它在教育上很成功,因为它无需解释其他概念。在你的下个项目中试试它。
|
||||
|
||||
\--
|
||||
|
||||
_此文章最初发布在[我的博客] [6]上,经许可重新发布。_
|
||||
此文章最初发布在[我的博客][6]上,经许可重新发布。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -141,7 +126,7 @@ via: https://opensource.com/article/20/2/logzero-python
|
||||
作者:[Ben Nuttall][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/) 荣誉推出
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11971-1.html)
|
||||
[#]: subject: (Install GNU Emacs on Windows)
|
||||
[#]: via: (https://opensource.com/article/20/3/emacs-windows)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
在 Windows 上安装 GNU Emacs
|
||||
如何在 Windows 上安装 GNU Emacs
|
||||
======
|
||||
即使你的操作系统是闭源的,你仍然可以使用这个流行的开源文本编辑器。
|
||||
![Tall building with windows][1]
|
||||
|
||||
GNU Emacs 是一个专为各种程序员设计的流行的文本编辑器。因为它是在 Unix 上开发的,并在 Linux(macOS 中也有)上得到了广泛使用,所以人们有时没有意识到它也可用于 Microsoft Windows 上。你也无需成为有经验的或专职的程序员即可使用 Emacs。只需单击几下就可以下载并安装 Emacs,本文向你展示了如何进行。
|
||||
> 即使你的操作系统是闭源的,你仍然可以使用这个流行的开源文本编辑器。
|
||||
|
||||

|
||||
|
||||
GNU Emacs 是一个专为各种程序员设计的流行的文本编辑器。因为它是在 Unix 上开发的,并在 Linux(macOS 中也有)上得到了广泛使用,所以人们有时没有意识到它也可用于微软 Windows 上。你也无需成为有经验的或专职的程序员即可使用 Emacs。只需单击几下就可以下载并安装 Emacs,本文向你展示了如何进行。
|
||||
|
||||
你可以手动安装 Windows,也可以使用包管理器安装,例如 [Chocolatey][2]。
|
||||
|
||||
### 7-zip
|
||||
|
||||
如果还没在 Windows 中安装 7-zip,那么就先安装它。[7-zip][3] 是一个开源的存档程序,能够创建和解压 ZIP、7z、TAR、XZ、BZIP2 和 GZIP(以及更多)文件。对于 Windows 用户来说,这是一个宝贵的工具。
|
||||
如果还没在 Windows 中安装 7-zip,那么就先安装它。[7-zip][3] 是一个开源的归档程序,能够创建和解压 ZIP、7z、TAR、XZ、BZIP2 和 GZIP(以及更多)文件。对于 Windows 用户来说,这是一个宝贵的工具。
|
||||
|
||||
安装 7-zip 后,在 Windows 资源管理器中浏览文件时,右键单击菜单中就有新的 7-zip 存档选项。
|
||||
安装 7-zip 后,在 Windows 资源管理器中浏览文件时,右键单击菜单中就有新的 7-zip 归档选项。
|
||||
|
||||
### Powershell 和 Chocolatey
|
||||
|
||||
要在 Windows 上使用 Chocolatey 安装 GNU Emacs :
|
||||
|
||||
|
||||
```
|
||||
`PS> choco install emacs-full`
|
||||
PS> choco install emacs-full
|
||||
```
|
||||
|
||||
安装后,在 Powershell 中启动 Emacs:
|
||||
|
||||
|
||||
```
|
||||
`PS> emacs`
|
||||
PS> emacs
|
||||
```
|
||||
|
||||
![Emacs running on Windows][4]
|
||||
@@ -46,35 +46,35 @@ GNU Emacs 是一个专为各种程序员设计的流行的文本编辑器。因
|
||||
|
||||
![GNU Windows downloader][6]
|
||||
|
||||
它会打开连接到离你最近的服务器,并展示所有可用的 Emacs 版本。找到发行版本号最高的目录,然后单击进入。Windows 有许多不同的 Emacs 构建,但是最通用的版本只是被命名为 emacs-VERSION-ARCHITECTURE.zip。**VERSION** 取决于你要下载的版本,而 **ARCHITECTURE** 取决于你使用的是 32 位还是 64 位计算机。大多数现代计算机都是 64 位的,但是如果你有疑问,可以下载 32 位版本,它可在两者上运行。
|
||||
它会打开连接到离你最近的服务器,并展示所有可用的 Emacs 版本。找到发行版本号最高的目录,然后单击进入。Windows 有许多不同的 Emacs 构建,但是最通用的版本只是被命名为 `emacs-VERSION-ARCHITECTURE.zip`。`VERSION` 取决于你要下载的版本,而 `ARCHITECTURE` 取决于你使用的是 32 位还是 64 位计算机。大多数现代计算机都是 64 位的,但是如果你有疑问,可以下载 32 位版本,它可在两者上运行。
|
||||
|
||||
如果要下载 64 位计算机的 Emacs v26,你应该点击 emacs-26.2-x86_64.zip 的链接。有较小的下载包(例如 “no-deps” 等),但是你必须熟悉如何从源码构建 Emacs,知道它需要哪些库以及你的计算机上已经拥有哪些库。通常,获取较大版本的 Emacs 最容易,因为它包含了在计算机上运行所需的一切。
|
||||
如果要下载 64 位计算机的 Emacs v26,你应该点击 `emacs-26.2-x86_64.zip` 的链接。有较小的下载包(例如 “no-deps” 等),但是你必须熟悉如何从源码构建 Emacs,知道它需要哪些库以及你的计算机上已经拥有哪些库。通常,获取较大版本的 Emacs 最容易,因为它包含了在计算机上运行所需的一切。
|
||||
|
||||
### 解压 Emacs
|
||||
|
||||
接下来,解压下载的 ZIP 文件。要解压缩,请右键单击 Emacs ZIP 文件,然后从 7-zip 子菜单中选择 **Extract to Emacs-VERSION**。这是一个很大的压缩包,因此解压可能需要一段时间,但是完成后,你将拥有一个新目录,其中包含与 Emacs 一起分发的所有文件。例如,在此例中,下载了 emacs-26.2-x86_64.zip,因此解压后的目录为 emacs-26.2-x86_64。
|
||||
接下来,解压下载的 ZIP 文件。要解压缩,请右键单击 Emacs ZIP 文件,然后从 7-zip 子菜单中选择 “Extract to Emacs-VERSION”。这是一个很大的压缩包,因此解压可能需要一段时间,但是完成后,你将拥有一个新目录,其中包含与 Emacs 一起分发的所有文件。例如,在此例中,下载了 `emacs-26.2-x86_64.zip`,因此解压后的目录为 `emacs-26.2-x86_64`。
|
||||
|
||||
### 启动 Emacs
|
||||
|
||||
在 Emacs 目录中,找到 **bin** 目录。此文件夹存储随 Emacs 一起分发的所有二进制可执行文件(EXE 文件)。双击 emacs.exe 文件启动应用。
|
||||
在 Emacs 目录中,找到 `bin` 目录。此文件夹存储随 Emacs 一起分发的所有二进制可执行文件(EXE 文件)。双击 `emacs.exe` 文件启动应用。
|
||||
|
||||
![Emacs running on Windows][7]
|
||||
|
||||
你可以在桌面上创建 **emacs.exe** 的快捷方式,以便于访问。
|
||||
你可以在桌面上创建 `emacs.exe` 的快捷方式,以便于访问。
|
||||
|
||||
### 学习 Emacs
|
||||
|
||||
Emacs 并不像传闻那样难用。它具有自己的传统和惯例,但是当你其中输入文本时,你可以像在记事本或者网站的文本框中那样使用它。
|
||||
|
||||
重要的区别是在你_编辑_输入的文本时。
|
||||
重要的区别是在你*编辑*输入的文本时。
|
||||
|
||||
但是,学习的唯一方法是开始使用它,因此,使 Emacs 成为完成简单任务的首选文本编辑器。当你通常打开记事本、Word 或 Evernote 或其他工具来做快速笔记或临时记录时,请启动 Emacs。
|
||||
|
||||
Emacs 以基于终端的应用而闻名,但它显然有 GUI,因此请像使用其他程序一样经常使用它的 GUI。从菜单而不是使用键盘复制、剪切和粘贴(paste)(或用 Emacs 的术语 “yank”),然后从菜单或工具栏打开和保存文件。从头开始,并根据应用本身来学习它,而不是根据你以往对其他编辑器的经验就认为它应该是怎样。
|
||||
|
||||
### 下载[速查表][8]!
|
||||
- 下载[速查表][8]!
|
||||
|
||||
_感谢 Matthias Pfuetzner 和 Stephen Smoogen。_
|
||||
感谢 Matthias Pfuetzner 和 Stephen Smoogen。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -83,7 +83,7 @@ via: https://opensource.com/article/20/3/emacs-windows
|
||||
作者:[Seth Kenlon][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/) 荣誉推出
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11972-1.html)
|
||||
[#]: subject: (Drauger OS Linux Aims to Bring Console Gaming Experience on the Desktop)
|
||||
[#]: via: (https://itsfoss.com/drauger-os/)
|
||||
[#]: author: (John Paul https://itsfoss.com/author/john/)
|
||||
@@ -10,7 +10,7 @@
|
||||
Drauger OS Linux 旨在为台式机带来主机游戏体验
|
||||
======
|
||||
|
||||
多年来(或数十年),人们抱怨不[使用Linux][1] 的原因之一是缺乏主流游戏。[Linux 上的游戏][2]在最近几年有了显著改进,特别是 [Steam Proton][3] 项目的引入使你可以[在 Linux 上玩很多 Windows 专用的游戏][4]。
|
||||
多年来(或数十年),人们抱怨不[使用Linux][1] 的原因之一是它缺乏主流游戏。[Linux 上的游戏][2]在最近几年有了显著改进,特别是 [Steam Proton][3] 项目的引入使你可以[在 Linux 上玩很多 Windows 专用的游戏][4]。
|
||||
|
||||
这也鼓励了一些[以游戏为中心的 Linux发行版][5]。以 [Lakka][6] 为例,你可以[借助 Lakka Linux 将旧计算机变成复古的街机游戏机][7]。
|
||||
|
||||
@@ -34,9 +34,9 @@ Drauger OS 开箱即用地安装了多个应用程序和工具,以改善游戏
|
||||
* Steam
|
||||
* [DXVK][15]
|
||||
|
||||
它还具有一组与游戏无关的有趣工具。[Drauger Installer][16] 是 .deb 安装程序,是 Gdebi 的替代品。[多软件库应用安装器][17](mrai)是“用于基于 Debian 的 Linux 操作系统的类似于 AUR-helper 的脚本”。Mrai 旨在与 apt、snap、flatpaks 配合使用,并且可以从 GitHub 安装应用程序。
|
||||
它还具有一组与游戏无关的有趣工具。[Drauger 安装器][16]是 .deb 安装程序,是 Gdebi 的替代品。[多软件库应用安装器][17](mrai)是“用于基于 Debian 的 Linux 操作系统的类似于 AUR-helper 的脚本”。Mrai 旨在与 apt、snap、flatpaks 配合使用,并且可以从 GitHub 安装应用程序。
|
||||
|
||||
有趣的是,Drauger OS 的名称是一个错误。首席开发者 [Thomas Castleman][18](即 batcastle)曾打算为其发行版命名为 Draugr,但是却打错了名字。在 Drauger OS 播客的[第 23 集][19]中,Castleman 说保持这个拼写错误的名称,因为要对其进行更正需要大量工作。根据 [Wikipedia][20] 的描述,Draugr 是“来自北欧神话中的不死生物”。
|
||||
有趣的是,Drauger OS 的名称是一个错误。开发负责人 [Thomas Castleman][18](即 batcastle)曾打算为其发行版命名为 Draugr,但是却打错了名字。在 Drauger OS 播客的[第 23 集][19]中,Castleman 说会保留这个拼写错误的名称,因为要对其进行更正需要大量工作。根据 [Wikipedia][20] 的描述,Draugr 是“来自北欧神话中的不死生物”。
|
||||
|
||||
是的,你没看错。Drauger OS 是仅有的几个具有自己的[播客][21]的发行版之一。当被问到这个问题时,Castleman 告诉我:“无论他们的情况如何,我都希望确保我们的社区拥有最大的透明度。”多数情况下,播客是 Drauger OS 博客的音频版本,但有时他们会在没有时间撰写博客文章时使用它来发布公告。
|
||||
|
||||
@@ -44,7 +44,7 @@ Drauger OS 开箱即用地安装了多个应用程序和工具,以改善游戏
|
||||
|
||||
![Drauger OS][22]
|
||||
|
||||
Druager OS 背后的开发人员正在开发其下一个主要版本:7.5.1。此版本将基于 Ubuntu 19.10。将有三个主要变化。首先,将使用“我们内部构建的内核” [替换][23] Liquorix 内核。该内核将基于 Linux Kernel GitHub 存储库,“因此,它变得越来越原汁原味”。
|
||||
Druager OS 背后的开发人员正在开发其下一个主要版本:7.5.1。此版本将基于 Ubuntu 19.10。将有三个主要变化。首先,将使用“我们内部构建的内核” [替换][23] Liquorix 内核。该内核将基于 Linux 内核 GitHub 存储库,“因此,它会变得越来越原汁原味”。
|
||||
|
||||
新版本的第二个主要变化将是为其桌面提供新布局。根据用户的反馈,他们决定将其更改为看起来更类似于 GNOME 的样子。
|
||||
|
||||
@@ -64,7 +64,7 @@ Drauger OS [系统要求][25]非常适中。请记住,Drauger OS 仅在 64 位
|
||||
* 图形处理器:集成
|
||||
* 屏幕分辨率:60Hz 时为 1024×768
|
||||
* 外部端口:1 个用于显示的端口(HDMI/DisplayPort/VGA/DVI),2 个用于安装 USB 驱动器和键盘的 USB 端口(鼠标可选,但建议使用)
|
||||
|
||||
|
||||
#### 推荐系统要求
|
||||
|
||||
* CPU:四核、2.2Ghz、64 位处理器
|
||||
@@ -93,15 +93,15 @@ via: https://itsfoss.com/drauger-os/
|
||||
作者:[John Paul][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/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/john/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/why-use-linux/
|
||||
[2]: https://itsfoss.com/linux-gaming-guide/
|
||||
[3]: https://itsfoss.com/steam-play-proton/
|
||||
[2]: https://linux.cn/article-7316-1.html
|
||||
[3]: https://linux.cn/article-10054-1.html
|
||||
[4]: https://itsfoss.com/steam-play/
|
||||
[5]: https://itsfoss.com/linux-gaming-distributions/
|
||||
[6]: http://www.lakka.tv/
|
||||
@@ -0,0 +1,111 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How I learned about burnout the hard way)
|
||||
[#]: via: (https://opensource.com/article/20/3/burnout)
|
||||
[#]: author: (Jason Hibbets https://opensource.com/users/jhibbets)
|
||||
|
||||
How I learned about burnout the hard way
|
||||
======
|
||||
Burnout can happen to anyone. Here are the 3 things I wish I knew before
|
||||
I burned out.
|
||||
![Light bulb][1]
|
||||
|
||||
In early 2017, I was mentally in a bad spot. It was the perfect storm of stress, the kind that no one asks for, but you deal with the hand you're dealt. Work was piling up to a point where I couldn't process all the things that were expected of me. I was training for spring half-marathons, which should have been stress relief, but I was putting too much pressure on myself to perform at a high level. And then on top of the everyday family obligations, a surgery in our household turned us into a one-car family and seriously added to the mounting pressure on me to provide and take care of the family.
|
||||
|
||||
Then I broke.
|
||||
|
||||
It wasn't one thing. It was the culmination of things. And it hit me from the blind side, unexpected. I never thought I would be a victim of burnout. I was aware of it and thoughtful about the community I was managing. But "not me," I thought to myself, "I've got this under control." I remember thinking that something was wrong; something was off. But I couldn't quite put my finger on the source.
|
||||
|
||||
I distinctly remember the day where I cried at work, crumbling under the pressure that I was putting on myself. I consider myself a high performer in the office environment. I push myself to exceed the goals that my team co-creates because I want that success. I want the feeling that comes with it. But this experience was different. This wasn't a healthy win for my team or me. I felt like I let everyone down, including myself.
|
||||
|
||||
I was attending South by Southwest in Austin, Texas, where I was [presenting my first Ignite Talk][2] on applying open source principles to government—a talk that was well received by the audience. I remember practicing, and practicing, and practicing more the day before and the morning of my talk. I got that high that comes after delivering a great talk. I had a book signing at the City of Raleigh's Economic Development booth during the event, which was another emotional boost. Life was good. Upon reflection, that's when I started noticing signs of my burnout.
|
||||
|
||||
I didn't have much of an appetite. I was tired all the time. I was sleeping in, and not because of jet lag. I was exercising but wasn't getting the endorphins I was used to. And I wasn't motivated to do the work that I normally love to do. I was very blah and meh about getting work done or hanging out with people I love. These are all signs of depression and burnout.
|
||||
|
||||
After the trip, I scheduled my annual physical and talked to my doctor about my situation, who recommended I see a psychologist. I sat on the couch and talked things out. I was diagnosed with severe anxiety, which was enough for me to know that I didn't want to know what true depression felt like.
|
||||
|
||||
I learned my lesson the hard way. I'd like to share my experience so that you can recognize the signs and avoid going down this path. And before we move on, I must say that it's perfectly fine to ask for help. Ask a trusted co-worker or friend for help or guidance. We're human, and we need to help each other through the ups and the downs.
|
||||
|
||||
### Three things to know about burnout
|
||||
|
||||
Work burnout is a form of depression where you are not motivated to do the things that are expected of you at your job. It's not the occasional slacking off or spring fever because the weather is nice. It's a buildup of emotional stress where you don't want to do what is asked of you at work. There are numerous factors that can lead to burnout.
|
||||
|
||||
#### Know the signs of burnout
|
||||
|
||||
Lesson number one about burnout is to know the signs. I mentioned some of the things I was experiencing, but there are many others. I remember one thing that was extremely abnormal for me (because I'm so social) is that I started to separate myself from my usual team activities and people.
|
||||
|
||||
* Hey Jason, want to grab lunch with us? Nope, I'm too busy.
|
||||
* Hey Jason, Matt's in town, want to join us for happy hour? No. I've got work to do.
|
||||
|
||||
|
||||
|
||||
This is totally unlike me. I would normally have said yes to both those opportunities. According to the [Mayo Clinic][3], here are a few things to ask yourself if you think you are experiencing burnout:
|
||||
|
||||
* Do you drag yourself to work?
|
||||
* Do you have trouble getting started with work?
|
||||
* Are you cynical or critical at work?
|
||||
* Have you become irritable or impatient with co-workers or customers?
|
||||
* Do you lack the energy to be productive?
|
||||
* Do you find it hard to concentrate?
|
||||
* Do you lack satisfaction from your achievements?
|
||||
* Do you feel disillusioned about your work?
|
||||
* Are you using food, drugs, or alcohol to feel better or to simply not feel?
|
||||
* Have your sleep habits changed?
|
||||
* Are you troubled by unexplained headaches, stomach or bowel problems, or other physical complaints?
|
||||
|
||||
|
||||
|
||||
You can check your own burnout risk at [BurnoutIndex.org][4], an anonymous online questionnaire created in response to the [high level of burnout][5] in the tech industry.
|
||||
|
||||
#### Prevent burnout
|
||||
|
||||
The second lesson is to identify ways [to prevent burnout][6]. First, take time away from your job and plan time to unplug and unwind. This means planning vacations, staycations, or other time away from work. It's sometimes hard to unplug like this with the pressures and obligations we put on ourselves.
|
||||
|
||||
There are three different levels of paid time off (PTO):
|
||||
|
||||
1. **Best way to unplug:** I'm totally cut-off, not logging in, not checking email.
|
||||
2. **Decent way to unplug:** I'm kind of checking in, but not as responsive as normal.
|
||||
3. **Meh way to unplug:** I'm available if you need me, I'll monitor email, but I'm away from normal office life.
|
||||
|
||||
|
||||
|
||||
Your situation will dictate which of these levels of time off will work for you. In my experience, you need at least two total check-outs a year. I typically have a blend of all three throughout the year, but since 2017, I have taken at least three week-long vacations each year to completely escape. It's working so far!
|
||||
|
||||
#### Manage stress
|
||||
|
||||
The third and final lesson is to manage stress effectively. My first go-to for stress management is exercise. I'm addicted to it. I work out pretty much every single day. And I like to mix it up: Cardio, weight lifting, swimming, running, cycling, surfing, and high-intensity interval training (HIIT) are staples in my exercise routine. I used to focus solely on running four to six half marathons a year, but I recently switched to triathlons. The multidisciplinary aspect of the activity has brought more joy and different challenges to my life.
|
||||
|
||||
Another way to reduce stress is to manage your time better. Time is our most precious resource. You've got to choose how you want to spend your time. Family, work, self, social? It's up to you. Find ways to work more efficiently, more effectively, and make sure that you put yourself first. It may sound selfish, but as I've learned from the airplane preflight safety videos, "you need to put your mask on first before helping others."
|
||||
|
||||
### Conclusion
|
||||
|
||||
Burnout can lead to fatigue, excessive stress, sadness, anger, irritability, insomnia, alcohol or substance misuse, heart disease, and other medical conditions—all things that are not good for humans or for your team at work. I hope you can use these tips to put yourself first, reduce stress, and prevent burnout.
|
||||
|
||||
* * *
|
||||
|
||||
_Jason Hibbets will present "[10 things I wish I knew before experiencing burnout][7]" at [SCaLE 18x][8], March 5–8, 2020, in Pasadena, Calif. This article is a preview for the talk and a way to share a bit of his experience._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/burnout
|
||||
|
||||
作者:[Jason Hibbets][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jhibbets
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bulb-light-energy-power-idea.png?itok=zTEEmTZB (Light bulb)
|
||||
[2]: https://schedule.sxsw.com/2017/events/PP96070
|
||||
[3]: https://www.mayoclinic.org/healthy-lifestyle/adult-health/in-depth/burnout/art-20046642
|
||||
[4]: https://burnoutindex.org/
|
||||
[5]: https://opensource.com/article/19/11/burnout-open-source-communities
|
||||
[6]: https://www.redhat.com/sysadmin/tips-avoiding-burnout
|
||||
[7]: https://www.socallinuxexpo.org/scale/18x/presentations/10-things-i-wish-i-knew-experiencing-burnout
|
||||
[8]: https://www.socallinuxexpo.org/scale/18x/
|
||||
@@ -0,0 +1,115 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (The De-Googled Android Fork is Making Good Progress)
|
||||
[#]: via: (https://itsfoss.com/gael-duval-interview/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
The De-Googled Android Fork is Making Good Progress
|
||||
======
|
||||
|
||||
A couple years ago, we covered the [Eelo project][1]. If you remember, the Eelo project was started by [Gael Duval][2] who once created Mandrake Linux. The goal of the Eelo project was to remove all Google services from Android to give you an [alternate mobile operating system][3] that doesn’t track you and invade your privacy.
|
||||
|
||||
A lot has happened to Eelo since then. It’s not called Eelo anymore, now it’s called /e/. So, what’s happening with this project? We talked to Gael Duval himself. Here’s what he shared with us.
|
||||
|
||||
![][4]
|
||||
|
||||
_**Why did you create this Eelo or /e/ project in the first place?**_
|
||||
|
||||
**Gael:** In 2017, I realized that using Android and iPhone, Google and many mobile apps was not compatible with my personal privacy.
|
||||
|
||||
A later study by a US University confirmed this: using an iPhone or and Android phone sends between 6 to 12 MB of personal data to Google servers, daily! And this doesn’t count mobile apps.
|
||||
|
||||
So I looked for reasonable alternatives to iPhone and Android phones but didn’t find any. Either I found options for hobbyists, like Ubuntu Touch, that were not compatible with existing apps and not fully unGoogled either. Or there were alternative ROMs with all the Google fat inside, and no associated basic online services that could be used without tweaking the system.
|
||||
|
||||
Therefore, an idea came to mind: why not fork Android, remove all the Google features, even low level, such as connectivity check, DNS…, replace default apps with more virtuous apps, add basic online services, and integrate all this into a consistent form that could be used by Mum and Dad and any people without tech or expert knowledge?
|
||||
|
||||
_**How is it any different from other custom Android ROMs?**_
|
||||
|
||||
**Gael:** It doesn’t send a bit of data to Google, and is and will be more and more privacy-focused.
|
||||
|
||||
Low-level: we remove any Android feature that sends data to Google servers. Even the connectivity check when you start the smartphone! To my knowledge, there is not any other Android ROM that does this at the moment. We change default DNS settings and offer users an option to set the DNS of their choice. We change NTP (automatic time configuration) settings to the default NTP servers because there is no reason to use Google NTP servers actually. Then we remove Google services, and we replace with a software layout called microG that can still receive push notifications and have geolocation data for apps (using Mozilla geolocation service).
|
||||
|
||||
Then we change the default apps by non-Google apps, including the maps applications, mail etc., most are open source applications and I can say that there is 99% probability that all will be open source before the end of this year.
|
||||
|
||||
Then we add our own Android application installer, with close to 80 000 available applications at the moment.
|
||||
|
||||
We provide a different web browser, which is a fork of Chromium, were all features that data to Google are removed, and were the default search engine is not Google…
|
||||
|
||||
And we operate online services:
|
||||
|
||||
* search, using a meta-search system that we have improve for a better user experience
|
||||
* online drive with encrypted data, calendar etc. using a modified version of NextCloud
|
||||
* mail…
|
||||
|
||||
|
||||
|
||||
And for we provide a unique identifier that can be used to access all those services, either on the web or from the /e/ OS system, by login once. Then you can sync all your data, calendar, email etc. between your smartphone and your personal /e/ cloud (it can also be self-hosted).
|
||||
The purpose of the project is to provide a normal, ready to use, and attractive “digital life” to users, without sending all your personal data to Google.
|
||||
|
||||
_**If it is completely ‘ungoogled’, how do users install new apps? Do you have your own app store? If yes, how can we trust that these apps don’t spy on user data?**_
|
||||
|
||||
**Gael:** Yes – we have our own application installer, with about 80 000 applications. And we analyse each application to unveil the number of trackers, and we display this information to our users, for each application. We are also adding Progressive Web Apps soon to this application installer.
|
||||
|
||||
/e/ OS is about freedom of choice. We want the core system to be better, and then offer as many possible options to users, by informing them as much as possible. In short: they can still any application they need. Next step will be to offer a feature to actually block trackers used in applications.
|
||||
|
||||
_**What is the target user base for /e/? Can an average Joey use it without much trouble?**_
|
||||
|
||||
![][5]
|
||||
|
||||
**Gael:** We started with tech-savvy users, and we’re expanding the user base to people with less knowledge. At the moment, our typical user base is a mix of tech-savvy users, who can flash a smartphone with /e/ OS and people who are very concerned with Google and their data privacy but have very limited technical knowledge. For those people we have some smartphones pre-installed with /e/ OS for sale, on high-grade refurbished hardware.
|
||||
|
||||
We are also announcing this week an “/e/ easy installer” that will make the flashing process much more easier, by pluging the smartphone to a PC and launching a dedicated application that will make most of the job.
|
||||
|
||||
Then, the next step will be to expand our target users to a more global market, once we find the good partners. But clearly, there is a demand for something different than the Apple-Google worldwide market duopoly on the mobile.
|
||||
|
||||
_**Initially the project was named eelo and it is called /e/ or [e foundation][6]. Personally, I find the name /e/ weird and it is not easily recognizable. Why did you change the project name?**_
|
||||
|
||||
**Gael:** We have been “attacked” by a company called “eelloo”. They considered that “eelo” would interfere with their business. They are in the HR business solutions, but registered their trademark in all the classes related to mobile OS, smartphones etc. This is silly and a shame, but we had no money to defend us strongly at the time.
|
||||
|
||||
However the/e/ name will be abandonned for something else quite soon.
|
||||
|
||||
_**It’s been a couple of years since the initial launch. How do you see the adoption of /e/?**_
|
||||
|
||||
**Gael:** We launched the first beta 18 months ago, and we have started to sell smartphones with /e/ a little more than 6 months ago. The adoption is growing a lot at the moment, we have to add terabytes of online storage regularly!
|
||||
|
||||
Also with the /e/ installer arriving, and some official partnerships with some hardware mobile manufacturers in the pipe, this is going to accelerate a lot this year.
|
||||
|
||||
However, this is not surprising, privacy concerns are rising both for individuals and corporations, and I think the rejection of Google is also trending.
|
||||
|
||||
_**What are your future plans to grow /e/?**_
|
||||
|
||||
**Gael:** The growth is very natural. There is a strong community of users who realize how unique our approach is. These guys are contributing, supporting us and talking a lot about the project.
|
||||
|
||||
With the easy installer coming along and strategic partnerships with hardware makers, this is going to accelerate a lot.
|
||||
|
||||
Also, and this is more personal, I think that there is a natural connection between /e/ OS, and the Linux world. OK, /e/ OS is based on Android, but it’s still a Linux kernel and it’s the same spirit, it’s Open Source… So I’d really like to have more natural integration between my /e/ smartphone and my Linux desktop. There should be some nice features added in this spirit in the next versions of /e/ OS.
|
||||
|
||||
_**What can /e/ users and our readers do to help e foundation?**_
|
||||
|
||||
**Gael:** Join us, talk about what we are doing, send your feedback, organize some meetups… Help improve the /e/ Wikipedia page which is very poor and doesn’t represent at all what we are actually doing.
|
||||
|
||||
We also have a [permanent crowdfunding campaign where users can support the project financially][7], pay for the servers etc. And, in addition to giving back in term of open source product, we send cool stuff in return :)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/gael-duval-interview/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [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/eelo-mobile-os/
|
||||
[2]: https://en.wikipedia.org/wiki/Ga%C3%ABl_Duval
|
||||
[3]: https://itsfoss.com/open-source-alternatives-android/
|
||||
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/03/e-os-interview.jpg?ssl=1
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/e-foundation-smartphones.jpg?resize=800%2C590&ssl=1
|
||||
[6]: https://e.foundation/
|
||||
[7]: https://e.foundation/donate/
|
||||
@@ -1,72 +0,0 @@
|
||||
Fisherman110 translating
|
||||
|
||||
Exploring free and open web fonts
|
||||
======
|
||||
|
||||

|
||||
|
||||
There is no question that the face of the web has been transformed in recent years by open source fonts. Prior to 2010, the only typefaces you were likely to see in a web browser were the generic "web safe" [core fonts][1] from Microsoft. But that year saw the start of several revolutions: the introduction of the Web Open Font Format ([WOFF][2]), which offered an open standard for efficiently delivering font files over HTTP, and the launch of web-font services like [Google Fonts][3] and the [Open Font Library][4]—both of which offered web publishers access to a large collection of fonts, for free, available under open licenses.
|
||||
|
||||
It is hard to overstate the positive impact of these events on web typography. But it can be all too easy to equate the successes of open web fonts with open source typography as a whole and conclude that the challenges are behind us, the puzzles solved. That is not the case, so if you care about type, the good news is there are a lot of opportunities to get involved in improvement.
|
||||
|
||||
For starters, it's critical to understand that Google Fonts and Open Font Library offer a specialized service—delivering fonts in web pages—and they don't implement solutions for other use cases. That is not a shortcoming on the services' side; it simply means that we have to develop other solutions.
|
||||
|
||||
There are a number of problems to solve. Probably the most obvious example is the awkwardness of installing fonts on a desktop Linux machine for use in other applications. You can download any of the web fonts offered by either service, but all you will get is a generic ZIP file with some TTF or OTF binaries inside and a plaintext license file. What happens next is up to you to guess.
|
||||
|
||||
Most users learn quickly that the "right" step is to manually copy those font binaries into any one of a handful of special directories on their hard drive. But that just makes the files visible to the operating system; it doesn't offer much in the way of a user experience. Again, this is not a flaw with the web-font service; rather it's evidence of the point where the service stops and more work needs to be done on the other side.
|
||||
|
||||
A big improvement from the user's perspective would be for the OS or the desktop environment to be smarter at this "just downloaded" stage. Not only would it install the font files to the right location but, more importantly, it could add important metadata that the user will want to access when selecting a font to use in a project.
|
||||
|
||||
What this additional information consists of and how it is presented to the user is tied to another challenge: Managing a font collection on Linux is noticeably less pleasant than on other operating systems. Periodically, font manager applications appear (see [GTK+ Font Manager][5] for one of the most recent examples), but they rarely catch on. I've been thinking a lot about where I think they come up short; one core factor is they have limited themselves to displaying only the information embedded in the font binary: basic character-set coverage, weight/width/slope settings, embedded license and copyright statements, etc.
|
||||
|
||||
But a lot of decisions go into the process of selecting a font for a job besides what's in this embedded data. Serious font users—like information designers, journal article authors, or book designers—make their font-selection decisions in the context of each document's requirements and needs. That includes license information, naturally, but it includes much more, like information about the designer and the foundry, stylistic trends, or details about how the font works in use.
|
||||
|
||||
For example, if your document includes both English and Arabic text, you probably want a font where the Latin and Arabic glyphs were designed together by someone experienced with the two scripts. Otherwise, you'll waste a ton of time making tiny adjustments to the font sizes and line spacing trying to get the two languages to mix well. You may have learned from experience that certain designers or vendors are better at multi-script design than others. Or it might be relevant to your project that today's fashion magazines almost exclusively use "[Didone][6]"-style typefaces, a name that refers to super-high-contrast styles pioneered by [Firmin Didot][7] and [Giambattista Bodoni][8] around 200 years ago. It just happens to be the trend.
|
||||
|
||||
But none of those terms (Didone, Didot, or Bodoni) are likely to show up in the binary's embedded data, nor is easy to tell whether the Latin and Arabic fit together or anything else about the typeface's back history. That information might appear in supplementary material like a type specimen or font documentation—if any exists.
|
||||
|
||||
A specimen is a designed document (often a PDF) that shows the font in use and includes background information; it frequently serves a dual role as a marketing piece and a sample to look at when choosing a font. The considered design of a specimen showcases how the font functions in practice and in a manner that an automatically generated character table simply cannot. Documentation may include some other vital information, like how to activate the font's OpenType features, what mathematical or archaic forms it provides, or how it varies stylistically across supported languages. Making this sort of material available to the user in the font-management application would go a long way towards helping users find the fonts that fit their projects' needs.
|
||||
|
||||
Of course, if we're going to consider a font manager that can handle documentation and specimens, we also have to take a hard look at what comes with the font packages provided by distributions. Linux users start with a few fonts automatically installed, and repository-provided packages are the only font source most users have besides downloading the generic ZIP archive. Those packages tend to be pretty bare-bones. Commercial fonts generally include specimens, documentation, and other support items, whereas open source fonts usually do not.
|
||||
|
||||
There are some excellent examples of open fonts that do provide quality specimens and documentation (see [SIL Gentium][9] and [Bungee][10] for two distinctly different but valid approaches), but they rarely (if ever) make their way into the downstream packaging chain. We plainly can do better.
|
||||
|
||||
There are some technical obstacles to offering a richer user experience for interacting with the fonts on your system. For one thing, the [AppStream][11] metadata standard defines a few [parameters][12] specific to font files, but so far includes nothing that would cover specimens, designer and foundry information, and other relevant details. For another, the [SPDX][13] (Software Package Data Exchange) format does not cover many of the software licenses (and license variants) used to distribute fonts.
|
||||
|
||||
Finally, as any audiophile will tell you, a music player that does not let you edit and augment the ID3 tags in your MP3 collection is going to get frustrating quickly. You want to fix errors in the tags, you want to add things like notes and album art—essentially, you want to polish your library. You would want to do the same to keep your local font library in a pleasant-to-use state.
|
||||
|
||||
But editing the embedded data in a font file has been taboo because fonts tend to get embedded and attached to other documents. If you monkey with the fields in a font binary, then redistribute it with your presentation slides, anyone who downloads those slides can end up with bad metadata through no fault of their own. So anyone making improvements to the font-management experience will have to figure out how to strategically wrangle repeated changes to the embedded and external font metadata.
|
||||
|
||||
In addition to the technical angle, enriching the font-management experience is also a design challenge. As I said above, good specimens and well-written documentation exist for several open fonts. But there are many more packages missing both, and there are a lot of older font packages that are no longer being maintained. That probably means the only way that most open font packages are going to get specimens or documentation is for the community to create them.
|
||||
|
||||
Perhaps that's a tall order. But the open source design community is bigger than it has ever been, and it is a highly motivated segment of the overall free and open source software movement. So who knows; maybe this time next year finding, downloading, and using fonts on a desktop Linux system will be an entirely different experience.
|
||||
|
||||
One train of thought on the typography challenges of modern Linux users includes packaging, document design, and maybe even a few new software components for desktop environments. There are other trains to consider, too. The commonality is that where the web-font service ends, matters get more difficult.
|
||||
|
||||
The best news, from my perspective, is that there are more people interested in this topic than ever before. For that, I think we have the higher profile that open fonts have received from big web-font services like Google Fonts and Open Font Library to thank.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/3/webfonts
|
||||
|
||||
作者:[Nathan Willis][a]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/n8willis
|
||||
[1]:https://en.wikipedia.org/wiki/Core_fonts_for_the_Web
|
||||
[2]:https://en.wikipedia.org/wiki/Web_Open_Font_Format
|
||||
[3]:https://fonts.google.com/
|
||||
[4]:https://fontlibrary.org/
|
||||
[5]:https://fontmanager.github.io/
|
||||
[6]:https://en.wikipedia.org/wiki/Didone_(typography)
|
||||
[7]:https://en.wikipedia.org/wiki/Firmin_Didot
|
||||
[8]:https://en.wikipedia.org/wiki/Giambattista_Bodoni
|
||||
[9]:https://software.sil.org/gentium/
|
||||
[10]:https://djr.com/bungee/
|
||||
[11]:https://www.freedesktop.org/wiki/Distributions/AppStream/
|
||||
[12]:https://www.freedesktop.org/software/appstream/docs/sect-Metadata-Fonts.html
|
||||
[13]:https://spdx.org/
|
||||
@@ -1,229 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to structure a multi-file C program: Part 2)
|
||||
[#]: via: (https://opensource.com/article/19/7/structure-multi-file-c-part-2)
|
||||
[#]: author: (Erik O'Shaughnessy https://opensource.com/users/jnyjny)
|
||||
|
||||
How to structure a multi-file C program: Part 2
|
||||
======
|
||||
Dive deeper into the structure of a C program composed of multiple files
|
||||
in the second part of this article.
|
||||
![4 manilla folders, yellow, green, purple, blue][1]
|
||||
|
||||
In [Part 1][2], I laid out the structure for a multi-file C program called [MeowMeow][3] that implements a toy [codec][4]. I also talked about the Unix philosophy of program design, laying out a number of empty files to start with a good structure from the very beginning. Lastly, I touched on what a Makefile is and what it can do for you. This article picks up where the other one left off and now I'll get to the actual implementation of our silly (but instructional) MeowMeow codec.
|
||||
|
||||
The structure of the **main.c** file for **meow**/**unmeow** should be familiar to anyone who's read my article "[How to write a good C main function][5]." It has the following general outline:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow, a stream encoder/decoder */
|
||||
|
||||
/* 00 system includes */
|
||||
/* 01 project includes */
|
||||
/* 02 externs */
|
||||
/* 03 defines */
|
||||
/* 04 typedefs */
|
||||
/* 05 globals (but don't)*/
|
||||
/* 06 ancillary function prototypes if any */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* 07 variable declarations */
|
||||
/* 08 check argv[0] to see how the program was invoked */
|
||||
/* 09 process the command line options from the user */
|
||||
/* 10 do the needful */
|
||||
}
|
||||
|
||||
/* 11 ancillary functions if any */
|
||||
```
|
||||
|
||||
### Including project header files
|
||||
|
||||
The second section, **/* 01 project includes /***, reads like this from the source:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow, a stream encoder/decoder */
|
||||
...
|
||||
/* 01 project includes */
|
||||
#include "main.h"
|
||||
#include "mmecode.h"
|
||||
#include "mmdecode.h"
|
||||
```
|
||||
|
||||
The **#include** directive is a C preprocessor command that causes the contents of the named file to be "included" at this point in the file. If the programmer uses double-quotes around the name of the header file, the compiler will look for that file in the current directory. If the file is enclosed in <>, it will look for the file in a set of predefined directories.
|
||||
|
||||
The file [**main.h**][6] contains the definitions and typedefs used in [**main.c**][7]. I like to collect these things here in case I want to use those definitions elsewhere in my program.
|
||||
|
||||
The files [**mmencode.h**][8] and [**mmdecode.h**][9] are nearly identical, so I'll break down **mmencode.h**.
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.h - MeowMeow, a stream encoder/decoder */
|
||||
|
||||
#ifndef _MMENCODE_H
|
||||
#define _MMENCODE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int mm_encode(FILE *src, FILE *dst);
|
||||
|
||||
#endif /* _MMENCODE_H */
|
||||
```
|
||||
|
||||
The **#ifdef, #define, #endif** construction is collectively known as a "guard." This keeps the C compiler from including this file more than once per file. The compiler will complain if it finds multiple definitions/prototypes/declarations, so the guard is a _must-have_ for header files.
|
||||
|
||||
Inside the guard, there are only two things: an **#include** directive and a function prototype declaration. I include **stdio.h** here to bring in the definition of **FILE** that is used in the function prototype. The function prototype can be included by other C files to establish that function in the file's namespace. You can think of each file as a separate _namespace_, which means variables and functions in one file are not usable by functions or variables in another file.
|
||||
|
||||
Writing header files is complex, and it is tough to manage in larger projects. Use guards.
|
||||
|
||||
### MeowMeow encoding, finally
|
||||
|
||||
The meat and potatoes of this program—encoding and decoding bytes into/out of **MeowMeow** strings—is actually the easy part of this project. All of our activities until now have been putting the scaffolding in place to support calling this function: parsing the command line, determining which operation to use, and opening the files that we'll operate on. Here is the encoding loop:
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.c - MeowMeow, a stream encoder/decoder */
|
||||
...
|
||||
while (![feof][10](src)) {
|
||||
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
|
||||
for(i=0; i<[strlen][12](buf); i++) {
|
||||
lo = (buf[i] & 0x000f);
|
||||
hi = (buf[i] & 0x00f0) >> 4;
|
||||
[fputs][13](tbl[hi], dst);
|
||||
[fputs][13](tbl[lo], dst);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In plain English, this loop reads in a chunk of the file while there are chunks left to read (**feof(3)** and **fgets(3)**). Then it splits each byte in the chunk into **hi** and **lo** nibbles. Remember, a nibble is half of a byte, or 4 bits. The real magic here is realizing that 4 bits can encode 16 values. I use **hi** and **lo** as indices into a 16-string lookup table, **tbl**, that contains the **MeowMeow** strings that encode each nibble. Those strings are written to the destination **FILE** stream using **fputs(3)**, then we move on to the next byte in the buffer.
|
||||
|
||||
The table is initialized with a macro defined in [**table.h**][14] for no particular reason except to demonstrate including another project local header file, and I like initialization macros. We will go further into why a future article.
|
||||
|
||||
### MeowMeow decoding
|
||||
|
||||
Alright, I'll admit it took me a couple of runs at this before I got it working. The decode loop is similar: read a buffer full of **MeowMeow** strings and reverse the encoding from strings to bytes.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
int mm_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
if (!src || !dst) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return stupid_decode(src, dst);
|
||||
}
|
||||
```
|
||||
|
||||
Not what you were expecting?
|
||||
|
||||
Here, I'm exposing the function **stupid_decode()** via the externally visible **mm_decode()** function. When I say "externally," I mean outside this file. Since **stupid_decode()** isn't in the header file, it isn't available to be called in other files.
|
||||
|
||||
Sometimes we do this when we want to publish a solid public interface, but we aren't quite done noodling around with functions to solve a problem. In my case, I've written an I/O-intensive function that reads 8 bytes at a time from the source stream to decode 1 byte to write to the destination stream. A better implementation would work on a buffer bigger than 8 bytes at a time. A _much_ better implementation would also buffer the output bytes to reduce the number of single-byte writes to the destination stream.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
int stupid_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
char buf[9];
|
||||
decoded_byte_t byte;
|
||||
int i;
|
||||
|
||||
while (![feof][10](src)) {
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
byte.field.f0 = [isupper][15](buf[0]);
|
||||
byte.field.f1 = [isupper][15](buf[1]);
|
||||
byte.field.f2 = [isupper][15](buf[2]);
|
||||
byte.field.f3 = [isupper][15](buf[3]);
|
||||
byte.field.f4 = [isupper][15](buf[4]);
|
||||
byte.field.f5 = [isupper][15](buf[5]);
|
||||
byte.field.f6 = [isupper][15](buf[6]);
|
||||
byte.field.f7 = [isupper][15](buf[7]);
|
||||
|
||||
[fputc][16](byte.value, dst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Instead of using the bit-shifting technique I used in the encoder, I elected to create a custom data structure called **decoded_byte_t**.
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow, a stream decoder/decoder */
|
||||
...
|
||||
|
||||
typedef struct {
|
||||
unsigned char f7:1;
|
||||
unsigned char f6:1;
|
||||
unsigned char f5:1;
|
||||
unsigned char f4:1;
|
||||
unsigned char f3:1;
|
||||
unsigned char f2:1;
|
||||
unsigned char f1:1;
|
||||
unsigned char f0:1;
|
||||
} fields_t;
|
||||
|
||||
typedef union {
|
||||
fields_t field;
|
||||
unsigned char value;
|
||||
} decoded_byte_t;
|
||||
```
|
||||
|
||||
It's a little complex when viewed all at once, but hang tight. The **decoded_byte_t** is defined as a **union** of a **fields_t** and an **unsigned char**. The named members of a union can be thought of as aliases for the same region of memory. In this case, **value** and **field** refer to the same 8-bit region of memory. Setting **field.f0** to 1 would also set the least significant bit in **value**.
|
||||
|
||||
While **unsigned char** shouldn't be a mystery, the **typedef** for **fields_t** might look a little unfamiliar. Modern C compilers allow programmers to specify "bit fields" in a **struct**. The field type needs to be an unsigned integral type, and the member identifier is followed by a colon and an integer that specifies the length of the bit field.
|
||||
|
||||
This data structure makes it simple to access each bit in the byte by field name and then access the assembled value via the **value** field of the union. We depend on the compiler to generate the correct bit-shifting instructions to access the fields, which can save you a lot of heartburn when you are debugging.
|
||||
|
||||
Lastly, **stupid_decode()** is _stupid_ because it only reads 8 bytes at a time from the source **FILE** stream. Usually, we try to minimize the number of reads and writes to improve performance and reduce our cost of system calls. Remember that reading or writing a bigger chunk less often is much better than reading/writing a lot of smaller chunks more frequently.
|
||||
|
||||
### The wrap-up
|
||||
|
||||
Writing a multi-file program in C requires a little more planning on behalf of the programmer than just a single **main.c**. But just a little effort up front can save a lot of time and headache when you refactor as you add functionality.
|
||||
|
||||
To recap, I like to have a lot of files with a few short functions in them. I like to expose a small subset of the functions in those files via header files. I like to keep my constants in header files, both numeric and string constants. I _love_ Makefiles and use them instead of Bash scripts to automate all sorts of things. I like my **main()** function to handle command-line argument parsing and act as a scaffold for the primary functionality of the program.
|
||||
|
||||
I know I've only touched the surface of what's going on in this simple program, and I'm excited to learn what things were helpful to you and which topics need better explanations. Share your thoughts in the comments to let me know.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/7/structure-multi-file-c-part-2
|
||||
|
||||
作者:[Erik O'Shaughnessy][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jnyjny
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/file_system.jpg?itok=pzCrX1Kc (4 manilla folders, yellow, green, purple, blue)
|
||||
[2]: https://opensource.com/article/19/7/how-structure-multi-file-c-program-part-1
|
||||
[3]: https://github.com/jnyjny/MeowMeow.git
|
||||
[4]: https://en.wikipedia.org/wiki/Codec
|
||||
[5]: https://opensource.com/article/19/5/how-write-good-c-main-function
|
||||
[6]: https://github.com/JnyJny/meowmeow/blob/master/main.h
|
||||
[7]: https://github.com/JnyJny/meowmeow/blob/master/main.c
|
||||
[8]: https://github.com/JnyJny/meowmeow/blob/master/mmencode.h
|
||||
[9]: https://github.com/JnyJny/meowmeow/blob/master/mmdecode.h
|
||||
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[11]: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html
|
||||
[12]: http://www.opengroup.org/onlinepubs/009695399/functions/strlen.html
|
||||
[13]: http://www.opengroup.org/onlinepubs/009695399/functions/fputs.html
|
||||
[14]: https://github.com/JnyJny/meowmeow/blob/master/table.h
|
||||
[15]: http://www.opengroup.org/onlinepubs/009695399/functions/isupper.html
|
||||
[16]: http://www.opengroup.org/onlinepubs/009695399/functions/fputc.html
|
||||
@@ -1,238 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (caiichenr)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Building a non-breaking breakpoint for Python debugging)
|
||||
[#]: via: (https://opensource.com/article/19/8/debug-python)
|
||||
[#]: author: (Liran Haimovitch https://opensource.com/users/liranhaimovitch)
|
||||
|
||||
Building a non-breaking breakpoint for Python debugging
|
||||
======
|
||||
Have you ever wondered how to speed up a debugger? Here are some lessons
|
||||
learned while building one for Python.
|
||||
![Real python in the graphic jungle][1]
|
||||
|
||||
This is the story of how our team at [Rookout][2] built non-breaking breakpoints for Python and some of the lessons we learned along the way. I'll be presenting all about the nuts and bolts of debugging in Python at [PyBay 2019][3] in San Francisco this month. Let's dig in.
|
||||
|
||||
### The heart of Python debugging: sys.set_trace
|
||||
|
||||
There are many Python debuggers out there. Some of the more popular include:
|
||||
|
||||
* **pdb**, part of the Python standard library
|
||||
* **PyDev**, the debugger behind the Eclipse and PyCharm IDEs
|
||||
* **ipdb**, the IPython debugger
|
||||
|
||||
|
||||
|
||||
Despite the range of choices, almost every Python debugger is based on just one function: **sys.set_trace**. And let me tell you, **[sys.settrace][4]** might just be the most complex function in the Python standard library.
|
||||
|
||||
![set_trace Python 2 docs page][5]
|
||||
|
||||
In simpler terms, **settrace** registers a trace function for the interpreter, which may be called in any of the following cases:
|
||||
|
||||
* Function call
|
||||
* Line execution
|
||||
* Function return
|
||||
* Exception raised
|
||||
|
||||
|
||||
|
||||
A simple trace function might look like this:
|
||||
|
||||
|
||||
```
|
||||
def simple_tracer(frame, event, arg):
|
||||
co = frame.f_code
|
||||
func_name = co.co_name
|
||||
line_no = frame.f_lineno
|
||||
print("{e} {f} {l}".format(
|
||||
e=event, f=func_name, l=line_no))
|
||||
return simple_tracer
|
||||
```
|
||||
|
||||
When looking at this function, the first things that come to mind are its arguments and return values. The trace function arguments are:
|
||||
|
||||
* **frame** object, which is the full state of the interpreter at the point of the function's execution
|
||||
* **event** string, which can be **call**, **line**, **return**, or **exception**
|
||||
* **arg** object, which is optional and depends on the event type
|
||||
|
||||
|
||||
|
||||
The trace function returns itself because the interpreter keeps track of two kinds of trace functions:
|
||||
|
||||
* **Global trace function (per thread):** This trace function is set for the current thread by **sys.settrace** and is invoked whenever a new **frame** is created by the interpreter (essentially on every function call). While there's no documented way to set the trace function for a different thread, you can call **threading.settrace** to set the trace function for all newly created **threading** module threads.
|
||||
* **Local trace function (per frame):** This trace function is set by the interpreter to the value returned by the global trace function upon frame creation. There's no documented way to set the local trace function once the frame has been created.
|
||||
|
||||
|
||||
|
||||
This mechanism is designed to allow the debugger to have more granular control over which frames are traced to reduce performance impact.
|
||||
|
||||
### Building our debugger in three easy steps (or so we thought)
|
||||
|
||||
With all that background, writing your own debugger using a custom trace function looks like a daunting task. Luckily, **pdb**, the standard Python debugger, is built on top of **Bdb**, a base class for building debuggers.
|
||||
|
||||
A naive breakpoints debugger based on **Bdb** might look like this:
|
||||
|
||||
|
||||
```
|
||||
import bdb
|
||||
import inspect
|
||||
|
||||
class Debugger(bdb.Bdb):
|
||||
def __init__(self):
|
||||
Bdb.__init__(self)
|
||||
self.breakpoints = dict()
|
||||
self.set_trace()
|
||||
|
||||
def set_breakpoint(self, filename, lineno, method):
|
||||
self.set_break(filename, lineno)
|
||||
try :
|
||||
self.breakpoints[(filename, lineno)].add(method)
|
||||
except KeyError:
|
||||
self.breakpoints[(filename, lineno)] = [method]
|
||||
|
||||
def user_line(self, frame):
|
||||
if not self.break_here(frame):
|
||||
return
|
||||
|
||||
# Get filename and lineno from frame
|
||||
(filename, lineno, _, _, _) = inspect.getframeinfo(frame)
|
||||
|
||||
methods = self.breakpoints[(filename, lineno)]
|
||||
for method in methods:
|
||||
method(frame)
|
||||
```
|
||||
|
||||
All this does is:
|
||||
|
||||
1. Inherits from **Bdb** and write a simple constructor initializing the base class and tracing.
|
||||
2. Adds a **set_breakpoint** method that uses **Bdb** to set the breakpoint and keeps track of our breakpoints.
|
||||
3. Overrides the **user_line** method that is called by **Bdb** on certain user lines. The function makes sure it is being called for a breakpoint, gets the source location, and invokes the registered breakpoints
|
||||
|
||||
|
||||
|
||||
### How well did the simple Bdb debugger work?
|
||||
|
||||
Rookout is about bringing a debugger-like user experience to production-grade performance and use cases. So, how well did our naive breakpoint debugger perform?
|
||||
|
||||
To test it and measure the global performance overhead, we wrote two simple test methods and executed each of them 16 million times under multiple scenarios. Keep in mind that no breakpoint was executed in any of the cases.
|
||||
|
||||
|
||||
```
|
||||
def empty_method():
|
||||
pass
|
||||
|
||||
def simple_method():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
e = 5
|
||||
f = 6
|
||||
g = 7
|
||||
h = 8
|
||||
i = 9
|
||||
j = 10
|
||||
```
|
||||
|
||||
Using the debugger takes a shocking amount of time to complete. The bad results make it clear that our naive **Bdb** debugger is not yet production-ready.
|
||||
|
||||
![First Bdb debugger results][6]
|
||||
|
||||
### Optimizing the debugger
|
||||
|
||||
There are three main ways to reduce debugger overhead:
|
||||
|
||||
1. **Limit local tracing as much as possible:** Local tracing is very costly compared to global tracing due to the much larger number of events per line of code.
|
||||
2. **Optimize "call" events and return control to the interpreter faster:** The main work in **call** events is deciding whether or not to trace.
|
||||
3. **Optimize "line" events and return control to the interpreter faster:** The main work in **line** events is deciding whether or not we hit a breakpoint.
|
||||
|
||||
|
||||
|
||||
So we forked **Bdb**, reduced the feature set, simplified the code, optimized for hot code paths, and got impressive results. However, we were still not satisfied. So, we took another stab at it, migrated and optimized our code to **.pyx**, and compiled it using [Cython][7]. The final results (as you can see below) were still not good enough. So, we ended up diving into CPython's source code and realizing we could not make tracing fast enough for production use.
|
||||
|
||||
![Second Bdb debugger results][8]
|
||||
|
||||
### Rejecting Bdb in favor of bytecode manipulation
|
||||
|
||||
After our initial disappointment from the trial-and-error cycles of standard debugging methods, we decided to look into a less obvious option: bytecode manipulation.
|
||||
|
||||
The Python interpreter works in two main stages:
|
||||
|
||||
1. **Compiling Python source code into Python bytecode:** This unreadable (for humans) format is optimized for efficient execution and is often cached in those **.pyc** files we have all come to love.
|
||||
2. **Iterating through the bytecode in the _interpreter loop_:** This executes one instruction at a time.
|
||||
|
||||
|
||||
|
||||
This is the pattern we chose: use **bytecode manipulation** to set **non-breaking breakpoints** with no global overhead. This is done by finding the bytecode in memory that represents the source line we are interested in and inserting a function call just before the relevant instruction. This way, the interpreter does not have to do any extra work to support our breakpoints.
|
||||
|
||||
This approach is not magic. Here's a quick example.
|
||||
|
||||
We start with a very simple function:
|
||||
|
||||
|
||||
```
|
||||
def multiply(a, b):
|
||||
result = a * b
|
||||
return result
|
||||
```
|
||||
|
||||
In documentation hidden in the **[inspect][9]** module (which has several useful utilities), we learn we can get the function's bytecode by accessing **multiply.func_code.co_code**:
|
||||
|
||||
|
||||
```
|
||||
`'|\x00\x00|\x01\x00\x14}\x02\x00|\x02\x00S'`
|
||||
```
|
||||
|
||||
This unreadable string can be improved using the **[dis][10]** module in the Python standard library. By calling **dis.dis(multiply.func_code.co_code)**, we get:
|
||||
|
||||
|
||||
```
|
||||
4 0 LOAD_FAST 0 (a)
|
||||
3 LOAD_FAST 1 (b)
|
||||
6 BINARY_MULTIPLY
|
||||
7 STORE_FAST 2 (result)
|
||||
|
||||
5 10 LOAD_FAST 2 (result)
|
||||
13 RETURN_VALUE
|
||||
```
|
||||
|
||||
This gets us closer to understanding what happens behind the scenes of debugging but not to a straightforward solution. Unfortunately, Python does not offer a method for changing a function's bytecode from within the interpreter. You can overwrite the function object, but that's not good enough for the majority of real-world debugging scenarios. You have to go about it in a roundabout way using a native extension.
|
||||
|
||||
### Conclusion
|
||||
|
||||
When building a new tool, you invariably end up learning a lot about how stuff works. It also makes you think out of the box and keep your mind open to unexpected solutions.
|
||||
|
||||
Working on non-breaking breakpoints for Rookout has taught me a lot about compilers, debuggers, server frameworks, concurrency models, and much much more. If you are interested in learning more about bytecode manipulation, Google's open source **[cloud-debug-python][11]** has tools for editing bytecode.
|
||||
|
||||
* * *
|
||||
|
||||
_Liran Haimovitch will present "[Understanding Python’s Debugging Internals][12]" at [PyBay][3], which will be held August 17-18 in San Francisco. Use code [OpenSource35][13] for a discount when you purchase your ticket to let them know you found out about the event from our community._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/debug-python
|
||||
|
||||
作者:[Liran Haimovitch][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/liranhaimovitch
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python_jungle_lead.jpeg?itok=pFKKEvT- (Real python in the graphic jungle)
|
||||
[2]: https://rookout.com/
|
||||
[3]: https://pybay.com/
|
||||
[4]: https://docs.python.org/3/library/sys.html#sys.settrace
|
||||
[5]: https://opensource.com/sites/default/files/uploads/python2docs.png (set_trace Python 2 docs page)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/debuggerresults1.png (First Bdb debugger results)
|
||||
[7]: https://cython.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/debuggerresults2.png (Second Bdb debugger results)
|
||||
[9]: https://docs.python.org/2/library/inspect.html
|
||||
[10]: https://docs.python.org/2/library/dis.html
|
||||
[11]: https://github.com/GoogleCloudPlatform/cloud-debug-python
|
||||
[12]: https://pybay.com/speaker/liran-haimovitch/
|
||||
[13]: https://ti.to/sf-python/pybay2019/discount/OpenSource35
|
||||
@@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (cycoe)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Session: An Open Source Private Messenger That Doesn’t Need Your Phone Number)
|
||||
[#]: via: (https://itsfoss.com/session-messenger/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Session: An Open Source Private Messenger That Doesn’t Need Your Phone Number
|
||||
======
|
||||
|
||||
_**Brief: Our open source software highlight of the week is Session. It is a fork of another increasingly popular private messenger Signal. Session doesn’t even need your phone number to operate.**_
|
||||
|
||||
### Session: A private messenger in true sense
|
||||
|
||||
![][1]
|
||||
|
||||
Privacy concerned people are always in the search of an ultimate service that lets you communicate securely while respecting our privacy across multiple platforms.
|
||||
|
||||
Recently, I came across an interesting open-source messaging app “[Session][2]” by [Loki Foundation][3], which is technically a fork of another [open source encrypted messenger Signal][4].
|
||||
|
||||
In this article, I’ll be sharing my experience with the Session app while highlighting the features it offers.
|
||||
|
||||
Session is fairly new to the scene – I’ve mentioned some of the bugs that I encountered at the bottom of the article.
|
||||
|
||||
### Features of Session Messenger
|
||||
|
||||
I’ll highlight the key features of Session that will help you decide if it’s good enough for you to try.
|
||||
|
||||
#### Session does not require a phone number
|
||||
|
||||
![][5]
|
||||
|
||||
For privacy-enthusiasts, registering the phone number with Signal or other such applications is a potential risk.
|
||||
|
||||
But, with Session, you do not need a phone number, simply click on “**Create Account**” after you install it on your desktop or phone and it will simply generate a random (unique) **Session ID**.
|
||||
|
||||
It’ll look something like this: **05652245af9a8bfee4f5a8138fd5c……..**
|
||||
|
||||
So, you just have to share your Session ID with the contact you want to add. Or, you can also opt to get the **QR Code** after account creation which you can share with your friends to add you back.
|
||||
|
||||
#### Session uses blockchain (and other crypto tech)
|
||||
|
||||
![Session ID][6]
|
||||
|
||||
For the users who’re aware of what a [blockchain][7] is – they’ve been waiting for real-world applications that an average user can utilize. Session is one such example that utilizes blockchain at its core and you don’t need to know it’s there.
|
||||
|
||||
If you’re curious about how it works, you can take a look at their [official blog post][8] explaining it.
|
||||
|
||||
#### Cross-Platform Support
|
||||
|
||||
![][9]
|
||||
|
||||
For something strictly privacy-focused, you’d also want it to be available across multiple platforms.
|
||||
|
||||
Of course, primarily, I’d focus on the Linux and Android support but it also supports Windows/Mac/iOS. So, you can easily sync between multiple devices cross-platform.
|
||||
|
||||
#### Includes Essential Privacy Options
|
||||
|
||||
![][10]
|
||||
|
||||
Undoubtedly, it offers some essential privacy-focused features that will help make the experience more secure.
|
||||
|
||||
For starters, you have the following options:
|
||||
|
||||
* **Message TTL**: This lets you control how long the message exists before the recipient sees the message.
|
||||
* **Read Receipts**: Let others know that you’ve seen the message or if your message has been read.
|
||||
|
||||
|
||||
|
||||
#### Session uses a decentralized network and protects your metadata
|
||||
|
||||
Even though Session isn’t a peer-to-peer technology, it does not have a central server for the network.
|
||||
|
||||
It takes a decentralized approach to how the messages are transmitted (or routed). If you’ve no idea what I’m talking about, you can follow Session’s official blog post to know the [difference between centralization and decentralization][11] and explore how it potentially works.
|
||||
|
||||
And, this approach of network helps them to protect the metadata (the information associated with a message like IP address).
|
||||
|
||||
#### Other Features
|
||||
|
||||
Not just limited to the latest/greatest privacy-friendly features, but it also supports group chats, voice messages, and also allows you to send attachments.
|
||||
|
||||
### Installing Session on Linux
|
||||
|
||||
If you head to the [official download page][12], you will be able to download an .**AppImage** file. In case you have no clue how it works, you should take a look at our article on [how to use AppImage][13].
|
||||
|
||||
In either case, you can also head to their [GitHub releases page][14] and grab the **.deb** file.
|
||||
|
||||
[Download Session][12]
|
||||
|
||||
### My Experience On Using Session App
|
||||
|
||||
I’ve managed to try it on multiple platforms. For the desktop, I utilized the .AppImage file on **Pop!_OS 19.10** to run Session.
|
||||
|
||||
Overall, the user experience was impressive and had no UI glitches.
|
||||
|
||||
It’s also easy to recover your account once you’ve backed up your secret code (which is known as **seed**) from the settings.
|
||||
|
||||
![][15]
|
||||
|
||||
But, I also noticed a couple of issues- which can be fixed/improved:
|
||||
|
||||
* Delay in accepting a friend request
|
||||
* The way of linking devices is not intuitive
|
||||
* Sometimes when you reply from two separate devices (using the same ID), the receiver gets two different conversations.
|
||||
|
||||
|
||||
|
||||
**Conclusion**
|
||||
|
||||
Of course, nothing’s ever perfect. For now, I’m thinking of keeping it installed and considering Session’s features, it is definitely something a privacy-focused user should try.
|
||||
|
||||
What do you think about it? Feel free to let me know your thoughts in the comments below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/session-messenger/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [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/session-app.jpg?ssl=1
|
||||
[2]: https://getsession.org/
|
||||
[3]: https://loki.foundation/
|
||||
[4]: https://itsfoss.com/signal-messaging-app/
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-create.jpg?ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/session-application-id.jpg?ssl=1
|
||||
[7]: https://en.wikipedia.org/wiki/Blockchain
|
||||
[8]: https://getsession.org/how-session-protects-your-anonymity-with-blockchain-and-crypto/
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-cross-platform.jpg?ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-settings.jpg?fit=800%2C512&ssl=1
|
||||
[11]: https://getsession.org/centralisation-vs-decentralisation-in-private-messaging/
|
||||
[12]: https://getsession.org/download/
|
||||
[13]: https://itsfoss.com/use-appimage-linux/
|
||||
[14]: https://github.com/loki-project/session-desktop/releases
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-seed.jpg?ssl=1
|
||||
@@ -0,0 +1,148 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Communicating with other users on the Linux command line)
|
||||
[#]: via: (https://www.networkworld.com/article/3530343/communicating-with-other-users-on-the-linux-command-line.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
Communicating with other users on the Linux command line
|
||||
======
|
||||
|
||||
Thinkstock / Linux
|
||||
|
||||
Sending messages to other users on the Linux command line can be very easy, but there are a number of commands that you might want to consider. In this post, we’ll look at four commands and see how each of them works.
|
||||
|
||||
### wall
|
||||
|
||||
The **wall** command (as in "write all") allows you to send a message to all users who are currently logged into the system. This implies that the system is likely a server and that users are working on the command line. While the wall command is generally used by sysadmins to send out notices to users to let send out information (e.g., that the server is going down for maintenance), it can be used by any user.
|
||||
|
||||
A sysadmin might send out a message like this:
|
||||
|
||||
```
|
||||
$ wall The system will be going down in 15 minutes to address a serious problem
|
||||
```
|
||||
|
||||
Everyone logged into the system will see something like this:
|
||||
|
||||
```
|
||||
Broadcast message from admin@dragonfly (pts/0) (Thu Mar 5 08:56:42 2020):
|
||||
|
||||
The system is going down in 15 minutes to address a serious problem
|
||||
```
|
||||
|
||||
If you want to use single quote marks in your message, enclose the message in double quote marks like this:
|
||||
|
||||
```
|
||||
$ wall “Don’t forget to save your work before logging off”
|
||||
```
|
||||
|
||||
The outside quote marks will not show up in the transmitted message, but, without them, the command sits and waits for a closing single quote.
|
||||
|
||||
### mesg
|
||||
|
||||
If, for some reason, you don’t want to accept messages from another user, you can stop them from arriving with the **mesg** command. This command can be used with a “n” argument to refuse mail from the user or a “y” argument to allow the messages to arrive.
|
||||
|
||||
[][1]
|
||||
|
||||
```
|
||||
$ mesg n doug
|
||||
$ mesg y doug
|
||||
```
|
||||
|
||||
The blocked user will not be notified that their messages have been blocked. You can also block or allow all messages with a **mesg** command like one of these:
|
||||
|
||||
```
|
||||
$ mesg y
|
||||
$ mesg n
|
||||
```
|
||||
|
||||
### write
|
||||
|
||||
Another command for sending text without reverting to email is **write**. This command can be used to communicate with a specific user.
|
||||
|
||||
```
|
||||
$ write nemo
|
||||
Are you still at your desk?
|
||||
I need to talk with you right away.
|
||||
^C
|
||||
```
|
||||
|
||||
Enter your text and use **^C** to exit when you’re done. The command allows you to send text, but doesn’t start a two-way conversation. It just sends the text. If the user is logged in on more than one terminal, you can specify which terminal you want to send the message to or you can rely on the system to choose the one with the shortest idle time.
|
||||
|
||||
```
|
||||
$ write nemo#1
|
||||
```
|
||||
|
||||
If the user you are trying to write to has messages blocked, you should see something like this:
|
||||
|
||||
```
|
||||
$ write nemo
|
||||
write: nemo has messages disabled
|
||||
```
|
||||
|
||||
### talk/ytalk
|
||||
|
||||
The **talk** or **ytalk** command gives you a chance to have an interactive chat with one or more other users. The command will bring up a double-pane (top and bottom) window. Each individual will type into the top portion of the display on their screen and see the responses in the bottom section(s). The respondents can respond to a talk request by typing "talk" followed by the username of the person addressing them.
|
||||
|
||||
```
|
||||
Message from Talk_Daemon@dragonfly at 10:10 ...
|
||||
talk: connection requested by dory@127.0.0.1.
|
||||
talk: respond with: talk dory@127.0.0.1
|
||||
|
||||
$ talk dory
|
||||
```
|
||||
|
||||
The window can involve more than two participants if **ytalk** is used. As you can see in the example below (the result of the "talk dory" command shown above), talk is often ytalk.
|
||||
|
||||
```
|
||||
----------------------------= YTalk version 3.3.0 =--------------------------
|
||||
Is the report ready?
|
||||
|
||||
-------------------------------= nemo@dragonfly =----------------------------
|
||||
Just finished it
|
||||
```
|
||||
|
||||
As explained above, on the other side of the conversation, the talk session window panes are reversed:
|
||||
|
||||
```
|
||||
----------------------------= YTalk version 3.3.0 =--------------------------
|
||||
Just finished it
|
||||
|
||||
-------------------------------= dory@dragonfly =----------------------------
|
||||
Is the report ready?
|
||||
```
|
||||
|
||||
Again, use **^C** to exit.
|
||||
|
||||
To talk with someone on another system, you just need to add a **-h** option and the hostname or IP address with a command like this:
|
||||
|
||||
```
|
||||
$ talk -h 192.168.0.11 nemo
|
||||
```
|
||||
|
||||
### Wrap-Up
|
||||
|
||||
There are a number of basic commands for sending messages to other logged-in users on Linux systems, and they can be especially useful when you need to send out a quick message to all of the users, prefer a quick exchange to a phone call or want to easily involve more than two people in a quick messaging session.
|
||||
|
||||
Some commands, like **wall**, allow a message to be broadcast, but are not interactive. Others, like **talk**, allow both lengthy and multi-user chats, avoiding the need to set up a conference call when a fairly quick exchange of information is all that's required.
|
||||
|
||||
Join the Network World communities on [Facebook][2] and [LinkedIn][3] to comment on topics that are top of mind.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3530343/communicating-with-other-users-on-the-linux-command-line.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [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/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)
|
||||
[2]: https://www.facebook.com/NetworkWorld/
|
||||
[3]: https://www.linkedin.com/company/network-world
|
||||
130
sources/tech/20200307 Compose music as code using Sonic Pi.md
Normal file
130
sources/tech/20200307 Compose music as code using Sonic Pi.md
Normal file
@@ -0,0 +1,130 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Compose music as code using Sonic Pi)
|
||||
[#]: via: (https://opensource.com/article/20/3/sonic-pi)
|
||||
[#]: author: (Matt Bargenquast https://opensource.com/users/mbargenquast)
|
||||
|
||||
Compose music as code using Sonic Pi
|
||||
======
|
||||
There's no need for instrumental mastery with this accessible open
|
||||
source program that can turn you into a musical virtuoso.
|
||||
![Bird singing and music notes][1]
|
||||
|
||||
Maybe you're like me, and you learned a musical instrument when you were in school. For me, it was the piano, and later, the viola. However, I've always held that, as my childhood interests shifted towards computers and coding, I subsequently neglected my music practice. I do wonder what I would have done if I'd had something like Sonic Pi when I was younger. Sonic Pi is an open source program that lets you compose and perform music through code itself. It's the perfect marriage of those two worlds.
|
||||
|
||||
Opensource.com is no stranger to Sonic Pi—we [featured an interview][2] with the creator, Dr. Sam Aaron, back in 2015. Since that time, a lot has changed, and Sonic Pi has grown substantially in many ways. It's reached a major new version milestone, with the long-awaited v3.2 release made publically available on February 28, 2020. A growing community of developers is actively contributing to its [GitHub project][3], while an equally thriving community of composers shares ideas and support in the [official forums][4]. The project is now also financially assisted through a [Patreon campaign][5], and Sam himself has been spreading the word of Sonic Pi through schools, conferences, and workshops worldwide.
|
||||
|
||||
What really shines about Sonic Pi is its approachability. Releases are available for many major flavors of OS, including Windows, macOS, Linux, and of course, the Raspberry Pi itself. In fact, getting started with Sonic Pi on a Raspberry Pi couldn't be simpler; it comes pre-installed with [Raspbian][6], so if you have an existing Raspbian-based setup, you'll find it situated in the programming menu.
|
||||
|
||||
Upon loading Sonic Pi for the first time, you'll be greeted with a simple interface with two main areas: an editor in which to write your code, and a section devoted to Sonic Pi's expansive tutorial. For newcomers, the tutorial is an essential resource for learning the basics, featuring accompanying music programs to reinforce each concept being taught.
|
||||
|
||||
If you're following along, let's code ourselves a simple bit of music and explore the potential of live-coding music. Type or paste the following code into the Sonic Pi editor:
|
||||
|
||||
|
||||
```
|
||||
live_loop :beat do
|
||||
sample :drum_heavy_kick
|
||||
sleep 1
|
||||
end
|
||||
```
|
||||
|
||||
Even if you're a Sonic Pi novice, many coders may immediately understand what's going on here. We're playing a drum kick sample, sleeping for a second, and then repeating. Click the Run button or press ALT+R (meta+R on macOS), and you should hear it begin to play.
|
||||
|
||||
This isn't a very exciting song yet, so let's liven it up with a snare playing on the off-beat. Replace the existing code with the block below and Run again. You can leave the existing beat playing while you do this; you'll notice that your changes will be applied naturally, in time with the beat:
|
||||
|
||||
|
||||
```
|
||||
live_loop :beat do
|
||||
sample :drum_heavy_kick
|
||||
sleep 0.5
|
||||
sample :drum_snare_soft
|
||||
sleep 0.5
|
||||
end
|
||||
```
|
||||
|
||||
While we're at it, let's add a hi-hat right before every fourth beat, just to make things a little interesting. Add this new block below our existing one and Run again:
|
||||
|
||||
|
||||
```
|
||||
live_loop :hihat do
|
||||
sleep 3.9
|
||||
sample :drum_cymbal_closed
|
||||
sleep 0.1
|
||||
end
|
||||
```
|
||||
|
||||
We've got our beat going now, so let's add a bassline! Sonic Pi comes with a variety of synths built-in, along with effects filters such as reverb and distortion. We'll use a combination of the "dsaw" and "tech_saw" synths to give it an electronic retro-synth feel. Add the block below to your existing program, Run, and have a listen:
|
||||
|
||||
|
||||
```
|
||||
live_loop :bass do
|
||||
use_synth :dsaw
|
||||
play :a2, attack: 1, release: 2, amp: 0.3
|
||||
sleep 2.5
|
||||
use_synth :tech_saws
|
||||
play :a1, attack: 1, release: 1.5, amp: 0.8
|
||||
sleep 1.5
|
||||
end
|
||||
```
|
||||
|
||||
You'll note above that we have full control over the [ADSR][7] envelope when playing notes, so we can decide when each sound should peak and fade.
|
||||
|
||||
Lastly, let's add a lead synth and try out one of those effects features known as the "slicer." To spice things up, we'll also introduce an element of pseudo-randomness by letting Sonic Pi pick from a series of potential chords. This is where some of the fun improvisation and "happy accidents" can begin to occur. Add the block below to your existing program and Run:
|
||||
|
||||
|
||||
```
|
||||
live_loop :lead do
|
||||
with_fx :slicer do
|
||||
chords = [(chord :A4, :minor7), (chord :A4, :minor), (chord :D4, :minor7), (chord :F4, :major7)]
|
||||
use_synth :blade
|
||||
play chords.choose, attack: 1, release: 2, amp: 1
|
||||
sleep 2
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
Great! Now, we're certainly not going to be competing with Daft Punk any time soon, but hopefully, through this process, you've seen how we can go from a bare beat to something much bigger, in real-time, by adding some simple morsels of code. It is well worth watching one of Sam Aaron's [live coding performances][8] on YouTube for a demonstration of how creative and adaptive Sonic Pi can let you be.
|
||||
|
||||
![Sonic Pi composition example][9]
|
||||
|
||||
Our finished piece, in full
|
||||
|
||||
If you've ever wanted to learn a musical instrument, but felt held back by thoughts like "I don't have rhythm" or "my hands aren't nimble enough," Sonic Pi is a versatile instrument for which none of those things matter. All you need are the ideas, the inspiration, and an inexpensive computer such as the humble Raspberry Pi. The rest is at your fingertips—literally!
|
||||
|
||||
Here are a few handy links to get you started:
|
||||
|
||||
* The Official Sonic Pi [website][10] and [tutorial][11]
|
||||
* [Getting Started with Sonic Pi][12] ([projects.raspberrypi.org][13])
|
||||
* Sonic Pi [Github project][3]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/3/sonic-pi
|
||||
|
||||
作者:[Matt Bargenquast][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mbargenquast
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/music-birds-recording-520.png?itok=UoM7brl0 (Bird singing and music notes)
|
||||
[2]: https://opensource.com/life/15/10/interview-sam-aaron-sonic-pi
|
||||
[3]: https://github.com/samaaron/sonic-pi/
|
||||
[4]: https://in-thread.sonic-pi.net/
|
||||
[5]: https://www.patreon.com/samaaron
|
||||
[6]: https://www.raspberrypi.org/downloads/raspbian/
|
||||
[7]: https://en.wikipedia.org/wiki/Envelope_(music)
|
||||
[8]: https://www.youtube.com/watch?v=JEHpS1aTKp0
|
||||
[9]: https://opensource.com/sites/default/files/uploads/sonicpi.png (Sonic Pi composition example)
|
||||
[10]: https://sonic-pi.net/
|
||||
[11]: https://sonic-pi.net/tutorial.html
|
||||
[12]: https://projects.raspberrypi.org/en/projects/getting-started-with-sonic-pi
|
||||
[13]: http://projects.raspberrypi.org
|
||||
@@ -0,0 +1,226 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to structure a multi-file C program: Part 2)
|
||||
[#]: via: (https://opensource.com/article/19/7/structure-multi-file-c-part-2)
|
||||
[#]: author: (Erik O'Shaughnessy https://opensource.com/users/jnyjny)
|
||||
|
||||
如何组织构建多文件 C 语言程序(二)
|
||||
======
|
||||
我将在本系列的第二篇中深入研究由多个文件组成的C程序的结构。
|
||||
![4 个 manilla 文件,黄色,绿色,紫色,蓝色][1]
|
||||
|
||||
在 [(第一篇)][2] 中,我设计了一个名为 [MeowMeow][3] 的多文件 C 程序,该程序实现了一个玩具——[codec][4]。我提到了程序设计中的 Unix 哲学,即在一开始创建多个空文件,并建立一个好的结构。最后,我创建了一个 Makefile 文件夹并阐述了它的作用。在本文中将另一个方向展开:现在我将介绍简单但具有指导性的 MeowMeow 编/解码器的实现。
|
||||
|
||||
当读过我的 "[如何写一个好的 C 语言 main 函数][5]." 后,你便会知道 `main.c` 文件中 `meow` 和 `unmeow` 的结构,其主体结构如下:
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow 流编码器和解码器 */
|
||||
|
||||
/* 00 system includes */
|
||||
/* 01 project includes */
|
||||
/* 02 externs */
|
||||
/* 03 defines */
|
||||
/* 04 typedefs */
|
||||
/* 05 globals (but don't)*/
|
||||
/* 06 ancillary function prototypes if any */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* 07 variable declarations */
|
||||
/* 08 check argv[0] to see how the program was invoked */
|
||||
/* 09 process the command line options from the user */
|
||||
/* 10 do the needful */
|
||||
}
|
||||
|
||||
/* 11 ancillary functions if any */
|
||||
```
|
||||
|
||||
### 包含项目头文件
|
||||
|
||||
位于第二部分中的 `/* 01 project includes */` 的源代码如下:
|
||||
|
||||
|
||||
```
|
||||
/* main.c - MeowMeow 流编码器和解码器 */
|
||||
...
|
||||
/* 01 project includes */
|
||||
#include "main.h"
|
||||
#include "mmecode.h"
|
||||
#include "mmdecode.h"
|
||||
```
|
||||
|
||||
`#include` 是 C 语言的预处理命令,它会将其后面的文件内容拷贝到当前文件中。如果程序员在头文件名称周围使用双引号,编译器将会在当前目录寻找该文件。如果文件被尖括号包围,编译器将在一组预定义的目录中查找该文件。
|
||||
|
||||
[main.h][6] 文件中包含了 [main.c][7] 文件中用到的定义和别名。我喜欢在头文件里尽可能多的声明,以便我想在我的程序的其他位置使用这些定义。
|
||||
|
||||
头文件 [mmencode.h][8] 和 [mmdecode.h][9] 几乎相同,因此我以 `mmencode.h` 为例来分析。
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.h - MeowMeow 流编码器和解码器 */
|
||||
|
||||
#ifndef _MMENCODE_H
|
||||
#define _MMENCODE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int mm_encode(FILE *src, FILE *dst);
|
||||
|
||||
#endif /* _MMENCODE_H */
|
||||
```
|
||||
|
||||
`#ifdef`,`#define`,`#endif` 指令统称为 “防护” 指令。其可以防止 C 编译器在一个文件中多次包含同一文件。如果编译器在一个文件中发现多个定义/原型/声明,它将会产生警告。因此这些防护措施是必要的。
|
||||
|
||||
在防护内部,它只做两件事:`#include` 指令和函数原型声明。我将包含 `stdio.h` 头文件,以便于能在函数原型中使用 `FILE` 流。函数原型也可以被包含在其他 C 文件中,以便于在文件的命名空间中创建它。你可以将每个文件视为一个命名空间,其中的变量和函数不能被另一个文件中的函数或者变量使用。
|
||||
|
||||
编写头文件很复杂,并且在大型项目中很难管理它。不要忘记使用防护。
|
||||
|
||||
### MeowMeow 编码的实现
|
||||
|
||||
该程序的功能是按照字节进行 `MeowMeow` 字符串的编解码,事实上这是该项目中最简单的部分。截止目前我所做的工作便是支持允许在适当的位置调用此函数:解析命令行,确定要使用的操作,并打开将要操作的文件。下面的循环是编码的过程:
|
||||
|
||||
|
||||
```
|
||||
/* mmencode.c - MeowMeow 流编码器 */
|
||||
...
|
||||
while (![feof][10](src)) {
|
||||
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
|
||||
for(i=0; i<[strlen][12](buf); i++) {
|
||||
lo = (buf[i] & 0x000f);
|
||||
hi = (buf[i] & 0x00f0) >> 4;
|
||||
[fputs][13](tbl[hi], dst);
|
||||
[fputs][13](tbl[lo], dst);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
简单的说,上面代码循环读取文件的一部分,剩下的内容通过 `feof(3)` 函数和 `fgets(3)` 函数读取。然后将读入的内容的每个字节分成 `hi` 和 `lo` 半个字节。半个字节是 4 个比特。这里的奥妙之处在于可以用 4 个比特来编码16个值。我将字符串 `hi` 和 `lo` 用作 16 字符串查找表 `tbl` 的索引,表中包含了对每半个字节编码后的 `MeowMeow` 字符串。这些字符串使用 `fputs(3)` 函数写入目标 `FILE` 流,然后移动到缓存区的下一个字节。
|
||||
|
||||
该表使用 [table.h][14] 中的宏定义进行初始化,在没有特殊原因(比如:要展示包含了另一个项目的本地头文件)时,我喜欢使用宏来进行初始化。我将在未来的文章中进一步探讨原因。
|
||||
|
||||
### MeowMeow 解码的实现
|
||||
|
||||
我承认在开始工作前花了一些时间。解码的循环与编码类似:读取 `MeowMeow` 字符串到缓冲区,将编码从字符串转换为字节
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
int mm_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
if (!src || !dst) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return stupid_decode(src, dst);
|
||||
}
|
||||
```
|
||||
|
||||
这不是所期望的吗?
|
||||
|
||||
在这里,我通过外部公开的 `mm_decode()` 函数公开了 `stupid_decode()` 函数细节。我上面所说的“外部”是指在这个文件之外。因为 `stupid_decode()` 函数不在头文件中,因此无法在其他文件中调用它。
|
||||
|
||||
当我们想发布一个可靠的公共接口时,有时候会这样做,但是我们还没有完全使用函数解决问题。在本例中,我编写了一个 I/O 密集型函数,该函数每次从源中读取 8 个字节,然后解码获得 1 个字节写入目标流中。较好的实现是一次处理多于 8 个字节的缓冲区。更好的实现还可以通过缓冲区输出字节,进而减少目标流中单字节的写入次数。
|
||||
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
int stupid_decode(FILE *src, FILE *dst)
|
||||
{
|
||||
char buf[9];
|
||||
decoded_byte_t byte;
|
||||
int i;
|
||||
|
||||
while (![feof][10](src)) {
|
||||
if (![fgets][11](buf, sizeof(buf), src))
|
||||
break;
|
||||
byte.field.f0 = [isupper][15](buf[0]);
|
||||
byte.field.f1 = [isupper][15](buf[1]);
|
||||
byte.field.f2 = [isupper][15](buf[2]);
|
||||
byte.field.f3 = [isupper][15](buf[3]);
|
||||
byte.field.f4 = [isupper][15](buf[4]);
|
||||
byte.field.f5 = [isupper][15](buf[5]);
|
||||
byte.field.f6 = [isupper][15](buf[6]);
|
||||
byte.field.f7 = [isupper][15](buf[7]);
|
||||
|
||||
[fputc][16](byte.value, dst);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
我并没有使用编码器中使用的位移方法,而是创建了一个名为 `decoded_byte_t` 的自定义数据结构。
|
||||
|
||||
```
|
||||
/* mmdecode.c - MeowMeow 流解码器 */
|
||||
...
|
||||
|
||||
typedef struct {
|
||||
unsigned char f7:1;
|
||||
unsigned char f6:1;
|
||||
unsigned char f5:1;
|
||||
unsigned char f4:1;
|
||||
unsigned char f3:1;
|
||||
unsigned char f2:1;
|
||||
unsigned char f1:1;
|
||||
unsigned char f0:1;
|
||||
} fields_t;
|
||||
|
||||
typedef union {
|
||||
fields_t field;
|
||||
unsigned char value;
|
||||
} decoded_byte_t;
|
||||
```
|
||||
|
||||
初次看到代码时可能会感到有点儿复杂,但不要放弃。`decoded_byte_t` 被定义为 `fields_t` 和 `unsigned char` 的 **联合体** 。可以将联合中的命名成员看作同一内存区域的别名。在这种情况下,`value` 和 `field` 指向相同的 8 比特内存区域。将 `field.f0` 设置为 1 也将设置 `value` 中的最低有效位。
|
||||
|
||||
虽然 `unsigned char` 并不神秘,但是对 `fields_t` 的 别名(`typedef`) 也许看起来有些陌生。现代 C 编译器允许程序员在结构体中指定单个 bit 的值。`field` 成员是一个无符号整数类型,可以在成员标识符后紧跟一个冒号和一个整数,该整数指定了比特字段的长度。
|
||||
|
||||
这种数据结构使得按 `field` 名称访问每个比特变得简单。我们依赖编译器生成正确的移位指令来访问 `field`,这可以在调试时为你节省不少时间。
|
||||
|
||||
最后,因为`stupid_decode()` 函数一次仅从源 `FILE` 流中读取 8 个字节,所以它效率并不高。通常我们尝试最小化读写次数,以提高性能和降低调用系统调用的开销。请记住:少次数的读取/写入大的块比多次数的读取/写入小的块好得多。
|
||||
|
||||
### 总结
|
||||
|
||||
用 C 语言编写一个多文件程序需要程序员做更多计划,而不仅仅是一个 `main.c`。但是当你添加功能或者重构时,只需要多花费一点儿努力便可以节省大量时间以及避免让你头痛的问题。
|
||||
|
||||
回顾一下,我更喜欢这样做:多个文件,每个文件仅有简单功能;通过头文件公开那些文件中的小部分功能;把数字常量和字符串常量保存在头文件中;使用 `Makefile` 而不是 Bash 脚本来自动化处理事务;使用 `main()` 函数来处理和解析命令行参数并作为程序主要功能的框架。
|
||||
|
||||
我知道我只是涉及了这个简单程序中发生的事情,并且我很高兴知道哪些事情对您有所帮助以及哪些主题需要详细的解释。在评论中分享您的想法,让我知道。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/7/structure-multi-file-c-part-2
|
||||
|
||||
作者:[Erik O'Shaughnessy][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jnyjny
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/file_system.jpg?itok=pzCrX1Kc (4 manilla folders, yellow, green, purple, blue)
|
||||
[2]: https://opensource.com/article/19/7/how-structure-multi-file-c-program-part-1
|
||||
[3]: https://github.com/jnyjny/MeowMeow.git
|
||||
[4]: https://en.wikipedia.org/wiki/Codec
|
||||
[5]: https://opensource.com/article/19/5/how-write-good-c-main-function
|
||||
[6]: https://github.com/JnyJny/meowmeow/blob/master/main.h
|
||||
[7]: https://github.com/JnyJny/meowmeow/blob/master/main.c
|
||||
[8]: https://github.com/JnyJny/meowmeow/blob/master/mmencode.h
|
||||
[9]: https://github.com/JnyJny/meowmeow/blob/master/mmdecode.h
|
||||
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/feof.html
|
||||
[11]: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html
|
||||
[12]: http://www.opengroup.org/onlinepubs/009695399/functions/strlen.html
|
||||
[13]: http://www.opengroup.org/onlinepubs/009695399/functions/fputs.html
|
||||
[14]: https://github.com/JnyJny/meowmeow/blob/master/table.h
|
||||
[15]: http://www.opengroup.org/onlinepubs/009695399/functions/isupper.html
|
||||
[16]: http://www.opengroup.org/onlinepubs/009695399/functions/fputc.html
|
||||
@@ -0,0 +1,237 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (caiichenr)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Building a non-breaking breakpoint for Python debugging)
|
||||
[#]: via: (https://opensource.com/article/19/8/debug-python)
|
||||
[#]: author: (Liran Haimovitch https://opensource.com/users/liranhaimovitch)
|
||||
|
||||
在 Python 调试过程中设置不中断的断点
|
||||
======
|
||||
你对如何让调试器变得更快产生过兴趣吗?本文将分享我们在为 Python 构建调试器时得到的一些经验。
|
||||
![Real python in the graphic jungle][1]
|
||||
|
||||
整段故事讲的是我们在 [Rookout][2] 公司的团队为 Python 调试器开发不中断断点的经历,以及开发过程中得到的经验。我将在本月于旧金山举办的 [PyBay 2019][3] 上介绍有关 Python 调试过程的更多细节,但现在就让我们立刻开始这段故事。
|
||||
|
||||
### Python 调试器的心脏:sys.set_trace
|
||||
|
||||
在诸多可选的 Python 调试器中,使用最广泛的三个是:
|
||||
|
||||
* **pdb**,它是 Python 标准库的一部分
|
||||
* **PyDev**,它是内嵌在 Eclipse 和 Pycharm 等 IDE 中的调试器
|
||||
* **ipdb**,它是IPython的调试器
|
||||
|
||||
|
||||
|
||||
Python 调试器的选择虽多,但它们几乎都基于同一个函数:**sys.set_trace**。 值得一提的是, **[sys.settrace][4]** 可能也是 Python 标准库中最复杂的函数。
|
||||
|
||||
![set_trace Python 2 docs page][5]
|
||||
|
||||
简单来讲,**settrace** 的作用是为解释器注册一个跟踪函数,它在下列四种情形发生时被调用:
|
||||
|
||||
* 函数调用 (Function call)
|
||||
* 语句执行 (Line execution)
|
||||
* 函数返回 (Function return)
|
||||
* 异常抛出 (Exception raised)
|
||||
|
||||
|
||||
|
||||
一个简单的跟踪函数看上去大概是这样:
|
||||
|
||||
|
||||
```
|
||||
def simple_tracer(frame, event, arg):
|
||||
co = frame.f_code
|
||||
func_name = co.co_name
|
||||
line_no = frame.f_lineno
|
||||
print("{e} {f} {l}".format(
|
||||
e=event, f=func_name, l=line_no))
|
||||
return simple_tracer
|
||||
```
|
||||
|
||||
在分析函数时我们首先关注的是参数和返回值,该跟踪函数的参数分别是:
|
||||
|
||||
* **frame**,当前堆栈帧,它是包含当前函数执行时解释器里完整状态的对象
|
||||
* **event**,它是一个值可能为 **"call"**, **"line"**, **"return"**, 或 **"exception"** 的字符串
|
||||
* **arg**,它的取值基于 event 的类型,是一个可选项
|
||||
|
||||
|
||||
|
||||
该跟踪函数的返回值是它自身,这是由于解释器需要持续跟踪两类跟踪函数:
|
||||
|
||||
* **全局跟踪函数(每线程):** 该跟踪函数由当前线程调用 **sys.settrace** 来设置,并在解释器创建一个新 **frame** 时被调用(即代码中发生函数调用时)。虽然没有现成的方式来为不同的线程设置跟踪函数,但你可以调用 **threading.settrace** 来为所有新创建的 **threading** 模块线程设置跟踪函数。
|
||||
* **局部跟踪函数(每一帧):** 解释器将该跟踪函数的值设置为全局跟踪函数创建帧时的返回值。同样也没有现成的方法能够在帧被创建时自动设置局部跟踪函数。
|
||||
|
||||
|
||||
|
||||
该机制的目的是让调试器对被跟踪的帧有更精确的把握,以减少对性能的影响。
|
||||
|
||||
### 简单三步构建调试器 (我们最初的设想)
|
||||
|
||||
仅仅依靠上文提到的内容,用自制的跟踪函数来构建一个真正的调试器似乎有些不切实际。幸运的是,Python 的标准调试器 **pdb** 是基于 **Bdb** 构建的,后者是 Python 标准库中专门用于构建调试器的基类。
|
||||
|
||||
基于 **Bdb** 的简易断点调试器看上去是这样的:
|
||||
|
||||
|
||||
```
|
||||
import bdb
|
||||
import inspect
|
||||
|
||||
class Debugger(bdb.Bdb):
|
||||
def __init__(self):
|
||||
Bdb.__init__(self)
|
||||
self.breakpoints = dict()
|
||||
self.set_trace()
|
||||
|
||||
def set_breakpoint(self, filename, lineno, method):
|
||||
self.set_break(filename, lineno)
|
||||
try :
|
||||
self.breakpoints[(filename, lineno)].add(method)
|
||||
except KeyError:
|
||||
self.breakpoints[(filename, lineno)] = [method]
|
||||
|
||||
def user_line(self, frame):
|
||||
if not self.break_here(frame):
|
||||
return
|
||||
|
||||
# Get filename and lineno from frame
|
||||
(filename, lineno, _, _, _) = inspect.getframeinfo(frame)
|
||||
|
||||
methods = self.breakpoints[(filename, lineno)]
|
||||
for method in methods:
|
||||
method(frame)
|
||||
```
|
||||
|
||||
这个调试器类的全部构成是:
|
||||
|
||||
1. 继承 **Bdb**,定义一个简单的构造函数来初始化基类,并开始跟踪。
|
||||
2. 添加 **set_breakpoint** 方法,它使用 **Bdb** 来设置断点,并跟踪这些断点。
|
||||
3. 重载 **Bdb** 在当前用户行调用的 **user_line** 方法,该方法一定被一个断点调用,之后获取该断点的源位置,并调用已注册的断点。
|
||||
|
||||
|
||||
|
||||
### 这个简易的 Bdb 调试器效率如何呢?
|
||||
|
||||
Rookout 的目标是在生产级性能的使用场景下提供接近普通调试器的使用体验。那么,让我们来看看先前构建出来的简易调试器表现的如何。
|
||||
|
||||
为了衡量调试器的整体性能开销,我们使用如下两个简单的函数来进行测试,它们分别在不同的情景下执行了 1600 万次。请注意,在所有情景下断点都不会被执行。
|
||||
|
||||
|
||||
```
|
||||
def empty_method():
|
||||
pass
|
||||
|
||||
def simple_method():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
d = 4
|
||||
e = 5
|
||||
f = 6
|
||||
g = 7
|
||||
h = 8
|
||||
i = 9
|
||||
j = 10
|
||||
```
|
||||
|
||||
在使用调试器的情况下需要大量的时间才能完成测试。糟糕的结果指明了,这个简陋 **Bdb** 调试器的性能还远不足以在生产环境中使用。
|
||||
|
||||
![First Bdb debugger results][6]
|
||||
|
||||
### 对调试器进行优化
|
||||
|
||||
降低调试器的额外开销主要有三种方法:
|
||||
|
||||
1. **尽可能的限制局部跟踪:** 由于每一行代码都可能包含大量事务,局部跟踪比全局跟踪的开销要大得多。
|
||||
2. **优化 "call" 事务并尽快将控制权还给解释器:** 在 **call** 事务发生时调试器的主要工作是判断是否需要对该事务进行跟踪。
|
||||
3. **优化 "line" 事务并尽快将控制权还给解释器:** 在 **line** 事务发生时调试器的主要工作是判断我们在此处是否需要设置一个断点。
|
||||
|
||||
|
||||
|
||||
于是我们克隆了 **Bdb** 项目,精简特征,简化代码,针对使用场景进行优化。这些工作虽然得到了一些效果,但仍无法满足我们的需求。因此我们又继续进行了其它的尝试,将代码优化并迁移至 **.pyx** 使用 [Cython][7] 进行编译,可惜结果(如下图所示)依旧不够理想。最终,我们在深入了解 CPython 源码之后意识到,让跟踪过程快到满足生产需求是不可能的。
|
||||
|
||||
![Second Bdb debugger results][8]
|
||||
|
||||
### 放弃 Bdb 转而尝试字节码操作
|
||||
|
||||
熬过先前对标准调试方法进行的试验-失败-再试验循环所带来的失望,我们将目光转向另一种选择:字节码操作。
|
||||
|
||||
Python 解释器的工作主要分为两个阶段:
|
||||
|
||||
1. **将 Python 源码编译成 Python 字节码:** 这种不可读(对人类而言)的格式专为执行的效率而优化,它们通常缓存在我们熟知的 **.pyc** 文件当中。
|
||||
2. **遍历 _interpreter loop_ 中的字节码:** 在这一步中解释器会逐条的执行指令
|
||||
|
||||
|
||||
|
||||
我们选择的模式是:使用**字节码操作**来设置没有全局额外开销的**不中断断点**。这种方式的实现首先需要在内存中的字节码里找到我们感兴趣的部分,然后在该部分的相关机器指令前插入一个函数调用。如此一来,解释器无需任何额外的工作即可实现我们的不中断断点。
|
||||
|
||||
这种方法并不依靠魔法来实现,让我们简要地举个例子。
|
||||
|
||||
首先定义一个简单的函数:
|
||||
|
||||
|
||||
```
|
||||
def multiply(a, b):
|
||||
result = a * b
|
||||
return result
|
||||
```
|
||||
|
||||
在 **[inspect][9]** 模块(其包含了许多实用的单元)的文档里,我们得知可以通过访问 **multiply.func_code.co_code** 来获取函数的字节码:
|
||||
|
||||
|
||||
```
|
||||
`'|\x00\x00|\x01\x00\x14}\x02\x00|\x02\x00S'`
|
||||
```
|
||||
|
||||
使用 Python 标准库中的 **[dis][10]** 模块可以翻译这些不可读的字符串。调用 **dis.dis(multiply.func_code.co_code)** 之后,我们就可以得到:
|
||||
|
||||
|
||||
```
|
||||
4 0 LOAD_FAST 0 (a)
|
||||
3 LOAD_FAST 1 (b)
|
||||
6 BINARY_MULTIPLY
|
||||
7 STORE_FAST 2 (result)
|
||||
|
||||
5 10 LOAD_FAST 2 (result)
|
||||
13 RETURN_VALUE
|
||||
```
|
||||
|
||||
与直截了当的解决方案相比,这种方法让我们更靠近发生在调试器背后的事情。可惜 Python 并没有提供在解释器中修改函数字节码的方法。我们可以对函数对象进行重写,不过那样做的效率满足不了大多数实际的调试场景。最后我们不得不采用一种迂回的方式来使用原生拓展才能完成这一任务。
|
||||
|
||||
### 总结
|
||||
|
||||
在构建一个新工具时,总会学到许多事情的工作原理。这种刨根问底的过程能够使你的思路跳出桎梏,从而得到意料之外的解决方案。
|
||||
|
||||
在 Rookout 团队中构建不中断断点的这段时间里,我学到了许多有关编译器、调试器、服务器框架、并发模型等等领域的知识。如果你希望更深入的了解字节码操作,谷歌的开源项目 **[cloud-debug-python][11]** 为编辑字节码提供了一些工具。
|
||||
|
||||
* * *
|
||||
|
||||
_Liran Haimovitch 将于 2019 年八月 17-18 日在旧金山举办的 [PyBay][3] 中发表题为 "[Understanding Python’s Debugging Internals][12]" 的演说,使用 [OpenSource35][13] 可以获得购票优惠,并使他们得知您是在我们的社区得知此事。_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/8/debug-python
|
||||
|
||||
作者:[Liran Haimovitch][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[caiichenr](https://github.com/caiichenr)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/liranhaimovitch
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python_jungle_lead.jpeg?itok=pFKKEvT- (Real python in the graphic jungle)
|
||||
[2]: https://rookout.com/
|
||||
[3]: https://pybay.com/
|
||||
[4]: https://docs.python.org/3/library/sys.html#sys.settrace
|
||||
[5]: https://opensource.com/sites/default/files/uploads/python2docs.png (set_trace Python 2 docs page)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/debuggerresults1.png (First Bdb debugger results)
|
||||
[7]: https://cython.org/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/debuggerresults2.png (Second Bdb debugger results)
|
||||
[9]: https://docs.python.org/2/library/inspect.html
|
||||
[10]: https://docs.python.org/2/library/dis.html
|
||||
[11]: https://github.com/GoogleCloudPlatform/cloud-debug-python
|
||||
[12]: https://pybay.com/speaker/liran-haimovitch/
|
||||
[13]: https://ti.to/sf-python/pybay2019/discount/OpenSource35
|
||||
@@ -1,241 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (heguangzhi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to find what you’re looking for on Linux with find)
|
||||
[#]: via: (https://www.networkworld.com/article/3527420/how-to-find-what-you-re-looking-for-on-linux-with-find.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
如何在 Linux上通过 find 命令找到你要找的东西
|
||||
======
|
||||
find 命令有大量选项可以帮助你准确定位你在 Linux 系统上需要寻找的文件。这篇文章讨论了一系列非常有用的选项。
|
||||
|
||||
CSA 图片/ Getty 图片
|
||||
|
||||
在 Linux 系统上有许多用于查找文件的命令,但是在查找文件时也有大量的选项可以选择。
|
||||
|
||||
例如,你不仅可以通过文件的名称来查找文件,还可以通过文件的所有者或者组、它们的创建时间、大小、分配的权限、最后一次访问它们的时间、关联的信息节点,甚至是文件是否属于系统上不再存在的帐户或组等等来查找文件。
|
||||
|
||||
[[Get regularly scheduled insights by signing up for Network World newsletters.]][1]
|
||||
你还可以指定搜索从哪里开始,搜索应该深入到文件系统的什么位置,以及搜索结果将告诉你它所找到的文件的数量。
|
||||
|
||||
而所有这些要求都可以通过 **find** 命令来处理。
|
||||
|
||||
下面提供了根据这些标准查找文件的示例。在某些命令中,错误(例如试图列出你没有读取权限的文件),错误输出将被发送到 **/dev/null**,以便我们不必查看它。在其他情况下,我们将简单地以 root 身份运行以避免这个问题。
|
||||
|
||||
请记住,还其他选项存在。这篇文章涵盖了很多内容,但并不是 **find** 命令帮助你定位查找文件的所有方式。
|
||||
|
||||
### 选择起点
|
||||
|
||||
使用 **find**,您可以选择一个起点或从你所在的位置开始。请在单词“find”后输入要选择起点。例如,“find /usr” 或 “find ./bin "将在 **/usr** 目录或 **bin** 目录开始搜索,而" find ~ " 将在你的主目录中开始,即使你位于当前文件系统中的其他位置。
|
||||
|
||||
[][2]
|
||||
|
||||
### 选择你想看的
|
||||
|
||||
最常用的搜索策略之一是按名称搜索文件。这需要使用 **-name** 选项。
|
||||
|
||||
默认情况下,**查找** 会显示找到的文件的完整路径。如果你在命令中添加 **-print**,你会看到同样的情况。如果你想查看与文件相关的详细信息—-例如:文件的长度、权限等,您需要在你的 **查找** 命令的末尾添加 **-ls** 命令。
|
||||
|
||||
```
|
||||
$ find ~/bin -name tryme
|
||||
/home/shs/bin/tryme
|
||||
$ find ~/bin -name tryme -print
|
||||
/home/shs/bin/tryme
|
||||
$ find ~/bin -name tryme -ls
|
||||
917528 4 -rwx------ 1 shs shs 139 Apr 8 2019 /home/shs/bin/tryme
|
||||
```
|
||||
|
||||
你也可以使用子字符串来查找文件。例如,如果你将上面示例中的“tryme”替换为“try*”,你将会找到所有名称以“try”开头的文件。
|
||||
|
||||
按名称查找文件可能是 **find** 命令最典型的用法,但是有很多其他的方式来查找文件,并且有很好的理由这样做。下面的部分展示了如何使用其他可用的方式。
|
||||
|
||||
此外,当按大小、组、索引节点等条件来搜索文件时,你需要确认找到的文件与你要查找的文件是否相匹配。使用 **-ls** 选项来显示细节是非常有用。
|
||||
|
||||
### 通过大小查找文件
|
||||
|
||||
按大小查找文件需要使用 **-size** 选项并且对相应规范使用一点技巧。如果你指定 **-size 189b**,例如,你将找到189个块长的文件,而不是189个字节。对于字节,你需要使用 **--size 189c**(字符)。而且,如果你指定 **--size 200w** ,你将会找到200个单词的文件——以“双字节增量”为单位的单词,而不是“我们彼此都在说的那些事情”中的单词。你还可以通过以千字节(k)、兆字节(M)和千兆字节(G)为单位提供大小来查找文件。
|
||||
|
||||
|
||||
大多数情况下,Linux用户会搜索比所选文件大的文件。例如,要查找大于1千兆字节的文件,你可以使用这样的命令,其中 +1G 表示“大于1千兆字节”:
|
||||
|
||||
```
|
||||
$ find -size +1G -ls 2>/dev/null
|
||||
787715 1053976 -rw-rw-r-- 1 shs shs 1079263432 Dec 21 2018 ./backup.zip
|
||||
801834 1052556 -rw-rw-r-- 1 shs shs 1077809525 Dec 21 2018 ./2019/hold.zip
|
||||
```
|
||||
|
||||
### 通过索引节点查找文件 #
|
||||
|
||||
你可以通过用于维护文件元数据(即除文件内容和文件名之外的所有内容)的索引节点来查找文件。
|
||||
|
||||
```
|
||||
$ find -inum 919674 -ls 2>/dev/null
|
||||
919674 4 -rw-rw-r-- 1 shs shs 512 Dec 27 15:25 ./bin/my.log
|
||||
```
|
||||
|
||||
### 查找具有特定文件所有者或组的文件
|
||||
|
||||
按所有者或组查找文件也非常简单。这里我们使用 sudo 来解决权限问题。
|
||||
|
||||
```
|
||||
$ sudo find /home -user nemo -name "*.png"-ls
|
||||
1705219 4 drwxr-xr-x 2 nemo nemo 4096 Jan 28 08:50 /home/nemo/Pictures/me.png
|
||||
```
|
||||
|
||||
在这个命令中,我们寻找一个被称为 “admins” 的多用户组拥有的文件。
|
||||
|
||||
```
|
||||
# find /tmp -group admins -ls
|
||||
262199 4 -rwxr-x--- 1 dory admins 27 Feb 16 18:57 /tmp/testscript
|
||||
```
|
||||
|
||||
### 查找没有所有者或组的文件
|
||||
|
||||
你可以使用如下命令所示的 **-nouser** 选项来查找系统上没有任何现存用户属性的文件。
|
||||
|
||||
```
|
||||
# find /tmp -nouser -ls
|
||||
262204 4 -rwx------ 1 1016 1016 17 Feb 17 16:42 /tmp/hello
|
||||
```
|
||||
|
||||
请注意,该列表显示了旧用户的 UID 和 GID,这清楚地表明该用户未在系统上定义。这种命令将查找由于帐户已从系统中删除的用户在非主目录中创建的文件,或者在用户帐户被删除后未被删除的主目录中创建的文件。类似地,**-nogroup** 选项会找到这样的文件,尤其是当这些用户是相关组的唯一成员时。
|
||||
|
||||
### 按上次更新时间查找文件
|
||||
|
||||
在此命令中,我们在特定用户的主目录中查找过去24小时内更新过的文件。**sudo** 用于搜索另一个用户的主目录。
|
||||
|
||||
```
|
||||
$ sudo find /home/nemo -mtime -1
|
||||
/home/nemo
|
||||
/home/nemo/snap/cheat
|
||||
/home/nemo/tryme
|
||||
```
|
||||
|
||||
### 按上次更改权限的时间查找文件
|
||||
|
||||
**-ctime** 选项可以帮助你查找在某个参考时间范围内状态(如权限)发生更改的文件。以下是查找在最后一天内权限发生更改的文件的示例:
|
||||
|
||||
```
|
||||
$ find . -ctime -1 -ls
|
||||
787987 4 -rwxr-xr-x 1 shs shs 189 Feb 11 07:31 ./tryme
|
||||
```
|
||||
|
||||
请记住,显示的日期和时间反映了文件内容的最后更新。你需要使用像 **stat** 这样的命令来查看与文件相关联的三个状态(文件创建、修改和状态更改)。
|
||||
|
||||
### Finding files based on last access times
|
||||
|
||||
在这个命令中,我们使用 **-atime** 选项查找在过去两天内访问过的本地 pdf 文件。
|
||||
|
||||
```
|
||||
$ find -name "*.pdf" -atime -2
|
||||
./Wingding_Invites.pdf
|
||||
```
|
||||
|
||||
### 根据文件相对于另一个文件的时间来查找文件
|
||||
|
||||
你可以使用 -newer 选项来查找比其他文件更新的文件。
|
||||
|
||||
```
|
||||
$ find . -newer dig1 -ls
|
||||
786434 68 drwxr-xr-x 67 shs shs 69632 Feb 16 19:05 .
|
||||
1064442 4 drwxr-xr-x 5 shs shs 4096 Feb 16 11:06 ./snap/cheat
|
||||
791846 4 -rw-rw-r-- 1 shs shs 649 Feb 13 14:26 ./dig
|
||||
```
|
||||
|
||||
没有相应的 **-older** 选项,但是你可以用**,得到类似的结果 **! -newer**(即更旧),这意味着几乎相同的事情。
|
||||
|
||||
### 按类型查找文件
|
||||
|
||||
通过文件类型找到一个文件,你有很多选项——常规文件、目录、块和字符文件等等。以下是文件类型选项列表:
|
||||
|
||||
```
|
||||
b block (buffered) special
|
||||
c character (unbuffered) special
|
||||
d directory
|
||||
p named pipe (FIFO)
|
||||
f regular file
|
||||
l symbolic link
|
||||
s socket
|
||||
```
|
||||
|
||||
这里有一个寻找符号链接的例子:
|
||||
|
||||
```
|
||||
$ find . -type l -ls
|
||||
805717 0 lrwxrwxrwx 1 shs shs 11 Apr 10 2019 ./volcano -> volcano.pdf
|
||||
918552 0 lrwxrwxrwx 1 shs shs 1 Jun 16 2018 ./letter -> pers/letter2mom
|
||||
```
|
||||
|
||||
### 限制查找的深度
|
||||
|
||||
**-mindepth** 和 **-maxdepth** 选项控制在文件系统中搜索的深度(从当前位置或起始点开始)。
|
||||
|
||||
```
|
||||
$ find -maxdepth 3 -name "*loop"
|
||||
./bin/save/oldloop
|
||||
./bin/long-loop
|
||||
./private/loop
|
||||
```
|
||||
|
||||
### 查找空文件
|
||||
|
||||
在这个命令中,我们寻找空文件,但不超过目录及其子目录。
|
||||
|
||||
```
|
||||
$ find . -maxdepth 2 -empty -type f -ls
|
||||
917517 0 -rw-rw-r-- 1 shs shs 0 Sep 23 11:00 ./complaints/newfile
|
||||
792050 0 -rw-rw-r-- 1 shs shs 0 Oct 4 19:02 ./junk
|
||||
```
|
||||
|
||||
### 按权限查找文件
|
||||
|
||||
你可以使用 **-perm** 选项查找具有特定权限集的文件。在下面的示例中,我们只查找常规文件(**-type f**),以避免看到默认情况下被赋予这些权限的符号链接,即使它们引用的文件是受限的。
|
||||
|
||||
```
|
||||
$ find -perm 777 -type f -ls
|
||||
find: ‘./.dbus’: Permission denied
|
||||
798748 4 -rwxrwxrwx 1 shs shs 15 Mar 28 2019 ./runme
|
||||
```
|
||||
|
||||
### 使用查找来帮助你删除文件
|
||||
|
||||
如果使用如下命令,你可以使用 find 命令定位并删除文件:
|
||||
|
||||
```
|
||||
$ find . -name runme -exec rm {} \;
|
||||
```
|
||||
|
||||
{} 代表根据搜索条件找到的每个文件的名称。
|
||||
|
||||
一个非常有用的选项是将 **-exec** 替换为 **-ok**。当您这样做时,**find** 会在删除任何文件之前要求确认。
|
||||
|
||||
```
|
||||
$ find . -name runme -ok rm -rf {} \;
|
||||
< rm ... ./bin/runme > ?
|
||||
```
|
||||
|
||||
删除文件并不是 **-ok** 和 **-rm** 能为你做的唯一事情。例如,你可以复制、重命名或移动文件。
|
||||
|
||||
确实有很多选择可以有效地使用 find 命令,毫无疑问还有一些在本文中没有涉及到。我希望你已经找到一些新的,特别有帮助的。
|
||||
|
||||
加入[Facebook][3]和[LinkedIn][4]上的网络世界社区,评论最热门的话题。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3527420/how-to-find-what-you-re-looking-for-on-linux-with-find.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[heguangzhi](https://github.com/heguangzhi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [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/newsletters/signup.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.facebook.com/NetworkWorld/
|
||||
[4]: https://www.linkedin.com/company/network-world
|
||||
@@ -0,0 +1,142 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Session: An Open Source Private Messenger That Doesn’t Need Your Phone Number)
|
||||
[#]: via: (https://itsfoss.com/session-messenger/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
Session:一款不需要电话号码的开源通信应用
|
||||
======
|
||||
|
||||
Signal 作为一款私人通信应用,正在变得愈发流行。而我们下面要介绍开源应用 Session 则是 Signal 的一个<ruby>复刻<rt>fork</rt></ruby>,它的一大亮点是并不需要提供手机号码即可以开始使用。
|
||||
|
||||
### Session:一款真正意义上的私人通信应用
|
||||
|
||||
![][1]
|
||||
|
||||
对于私人通信服务来说,有没有既能保护通信安全性,又尊重用户跨平台隐私的集大成者呢?很多注重个人隐私的用户似乎都在寻找这个问题的答案。
|
||||
|
||||
最近,我留意到 [Loki Foundation][3] 开发的一款叫做 [Session][2] 的开源通信应用。从技术上来说,Session 是另一款[开源、加密的通信应用 Signal][4] 的一个复刻。
|
||||
|
||||
在本文中,我会讲述我自己使用 Session 的体验,以及 Session 的一些主要功能。
|
||||
|
||||
Session 在这个领域中算是一款比较新的应用了,因此我还会在文章的最后提到它的一些不足之处。
|
||||
|
||||
### Session 的一些主要功能
|
||||
|
||||
接下来我会重点介绍 Session 的主要功能,可以供你参考这款应用是否值得使用。
|
||||
|
||||
#### Session 的使用过程中不需要提供手机号码
|
||||
|
||||
![][5]
|
||||
|
||||
在 Signal 或者其它类似的通信应用中,用户都需要提供手机号码才得以成功注册。注重隐私的用户们都认为这样的做法会潜藏着巨大的安全隐患。
|
||||
|
||||
而使用 Session 则简单得多。在 PC 或手机上安装应用之后,只需要点击“<ruby>创建账号<rt>Create Account</rt></ruby>”,无须提供手机号码,它就会生成一个类似 **05652245af9a8bfee4f5a8138fd5c……..** 这样的随机且唯一的 Session ID。
|
||||
|
||||
此后,把 Session ID 分享给想要添加的联系人就可以了。Session 还支持二维码,其他人可以通过扫描二维码添加你的 Session ID 为好友。
|
||||
|
||||
#### Session 使用了区块链等加密技术
|
||||
|
||||
![Session ID][6]
|
||||
|
||||
对[区块链][7]有所了解的用户都很期待区块链能为普罗大众做出什么有实际意义的应用,而 Session 可以算得上其中一个。尽管 Session 的核心是基于区块链的,但普通用户在使用时并不需要真正弄懂区块链。
|
||||
|
||||
如果你好奇它的工作原理,可以参考这篇[官方的博客文章][8],里面有相关的解释。
|
||||
|
||||
#### 跨平台支持
|
||||
|
||||
![][9]
|
||||
|
||||
这样严格保护隐私的应用,是否能在不同平台上使用?
|
||||
|
||||
答案是肯定的。首先,它支持 Linux 和 Android 平台,同时也支持 Windows/Mac/iOS 平台。因此跨平台、跨设备的消息同步是没有问题的。
|
||||
|
||||
#### 包含基本隐私选项
|
||||
|
||||
![][10]
|
||||
|
||||
毫无疑问,基本的隐私功能是必须有的,这是作为一个以安全为卖点的应用所必备的体验。
|
||||
|
||||
最基本的选项包括:
|
||||
|
||||
* **消息有效期**:你可以控制一条消息在接收者阅读前的保留时长
|
||||
* **已读回执**:消息发送者可以知晓你已经阅读该消息
|
||||
|
||||
|
||||
|
||||
#### Session 使用去中心化网络保护你的元数据
|
||||
|
||||
尽管 Session 不使用<ruby>端对端<rt>peer-to-peer</rt></ruby>技术,但它也不适用中心化的服务器。
|
||||
|
||||
Session 采用了去中心化的架构实现消息的传输和路由。如果你不熟悉这方面的内容,可以关注 Session 的官方博客,尝试了解[中心化网络和去中心化网络的区别][11],以及它的实际工作原理。
|
||||
|
||||
同时,这样的网络架构还有助于保护诸如与 IP 地址相关的信息等元数据。
|
||||
|
||||
#### 其它功能
|
||||
|
||||
除了专注于隐私之外,Session 也支持群聊、语音消息、发送附件等通信应用的基本功能。
|
||||
|
||||
### 在 Linux 上安装 Session
|
||||
|
||||
在[官方下载页面][12]中可以下载到对应的 .AppImage 文件。如果你不了解这个文件的使用方法,可以查阅我们的[相关文章][13]。
|
||||
|
||||
另外,你也可以在它的 [Github 发布页面][14] 获取到对应的 .deb 安装文件。
|
||||
|
||||
[下载 Session][12]
|
||||
|
||||
### 我使用 Session 的体验
|
||||
|
||||
我在各种平台上都试用过 Session,其中在 PC 上我使用了 Pop!_OS 19.10 的 .AppImage 文件运行这个应用。
|
||||
|
||||
总的来说,使用的体验很不错,用户界面也没有出现问题。
|
||||
|
||||
在设置中备份了密码(也称为<ruby>种子<rt>seed</rt></ruby>)后,可以很方便地恢复账号。
|
||||
|
||||
![][15]
|
||||
|
||||
当然,我也发现了一些需要改进的地方:
|
||||
|
||||
* 在接受好友请求时会出现延迟
|
||||
* 设备间连接的方式不太直观
|
||||
* 当你在不同的设备上使用同一个 Session ID 向同一个人回复消息时,对方会收到两个不同的对话
|
||||
|
||||
|
||||
|
||||
### 总结
|
||||
|
||||
当然,最完美的事物是不存在的。我也会一直使用 Session 并考虑它发展的方向,这是一个注重引得的用户应该做的事情。
|
||||
|
||||
欢迎在评论区发表你的看法。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/session-messenger/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[HankChow](https://github.com/HankChow)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [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/session-app.jpg?ssl=1
|
||||
[2]: https://getsession.org/
|
||||
[3]: https://loki.foundation/
|
||||
[4]: https://itsfoss.com/signal-messaging-app/
|
||||
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-create.jpg?ssl=1
|
||||
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/03/session-application-id.jpg?ssl=1
|
||||
[7]: https://en.wikipedia.org/wiki/Blockchain
|
||||
[8]: https://getsession.org/how-session-protects-your-anonymity-with-blockchain-and-crypto/
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-cross-platform.jpg?ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-settings.jpg?fit=800%2C512&ssl=1
|
||||
[11]: https://getsession.org/centralisation-vs-decentralisation-in-private-messaging/
|
||||
[12]: https://getsession.org/download/
|
||||
[13]: https://itsfoss.com/use-appimage-linux/
|
||||
[14]: https://github.com/loki-project/session-desktop/releases
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/02/session-seed.jpg?ssl=1
|
||||
Reference in New Issue
Block a user