mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
Merge branch 'LCTT:master' into master
This commit is contained in:
commit
9f692f8069
@ -2,93 +2,96 @@
|
||||
[#]: via: "https://ostechnix.com/monitor-user-activity-linux/"
|
||||
[#]: author: "sk https://ostechnix.com/author/sk/"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: translator: "ChatGPT"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-16297-1.html"
|
||||
|
||||
How To Monitor User Activity In Linux
|
||||
如何在 Linux 中监控用户活动
|
||||
======
|
||||
As a Linux administrator, you need to keep track of all users' activities. When something goes wrong in the server, you can analyze and investigate the users' activities, and try to find the root cause of the problem. There are many ways to **monitor users in Linux**. In this guide, we are going to talk about **GNU accounting utilities** that can be used to **monitor the user activity in Linux**.
|
||||
|
||||
### What are Accounting utilities?
|
||||
![][0]
|
||||
|
||||
The Accounting utilities provides the useful information about system usage, such as connections, programs executed, and utilization of system resources in Linux. These accounting utilities can be installed using **psacct** or **acct** package.
|
||||
作为一位 Linux 管理员,你需要跟踪所有用户的活动。当服务器发生故障时,你可以分析和查看用户活动,以便寻找问题的根源。监控 Linux 用户有多种方式。本指南将专门讨论 **GNU 记账工具**,这是一项用于监视 Linux 用户活动的实用工具。
|
||||
|
||||
The psacct or acct are same. In RPM-based systems, it is available as psacct, and in DEB-based systems, it is available as acct.
|
||||
### 什么是记账工具?
|
||||
|
||||
What is the use of psacct or acct utilities? You might wonder. Generally, the user's command line history details will be stored in **.bash_history** file in their $HOME directory. Some users might try to edit, modify or delete the history.
|
||||
记账工具可以提供诸如 Linux 系统中的连接、已执行的程序以及系统资源的使用等有底系统使用信息。这些记账工具可以通过 `psacct` 或 `acct` 软件包安装。
|
||||
|
||||
However, the accounting utilities will still be able to retrieve the users activities even though they [cleared their command line history][1] completely. Because, **all process accounting files are owned by root** user, and the normal users can't edit them.
|
||||
`psacct` 和 `acct` 实际上是相同的。在基于 RPM 的系统中,它以 `psacct` 的形式存在;而在基于 DEB 的系统中,它作为 `acct` 提供。
|
||||
|
||||
### Install psacct or acct in Linux
|
||||
你可能想知道 `psacct` 或 `acct` 工具的作用。通常,用户在命令行的历史记录会保存在他们的 `$HOME` 目录下的 `.bash_history` 文件中。有些用户可能会尝试编辑、修改或删除这些历史记录。
|
||||
|
||||
The psacct/acct utilities are packaged for popular Linux distributions.
|
||||
然而,即使他们完全 [清除了命令行历史][1],记账工具依然能够获取用户活动信息。这是因为,**所有进程记账文件都由 root 用户拥有**,而普通用户则无法进行编辑。
|
||||
|
||||
To install psacct in Alpine Linux, run:
|
||||
### Linux 中如何安装 psacct 或 acct
|
||||
|
||||
`psacct`/`acct` 被打包在多种流行的 Linux 发行版本中。
|
||||
|
||||
如果要在 Alpine Linux 中安装 `psacct`,请运行以下命令:
|
||||
|
||||
```
|
||||
$ sudo apk add psacct
|
||||
```
|
||||
|
||||
To install acct in Arch Linux and its variants like EndeavourOS and Manjaro Linux, run:
|
||||
如果在 Arch Linux 及其变体版本(如 EndeavourOS 和 Manjaro Linux)中安装 `acct`,请运行以下命令:
|
||||
|
||||
```
|
||||
$ sudo pacman -S acct
|
||||
```
|
||||
|
||||
On Fedora, RHEL, and its clones like CentOS, AlmaLinux and Rocky Linux, run the following command to install psacct:
|
||||
在 Fedora、RHEL 及其衍生版本(如 CentOS、AlmaLinux 和 Rocky Linux)中安装 `psacct`,请运行以下命令:
|
||||
|
||||
```
|
||||
$ sudo dnf install psacct
|
||||
```
|
||||
|
||||
In RHEL 6 and older versions, you should use `yum` instead of `dnf` to install psacct.
|
||||
在 RHEL 6 以及更早版本中,你应当使用 `yum` 命令而非 `dnf` 来安装 `psacct`。
|
||||
|
||||
```
|
||||
$ sudo yum install psacct
|
||||
```
|
||||
|
||||
On Debian, Ubuntu, Linux Mint, install acct using command:
|
||||
在 Debian、Ubuntu 以及 Linux Mint 中,通过如下命令来安装 `acct`:
|
||||
|
||||
```
|
||||
$ sudo apt install acct
|
||||
```
|
||||
|
||||
To install acct on openSUSE, run:
|
||||
若在 openSUSE 中安装 `acct`,则运行:
|
||||
|
||||
```
|
||||
$ sudo zypper install acct
|
||||
```
|
||||
|
||||
### Start psacct/acct service
|
||||
### 启动 psacct/acct 服务
|
||||
|
||||
To enable and start the psacct service, run:
|
||||
要启用并开启 `psacct` 服务,请执行以下命令:
|
||||
|
||||
```
|
||||
$ sudo systemctl enable psacct
|
||||
```
|
||||
|
||||
接着启动 `psacct` 服务:
|
||||
|
||||
```
|
||||
$ sudo systemctl start psacct
|
||||
```
|
||||
|
||||
To check if psacct service is loaded and active, run:
|
||||
如果你需要检查 `psacct` 服务是否已加载和激活,可以运行:
|
||||
|
||||
```
|
||||
$ sudo systemctl status psacct
|
||||
```
|
||||
|
||||
On DEB-based systems, the acct service will be automatically started after installing it.
|
||||
在基于 DEB 的系统中,安装完成之后,`acct` 服务会自动启动。
|
||||
|
||||
You can verify whether acct service is started or not using command:
|
||||
如果你想验证 `acct` 服务是否已经启动,可以执行以下命令:
|
||||
|
||||
```
|
||||
$ sudo systemctl status acct
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
|
||||
```
|
||||
● acct.service - Kernel process accounting
|
||||
Loaded: loaded (/lib/systemd/system/acct.service; enabled; vendor preset: enabled)
|
||||
@ -103,48 +106,46 @@ Oct 13 16:06:35 ubuntu2204 accton[3241]: Turning on process accounting, file set
|
||||
Oct 13 16:06:35 ubuntu2204 systemd[1]: Finished Kernel process accounting.
|
||||
```
|
||||
|
||||
> **Download** - [Free eBook: "Nagios Monitoring Handbook"][2]
|
||||
### 利用 psacct 或 acct 来监测 Linux 中的用户活动
|
||||
|
||||
### Monitor User Activity in Linux using psacct or acct
|
||||
`psacct`(进程记账)软件包包含以下用来监测用户和进程活动的工具:
|
||||
|
||||
The psacct (Process accounting) package contains following useful utilities to monitor the user and process activities.
|
||||
* `ac` - 提供用户登录时间的统计信息。
|
||||
* `lastcomm` - 展示先前执行过的命令的信息。
|
||||
* `accton` - 开启或关闭进程记账。
|
||||
* `dump-acct` - 把 `accton` 的输出文件转化为易读的格式。
|
||||
* `dump-utmp` - 以易读的方式打印 `utmp` 文件。
|
||||
* `sa` - 汇总信息,关于先前执行的命令。
|
||||
|
||||
* ac - Displays statistics about how long users have been logged on.
|
||||
* lastcomm - Displays information about previously executed commands.
|
||||
* accton - Turns process accounting on or off.
|
||||
* dump-acct - Transforms the output file from the accton format to a human-readable format.
|
||||
* dump-utmp - Prints utmp files in human-readable format.
|
||||
* sa - Summarizes information about previously executed commands.
|
||||
现在就让我们一起了解如何通过每个工具来监控 Linux 用户的活动。
|
||||
|
||||
Let us learn how to monitor the activities of Linux users by using each utility with examples.
|
||||
#### 1、使用 ac 命令
|
||||
|
||||
#### 1. The ac command examples
|
||||
`ac` 工具可以为你提供以小时为单位的连接时间报告,这样你就能知道用户或一组用户连接到系统的时长。
|
||||
|
||||
The **ac** utility will display the report of connect time in hours. It can tell you how long a user or group of users were connected to the system.
|
||||
|
||||
##### 1.1. Display total connect time of all users
|
||||
##### 1.1、展示所有用户的总连接时间
|
||||
|
||||
```
|
||||
$ ac
|
||||
```
|
||||
|
||||
This command displays the total connect time of all users in hours.
|
||||
上述命令会显示所有用户的总连接时间(单位为小时)。
|
||||
|
||||
```
|
||||
total 52.91
|
||||
```
|
||||
|
||||
![Display total connect time of all users][3]
|
||||
![展示所有用户的总连接时间][3]
|
||||
|
||||
##### 1.2. Show total connect of all users by day-wise
|
||||
##### 1.2、按日期排序显示所有用户的总连接时间
|
||||
|
||||
You can sort this result by day-wise by using **-d** flag as shown below.
|
||||
你可以通过使用 `-d` 参数,按日期排序显示所有用户的连接时间,操作如下:
|
||||
|
||||
```
|
||||
$ ac -d
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
May 11 total 4.29
|
||||
@ -161,17 +162,17 @@ Jul 19 total 1.95
|
||||
Today total 0.29
|
||||
```
|
||||
|
||||
![Show total connect of all users by day-wise][4]
|
||||
![按日期排序显示所有用户的总时间][4]
|
||||
|
||||
##### 1.3. Get total connect time by user-wise
|
||||
##### 1.3、获取各个用户的总连接时间
|
||||
|
||||
Also, you can display how long each user was connected with the system with **-p** flag.
|
||||
使用 `-p` 参数,你可以查看每位用户各自在系统中总的连接时长。
|
||||
|
||||
```
|
||||
$ ac -p
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
ostechnix 52.85
|
||||
@ -179,31 +180,31 @@ root 0.51
|
||||
total 53.36
|
||||
```
|
||||
|
||||
![Get total connect time by user-wise][5]
|
||||
![获取各个用户的总连接时间][5]
|
||||
|
||||
##### 1.4. Print total connect time of a specific user
|
||||
##### 1.4、显示指定用户的总连接时间
|
||||
|
||||
And also, you can display the individual user's total login time as well.
|
||||
你还可以显示特定用户的总登录时间。
|
||||
|
||||
```
|
||||
$ ac ostechnix
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
total 52.95
|
||||
```
|
||||
|
||||
##### 1.5. View total connect time of a certain user by day-wise
|
||||
##### 1.5、显示特定用户各日期的总连接时间
|
||||
|
||||
To display individual user's login time by day-wise, run:
|
||||
要按日期查看某个用户的登录时间,可以运行:
|
||||
|
||||
```
|
||||
$ ac -d ostechnix
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
May 11 total 4.29
|
||||
@ -220,25 +221,25 @@ Jul 19 total 1.95
|
||||
Today total 0.68
|
||||
```
|
||||
|
||||
![View total connect time of a certain user by day-wise][6]
|
||||
![显示某个用户各日期的总连接时间][6]
|
||||
|
||||
For more details, refer the man pages.
|
||||
如需更多详情,可参考手册页面。
|
||||
|
||||
```
|
||||
$ man ac
|
||||
```
|
||||
|
||||
#### 2. The lastcomm command examples
|
||||
#### 2、lastcomm 命令使用示例
|
||||
|
||||
The **lastcomm** utility displays the list of previously executed commands. The most recent executed commands will be listed first.
|
||||
`lastcomm` 工具用于列出过去执行过的命令,它会按执行的最近程度将命令列在前面。
|
||||
|
||||
##### 2.1. Display previously executed commands
|
||||
##### 2.1、展示过去执行的命令
|
||||
|
||||
```
|
||||
$ lastcomm
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
systemd-hostnam S root __ 0.06 secs Thu Oct 13 17:21
|
||||
@ -260,15 +261,15 @@ bash F ostechni pts/1 0.00 secs Thu Oct 13 17:22
|
||||
[...]
|
||||
```
|
||||
|
||||
##### 2.2. Print last executed commands of a specific user
|
||||
##### 2.2、打印特定用户先前执行的命令
|
||||
|
||||
The above command displays all user's commands. You can display the previously executed commands by a particular user using command:
|
||||
上述命令显示的是所有用户的命令。要显示特定用户以前执行的命令,可以使用下面的命令:
|
||||
|
||||
```
|
||||
$ lastcomm ostechnix
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
less ostechni pts/1 0.00 secs Thu Oct 13 17:26
|
||||
@ -289,15 +290,15 @@ dpkg ostechni __ 0.00 secs Thu Oct 13 17:23
|
||||
[...]
|
||||
```
|
||||
|
||||
##### 2.3. Print total number of command execution
|
||||
##### 2.3、打印特定命令的执行次数
|
||||
|
||||
Also, you can view how many times a particular command has been executed.
|
||||
你还可以查看特定命令被执行的次数。
|
||||
|
||||
```
|
||||
$ lastcomm apt
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
apt S root pts/2 0.70 secs Thu Oct 13 16:06
|
||||
@ -305,25 +306,25 @@ apt F root pts/2 0.00 secs Thu Oct 13 16:06
|
||||
apt F root pts/2 0.00 secs Thu Oct 13 16:06
|
||||
```
|
||||
|
||||
As you see in the above output, the `apt` command has been executed three times by `root` user.
|
||||
如上述输出所示,root 用户执行了 `apt` 命令三次。
|
||||
|
||||
For more details, refer the man pages.
|
||||
更详细的信息,可参考手册页:
|
||||
|
||||
```
|
||||
$ man lastcomm
|
||||
```
|
||||
|
||||
#### 3. The sa command examples
|
||||
#### 3、sa 命令示例
|
||||
|
||||
The sa utility will summarize the information about previously executed commands.
|
||||
`sa` 实用程序将总结关于先前执行的命令的信息。
|
||||
|
||||
##### 3.1. Print summary of all commands
|
||||
##### 3.1、打印所有命令的总结
|
||||
|
||||
```
|
||||
$ sa
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
1522 1598.63re 0.23cp 0avio 32712k
|
||||
@ -346,15 +347,15 @@ $ sa
|
||||
[...]
|
||||
```
|
||||
|
||||
##### 3.2. View number of processes and CPU minutes
|
||||
##### 3.2、查看进程数量和 CPU 分钟数
|
||||
|
||||
To print the number of processes and number of CPU minutes on a per-user basis, run `sa` command with `-m` flag:
|
||||
要打印基于每个用户的进程数量和 CPU 分钟数,运行带 `-m` 标志的 `sa` 命令:
|
||||
|
||||
```
|
||||
$ sa -m
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
1525 1598.63re 0.23cp 0avio 32651k
|
||||
@ -370,15 +371,15 @@ sshd 1 0.05re 0.00cp 0avi
|
||||
whoopsie 1 0.00re 0.00cp 0avio 8552k
|
||||
```
|
||||
|
||||
##### 3.3. Print user id and command name
|
||||
##### 3.3、打印用户 ID 和命令名称
|
||||
|
||||
For each command in the accounting file, print the userid and command name using `-u` flag.
|
||||
对于账户文件中的每个命令,使用 `-u` 标志打印用户 ID 和命令名称。
|
||||
|
||||
```
|
||||
$ sa -u
|
||||
```
|
||||
|
||||
**Sample output:**
|
||||
示例输出:
|
||||
|
||||
```
|
||||
root 0.00 cpu 693k mem 0 io accton
|
||||
@ -397,27 +398,27 @@ root 0.00 cpu 911k mem 0 io gzip
|
||||
[...]
|
||||
```
|
||||
|
||||
For more details, refer the man pages.
|
||||
如需更多详细信息,请参考手册页:
|
||||
|
||||
```
|
||||
$ man sa
|
||||
```
|
||||
|
||||
#### 4. The dump-acct and dump-utmp command examples
|
||||
#### 4、dump-acct 和 dump-utmp 命令
|
||||
|
||||
The **dump-acct** utility displays the output file from the accton format to a human-readable format.
|
||||
`dump-acct` 实用工具将 accton 格式的输出文件显示为人类可读的格式。
|
||||
|
||||
```
|
||||
$ dump-acct /var/account/pacct
|
||||
```
|
||||
|
||||
dump-utmp displays utmp files in human-readable format.
|
||||
`dump-utmp` 将 utmp 文件显示为人类可读的格式。
|
||||
|
||||
```
|
||||
$ dump-utmp /var/run/utmp
|
||||
```
|
||||
|
||||
For more details, refer the man pages.
|
||||
如需了解更多详情,请参考手册页:
|
||||
|
||||
```
|
||||
$ man dump-acct
|
||||
@ -427,35 +428,37 @@ $ man dump-acct
|
||||
$ man dump-utmp
|
||||
```
|
||||
|
||||
#### 5. The accton command examples
|
||||
#### 5、accton 命令
|
||||
|
||||
The accton command will allow you to turn on or turn off accounting.
|
||||
`accton` 命令将允许你开启或关闭记账。
|
||||
|
||||
To turn on process accounting, run:
|
||||
要开启进程记账,请运行:
|
||||
|
||||
```
|
||||
$ accton on
|
||||
```
|
||||
|
||||
To turn it off, run:
|
||||
要关闭它,运行:
|
||||
|
||||
```
|
||||
$ accton off
|
||||
```
|
||||
|
||||
For more details, refer the man pages.
|
||||
如需了解更多详情,请参考手册页:
|
||||
|
||||
```
|
||||
$ man accton
|
||||
```
|
||||
|
||||
### Conclusion
|
||||
### 总结
|
||||
|
||||
Every Linux administrator should be aware of GNU accounting utilities to keep an eye on all users. These utilities will be quite helpful in troubleshooting time.
|
||||
每个 Linux 管理员都应该知道 GNU 记账实用程序,以便注意所有用户的行为。在故障排除时,这些实用程序会非常有帮助。
|
||||
|
||||
**Resource:**
|
||||
### 资源
|
||||
|
||||
* [The GNU Accounting Utilities website][7]
|
||||
* [GNU 记账实用程序官网][7]
|
||||
|
||||
*(题图:MJ/da3f7e79-2a53-4121-a2ed-d63a22c3d3f4)*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -463,8 +466,8 @@ via: https://ostechnix.com/monitor-user-activity-linux/
|
||||
|
||||
作者:[sk][a]
|
||||
选题:[lkxed][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[ChatGPT](https://linux.cn/lctt/ChatGPT)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -477,3 +480,4 @@ via: https://ostechnix.com/monitor-user-activity-linux/
|
||||
[5]: https://ostechnix.com/wp-content/uploads/2022/10/Get-total-connect-time-by-user-wise.png
|
||||
[6]: https://ostechnix.com/wp-content/uploads/2022/10/View-total-connect-time-of-a-certain-user-by-day-wise.png
|
||||
[7]: https://www.gnu.org/software/acct/manual/accounting.html
|
||||
[0]: https://img.linux.net.cn/data/attachment/album/202310/19/105911voe22858b5o7287s.jpg
|
312
published/20230217 Working with Btrfs - Compression.md
Normal file
312
published/20230217 Working with Btrfs - Compression.md
Normal file
@ -0,0 +1,312 @@
|
||||
[#]: subject: "Working with Btrfs – Compression"
|
||||
[#]: via: "https://fedoramagazine.org/working-with-btrfs-compression/"
|
||||
[#]: author: "Andreas Hartmann https://fedoramagazine.org/author/hartan/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: "A2ureStone"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-16299-1.html"
|
||||
|
||||
Btrfs 详解:压缩
|
||||
======
|
||||
|
||||
![][0]
|
||||
|
||||
这篇文章将探索 Btrfs 中的透明文件系统压缩,以及它如何帮助节省存储空间。这篇文章是《Btrfs 详解》系列文章中的一篇。从 Fedora Linux 33 开始,Btrfs 就是 Fedora Workstation 和 Fedora Silverblue 的默认文件系统。
|
||||
|
||||
如果你错过了,这里是本系列的上一篇文章:[Btrfs 详解:快照][1]。
|
||||
|
||||
### 简介
|
||||
|
||||
很多人都经历过存储空间用完的情况。也许你想从互联网下载一个大文件,或者你需要快速从你的手机中复制些照片,然后操作突然失败。虽然存储空间成本正在稳步降低,但越来越多的设备要么制造时就是固定数量的存储容量,要么最终用户难以扩展其存储容量。
|
||||
|
||||
但当你的存储空间不足时你可以做什么呢?也许你会求助于云存储,或者你可以随身携带一些外部存储设备。
|
||||
|
||||
在这篇文章里我会研究该问题的另一种解决方案:透明的文件系统压缩,这是 Btrfs 的一个特性。理想情况下,这将解决你的存储问题,同时几乎不需要对你的系统进行修改!让我们来看看是如何做到的。
|
||||
|
||||
### 透明压缩的解释
|
||||
|
||||
首先,让我们来探寻 _透明_ 压缩是什么意思。你可以通过像 gzip、xz 或者 bzip2 这些压缩算法去压缩文件。这通常是显式操作:你利用一个压缩工具并且让它操作你的文件。虽然根据文件的内容,节约了空间,这有一个主要的缺点:当你想读取文件或者修改的时候,你得先解压缩。
|
||||
|
||||
这不仅是一个乏味的过程,而且也暂时打破了你之前节省的空间。再者,你最终解压了你不想访问的那部分文件内容。明显有比这更好的方法!
|
||||
|
||||
相反,透明压缩发生在文件系统级别。在这里,压缩的文件对用户看起来像常规的未压缩文件一样。但是,它们是被压缩后存储在硬盘上的。这之所以可行,是因为操作系统仅仅选择性地访问那部分文件,并且确保在向磁盘写入更新时再次压缩它们。
|
||||
|
||||
这里的压缩是透明的在于它不被用户感知,除了在文件访问时可能的 CPU 负载小量增加。因此,你可以应用在已有的系统而不是进行硬件修改或者求助于云存储。
|
||||
|
||||
### 压缩算法对比
|
||||
|
||||
Btrfs 提供了多个压缩算法的选择。出于技术原因它不能选用任意的压缩算法。它现在支持:
|
||||
|
||||
* zstd
|
||||
* lzo
|
||||
* zlib
|
||||
|
||||
好消息是,由于透明压缩的工作原理,你不需要安装这些程序供 Btrfs 使用。在下面的文章里,你会看到如何去运行一个简单的性能测试来对比压缩算法。但是,为了运行性能测试,你必须安装必要的可执行文件。事后不需要留着它们,所以你将使用 Podman 容器来确保不会在系统中留下任何痕迹。
|
||||
|
||||
**注意** :因为 Btrfs 使用的压缩依赖于内核对这些压缩算法的(重新)实现,用户空间版本的算法得出的结果应该认为是粗略估计。
|
||||
|
||||
因为一次次敲重复的命令是枯燥的工作,我已经在 Gitlab 上准备了一个可以运行的 Bash 脚本 (<https://gitlab.com/hartang/btrfs-compression-test>)。这会用上面提到的每个算法在不同的压缩级别运行一次简单的压缩和解压缩。
|
||||
|
||||
首先,下载脚本:
|
||||
|
||||
```
|
||||
$ curl -LO https://gitlab.com/hartang/btrfs-compression-test/-/raw/main/btrfs_compression_test.sh
|
||||
```
|
||||
|
||||
下一步,启动一个 Fedora Linux 容器去挂载你当前的工作目录,以便你可以和主机交换文件同时在那里运行脚本:
|
||||
|
||||
```
|
||||
$ podman run --rm -it --security-opt label=disable -v "$PWD:$PWD" \
|
||||
-w "$PWD" registry.fedoraproject.org/fedora:37
|
||||
```
|
||||
|
||||
最后运行脚本:
|
||||
|
||||
```
|
||||
$ chmod +x ./btrfs_compression_test.sh
|
||||
$ ./btrfs_compression_test.sh
|
||||
```
|
||||
|
||||
在我机器上的输出是这样:
|
||||
|
||||
```
|
||||
[INFO] Using file 'glibc-2.36.tar' as compression target
|
||||
[INFO] Target file 'glibc-2.36.tar' not found, downloading now...
|
||||
################################################################### 100.0%
|
||||
[ OK ] Download successful!
|
||||
[INFO] Copying 'glibc-2.36.tar' to '/tmp/tmp.vNBWYg1Vol/' for benchmark...
|
||||
[INFO] Installing required utilities
|
||||
[INFO] Testing compression for 'zlib'
|
||||
|
||||
Level | Time (compress) | Compression Ratio | Time (decompress)
|
||||
-------+-----------------+-------------------+-------------------
|
||||
1 | 0.322 s | 18.324 % | 0.659 s
|
||||
2 | 0.342 s | 17.738 % | 0.635 s
|
||||
3 | 0.473 s | 17.181 % | 0.647 s
|
||||
4 | 0.505 s | 16.101 % | 0.607 s
|
||||
5 | 0.640 s | 15.270 % | 0.590 s
|
||||
6 | 0.958 s | 14.858 % | 0.577 s
|
||||
7 | 1.198 s | 14.716 % | 0.561 s
|
||||
8 | 2.577 s | 14.619 % | 0.571 s
|
||||
9 | 3.114 s | 14.605 % | 0.570 s
|
||||
|
||||
[INFO] Testing compression for 'zstd'
|
||||
|
||||
Level | Time (compress) | Compression Ratio | Time (decompress)
|
||||
-------+-----------------+-------------------+-------------------
|
||||
1 | 0.492 s | 14.831 % | 0.313 s
|
||||
2 | 0.607 s | 14.008 % | 0.341 s
|
||||
3 | 0.709 s | 13.195 % | 0.318 s
|
||||
4 | 0.683 s | 13.108 % | 0.306 s
|
||||
5 | 1.300 s | 11.825 % | 0.292 s
|
||||
6 | 1.824 s | 11.298 % | 0.286 s
|
||||
7 | 2.215 s | 11.052 % | 0.284 s
|
||||
8 | 2.834 s | 10.619 % | 0.294 s
|
||||
9 | 3.079 s | 10.408 % | 0.272 s
|
||||
10 | 4.355 s | 10.254 % | 0.282 s
|
||||
11 | 6.161 s | 10.167 % | 0.283 s
|
||||
12 | 6.670 s | 10.165 % | 0.304 s
|
||||
13 | 12.471 s | 10.183 % | 0.279 s
|
||||
14 | 15.619 s | 10.075 % | 0.267 s
|
||||
15 | 21.387 s | 9.989 % | 0.270 s
|
||||
|
||||
[INFO] Testing compression for 'lzo'
|
||||
|
||||
Level | Time (compress) | Compression Ratio | Time (decompress)
|
||||
-------+-----------------+-------------------+-------------------
|
||||
1 | 0.447 s | 25.677 % | 0.438 s
|
||||
2 | 0.448 s | 25.582 % | 0.438 s
|
||||
3 | 0.444 s | 25.582 % | 0.441 s
|
||||
4 | 0.444 s | 25.582 % | 0.444 s
|
||||
5 | 0.445 s | 25.582 % | 0.453 s
|
||||
6 | 0.438 s | 25.582 % | 0.444 s
|
||||
7 | 8.990 s | 18.666 % | 0.410 s
|
||||
8 | 34.233 s | 18.463 % | 0.405 s
|
||||
9 | 41.328 s | 18.450 % | 0.426 s
|
||||
|
||||
[INFO] Cleaning up...
|
||||
[ OK ] Benchmark complete!
|
||||
```
|
||||
|
||||
重要的是在根据脚本得出的数据做决定之前注意这些事情:
|
||||
|
||||
* 不是所有的文件压缩效果都一样好。像图片或电影这种已经压缩过的现代多媒体格式不会压缩得更小。
|
||||
* 脚本中压缩和解压缩各进行一次。重复运行会产生稍微不同的输出。因此,时间应该被理解为是估计,而不是准确的测量。
|
||||
|
||||
鉴于输出的数据,我决定在我的系统上使用压缩级别 3 的 zstd 压缩算法。依据你的需求,你可能想使用更高的压缩级别(比如,如果你存储设备相当的慢)。要估算可达到的读/写速度,可以将源存档大小(约 260MB)除以(解)压缩时间。
|
||||
|
||||
压缩测试默认是对 GNU libc 2.36 源码进行的。如果你想看看对指定文件的效果,你可以通过第一个参数传递文件路径给脚本。记住文件一定要可以在容器内访问才行。
|
||||
|
||||
如果你想要测试其他东西或者执行更加详细的测试,可以阅读脚本的源码,根据需要修改它。
|
||||
|
||||
### 配置 Btrfs 压缩
|
||||
|
||||
Btrfs 里的透明文件系统压缩可以通过几种方式配置:
|
||||
|
||||
* 作为挂载文件系统的挂载选项(可用于相同 Btrfs 文件系统的所有子卷)
|
||||
* 通过 Btrfs 文件属性
|
||||
* 在 `btrfs filesystem defrag` 时(不是永久的,不在这里介绍)
|
||||
* 通过 `chattr` 文件属性接口(不在这里介绍)
|
||||
|
||||
我只会介绍其中前两个。
|
||||
|
||||
#### 在挂载时开启压缩
|
||||
|
||||
有一个 Btrfs 挂载选项可以开启文件压缩:
|
||||
|
||||
```
|
||||
$ sudo mount -o compress=<ALGORITHM>:<LEVEL> ...
|
||||
```
|
||||
|
||||
例如,去挂载一个文件系统,并使用等级 3 的 `ztsd` 算法去压缩,你可以写成:
|
||||
|
||||
```
|
||||
$ sudo mount -o compress=zstd:3 ...
|
||||
```
|
||||
|
||||
设置压缩等级是可选的。重要的是注意到 `compress` 挂载选项应用到整个 Btrfs 文件系统和它所有的子卷。此外,这是目前唯一支持的指定压缩等级的方式。
|
||||
|
||||
为了对文件系统的根应用压缩,必须在 `/etc/fstab` 上指定。例如,Fedora Linux 安装器,默认启用级别 1 的 `zstd` 压缩,在 `/etc/fstab` 里是这样:
|
||||
|
||||
```
|
||||
$ cat /etc/fstab
|
||||
[ ... ]
|
||||
UUID=47b03671-39f1-43a7-b0a7-db733bfb47ff / btrfs subvol=root,compress=zstd:1,[ ... ] 0 0
|
||||
```
|
||||
|
||||
#### 启用单个文件压缩
|
||||
|
||||
另外一种方式指定压缩的方法是通过 Btrfs 文件系统属性。使用下面的命令去查看文件、目录或子卷的压缩设置:
|
||||
|
||||
```
|
||||
$ btrfs property get <PATH> compression
|
||||
```
|
||||
|
||||
类似的,你可以像这样配置压缩:
|
||||
|
||||
```
|
||||
$ sudo btrfs property set <PATH> compression <VALUE>
|
||||
```
|
||||
|
||||
例如,对在 `/etc` 下所有文件启用 `zlib` 压缩:
|
||||
|
||||
```
|
||||
$ sudo btrfs property set /etc compression zlib
|
||||
```
|
||||
|
||||
你可以通过 `man btrfs-property` 得到支持值的列表。记住这个接口不允许指定压缩级别。除此之外,如果设置了一个压缩属性,它会覆盖挂载时的其他压缩配置。
|
||||
|
||||
### 压缩已有文件
|
||||
|
||||
在这时,如果你对现有文件系统采用压缩,然后通过 `df` 或类似命令检查空间利用率,你会发现什么都没变。这是因为 Btrfs 自身不会 “重新压缩” 所有已有的文件。压缩只会发生在往磁盘写新数据的时候。有一些方式去执行显式的重压缩:
|
||||
|
||||
1. 等待,什么都不做:只要文件被修改并被写回磁盘,Btrfs 根据配置压缩新写入的文件内容。如果我们等待足够长,越来越多的文件被重写,在某个时间点就会被压缩。
|
||||
2. 移动文件到另一个文件系统然后移动回来:取决于你想压缩哪些文件,这可能是相当乏味的选项。
|
||||
3. 执行一次 Btrfs 碎片整理。
|
||||
|
||||
最后一个选项可能是最方便的,但是它会对已经包含快照的 Btrfs 文件系统提出警告:它会破坏快照间的共享范围。换句话来说,两个快照间所有的共享内容,或者一个快照和它的父子卷,在碎片整理操作后将保存多份。
|
||||
|
||||
因此,如果你在你的文件系统里已经有很多快照,你不应该对整个文件系统运行碎片整理。这也没有必要,因为如果你想的话,Btrfs 可以对特定的目录或者单个文件进行碎片整理。
|
||||
|
||||
你可以使用以下命令去执行一次碎片整理:
|
||||
|
||||
```
|
||||
$ sudo btrfs filesystem defragment -r /path/to/defragment
|
||||
```
|
||||
|
||||
例如,你想像这样去整理你主目录的碎片:
|
||||
|
||||
```
|
||||
$ sudo btrfs filesystem defragment -r "$HOME"
|
||||
```
|
||||
|
||||
如果有疑问,最好从碎片整理单个大文件开始,并在监视文件系统上的可用空间的同时继续处理越来越大的目录。
|
||||
|
||||
### 测量文件系统压缩
|
||||
|
||||
有时,你可能会想,文件系统压缩为你节省了多少空间。但如何判断呢?首先,要知道一个 Btrfs 文件系统是否在挂载时启用了压缩,你可以使用以下命令:
|
||||
|
||||
```
|
||||
$ findmnt -vno OPTIONS /path/to/mountpoint | grep compress
|
||||
```
|
||||
|
||||
如果你得到了结果,那么给定挂载点的文件系统就使用了压缩!下一步,`compsize` 命令会告诉你你的文件需要多少空间:
|
||||
|
||||
```
|
||||
$ sudo compsize -x /path/to/examine
|
||||
```
|
||||
|
||||
在我的主目录,结果是这样:
|
||||
|
||||
```
|
||||
$ sudo compsize -x "$HOME"
|
||||
Processed 942853 files, 550658 regular extents (799985 refs), 462779 inline.
|
||||
Type Perc Disk Usage Uncompressed Referenced
|
||||
TOTAL 81% 74G 91G 111G
|
||||
none 100% 67G 67G 77G
|
||||
zstd 28% 6.6G 23G 33G
|
||||
```
|
||||
|
||||
每一行告诉你应用到文件的压缩 “类型” 。* `TOTAL` 是下面所有行的总计。
|
||||
|
||||
另一方面,这些列告诉你我们的文件需要多少空间:
|
||||
|
||||
* `Disk Usage` 是实际分配在硬盘上的空间,
|
||||
* `Uncompressed` 是如果没有压缩,文件所需要的空间,
|
||||
* `Referenced` 是所有未压缩文件加起来的总大小。
|
||||
|
||||
`Referenced` 可以与数据 `Uncompressed` 不同,比如一个文件之前被重复了,或者有快照共享内容。在上面的例子,你可以看到在我的硬盘上总计 91 GB 的未压缩文件仅占据了 74 GB 的存储。取决于在目录里存储的文件类型和应用的压缩等级,这些数字可以有很大差异。
|
||||
|
||||
### 文件压缩的其它注意事项
|
||||
|
||||
Btrfs 使用启发式算法去探测压缩文件。这是因为压缩文件通常效果不好,所以没有必要浪费 CPU 周期去尝试进一步的压缩。为了这个目的,Btrfs 在写入压缩数据到磁盘之前测量压缩率。如果文件的第一部分压缩效果不好,文件被标记为不可压缩并且不会有后续的压缩。
|
||||
|
||||
如果出于某些原因,你想 Btrfs 压缩所有写入的数据,你可以通过 `compress-force` 选项挂载一个 Btrfs 文件系统,像这样:
|
||||
|
||||
```
|
||||
$ sudo mount -o compress-force=zstd:3 ...
|
||||
```
|
||||
|
||||
当像这样配置,Btrfs 会用等级 3 的 `zstd` 算法压缩所有写入磁盘的数据。
|
||||
|
||||
一个重要的注意事项是挂载一个有很多数据并开启压缩的 Btrfs 文件系统会比没开启压缩耗时更长。这是有技术上的原因的,而且这是一个不会影响文件系统操作的正常行为。
|
||||
|
||||
### 总结
|
||||
|
||||
本文详细介绍了 Btrfs 中的透明文件系统压缩。这是一种内置的、相对廉价的方法,可以在不需要修改的情况下从现有硬件中获得一些额外的存储空间。
|
||||
|
||||
本系列文章的下一篇将讨论:
|
||||
|
||||
- Qgroups - 限制文件系统大小
|
||||
- RAID - 替换 mdadm 配置
|
||||
|
||||
(LCTT 译注:后继文章尚未发布,一旦发布我们会尽快翻译。)
|
||||
|
||||
如果你想了解与 Btrfs 相关的其他主题,请查看 Btrfs 维基 [^1] 和文档 [^2]。如果你还没有阅读本系列的前三篇文章,请不要忘记去看看!如果你觉得本文缺少某些内容,请在下面的评论中让我知道。我们下篇文章见!
|
||||
|
||||
### 参考资料
|
||||
|
||||
[^1]: <https://btrfs.wiki.kernel.org/index.php/Main_Page>
|
||||
[^2]: <https://btrfs.readthedocs.io/en/latest/Introduction.html>
|
||||
|
||||
*(题图:MJ/1a45064c-8da5-4b60-87f2-9886d6a3299e)*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/working-with-btrfs-compression/
|
||||
|
||||
作者:[Andreas Hartmann][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[A2ureStone](https://github.com/A2ureStone)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/hartan/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linux.cn/article-16287-1.html
|
||||
[2]: https://unsplash.com/@helibertoarias?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/hdd?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: tmp.AcVqx2gIro#sources
|
||||
[0]: https://img.linux.net.cn/data/attachment/album/202310/19/153401dyst48ybibpy3oyd.jpg
|
187
published/20231010 How to Add Comments in Bash Scripts.md
Normal file
187
published/20231010 How to Add Comments in Bash Scripts.md
Normal file
@ -0,0 +1,187 @@
|
||||
[#]: subject: "How to Add Comments in Bash Scripts"
|
||||
[#]: via: "https://itsfoss.com/bash-comments/"
|
||||
[#]: author: "Sagar Sharma https://itsfoss.com/author/sagar/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-16298-1.html"
|
||||
|
||||
如何在 Bash 脚本中添加注释
|
||||
======
|
||||
|
||||
![][0]
|
||||
|
||||
> 你有要说明的地方吗?请将它们添加到你的 Bash 脚本中。
|
||||
|
||||
在 Bash 脚本中添加注释是保持代码整洁且易于理解的最有效方法之一。
|
||||
|
||||
你可能会问为什么。
|
||||
|
||||
假设你的脚本包含一个复杂的正则表达式或多个复杂的代码块,在这种情况下,你可以添加注释,以便其他开发人员或你可以了解该代码块的含义。
|
||||
|
||||
注释掉部分代码也有助于调试脚本。
|
||||
|
||||
在本教程中,我将引导你了解在 Bash 脚本中添加注释的三种方法:
|
||||
|
||||
* 单行注释
|
||||
* 行内评论
|
||||
* 多行注释
|
||||
|
||||
那么让我们从第一个开始。
|
||||
|
||||
### Bash 中的单行注释
|
||||
|
||||
要添加单行注释,你必须将哈希符号(`#`)放在行的开头并编写注释。
|
||||
|
||||
这是一个简单的例子:
|
||||
|
||||
````
|
||||
#!/bin/bash
|
||||
# This is a comment
|
||||
echo "Hello, World!"
|
||||
````
|
||||
|
||||
执行时,注释将被忽略,当我执行上面的命令时,它看起来像这样:
|
||||
|
||||
![][1]
|
||||
|
||||
> 💡 `#` 注释规则的唯一例外是脚本开头的 `#!/bin/bash` 行。它称为 [释伴][2],用于指定运行脚本时要使用的解释器。有不同的 Shell,语法也可能不同。因此,一个好的做法是指定脚本是为哪个 Shell 编写的。例如,如果是 ksh,则可以使用 `#!/bin/ksh`.
|
||||
|
||||
### Bash 脚本中的内联注释
|
||||
|
||||
或者,你可以将注释放在代码块内以记录该特定行的用途。
|
||||
|
||||
> 🚧 `#` 之后的任何内容在该行结束之前都不会执行,因此请确保在代码末尾添加注释。
|
||||
|
||||
这是一个简单的例子:
|
||||
|
||||
````
|
||||
#!/bin/bash
|
||||
echo "Hello, World!" #Prints hello world
|
||||
````
|
||||
|
||||
![][3]
|
||||
|
||||
### Bash 中的多行注释
|
||||
|
||||
> 🚧 Bash 中没有内置的多行注释功能。但是,有一些解决方法可以实现多行注释效果。
|
||||
|
||||
顾名思义,Bash 脚本中的多行注释允许你在多行中编写注释,或者通过将它们放在多行注释部分来阻止执行代码块:
|
||||
|
||||
1. 在每行的开头使用 `#`
|
||||
2. [冒号表示法][4](使用冒号后跟单引号)
|
||||
3. 现场文档(使用 `<<` 后跟分隔符)
|
||||
|
||||
那么让我们从第一个开始。
|
||||
|
||||
#### 1、对块注释的每一行使用 `#`
|
||||
|
||||
如果你的目的是解释脚本的一部分,我建议使用此方法。毕竟,`#` 才是真正的注释功能。
|
||||
|
||||
这也是许多开发人员使用的方法。
|
||||
|
||||
假设你必须在一开始就解释脚本的用途、作者信息或许可信息。你可以这样写:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
######################################
|
||||
## This script is used for scanning ##
|
||||
## local network ##
|
||||
## Licensed under GPL 2.0 ##
|
||||
######################################
|
||||
|
||||
这个 Bash 脚本的其它部分……
|
||||
|
||||
```
|
||||
|
||||
当你想说明 Bash 脚本的行为方式时这不错。如果你正在调试 Bash 脚本并希望隐藏部分脚本,则在所需代码的每一行开头添加 `#` 并在调试后将其删除是一项耗时的任务。
|
||||
|
||||
接下来的两节将帮助你做到这一点。
|
||||
|
||||
#### 2、冒号表示法
|
||||
|
||||
要使用冒号表示法,请在 `: '` 和结束的 `'` 之间编写块注释,如下所示:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
: '
|
||||
This is how you can use colon notation
|
||||
And this line too will be ignored
|
||||
'
|
||||
echo "GOODBYE"
|
||||
|
||||
```
|
||||
|
||||
当你执行上面的脚本时,它应该只打印 `GOODBYE`。
|
||||
|
||||
![][5]
|
||||
|
||||
#### 3、现场文档
|
||||
|
||||
到目前为止,这是在 Bash 中编写多行注释的最流行的方法,你可以使用 `<<` 后跟分隔符(一组用于指定注释开始和结束的字符)。
|
||||
|
||||
(LCTT 译注:在编程领域,“**here document**” 是一个常见的术语,特指在脚本语言(如 Perl、Bash)中,能够直接在代码内部嵌入并处理一个数据块或文本串的技术。尽管传统上我们将它翻译为“嵌入式文档” 或不翻译,但这个译法似乎并不能完全地体现出原文的感觉和含义。为了让这个概念变得更为直观和易理解,我们建议将 “here document” 翻译为 “**现场文档**”。“现场”相比于“嵌入式”,更好的传达了文档就在代码的当前位置,或代码“现场”的含义。这样的译法也与原文 “here document” 中 “here”(这里)的含义更为契合。我们希望这个译法能够在未来得到更广泛的使用和认可,让编程的世界因语言的精准而变得更美好。PS., 该译法和解释得到了 ChatGPT 的建议和生成。)
|
||||
|
||||
使用方法如下:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
<<DELIMITER
|
||||
Comment line 1
|
||||
Comment line 2
|
||||
DELIMITER
|
||||
|
||||
echo "Hello, World!"
|
||||
```
|
||||
|
||||
还困惑吗? 这是一个简单的例子:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
<<COMMENT
|
||||
This is a multi-line comment using a here document.
|
||||
You can add as many lines as you want between <<COMMENT and the terminating keyword.
|
||||
This block won't be executed by the shell.
|
||||
COMMENT
|
||||
|
||||
echo "Hello, World!"
|
||||
```
|
||||
|
||||
在上面的示例中,我使用了 `COMMENT` 作为分隔符,但你可以使用任何内容,但要确保它从注释中脱颖而出,否则会造成混乱。
|
||||
|
||||
当我执行上面的脚本时,它给出了以下输出:
|
||||
|
||||
![][6]
|
||||
|
||||
正如你所看到的,它忽略了从 `<<COMMENT` 到 `COMMENT` 的所有内容。
|
||||
|
||||
我希望本指南对你有所帮助。
|
||||
|
||||
*(题图:MJ/7c2a3ef4-5256-405e-b757-23e0ba1f0bc5)*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/bash-comments/
|
||||
|
||||
作者:[Sagar Sharma][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/sagar/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/content/images/2023/10/Use-single-line-comments-in-bash.png
|
||||
[2]: https://linux.cn/article-3664-1.html
|
||||
[3]: https://itsfoss.com/content/images/2023/10/How-to-use-the-single-line-comments-in-bash.png
|
||||
[4]: https://stackoverflow.com/questions/3224878/what-is-the-purpose-of-the-colon-gnu-bash-builtin
|
||||
[5]: https://itsfoss.com/content/images/2023/10/Use-multi-line-comments-using-colon-notation-in-bash.png
|
||||
[6]: https://itsfoss.com/content/images/2023/10/Use-multi-line-comments-in-bash-using----and-delimeter.png
|
||||
[7]: https://itsfoss.com/content/images/size/w256h256/2022/12/android-chrome-192x192.png
|
||||
[0]: https://img.linux.net.cn/data/attachment/album/202310/19/113658dld7b9987xa89l99.jpg
|
@ -0,0 +1,110 @@
|
||||
[#]: subject: "Ubuntu MATE 23.10 Released: A Modest Upgrade"
|
||||
[#]: via: "https://news.itsfoss.com/ubuntu-mate-23-10/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-16300-1.html"
|
||||
|
||||
Ubuntu MATE 23.10发布: 一个适度的升级
|
||||
======
|
||||
|
||||
![][0]
|
||||
|
||||
> Ubuntu MATE 23.10 发布了!
|
||||
|
||||
在所有的 Ubuntu 版本中,Ubuntu MATE 的升级总是非常有趣的。
|
||||
|
||||
不过,最近发布的 Ubuntu MATE 决定坚持小幅改动,并进行预期的软件包升级和修复。你可能知道为什么!
|
||||
|
||||
**对于不了解的读者**:这是为了开发我们去年报道过的 [计划中的 Debian MATE 定制版][1]。
|
||||
|
||||
说到这里,让我重点介绍一下这些变化。
|
||||
|
||||
> 💡 Ubuntu MATE 23.10 将支持**九个月,直至 2024 年 7 月**。
|
||||
|
||||
### Ubuntu MATE 23.10:有什么新功能?
|
||||
|
||||
![][2]
|
||||
|
||||
Ubuntu MATE 23.10 受益于 [Ubuntu 23.10][3] 推出的所有好东西。
|
||||
|
||||
此外,这里还有一些改进:
|
||||
|
||||
* MATE 桌面更新至 v1.26.2。
|
||||
* 添加更多人工智能生成的壁纸。
|
||||
* 应用更新。
|
||||
|
||||
#### MATE 桌面升级
|
||||
|
||||
在最新的 MATE 桌面 1.26.2 中,你将获得大量错误修复和一些小的改进。
|
||||
|
||||
升级包括以下内容:
|
||||
|
||||
* 更新 MATE 用户指南 v1.26.2-1
|
||||
* 改进门户支持
|
||||
* 改进系统监视器,以便从 `/usr/libexec` 获取 `libexec` 文件
|
||||
* 修正 MATE 会话管理器,使其更好地与系统监视器配合使用
|
||||
* mate-utils 1.26.1-1 修复了内存泄漏问题
|
||||
|
||||
#### 额外的人工智能生成的壁纸
|
||||
|
||||
![][5]
|
||||
|
||||
虽然你已经可以从 [Ubuntu 23.10 更新合集][6] 中下载一些有趣的壁纸,但在这里你还能获得额外的壁纸(如上面的截图所示)。
|
||||
|
||||
Simon Butcher 是使用前沿的 Diffusion 模型制作这款壁纸的人,他提到:
|
||||
|
||||
> 由于牛头人是一种想象中的生物,因此对其的解释往往千差万别。我想制作一个具有漫画小说风格的强大生物图像,尽管不像许多描述那样令人毛骨悚然。
|
||||
>
|
||||
> 最新开源的 Stable Diffusion XL 基本模型在更高分辨率下进行了训练,质量上的差异非常明显,尤其是在整体一致性和细节方面,同时减少了图像中的解剖不规则性。图像是使用 Linux 和英伟达 A100 80GB GPU 在本地制作的,从最初的文本提示开始,使用 img2img、修复和放大功能进行完善。
|
||||
|
||||
#### Linux 内核 6.5
|
||||
|
||||
当然,[Linux 内核 6.5][7] 还能为硬件带来更好的兼容性、新代组件和其他改进。
|
||||
|
||||
![][8]
|
||||
|
||||
#### 其他改进
|
||||
|
||||
主要的应用程序升级包括 [Firefox 118][9]、Celluloid 0.25、Evolution 3.50 和 LibreOffice 7.6.1。
|
||||
|
||||
所有这些都将改善用户体验。
|
||||
|
||||
### 📥 获取 Ubuntu MATE 23.10
|
||||
|
||||
你可以从 [官方网站][10] 或 [Ubuntu 仓库][11] 下载 Ubuntu MATE 23.10 ISO。
|
||||
|
||||
> **[Ubuntu MATE 23.10][12]**
|
||||
|
||||
如果你是现有用户并希望升级,请按照 [发布说明][13] 中的官方说明进行操作。
|
||||
|
||||
*(题图:[Ubuntu Mate](https://ubuntu-mate.org/blog/ubuntu-mate-mantic-minotaur-release-notes/))*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/ubuntu-mate-23-10/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://linux.cn/article-15119-1.html
|
||||
[2]: https://news.itsfoss.com/content/images/2023/10/ubuntu-mate-23-10.jpg
|
||||
[3]: https://news.itsfoss.com/ubuntu-23-10/
|
||||
[5]: https://news.itsfoss.com/content/images/2023/10/ubuntu-mate-23-10-new-wall.jpg
|
||||
[6]: https://ubuntu.com/blog/into-the-labyrinth
|
||||
[7]: https://news.itsfoss.com/linux-kernel-6-5-release/
|
||||
[8]: https://news.itsfoss.com/content/images/2023/10/ubuntu-mate-23-10-neofetch.jpg
|
||||
[9]: https://news.itsfoss.com/firefox-118-release/
|
||||
[10]: https://ubuntu-mate.org/download/
|
||||
[11]: https://cdimage.ubuntu.com/ubuntu-mate/releases/23.10/
|
||||
[12]: https://cdimage.ubuntu.com/ubuntu-mate/releases/23.10/release/
|
||||
[13]: https://ubuntu-mate.org/blog/ubuntu-mate-lunar-lobster-release-notes/
|
||||
[0]: https://img.linux.net.cn/data/attachment/album/202310/19/160226cp45xfznfzw2xjj0.jpg
|
@ -1,122 +0,0 @@
|
||||
[#]: subject: "Ubuntu MATE 23.10 Released: A Modest Upgrade"
|
||||
[#]: via: "https://news.itsfoss.com/ubuntu-mate-23-10/"
|
||||
[#]: author: "Ankush Das https://news.itsfoss.com/author/ankush/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Ubuntu MATE 23.10 Released: A Modest Upgrade
|
||||
======
|
||||
Ubuntu MATE 23.10 release has arrived!
|
||||
Among all the Ubuntu flavours, the Ubuntu MATE upgrade is always an interesting one.
|
||||
|
||||
However, recent Ubuntu MATE releases have decided to stick to minor changes, with the expected package upgrades and fixes. And, you probably know why!
|
||||
|
||||
**For readers unaware** : it is because of the [planned Debian's MATE spin][1] that we covered last year.
|
||||
|
||||
With that being said, let me highlight the changes.
|
||||
|
||||
💡
|
||||
|
||||
Ubuntu MATE 23.10 will be supported for **nine** months until **July 2024**.
|
||||
|
||||
### Ubuntu MATE 23.10: What's New?
|
||||
|
||||
![][2]
|
||||
|
||||
Ubuntu MATE 23.10 benefits from all the goodies introduced with [Ubuntu 23.10][3].
|
||||
|
||||
Moreover, here are a couple of refinements:
|
||||
|
||||
* **MATE Desktop updated to v1.26.2**
|
||||
* **More AI-generated wallpapers added**
|
||||
* **Application updates**
|
||||
|
||||
|
||||
|
||||
**Suggested Read** 📖
|
||||
|
||||
![][4]
|
||||
|
||||
#### MATE Desktop Upgrades
|
||||
|
||||
With the latest MATE Desktop 1.26.2, you get a slew of bug fixes and some minor improvements.
|
||||
|
||||
The upgrades involve the following:
|
||||
|
||||
* Updated MATE user guide v1.26.2-1
|
||||
* Improved portals support
|
||||
* Improvement to the system monitor to pick up libexec files from /usr/libexec
|
||||
* Fixes to the MATE session manager to work with system monitor better
|
||||
* mate-utils 1.26.1-1 fixes memory leaks
|
||||
|
||||
|
||||
|
||||
#### Another AI-generated Wallpaper
|
||||
|
||||
![][5]
|
||||
|
||||
While you can already download some interesting wallpapers from the [Ubuntu 23.10 updated collection][6], you get an extra here (as shown in the screenshot above).
|
||||
|
||||
Simon Butcher, the one who created this using bleeding-edge diffusion models, mentions:
|
||||
|
||||
> Since Minotaurs are imaginary creatures, interpretations tend to vary widely. I wanted to produce an image of a powerful creature in a graphic novel style, although not gruesome like many depictions.
|
||||
>
|
||||
> The latest open source Stable Diffusion XL base model was trained at a higher resolution and the difference in quality has been noticeable, particularly at better overall consistency and detail, while reducing anatomical irregularities in images. The image was produced locally using Linux and an NVIDIA A100 80GB GPU, starting from an initial text prompt and refined using img2img, inpainting and upscaling features.
|
||||
|
||||
#### Linux Kernel 6.5
|
||||
|
||||
Of course, with [Linux Kernel 6.5][7], you can expect better hardware compatibility with new gen components and other improvements.
|
||||
|
||||
![][8]
|
||||
|
||||
![][4]
|
||||
|
||||
#### Other Improvements
|
||||
|
||||
The major app upgrades include [Firefox 118][9], Celluloid 0.25, Evolution 3.50, and LibreOffice 7.6.1.
|
||||
|
||||
All of this should improve the user experience.
|
||||
|
||||
### 📥 Getting Ubuntu MATE 23.10
|
||||
|
||||
📋
|
||||
|
||||
The download may take some time to be available after the release announcement.
|
||||
|
||||
You can download Ubuntu MATE 23.10 ISO from the [official website][10] or [Ubuntu's repository][11].
|
||||
|
||||
[Ubuntu MATE 23.10][12]
|
||||
|
||||
If you are an existing user and want to upgrade, follow the official instructions in the [release notes][13].
|
||||
|
||||
* * *
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/ubuntu-mate-23-10/
|
||||
|
||||
作者:[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://news.itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://news.itsfoss.com/ubuntu-mate-debian/
|
||||
[2]: https://news.itsfoss.com/content/images/2023/10/ubuntu-mate-23-10.jpg
|
||||
[3]: https://news.itsfoss.com/ubuntu-23-10/
|
||||
[4]: https://news.itsfoss.com/content/images/size/w256h256/2022/08/android-chrome-192x192.png
|
||||
[5]: https://news.itsfoss.com/content/images/2023/10/ubuntu-mate-23-10-new-wall.jpg
|
||||
[6]: https://ubuntu.com/blog/into-the-labyrinth
|
||||
[7]: https://news.itsfoss.com/linux-kernel-6-5-release/
|
||||
[8]: https://news.itsfoss.com/content/images/2023/10/ubuntu-mate-23-10-neofetch.jpg
|
||||
[9]: https://news.itsfoss.com/firefox-118-release/
|
||||
[10]: https://ubuntu-mate.org/download/
|
||||
[11]: https://cdimage.ubuntu.com/ubuntu-mate/releases/23.10/
|
||||
[12]: https://cdimage.ubuntu.com/ubuntu-mate/releases/23.10/release/
|
||||
[13]: https://ubuntu-mate.org/blog/ubuntu-mate-lunar-lobster-release-notes/
|
@ -2,7 +2,7 @@
|
||||
[#]: via: "https://news.itsfoss.com/tor-browser-13-0-release/"
|
||||
[#]: author: "Sourav Rudra https://news.itsfoss.com/author/sourav/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: " "
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
@ -0,0 +1,101 @@
|
||||
[#]: subject: "An Interesting Bluetooth App for Linux Just Appeared!"
|
||||
[#]: via: "https://news.itsfoss.com/bluetooth-app-linux-overskride/"
|
||||
[#]: author: "Sourav Rudra https://news.itsfoss.com/author/sourav/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
An Interesting Bluetooth App for Linux Just Appeared!
|
||||
======
|
||||
All things Bluetooth with this brand new app!
|
||||
A new app for Linux has shown up that could be a one-stop app for all your Bluetooth needs.
|
||||
|
||||
Called ' **Overskride** ', it is **an open-source app** making an appearance with its first release. Even though it is in a work-in-progress state, it offers some decent functionality.
|
||||
|
||||
Allow me to take you through it.
|
||||
|
||||
### Overskride: What to Expect?
|
||||
|
||||
![][1]
|
||||
|
||||
Overskride will appeal to the Rust-heads out there, as it is **primarily written in the Rust programming language** with **a GTK4/libadwaita flavor** to it.
|
||||
|
||||
According to the developer, it is meant to be **a straightforward Bluetooth and Obex client** _(planned for future)_ that works irrespective of the desktop environment or window manager being used.
|
||||
|
||||
![][2]
|
||||
|
||||
Some key features include:
|
||||
|
||||
* **Trust/Block devices.**
|
||||
* **Ability to send/receive files.**
|
||||
* **Set connection timeout periods.**
|
||||
* **Support for configuring the adapter.**
|
||||
|
||||
|
||||
|
||||
Looking at the screenshot above, you have got about every essential option to customize the Bluetooth device, and the connection, including the adapter name.
|
||||
|
||||
Of course, considering this is the first release of the app ever, one should not set high expectations. So, there would be room for improvements.
|
||||
|
||||
For now, here's **a little sneak peek of Overskride** to check what it offers.
|
||||
|
||||
I set it up using the provided Flatpak package on Ubuntu 22.04 LTS with GNOME 42.9. It didn't seem to have any issues with running on this setup.
|
||||
|
||||
Overskride was able to detect my smartphone, with various options to configure it.
|
||||
|
||||
![][3]
|
||||
|
||||
You can add the device to the trusted list or block list, rename it, and send a file as well.
|
||||
|
||||
I gave the **file transfer feature** a try, but before I could do that, I had to allow access to user files using [Flatseal][4] so that it could read the files on my system.
|
||||
|
||||
![][5]
|
||||
|
||||
The transfer began after I accepted the file transfer on my phone. The speeds were okay, and the file did get there in one piece, without any issues.
|
||||
|
||||
![][6]
|
||||
|
||||
I must say, for its first-ever release, the developer has presented us with a useful utility. I am excited to see what kind of improvements its future releases will offer.
|
||||
|
||||
The developer [was asked][7] by a Reddit user if there are any plans to **support for showing the battery percentage of wireless headphones.** In response to that, the dev mentioned that it is tricky to do so, as every device follows a different specification, which makes such a goal harder to achieve.
|
||||
|
||||
**Suggested Read** 📖
|
||||
|
||||
![][8]
|
||||
|
||||
### 📥 Get Overskride
|
||||
|
||||
For now, Overskride is only available via its [GitHub repo][9] as a Flatpak package. Or, you can compile it from source.
|
||||
|
||||
[Overskride (GitHub)][10]
|
||||
|
||||
I hope the developer publishes it on [Flathub][11] once it gets to a stable release to make it accessible for users.
|
||||
|
||||
* * *
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://news.itsfoss.com/bluetooth-app-linux-overskride/
|
||||
|
||||
作者:[Sourav Rudra][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://news.itsfoss.com/author/sourav/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://news.itsfoss.com/content/images/2023/10/Overskride_1.png
|
||||
[2]: https://news.itsfoss.com/content/images/2023/04/Follow-us-on-Google-News.png
|
||||
[3]: https://news.itsfoss.com/content/images/2023/10/Overskride_2.png
|
||||
[4]: https://itsfoss.com/flatseal/
|
||||
[5]: https://news.itsfoss.com/content/images/2023/10/Overskride_3.png
|
||||
[6]: https://news.itsfoss.com/content/images/2023/10/Overskride_4.png
|
||||
[7]: https://www.reddit.com/r/gnome/comments/17a5m99/full_release_of_my_bluetooth_app_d/k5b3ybg/
|
||||
[8]: https://news.itsfoss.com/content/images/size/w256h256/2022/08/android-chrome-192x192.png
|
||||
[9]: https://github.com/kaii-lb/overskride
|
||||
[10]: https://github.com/kaii-lb/overskride/releases/
|
||||
[11]: https://flathub.org/en
|
@ -2,7 +2,7 @@
|
||||
[#]: via: "https://opensource.com/article/23/2/what-open-license-means-gamers"
|
||||
[#]: author: "Seth Kenlon https://opensource.com/users/seth"
|
||||
[#]: collector: "lkxed"
|
||||
[#]: translator: " "
|
||||
[#]: translator: "wcjjdlhws"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
@ -1,548 +0,0 @@
|
||||
[#]: subject: "Making a DNS query in Ruby from scratch"
|
||||
[#]: via: "https://jvns.ca/blog/2022/11/06/making-a-dns-query-in-ruby-from-scratch/"
|
||||
[#]: author: "Julia Evans https://jvns.ca/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Making a DNS query in Ruby from scratch
|
||||
======
|
||||
|
||||
Hello! A while back I wrote a post about [how to write a toy DNS resolver in Go][1].
|
||||
|
||||
In that post I left out “how to generate and parse DNS queries” because I thought it was boring, but a few people pointed out that they did not know how to parse and generate DNS queries and they were interested in how to do it.
|
||||
|
||||
This made me curious – how much work _is_ it do the DNS parsing? It turns out we can do it in a pretty nice 120-line Ruby program, which is not that bad.
|
||||
|
||||
So here’s a quick post on how to generate DNS queries and parse DNS responses! We’re going to do it in Ruby because I’m giving a talk at a Ruby conference soon, and this blog post is partly prep for that talk :). I’ve tried to keep it readable for folks who don’t know Ruby though, I’ve only used pretty basic Ruby code.
|
||||
|
||||
At the end we’re going to have a very simple toy Ruby version of `dig` that can look up domain names like this:
|
||||
|
||||
```
|
||||
|
||||
$ ruby dig.rb example.com
|
||||
example.com 20314 A 93.184.216.34
|
||||
|
||||
```
|
||||
|
||||
The whole thing is about 120 lines of code, so it’s not _that_ much. (The final program is [dig.rb][2] if you want to skip the explanations and just read some code.) We won’t implement the “how a DNS resolver works” from the previous post because, well, we already did that. Let’s get into it!
|
||||
|
||||
Along the way I’m going to try to explain how you could figure out some of this stuff yourself if you were trying to figure out how DNS queries are formatted from scratch. Mostly that’s “poke around in Wireshark” and “read RFC 1035, the DNS RFC”.
|
||||
|
||||
### step 1: open a UDP socket
|
||||
|
||||
We need to actually _send_ our queries, so to do that we need to open a UDP socket. We’ll send our queries to `8.8.8.8`, Google’s DNS server.
|
||||
|
||||
Here’s the code to set up a UDP connection to `8.8.8.8`, port 53 (the DNS port).
|
||||
|
||||
```
|
||||
|
||||
require 'socket'
|
||||
sock = UDPSocket.new
|
||||
|
||||
sock.bind('0.0.0.0', 12345)
|
||||
sock.connect('8.8.8.8', 53)
|
||||
|
||||
```
|
||||
|
||||
##### a quick note on UDP
|
||||
|
||||
I’m not going to say too much about UDP here, but I will say that the basic unit of computer networking is the “packet” (a packet is a string of bytes), and in this program we’re going to do the simplest possible thing you can do with a computer network – send 1 packet and receive 1 packet in response.
|
||||
|
||||
So UDP is a way to send packets in the simplest possible way.
|
||||
|
||||
It’s the most common way to send DNS queries, though you can also use TCP or DNS-over-HTTPS instead.
|
||||
|
||||
##### step 2: copy a DNS query from Wireshark
|
||||
|
||||
Next: let’s say we have no idea how DNS works but we want to send a working query as fast as possible. The easiest way to get a DNS query to play with and make sure our UDP connection is working is to just copy one that already works!
|
||||
|
||||
So that’s what we’re going to do, using Wireshark (an incredible packet analysis tool)
|
||||
|
||||
The steps I used to this are roughly:
|
||||
|
||||
1. Open Wireshark and click ‘capture’
|
||||
2. Enter `udp.port == 53` as a filter (in the search bar)
|
||||
3. Run `ping example.com` in my terminal (to generate a DNS query)
|
||||
4. Click on the DNS query (“Standard query A example.com”)
|
||||
5. Right click on “Domain Name System (query”) in the bottom left pane
|
||||
6. Click ‘Copy’ -> ‘as a hex stream’
|
||||
7. Now I have “b96201000001000000000000076578616d706c6503636f6d0000010001” on my clipboard, to use in my Ruby program. Hooray!
|
||||
|
||||
|
||||
|
||||
##### step 3: decode the hex stream and send the DNS query
|
||||
|
||||
Now we can send our DNS query to `8.8.8.8`! Here’s what that looks like: we just need to add 5 lines of code
|
||||
|
||||
```
|
||||
|
||||
hex_string = "b96201000001000000000000076578616d706c6503636f6d0000010001"
|
||||
bytes = [hex_string].pack('H*')
|
||||
sock.send(bytes, 0)
|
||||
|
||||
# get the reply
|
||||
reply, _ = sock.recvfrom(1024)
|
||||
puts reply.unpack('H*')
|
||||
|
||||
```
|
||||
|
||||
`[hex_string].pack('H*')` is translating our hex string into a byte string. At this point we don’t really know what this data _means_ but we’ll get there in a second.
|
||||
|
||||
We can also take this opportunity to make sure our program is working and is sending valid data, using `tcpdump`. How I did that:
|
||||
|
||||
1. Run `sudo tcpdump -ni any port 53 and host 8.8.8.8` in a terminal tab
|
||||
2. In a different terminal tab, run [this Ruby program][3] (`ruby dns-1.rb`)
|
||||
|
||||
|
||||
|
||||
Here’s what the output looks like:
|
||||
|
||||
```
|
||||
|
||||
$ sudo tcpdump -ni any port 53 and host 8.8.8.8
|
||||
08:50:28.287440 IP 192.168.1.174.12345 > 8.8.8.8.53: 47458+ A? example.com. (29)
|
||||
08:50:28.312043 IP 8.8.8.8.53 > 192.168.1.174.12345: 47458 1/0/0 A 93.184.216.34 (45)
|
||||
|
||||
```
|
||||
|
||||
This is really good - we can see the DNS request (“what’s the IP for `example.com`”) and the response (“it’s 93.184.216.34”). So everything is working. Now we just need to, you know, figure out how to generate and decode this data ourselves.
|
||||
|
||||
##### step 4: learn a little about how DNS queries are formatted
|
||||
|
||||
Now that we have a DNS query for `example.com`, let’s learn about what it means.
|
||||
|
||||
Here’s our query, formatted as hex.
|
||||
|
||||
```
|
||||
|
||||
b96201000001000000000000076578616d706c6503636f6d0000010001
|
||||
|
||||
```
|
||||
|
||||
If you poke around in Wireshark, you’ll see that this query has 2 parts:
|
||||
|
||||
* The **header** (`b96201000001000000000000`)
|
||||
* The **question** (`076578616d706c6503636f6d0000010001`)
|
||||
|
||||
|
||||
|
||||
##### step 5: make the header
|
||||
|
||||
Our goal in this step is to generate the byte string `b96201000001000000000000`, but with a Ruby function instead of hardcoding it.
|
||||
|
||||
So: the header is 12 bytes. What do those 12 bytes mean? If you look at Wireshark (or read [RFC 1035][4]), you’ll see that it’s 6 2-byte numbers concatenated together.
|
||||
|
||||
The 6 numbers correspond to the query ID, the flags, and then the number of questions, answer records, authoritative records, and additional records in the packet.
|
||||
|
||||
We don’t need to worry about what all those things are yet though – we just need to put in 6 numbers.
|
||||
|
||||
And luckily we know exactly which 6 numbers to put because our goal is to literally generate the string `b96201000001000000000000`.
|
||||
|
||||
So here’s a function to make the header. (note: there’s no `return` because you don’t need to write `return` in Ruby if it’s the last line of the function)
|
||||
|
||||
```
|
||||
|
||||
def make_question_header(query_id)
|
||||
# id, flags, num questions, num answers, num auth, num additional
|
||||
[query_id, 0x0100, 0x0001, 0x0000, 0x0000, 0x0000].pack('nnnnnn')
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
This is very short because we’ve hardcoded everything except the query ID.
|
||||
|
||||
##### what’s `nnnnnn`?
|
||||
|
||||
You might be wondering what `nnnnnn` is in `.pack('nnnnnn')`. That’s a format string telling `.pack()` how to convert that array of 6 numbers into a byte string.
|
||||
|
||||
[The documentation for `.pack` is here][5], and it says that `n` means “represent it as “16-bit unsigned, network (big-endian) byte order”.
|
||||
|
||||
16 bits is the same as 2 bytes, and we need to use network byte order because this is computer networking. I’m not going to explain byte order right now (though I do have a [comic attempting to explain it][6])
|
||||
|
||||
##### test the header code
|
||||
|
||||
Let’s quickly test that our `make_question_header` function works.
|
||||
|
||||
```
|
||||
|
||||
puts make_question_header(0xb962) == ["b96201000001000000000000"].pack("H*")
|
||||
|
||||
```
|
||||
|
||||
This prints out “true”, so we win and we can move on.
|
||||
|
||||
##### step 5: encode the domain name
|
||||
|
||||
Next we need to generate the **question** (“what’s the IP for `example.com`?“). This has 3 parts:
|
||||
|
||||
* the **domain name** (for example “example.com”)
|
||||
* the **query type** (for example “A” is for “IPv4 **A**ddress”
|
||||
* the **query class** (which is always the same, 1 is for **IN** is for **IN**ternet)
|
||||
|
||||
|
||||
|
||||
The hardest part of this is the domain name so let’s write a function to do that.
|
||||
|
||||
`example.com` is encoded in a DNS query, in hex, as `076578616d706c6503636f6d00`. What does that mean?
|
||||
|
||||
Well, if we translate the bytes into ASCII, it looks like this:
|
||||
|
||||
```
|
||||
|
||||
076578616d706c6503636f6d00
|
||||
7 e x a m p l e 3 c o m 0
|
||||
|
||||
```
|
||||
|
||||
So each segment (like `example`) has its length (like 7) in front of it.
|
||||
|
||||
Here’s the Ruby code to translate `example.com` into `7 e x a m p l e 3 c o m 0`:
|
||||
|
||||
```
|
||||
|
||||
def encode_domain_name(domain)
|
||||
domain
|
||||
.split(".")
|
||||
.map { |x| x.length.chr + x }
|
||||
.join + "\0"
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
Other than that, to finish generating the question section we just need to append the type and class onto the end of the domain name.
|
||||
|
||||
##### step 6: write `make_dns_query`
|
||||
|
||||
Here’s the final function to make a DNS query:
|
||||
|
||||
```
|
||||
|
||||
def make_dns_query(domain, type)
|
||||
query_id = rand(65535)
|
||||
header = make_question_header(query_id)
|
||||
question = encode_domain_name(domain) + [type, 1].pack('nn')
|
||||
header + question
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
[Here’s all the code we’ve written before in `dns-2.rb`][7] – it’s still only 29 lines.
|
||||
|
||||
##### now for the parsing
|
||||
|
||||
Now that we’ve managed to _generate_ a DNS query, we get into the hard part: the parsing. Again, we’ll split this into a bunch of different
|
||||
|
||||
* parse a DNS header
|
||||
* parse a DNS name
|
||||
* parse a DNS record
|
||||
|
||||
|
||||
|
||||
The hardest part of this (maybe surprisingly) is going to be “parse a DNS name”.
|
||||
|
||||
##### step 7: parse the DNS header
|
||||
|
||||
Let’s start with the easiest part: the DNS header. We already talked about how it’s 6 numbers concatenated together.
|
||||
|
||||
So all we need to do is
|
||||
|
||||
* read the first 12 bytes
|
||||
* convert that into an array of 6 numbers
|
||||
* put those numbers in a class for convenience
|
||||
|
||||
|
||||
|
||||
Here’s the Ruby code to do that.
|
||||
|
||||
```
|
||||
|
||||
class DNSHeader
|
||||
attr_reader :id, :flags, :num_questions, :num_answers, :num_auth, :num_additional
|
||||
def initialize(buf)
|
||||
hdr = buf.read(12)
|
||||
@id, @flags, @num_questions, @num_answers, @num_auth, @num_additional = hdr.unpack('nnnnnn')
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
Quick Ruby note: `attr_reader` is a Ruby thing that means “make these instance variables accessible as methods”. So you can call `header.flags` to look at the `@flags` variable.
|
||||
|
||||
We can call this with `DNSHeader(buf)`. Not so bad.
|
||||
|
||||
Let’s move on to the hardest part: parsing a domain name.
|
||||
|
||||
##### step 8: parse a domain name
|
||||
|
||||
First, let’s write a partial version.
|
||||
|
||||
```
|
||||
|
||||
def read_domain_name_wrong(buf)
|
||||
domain = []
|
||||
loop do
|
||||
len = buf.read(1).unpack('C')[0]
|
||||
break if len == 0
|
||||
domain << buf.read(len)
|
||||
end
|
||||
domain.join('.')
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
This repeatedly reads 1 byte and then reads that length into a string until the length is 0.
|
||||
|
||||
This works great, for the first time we see a domain name (`example.com`) in our DNS response.
|
||||
|
||||
##### trouble with domain names: compression!
|
||||
|
||||
But the second time `example.com` appears, we run into trouble – in Wireshark, it says that the domain is represented cryptically as just the 2 bytes `c00c`.
|
||||
|
||||
This is something called **DNS compression** and if we want to parse any DNS responses we’re going to have to implement it.
|
||||
|
||||
This is luckily not **that** hard. All `c00c` is saying is:
|
||||
|
||||
* The first 2 bits (`0b11.....`) mean “DNS compression ahead!”
|
||||
* The remaining 14 bits are an integer. In this case that integer is `12` (`0x0c`), so that means “go back to the 12th byte in the packet and use the domain name you find there”
|
||||
|
||||
|
||||
|
||||
If you want to read more about DNS compression, I found the [explanation in the DNS RFC][8] relatively readable.
|
||||
|
||||
##### step 9: implement DNS compression
|
||||
|
||||
So we need a more complicated version of our `read_domain_name` function
|
||||
|
||||
Here it is.
|
||||
|
||||
```
|
||||
|
||||
domain = []
|
||||
loop do
|
||||
len = buf.read(1).unpack('C')[0]
|
||||
break if len == 0
|
||||
if len & 0b11000000 == 0b11000000
|
||||
# weird case: DNS compression!
|
||||
second_byte = buf.read(1).unpack('C')[0]
|
||||
offset = ((len & 0x3f) << 8) + second_byte
|
||||
old_pos = buf.pos
|
||||
buf.pos = offset
|
||||
domain << read_domain_name(buf)
|
||||
buf.pos = old_pos
|
||||
break
|
||||
else
|
||||
# normal case
|
||||
domain << buf.read(len)
|
||||
end
|
||||
end
|
||||
domain.join('.')
|
||||
|
||||
```
|
||||
|
||||
Basically what’s happening is:
|
||||
|
||||
* if the first 2 bits are `0b11`, we need to do DNS compression. Then:
|
||||
* read the second byte and do a little bit arithmetic to convert that into the offset
|
||||
* save the current position in the buffer
|
||||
* read the domain name at the offset we calculated
|
||||
* restore our position in the buffer
|
||||
|
||||
|
||||
|
||||
This is kind of messy but it’s the most complicated part of parsing the DNS response, so we’re almost done!
|
||||
|
||||
##### step 10: parse a DNS query
|
||||
|
||||
You might think “why do we need to parse a DNS query? This is the response!”. But every DNS response has the original query in it, so we need to parse it.
|
||||
|
||||
Here’s the code for parsing the DNS query.
|
||||
|
||||
```
|
||||
|
||||
class DNSQuery
|
||||
attr_reader :domain, :type, :cls
|
||||
def initialize(buf)
|
||||
@domain = read_domain_name(buf)
|
||||
@type, @cls = buf.read(4).unpack('nn')
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
There’s not very much to it: the type and class are 2 bytes each.
|
||||
|
||||
##### step 11: parse a DNS record
|
||||
|
||||
This is the exciting part – the DNS record is where our query data lives! The “rdata field” (“record data”) is where the IP address we’re going to get in response to our DNS query lives.
|
||||
|
||||
Here’s the code:
|
||||
|
||||
```
|
||||
|
||||
class DNSRecord
|
||||
attr_reader :name, :type, :class, :ttl, :rdlength, :rdata
|
||||
def initialize(buf)
|
||||
@name = read_domain_name(buf)
|
||||
@type, @class, @ttl, @rdlength = buf.read(10).unpack('nnNn')
|
||||
@rdata = buf.read(@rdlength)
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
We also need to do a little work to make the `rdata` field human readable. The meaning of the record data depends on the record type – for example for an “A” record it’s a 4-byte IP address, for but a “CNAME” record it’s a domain name.
|
||||
|
||||
So here’s some code to make the request data human readable:
|
||||
|
||||
```
|
||||
|
||||
def read_rdata(buf, length)
|
||||
@type_name = TYPES[@type] || @type
|
||||
if @type_name == "CNAME" or @type_name == "NS"
|
||||
read_domain_name(buf)
|
||||
elsif @type_name == "A"
|
||||
buf.read(length).unpack('C*').join('.')
|
||||
else
|
||||
buf.read(length)
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
This function uses this `TYPES` hash to map the record type to a human-readable name:
|
||||
|
||||
```
|
||||
|
||||
TYPES = {
|
||||
1 => "A",
|
||||
2 => "NS",
|
||||
5 => "CNAME",
|
||||
# there are a lot more but we don't need them for this example
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The most interesting part of `read_rdata` is probably the line `buf.read(length).unpack('C*').join('.')` – it’s saying “hey, an IP address is 4 bytes, so convert it into an array of 4 numbers and then join those with “.“s”.
|
||||
|
||||
##### step 12: finish parsing the DNS response
|
||||
|
||||
Now we’re ready to parse the DNS response!
|
||||
|
||||
Here’s some code to do that:
|
||||
|
||||
```
|
||||
|
||||
class DNSResponse
|
||||
attr_reader :header, :queries, :answers, :authorities, :additionals
|
||||
def initialize(bytes)
|
||||
buf = StringIO.new(bytes)
|
||||
@header = DNSHeader.new(buf)
|
||||
@queries = (1..@header.num_questions).map { DNSQuery.new(buf) }
|
||||
@answers = (1..@header.num_answers).map { DNSRecord.new(buf) }
|
||||
@authorities = (1..@header.num_auth).map { DNSRecord.new(buf) }
|
||||
@additionals = (1..@header.num_additional).map { DNSRecord.new(buf) }
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
This mostly just calls the other functions we’ve written to parse the DNS response.
|
||||
|
||||
It uses this cute `(1..@header.num_answers).map` construction to create an array of 2 DNS records if `@header.num_answers` is 2. (which is maybe a _little_ bit of Ruby magic but I think it’s kind of fun and hopefully isn’t too hard to read)
|
||||
|
||||
We can integrate this code into our main function like this:
|
||||
|
||||
```
|
||||
|
||||
sock.send(make_dns_query("example.com", 1), 0) # 1 is "A", for IP address
|
||||
reply, _ = sock.recvfrom(1024)
|
||||
response = DNSResponse.new(reply) # parse the response!!!
|
||||
puts response.answers[0]
|
||||
|
||||
```
|
||||
|
||||
Printing out the records looks awful though (it says something like `#<DNSRecord:0x00000001368e3118>`). So we need to write some pretty printing code to make it human readable.
|
||||
|
||||
##### step 13: pretty print our DNS records
|
||||
|
||||
We need to add a `.to_s` field to DNS records to make them have a nice string representation. This is just a 1-line method in `DNSRecord`:
|
||||
|
||||
```
|
||||
|
||||
def to_s
|
||||
"#{@name}\t\t#{@ttl}\t#{@type_name}\t#{@parsed_rdata}"
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
You also might notice that I left out the `class` field of the DNS record. That’s because it’s always the same (IN for “internet”) so I felt it was redundant. Most DNS tools (like real `dig`) will print out the class though.
|
||||
|
||||
##### and we’re done!
|
||||
|
||||
Here’s our final `main` function:
|
||||
|
||||
```
|
||||
|
||||
def main
|
||||
# connect to google dns
|
||||
sock = UDPSocket.new
|
||||
sock.bind('0.0.0.0', 12345)
|
||||
sock.connect('8.8.8.8', 53)
|
||||
|
||||
# send query
|
||||
domain = ARGV[0]
|
||||
sock.send(make_dns_query(domain, 1), 0)
|
||||
|
||||
# receive & parse response
|
||||
reply, _ = sock.recvfrom(1024)
|
||||
response = DNSResponse.new(reply)
|
||||
response.answers.each do |record|
|
||||
puts record
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
I don’t think there’s too much to say about this – we connect, send a query, print out each of the answers, and exit. Success!
|
||||
|
||||
```
|
||||
|
||||
$ ruby dig.rb example.com
|
||||
example.com 18608 A 93.184.216.34
|
||||
|
||||
```
|
||||
|
||||
You can see the final program as a gist here: [dig.rb][2]. You could add more features to it if you want, like
|
||||
|
||||
* pretty printing for other query types
|
||||
* options to print out the “authority” and “additional” sections of the DNS response
|
||||
* retries
|
||||
* making sure that the DNS response we see is _actually_ a response to the query we sent (the query ID has to match!
|
||||
|
||||
|
||||
|
||||
Also [you can let me know on Twitter][9] if I’ve made a mistake in this post somewhere – I wrote this pretty quickly so I probably got something wrong.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2022/11/06/making-a-dns-query-in-ruby-from-scratch/
|
||||
|
||||
作者:[Julia Evans][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://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://jvns.ca/blog/2022/02/01/a-dns-resolver-in-80-lines-of-go/
|
||||
[2]: https://gist.github.com/jvns/1e5838a53520e45969687e2f90199770
|
||||
[3]: https://gist.github.com/jvns/aa202b1edd97ae261715c806b2ba7d39
|
||||
[4]: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.1
|
||||
[5]: https://ruby-doc.org/core-3.0.0/Array.html#method-i-pack
|
||||
[6]: https://wizardzines.com/comics/little-endian/
|
||||
[7]: https://gist.github.com/jvns/3587ea0b4a2a6c20dcfd8bf653fc11d9
|
||||
[8]: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4
|
||||
[9]: https://twitter.com/b0rk
|
@ -0,0 +1,131 @@
|
||||
[#]: subject: "Fedora Linux Flatpak cool apps to try for October"
|
||||
[#]: via: "https://fedoramagazine.org/fedora-linux-flatpak-cool-apps-to-try-for-october/"
|
||||
[#]: author: "Eduard Lucena https://fedoramagazine.org/author/x3mboy/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Fedora Linux Flatpak cool apps to try for October
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Original image by Daimar Stein
|
||||
|
||||
This article introduces projects available in Flathub with installation instructions.
|
||||
|
||||
[Flathub][2] is the place to get and distribute apps for all of Linux. It is powered by Flatpak, allowing Flathub apps to run on almost any Linux distribution.
|
||||
|
||||
Please read “[Getting started with Flatpak][3]“. In order to enable flathub as your flatpak provider, use the instructions on the [flatpak site][4].
|
||||
|
||||
### Warehouse
|
||||
|
||||
[Warehouse][5] is a graphical utility to manage your installed flatpak applications and your flatpak remotes. Some of the most important features are:
|
||||
|
||||
* Viewing Flatpak Info
|
||||
* Managing User Data
|
||||
* Batch Actions
|
||||
* Leftover Data Management
|
||||
* Manage Remotes
|
||||
|
||||
|
||||
|
||||
You can install “Warehouse” by clicking the install button on the web site or manually using this command:
|
||||
|
||||
```
|
||||
|
||||
flatpak install flathub io.github.flattool.Warehouse
|
||||
|
||||
```
|
||||
|
||||
### Jogger
|
||||
|
||||
[Jogger][6] is an app for Gnome Mobile to track running and other workouts. It is built with GTK4, Libadwaita, Rust and Sqlite. Even though targeted for Gnome Mobile, it works pretty well under Gnome Shell and I find it very useful to keep my stats. Some of the features are:
|
||||
|
||||
* Track a workout using Geoclue location
|
||||
* Import workouts from a Fitotrack export
|
||||
* Manually enter a workout
|
||||
* View workout details
|
||||
* Edit a workout
|
||||
* Delete a workout
|
||||
* Calculate calories burned for workouts
|
||||
|
||||
|
||||
|
||||
You can install “Jogger” by clicking the install button on the web site or manually using this command:
|
||||
|
||||
```
|
||||
|
||||
flatpak install flathub xyz.slothlife.Jogger
|
||||
|
||||
```
|
||||
|
||||
### Kooha
|
||||
|
||||
[Kooha][7] is a simple screen recorder with a minimalist interface. You can just click the record button without having to configure a bunch of settings.
|
||||
|
||||
The main features of Kooha include the following:
|
||||
|
||||
* Record microphone, desktop audio, or both at the same time
|
||||
* Support for WebM, MP4, GIF, and Matroska formats
|
||||
* Select a monitor, a window, or a portion of the screen to record
|
||||
* Multiple sources selection
|
||||
* Configurable saving location, pointer visibility, frame rate, and delay
|
||||
* It works very well on wayland.
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
flatpak install flathub io.github.seadve.Kooha
|
||||
|
||||
```
|
||||
|
||||
### Warzone 2100
|
||||
|
||||
And who doesn’t love a classic Linux game?
|
||||
|
||||
[Warzone 2100][8] lets you command the forces of The Project in a battle to rebuild the world after mankind was nearly destroyed by nuclear missiles.
|
||||
|
||||
![][9]
|
||||
|
||||
Warzone 2100, released in 1999 and developed by Pumpkin Studios, is a ground-breaking and innovative 3D real-time strategy game.
|
||||
|
||||
In 2004 Eidos, in collaboration with Pumpkin Studios, released the source for the game under the terms of the GNU GPL. This release included everything but the music and in-game video sequences. These, however, were also later released.
|
||||
|
||||
This game has one problem: It uses an old platform package (org.kde.Platform 6.4). This means that it takes more space on disk but the fun is worth it!
|
||||
|
||||
You can install “Warzone 2100” by clicking the install button on the web site or manually using this command:
|
||||
|
||||
```
|
||||
|
||||
flatpak install flathub net.wz2100.wz2100
|
||||
|
||||
```
|
||||
|
||||
_**Warzone 2100**_ _**is also available as rpm on fedora’s repositories**_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/fedora-linux-flatpak-cool-apps-to-try-for-october/
|
||||
|
||||
作者:[Eduard Lucena][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://fedoramagazine.org/author/x3mboy/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2023/10/flatpak_for_October-816x345.jpg
|
||||
[2]: https://flathub.org
|
||||
[3]: https://fedoramagazine.org/getting-started-flatpak/
|
||||
[4]: https://flatpak.org/setup/Fedora
|
||||
[5]: https://flathub.org/apps/io.github.flattool.Warehouse
|
||||
[6]: https://flathub.org/apps/xyz.slothlife.Jogger
|
||||
[7]: https://flathub.org/apps/io.github.seadve.Kooha
|
||||
[8]: https://flathub.org/apps/net.wz2100.wz2100
|
||||
[9]: https://fedoramagazine.org/wp-content/uploads/2023/10/image-1024x738.png
|
249
sources/tech/20231018 Fun With Cmatrix in Linux.md
Normal file
249
sources/tech/20231018 Fun With Cmatrix in Linux.md
Normal file
@ -0,0 +1,249 @@
|
||||
[#]: subject: "Fun With Cmatrix in Linux"
|
||||
[#]: via: "https://itsfoss.com/using-cmatrix/"
|
||||
[#]: author: "Sreenath https://itsfoss.com/author/sreenath/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: " "
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Fun With Cmatrix in Linux
|
||||
======
|
||||
|
||||
Cmatrix is an entertaining command-line program for Linux and Unix systems. It gives a 'Matrix'-style display, where a rain of green characters streams down the screen, just like in the iconic Matrix film series.
|
||||
|
||||
![Cmatrix Command][1]
|
||||
|
||||
But other than this green streams of characters, you can do several other things with this interesting command.
|
||||
|
||||
🚧
|
||||
|
||||
Cmatrix is a CPU intensive command. So use this with caution.
|
||||
|
||||
### Install Cmatrix in Ubuntu and Other Linux systems
|
||||
|
||||
Cmatrix is available in the official repositories of almost all major Linux distributions. In Ubuntu, you can install Cmatrix using the command:
|
||||
|
||||
```
|
||||
|
||||
sudo apt install cmatrix
|
||||
|
||||
```
|
||||
|
||||
Fedora users should use:
|
||||
|
||||
```
|
||||
|
||||
sudo dnf install cmatrix
|
||||
|
||||
```
|
||||
|
||||
Arch Linux user can use pacman:
|
||||
|
||||
```
|
||||
|
||||
sudo pacman -S cmatrix
|
||||
|
||||
```
|
||||
|
||||
### Basic cmatrix options
|
||||
|
||||
The cmatrix command alone provides several options, to change the appearance of the default output, that is the green character streams.
|
||||
|
||||
#### Bold characters
|
||||
|
||||
You can either toggle the bold characters on using `-b` option, where you will find occasional bold characters,
|
||||
|
||||
```
|
||||
|
||||
cmatrix -b
|
||||
|
||||
```
|
||||
|
||||
![Cmatrix with Occasional Bold Characters][2]
|
||||
|
||||
or, turn all the characters to bold using:
|
||||
|
||||
```
|
||||
|
||||
cmatrix -B
|
||||
|
||||
```
|
||||
|
||||
![All Bold Characters][3]
|
||||
|
||||
#### Asynchronous scroll
|
||||
|
||||
The usual Cmatrix will create a display, where characters are falling down in a synchronous manner. In this mode, you can see a dynamic and visually engaging display, where the speed of the characters is varied.
|
||||
|
||||
To use Cmatrix in asynchronous scroll:
|
||||
|
||||
```
|
||||
|
||||
cmatrix -a
|
||||
|
||||
```
|
||||
|
||||
#### Change the speed of characters
|
||||
|
||||
Do you want to display the characters falling very fast, or very slow? You can do this in Cmatrix.
|
||||
|
||||
To make characters fall down fast, use:
|
||||
|
||||
```
|
||||
|
||||
cmatrix -u 2
|
||||
|
||||
```
|
||||
|
||||
![Characters Moving Fast][4]
|
||||
|
||||
Here, the default value of screen update delay is 4 and if you reduce it, the speed will be increased and vice versa. So, to run a slower cmatrix, use:
|
||||
|
||||
```
|
||||
|
||||
cmatrix -u 9
|
||||
|
||||
```
|
||||
|
||||
![Characters Moving Slow][5]
|
||||
|
||||
#### Use different Colors
|
||||
|
||||
Go green! Or perhaps go purple?
|
||||
|
||||
You can run Cmatrix with a different color. For this, you can use the `-C` option.
|
||||
|
||||
```
|
||||
|
||||
cmatrix -C magenta
|
||||
|
||||
```
|
||||
|
||||
![The color is Magenta][6]
|
||||
|
||||
The supported colors are **green, red, blue, white, yellow, cyan, magenta and black**.
|
||||
|
||||
#### Other Options
|
||||
|
||||
Option | Function
|
||||
---|---
|
||||
cmatrix -o | Old Style Scrolling
|
||||
cmatrix -m | Lambda Mode: Every character becomes a lambda
|
||||
cmatrix -s | Screensaver Mode: Exits on first keystroke
|
||||
cmatrix -h | Help
|
||||
|
||||
### Cmatrix keystrokes during execution
|
||||
|
||||
Even if you don’t provide any option in Cmatrix, you can provide some input later on during execution. Those are listed below.
|
||||
|
||||
#### Change Color
|
||||
|
||||
Yes, you can change the color of characters while running. But you need to remember some keys and their corresponding color. What to do is, while running Cmatrix, press these keys and the color will change.
|
||||
|
||||
Color | Keystroke
|
||||
---|---
|
||||
Red | !
|
||||
Green | @
|
||||
Yellow | #
|
||||
Blue | $
|
||||
Magenta | %
|
||||
Cyan | ^
|
||||
White | &
|
||||
Black | )
|
||||
|
||||
#### Adjust update speed
|
||||
|
||||
While running, you can use the number keys from 0 through 9 to change the update speed.
|
||||
|
||||
There are other options also, which you can find from the man page of the command.
|
||||
|
||||
```
|
||||
|
||||
man cmatrix
|
||||
|
||||
```
|
||||
|
||||
### Bonus: Cmatrix with lolcat
|
||||
|
||||
🚧
|
||||
|
||||
Cmatrix itself is CPU intensive. So use the other commands with caution.
|
||||
|
||||
You can use Cmatrix, in combination with the lolcat command, to make it look more interesting. In Ubuntu, you can install lolcat using:
|
||||
|
||||
```
|
||||
|
||||
sudo apt install lolcat
|
||||
|
||||
```
|
||||
|
||||
Now, just pipe Cmatrix to lolcat so that you will get a rainbow effect.
|
||||
|
||||
```
|
||||
|
||||
cmatrix | lolcat
|
||||
|
||||
```
|
||||
|
||||
![Cmatrix with Lolcat][7]
|
||||
|
||||
Also, try all the above functions of Cmatrix, while piping into lolcat.
|
||||
|
||||
Or, you can use an inclined stripe for a rainbow effect, giving another type of experience.
|
||||
|
||||
```
|
||||
|
||||
cmatrix | lolcat -p 100
|
||||
|
||||
```
|
||||
|
||||
Additionally, you can just invert the background and foreground colors so that your terminal will be filled with colors.
|
||||
|
||||
```
|
||||
|
||||
cmatrix | lolcat -i
|
||||
|
||||
```
|
||||
|
||||
![Cmatrix with Lolcat Inverted Color Option][8]
|
||||
|
||||
### More fun with terminal
|
||||
|
||||
I know this is not the [most useful Linux command][9] but it's fun nonetheless and you can have some [fun with your Linux system][10] sometime, right?
|
||||
|
||||
[Cowsay][11] is another such command:
|
||||
|
||||
![][12]
|
||||
|
||||
And even more here:
|
||||
|
||||
![][12]
|
||||
|
||||
I let you enjoy it now, Mr. Anderson.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/using-cmatrix/
|
||||
|
||||
作者:[Sreenath][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/sreenath/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/content/images/2023/10/Cmatrix.gif
|
||||
[2]: https://itsfoss.com/content/images/2023/10/cmatrix-occasional-bold-characters.png
|
||||
[3]: https://itsfoss.com/content/images/2023/10/cmatrix-all-bold-characters.png
|
||||
[4]: https://itsfoss.com/content/images/2023/10/Cmatrix-fast.gif
|
||||
[5]: https://itsfoss.com/content/images/2023/10/cmatrix-slow.gif
|
||||
[6]: https://itsfoss.com/content/images/2023/10/cmatrix-magenta-color.png
|
||||
[7]: https://itsfoss.com/content/images/2023/10/Cmatrix-with-lolcat.png
|
||||
[8]: https://itsfoss.com/content/images/2023/10/cmatrix-with-inverse-colors.png
|
||||
[9]: https://itsfoss.com/essential-ubuntu-commands/
|
||||
[10]: https://itsfoss.com/funny-linux-commands/
|
||||
[11]: https://itsfoss.com/cowsay/
|
||||
[12]: https://itsfoss.com/content/images/size/w256h256/2022/12/android-chrome-192x192.png
|
@ -0,0 +1,568 @@
|
||||
[#]: subject: "Making a DNS query in Ruby from scratch"
|
||||
[#]: via: "https://jvns.ca/blog/2022/11/06/making-a-dns-query-in-ruby-from-scratch/"
|
||||
[#]: author: "Julia Evans https://jvns.ca/"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "Drwhooooo"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
从零开始,运用 Ruby 语言创建一个 DNS 查询
|
||||
======
|
||||
|
||||
大家好!
|
||||
|
||||
前段时间我写了一篇关于“[如何用 Go 语言建立一个简易的 DNS 解析器][1]”的帖子。
|
||||
|
||||
那篇帖子里我没写有关“如何生成以及解析 DNS 查询请求”的内容,因为我觉得这很无聊,不过一些伙计指出他们不知道如何解析和生成 DNS 查询请求,并且对此很感兴趣。
|
||||
|
||||
我开始好奇了——解析 DNS _能_花多大功夫?事实证明,编写一段 120 行精巧的Ruby语言代码组成的程序我们就可以做到,这并不是很困难。
|
||||
|
||||
所以,在这里有一个如何生成 DNS 查询请求以及如何解析DNS响应报文的速成教学!我们会用 Ruby 语言完成这项任务,主要是因为不久以后我将在一场 Ruby 语言大会上发表观点,而这篇博客帖的部分内容是为了那场谈话做准备的。:)
|
||||
|
||||
(我尽可能让代码在那些之前不知道 Ruby 语言的人们面前保持可读性,我也只用过非常基础的 Ruby 语言代码。)
|
||||
|
||||
最后,我们就能制作一个非常简易的 Ruby 版本的`dig`工具,能够查找域名,就像这样:
|
||||
|
||||
```
|
||||
|
||||
$ ruby dig.rb example.com
|
||||
example.com 20314 A 93.184.216.34
|
||||
|
||||
```
|
||||
|
||||
整个大概 120 行左右,并没有 _那么_ 多。 (最终程序在这里,[dig.rb][2],如果你想略过细则,单纯想去读代码的话。)
|
||||
|
||||
我们不会去实现之前帖中所说的“一个 DNS 解析器是如何运作的?”,因为我们已经做过了。
|
||||
|
||||
那么我们开始吧!
|
||||
|
||||
顺便提一嘴,我会试着去解释为什么如果你们想尽办法从头理解 DNS 查询是如何布局的,你们就能够自己去解决这一档子事儿。大多数情况下的答案是“搜索 Wireshark”以及“阅读 RFC 1035,即 DNS 的请求注解”。
|
||||
|
||||
### 步骤一:打开一个 UDP 套接字
|
||||
|
||||
我们需要切实发送我们的DNS查询,那么为了达成目的我们就需要打开一个 UDP 套接字。我们会将我们的 DNS 查询发送至 `8.8.8.8`,即 Google 服务器。
|
||||
|
||||
下面是用于建立与 `8.8.8.8` 的 UDP 联接,端口为 53(UDP 端口) 的代码。
|
||||
|
||||
```
|
||||
|
||||
require 'socket'
|
||||
sock = UDPSocket.new
|
||||
|
||||
sock.bind('0.0.0.0', 12345)
|
||||
sock.connect('8.8.8.8', 53)
|
||||
|
||||
```
|
||||
|
||||
##### 关于 UDP 的一个小贴士:
|
||||
|
||||
我不再多说更多关于 UDP 的内容了,但是我还是会说有关计算机网络基础知识中的“数据包”(数据包,即一个字节串),而在这个程序中我会教你们关于计算机网络里能做到的最简单的事情——传递一个数据包,并接收一个数据包作为响应。
|
||||
|
||||
所以 UDP 是一个传递数据包的最简单的方法。
|
||||
|
||||
这是发送 DNS 查询最寻常的方法,不过你还可以用 TCP 或者 DNS-over-HTTPS。
|
||||
|
||||
##### 步骤二:自 Wireshark 复制一个 DNS 查询
|
||||
|
||||
那么:要是我们都没法理解 DNS 是如何运作的但我们还是想尽快发送一个能运行的 DNS 查询。那么最简单的方式便是,粘过来个已经能够运行的来玩玩!只要确保我们的 UDP 连接运行正常就行。
|
||||
|
||||
所以这就是我们接下来要做的,运用 Wireshark (一个绝赞的数据包分析工具)
|
||||
|
||||
我之前的操作大致如下:
|
||||
|
||||
1. 打开 Wireshark,点击 “capture” 按钮。
|
||||
2. (在搜索栏)输入 `udp.port == 53` 作为一个筛选条件,然后键盘点击 Enter。
|
||||
3. 在我的终端运行 `ping example.com`(用来生成一个 DNS 查询)。
|
||||
4. 点击 DNS 查询(显示“Standard query A example.com”)。
|
||||
(“A”:查询类型;“example.com”:域名;“Standard query”:查询类型描述)
|
||||
5. 右键点击位于左下角面板上的“Domain Name System (query)”。
|
||||
6. 点击‘Copy’ ——> ‘as a hex stream’
|
||||
7. 现在的话
|
||||
`b96201000001000000000000076578616d706c6503636f6d0000010001`
|
||||
就留存在了我后台的剪贴板上,之后会用在我的 Ruby 程序里。好欸!
|
||||
|
||||
|
||||
|
||||
##### 步骤三:解析 16 进制数据流并发送 DNS 查询
|
||||
|
||||
现在我们能够发送我们的 DNS 查询到 `8.8.8.8` 了!就像这样,我们只需要再加 5 行代码:
|
||||
|
||||
```
|
||||
|
||||
hex_string = "b96201000001000000000000076578616d706c6503636f6d0000010001"
|
||||
bytes = [hex_string].pack('H*')
|
||||
sock.send(bytes, 0)
|
||||
|
||||
# get the reply
|
||||
reply, _ = sock.recvfrom(1024)
|
||||
puts reply.unpack('H*')
|
||||
|
||||
```
|
||||
|
||||
`[hex_string].pack('H*')` 意思就是将我们的 16 位字符串翻译成一个字节串。此时我们不知道这组数据到底是什么意思但是很快我们就会知道了。
|
||||
|
||||
我们还可以借此机会运用 `tcpdump` ,确认程序是否正常进行以及发送有效数据。我是这么做的:
|
||||
|
||||
1. 在一个终端选项卡下执行 `sudo tcpdump -ni any port 53 and host 8.8.8.8` 语句
|
||||
2. 在另一个不同的终端指标卡下,运行[这个程序][3](`ruby dns-1.rb`)
|
||||
|
||||
|
||||
|
||||
以下是输出结果:
|
||||
|
||||
```
|
||||
|
||||
$ sudo tcpdump -ni any port 53 and host 8.8.8.8
|
||||
08:50:28.287440 IP 192.168.1.174.12345 > 8.8.8.8.53: 47458+ A? example.com. (29)
|
||||
08:50:28.312043 IP 8.8.8.8.53 > 192.168.1.174.12345: 47458 1/0/0 A 93.184.216.34 (45)
|
||||
|
||||
```
|
||||
|
||||
非常棒 —— 我们可以看到 DNS 请求(”这个 `example.com` 的 IP 地址在哪里?“)以及响应(“在93.184.216.34”)。所以一切运行正常。现在只需要(你懂的)—— 搞清我们是如何生成并解析这组数据的。
|
||||
|
||||
##### 步骤四:学一点点 DNS 查询是怎样布局的
|
||||
|
||||
现在我们有一个关于 `example.com` 的 DNS 查询,让我们了解它的含义。
|
||||
|
||||
下方是我们的查询(16 位进制格式):
|
||||
|
||||
```
|
||||
|
||||
b96201000001000000000000076578616d706c6503636f6d0000010001
|
||||
|
||||
```
|
||||
|
||||
如果你在 Wireshark 上搜索,你就能看见这个查询它由两部分组成:
|
||||
|
||||
* **请求头** **the header**(`b96201000001000000000000`)
|
||||
* **语句本身** **the question**(`076578616d706c6503636f6d0000010001`)
|
||||
|
||||
|
||||
|
||||
##### 步骤五:制作请求头 the header
|
||||
|
||||
我们这一步的目标就是制作字节串 `b96201000001000000000000`(借助一个 Ruby 函数 而不是把它硬编码出来)
|
||||
(硬编码(hardcode):指在软件实现上,将输出或输入的相关参数(例如:路径、输出的形式或格式)直接以**常量**的方式撰写在源代码中,而非在运行期间由外界指定的设置、资源、数据或格式做出适当回应。)
|
||||
|
||||
那么:请求头是 12 个字节。那些个 12 字节到底意味着什么呢?如果你在 Wireshark 里看看(亦或者阅读 [RFC-1035][4]),你就能理解:它是由 6 个 2 字节大小的数字串联在一起组成的。
|
||||
|
||||
这六个数字与查询的 ID、标志、问题计数、回答资源记录数、权威名称服务器记录数、附加资源记录数在一个数据包内。
|
||||
|
||||
我们不需要在意这些都是些什么东西 —— 我们只需要把这六个数字输进去就行。
|
||||
|
||||
但所幸我们知道该输哪六位数,因为我们就是为了直观地生成字符串`b96201000001000000000000`。
|
||||
|
||||
所以这里有一个制作请求头的函数(注意:这里没有`return`,因为在Ruby语言里,如果处在函数最后一行是不需要写`return`语句的):
|
||||
|
||||
```
|
||||
|
||||
def make_question_header(query_id)
|
||||
# id, flags, num questions, num answers, num auth, num additional
|
||||
[query_id, 0x0100, 0x0001, 0x0000, 0x0000, 0x0000].pack('nnnnnn')
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
上面内容非常的短,主要因为除了查询 ID ,其余所有内容都由我们硬编码写了出来。
|
||||
|
||||
##### 什么是 `nnnnnn`?
|
||||
|
||||
可能能想知道在`.pack('nnnnnn')`中的`nnnnnn`是个什么意思。那是一个向`.pack()`解释如何将那个 6 个数字组成的数据转换成一个字节串的一个格式字符串。
|
||||
|
||||
[`.pack` 的文件在这里][5],其中描述了`n`的含义其实是“将其表示为‘16 位无符号,网络(大端序)字节序’”。
|
||||
(大端序(Big-endian):指将高位字节存储在低地址,低位字节存储在高地址的方式。)
|
||||
|
||||
16 比特等同于 2 字节,同时我们需要用网络字节序,因为这属于计算机网络范畴。我不会再去解释什么是字节序了(尽管我确实有[一本尝试去描述它的自制漫画][6])
|
||||
|
||||
##### 测试请求头代码
|
||||
|
||||
让我们快速检测一下我们的 `make_question_header` 函数运行情况。
|
||||
|
||||
```
|
||||
|
||||
puts make_question_header(0xb962) == ["b96201000001000000000000"].pack("H*")
|
||||
|
||||
```
|
||||
|
||||
这里运行后输出“true”的话,我们就赢了。
|
||||
|
||||
好了我们接着继续。
|
||||
|
||||
##### 步骤五:为域名进行编码
|
||||
|
||||
下一步我们需要生成**问题本身**(“`example.com` 的 IP 是什么?“)。这里有三个部分:
|
||||
|
||||
* **域名**(比如说“example.com”)
|
||||
* **查询类型**(比如说”A“代表”IPv4**A**ddress“)
|
||||
* **查询类**(和第二条类似,1代表 **IN**(**IN**ternet))
|
||||
|
||||
以上三个中麻烦的就是域名,让我们写个函数对付这个。
|
||||
|
||||
`example.com` 以 16 进制被编码进一个 DNS 查询中,如`076578616d706c6503636f6d00`。这有什么含义吗?
|
||||
|
||||
如果我们把这些字节以 ASCII 值翻译出来,结果会是这样:
|
||||
|
||||
```
|
||||
|
||||
076578616d706c6503636f6d00
|
||||
7 e x a m p l e 3 c o m 0
|
||||
|
||||
```
|
||||
|
||||
你看每一个片段(像`example`) 的前面都会显示它的长度(像`7`)。
|
||||
|
||||
下面是有关将`example`翻译成`7 e x a m p l e 3 c o m 0`的Ruby 代码:
|
||||
|
||||
```
|
||||
|
||||
def encode_domain_name(domain)
|
||||
domain
|
||||
.split(".")
|
||||
.map { |x| x.length.chr + x }
|
||||
.join + "\0"
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
另外,为结束生成问题本身这一环节,我们只需要在域名结尾追加上它(查询)的类型和类。
|
||||
|
||||
##### 步骤六:编写 `make_dns_query`
|
||||
|
||||
下面是制作一个 DNS 查询的最终函数:
|
||||
|
||||
```
|
||||
|
||||
def make_dns_query(domain, type)
|
||||
query_id = rand(65535)
|
||||
header = make_question_header(query_id)
|
||||
question = encode_domain_name(domain) + [type, 1].pack('nn')
|
||||
header + question
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
[这是目前我们写的所有代码的文件链接dns-2.rb][7] —— 目前仅29行。
|
||||
|
||||
##### 接下来是 解析 的阶段
|
||||
|
||||
现在我尝试去解析一个 DNS 查询,我们到了个硬核的部分:解析。同样的,我们会将其分成不同部分:
|
||||
|
||||
* 解析一个 DNS 的请求头
|
||||
* 解析一个 DNS 的名称
|
||||
* 解析一个 DNS 的记录
|
||||
|
||||
|
||||
|
||||
这几个部分中最难的(可能跟你想的不一样)就是:”解析一个 DNS 的名称“。
|
||||
|
||||
##### 步骤七:解析 DNS 的请求头
|
||||
|
||||
让我们先从最简单的部分开始。我们之前已经讲过关于它那六个数字是如何串联在一起的了。
|
||||
|
||||
那么我们现在要做的就是:
|
||||
|
||||
* 读其首部 12 个字节
|
||||
* 将其转换成一个由 6 个数字组成的数组
|
||||
* 将这六个数字归于一个类中方便使用
|
||||
|
||||
|
||||
|
||||
以下是具体进行工作的 Ruby 代码:
|
||||
|
||||
```
|
||||
|
||||
class DNSHeader
|
||||
attr_reader :id, :flags, :num_questions, :num_answers, :num_auth, :num_additional
|
||||
def initialize(buf)
|
||||
hdr = buf.read(12)
|
||||
@id, @flags, @num_questions, @num_answers, @num_auth, @num_additional = hdr.unpack('nnnnnn')
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
注: `attr_reader` 是 Ruby 里的内容意思是”使这些直接变量像方法一样易用“。所以我们可以调用`header.flags`来查看`@flags`变量。
|
||||
|
||||
我们也可以借助`DNSheader(buf)`调用这个,也不差。
|
||||
|
||||
让我们往最难的那一步挪挪:解析一个域名。
|
||||
|
||||
##### 步骤八:解析一个域名
|
||||
|
||||
首先,让我们写其中的一部分:
|
||||
|
||||
```
|
||||
|
||||
def read_domain_name_wrong(buf)
|
||||
domain = []
|
||||
loop do
|
||||
len = buf.read(1).unpack('C')[0]
|
||||
break if len == 0
|
||||
domain << buf.read(len)
|
||||
end
|
||||
domain.join('.')
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
这里会重复读取一个字节的数据,然后直到读取到长度为0的数据之前,会将长度数据存在一个字符串内。
|
||||
|
||||
这里运行正常的话,我们就能在我们的 DNS 响应头第一次看见一个域名(`example.com`)。
|
||||
|
||||
##### 关于域名方面的麻烦:压缩!
|
||||
|
||||
但当 `example.com` 第二次出现的时候,我们的运行出现了问题 —— 在 Wireshark 中,它报告上显示输出的域的值为含糊不清的2个字节的`c00c`。
|
||||
|
||||
这种情况就是所谓的 **DNS 域名压缩**,并且如果我们想再解析其它的响应我们就要先把这个实现完。
|
||||
|
||||
|
||||
这个索性没有**那——么**难。这里 `c00c` 的含义就是:
|
||||
|
||||
* 前两个比特(`0b11.....`)意思是”前面有 DNS 域名压缩!”
|
||||
* 而余下的14比特是一个整型。这种情况下的整数为`12`(`0x0c`),意思是”返回至数据包中的第12个字节处,使用在那里找的域名“
|
||||
|
||||
|
||||
如果你想阅读更多有关 DNS 域名压缩之类的内容。我找到了相关更容易让你理解这方面内容的文章:[关于 DNS RFC 的释义][8]。
|
||||
|
||||
##### 步骤九:实现 DNS 域名压缩
|
||||
|
||||
下面我们需要我们的 `read_domain_name` 有一个更复杂的版本。
|
||||
|
||||
如下所示:
|
||||
|
||||
```
|
||||
|
||||
domain = []
|
||||
loop do
|
||||
len = buf.read(1).unpack('C')[0]
|
||||
break if len == 0
|
||||
if len & 0b11000000 == 0b11000000
|
||||
# weird case: DNS compression!
|
||||
second_byte = buf.read(1).unpack('C')[0]
|
||||
offset = ((len & 0x3f) << 8) + second_byte
|
||||
old_pos = buf.pos
|
||||
buf.pos = offset
|
||||
domain << read_domain_name(buf)
|
||||
buf.pos = old_pos
|
||||
break
|
||||
else
|
||||
# normal case
|
||||
domain << buf.read(len)
|
||||
end
|
||||
end
|
||||
domain.join('.')
|
||||
|
||||
```
|
||||
这里具体是这么个情况:
|
||||
|
||||
* 如果前两个比特为`0b11` ,那么我们就需要做 DNS 域名压缩。那么:
|
||||
* 读取第二个字节并用一点儿算法将其转化为偏移量。
|
||||
|
||||
* 在缓冲区保存当前位置。
|
||||
|
||||
* 在我们计算偏移量的位置上读取域名
|
||||
|
||||
* 在缓冲区存储我们的位置。
|
||||
|
||||
|
||||
可能看起来很乱,但是这是解析 DNS 响应的部分中最难的一处了,我们快搞定了!
|
||||
|
||||
##### 一个关于 DNS 压缩的漏洞
|
||||
|
||||
有些人可能会说,有恶意行为者可以借助这个代码,通过一个带 DNS 压缩条目的 DNS 响应指向这个响应本身,这样 `read_domain_name` 就会陷入无限循环。我才不会改进它(这个代码已经够复杂了好吗!)但一个真正的 DNS 解析器确实会更巧妙地处理它。比如,这里有个[能够避免在 miekg/dns 中陷入无限循环的代码][9]。
|
||||
|
||||
##### 步骤十:解析一个 DNS 查询
|
||||
|
||||
你可能在想:”为什么我们需要解析一个 DNS 查询?这是一个响应啊!”
|
||||
|
||||
但每一个 DNS 响应有它原本自己的查询,所以我们有必要去解析它。
|
||||
|
||||
这是解析 DNS 查询的代码:
|
||||
|
||||
```
|
||||
|
||||
class DNSQuery
|
||||
attr_reader :domain, :type, :cls
|
||||
def initialize(buf)
|
||||
@domain = read_domain_name(buf)
|
||||
@type, @cls = buf.read(4).unpack('nn')
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
内容不是太多:类型和类各占2个字节。
|
||||
|
||||
##### 步骤十一:解析一个 DNS 记录
|
||||
|
||||
最让人兴奋的部分 —— DNS 记录是我们的查询数据存放的地方!即这个“rdata 区域”(“记录数据字段”)就是我们会在 DNS 查询对应的响应中获得的 IP 地址所驻留的地方。
|
||||
|
||||
代码如下:
|
||||
|
||||
```
|
||||
|
||||
class DNSRecord
|
||||
attr_reader :name, :type, :class, :ttl, :rdlength, :rdata
|
||||
def initialize(buf)
|
||||
@name = read_domain_name(buf)
|
||||
@type, @class, @ttl, @rdlength = buf.read(10).unpack('nnNn')
|
||||
@rdata = buf.read(@rdlength)
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
我们还需要让这个 `rdata` 区域更加可读。记录数据字段的实际用途取决于记录类型 —— 比如一个“A”记录就是一个四个字节的 IP 地址,而一个“CNAME”记录则是一个域名。
|
||||
|
||||
所以下面的代码可以让请求数据更可读:
|
||||
```
|
||||
|
||||
def read_rdata(buf, length)
|
||||
@type_name = TYPES[@type] || @type
|
||||
if @type_name == "CNAME" or @type_name == "NS"
|
||||
read_domain_name(buf)
|
||||
elsif @type_name == "A"
|
||||
buf.read(length).unpack('C*').join('.')
|
||||
else
|
||||
buf.read(length)
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
这个函数使用了 `TYPES` 这个哈希表将一个记录类型映射为一个更可读的名称:
|
||||
|
||||
```
|
||||
|
||||
TYPES = {
|
||||
1 => "A",
|
||||
2 => "NS",
|
||||
5 => "CNAME",
|
||||
# there are a lot more but we don't need them for this example
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
`read.rdata` 中最有趣的一部分可能就是这一行`buf.read(length).unpack('C*').join('.')` —— 像是在说:”嘿!有个 IP 地址4个字节,就将它转换成一组四个数字组成的数组,然后数字互相之间用‘ . ’联个谊吧。”
|
||||
|
||||
##### 解析 DNS 响应的收尾工作
|
||||
|
||||
现在我们正式准备好解析 DNS 响应了!
|
||||
|
||||
工作代码如下所示:
|
||||
|
||||
```
|
||||
|
||||
class DNSResponse
|
||||
attr_reader :header, :queries, :answers, :authorities, :additionals
|
||||
def initialize(bytes)
|
||||
buf = StringIO.new(bytes)
|
||||
@header = DNSHeader.new(buf)
|
||||
@queries = (1..@header.num_questions).map { DNSQuery.new(buf) }
|
||||
@answers = (1..@header.num_answers).map { DNSRecord.new(buf) }
|
||||
@authorities = (1..@header.num_auth).map { DNSRecord.new(buf) }
|
||||
@additionals = (1..@header.num_additional).map { DNSRecord.new(buf) }
|
||||
end
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
这里大部分内容就是在调用之前我们写过的其他函数来协助解析 DNS 响应。
|
||||
|
||||
如果`@header.num_answers` 的值为2,代码会使用了`(1..@header.num_answers).map` 这个巧妙的结构创建一个包含两个 DNS 记录的数组。(在 Ruby 中可能有些魔幻,但我就是觉得有趣,但愿不会影响可读性。)
|
||||
|
||||
我们可以把这段代码整合进我们的主函数中,就像这样:
|
||||
|
||||
```
|
||||
|
||||
sock.send(make_dns_query("example.com", 1), 0) # 1 is "A", for IP address
|
||||
reply, _ = sock.recvfrom(1024)
|
||||
response = DNSResponse.new(reply) # parse the response!!!
|
||||
puts response.answers[0]
|
||||
|
||||
```
|
||||
|
||||
尽管输出结果看起来有点辣眼睛(类似于`#<DNSRecord:0x00000001368e3118>`)所以我们需要编写一些好看的输出代码,提升它的可读性。
|
||||
|
||||
##### 步骤十三:对于我们输出的 DNS 记录进行美化
|
||||
|
||||
我们需要向 DNS 记录增加一个 `.to_s` 区域从而让它有一个更良好的字符串展示方式。而者只是做为一行方法的代码在 `DNSRecord` 中存在。
|
||||
|
||||
```
|
||||
|
||||
def to_s
|
||||
"#{@name}\t\t#{@ttl}\t#{@type_name}\t#{@parsed_rdata}"
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
你可能也注意到了我忽略了 DNS 记录中的`class`区域。那是因为它通常都比较同质化(很多都为代表”internet“的 IN)所以我觉得它是个冗余。虽然很多 DNS 工具(像真正的 `dig`)会输出 class。
|
||||
|
||||
##### 大功告成!
|
||||
|
||||
这是我们最终的主函数:
|
||||
|
||||
```
|
||||
|
||||
def main
|
||||
# connect to google dns
|
||||
sock = UDPSocket.new
|
||||
sock.bind('0.0.0.0', 12345)
|
||||
sock.connect('8.8.8.8', 53)
|
||||
|
||||
# send query
|
||||
domain = ARGV[0]
|
||||
sock.send(make_dns_query(domain, 1), 0)
|
||||
|
||||
# receive & parse response
|
||||
reply, _ = sock.recvfrom(1024)
|
||||
response = DNSResponse.new(reply)
|
||||
response.answers.each do |record|
|
||||
puts record
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
我不觉得我们还能再补充什么 —— 我们连接、发送一个查询、输出每一个回答,然后退出。完事儿!
|
||||
|
||||
```
|
||||
|
||||
$ ruby dig.rb example.com
|
||||
example.com 18608 A 93.184.216.34
|
||||
|
||||
```
|
||||
|
||||
你可以在这里查看最终程序:[dig.rb][2]。可以根据你的喜好给它增加更多特性,就比如说:
|
||||
|
||||
* 为其他查询类型添加美化输出。
|
||||
* 输出 DNS 响应时增加“授权”和“可追加”的选项
|
||||
* 重试
|
||||
* 确保我们看到的 DNS 响应和我们发送查询的响应( ID 信息必须是对的上的!)
|
||||
|
||||
|
||||
|
||||
另外如果我再本帖出现了什么错误,就[在推特和我聊聊][10]。(我写的比较赶所以可能还是会有些错误)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://jvns.ca/blog/2022/11/06/making-a-dns-query-in-ruby-from-scratch/
|
||||
|
||||
作者:[Julia Evans][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://jvns.ca/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://jvns.ca/blog/2022/02/01/a-dns-resolver-in-80-lines-of-go/
|
||||
[2]: https://gist.github.com/jvns/1e5838a53520e45969687e2f90199770
|
||||
[3]: https://gist.github.com/jvns/aa202b1edd97ae261715c806b2ba7d39
|
||||
[4]: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.1
|
||||
[5]: https://ruby-doc.org/core-3.0.0/Array.html#method-i-pack
|
||||
[6]: https://wizardzines.com/comics/little-endian/
|
||||
[7]: https://gist.github.com/jvns/3587ea0b4a2a6c20dcfd8bf653fc11d9
|
||||
[8]: https://datatracker.ietf.org/doc/html/rfc1035#section-4.1.4
|
||||
[9]: https://link.zhihu.com/?target=https%3A//github.com/miekg/dns/blob/b3dfea07155dbe4baafd90792c67b85a3bf5be23/msg.go%23L430-L435
|
||||
[10]: https://twitter.com/b0rk
|
@ -1,351 +0,0 @@
|
||||
[#]: subject: "Working with Btrfs – Compression"
|
||||
[#]: via: "https://fedoramagazine.org/working-with-btrfs-compression/"
|
||||
[#]: author: "Andreas Hartmann https://fedoramagazine.org/author/hartan/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: "A2ureStone"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
Btrfs 详解:压缩
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Photo by [Heliberto Arias][2] on [Unsplash][3]
|
||||
|
||||
这篇文章将探索 Btrfs 中的透明文件系统压缩,以及它如何帮助节省存储空间。这篇文章是《Btrfs 详解》系列文章中的一篇。从 Fedora Linux 33 开始,Btrfs 就是 Fedora Workstation 和 Fedora Silverblue 的默认文件系统。
|
||||
|
||||
如果你错过了,这里是本系列的上一篇文章:<https://fedoramagazine.org/working-with-btrfs-snapshots>
|
||||
|
||||
### 简介
|
||||
|
||||
很多人都经历过存储空间用完的情况。也许你想从互联网下载一个大文件,或者你需要去快速从你的手机中复制些照片,然后操作突然失败。虽然存储空间成本正在稳步降低,但越来越多的设备要么以固定数量的存储空间制造,要么难以被最终用户扩展。
|
||||
|
||||
但当你的存储空间不足时你可以做什么呢?也许你会求助于云存储,或者你可以随身携带一些外部存储设备。
|
||||
|
||||
在这篇文章里我会研究该问题的另一种解决方案:透明的文件系统压缩,Btrfs 的一个特性。理想情况下,这将解决你的存储问题同时几乎不需要对你的系统进行修改!让我们来看看是如何做到的。
|
||||
|
||||
### 透明压缩的解释
|
||||
|
||||
首先,让我们来探寻 _透明_ 压缩是什么意思。你可以通过像 gzip,xz 或者 bzip2 这些压缩算法去压缩文件。这通常是显式操作:你利用一个压缩工具并且让它操作你的文件。虽然根据文件的内容,这节约了空间,这有一个主要的缺点:当你想读取文件或者修改的时候,你得先解压缩。
|
||||
|
||||
这不仅是一个乏味的过程,而且但也暂时打破了你之前节省的空间。再者,你最终解压了你不想访问的那部分文件。明显有比这更好的方法!
|
||||
|
||||
相反透明压缩发生在文件系统级别。在这里,压缩的文件对用户看起来像常规的未压缩文件一样。但是,他们是被压缩后存储在硬盘上的。这可行是因为操作系统仅仅选择性地你访问的那部分文件,并且保证在向磁盘写入更新时再次压缩它们。
|
||||
|
||||
这里的压缩是透明的在于它不被用户感知,除了在文件访问时可能的 CPU 负载小量增加。因此,你可以应用在已有的系统而不是进行硬件修改或者求助于云存储。
|
||||
|
||||
### 压缩算法对比
|
||||
|
||||
Btrfs 提供了多个压缩算法的选择。出于技术原因它不能选用任意的压缩算法。它现在支持
|
||||
|
||||
* zstd
|
||||
* lzo
|
||||
* zlib
|
||||
|
||||
|
||||
|
||||
好消息是,由于透明压缩的工作原理,你不需要安装这些程序供 Btrfs 使用。在下面的段落里,你会看到如何去运行一个简单的性能测试来对比压缩算法。但是,为了运行性能测试,你必须安装必要的可执行文件。事后不需要留着它们,所以你将使用 podman 容器来确保不会在系统中留下任何痕迹。
|
||||
|
||||
**注意** :因为 Btrfs 使用的压缩依赖于内核对这些压缩算法的(重新)实现,用户空间版本的算法得出的结果应该认为是粗略估计。
|
||||
|
||||
因为一次次敲重复的命令是枯燥的工作,我已经在 Gitlab 上准备了一个可以运行的 bash 脚本 (<https://gitlab.com/hartang/btrfs-compression-test>). 这会用上面提到的每个算法在不同的压缩级别运行一次简单的压缩和解压缩。
|
||||
|
||||
首先,下载脚本:
|
||||
|
||||
```
|
||||
|
||||
$ curl -LO https://gitlab.com/hartang/btrfs-compression-test/-/raw/main/btrfs_compression_test.sh
|
||||
|
||||
```
|
||||
|
||||
下一步,启动一个 Fedora Linux 容器去挂载你当前的工作目录,以便你可以和主机交换文件同时在那里运行脚本:
|
||||
|
||||
```
|
||||
|
||||
$ podman run --rm -it --security-opt label=disable -v "$PWD:$PWD" \
|
||||
-w "$PWD" registry.fedoraproject.org/fedora:37
|
||||
|
||||
```
|
||||
|
||||
最后运行脚本:
|
||||
|
||||
```
|
||||
|
||||
$ chmod +x ./btrfs_compression_test.sh
|
||||
$ ./btrfs_compression_test.sh
|
||||
|
||||
```
|
||||
|
||||
在我机器上的输出是这样:
|
||||
|
||||
```
|
||||
|
||||
[INFO] Using file 'glibc-2.36.tar' as compression target
|
||||
[INFO] Target file 'glibc-2.36.tar' not found, downloading now...
|
||||
################################################################### 100.0%
|
||||
[ OK ] Download successful!
|
||||
[INFO] Copying 'glibc-2.36.tar' to '/tmp/tmp.vNBWYg1Vol/' for benchmark...
|
||||
[INFO] Installing required utilities
|
||||
[INFO] Testing compression for 'zlib'
|
||||
|
||||
Level | Time (compress) | Compression Ratio | Time (decompress)
|
||||
-------+-----------------+-------------------+-------------------
|
||||
1 | 0.322 s | 18.324 % | 0.659 s
|
||||
2 | 0.342 s | 17.738 % | 0.635 s
|
||||
3 | 0.473 s | 17.181 % | 0.647 s
|
||||
4 | 0.505 s | 16.101 % | 0.607 s
|
||||
5 | 0.640 s | 15.270 % | 0.590 s
|
||||
6 | 0.958 s | 14.858 % | 0.577 s
|
||||
7 | 1.198 s | 14.716 % | 0.561 s
|
||||
8 | 2.577 s | 14.619 % | 0.571 s
|
||||
9 | 3.114 s | 14.605 % | 0.570 s
|
||||
|
||||
[INFO] Testing compression for 'zstd'
|
||||
|
||||
Level | Time (compress) | Compression Ratio | Time (decompress)
|
||||
-------+-----------------+-------------------+-------------------
|
||||
1 | 0.492 s | 14.831 % | 0.313 s
|
||||
2 | 0.607 s | 14.008 % | 0.341 s
|
||||
3 | 0.709 s | 13.195 % | 0.318 s
|
||||
4 | 0.683 s | 13.108 % | 0.306 s
|
||||
5 | 1.300 s | 11.825 % | 0.292 s
|
||||
6 | 1.824 s | 11.298 % | 0.286 s
|
||||
7 | 2.215 s | 11.052 % | 0.284 s
|
||||
8 | 2.834 s | 10.619 % | 0.294 s
|
||||
9 | 3.079 s | 10.408 % | 0.272 s
|
||||
10 | 4.355 s | 10.254 % | 0.282 s
|
||||
11 | 6.161 s | 10.167 % | 0.283 s
|
||||
12 | 6.670 s | 10.165 % | 0.304 s
|
||||
13 | 12.471 s | 10.183 % | 0.279 s
|
||||
14 | 15.619 s | 10.075 % | 0.267 s
|
||||
15 | 21.387 s | 9.989 % | 0.270 s
|
||||
|
||||
[INFO] Testing compression for 'lzo'
|
||||
|
||||
Level | Time (compress) | Compression Ratio | Time (decompress)
|
||||
-------+-----------------+-------------------+-------------------
|
||||
1 | 0.447 s | 25.677 % | 0.438 s
|
||||
2 | 0.448 s | 25.582 % | 0.438 s
|
||||
3 | 0.444 s | 25.582 % | 0.441 s
|
||||
4 | 0.444 s | 25.582 % | 0.444 s
|
||||
5 | 0.445 s | 25.582 % | 0.453 s
|
||||
6 | 0.438 s | 25.582 % | 0.444 s
|
||||
7 | 8.990 s | 18.666 % | 0.410 s
|
||||
8 | 34.233 s | 18.463 % | 0.405 s
|
||||
9 | 41.328 s | 18.450 % | 0.426 s
|
||||
|
||||
[INFO] Cleaning up...
|
||||
[ OK ] Benchmark complete!
|
||||
|
||||
```
|
||||
|
||||
重要的是在根据脚本得出的数据做决定之前注意这些事情:
|
||||
|
||||
* 不是所有的文件压缩效果都一样好。像图片或电影这种已经压缩过的现代多媒体格式不会压缩得更小。
|
||||
* 脚本压缩和解压缩各一次。对输入重复运行会产生稍微不同的输出。因此,时间应该被理解为是估计,而不是准确的测量。
|
||||
|
||||
|
||||
|
||||
鉴于输出的数据,我决定在我的系统上使用压缩级别 3 的 ztsd 压缩算法。依据你的需求,你可能想使用更高的压缩级别(比如,如果你存储设备相当的慢)。要获得可实现的读/写速度的估计值,可以将源存档大小(约260MB)除以(解)压缩时间。
|
||||
|
||||
压缩测试默认是运行于 GNU libc 2.36 源码。如果你想看看对特定文件的效果,你可以通过第一个参数传递文件路径给脚本。记住文件一定要可以在容器内访问。
|
||||
|
||||
请随意阅读脚本的源码,修改它,如果你想要测试其他东西或者执行更加详细的测试。
|
||||
|
||||
### 配置 Btrfs 压缩
|
||||
|
||||
Btrfs 里的透明文件系统压缩可以在许多方面配置:
|
||||
|
||||
* 作为挂载文件系统的挂载选项(可用于相同 Btrfs 文件系统的所有子卷)
|
||||
* 通过 Btrfs 文件性质
|
||||
* 在 _btrfs filesystem defrag_ 时(不是永久的,不在这里介绍)
|
||||
* 通过 _chattr_ 文件属性接口(不在这里介绍)
|
||||
|
||||
|
||||
|
||||
我只会介绍其中的前两个。
|
||||
|
||||
#### 在挂载时开启压缩
|
||||
|
||||
有一个 Btrfs 挂载选项 可以开启文件压缩:
|
||||
|
||||
```
|
||||
|
||||
$ sudo mount -o compress=<ALGORITHM>:<LEVEL> ...
|
||||
|
||||
```
|
||||
|
||||
例如,去挂载一个文件系统,并使用等级 3 的 _ztsd_ 算法去压缩,你可以写:
|
||||
|
||||
```
|
||||
|
||||
$ sudo mount -o compress=zstd:3 ...
|
||||
|
||||
```
|
||||
|
||||
设置压缩等级是可选的。重要的是注意到 _compress_ 挂载选项应用到整个 Btrfs 文件系统和它所有的子卷。此外,这是目前唯一支持的指定压缩等级的方式。
|
||||
|
||||
为了对文件系统的根应用压缩,必须在 _/etc/fstab_ 上指定。例如,Fedora Linux 安装器,默认启用级别 1的 _zstd_ 压缩,在 _/etc/fstab_ 里是这样:
|
||||
|
||||
```
|
||||
|
||||
$ cat /etc/fstab
|
||||
[ ... ]
|
||||
UUID=47b03671-39f1-43a7-b0a7-db733bfb47ff / btrfs subvol=root,compress=zstd:1,[ ... ] 0 0
|
||||
|
||||
```
|
||||
|
||||
#### 启用单个文件压缩
|
||||
|
||||
另外一种方式指定压缩是通过 Btrfs 文件系统属性。使用下面的命令去阅读对任何文件,目录或子卷的压缩设置
|
||||
|
||||
```
|
||||
|
||||
$ btrfs property get <PATH> compression
|
||||
|
||||
```
|
||||
|
||||
类似的,你可以像这样配置压缩:
|
||||
|
||||
```
|
||||
|
||||
$ sudo btrfs property set <PATH> compression <VALUE>
|
||||
|
||||
```
|
||||
|
||||
例如,对在 _/etc_ 下所有文件启用 _zlib_ 压缩:
|
||||
|
||||
```
|
||||
|
||||
$ sudo btrfs property set /etc compression zlib
|
||||
|
||||
```
|
||||
|
||||
你可以通过 _man btrfs-property_ 得到支持值的列表。记住这个接口不允许指定压缩级别。除此之外,如果一个压缩属性被设置,它覆盖在挂载时的其他压缩配置。
|
||||
|
||||
### 压缩已有文件
|
||||
|
||||
在这时,如果你对现有文件系统采用压缩,然后通过 _df_ 或类似命令检查空间利用率,你会发现什么都没变。这是因为 Btrfs 自身不会 “重新压缩” 所有已有的文件。压缩只会发生在往磁盘写新数据的时候。有一些方式去执行显式的重压缩:
|
||||
|
||||
1. 等待,什么都不做:只要文件被修改并被写回磁盘,Btrfs 根据配置压缩新写入的文件内容。在某个时间点,如果我们等待足够长,越来越多的文件被重写,因此被压缩。
|
||||
2. 移动文件到另一个文件系统然后移动回来:取决于你想压缩哪些文件,这可能是相当乏味的选项。
|
||||
3. 执行一次 Btrfs 碎片整理
|
||||
|
||||
|
||||
|
||||
最后一个选项可能是最方便的,但是它对已经包含快照的 Btrfs 文件系统提出警告:它会破坏快照间的共享范围。换句话来说,两个快照间所有的共享内容,或者一个快照和它的父子卷,在碎片整理操作后将存在多份。
|
||||
|
||||
因此,如果你在你的文件系统里已经有很多快照,你不应该对整个文件系统运行碎片整理。这也没有必要,因为如果你想的话,Btrfs 可以对特定的目录或者单个文件进行碎片整理。
|
||||
|
||||
你可以使用以下命令去执行一次碎片整理:
|
||||
|
||||
```
|
||||
|
||||
$ sudo btrfs filesystem defragment -r /path/to/defragment
|
||||
|
||||
```
|
||||
|
||||
例如,你想像这样去整理你 home 目录的碎片:
|
||||
|
||||
```
|
||||
|
||||
$ sudo btrfs filesystem defragment -r "$HOME"
|
||||
|
||||
```
|
||||
|
||||
如果有疑问,最好从碎片整理单个大文件开始,并在监视文件系统上的可用空间的同时继续处理越来越大的目录。
|
||||
|
||||
### 测量文件系统压缩
|
||||
|
||||
在某些时间点,你想知道得益于文件系统压缩,你节约了多少空间。但你怎样说出来呢?首先,去知道一个 Btrfs 文件系统是否在挂载时启用了压缩,你可以使用以下命令:
|
||||
|
||||
```
|
||||
|
||||
$ findmnt -vno OPTIONS /path/to/mountpoint | grep compress
|
||||
|
||||
```
|
||||
|
||||
如果你得到了结果,在给定挂载点的文件系统使用了压缩!下一步,_compsize_ 命令会告诉你你的文件需要多少空间:
|
||||
|
||||
```
|
||||
|
||||
$ sudo compsize -x /path/to/examine
|
||||
|
||||
```
|
||||
|
||||
在我的 home 目录,结果是这样:
|
||||
|
||||
```
|
||||
|
||||
$ sudo compsize -x "$HOME"
|
||||
Processed 942853 files, 550658 regular extents (799985 refs), 462779 inline.
|
||||
Type Perc Disk Usage Uncompressed Referenced
|
||||
TOTAL 81% 74G 91G 111G
|
||||
none 100% 67G 67G 77G
|
||||
zstd 28% 6.6G 23G 33G
|
||||
|
||||
```
|
||||
|
||||
每一行告诉你应用到文件的压缩 “类型” 。“TOTAL” 是下面所有行的总和。另一方面,列告诉你我们的文件需要多少空间:
|
||||
|
||||
* “Disk Usage” 是实际分配在硬盘上的空间,
|
||||
* “Uncompressed” 是如果没有压缩文件需要的空间,
|
||||
* “Referenced” 是所有未压缩文件加起来的总大小。
|
||||
|
||||
|
||||
|
||||
“Referenced” 可以与数据 “Uncompressed” 不同,比如一个文件之前被重复了,或者有快照共享内容。在上面的例子,你可以看到在我的硬盘上价值 91 GB 的未压缩文件仅占据了 74 GB 的存储。取决于在目录里存储的文件类型和应用的压缩等级,这些数字可以有很大差异。
|
||||
|
||||
### 文件压缩的额外内容
|
||||
|
||||
Btrfs 使用启发式算法去探测压缩文件。这是因为压缩文件通常效果不好,所以没有必要浪费 CPU 周期去尝试进一步的压缩。为了这个目的,Btrfs 在写入压缩数据到磁盘之前测量压缩率。如果文件的第一部分压缩效果不好,文件被标记为不可压缩并且不会有后续的压缩发生。
|
||||
|
||||
如果出于某些原因,你想 Btrfs 压缩所有写入的数据,你可以通过 _compress-force_ 选项挂载一个 Btrfs 文件系统,像这样:
|
||||
|
||||
```
|
||||
|
||||
$ sudo mount -o compress-force=zstd:3 ...
|
||||
|
||||
```
|
||||
|
||||
当像这样配置,Btrfs 会用等级 3 的 _zstd_ 算法压缩所有写入磁盘的数据。
|
||||
|
||||
一个重要的注意事项是挂载一个有很多数据并开启压缩的 Btrfs 文件系统会比没开启压缩耗时更长。这是有技术上的原因,而且这是一个不会影响文件系统操作的正常行为。
|
||||
|
||||
### 总结
|
||||
|
||||
本文详细介绍了 Btrfs 中的透明文件系统压缩。这是一种内置的、相对廉价的方法,可以在不需要修改的情况下从现有硬件中获得一些额外的存储空间。
|
||||
|
||||
本系列文章的下一篇将讨论:
|
||||
|
||||
- Qgroups - 限制文件系统大小
|
||||
- RAID - 替换 mdadm 配置
|
||||
|
||||
|
||||
|
||||
如果您想了解与 Btrfs 相关的其他主题,请查看 Btrfs Wiki [[1]][4] 和文档 [[2]][4]。如果您还没有阅读本系列的前三篇文章,请不要忘记去看看!如果您觉得本文缺少某些内容,请在下面的评论中让我知道。我们下篇文章见!
|
||||
|
||||
### 参考资料
|
||||
|
||||
[1]: <https://btrfs.wiki.kernel.org/index.php/Main_Page>
|
||||
[2]: <https://btrfs.readthedocs.io/en/latest/Introduction.html>
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/working-with-btrfs-compression/
|
||||
|
||||
作者:[Andreas Hartmann][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/A2ureStone)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/hartan/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2023/01/working_w_btrfs_compression-816x345.jpg
|
||||
[2]: https://unsplash.com/@helibertoarias?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/s/photos/hdd?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: tmp.AcVqx2gIro#sources
|
@ -1,204 +0,0 @@
|
||||
[#]: subject: "How to Add Comments in Bash Scripts"
|
||||
[#]: via: "https://itsfoss.com/bash-comments/"
|
||||
[#]: author: "Sagar Sharma https://itsfoss.com/author/sagar/"
|
||||
[#]: collector: "lujun9972/lctt-scripts-1693450080"
|
||||
[#]: translator: "geekpi"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
如何在 Bash 脚本中添加注释
|
||||
======
|
||||
|
||||
在 bash 脚本中添加注释是保持代码整洁且易于理解的最有效方法之一。
|
||||
|
||||
你可能会问为什么。
|
||||
|
||||
假设你的脚本包含一个复杂的正则表达式或多个复杂的代码块,在这种情况下,你可以添加注释,以便其他开发人员或你可以了解该代码块的含义。
|
||||
|
||||
注释掉部分代码也有助于调试脚本。
|
||||
|
||||
在本教程中,我将引导你了解在 bash 脚本中添加注释的三种方法:
|
||||
|
||||
* 单行注释
|
||||
* 行内评论
|
||||
* 多行注释
|
||||
|
||||
|
||||
|
||||
那么让我们从第一个开始。
|
||||
|
||||
### bash 中的单行注释
|
||||
|
||||
要添加单行注释,你必须将 hashtag (#) 放在行的开头并编写注释。
|
||||
|
||||
这是一个简单的例子:
|
||||
|
||||
````
|
||||
|
||||
#!/bin/bash
|
||||
# This is a comment
|
||||
echo "Hello, World!"
|
||||
|
||||
````
|
||||
|
||||
执行时,注释将被忽略,当我执行上面的命令时,它看起来像这样:
|
||||
|
||||
![][1]
|
||||
|
||||
💡
|
||||
|
||||
# 注释规则的唯一例外是脚本开头的 #!/bin/bash 行。它称为[释伴][2],用于指定运行脚本时要使用的解释器。有不同的 shell,语法也可能不同。因此,一个好的做法是指定脚本是为哪个 shell 编写的。例如,如果是 ksh,则可以使用 #!/bin/ksh
|
||||
|
||||
### bash 脚本中的内联注释
|
||||
|
||||
或者,你可以将注释放在代码块内以记录该特定行的用途。
|
||||
|
||||
🚧
|
||||
|
||||
# 之后的任何内容在该行结束之前都不会执行,因此请确保在代码末尾添加注释。
|
||||
|
||||
这是一个简单的例子:
|
||||
|
||||
````
|
||||
|
||||
#!/bin/bash
|
||||
echo "Hello, World!" #Prints hello world
|
||||
|
||||
````
|
||||
|
||||
![][3]
|
||||
|
||||
### bash 中的多行注释
|
||||
|
||||
🚧
|
||||
|
||||
Bash 中没有内置的多行注释功能。但是,有一些解决方法可以实现多行注释效果。
|
||||
|
||||
顾名思义,bash 脚本中的多行注释允许你在多行中编写注释,或者通过将它们放在多行注释部分来阻止执行代码块:
|
||||
|
||||
1. 在每行的开头使用#
|
||||
2. [冒号表示法][4](使用冒号后跟单引号)
|
||||
3. Here 文档(使用 << 后跟分隔符)
|
||||
|
||||
|
||||
|
||||
那么让我们从第一个开始。
|
||||
|
||||
#### 1\. 对块注释的每一行使用 #
|
||||
|
||||
如果你的目的是解释脚本的一部分,我建议使用此方法。毕竟,# 才是真正的注释功能。
|
||||
|
||||
这也是许多开发人员使用的方法。
|
||||
|
||||
假设你必须在一开始就解释脚本的用途、作者信息或许可信息。你可以这样写:
|
||||
|
||||
```
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
######################################
|
||||
## This script is used for scanning ##
|
||||
## local network ##
|
||||
## Licensed under GPL 2.0 ##
|
||||
######################################
|
||||
|
||||
rest of the bash script code
|
||||
|
||||
```
|
||||
|
||||
当你知道 bash 脚本的行为方式时这不错。如果你正在调试 bash 脚本并希望隐藏部分脚本,则在所需代码的每一行开头添加 # 并在调试后将其删除是一项耗时的任务。
|
||||
|
||||
接下来的两节将帮助你做到这一点。
|
||||
|
||||
#### 2\. 冒号表示法
|
||||
|
||||
要使用冒号表示法,请在 `: '` 和结束的 `'` 之间编写块注释,如下所示:
|
||||
|
||||
```
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
: '
|
||||
This is how you can use colon notation
|
||||
And this line too will be ignored
|
||||
'
|
||||
echo "GOODBYE"
|
||||
|
||||
```
|
||||
|
||||
当你执行上面的脚本时,它应该只打印 GOODBYE。
|
||||
|
||||
![][5]
|
||||
|
||||
#### 2\. Here 文档
|
||||
|
||||
到目前为止,这是在 bash 中编写多行注释的最流行的方法,你可以使用 `<<` 后跟分隔符(一组用于指定注释开始和结束的字符)。
|
||||
|
||||
使用方法如下:
|
||||
|
||||
```
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
<<DELIMITER
|
||||
Comment line 1
|
||||
Comment line 2
|
||||
DELIMITER
|
||||
|
||||
echo "Hello, World!"
|
||||
|
||||
```
|
||||
|
||||
还困惑吗? 这是一个简单的例子:
|
||||
|
||||
```
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
<<COMMENT
|
||||
This is a multi-line comment using a here document.
|
||||
You can add as many lines as you want between <<COMMENT and the terminating keyword.
|
||||
This block won't be executed by the shell.
|
||||
COMMENT
|
||||
|
||||
echo "Hello, World!"
|
||||
|
||||
```
|
||||
|
||||
在上面的示例中,我使用了 `COMMENT` 作为分隔符,但你可以使用任何内容,但要确保它从注释中脱颖而出,否则会造成混乱。
|
||||
|
||||
当我执行上面的脚本时,它给出了以下输出:
|
||||
|
||||
![][6]
|
||||
|
||||
正如你所看到的,它忽略了 <<COMMENT 中的所有内容
|
||||
|
||||
### 从头开始学习 bash!
|
||||
|
||||
如果你打算从头开始学习 bash 或者想浏览所有基础知识,我们为你制作了详细的指南:
|
||||
|
||||
![][7]
|
||||
|
||||
我希望本指南对你有所帮助。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/bash-comments/
|
||||
|
||||
作者:[Sagar Sharma][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/sagar/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://itsfoss.com/content/images/2023/10/Use-single-line-comments-in-bash.png
|
||||
[2]: https://linuxhandbook.com/shebang/
|
||||
[3]: https://itsfoss.com/content/images/2023/10/How-to-use-the-single-line-comments-in-bash.png
|
||||
[4]: https://stackoverflow.com/questions/3224878/what-is-the-purpose-of-the-colon-gnu-bash-builtin
|
||||
[5]: https://itsfoss.com/content/images/2023/10/Use-multi-line-comments-using-colon-notation-in-bash.png
|
||||
[6]: https://itsfoss.com/content/images/2023/10/Use-multi-line-comments-in-bash-using----and-delimeter.png
|
||||
[7]: https://itsfoss.com/content/images/size/w256h256/2022/12/android-chrome-192x192.png
|
Loading…
Reference in New Issue
Block a user