Contents

在 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命令

cattac一样,这些命令带有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会好得多。而且,随着文件变大,性能差距会越来越大。