分类 技术 下的文章

用 Cockpit 建立你的树莓派的控制中心。

 title=

去年,我写了关于使用 Cockpit 管理我的 Linux 服务器的文章。它是一个基于 Web 的工具,为管理多个服务器及其相关的服务和应用提供了一个简洁、强大的界面。它还简化了日常的管理任务。

在这篇文章中,我将会介绍如何在树莓派基金会提供的标准操作系统树莓派 OS 上安装用于 Linux 服务器的 Cockpit Web 控制台。我还会简要介绍它的特性。

在树莓派 OS 上安装 Cockpit

sudo 权限下使用一个账户通过 SSH 登录你的树莓派系统。如果你还没有建立一个账户:

$ ssh pibox
alan@pibox's password:
Linux pibox.someplace.org 5.10.17-v7+ #1403 SMP Mon Feb 22 11:29:51 GMT 2021 armv7l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue May  4 09:55:57 2021 from 172.1.4.5
alan@pibox:~ $

在树莓派 OS 上安装 Cockpit Web 控制台和在 Linux 服务器上一样简单:

$ sudo apt install cockpit

Cockpit 只需要 60.4 KB 的磁盘空间。加上它的几个包依赖项,总使用量是 115MB。

安装过程将负责设置和启动服务。你可以使用 systemctl 命令来验证状态:

$ systemctl status cockpit.socket
● cockpit.socket - Cockpit Web Service Socket
   Loaded: loaded (/lib/systemd/system/cockpit.socket; enabled; vendor preset: enabled)
   Active: active (listening) since Tue 2021-05-04 10:24:43 EDT; 35s ago
     Docs: man:cockpit-ws(8)
   Listen: 0.0.0.0:9090 (Stream)
  Process: 6563 ExecStartPost=/usr/share/cockpit/motd/update-motd  localhost (code=exited, status=0/SUCCESS)
  Process: 6570 ExecStartPost=/bin/ln -snf active.motd /run/cockpit/motd (code=exited, status=0/SUCCESS)
    Tasks: 0 (limit: 2181)
   CGroup: /system.slice/cockpit.socket

使用 Cockpit

连接

默认的监听端口号是 9090。打开你最喜欢的 Web 浏览器并输入地址,例如: https://pibox:9090

 title=

你现在可以使用你的普通账户登录。同样,这个账户上需要有使用 sudo 的权限 —— 很可能就是你用来 SSH 和运行 Apt 的那个账户。一定要勾选“为特权任务重用我的密码”。

管理你的树莓派

Cockpit 的初始屏幕以 “System” 页开始,提供当前 CPU 和内存使用的详细信息和图表。

 title=

你可以从这个屏幕看到硬件细节。

 title=

通过点击每一项来展开左边的列(例如,日志、存储、服务等)。这些是标准的 Cockpit 部分,不言自明。让我快速描述一下每个部分。

日志

这部分展示了日志。它们可以根据日期和严重程度来过滤。

存储

存储部分展示了已经安装的物理驱动器和 RAID 设备。例如大小、序列号等细节都被展示了出来。还展示了读/写活动和实际空间使用的图表。存储的具体日志显示在底部。

网络

这部分展示了发送和接收活动、IP 地址以及网络特定的日志。你还可以使用相应的按钮添加更多的网络设备,如绑定、网桥和 VLAN。

账户

这里展示了已有的账户。点击每个账户来管理,或使用创建新账户按钮来添加用户。账户也可以被删除。

服务

这部分可以让管理员查看系统所有服务的状态。点击任何服务都会转到一个包含启动、重启和禁用的标准任务的屏幕。

应用程序

通常,这个屏幕提供了各种用于管理功能的应用程序,例如 389 目录服务器或创建 Podman 容器。但在我的树莓派 OS 上,这个屏幕只显示“没有安装或可用的应用程序”。在写这篇文章的时候,这个或许还没有实现。虽然,你可能会怀疑这类型的程序对于树莓派硬件来说是否太过沉重。

软件更新

对任何系统管理员来说,保持软件最新是最重要的任务之一。Cockpit 的软件更新部分可以检查并进行更新。

 title=

终端

Cockpit 最方便的特点之一是终端。你可以使用它,而不是打开一个单独的终端模拟器并使用 SSH。我使用终端来安装 ScreenFetch

$ sudo apt install screenfetch

使用 ScreenFetch 生成了这张截图:

 title=

使用 Cockpit 的中心控制

Cockpit 在树莓派上的表现就像它在其他 Linux 系统上一样。你可以将它添加到仪表盘上进行集中控制。它允许企业在 Cockpit 作为管理仪表盘解决方案的任何地方,将基于树莓派的服务和系统整合到他们的整体 Linux 基础设施中。因为树莓派经常在高密度机架数据中心以 无外接控制 headless 方式运行,而这些数据中心通常会缺乏 KVM 访问方式,这是非常方便的。


via: https://opensource.com/article/21/5/raspberry-pi-cockpit

作者:Alan Formy-Duval 选题:lujun9972 译者:RiaXu 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

创建一个 API(应用程序接口),我们所要做的远远不止是让它能“正常工作”。

 title=

如果你正在构建基于 C/S 模型的应用程序,那么你需要一个应用程序接口(API)。API 就是一种非常清晰而又明确的定义,它是一个 进程 process 与另一个进程之间明确定义的边界。Web 应用中我们常见的边界定义就是 REST/JSON API。

虽然很多开发者可能主要关注在如何让 API 正常工作(或功能正常),但却还有一些“非功能性”的要求也是需要他们注意的。所有的 API 必须具备 的 4 个非功能性的要求是:

  • 安全
  • 文档
  • 验证
  • 测试

安全

在软件开发中,安全是最基本的要求。对于 API 开发者来说,API 的安全性主要包含以下 4 个方面:

  1. HTTPS/SSL 证书
  2. 跨域资源共享
  3. 身份认证与 JSON Web 令牌
  4. 授权与作用域

1、HTTPS/SSL 证书

