在 Linux 中反转文本文件或文本流
1. 概述
有时我们有一个需要反转的文本文件。也许它是一个日志文件,我们希望首先在其中查看最新条目。同样,我们也可能希望反转命令的输出。
在本教程中,我们将了解在 Linux 中反转文本文件或文本流的三种不同方法。我们还将比较它们的优势和能力。
2. tac
Linux 的核心理念之一是“一切都是文件”。因此,大多数 Linux 发行版都预先装备好来帮助我们也就不足为奇了。 cat 是输出文件内容的最流行和众所周知的方法之一。另一方面, tac 是一个鲜为人知的命令。它的名字来自cat的倒写, ** tac的作用相当于一个倒转的cat。**
这两个命令都属于*coreutils *包,几乎所有 Linux 发行版都预装了该包。
让我们先用cat看一下我们的测试文件:
$ cat /tmp/test
line_one
line_two
line_three
现在,让我们用tac查看同一个文件:
$ tac /tmp/test
line_three
line_two
line_one
正如我们所见,tac反转了输出。
我们还可以在管道中使用tac来反转命令的输出:
$ cat /tmp/test | tac
line_three
line_two
line_one
tac是反转文件的最直接和最有效的方法。它使用单核,并且它有一个可以很好地完成的工作。
但是,除了它使用的行分隔符和它输出的文件数量之外,它不提供任何配置选项。
3. nl/sort/cut命令
像cat和tac一样,这些命令带有coreutils包,它预装在所有常见的发行版中。sort 、*nl *和cut 命令需要链接在一起才能反转文件。
让我们一次建立一个链,这样我们就可以了解每个命令是如何贡献的。
3.1. nl
为了能够以相反的顺序对文件进行排序,我们需要为每一行创建一个索引。因此,我们使用nl命令将行号放在每行的开头:
$ nl /tmp/test
1 line_one
2 line_two
3 line_three
3.2. sort
现在我们要将这些索引行排序为相反的顺序,我们应该使用sort :
$ nl /tmp/test | sort -nr
3 line_three
2 line_two
1 line_one
默认情况下,sort按词法对行进行排序,并从最小到最大排列它们。我们在这里使用了几个参数来改变它:
- -n - 数字排序
- -r - 倒序
我们还可以添加一些其他参数以获得额外的性能:
- –parallel – 同时运行的排序数
- –batch – 一次处理的最大输入数
- -S - 最大内存排序可以使用
这些参数的最佳值将取决于我们的系统硬件和操作系统限制。
3.3. cut
当我们在流程开始时添加了一个数字索引时,我们需要将其删除以使我们的行恢复其原始形式:
$ nl /tmp/test | sort -nr | cut -f 2-
line_three
line_two
line_one
-f 2-参数告诉cut打印出现在第二个空格之后的字符。在这里,这意味着就在nl命令生成的行号之后。
4. sed
*sed *是一个用于过滤和转换文本的流编辑器。它可以处理最复杂的文本处理任务。
在文本处理方面,sed是一个强大的工具。它可以查找和替换文件 ,删除某些字符之后的所有文本 ,以及做许多其他事情,同时还可以反转我们的文本。
4.1. 安装
sed不是coreutils的一部分,但它预装在大多数主要的 Linux 发行版中。我们也可以自己安装。
使用apt包管理器安装 sed :
$ sudo apt-get install sed
使用yum包管理器安装 sed :
$ sudo yum install sed
4.2. sed脚本反转文件
使用sed反转给定的文本文件:
$ sed '1!G;h;$!d' /tmp/test
line_three
line_two
line_one
sed脚本很难理解,所以让我们解压缩这个。
4.3. sed的子命令
**上面的 one-liner 对每一行应用了三个sed命令。**用分号分隔的命令是:
- 1!G – G 命令将保持空间中的内容附加到模式空间,*1!*确保此命令将忽略第一行
- h - 将模式空间复制到保持空间
- $!d – 删除该行,$! 确保此命令将忽略最后一行
有关更多信息,请查看我们关于sed 及其不同空间的深入指南。
5. 方法之间的比较
让我们比较一下我们学到的方法。
5.1. 每日表现
为了进行测试,我们将使用一个 100,000 行、大小为 6.6 兆字节的文件:
$ wc -l test
100000 test
$ du -h test
6,6M test
让我们在跟踪时间的同时用tac反转这个文件:
$ time tac test
...
...
...
real 0m0,571s
user 0m0,004s
sys 0m0,086s
tac在大约半秒内完成任务。
现在,让我们用nl sort和 cut做同样的测试:
$ time nl test | sort -nr | cut -f 2-
...
...
...
real 0m1,063s
user 0m0,122s
sys 0m0,236s
完成此命令只需一秒钟多一点。现在,让我们在具有 1 GB 内存和 1021 批次的多核上运行它:
$ time nl test | sort -nr -S 1G --parallel=7 --batch=1021 | cut -f 2-
...
...
...
real 0m0,882s
user 0m0,130s
sys 0m0,194s
现在只需要不到一秒钟。这不是一个很大的改进。
现在,让我们为sed命令计时:
$ time sed '1!G;h;$!d' test
...
...
...
real 0m54,336s
user 0m53,802s
sys 0m0,104s
这是迄今为止最糟糕的结果。我们不会用它来提高速度。但是,使用sed的重点在于其先进的文本处理能力。
结果表明, 就日常任务的性能而言, tac显然是赢家。那么,排序方法有什么好处吗?
5.2. 大数据性能
sort可以同时使用多个内核,当我们在功能强大的工作站上处理大量文件时, sort 的真正威力就会发挥作用。 让我们处理以下文件:
$ du -h megafile
54G megafile
$ wc -l megafile
1000000000 megafile
该文件有 1,000,000,000 行,大小为 54 GB。
$ time tac megafile >> /dev/null
real 13m5.686s
user 0m59.028s
sys 0m47.556s
tac在 13 分 5 秒内完成任务。
让我们尝试使用 23 个内核和 200 GB RAM 进行排序:
$ time nl megafile | sort -S 200G -nr --parallel=23 --batch=1021 | cut -f 2- >> /dev/null
real 6m34.510s
user 9m47.677s
sys 3m1.545s
tac显然总体上使用更少的资源,即使它需要更长的时间。
但是,如果我们需要在庞大的数据集上尽快完成任务,sort会好得多。而且,随着文件变大,性能差距会越来越大。