快速的Unix命令打印文本文件中不连续的行?

4

给定一个名为“people.txt”的文本文件,其中包含:

Anne
Bob
Carl
Daphne
Erwin
Gary
Heather

我该如何使用sed命令或类似的单行命令,仅指定一组不连续的行号,以过滤内容并得到以下结果:

Bob
Erwin
Heather

(注意:忽略它们按字母顺序排列的事实)

请注意,我使用的真实文件有超过10万行,因此答案应考虑效率。

我知道我可以使用:

sed '5q;d' people.txt 

我希望只获取第5行(“Erwin”),但是否有一种变体的参数可以指定任意行号列表?

我认为这可以仅使用sed实现,但即使阅读了man sed,我也很难弄清楚。我一直在查看其他几个答案,它们非常接近于执行此操作,但几乎所有答案都处理获取单个行或连续行(一系列行),或者使用更复杂的bash脚本;例如,{{link1:“快速unix命令以显示文件中特定行?”}}和{{link2:“如何从Unix文件中打印特定行?”}}。


1
“非连续行号”是什么意思? - anubhava
3个回答

10

您可以按照行号来请求特定的行,就像这样:

sed -n '1p;5p;7p' my_file

-n 标志的意思是“默认情况下不打印行”,然后对于每一行你想要的,你指定行号和 p(打印)命令。


啊,那可能是原帖作者想要的。在看到你的回答之前,我无法理解它 :-) - Fredrik Pihl
太好了,谢谢!我想这只是一些简单的东西。我今天会测试一下,但也许你知道:如果我从一个有200K行的文件中挑选出50K行,这个方法是否有效? - Adam Friedman
好的回答 - 特别是因为它包括了解释正在发生的事情。有些 sed 的特性可能有点难以理解 :)。 - Sobrique

2
$ awk -v lines="2 4 7" 'index(" "lines" "," "NR" ")' file  
Bob
Daphne
Heather

$ awk -v lines="3 5" 'index(" "lines" "," "NR" ")' file  
Carl
Erwin

上面代码中linesNR周围的空格是必需的,这样当lines包含19时,NR9不会匹配。
如果你不介意在脚本中硬编码行号,你也可以这样做:
awk 'NR~/^(2|4|7)$/' file

@AdamKatz - 您昨天对index()参数周围的空白字符所做的修改破坏了上面答案中的脚本,我刚刚不得不将其改回来。请不要编辑我的awk答案,因为我通常知道自己在做什么。如果您认为我发布的答案有误,可以随时给我留言,我会很乐意进行解释或修复。 - Ed Morton
我非常抱歉,这可能是有趣的。在我的测试中,它起作用了。你能解释一下为什么这些引号是必要的吗?他们所做的就是将空格连接到你的行的两端。 - Adam Katz
没问题,你需要始终在NR周围留空格以避免错误匹配(NR=9会误匹配3<空格>19<空格>7中的19,但NR=<空格>9<空格>不会),而且由于你需要在NR周围留空格,所以你需要确保行的开头和结尾始终有一个空格(NR=<空格> 3 <空格>不希望匹配行=3<空格>19<空格>7,但会匹配行= <空格> 3 <空格> 19 <空格> 7 <空格>)。从给定输入集生成预期输出的代码总是很容易编写的,而不会为其他输入产生意外输出的代码则变得复杂。 - Ed Morton
最好不要依赖于脚本的用户在文本中添加空格,而是在脚本内部添加。通常情况下,lines 不会被硬编码 - 如果是这样的话,你根本不需要它,你可以直接将第一个参数硬编码到 index() 中。当 lines 中有两位数(或更多)数字时(例如 19),就会出现故障,因为单个数字 NR(例如 1 或 9)将匹配任何一个数字。在具有 20 行的文件上尝试 awk -v lines="19" 'index(lines,NR)' file,然后尝试 awk -v lines="19" 'index(lines," "NR" ")' file,最后尝试 awk -v lines="19" 'index(" "lines" "," "NR" ")' file - Ed Morton
1
谢谢解释。我没有意识到 index() 是一个子字符串函数。在这种情况下,我可能会建议使用更直接的方式,例如 awk 'NR == 2 || NR == 4 || NR == 7' file,但使用 index() 确实非常聪明。 - Adam Katz
显示剩余2条评论

0
动态生成sed程序:
将要使用的行存储在数组中:
$ lines=(2 5 7)
$ sed -n "$(printf "%dp;" "${lines[@]}")" file
Bob
Erwin
Heather

或者如果行号在文件中:

$ sed -n "$(sed 's/$/p/' numbers)" file

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接