我有一个文件,我想从该文件中提取特定行,如第2,10,15,21 ......等等。从文件中提取大约20万行。我怎样才能在bash中有效地做到这一点
答案 0 :(得分:1)
也许正在寻找: sed -n -e 1p -e 4p afile
答案 1 :(得分:1)
将所需行的亚麻布放在名为“想要”的文件中,如下所示:
2
10
15
21
然后运行此脚本:
#!/bin/bash
while read w
do
sed -n ${w}p yourfile
done < wanted
完全替代方法
或者你可以让“awk”为你做这一切,比如这可能要快几英里,因为你不必创建200,000个sed进程:
awk 'FNR==NR{a[$1]=1;next}{if(FNR in a){print;}}' wanted yourfile
FNR == NR部分检测到awk何时正在读取名为“想要”的文件,如果是,则将数组“a”的元素“$ 1”设置为“1”,因此我们知道该行号是需要的。第二组花括号中的东西在处理较大的文件时是活动的,如果它的亚麻布在我们在读取“想要的”文件时创建的数组“a”中,它会打印当前行。
答案 2 :(得分:1)
$ gawk 'ARGIND==1 { L[$0]++ }; ARGIND==2 && FNR in L' lines file > file.lines
通缉行号必须存储在换行符分隔的lines
中,并且可以安全地按随机顺序排列。它与@Mark Setchell的第二种方法几乎完全相同,但使用更清晰的方法来确定哪个文件是最新的。虽然此ARGIND
是GNU扩展,但gawk
。如果您仅限于原始AWK或mawk
,则可以将其写为:
$ awk 'FILENAME==ARGV[1] { L[$0]++ }; FILENAME==ARGV[2] && FNR in L' lines file > file.lines
效率测试:
$ awk 'BEGIN { for (i=1; i<=1000000; i++) print i }' > file
$ shuf -i 1-1000000 -n 200000 > lines
$ time gawk 'ARGIND==1 { L[$0]++ }; ARGIND==2 && FNR in L' lines file > file.lines
real 0m1.734s
user 0m1.460s
sys 0m0.052s
正如@Costi Ciudatu指出的那样,当所有想要的行都在文件的头部时,这个案子还有空间。
#!/usr/bin/gawk -f
ARGIND==1 { L[$0]++ }
ENDFILE { L_COUNT = FNR }
ARGIND==2 && FNR in L { L_PRINTED++; print }
ARGIND==2 && L_PRINTED == L_COUNT { exit 0 }
当打印最后一行时,Sript会中断,所以现在需要几毫秒来从一百万行文件的前1%中过滤掉2000条随机行。
$ time ./getlines.awk lines file > file.lines
real 0m0.016s
user 0m0.012s
sys 0m0.000s
虽然阅读整个文件仍然需要大约一秒钟。
$ time gawk 'ARGIND==1 { L[$0]++ }; ARGIND==2 && FNR in L' lines file > file.lines
real 0m0.780s
user 0m0.756s
sys 0m0.016s
答案 3 :(得分:0)
如果您的系统支持sed -f -
(即sed
在标准输入上读取其脚本;它适用于Linux,但不适用于其他某些平台)您可以将行号文件转换为sed
脚本,自然使用sed
:
sed 's/$/p/' lines | sed -n -f - inputfile >output
答案 4 :(得分:0)
如果您感兴趣的行靠近文件的开头,则可以使用head
和tail
来有效地提取特定行。
对于您的示例行号(假设列表在接近200,000之前不会继续),读取这些行的虚拟但仍然有效的方法如下:
for n in 2 10 15 21; do
head -n $n /your/large/file | tail -1
done
答案 5 :(得分:-1)
sed示例
sed -n '2p' file
awk示例
awk 'NR==2' file
这将打印第二行文件
在循环中使用相同的逻辑尝试。
说一个for循环
for VARIABLE in 2 10 15 21
do
awk "NR==$VARIABLE" file
done
以这种方式提供您的行号。