Web 应用的黄金标准是使用 SSL 证书的 HTTPS 协议。Let's Encrypt 可以帮你达到这一目的。Let's Encrypt 来自于非营利性的互联网安全研究小组(ISRG),它是一个免费的、自动化的、开放的证书颁发机构。

Let's Encrypt 的软件会为你的域(LCTT 译注:包含域名、IP 等信息)生成中央授权证书。而正是这些证书确保了从你的 API 到客户端的数据载荷是点对点加密的。

Let's Encrypt 支持证书管理的多种部署方案。我们可以通过查看 文档 来找出最适合自己需要的方案。

2、跨域资源共享

跨域资源共享 Cross-origin resource sharing (CORS)是一个针对浏览器的安全策略预检。如果你的 API 服务器与发出请求的客户端不在同一个域中,那么你就要处理 CORS。例如,如果你的服务器运行在 api.domain-a.com 并且接到一个来自 domain-b.com 的客户端的请求,那么 CORS 就会(让浏览器)发送一个 HTTP 预检请求,以便查看你的 API 服务是否会接受来自此客户域的客户端请求。

来自 MDN 的定义

“跨域资源共享(CORS)是一种基于 HTTP 头的机制,这种机制允许服务器标记除自身源外的其他任何来源(域、方案或端口)。而对于这些被服务器标识的源,浏览器应该允许我们从它们加载资源。”

 title=

(MDN文档CC-BY-SA 2.5)

另外,有很多用于 Node.js 的辅助库来 帮助 API 开发者处理 CORS

3、身份认证与 JSON Web 令牌

有多种方法可以验证你的 API 中的认证用户,但最好的方法之一是使用 JSON Web 令牌(JWT),而这些令牌使用各种知名的加密库进行签名。

当客户端登录时,身份管理服务会向客户端提供一个 JWT。然后,客户端可以使用这个令牌向 API 发出请求,API 收到请求后,从服务器读取公钥或私密信息来验证这个令牌。

有一些现有的库,可以帮助我们对令牌进行验证,包括 jsonwebtoken。关于 JWT 的更多信息,以及各种语言中对其的支持库,请查看 JWT.io

import jwt from 'jsonwebtoken'

export default function (req, res, next) {
    // req.headers.authorization Bearer token
    const token = extractToken(req)
    jwt.verify(token, SECRET, { algorithms: ['HS256'] }, (err, decoded) => {
        if (err) { next(err) }
        req.session = decoded
        next()
    })
}

4、授权与作用域

认证(或身份验证)很重要,但授权同样很重要。也就是说,经过验证的客户端是否有权限让服务器执行某个请求呢?这就是作用域的价值所在。当身份管理服务器对客户端进行身份认证,且创建 JWT 令牌时,身份管理服务会给当前客户提供一个作用域,这个作用域将会决定当前经过验证的客户的 API 请求能否被服务器执行。这样也就免去了服务器对访问控制列表的一些不必要的查询。

作用域是一个文本块(通常以空格分隔),用于描述一个 API 端点的访问能力。一般来说,作用域被分为资源与动作。这种模式对 REST/JSON API 很有效,因为它们有相似的 RESOURCE:ACTION 结构。(例如,ARTICLE:WRITEARTICLE:READ,其中 ARTICLE 是资源,READWRITE 是动作)。

作用域的划分让我们的 API 能够专注于功能的实现,而不是去考虑各种角色和用户。身份访问管理服务可以将不同的角色和用户分配不同的权限范围,然后再将这些不同的作用域提供给不同的 JWT 验证中的客户。

总结

当我们开发和部署 API 时,安全应该一直是最重要的要求之一。虽然安全性是一个比较宽泛的话题,但如果能解决上面四个方面的问题,这对于你的 API 来说,在生产环境中将会表现得更好。

文档

有什么能比没有文档更糟糕?过期的文档。

开发者对文档真的是又爱又恨。尽管如此,文档仍然是 API 定义是否完善的一个关键部分。开发者需要从文档中知道如何使用这些 API,且你创建的文档对于开发者如何更好地使用 API 也有着非常巨大的作用。

创建 API 文档,我们需要关注下面三个方面:

  1. 开发者入门文档(自述文件/基本介绍)
  2. 技术参考(规范/说明书)
  3. 使用方法(入门和其他指南)

1、入门文档

在构建 API 服务的时候,你需要明确一些事情,比如:这个 API 是做什么的?如何建立开发者环境?如何测试该服务?如何提交问题?如何部署它?

通常我们可以通过自述(README)文件来回答上面的这些问题,自述文件一般放在你的代码库中,用于为开发者提供使用你项目的最基本的起点和说明。

自述文件应该包含:

  • API 的描述
  • 技术参考与指南的链接
  • 如何以开发者的身份设置你的项目
  • 如何测试这个项目
  • 如何部署这个项目
  • 依赖管理
  • 代码贡献指南
  • 行为准则
  • 许可证
  • 致谢

你的自述文件应该简明扼要;你不必解释每一个方面,但要提供足够的信息,以便开发者在熟悉你的项目后可以进一步深入研究。

2、技术参考

在 REST/JSON API 中, 每一个具体的 端点 endpoint 都对应一个特定的功能,都需要一个具体的说明文档,这非常重要。文档中会定义 API 的描述,输入和可能的输出,并为各种客户端提供使用示例。

OpenAPI 是一个创建 REST/JSON 文档的标准, 它可以指导你完成编写 API 文档所需的各种细节。OpenAPI 还可以为你的 API 生成演示文档。

3、使用方法

对于 API 的用户来说,仅仅只有技术说明是不够的。他们还需要知道如何在一些特定的情况和场景下来使用这些 API,而大多数的潜在用户可能希望通过你的 API 来解决他们所遇到的问题。

向用户介绍 API 的一个好的方法是利用一个“开始”页面。“开始”页面可以通过一个简单的用例引导用户,让他们迅速了解你的 API 能给他们能带来的益处。

总结

