如何在Linux中读取文件中特定的一行?


在使用Linux shell时,读取文本文件通常是一个重要的操作。有时,我们可能只对读取文件中的特定一行感兴趣。

我们将看看从文件中获取特定文本的不同方法。

实际问题

让我们来看一个例子。

假设我们有一个名为“test.txt”的文件:

$ nl test.txt
1 This is line 1, I don't have any interesting data.
2 This is line 2, I don't have any interesting data.
3 This is line 3, I don't have any interesting data.
4 This is line 4, I don't have any interesting data.
5 This is line 5, interesting data: Linux is awesome!
6 This is line 6, I don't have any interesting data.
7 This is line 7, I don't have any interesting data.

我们使用nl函数显示带有行号的文本文件内容。

我们知道前四行包含一些有趣的信息。因此,我们只想读取第五行。

在Linux命令行中有很多方法可以做到这一点。在本指南中,我们将介绍四种不同的方法:

  • 使用Bash命令

  • 使用sed命令

  • 使用awk命令

  • 使用headtail命令

让我们来看一些例子。

使用Bash命令

为了解决这个问题,我们需要编写一个名为getLine的shell脚本。

$ cat getLine.sh
#!/bin/bash
FILE="$1"
LINE_NO=$2
i=0
while read line; do
   i=$(( i + 1 )
   test $i = $LINE_NO && echo "$line";
done <"$FILE"

上面的shell脚本接受两个参数:文件名和目标行号。

基本上,它包含一个段落。我们首先将$i的值设置为零。然后我们检查当前行是否与我们目标的行(第十行)匹配。如果是,我们将$i加1。否则,我们将打印当前行。

命令

$ ./getLine.sh test.txt 5

输出

This is line 5, interesting data: Linux is awesome!

结果显示我们的脚本运行成功。

如果我们仔细阅读文本,我们可能会改进它。

我们在循环中检查字符串中的每一个字符,即使我们已经找到并打印了我们想要的字符。实际上,我们可能在找到我们想要的内容之前处理了大量数据。但是,让我们坚持这个例子!我们的示例输入只有七行。然而在现实世界中,您的输入可能包含数百万行。

因此,如果我们能够在找到正确的行后退出循环,那就太好了。所以,让我们稍微修改一下脚本:

$ cat getLine2.sh
#!/bin/bash
FILE="$1"
LINE_NO=$2
i=0
while read line; do
   i=$(( i + 1 ))
   case $i in $LINE_NO) echo "$line"; break;; esac done <"$FILE"

我们使用case语句在找到我们想要的行时停止循环。让我们看看它是否有效:

命令

$ ./getLine2.sh test.txt 5

输出

This is line 5, interesting data: Linux is awesome!

我们通过使用一些bash脚本解决了这个问题。

使用sed命令

sed命令非常擅长解决这类问题。这里有两个简洁的sed单行命令可以完成这项工作。

命令

$ sed '5!d' test.txt

输出

This is line 5, interesting data: Linux is awesome!

命令

$ sed -n '5p' test.txt

输出

This is line 5, interesting data: Linux is awesome!

要删除目录中除第五行(也是唯一一行)以外的所有行,请使用以下命令:5!d 要只显示第五行(也是唯一一行),请使用以下命令:-n '5p'

这两个单行脚本按预期运行。但是,它们会逐行读取整个输入,这对于大型文件来说花费的时间太长。

shell脚本提供了一个“q”(退出)选项来退出进一步的执行。因此,我们可以使用“&&”运算符将这两个命令组合成一行:

命令

$ sed '5!d;q' test.txt

输出

This is line 5, interesting data: Linux is awesome!

命令

$ sed -n '5{p;q}' test.txt

输出

This is line 5, interesting data: Linux is awesome!

我们没有注意到两个输出之间的任何差异,因此让我们使用sed -e's/^.*$//'命令删除从每一行开头到行尾的所有内容。

让我们首先快速浏览一下没有“q”命令的版本。

命令

$ sedsed -d '5!d' test.txt

输出

PATT:This is line 1, I don't have any interesting data.$
HOLD:$
COMM:5 !d
PATT:This is line 2, I don't have any interesting data.$
...
This is line 5, interesting data: Linux is awesome!
PATT:This is line 6, I don't have any interesting data.$
HOLD:$
COMM:5 !d
PATT:This is line 7, I don't have any interesting data.$
HOLD:$
COMM:5 !d

然后我们可以看到sed命令已经从第一个字符处理到最后一个字符(第七个字符)。

我们现在将使用q测试sed命令。

命令

$ sedsed -d '5!d;q' test.txt

输出

PATT:This is line 1, I don't have any interesting data.$
HOLD:$
COMM:5 !d
PATT:This is line 2, I don't have any interesting data.$
...
PATT:This is line 5, interesting data: Linux is awesome!$
HOLD:$
COMM:q
This is line 5, interesting data: Linux is awesome!

调试输出表明sed处理在第5行停止。

使用awk命令

另一个强大的文本处理工具是awk。您可以使用它用一行代码来解决问题:awk 'NR == 5' input.txt。

我们不想在打印第5行后继续处理。

类似地,awk也有“quit”命令来退出当前处理。

命令

$ awk 'NR==5{ print; exit }' test.txt

输出

This is line 5, interesting data: Linux is awesome!

因此,如输出所示,我们已经解决了这个问题。

使用headtail命令

我们可以使用`tail`命令提取文本文档的最后部分。

我们还可以使用这两个命令的组合来读取特定行。

让我们假设我们要读取x行。思路是:

  • 我们首先使用head命令从输入文件中获取第1行到第X行。

  • 然后我们将第一步的输出通过管道传递到tail命令以检索最后一个条目:head -n X input | tail -1

让我们看看这个想法对我们的例子是否有效:

命令

$ head -n 5 test.txt | tail -1

输出

I am line 5, interesting data: Linux is awesome!

我们得到了预期的结果,并且我们解决了这个问题。

结论

我们讨论了在Linux中从输入文件读取单行的不同方法。

我们讨论了如何提高bash、awk和/或sed解决方案的性能。

更新于:2022年12月1日

15K+ 次浏览

启动你的职业生涯

通过完成课程获得认证

开始
广告
© . All rights reserved.