如何在Linux中显示文本文件中的某些行?


85

我想每个人都知道有用的Linux cmd line实用程序headtailhead允许您打印文件的前X行,tail执行相同操作,但打印文件的末尾。什么是打印文件中间的好命令?类似于middle --start 10000000 --count 20(打印第10'000'至第10'000'010行)。

我正在寻找可以有效处理大型文件的东西。我尝试过tail -n 10000000 | head 10,而且速度非常慢。


Answers:


111
sed -n '10000000,10000020p' filename

您也许可以像这样加快速度:

sed -n '10000000,10000020p; 10000021q' filename

在这些命令中,该选项-n导致sed“禁止自动打印图案空间”。该p命令“打印[S]当前模式空间”和q命令“立即退出[S] sed脚本不处理任何更多的输入......”的报价是从sed man

顺便说一句,您的命令

tail -n 10000000 filename | head 10

从文件末尾的第1 百万行开始,而您的“ middle”命令似乎从文件的第1百万分之一开始,这等效于:

head -n 10000010 filename | tail 10

问题在于,对于具有可变长度行的未排序文件,任何过程都将必须对文件进行换行计数。没有捷径可循。

但是,如果文件已排序(例如,带有时间戳的日志文件)或具有固定长度的行,则可以基于字节位置查找文件。在日志文件示例中,您可以像我的Python脚本*那样一定范围内进行二进制搜索。对于固定记录长度的文件,这确实很容易。您只需要linelength * linecount在文件中查找字符。

*我一直想发布该脚本的另一个更新。也许这几天我会解决它。


这是sedCharles middle函数的一个版本:middle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; }。它将处理多个文件参数,带空格的文件名等。多个文件将像正常处理一样被处理在一起sed(因此,中间的1000 100 file1 file2会跨越第一个文件的末尾到开头(如果第一个少于1100行)。
丹尼斯·威廉姆森

可以使用文件名参数:middle startline count filename或多个文件名:middle startline count file1 file2 file3或重定向:middle startline count < filename或在管道中:some_command | 中间起始行计数`或cat file* | middle startline count
Dennis Williamson

sed命令中的`不应为'吗?我无法将其与反引号一起使用,但单引号可以正常使用。
伊恩·亨特

@beanland:是的,这是一个错字。我已经解决了。谢谢。
丹尼斯·威廉姆森

1
@kev:我在回答中添加了一些解释。
丹尼斯·威廉姆森

28

我发现了以下用途 sed

sed -n '10000000,+20p'  filename

希望对某人有用!


很高兴知道,Dennis提出的最后一个参数行有一个替代:行数作为第二个sed -n参数,使它相当易读。
user3123159

用法示例:extract_lines(){sed -n "$1,+$2p" <file>}写入标准输出。
user3123159

4

这是我第一次在这里发布!无论如何,这很容易。假设您要从名为file.txt的文件中提取第8872行。这是您的操作方式:

cat -n file.txt | grep'^ * 8872'

现在的问题是在此之后找到20行。为此,您要做

cat -n file.txt | grep -A 20'^ * 8872'

有关周围或之前的行,请参见grep手册中的-B和-C标志。


尽管从技术上讲这是正确的,并且是在合理大小的文件上执行此操作的有趣方法,但我对使用海报要求的大小的文件时的效果感到好奇。
珍妮D

多行:cat -n file.txt | grep“ ^ \ s \ +(10 \ | 20 \ | 30)\ s \ +”
Jeffrey Knight

cat -n file.txt | grep '^ *1'产生所有右边有1的行。如何用这种技术输出第1行?我知道我可以-n 1 ....但是如何使用grep?
Sean87 '17

1

丹尼斯的sed答案是正确的方法。但是在bash下仅使用头和尾:

Middle(){head -n $ [$ 1 + $ 2] | 尾-n $ 2; }

这会扫描前$ 1 + $ 2行两次,因此比Dennis的答案差很多。但是您无需记住所有这些sed字母即可使用它。


使用$[...]已过时,至少在猛砸。另外,您缺少文件参数。
丹尼斯·威廉姆森

@Dennis:不丢失任何参数:您应该按照标准在stdin上使用它middle 10 10 < /var/log/auth.log
查尔斯·斯图尔特

1

使用以下命令获取特定范围的行

awk 'NR < 1220974{next}1;NR==1513793{exit}' debug.log | tee -a test.log

在这里debug.log是我的文件,其中缺少行,并且我以前将行号从1220974到1513793的行打印到文件test.log。希望对捕获线段范围有所帮助。


答案与serverfault.com/a/641252/140016相同。不赞成投票。
鹿猎人

答案不一样。对于大型文件,这应该更快,因为它实际上在打印最后一行后中止,而不是继续扫描文件。
恐惧

0

红宝石oneliner版本。

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

对某人可能有用。Dennis和Dox提供的带有“ sed”的解决方案非常好,即使它看起来更快。


0

您可以使用“ nl”。

nl filename | grep <line_num>


0

如果您知道行号,则说您想从文件中获取行1、3和5,请说/ etc / passwd:

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd

0

Perl为王:

perl -ne 'print if ($. == 10000000 .. $. == 10000020)' filename
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.