对于任何完善的 API,文档都是一个很关键的组成部分。当你在创建文档时,你需要关注 API 文档中的如何入门、技术参考以及如何快速开始等三个方面,这样你的 API 才算是一个完善的 API。

验证

API 开发过程中经常被忽视的一个点就是验证。它是一个验证来自外部来源的输入的过程。这些来源可以是客户端发送过来的 JSON 数据,或者是你请求别人的服务收到的响应数据。我们不仅仅要检查这些数据的类型,还要确保这些数据确实是我们要的数据,这样可以消除很多潜在的问题。了解你的边界以及你能控制的和不能控制的东西,对于 API 的数据验证来说是一个很重要的方面。

最好的策略是在进入数据逻辑处理之前,在你能控制的边界的边缘处进行数据的验证。当客户端向你的 API 发送数据时,你需要对该数据做出任何处理之前应用你的验证,比如:确保 Email 是真实的邮件地址、日期数据有正确的格式、字符串符合长度要求。

这种简单的检查可以为你的应用增加安全性和一致性。还有,当你从某个服务接收数据时,比如数据库或缓存,你需要重新验证这些数据,以确保返回的结果符合你的数据检查。

你可以自己手写这些校验逻辑,当然也可以用像 LodashRamda 这样的函数库,它们对于一些小的数据对象非常有用。像 JoiYupZod 这样的验证库效果会更好,因为它们包含了一些常见的验证方法,可以节省你的时间和精力。除此,它们还能创建一个可读性强的模式。如果你需要看看与语言无关的东西,请看 JSON Schema

总结

数据验证虽然并不显眼和突出(LCTT 译注:跟 API 的功能实现以及其他几个方面比),但它可以帮你节省大量的时间。如果不做验证,这些时间将可能被用于故障排除和编写数据迁移脚本。真的不要相信你的客户端会发送干净的数据给你,也不要让验证不通过的数据渗入到你的业务逻辑或持久数据存储中去。花点时间验证你的 API 收到的数据和请求到的响应数据,虽然在前期你可能会感到一些挫折和不适,但这总比你在后期花大量时间去做各种数据收紧管制、故障排除等要容易得多。

测试

测试是软件开发中的最佳实践,它应该是最主要的非功能性的要求。对于包括 API 在内的任何项目,确定测试策略都是一个挑战,因为你自始至终都要掌握各种约束,以便相应的来制定你的测试策略。

集成测试 Integration testing 是测试 API 的最有效的方法之一。在集成测试模式中,开发团队会创建一个测试集用来覆盖应用流程中的某些部分,从一个点到另一个点。一个好的集成测试流程包括测试 API 的入口点以及模拟请求到服务端的响应。搞定这两点,你就覆盖了整个逻辑,包括从 API 请求的开始到模拟服务器的响应,并返回数据给 API。

虽然使用的是模拟,但这种方法让能我们专注于代码逻辑层,而不需要去依赖后端服务和展示逻辑来进行测试。没有依赖的测试会更加可靠、更容易实现自动化,且更容易被接入持续集成管道流。

集成测试的实施中,我会用 TapeTest-serverFetch-mock。这些库让我们能够从 API 的请求到数据的响应进行隔离测试,使用 Fetch-mock 还可以将出站请求捕获到持久层。

总结

虽然其他的各种测试和类型检查对 API 也都有很好的益处,但集成测试在流程效率、构建和管理时间方面却有着更大的优势。使用 Fetch-mock 这样的工具,可以在服务边界提供一个干净的模拟场景。

专注于基础

不管是设计和构建应用程序还是 API,都要确保包含上面的四个基本要素。它们并不是我们唯一需要考虑的非功能性需求,其他的还包括应用监控、日志和 API 管理等。即便如此,安全、文档、验证和测试这四个基本点,对于构建任何使用场景下的完善 API 都是至关重要的关注点。


via: https://opensource.com/article/21/5/successful-apis

作者:Tom Wilson 选题:lujun9972 译者:ywxgod 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

毫无疑问,微软的 VS Code是最好的开源代码编辑器之一。它与传说中的 Vim 不同,VS Code 不需要你是一个快捷键大师(LCTT 译注:以下都指键盘快捷键),开发者们对它大部分的功能都及其熟悉,且推崇备至。

但这并不意味着你不能成为快捷键大师,或者说你在 VS Code 中不应该使用快捷键。

在敲代码的时候,你可能需要用鼠标去执行其他的动作,比如在 VS Code 编辑器中切换终端,而此时你的代码流程会被打断,这是不是很讨厌?如果是的,那么你应该立即熟记下面这些 VS Code 有用的快捷键。

它不仅能帮助你摆脱鼠标,还能使你的生产力和工作效率得到提高。

那么,让我们来了解一下如何通过使用快捷键快速进行代码导航来进行快速编码。

有用的 VS Code 快捷键

免责声明。下面的这些快捷键是我在 VS Code 的使用中发现的较为有用的,你可以根据你的需要来发现更多有用的快捷键。

下面我还给出了 MacOS 用户的键盘快捷键。

1、显示所有命令

Windows/LinuxmacOS
CTRL + SHIFT + PF1SHIFT + ⌘ + PF1

我们从最有用的快捷键开始,这个快捷键能打开命令面板(列表),它提供了对 VS Code 所有功能的访问。

命令面板

这是一个非常重要的 VS Code 快捷键,因为即使你忘记了或不想记起其他任何快捷键,但你记得这个,那么你仍然可以使用命令面板进行各种操作,如创建新文件、打开设置、改变主题,还可以查看所有快捷键。

2、垂直和水平拆分 VS Code 编辑器

Windows/LinuxmacOS
CTRL + \⌘ + \

为了提高效率,但你又没有安装多个显示器,那么你可以通过水平或垂直分割 VS Code 的编辑器来一次查看多个文件的代码。

分割 VS Code 编辑区

要在多个编辑区间切换焦点,你可以使用数字键或箭头键。

Windows/LinuxmacOS
CTRL + 1/2/3⌘ + 1/2/3
CTRL + K CTRL + ←/⌘ + K ⌘ + ←/

3、切换集成终端

