Byobu 能让你在保持会话活跃的情况下维护多个终端窗口，通过 SSH 连接、断开、重连以及共享访问。Byobu 是基于文本的窗口管理器和终端多路复用器。它类似于 GNU Screen，但更现代、更直观。它还适用于大多数 Linux、BSD 和 Mac 发行版。Byobu 能让你在保持会话活跃的情况下维护多个终端窗口、通过 SSH（secure shell）连接、断开、重连，甚至让其他人访问。比如，你 SSH 进入树莓派或服务器，并运行（比如） sudo apt update && sudo apt upgrade，然后你在它运行的时候失去了互联网连接，你的命令会丢失无效。然而，如果你首先启动 byobu 会话，那么它会继续运行，在你重连后，你会发现它仍在继续运行。Byobu 名称来自于日语的装饰性多面板屏风，它可作为折叠式隔断，我认为这很合适。要在 Debian/Raspbian/Ubuntu 上安装 byobu：sudo apt install byobu接着启用它：byobu-enable现在，请退出 SSH 会话并重新登录，你将会在 byobu 会话中登录。运行类似 sudo apt update 命令并关闭窗口（或输入转义序列（Enter + ~ + .）并重新登录。你将看到更新命令在你离开后还在运行。有很多我不常使用的功能。我通常使用的是：F2 – 新窗口F3/F4 – 在窗口间导航Ctrl+F2 – 垂直拆分窗格Shift+F2 – 水平拆分窗格Shift+左箭头/Shift+右箭头 – 在拆分窗格间导航Shift+F11 – 放大（或缩小）拆分窗格我们如何使用 byobuByobu 对于维护 piwheels（一个用于树莓派的方便的，预编译 Python 包）很好用。我水平拆分了窗格，在上半部分显示了 piwheels 监视器，在下半部分实时显示了 syslog 条目。接着，如果我们想要做其他事情，我们可以切换到另外一个窗口。当我们进行协作分析时，这特别方便，因为当我在 IRC 中聊天时，我可以看到我的同事 Dave 输入了什么（并纠正他的错字）。我在家庭和办公服务器上启用了 byobu，因此，当我登录到任何一台计算机时，一切都与我离开时一样。它正在运行多个作业、在特定目录中保留一个窗口，以另一个用户身份运行进程等。Byobu 对于在树莓派上进行开发也很方便。你可以在桌面上启动它，运行命令，然后 SSH 进入，并连接到该命令运行所在的会话。请注意，启用 byobu 不会更改终端启动器的功能。只需运行 byobu 即可启动它。本文最初发表在 Ben Nuttall 的 Tooling blog 中，并获许重用。via: https://opensource.com/article/20/2/byobu-ssh作者：Ben Nuttall 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
了解如何使用 Python 和 GNU Octave 完成一项常见的数据科学任务。数据科学是跨越编程语言的知识领域。有些语言以解决这一领域的问题而闻名，而另一些则鲜为人知。这篇文章将帮助你熟悉用一些流行的语言完成数据科学的工作。选择 Python 和 GNU Octave 做数据科学工作我经常尝试学习一种新的编程语言。为什么？这既有对旧方式的厌倦，也有对新方式的好奇。当我开始学习编程时，我唯一知道的语言是 C 语言。那些年的编程生涯既艰难又危险，因为我必须手动分配内存、管理指针、并记得释放内存。后来一个朋友建议我试试 Python，现在我的编程生活变得轻松多了。虽然程序运行变得慢多了，但我不必通过编写分析软件来受苦了。然而，我很快就意识到每种语言都有比其它语言更适合自己的应用场景。后来我学习了一些其它语言，每种语言都给我带来了一些新的启发。发现新的编程风格让我可以将一些解决方案移植到其他语言中，这样一切都变得有趣多了。为了对一种新的编程语言（及其文档）有所了解，我总是从编写一些执行我熟悉的任务的示例程序开始。为此，我将解释如何用 Python 和 GNU Octave 编写一个程序来完成一个你可以归类为数据科学的特殊任务。如果你已经熟悉其中一种语言，从它开始，然后通过其他语言寻找相似之处和不同之处。这篇文章并不是对编程语言的详尽比较，只是一个小小的展示。所有的程序都应该在命令行上运行，而不是用图形用户界面（GUI）。完整的例子可以在 polyglot\_fit 存储库中找到。编程任务你将在本系列中编写的程序:从 CSV 文件中读取数据用直线插入数据（例如 f(x)=m ⋅ x + q）将结果生成图像文件这是许多数据科学家遇到的常见情况。示例数据是 Anscombe 的四重奏的第一组，如下表所示。这是一组人工构建的数据，当用直线拟合时会给出相同的结果，但是它们的曲线非常不同。数据文件是一个文本文件，以制表符作为列分隔符，开头几行作为标题。此任务将仅使用第一组（即前两列）。Python 方式Python 是一种通用编程语言，是当今最流行的语言之一（依据 TIOBE 指数、RedMonk 编程语言排名、编程语言流行指数、GitHub Octoverse 状态和其他来源的调查结果）。它是一种解释型语言；因此，源代码由执行该指令的程序读取和评估。它有一个全面的标准库并且总体上非常好用（我对这最后一句话没有证据；这只是我的拙见）。安装要使用 Python 开发，你需要解释器和一些库。最低要求是：NumPy 用于简化数组和矩阵的操作SciPy 用于数据科学Matplotlib 用于绘图在 Fedora 安装它们是很容易的：sudo dnf install python3 python3-numpy python3-scipy python3-matplotlib代码注释在 Python中，注释)是通过在行首添加一个 # 来实现的，该行的其余部分将被解释器丢弃：# 这是被解释器忽略的注释。fitting\_python.py 示例使用注释在源代码中插入许可证信息，第一行是特殊注释)，它允许该脚本在命令行上执行:#!/usr/bin/env python3这一行通知命令行解释器，该脚本需要由程序 python3 执行。需要的库在 Python 中，库和模块可以作为一个对象导入（如示例中的第一行），其中包含库的所有函数和成员。可以通过使用 as 方式用自定义标签重命名它们：import numpy as np from scipy import stats import matplotlib.pyplot as plt你也可以决定只导入一个子模块（如第二行和第三行）。语法有两个（基本上）等效的方式：import module.submodule 和 from module import submodule。定义变量Python 的变量是在第一次赋值时被声明的：input_file_name = "anscombe.csv" delimiter = "\t" skip_header = 3 column_x = 0 column_y = 1变量类型由分配给变量的值推断。没有具有常量值的变量，除非它们在模块中声明并且只能被读取。习惯上，不应被修改的变量应该用大写字母命名。打印输出通过命令行运行程序意味着输出只能打印在终端上。Python 有 print() 函数，默认情况下，该函数打印其参数，并在输出的末尾添加一个换行符：print("#### Anscombe's first set with Python ####")在 Python 中，可以将 print() 函数与字符串类的格式化能力相结合。字符串具有format 方法，可用于向字符串本身添加一些格式化文本。例如，可以添加格式化的浮点数，例如:print("Slope: {:f}".format(slope))读取数据使用 NumPy 和函数 genfromtxt() 读取 CSV 文件非常容易，该函数生成 NumPy 数组：data = np.genfromtxt(input_file_name, delimiter = delimiter, skip_header = skip_header)在 Python 中，一个函数可以有数量可变的参数，你可以通过指定所需的参数来传递一个参数的子集。数组是非常强大的矩阵状对象，可以很容易地分割成更小的数组：x = data[:, column_x] y = data[:, column_y]冒号选择整个范围，也可以用来选择子范围。例如，要选择数组的前两行，可以使用：first_two_rows = data[0:1, :]拟合数据SciPy 提供了方便的数据拟合功能，例如 linregress() 功能。该函数提供了一些与拟合相关的重要值，如斜率、截距和两个数据集的相关系数:slope, intercept, r_value, p_value, std_err = stats.linregress(x, y) print("Slope: {:f}".format(slope)) print("Intercept: {:f}".format(intercept)) print("Correlation coefficient: {:f}".format(r_value))因为 linregress() 提供了几条信息，所以结果可以同时保存到几个变量中。绘图Matplotlib 库仅仅绘制数据点，因此，你应该定义要绘制的点的坐标。已经定义了 x 和 y 数组，所以你可以直接绘制它们，但是你还需要代表直线的数据点。fit_x = np.linspace(x.min() - 1, x.max() + 1, 100)linspace() 函数可以方便地在两个值之间生成一组等距值。利用强大的 NumPy 数组可以轻松计算纵坐标，该数组可以像普通数值变量一样在公式中使用：fit_y = slope * fit_x + intercept该公式在数组中逐元素应用；因此，结果在初始数组中具有相同数量的条目。要绘图，首先，定义一个包含所有图形的图形对象：fig_width = 7 #inch fig_height = fig_width / 16 * 9 #inch fig_dpi = 100 fig = plt.figure(figsize = (fig_width, fig_height), dpi = fig_dpi)一个图形可以画几个图；在 Matplotlib 中，这些图被称为轴。本示例定义一个单轴对象来绘制数据点：ax = fig.add_subplot(111) ax.plot(fit_x, fit_y, label = "Fit", linestyle = '-') ax.plot(x, y, label = "Data", marker = '.', linestyle = '') ax.legend() ax.set_xlim(min(x) - 1, max(x) + 1) ax.set_ylim(min(y) - 1, max(y) + 1) ax.set_xlabel('x') ax.set_ylabel('y')将该图保存到 PNG 图形文件中，有:fig.savefig('fit_python.png')如果要显示（而不是保存）该绘图，请调用：plt.show()此示例引用了绘图部分中使用的所有对象：它定义了对象 fig 和对象 ax。这在技术上是不必要的，因为 plt 对象可以直接用于绘制数据集。《Matplotlib 教程》展示了这样一个接口：plt.plot(fit_x, fit_y)坦率地说，我不喜欢这种方法，因为它隐藏了各种对象之间发生的重要交互。不幸的是，有时官方的例子有点令人困惑，因为他们倾向于使用不同的方法。在这个简单的例子中，引用图形对象是不必要的，但是在更复杂的例子中（例如在图形用户界面中嵌入图形时），引用图形对象就变得很重要了。结果命令行输入：#### Anscombe's first set with Python #### Slope: 0.500091 Intercept: 3.000091 Correlation coefficient: 0.816421这是 Matplotlib 产生的图像：GNU Octave 方式GNU Octave 语言主要用于数值计算。它提供了一个简单的操作向量和矩阵的语法，并且有一些强大的绘图工具。这是一种像 Python 一样的解释语言。由于 Octave 的语法几乎兼容 MATLAB，它经常被描述为一个替代 MATLAB 的免费方案。Octave 没有被列为最流行的编程语言，而 MATLAB 则是，所以 Octave 在某种意义上是相当流行的。MATLAB 早于 NumPy，我觉得它是受到了前者的启发。当你看这个例子时，你会看到相似之处。安装fitting\_octave.m 的例子只需要基本的 Octave 包，在 Fedora 中安装相当简单：sudo dnf install octave代码注释在 Octave 中，你可以用百分比符号（%）为代码添加注释，如果不需要与 MATLAB 兼容，你也可以使用 #。使用 # 的选项允许你编写像 Python 示例一样的特殊注释行，以便直接在命令行上执行脚本。必要的库本例中使用的所有内容都包含在基本包中，因此你不需要加载任何新的库。如果你需要一个库，语法是 pkg load module。该命令将模块的功能添加到可用功能列表中。在这方面，Python 具有更大的灵活性。定义变量变量的定义与 Python 的语法基本相同：input_file_name = "anscombe.csv"; delimiter = "\t"; skip_header = 3; column_x = 1; column_y = 2;请注意，行尾有一个分号；这不是必需的，但是它会抑制该行结果的输出。如果没有分号，解释器将打印表达式的结果：octave:1> input_file_name = "anscombe.csv" input_file_name = anscombe.csv octave:2> sqrt(2) ans = 1.4142打印输出结果强大的函数 printf() 是用来在终端上打印的。与 Python 不同，printf() 函数不会自动在打印字符串的末尾添加换行，因此你必须添加它。第一个参数是一个字符串，可以包含要传递给函数的其他参数的格式信息，例如：printf("Slope: %f\n", slope);在 Python 中，格式是内置在字符串本身中的，但是在 Octave 中，它是特定于 printf() 函数。读取数据dlmread() 函数可以读取类似 CSV 文件的文本内容：data = dlmread(input_file_name, delimiter, skip_header, 0);结果是一个矩阵对象，这是 Octave 中的基本数据类型之一。矩阵可以用类似于 Python 的语法进行切片：x = data(:, column_x); y = data(:, column_y);根本的区别是索引从 1 开始，而不是从 0 开始。因此，在该示例中，x 列是第一列。拟合数据要用直线拟合数据，可以使用 polyfit() 函数。它用一个多项式拟合输入数据，所以你只需要使用一阶多项式：p = polyfit(x, y, 1); slope = p(1); intercept = p(2);结果是具有多项式系数的矩阵；因此，它选择前两个索引。要确定相关系数，请使用 corr() 函数：r_value = corr(x, y);最后，使用 printf() 函数打印结果：printf("Slope: %f\n", slope); printf("Intercept: %f\n", intercept); printf("Correlation coefficient: %f\n", r_value);绘图与 Matplotlib 示例一样，首先需要创建一个表示拟合直线的数据集:fit_x = linspace(min(x) - 1, max(x) + 1, 100); fit_y = slope * fit_x + intercept;与 NumPy 的相似性也很明显，因为它使用了 linspace() 函数，其行为就像 Python 的等效版本一样。同样，与 Matplotlib 一样，首先创建一个图对象，然后创建一个轴对象来保存这些图：fig_width = 7; %inch fig_height = fig_width / 16 * 9; %inch fig_dpi = 100; fig = figure("units", "inches", "position", [1, 1, fig_width, fig_height]); ax = axes("parent", fig); set(ax, "fontsize", 14); set(ax, "linewidth", 2);要设置轴对象的属性，请使用 set() 函数。然而，该接口相当混乱，因为该函数需要一个逗号分隔的属性和值对列表。这些对只是代表属性名的一个字符串和代表该属性值的第二个对象的连续。还有其他设置各种属性的函数：xlim(ax, [min(x) - 1, max(x) + 1]); ylim(ax, [min(y) - 1, max(y) + 1]); xlabel(ax, 'x'); ylabel(ax, 'y');绘图是用 plot() 功能实现的。默认行为是每次调用都会重置坐标轴，因此需要使用函数 hold()。hold(ax, "on"); plot(ax, fit_x, fit_y, "marker", "none", "linestyle", "-", "linewidth", 2); plot(ax, x, y, "marker", ".", "markersize", 20, "linestyle", "none"); hold(ax, "off");此外，还可以在 plot() 函数中添加属性和值对。legend 必须单独创建，标签应手动声明：lg = legend(ax, "Fit", "Data"); set(lg, "location", "northwest");最后，将输出保存到 PNG 图像：image_size = sprintf("-S%f,%f", fig_width * fig_dpi, fig_height * fig_dpi); image_resolution = sprintf("-r%f,%f", fig_dpi); print(fig, 'fit_octave.png', '-dpng', image_size, image_resolution);令人困惑的是，在这种情况下，选项被作为一个字符串传递，带有属性名和值。因为在 Octave 字符串中没有 Python 的格式化工具，所以必须使用 sprintf() 函数。它的行为就像 printf() 函数，但是它的结果不是打印出来的，而是作为字符串返回的。在这个例子中，就像在 Python 中一样，图形对象很明显被引用以保持它们之间的交互。如果说 Python 在这方面的文档有点混乱，那么 Octave 的文档就更糟糕了。我发现的大多数例子都不关心引用对象；相反，它们依赖于绘图命令作用于当前活动图形。全局根图形对象跟踪现有的图形和轴。结果命令行上的结果输出是：#### Anscombe's first set with Octave #### Slope: 0.500091 Intercept: 3.000091 Correlation coefficient: 0.816421它显示了用 Octave 生成的结果图像。接下来Python 和 GNU Octave 都可以绘制出相同的信息，尽管它们的实现方式不同。如果你想探索其他语言来完成类似的任务，我强烈建议你看看 Rosetta Code。这是一个了不起的资源，可以看到如何用多种语言解决同样的问题。你喜欢用什么语言绘制数据？在评论中分享你的想法。via: https://opensource.com/article/20/2/python-gnu-octave-data-science作者：Cristiano L. Fontana 选题：lujun9972 译者：heguangzhi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
Mongo（来自 “humongous” —— 巨大的）是一个高性能、开源、无模式的、面向文档的数据库，它是最受欢迎的 NoSQL 数据库之一。它使用 JSON 作为文档格式，并且可以在多个服务器节点之间进行扩展和复制。有关许可证更改的故事MongoDB 上游决定更改服务器代码的许可证已经一年多了。先前的许可证是 GNU Affero General Public License v3（AGPLv3）。但是，上游公司写了一个新许可证，旨在使运行 MongoDB 即服务的公司可以回馈社区。新许可证称为 Server Side Public License（SSPLv1），关于这个举措及其解释的更多说明，请参见 MongoDB SSPL FAQ。Fedora 一直只包含自由软件。当 SSPL 发布后，Fedora 确定它并不是自由软件许可证。许可证更改日期（2018 年 10 月）之前发布的所有 MongoDB 版本都可保留在 Fedora 中，但之后再也不更新的软件包会带来安全问题。因此，从 Fedora 30 开始，Fedora 社区决定完全移除 MongoDB 服务器。开发人员还有哪些选择？是的，还有替代方案，例如 PostgreSQL 在最新版本中也支持 JSON，它可以在无法再使用 MongoDB 的情况下使用它。使用 JSONB 类型，索引在 PostgreSQL 中可以很好地工作，其性能可与 MongoDB 媲美，甚至不会受到 ACID 的影响。开发人员可能选择 MongoDB 的技术原因并未随许可证而改变，因此许多人仍想使用它。重要的是要意识到，SSPL 许可证仅更改仅针对 MongoDB 服务器。MongoDB 上游还开发了其他项目，例如 MongoDB 工具、C 和 C++ 客户端库以及用于各种动态语言的连接器，这些项目在客户端使用（通过网络与服务器通信的应用中）。由于这些包的许可证人保持自由（主要是 Apache 许可证），因此它们保留在 Fedora 仓库中，因此用户可以将其用于应用开发。唯一的变化实际是服务器软件包本身，它已从 Fedora 仓库中完全删除。让我们看看 Fedora 用户可以如何获取非自由的包。如何从上游安装 MongoDB 服务器当 Fedora 用户想要安装 MongoDB 服务器时，他们需要直接向上游获取 MongoDB。但是，上游不为 Fedora 提供 RPM 包。相反，MongoDB 服务器可以获取源码 tarball，用户需要自己进行编译（这需要一些开发知识），或者 Fedora 用户可以使用一些兼容的包。在兼容的选项中，最好的选择是 RHEL-8 RPM。以下步骤描述了如何安装它们以及如何启动守护进程。1、使用上游 RPM 创建仓库（RHEL-8 构建）$ sudo cat > /etc/yum.repos.d/mongodb.repo >>EOF [mongodb-upstream] name=MongoDB Upstream Repository baseurl=https://repo.mongodb.org/yum/redhat/8Server/mongodb-org/4.2/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc EOF2、安装元软件包，来拉取服务器和工具包$ sudo dnf install mongodb-org ...... Installed: mongodb-org-4.2.3-1.el8.x86_64 mongodb-org-mongos-4.2.3-1.el8.x86_64 mongodb-org-server-4.2.3-1.el8.x86_64 mongodb-org-shell-4.2.3-1.el8.x86_64 mongodb-org-tools-4.2.3-1.el8.x86_64 Complete!3、启动 MongoDB 守护进程$ sudo systemctl status mongod ● mongod.service - MongoDB Database Server Loaded: loaded (/usr/lib/systemd/system/mongod.service; enabled; vendor preset: disabled) Active: active (running) since Sat 2020-02-08 12:33:45 EST; 2s ago Docs: https://docs.mongodb.org/manual Process: 15768 ExecStartPre=/usr/bin/mkdir -p /var/run/mongodb (code=exited, status=0/SUCCESS) Process: 15769 ExecStartPre=/usr/bin/chown mongod:mongod /var/run/mongodb (code=exited, status=0/SUCCESS) Process: 15770 ExecStartPre=/usr/bin/chmod 0755 /var/run/mongodb (code=exited, status=0/SUCCESS) Process: 15771 ExecStart=/usr/bin/mongod $OPTIONS (code=exited, status=0/SUCCESS) Main PID: 15773 (mongod) Memory: 70.4M CPU: 611ms CGroup: /system.slice/mongod.service 4、通过 mongo shell 连接服务器来验证是否运行$ mongo MongoDB shell version v4.2.3 connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb Implicit session: session { "id" : UUID("20b6e61f-c7cc-4e9b-a25e-5e306d60482f") } MongoDB server version: 4.2.3 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see http://docs.mongodb.org/ ---就是这样了。如你所见，RHEL-8 包完美兼容，只要 Fedora 包还与 RHEL-8 兼容，它就应该会一直兼容。请注意，在使用时必须遵守 SSPLv1 许可证。via: https://fedoramagazine.org/how-to-get-mongodb-server-on-fedora/作者：Honza Horak 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
对于原生云生态系统来说，2019 年是改变游戏规则的一年。有大的并购，如 Red Hat Docker 和 Pivotal，并出现其他的玩家，如 Rancher Labs 和 Mirantis。Rancher Labs （一家为采用容器的团队提供完整软件栈的公司）的联合创始人兼首席执行官盛亮表示：“所有这些整合和并购，都表明这一领域的市场成熟的速度很快。”传统上，像 Kubernetes 和 Docker 这样的新兴技术吸引着开发者和像脸书和谷歌这样的超级用户。除了这群人之外则没什么兴趣。然而，这两种技术都在企业层面得到了广泛采用。突然间，出现了一个巨大的市场，有着巨大的机会。几乎每个人都跳了进去。有人带来了创新的解决方案，也有人试图赶上其他人。它很快变得非常拥挤和热闹起来。它也改变了创新的方式。早期采用者通常是精通技术的公司。现在，几乎每个人都在使用它，即使是在不被认为是 Kubernetes 地盘的地方。它改变了市场动态，像 Rancher Labs 这样的公司见证了独特的用例。盛亮补充道，“我从来没有经历过像 Kubernete 这样快速、动态的市场或技术演变。当我们五年前开始的时候，这是一个非常拥挤的空间。随着时间的推移，我们大多数的友商因为这样或那样的原因消失了。他们要么无法适应变化，要么选择不适应某些变化。”在 Kubernetes 的早期，最明显的机会是建立 Kubernetes 发行版本和 Kubernetes 业务。这是新技术。众所周知，它的安装、升级和操作相当的复杂。当谷歌、AWS 和微软进入市场时，一切都变了。当时，一群供应商蜂拥而至，为平台提供解决方案。盛亮表示:“一旦像谷歌这样的云提供商决定将 Kubernetes 作为一项服务，并免费提供亏本出售的商品，以推动基础设施消费；我们就知道，运营和支持 Kubernetes 业务的优势将非常有限了。”对谷歌之外的其它玩家来说，并非一切都不好。由于云供应商通过将它作为服务来提供，消除了 Kubernetes 带来的所有复杂性，这意味着更广泛地采用该技术，即使是那些由于运营成本而不愿使用该技术的人也是如此。这意味着 Kubernetes 将变得无处不在，并将成为一个行业标准。“Rancher Labs 是极少数将此视为机遇并比其他公司看得更远的公司之一。我们意识到 Kubernetes 将成为新的计算标准，就像 TCP/IP 成为网络标准一样，”盛亮说。CNCF 在围绕 Kubernetes 构建一个充满活力的生态系统方面发挥着至关重要的作用，创建了一个庞大的社区来构建、培育和商业化原生云开源技术。via: https://www.linux.com/articles/how-kubernetes-became-the-standard-for-compute-resources/作者：Swapnil Bhartiya 选题：lujun9972 译者：heguangzhi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
elementary OS 正在构建一个可以买应用的开源应用商店
elementary OS 正在构建一个应用中心生态系统，你可以在其中购买用于 Linux 发行版的开源应用程序。众筹构建一个开源应用中心elementary OS 最近宣布，它正在众筹举办一个构建应用中心的活动，你可以从这个应用中心购买开源应用程序。应用中心中的应用程序将为 Flatpak 格式。尽管这是 elementary OS 发起的活动，但这个新的应用中心也将适用于其他发行版。该活动旨在资助在美国科罗拉多州丹佛市进行的一项一周个人开发冲刺活动，其中包括来自 elementary OS、Endless、Flathub 和 GNOME 的开发人员。众筹活动已经超过了筹集 1 万美元的目标（LCTT 译注：截止至本译文发布，已近 15000 美金）。但你仍然可以为其提供资金，因为其他资金将用于开发 elementary OS。这个应用中心将带来什么功能其重点是提供“安全”应用程序，因此使用 Flatpak 应用来提供受限的应用程序。在这种格式下，默认情况下将会限制应用程序访问系统或个人文件，并在技术层面上将它们与其他应用程序隔离。仅当你明确表示同意时，应用程序才能访问操作系统和个人文件。除了安全性，Flatpak 还捆绑了所有依赖项。这样，即使当前 Linux 发行版中不提供这些依赖项，应用程序开发人员也可以利用这种最先进的技术使用它。AppCenter 还具有钱包功能，可以保存你的信用卡详细信息。这样，你无需每次输入卡的详细信息即可快速为应用付费。这个新的开源“应用中心”也将适用于其他 Linux 发行版。受到了 elementary OS 自己的“按需付费”应用中心模型成功的启发几年前，elementary OS 推出了自己的应用中心。应用中心的“按需付费”方法很受欢迎。开发人员可以为其开源应用设置最低金额，而用户可以选择支付等于或高于最低金额的金额。这帮助了几位独立开发人员可以对其开源应用程序接受付款。该应用中心现在拥有约 160 个原生应用程序，elementary OS 表示已通过应用中心向开发人员支付了数千美元。受到此应用中心实验在 elementary OS 中的成功的启发，他们现在也希望将此应用中心的方法也引入其他发行版。如果应用程序是开源的，你怎么为此付费？某些人仍然对 FOSS（自由而开源）的概念感到困惑。在这里，该软件的“源代码”是“开源的”，任何人都可以“自由”进行修改和重新分发。但这并不意味着开源软件必须免费。一些开发者依靠捐赠，而另一些则收取支持费用。获得开源应用程序的报酬可能会鼓励开发人员创建 Linux 应用程序。让我们拭目以待就个人而言，我不是 Flatpak 或 Snap 包格式的忠实拥护者。它们确实有其优点，但是它们花费了相对更多的时间来启动，并且它们的包大小很大。如果安装了多个此类 Snap 或 Flatpak 软件包，磁盘空间就会慢慢耗尽。也需要对这个新的应用程序生态系统中的假冒和欺诈开发者保持警惕。想象一下，如果某些骗子开始创建冷门的开源应用程序的 Flatpak 程序包，并将其放在应用中心上？我希望开发人员采用某种机制来淘汰此类应用程序。我确实希望这个新的应用中心能够复制在 elementary OS 中已经看到的成功。对于桌面 Linux 的开源应用程序，我们绝对需要更好的生态系统。你对此有何看法？这是正确的方法吗？你对改进应用中心有什么建议？via: https://itsfoss.com/appcenter-for-everyone/作者：Abhishek Prakash 选题：lujun9972 译者：wxy 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
你知道吗，Emacs 捆绑了一个俄罗斯方块的实现？只需要输入 M-x tetris 就行了。在对文本编辑器的讨论中，Emacs 鼓吹者经常提到这一点。“没错，但是你那个编辑器能运行俄罗斯方块吗？”我很好奇，这会让大家相信 Emacs 更优秀吗？比如，为什么有人会关心他们是否可以在文本编辑器中玩游戏呢？“没错，但是你那台吸尘器能播放 mp3 吗？”有人说，俄罗斯方块总是很有趣的。像 Emacs 中的所有东西一样，它的源代码是开放的，易于检查和修改，因此 我们可以使它变得更加有趣。所谓更加有趣，我的意思是更难。让游戏变得更难的一个最简单的方法就是“隐藏下一个块预览”。你无法在知道下一个块会填满空间的情况下有意地将 S/Z 块放在一个危险的位置——你必须碰碰运气，希望出现最好的情况。下面是没有预览的情况（如你所见，没有预览，我做出的某些选择带来了“可怕的后果”）:预览框由一个名为 tetris-draw-next-shape 1 的函数设置：(defun tetris-draw-next-shape () (dotimes (x 4) (dotimes (y 4) (gamegrid-set-cell (+ tetris-next-x x) (+ tetris-next-y y) tetris-blank))) (dotimes (i 4) (let ((tetris-shape tetris-next-shape) (tetris-rot 0)) (gamegrid-set-cell (+ tetris-next-x (aref (tetris-get-shape-cell i) 0)) (+ tetris-next-y (aref (tetris-get-shape-cell i) 1)) tetris-shape))))首先，我们引入一个标志，决定是否允许显示下一个预览块 2 ：(defvar tetris-preview-next-shape nil "When non-nil, show the next block the preview box.")现在的问题是，我们如何才能让 tetris-draw-next-shape 遵从这个标志？最明显的方法是重新定义它：(defun tetris-draw-next-shape () (when tetris-preview-next-shape ;; existing tetris-draw-next-shape logic ))但这不是理想的解决方案。同一个函数有两个定义，这很容易引起混淆，如果上游版本发生变化，我们必须维护修改后的定义。一个更好的方法是使用 advice。Emacs 的 advice 类似于 Python 装饰器，但是更加灵活，因为 advice 可以从任何地方添加到函数中。这意味着我们可以修改函数而不影响原始的源文件。有很多不同的方法使用 Emacs advice（查看手册），但是这里我们只使用 advice-add 函数和 :around 标志。advice 函数将原始函数作为参数，原始函数可能执行也可能不执行。我们这里，我们让原始函数只有在预览标志是非空的情况下才能执行：(defun tetris-maybe-draw-next-shape (tetris-draw-next-shape) (when tetris-preview-next-shape (funcall tetris-draw-next-shape))) (advice-add 'tetris-draw-next-shape :around #'tetris-maybe-draw-next-shape)这段代码将修改 tetris-draw-next-shape 的行为，而且它可以存储在配置文件中，与实际的俄罗斯方块代码分离。去掉预览框是一个简单的改变。一个更激烈的变化是，让块随机停止在空中：本图中，红色的 I 和绿色的 T 部分没有掉下来，它们被固定下来了。这会让游戏变得 极其困难，但却很容易实现。和前面一样，我们首先定义一个标志：(defvar tetris-stop-midair t "If non-nil, pieces will sometimes stop in the air.")目前，Emacs 俄罗斯方块的工作方式 类似这样子：活动部件有 x 和 y 坐标。在每个时钟滴答声中，y 坐标递增（块向下移动一行），然后检查是否有与现存的块重叠。如果检测到重叠，则将该块回退（其 y 坐标递减）并设置该活动块到位。为了让一个块在半空中停下来，我们所要做的就是破解检测函数 tetris-test-shape。这个函数内部做什么并不重要 —— 重要的是它是一个返回布尔值的无参数函数。我们需要它在正常情况下返回布尔值 true（否则我们将出现奇怪的重叠情况），但在其他时候也需要它返回 true。我相信有很多方法可以做到这一点，以下是我的方法的：(defun tetris-test-shape-random (tetris-test-shape) (or (and tetris-stop-midair ;; Don't stop on the first shape. (< 1 tetris-n-shapes ) ;; Stop every INTERVAL pieces. (let ((interval 7)) (zerop (mod tetris-n-shapes interval))) ;; Don't stop too early (it makes the game unplayable). (let ((upper-limit 8)) (< upper-limit tetris-pos-y)) ;; Don't stop at the same place every time. (zerop (mod (random 7) 10))) (funcall tetris-test-shape))) (advice-add 'tetris-test-shape :around #'tetris-test-shape-random)这里的硬编码参数使游戏变得更困难，但仍然可玩。当时我在飞机上喝醉了，所以它们可能需要进一步调整。顺便说一下，根据我的 tetris-scores 文件，我的 最高分 是：01389 Wed Dec 5 15:32:19 2018该文件中列出的分数默认最多为五位数，因此这个分数看起来不是很好。给读者的练习使用 advice 修改 Emacs 俄罗斯方块，使得每当方块下移动时就闪烁显示讯息 “OH SHIT”。消息的大小与块堆的高度成比例（当没有块时，消息应该很小的或不存在的，当最高块接近天花板时，消息应该很大）。在这里给出的 tetris-test-shape-random 版本中，每隔七格就有一个半空中停止。一个玩家有可能能计算出时间间隔，并利用它来获得优势。修改它，使间隔随机在一些合理的范围内（例如，每 5 到 10 格）。另一个对使用 Tetris 使用 advise 的场景，你可以试试 autotetris-mode。想出一个有趣的方法来打乱块的旋转机制，然后使用 advice 来实现它。Emacs 只有一个巨大的全局命名空间，因此函数和变量名一般以包名做前缀以避免冲突。 ↩很多人会说你不应该使用已有的命名空间前缀而且应该将自己定义的所有东西都放在一个预留的命名空间中，比如像这样 my/tetris-preview-next-shape，然而这样很难看而且没什么意义，因此我不会这么干。 ↩via: https://nickdrozd.github.io/2019/01/14/tetris.html作者：nickdrozd 选题：lujun9972 译者：lujun9972 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
用 KRAWL 脚本来识别 Kubernetes Pod 和容器中的错误。当你使用 Kubernetes 运行容器时，你通常会发现它们堆积在一起。这是设计使然。它是容器的优点之一：每当需要新的容器时，它们启动成本都很低。你可以使用前端工具（如 OpenShift 或 OKD）来管理 Pod 和容器。这些工具使可视化设置变得容易，并且它具有一组丰富的用于快速交互的命令。如果管理容器的平台不符合你的要求，你也可以仅使用 Kubernetes 工具链获取这些信息，但这需要大量命令才能全面了解复杂环境。出于这个原因，我编写了 KRAWL，这是一个简单的脚本，可用于扫描 Kubernetes 集群命名空间下的 Pod 和容器，并在发现任何事件时，显示事件的输出。它也可用作为 Kubernetes 插件使用。这是获取大量有用信息的快速简便方法。先决条件必须安装 kubectl。集群的 kubeconfig 配置必须在它的默认位置（$HOME/.kube/config）或已被导出到环境变量（KUBECONFIG=/path/to/kubeconfig）。使用$ ./krawl脚本#!/bin/bash # AUTHOR: Abhishek Tamrakar # EMAIL: abhishek.tamrakar08@gmail.com # LICENSE: Copyright (C) 2018 Abhishek Tamrakar # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ## #define the variables KUBE_LOC=~/.kube/config #define variables KUBECTL=$(which kubectl) GET=$(which egrep) AWK=$(which awk) red=$(tput setaf 1) normal=$(tput sgr0) # define functions # wrapper for printing info messages info() { printf '\n\e[34m%s\e[m: %s\n' "INFO" "$@" } # cleanup when all done cleanup() { rm -f results.csv } # just check if the command we are about to call is available checkcmd() { #check if command exists local cmd=$1 if [ -z "${!cmd}" ] then printf '\n\e[31m%s\e[m: %s\n' "ERROR" "check if $1 is installed !!!" exit 1 fi } get_namespaces() { #get namespaces namespaces=( \ $($KUBECTL get namespaces --ignore-not-found=true | \ $AWK '/Active/ {print $1}' \ ORS=" ") \ ) #exit if namespaces are not found if [ ${#namespaces[@]} -eq 0 ] then printf '\n\e[31m%s\e[m: %s\n' "ERROR" "No namespaces found!!" exit 1 fi } #get events for pods in errored state get_pod_events() { printf '\n' if [ ${#ERRORED[@]} -ne 0 ] then info "${#ERRORED[@]} errored pods found." for CULPRIT in ${ERRORED[@]} do info "POD: $CULPRIT" info $KUBECTL get events \ --field-selector=involvedObject.name=$CULPRIT \ -ocustom-columns=LASTSEEN:.lastTimestamp,REASON:.reason,MESSAGE:.message \ --all-namespaces \ --ignore-not-found=true done else info "0 pods with errored events found." fi } #define the logic get_pod_errors() { printf "%s %s %s\n" "NAMESPACE,POD_NAME,CONTAINER_NAME,ERRORS" > results.csv printf "%s %s %s\n" "---------,--------,--------------,------" >> results.csv for NAMESPACE in ${namespaces[@]} do while IFS=' ' read -r POD CONTAINERS do for CONTAINER in ${CONTAINERS//,/ } do COUNT=$($KUBECTL logs --since=1h --tail=20 $POD -c $CONTAINER -n $NAMESPACE 2>/dev/null| \ $GET -c '^error|Error|ERROR|Warn|WARN') if [ $COUNT -gt 0 ] then STATE=("${STATE[@]}" "$NAMESPACE,$POD,$CONTAINER,$COUNT") else #catch pods in errored state ERRORED=($($KUBECTL get pods -n $NAMESPACE --no-headers=true | \ awk '!/Running/ {print $1}' ORS=" ") \ ) fi done done< <($KUBECTL get pods -n $NAMESPACE --ignore-not-found=true -o=custom-columns=NAME:.metadata.name,CONTAINERS:.spec.containers[*].name --no-headers=true) done printf "%s\n" ${STATE[@]:-None} >> results.csv STATE=() } #define usage for seprate run usage() { cat << EOF USAGE: "${0##*/} </path/to/kube-config>(optional)" This program is a free software under the terms of Apache 2.0 License. COPYRIGHT (C) 2018 Abhishek Tamrakar EOF exit 0 } #check if basic commands are found trap cleanup EXIT checkcmd KUBECTL # #set the ground if [ $# -lt 1 ]; then if [ ! -e ${KUBE_LOC} -a ! -s ${KUBE_LOC} ] then info "A readable kube config location is required!!" usage fi elif [ $# -eq 1 ] then export KUBECONFIG=$1 elif [ $# -gt 1 ] then usage fi #play get_namespaces get_pod_errors printf '\n%40s\n' 'KRAWL' printf '%s\n' '---------------------------------------------------------------------------------' printf '%s\n' ' Krawl is a command line utility to scan pods and prints name of errored pods ' printf '%s\n\n' ' +and containers within. To use it as kubernetes plugin, please check their page ' printf '%s\n' '=================================================================================' cat results.csv | sed 's/,/,|/g'| column -s ',' -t get_pod_events此文最初发布在 KRAWL 的 GitHub 仓库下的 README 中，并被或许重用。via: https://opensource.com/article/20/2/kubernetes-scanner作者：Abhishek Tamrakar 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
准备好你喜欢的饮料、编辑器和编译器，放一些音乐，然后开始构建一个由多个文件组成的 C 语言程序。大家常说计算机编程的艺术部分是处理复杂性，部分是命名某些事物。此外，我认为“有时需要添加绘图”是在很大程度上是正确的。在这篇文章里，我会编写一个小型 C 程序，命名一些东西，同时处理一些复杂性。该程序的结构大致基于我在 《如何写一个好的 C 语言 main 函数》 文中讨论的。但是，这次做一些不同的事。准备好你喜欢的饮料、编辑器和编译器，放一些音乐，让我们一起编写一个有趣的 C 语言程序。优秀 Unix 程序哲学首先，你要知道这个 C 程序是一个 Unix 命令行工具。这意味着它运行在（或者可被移植到）那些提供 Unix C 运行环境的操作系统中。当贝尔实验室发明 Unix 后，它从一开始便充满了设计哲学。用我自己的话来说就是：程序只做一件事，并做好它，并且对文件进行一些操作。虽然“只做一件事，并做好它”是有意义的，但是“对文件进行一些操作”的部分似乎有点儿不合适。事实证明，Unix 中抽象的 “文件” 非常强大。一个 Unix 文件是以文件结束符（EOF）标志为结尾的字节流。仅此而已。文件中任何其它结构均由应用程序所施加而非操作系统。操作系统提供了系统调用，使得程序能够对文件执行一套标准的操作：打开、读取、写入、寻址和关闭（还有其他，但说起来那就复杂了）。对于文件的标准化访问使得不同的程序共用相同的抽象，而且可以一同工作，即使它们是不同的人用不同语言编写的程序。具有共享的文件接口使得构建可组合的的程序成为可能。一个程序的输出可以作为另一个程序的输入。Unix 家族的操作系统默认在执行程序时提供了三个文件：标准输入（stdin）、标准输出（stdout）和标准错误（stderr）。其中两个文件是只写的：stdout 和 stderr。而 stdin 是只读的。当我们在常见的 Shell 比如 Bash 中使用文件重定向时，可以看到其效果。$ ls | grep foo | sed -e 's/bar/baz/g' > ack这条指令可以被简要地描述为：ls 的结果被写入标准输出，它重定向到 grep 的标准输入，grep 的标准输出重定向到 sed 的标准输入，sed 的标准输出重定向到当前目录下文件名为 ack 的文件中。我们希望我们的程序在这个灵活又出色的生态系统中运作良好，因此让我们编写一个可以读写文件的程序。喵呜喵呜：流编码器/解码器概念当我还是一个露着豁牙的孩子懵懵懂懂地学习计算机科学时，学过很多编码方案。它们中的有些用于压缩文件，有些用于打包文件，另一些毫无用处因此显得十分愚蠢。列举最后这种情况的一个例子：哞哞编码方案。为了让我们的程序有个用途，我为它更新了一个 21 世纪 的概念，并且实现了一个名为“喵呜喵呜” 的编码方案的概念（毕竟网上大家都喜欢猫）。这里的基本的思路是获取文件并且使用文本 “meow” 对每个半字节（半个字节）进行编码。小写字母代表 0，大写字母代表 1。因为它会将 4 个比特替换为 32 个比特，因此会扩大文件的大小。没错，这毫无意义。但是想象一下人们看到经过这样编码后的惊讶表情。$ cat /home/your_sibling/.super_secret_journal_of_my_innermost_thoughts MeOWmeOWmeowMEoW...这非常棒。最终的实现完整的源代码可以在 GitHub 上面找到，但是我会写下我在编写程序时的思考。目的是说明如何组织构建多文件 C 语言程序。既然已经确定了要编写一个编码和解码“喵呜喵呜”格式的文件的程序时，我在 Shell 中执行了以下的命令 ：$ mkdir meowmeow $ cd meowmeow $ git init $ touch Makefile # 编译程序的方法 $ touch main.c # 处理命令行选项 $ touch main.h # “全局”常量和定义 $ touch mmencode.c # 实现对喵呜喵呜文件的编码 $ touch mmencode.h # 描述编码 API $ touch mmdecode.c # 实现对喵呜喵呜文件的解码 $ touch mmdecode.h # 描述解码 API $ touch table.h # 定义编码查找表 $ touch .gitignore # 这个文件中的文件名会被 git 忽略 $ git add . $ git commit -m "initial commit of empty files"简单的说，我创建了一个目录，里面全是空文件，并且提交到 git。即使这些文件中没有内容，你依旧可以从它的文件名推断每个文件的用途。为了避免万一你无法理解，我在每条 touch 命令后面进行了简单描述。通常，程序从一个简单 main.c 文件开始，只有两三个解决问题的函数。然后程序员轻率地向自己的朋友或者老板展示了该程序，然后为了支持所有新的“功能”和“需求”，文件中的函数数量就迅速爆开了。“程序俱乐部”的第一条规则便是不要谈论“程序俱乐部”，第二条规则是尽量减少单个文件中的函数。老实说，C 编译器并不关心程序中的所有函数是否都在一个文件中。但是我们并不是为计算机或编译器写程序，我们是为其他人（有时也包括我们）去写程序的。我知道这可能有些奇怪，但这就是事实。程序体现了计算机解决问题所采用的一组算法，当问题的参数发生了意料之外的变化时，保证人们可以理解它们是非常重要的。当在人们修改程序时，发现一个文件中有 2049 函数时他们会诅咒你的。因此，优秀的程序员会将函数分隔开，将相似的函数分组到不同的文件中。这里我用了三个文件 main.c、mmencode.c 和 mmdecode.c。对于这样小的程序，也许看起来有些过头了。但是小的程序很难保证一直小下去，因此哥忒拓展做好计划是一个“好主意”。但是那些 .h 文件呢？我会在后面解释一般的术语，简单地说，它们被称为头文件，同时它们可以包含 C 语言类型定义和 C 预处理指令。头文件中不应该包含任何函数。你可以认为头文件是提供了应用程序接口（API）的定义的一种 .c 文件，可以供其它 .c 文件使用。但是 Makefile 是什么呢？我知道下一个轰动一时的应用都是你们这些好孩子们用 “终极代码粉碎者 3000” 集成开发环境来编写的，而构建项目是用 Ctrl-Meta-Shift-Alt-Super-B 等一系列复杂的按键混搭出来的。但是如今（也就是今天），使用 Makefile 文件可以在构建 C 程序时帮助做很多有用的工作。Makefile 是一个包含如何处理文件的方式的文本文件，程序员可以使用其自动地从源代码构建二进制程序（以及其它东西！）以下面这个小东西为例：00 # Makefile 01 TARGET= my_sweet_program 02 $(TARGET): main.c 03 cc -o my_sweet_program main.c# 符号后面的文本是注释，例如 00 行。01 行是一个变量赋值，将 TARGET 变量赋值为字符串 my_sweet_program。按照惯例，也是我的习惯，所有 Makefile 变量均使用大写字母并用下划线分隔单词。02 行包含该 步骤 recipe 要创建的文件名和其依赖的文件。在本例中，构建 目标 target 是 my_sweet_program，其依赖是 main.c。最后的 03 行使用了一个制表符号（tab）而不是四个空格。这是将要执行创建目标的命令。在本例中，我们使用 C 编译器 C compiler 前端 cc 以编译链接为 my_sweet_program。使用 Makefile 是非常简单的。$ make cc -o my_sweet_program main.c $ ls Makefile main.c my_sweet_program构建我们喵呜喵呜编码器/解码器的 Makefile 比上面的例子要复杂，但其基本结构是相同的。我将在另一篇文章中将其分解为 Barney 风格。形式伴随着功能我的想法是程序从一个文件中读取、转换它，并将转换后的结果存储到另一个文件中。以下是我想象使用程序命令行交互时的情况：$ meow < clear.txt > clear.meow $ unmeow < clear.meow > meow.tx $ diff clear.txt meow.tx $我们需要编写代码以进行命令行解析和处理输入/输出流。我们需要一个函数对流进行编码并将结果写到另一个流中。最后，我们需要一个函数对流进行解码并将结果写到另一个流中。等一下，我们在讨论如何写一个程序，但是在上面的例子中，我调用了两个指令：meow 和 unmeow？我知道你可能会认为这会导致越变越复杂。次要内容：argv[0] 和 ln 指令回想一下，C 语言 main 函数的结构如下：int main(int argc, char *argv[])其中 argc 是命令行参数的数量，argv 是字符指针（字符串）的列表。argv[0] 是包含正在执行的程序的文件路径。在 Unix 系统中许多互补功能的程序（比如：压缩和解压缩）看起来像两个命令，但事实上，它们是在文件系统中拥有两个名称的一个程序。这个技巧是通过使用 ln 命令创建文件系统链接来实现两个名称的。在我笔记本电脑中 /usr/bin 的一个例子如下：$ ls -li /usr/bin/git* 3376 -rwxr-xr-x. 113 root root 1.5M Aug 30 2018 /usr/bin/git 3376 -rwxr-xr-x. 113 root root 1.5M Aug 30 2018 /usr/bin/git-receive-pack ...这里 git 和 git-receive-pack 是同一个文件但是拥有不同的名字。我们说它们是相同的文件因为它们具有相同的 inode 值（第一列）。inode 是 Unix 文件系统的一个特点，对它的介绍超越了本文的内容范畴。优秀或懒惰的程序可以通过 Unix 文件系统的这个特点达到写更少的代码但是交付双倍的程序。首先，我们编写一个基于其 argv[0] 的值而作出相应改变的程序，然后我们确保为导致该行为的名称创建链接。在我们的 Makefile 中，unmeow 链接通过以下的方式来创建：# Makefile ... $(DECODER): $(ENCODER) $(LN) -f $< $@ ...我倾向于在 Makefile 中将所有内容参数化，很少使用 “裸” 字符串。我将所有的定义都放置在 Makefile 文件顶部，以便可以简单地找到并改变它们。当你尝试将程序移植到新的平台上时，需要将 cc 改变为某个 cc 时，这会很方便。除了两个内置变量 $@ 和 $< 之外，该 步骤 recipe 看起来相对简单。第一个便是该步骤的目标的快捷方式，在本例中是 $(DECODER)（我能记得这个是因为 @ 符号看起来像是一个目标）。第二个，$< 是规则依赖项，在本例中，它解析为 $(ENCODER)。事情肯定会变得复杂，但它还在管理之中。via: https://opensource.com/article/19/7/structure-multi-file-c-part-1作者：Erik O'Shaughnessy 选题：lujun9972 译者：萌新阿岩 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
一个简单又原始的脚本来用 Vim 打开你选择的文件。像大多数开发者一样，我整天都在搜索和阅读源码。就我个人而言，我从来没有习惯过集成开发环境 （IDE），多年来，我主要使用 grep （找到文件），并复制/粘贴文件名来打开 Vi(m)。最终，我写了这个脚本，并根据需要缓慢地对其进行了完善。它依赖 Vim 和 rlwrap，并使用 Apache 2.0 许可证开源。要使用该脚本，请将它放到 PATH 中，然后在文本目录下运行：grepgitvi <grep options> <grep/vim search pattern>它将返回搜索结果的编号列表，并提示你输入结果编号并打开 Vim。退出 Vim 后，它将再次显示列表，直到你输入除结果编号以外的任何内容。你也可以使用向上和向下箭头键选择一个文件。（这对我来说）更容易找到我已经看过的结果。与现代 IDE 甚至与 Vim 的更复杂的用法相比，它简单而原始，但它对我有用。脚本#!/bin/bash # grepgitvi - grep source files, interactively open vim on results # Doesnt really have to do much with git, other than ignoring .git # # Copyright Yedidyah Bar David 2019 # # SPDX-License-Identifier: Apache-2.0 # # Requires vim and rlwrap # # Usage: grepgitvi <grep options> <grep/vim pattern> # TMPD=$(mktemp -d /tmp/grepgitvi.XXXXXX) UNCOLORED=${TMPD}/uncolored COLORED=${TMPD}/colored RLHIST=${TMPD}/readline-history [ -z "${DIRS}" ] && DIRS=. cleanup() { rm -rf "${TMPD}" } trap cleanup 0 find ${DIRS} -iname .git -prune -o \! -iname "*.min.css*" -type f -print0 > ${TMPD}/allfiles cat ${TMPD}/allfiles | xargs -0 grep --color=always -n -H "$@" > $COLORED cat ${TMPD}/allfiles | xargs -0 grep -n -H "$@" > $UNCOLORED max=`cat $UNCOLORED | wc -l` pat="${@: -1}" inp='' while true; do echo "============================ grep results ===============================" cat $COLORED | nl echo "============================ grep results ===============================" prompt="Enter a number between 1 and $max or anything else to quit: " inp=$(rlwrap -H $RLHIST bash -c "read -p \"$prompt\" inp; echo \$inp") if ! echo "$inp" | grep -q '^[0-9][0-9]*$' || [ "$inp" -gt "$max" ]; then break fi filename=$(cat $UNCOLORED | awk -F: "NR==$inp"' {print $1}') linenum=$(cat $UNCOLORED | awk -F: "NR==$inp"' {print $2-1}') vim +:"$linenum" +"norm zz" +/"${pat}" "$filename" donevia: https://opensource.com/article/20/2/no-ide-script作者：Yedidyah Bar David 选题：lujun9972 译者：geekpi 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出
在 2020 年用开源实现更高生产力的二十种方式的第十八篇文章中，使用 Emacs 文本编辑器管理电子邮件和查看日程安排。去年，我给你们带来了 2019 年的 19 天新生产力工具系列。今年，我将采取一种不同的方式：建立一个新的环境，让你使用已用或未用的工具来在新的一年里变得更有效率。使用 Emacs 做（几乎）所有的事情，第 1 部分两天前，我曾经说过我经常使用 Vim 和 Emacs，在本系列的 16 和 17 天，我讲解了如何在 Vim 中做几乎所有的事情。现在，Emacs 的时间到了！在深入之前，我需要说明两件事。首先，我这里使用默认的 Emacs 配置，而不是我之前写过的 Spacemacs。为什么呢？因为这样一来我使用的就是默认快捷键，从而使你可以参考文档，而不必将“原生的 Emacs” 转换为 Spacemacs。第二，在本系列文章中我没有对 Org 模式进行任何设置。Org 模式本身几乎可以自成一个完整的系列，它非常强大，但是设置可能非常复杂。配置 Emacs配置 Emacs 比配置 Vim 稍微复杂一些，但以我之见，从长远来看，这样做是值得的。首先我们创建一个配置文件，并在 Emacs 中打开它：mkdir ~/.emacs.d emacs ~/.emacs.d/init.el接下来，向内置的包管理器添加一些额外的包源。在 init.el 中添加以下内容：(package-initialize) (add-to-list 'package-archives '("melpa" . "<http://melpa.org/packages/>")) (add-to-list 'package-archives '("org" . "<http://orgmode.org/elpa/>") t) (add-to-list 'package-archives '("gnu" . "<https://elpa.gnu.org/packages/>")) (package-refresh-contents)使用 Ctrl+x Ctrl+s 保存文件，然后按下 Ctrl+x Ctrl+c 退出，再重启 Emacs。Emacs 会在启动时下载所有的插件包列表，之后你就可以使用内置的包管理器安装插件了。输入 Meta+x 会弹出命令提示符（大多数键盘上 Meta 键就是的 Alt 键，而在 MacOS 上则是 Option）。在命令提示符下输入 package-list-packages 就会显示可以安装的包列表。遍历该列表并使用 i 键选择以下包：bbdb bbdb-vcard calfw calfw-ical notmuch选好软件包后按 x 安装它们。根据你的网络连接情况，这可能需要一段时间。你也许会看到一些编译错误，但是可以忽略它们。安装完成后，使用组合键 Ctrl+x Ctrl+f 打开 ~/.emacs.d/init.el，并在 (package-refresh-packages) 之后、 (custom-set-variables 之前添加以下行到文件中。 (custom-set-variables 行由 Emacs 内部维护，你永远不应该修改它之后的任何内容。以 ;; 开头的行则是注释。;; Set up bbdb (require 'bbdb) (bbdb-initialize 'message) (bbdb-insinuate-message) (add-hook 'message-setup-hook 'bbdb-insinuate-mail) ;; set up calendar (require 'calfw) (require 'calfw-ical) ;; Set this to the URL of your calendar. Google users will use ;; the Secret Address in iCalendar Format from the calendar settings (cfw:open-ical-calendar "<https://path/to/my/ics/file.ics>") ;; Set up notmuch (require 'notmuch) ;; set up mail sending using sendmail (setq send-mail-function (quote sendmail-send-it)) (setq user-mail-address "[myemail@mydomain.com][9]" user-full-name "My Name")现在，你已经准备好使用自己的配置启动 Emacs 了！保存 init.el 文件（Ctrl+x Ctrl+s），退出 Emacs（Ctrl+x Ctrl+c），然后重启之。这次重启要多花些时间。使用 Notmuch 在 Emacs 中读写电子邮件一旦你看到了 Emacs 启动屏幕，你就可以使用 Notmuch 来阅读电子邮件了。键入 Meta+x notmuch，你将看到 notmuch 的 Emacs 界面。所有加粗的项目都是指向电子邮件视图的链接。你可以通过点击鼠标或者使用 tab 键在它们之间跳转并按回车来访问它们。你可以使用搜索栏来搜索 Notmuch 的数据库，语法与 Notmuch 命令行上的语法 相同。如果你愿意，还可以使用 [save] 按钮保存搜索以便未来使用，这些搜索会被添加到屏幕顶部的列表中。如果你进入一个链接就会看到一个相关电子邮件的列表。你可以使用箭头键在列表中导航，并在要读取的消息上按回车。按 r 可以回复一条消息，f 转发该消息，q 退出当前屏幕。你可以通过键入 Meta+x compose-mail 来编写新消息。撰写、回复和转发都将打开编写邮件的界面。写完邮件后，按 Ctrl+c Ctrl+c 发送。如果你决定不发送它，按 Ctrl+c Ctrl+k 关闭消息撰写缓冲区（窗口）。使用 BBDB 在 Emacs 中自动补完电子邮件地址那么通讯录怎么办？这就是 BBDB 发挥作用的地方。但首先我们需要从 abook 导入所有地址，方法是打开命令行并运行以下导出命令：abook --convert --outformat vcard --outfile ~/all-my-addresses.vcf --infile ~/.abook/addressesEmacs 启动后，运行 Meta+x bbdb-vcard-import-file。它将提示你输入要导入的文件名，即 ~/all-my-address.vcf。导入完成后，在编写消息时，可以开始输入名称并使用 Tab 搜索和自动完成 “to” 字段的内容。BBDB 还会打开一个联系人缓冲区，以便你确保它是正确的。既然在 vdirsyncer 中已经为每个地址都生成了对应的 .vcf 文件了，为什么我们还要这样做呢？如果你像我一样，有许多地址，一次处理一个地址是很麻烦的。这样做，你就可以把所有的东西都放在 abook 里，做成一个大文件。使用 calfw 在 Emacs 中浏览日历最后，你可以使用 Emacs 查看日历。在上面的配置中，你安装了 calfw 包，并添加了一些行来告诉它在哪里可以找到要加载的日历。Calfw 是 “ Emacs 日历框架 Calendar Framework for Emacs ”的简称，它支持多种日历格式。我使用的是谷歌日历，这也是我放在配置中的链接。日历将在启动时自动加载，你可以通过 Ctrl+x+b 命令切换到 cfw-calendar 缓冲区来查看日历。Calfw 提供日、周、双周和月视图。你可以在日历顶部选择视图，并使用箭头键导航日历。不幸的是，calfw 只能查看日历，所以你仍然需要使用 khal 之类的工具或通过 web 界面来添加、删除和修改事件。这就是 Emacs 中的邮件、日历和邮件地址。明天我会展示更多。via: https://opensource.com/article/20/1/emacs-mail-calendar作者：Kevin Sonney 选题：lujun9972 译者：lujun9972 校对：wxy本文由 LCTT 原创编译，Linux中国 荣誉推出