Windows/LinuxmacOS
CTRL + `⌘ + `

VS Code 中的集成终端是一个非常方便的功能,它可以让你在不切换窗口的情况下快速执行任务。要在编辑器中显示/隐藏终端,下面的快捷键会非常方便。

集成终端

但是,如果你跟我一样觉得 CTRL + 在键盘的角落位置而比较难按到,你可以打开命令面板执行View: Toggle Terminal` 命令来切换终端。

使用命令面板切换终端

4、转到文件

Windows/LinuxmacOS
CTRL + P⌘ + P

随着项目的壮大,查找文件可能会变得困难。因此,我建议,即使你使用鼠标,这个命令也能为你节省很多搜索和导航到版本库中的文件的时间。

转到文件

5、转到行

Windows/LinuxmacOS
CTRL + G^ + G

当你找到文件,你可能需要去到文件中指定的行增加或编辑代码,而如果这个文件包含了数千行代码,那么滚动代码将会浪费你大量的时间。而 CTRL + G^ + G 快捷键能让你快速的去掉指定的行。

转到行

另外,你也可以使用上面的转到文件的快捷键,在输入框中输入冒号 : 加行号,结果就跟转到行是一样的。

6、在整个项目中搜索

Windows/LinuxmacOS
CTRL + SHIFT + F⌘ + SHIFT + F

很可能你需要在整个项目中搜索一个文本、变量或函数,在这种情况下,上面的命令就非常方便,它会在侧边栏显示一个搜索输入框。

在项目中搜索

我们还可以在搜索的时候添加一些过滤器,比如使用 ALT+C 来启用大写匹配,ALT+W 用于匹配整个单词,ALT+R 用于启用正则表达式。

7、禅模式

Windows/LinuxmacOS
CTRL + K Z⌘ + K Z

想要在不受干扰的环境中工作以保持更专注? 你可以试试禅模式(先按下 CTRL + K,再按下 Z),它会隐藏所有 UI(状态栏、活动栏、面板和侧边栏)并仅在全屏上显示编辑器。

禅模式

要启用禅模式,你可以使用上面的快捷键或者打开命令面板执行 View: Toggle Zen Mode,要退出禅模式,你可以按两次 Esc 键。

8、将选择添加到下一次匹配中

Windows/LinuxmacOS
CTRL + D⌘ + D

这条命令能让你选择所选文本的下一个出现的地方,从而进行编辑。如果下一个匹配出现的位置与第一个相离较远,那这将会很方便处理。

查找下一个匹配

9、切换行注释

Windows/LinuxmacOS
CTRL + /⌘ + /

将光标移到行的开头,然后添加双斜杠进行注释,这种麻烦的操作我们可以用上面的快捷键来代替了。

注释代码

甚至,如果你想注释多行代码,你可以先通过 SHIFT+UP/Down 快捷键来选中多行,然后按 CTRL+/ 快捷键进行注释。

10、转到文件的开头或结尾

Windows/LinuxmacOS
CTRL + HOME/END⌘ + ↑/

如果你迷失在文件的中间位置,该命令可以让你快速达到文件的起点或终点。

11、代码折叠或打开

Windows/LinuxmacOS
CTRL + SHIFT + [/]⌥ + ⌘ + [/]

这也是最有用的快捷键之一,它可以帮助你折叠/取消折叠一个区域的代码。通过这种方式,你可以隐藏不必要的代码,每次只查看所需的部分代码,以便更加专注和快速编码。

折叠一块代码

12、窥视执行

Windows/LinuxmacOS
CTRL + SHIFT + F12⌘ + SHIFT + F12

这个快捷键最有可能的作用是帮助你进行代码分析,或修复 bug 时了解函数和变量的运行情况。

窥视执行

13、删除当前行

Windows/LinuxmacOS
CTRL + SHIFT + KSHIFT + ⌘ + K

这是一条可以快速执行,选中当前行并按删除/退格键,这两个任务的简单命令。

14、查找与替换

Windows/LinuxmacOS
CTRL + F⌘ + F
CTRL + H⌥ + ⌘ + F

用一个新的文本替换文件中所有出现的该文本的最好方法是什么?如果你手动一个一个的通过滚动代码来处理,且如果需要替换的地方又很多,那么你可能会花费大量的时间。

查找与替换

而使用查找和替换功能我们能在几秒内完成相同的任务。你可以用两个快捷键来打开它,其中一个实际上是打开用于查找文本的输入框,另一个用于输入新的文本。

15、VS Code 的全部键盘快捷键

Windows/LinuxmacOS
CTRL + K CTRL + S⌘ + K ⌘ + S

最后,如果你还在为记住上述所有的快捷键而苦恼,你大可不必。因为你可以使用上面的快捷键查看编辑器所有可用的命令。

快捷键

你还可以根据自己的喜好编辑命令的绑定键。

想要为 VS Code 添加更多快捷键?

如果你想对 VS Code 的快捷键有完整的了解,你可以查看 VS Code 的 文档

或者,如果你想在纸上将所有快捷键打印出来慢慢看,下面这些是各个系统对应的快捷键速查表: LinuxmacOSWindows


via: https://itsfoss.com/vs-code-shortcuts/

作者:Sarvottam Kumar 选题:lujun9972 译者:ywxgod 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

手册页 man pages ,即 参考手册页 reference manual pages 的简称,是你进入 Linux 的钥匙。你想知道的一切都在那里,包罗万象。这套文档永远不会赢得普利策奖,但这套文档是相当准确和完整的。手册页是主要信源,其权威性是众所周知的。

虽然它们是源头,但阅读起来并不是最令人愉快的。有一次,在很久以前的哲学课上,有人告诉我,阅读 亚里士多德 是最无聊的阅读。我不同意:说到枯燥的阅读,亚里士多德远远地排在第二位,仅次于手册页。

乍一看,这些页面可能看起来并不完整,但是,不管你信不信,手册页并不是为了隐藏信息 —— 只是因为信息量太大,这些页面必须要有结构,而且信息是以尽可能简短的形式给出的。这些解释相当简略,需要一些时间来适应,但一旦你掌握了使用它们的技巧,你就会发现它们实际上是多么有用。

Linux 中的手册页入门

这些页面是通过一个叫做 man 的工具查看的,使用它的命令相当简单。在最简单的情况下,要使用 man,你要在命令行上输入 man,后面加一个空格和你想查询的命令,比如 lscp,像这样:

man ls

man 会打开 ls 命令的手册页。

你可以用方向键上下移动,按 q 退出查看手册页。通常情况下,手册页是用 less 打开的,所以 less 命令的键盘快捷键在 man 中也可以使用。

例如,你可以用 /search_term 来搜索一个特定的文本,等等。

有一个关于手册页的介绍,这是一篇值得阅读介绍。它非常详细地说明了手册页是如何布局和组织的。

要看这个页面,请打开一个终端,然后输入:

man man

man page of man

在你开始更深入地研究手册页之前,知道手册页有一个固定的页面布局和一个归档方案会有帮助。这可能会让新手感到困惑,因为我可以说:“看手册页中关于 ls 的 NAME section ”,我也可以说:“看第 5 section 中的 passwd 的手册页。”

我把 “ section ” 这个词用斜体字表示,是为了显示混淆的来源。这个词,“节” 被用于两种不同的方式,但并不总是向新人解释其中的区别。

我不确定为什么会出现这种混淆,但我在培训新用户和初级系统管理员时看到过几次这种混淆。我认为这可能是隧道视野,专注于一件事会使一个人忘记另一件事。一叶障目,不见泰山。

对于那些已经知道其中的区别的人,你可以跳过这一小节。这一部分是针对那些刚接触到手册页的人。

这就是区别:

对于手册页

单独的手册页是用来显示信息块的。例如,每个手册页都有一个“NAME”节,显示命令的名称和简短的描述。还会有另一个信息块,称为“SYNOPSIS”,显示该命令是如何使用的,以此类推。

每个手册页都会有这些,以及其他的标题。这些在各个手册页上的节,或者说标题,有助于保持事情的一致性和信息的分工。

对于手册

使用“节”,如 “查看第 5 节中的 passwd 的手册页”,是指整个手册的内容。当我们只看一页时,很容易忽略这一点,但是 passwd 手册页是同一本手册的一部分,该手册还有 lsrmdatecal 等的手册页。

整个 Linux 手册是巨大的;它有成千上万的手册页。其中一些手册页有专门的信息。有些手册页有程序员需要的信息,有些手册页有网络方面的独特信息,还有一些是系统管理员会感兴趣的。

这些手册页根据其独特的目的被分组。想想看,把整个手册分成几个章节 —— 每章有一个特定的主题。有 9 个左右的章节(非常大的章节)。碰巧的是,这些章节被称为“节”。

总结一下:

  • 手册中单页(我们称之为“手册页”)的节是由标题定义的信息块。
  • 这个大的手册(所有页面的集合)中的章节,刚好被称为“节”。

现在你知道区别了,希望本文的其余部分会更容易理解。

手册页的节

你将会看到不同的手册页,所以让我们先研究一下各个页面的布局。

手册页被分成几个标题,它们可能因提供者不同而不同,但会有相似之处。一般的分类如下:

  • NAME(名称)
  • SYNOPSIS(概要)
  • DESCRIPTION(描述)
  • EXAMPLES(例子)
  • DIAGNOSTICS(诊断)
  • FILES(文件)
  • LIMITS(限制)
  • PORTABILITY(可移植性)
  • SEE ALSO(另见)
  • HISTORY(历史)
  • WARNING(警告)或BUGS`(错误)
  • NOTES(注意事项)

NAME - 在这个标题下是命令的名称和命令的简要描述。

SYNOPSIS - 显示该命令的使用方法。例如,这里是 cal 命令的概要:

cal [Month] [Year]

概要以命令的名称开始,后面是选项列表。概要采用命令行的一般形式;它显示了你可以输入的内容和参数的顺序。方括号中的参数([])是可选的;你可以不输入这些参数,命令仍然可以正常工作。不在括号内的项目必须使用。

请注意,方括号只是为了便于阅读。当你输入命令时,不应该输入它们。

DESCRIPTION - 描述该命令或工具的作用以及如何使用它。这一节通常以对概要的解释开始,并说明如果你省略任何一个可选参数会发生什么。对于长的或复杂的命令,这一节可能会被细分。

EXAMPLES - 一些手册页提供了如何使用命令或工具的例子。如果有这一节,手册页会尝试给出一些简单的使用例子,以及更复杂的例子来说明如何完成复杂的任务。

DIAGNOSTICS - 本节列出了由命令或工具返回的状态或错误信息。通常不显示不言自明的错误和状态信息。通常会列出可能难以理解的信息。

FILES - 本节包含了 UNIX 用来运行这个特定命令的补充文件的列表。这里,“补充文件”是指没有在命令行中指定的文件。例如,如果你在看 passwd 命令的手册,你可能会发现 /etc/passwd 列在这一节中,因为 UNIX 是在这里存储密码信息。

LIMITS - 本节描述了一个工具的限制。操作系统和硬件的限制通常不会被列出,因为它们不在工具的控制范围内。

PORTABILITY - 列出其他可以使用该工具的系统,以及该工具的其他版本可能有什么不同。

SEE ALSO - 列出包含相关信息的相关手册页。

HISTORY - 提供命令的简要历史,如它第一次出现的时间。

WARNING - 如果有这个部分,它包含了对用户的重要建议。

NOTES - 不像警告那样严重,但也是重要的信息。

同样,并不是所有的手册都使用上面列出的确切标题,但它们足够接近,可以遵循。

手册的节

整个 Linux 手册集合的手册页传统上被划分为有编号的节:

第 1 节:Shell 命令和应用程序 第 2 节:基本内核服务 - 系统调用和错误代码 第 3 节:为程序员提供的库信息 第 4 节:网络服务 - 如果安装了 TCP/IP 或 NFS 设备驱动和网络协议 第 5 节:文件格式 - 例如:显示 tar 存档的样子 第 6 节:游戏 第 7 节:杂项文件和文档 第 8 节:系统管理和维护命令 第 9 节:不知名的内核规格和接口

将手册页分成这些组,可以使搜索更有效率。在我工作的地方,我有时会做一些编程工作,所以我花了一点时间看第 3 节的手册页。我也做一些网络方面的工作,所以我也知道要涉足网络部分。作为几个实验性机器的系统管理员,我在第 8 节花了很多时间。

将手册网归入特定的节(章节),使搜索信息更加容易 —— 无论是对需要搜索的人,还是对进行搜索的机器。

你可以通过名称旁边的数字来判断哪个手册页属于哪个部分。例如,如果你正在看 ls 的手册页,而页面的最上面写着。 LS(1),那么你正在浏览第 1 节中的 ls 页面,该节包含关于 shell 命令和应用程序的页面。

下面是另一个例子。如果你在看 passwd 的手册页,页面的顶部显示: PASSWD(1),说明你正在阅读第 1 节中描述 passwd 命令如何更改用户账户密码的手册页。如果你看到 PASSWD(5),那么你正在阅读关于密码文件和它是如何组成的的手册页。

passwd 恰好是两个不同的东西:一个是命令的名称,一个是文件的名称。同样,第 1 节描述了命令,而第 5 节涉及文件格式。

括号中的数字是重要的线索 —— 这个数字告诉你正在阅读的页面来自哪一节。

搜索一个特定的节

基本命令:

man -a name

将在每一节中搜索由 name 标识的手册页,按数字顺序逐一显示。要把搜索限制在一个特定的部分,请在 man 命令中使用一个参数,像这样:

man 1 name

这个命令将只在手册页的第 1 节中搜索 name。使用我们前面的 passwd 例子,这意味着我们可以保持搜索的针对性。如果我想阅读 passwd 命令的手册页,我可以在终端输入以下内容:

man 1 passwd

man 工具将只在第 1 节中搜索 passwd 并显示它。它不会在任何其他节中寻找 passwd

这个命令的另一种方法是输入: man passwd.1

使用 man -k 来搜索包含某个关键词的所有手册页

如果你想获得包含某个关键词的手册页的列表,man 命令中的 -k 选项(通常称为标志或开关)可以派上用场。例如,如果你想看一个关于 ftp 的手册列表,你可以通过输入以下内容得到这个列表:

man -k ftp

在接下来的列表中,你可以选择一个特定的手册页来阅读:

man k example

在某些系统上,在 man -k 工作之前,系统管理员需要运行一个叫做 catman 的工具。

使用 whatis 和 whereis 命令来了解手册的各个节

有两个有趣的工具可以帮助你搜索信息:whatiswhereis

whatis

有的时候,我们完全可以得到我们需要的信息。我们需要的信息有很大的机会是可以找到的 —— 找到它可能是一个小问题。

例如,如果我想看关于 passwd 文件的手册页,我在终端上输入:

man passwd

我就会看到关于 passwd 命令所有信息的手册页,但没有关于 passwd 文件的内容。我知道 passwd 是一个命令,也有一个 passwd 文件,但有时,我可能会忘记这一点。这时我才意识到,文件结构在手册页中的不同节,所以我输入了:

man 4 passwd

我得到这样的答复:

No manual entry for passwd in section 4
See 'man 7 undocumented' for help when manual pages are not available.

又是一次健忘的失误。文件结构在 System V UNIX 页面的第 4 节中。几年前,当我建立文件时,我经常使用 man 4 ...;这仍然是我的一个习惯。那么它在 Linux 手册中的什么地方呢?

现在是时候调用 whatis 来纠正我了。为了做到这一点,我在我的终端中输入以下内容:

whatis passwd

然后我看到以下内容:

passwd (1)           - change user password
passwd (1ssl)        - compute password hashes
passwd (5)           - the password file

啊!passwd 文件的页面在第 5 节。现在没问题了,可以访问我想要的信息了:

man 5 passwd

然后我被带到了有我需要的信息的手册页。

whatis 是一个方便的工具,可以用简短的一句话告诉你一个命令的作用。想象一下,你想知道 cal 是做什么的,而不想查看手册页。只要在命令提示符下键入以下内容。

whatis cal

你会看到这样的回应:

cal (1)              - displays a calendar and the date of Easter

现在你知道了 whatis 命令,我可以告诉你一个秘密 —— 有一个 man 命令的等价物。为了得到这个,我们使用 -f 开关:man -f ...

试试吧。在终端提示下输入 whatis cal。执行后就输入:man -f cal。两个命令的输出将是相同的:

whatis cal and man f cal outputs are the same

whereis

whereis 命令的名字就说明了这一点 —— 它告诉你一个程序在文件系统中的位置。它也会告诉你手册页的存放位置。再以 cal 为例,我在提示符下输入以下内容:

whereis cal

我将看到这个:

whereis cal output

仔细看一下这个回答。答案只在一行里,但它告诉我两件事:

  • /usr/bin/calcal 程序所在的地方,以及
  • /usr/share/man/man1/cal.1.gz 是手册页所在的地方(我也知道手册页是被压缩的,但不用担心 —— man 命令知道如何即时解压)。

whereis 依赖于 PATH 环境变量;它只能告诉你文件在哪里,如果它们在你的 PATH 环境变量中。

你可能想知道是否有一个与 whereis 相当的 man 命令。没有一个命令可以告诉你可执行文件的位置,但有一个开关可以告诉你手册页的位置。在这个例子中使用 date 命令,如果我们输入:

whereis date

在终端提示符下,我们会看到:

whereis date output

我们看到 date 程序在 /usr/bin/ 目录下,其手册页的名称和位置是:/usr/share/man/man1/date.1.gz

我们可以让 manwhereis 一样行事,最接近的方法是使用 -w 开关。我们不会得到程序的位置,但我们至少可以得到手册页的位置,像这样:

man -w date

我们将看到这样的返回:

你知道了 whatiswhereis,以及让 man 命令做同样(或接近)事情的方法。我展示了这两种方法,有几个不同的原因。

多年来,我使用 whatiswhereis,因为它们在我的培训手册中。直到最近我才了解到 man -f ...man -w ...。我确信我看了几百次 man 的手册页,但我从未注意到 -f-w 开关。我总是在看手册页的其他东西(例如:man -k ...)。我只专注于我需要找到的东西,而忽略了其他的东西。一旦我找到了我需要的信息,我就会离开这个页面,去完成工作,而不去注意这个命令所提供的其他一些宝贝。

这没关系,因为这部分就是手册页的作用:帮助你完成工作。

直到最近我向别人展示如何使用手册页时,我才花时间去阅读 —— “看看还有什么可能” —— 我们才真正注意到关于 man 命令的 -f-w 标记可以做什么的信息。

不管你使用 Linux 多久了,或者多么有经验,总有一些新东西需要学习。

手册页会告诉你在完成某项任务时可能需要知道的东西 —— 但它们也有很多内容 —— 足以让你看起来像个魔术师,但前提是你要花时间去读。

结论

如果你花一些时间和精力在手册页上,你将会取得胜利。你对手册页的熟练程度,将在你掌握 Linux 的过程中发挥巨大作用。


via: https://itsfoss.com/linux-man-page-guide/

作者:Bill Dyer 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

探索最近版本的 Python 的一些有用的特性。

 title=

这是 Python 3.x 首发特性系列文章中的第十篇,其中一些版本已经发布了一段时间。Python 3.9 在 2020 年首次发布,具有很酷的新特性,但仍未被充分利用。下面是其中的三个。

添加字典

假设你有一个 defaults 字典,而你想更新它的参数。在 Python 3.9 之前,最好的办法是复制 defaults 字典,然后使用 .update() 方法。

Python 3.9 为字典引入了联合运算符:

defaults = dict(who="someone", where="somewhere")
params = dict(where="our town", when="today")
defaults | params
    {'who': 'someone', 'where': 'our town', 'when': 'today'}

注意,顺序很重要。在这种情况下,正如预期,来自 paramswhere 值覆盖了默认值。

删除前缀

如果你用 Python 做临时的文本解析或清理,你会写出这样的代码:

def process_pricing_line(line):
    if line.startswith("pricing:"):
        return line[len("pricing:"):]
    return line
process_pricing_line("pricing:20")
    '20'

这样的代码很容易出错。例如,如果字符串被错误地复制到下一行,价格就会变成 0 而不是 20,而且会悄悄地发生。

从 Python 3.9 开始,字符串有了一个 .lstrip() 方法:

"pricing:20".lstrip("pricing:")
    '20'

任意的装饰器表达式

以前,关于装饰器中允许哪些表达式的规则没有得到充分的说明,而且很难理解。例如:虽然

@item.thing
def foo():
    pass

是有效的,而且:

@item.thing()
def foo():
    pass

是有效的,相似地:

@item().thing
def foo():
    pass

产生一个语法错误。

从 Python 3.9 开始,任何表达式作为装饰器都是有效的:

from unittest import mock

item = mock.MagicMock()

@item().thing
def foo():
    pass
print(item.return_value.thing.call_args[0][0])
    <function foo at 0x7f3733897040>

虽然在装饰器中保持简单的表达式仍然是一个好主意,但现在是人类的决定,而不是 Python 分析器的选择。

欢迎来到 2020 年

Python 3.9 大约在一年前发布,但在这个版本中首次出现的一些特性非常酷,而且没有得到充分利用。如果你还没使用,那么将它们添加到你的工具箱中。


via: https://opensource.com/article/21/5/python-39-features

作者:Moshe Zadka 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

编者按:本文来自华辰连科技术团队,分享了他们在将浮点运算放到内核态时的探索。

最近我们有一个需求,需要把用户态的浮点数运算全部放到内核态运行,以提高运行速度,移植的过程中发现问题没有这么简单,然后我们抽丝剥茧,揭开 Linux 对浮点处理的原理。

此文章的代码基于 x86 64 位 CPU,Linux 4.14 内核。

一、 Linux 内核添加浮点运算出现的问题

我们以一个简单的浮点运算例子来说明:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <asm/fpu/api.h>
#include <linux/delay.h>

static noinline double float_divide(double float1, double float2)
{
    return float1 / float2;
}

static int __init test_float_init(void)
{
  double result, float1 = 4.9, float2 = 0.49;
​
  result = float_divide(float1, float2);
  printk("result = %d\n", (int)result);
​
  return 0;
}
​
static void __exit test_float_exit(void)
{
  ;
}
​
module_init(test_float_init);
module_exit(test_float_exit);
MODULE_LICENSE("GPL");

test\_float.c

obj-m := test_float.o
KDIR := /lib/modules/$(shell uname -r)/build
​
all:
make -C $(KDIR) M=$(PWD) modules

Makefile

这个内核模块就是计算了两个浮点数除的结果,然后将结果打印出来 。但是我们执行 make 编译的时候发现报错:

提示 SSE 寄存器返回的报错信息为 “SSE disabled”。我们执行 make V=1 查看关键的编译信息:

我们发现在 gcc 的参数中有 -mno-sse -mno-mmx -mno-sse2 选项,原来 gcc 默认的编译选项禁用了 sse、mmx、sse2 等浮点运算指令。

二、通过添加 gcc 编译参数和 kernel\_fpu\_begin/kernel\_fpu\_end 来解决问题

为了让内核支持浮点运算,我们在 Makefile 中添加支持 sse 等选项,源码中添加 kernel_fpu_begin/kernel_fpu_end 函数,修改后的源码如下所示:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <asm/fpu/api.h>
#include <linux/delay.h>

static noinline double float_divide(double float1, double float2)
{
    return float1 / float2;
}

static int __init test_float_init(void)
{
  double result, float1 = 4.9, float2 = 0.49;
​
  kernel_fpu_begin();
  result = float_divide(float1, float2);
  kernel_fpu_end();
  printk("result = %d\n", (int)result);
​
  return 0;
}
​
static void __exit test_float_exit(void)
{
  ;
}
​
module_init(test_float_init);
module_exit(test_float_exit);
MODULE_LICENSE("GPL");

test\_float.c

obj-m := test_float.o
KDIR := /lib/modules/$(shell uname -r)/build
​
FPU_CFLAGS += -mhard-float
FPU_CFLAGS += -msse -msse2
CFLAGS_test_float.o += $(FPU_CFLAGS)
​
all:
make -C $(KDIR) M=$(PWD) modules

Makefile

此时执行 make,发现编译正确通过了:

然后 insmod test_float.ko,观察 dmesg 的输出:

从上面的例子,结合内核源码中 arch/x86/Makefile 中的 KBUILD_CFLAGS,可以看到编译内核及内核模块时,gcc 选项继承 Linux 中的规则,指定了 -mno-sse -mno-mmx -mno-sse2,也就是禁用了 FPU 。所以,要想内核模组支持浮点运算,编译选项需要显式的指定 -msse -msse2

三、 Linux 内核态对浮点运算处理方式的分析

从上面可以看到,我们为了实现一个内核模块的浮点运算,添加了编译参数 -mhard-float和-msse -msse2,对于编译参数来说,-mhard-float 是告诉编译器直接生成浮点运算的指令,而 -msse -msse2 则是告诉编译器可以使用 sse/sse2 指令集来编译代码。

kernel_fpu_beginkernel_fpu_end 也是必须的,因为 Linux 内核为了提高系统的运行速率,在任务上下文切换时,只会保存/恢复普通寄存器的值,并不包括 FPU 浮点寄存器的值,而调用 kernel_fpu_begin 主要作用是关掉系统抢占,浮点计算结束后调用 kernel_fpu_end 开启系统抢占,这使得代码不会被中断,从而安全的进行浮点运算,并且要求这之间的代码不能有休眠或调度操作,另外不得有嵌套的情况出现(将会覆盖原始保存的状态,然后执行 kernel_fpu_end() 最终将恢复错误的 FPU 状态)。

void kernel_fpu_begin(void)
{
  preempt_disable();
  __kernel_fpu_begin();
}

四、三角函数在 Linux 内核态的实现

由于内核态不支持浮点运算,所以像三角函数之类浮点运算都没有实现,如果需要,可以将用户态 glibc 中相关的三角函数的实现移植到内核态。

五、 Linux 用户态对浮点运算处理方式的分析

为什么用户态浮点运算就不需要指定编译选项以及显式调用 kernel_fpu_beginkernel_fpu_end 函数呢?我们在用户态下写一个简单的带浮点运算的例子:

#include <stdio.h>
​
int main(int argc, char **argv)
{
  int result, float1=4.9, float2=0.49;
​
  result = float1 / float2;
  printf("result = %d\n", result);
​
  return 0;
}

user\_float.c

我们分别使用下面四条编译指令查看编译出来的汇编:

  1. gcc -S user_float.c
  2. gcc -S user_float.c -msoft-float
  3. gcc -S user_float.c -mhard-float
  4. gcc -S user_float.c -msoft-float -mno-sse -mno-mmx -mno-sse2

前三条命令编译成功。依次查看编译生成的汇编代码,发现生成的汇编代码是完全一样的,都是用到了 sse 指令中的 mmx 寄存器,也就是使用到了 FPU。

第四条命令编译失败 ,提示 error: SSE register return with SSE disabled。从上面的现象中我们可以得出结论,系统默认使用 gcc 编译用户态程序时,gcc 默认使用 FPU,也就是使用硬浮点来编译。

经过查阅各种文档和分析代码,x86 CPU 提供如下特性:CPU 提供的 TS 寄存器的第三个位是 任务已切换标志 Task Switched bit ,CPU 在每次任务切换时会设置这个位。而且 TS 的这个位被设置时,当进程使用 FPU 指令时 CPU 会产生一个 DNA(Device Not Availabel)异常。Linux 使用此特性,当用户态应用程序进行浮点运算时(SSE 等指令),触发 DNA 异常,同时使用 FPU 专用寄存器和指令来执行浮点数功能,此时 TS_USEDFPU 标志为 1,表示用户态进程使用了 FPU。

void fpu__restore(struct fpu *fpu)
{
  fpu__initialize(fpu);

  /* Avoid __kernel_fpu_begin() right after fpregs_activate() */
  kernel_fpu_disable();
  trace_x86_fpu_before_restore(fpu);
  fpregs_activate(fpu);
  copy_kernel_to_fpregs(&fpu->state);
  trace_x86_fpu_after_restore(fpu);
  kernel_fpu_enable();
}
EXPORT_SYMBOL_GPL(fpu__restore);

假设用户态进程 A 使用到了 FPU 执行浮点运算,此时用户态进程 B 被调度执行,那么当进程 A 被调度出去的时候,内核设置 TS 并调用 fpu__restore 将 FPU 的内容保存。当进程 A 恢复浮点运算执行时,触发 DNA 异常,相应的异常处理程序会恢复 FPU 之前保存的状态。

假设用户态进程 A 使用到了 FPU 执行浮点运算(TS_USEDFPU 标志为 1),此时内核态进程 C 调度并使用 FPU,由于内核只会保存普通的寄存器的值,并不包括 FP 等寄存器的值,所以内核会主动调用 kernel_fpu_begin 函数保存寄存器内容,使用完之后调用 kernel_fpu_end。当用户态进程 A 恢复浮点运算执行时,触发 DNA 异常,相应的异常处理程序会恢复 FPU 寄存器的内容。

六、 结论

  1. Linux 中当任务切换时,缺省不保存浮点器寄存器。
  2. 如果需要内核态支持浮点运算,需要增加支持浮点的编译选项和使用 kernel_fpu_beginkernel_fpu_end 函数手动处理上下文。
  3. 用户态缺省支持浮点运算,但是需要内核来辅助。