我有一个大约50,000行的文件,我需要检索特定的行。我尝试了以下命令:
sed -n 'Np;Np;Np' inputFile.txt > outputFile.txt
(' N'是特定的行,我想提取)
这样可以正常工作,但是命令会在ORDER中提取行(即它重新输入我的输入)ex。如果我尝试:
sed -n '200p;33p;40,000p' inputFile.txt > outputFile.txt
我得到一个文本文件,其行的顺序为:33,200,40,000(这对我的目的不起作用)。有没有办法维持命令行中出现的顺序?
答案 0 :(得分:13)
你必须坚持到第33行,直到你看到第200行:
sed -n '33h; 200{p; g; p}; 40000p' file
有关详细说明,请参阅手册:https://www.gnu.org/software/sed/manual/html_node/Other-Commands.html
awk
可能更具可读性:
awk '
NR == 33 {line33 = $0}
NR == 200 {print; print line33}
NR == 40000 {print}
' file
如果您要按特定顺序打印任意数量的行,则可以概括为:
awk -v line_order="11 3 5 1" '
BEGIN {
n = split(line_order, inorder)
for (i=1; i<=n; i++) linenums[inorder[i]]
}
NR in linenums {cache[NR]=$0}
END {for (i=1; i<=n; i++) print cache[inorder[i]]}
' file
答案 1 :(得分:4)
perl
的将输入行保存在哈希变量中,行号为键
$ seq 12 20 | perl -nle '
@l = (5,2,3,1);
$a{$.} = $_ if( grep { $_ == $. } @l );
END { print $a{$_} foreach @l } '
16
13
14
12
$.
是行号,grep { $_ == $. } @l
检查数组@l
中是否存在包含所需行所需的行号
作为@l
内的一行BEGIN
声明,以避免每次迭代初始化,并且如果行号超出范围,也确保没有空行:
$ seq 50000 > inputFile.txt
$ perl -nle 'BEGIN{@l=(200,33,40000)} $a{$.}=$_ if(grep {$_ == $.} @l); END { $a{$_} and print $a{$_} foreach (@l) }' inputFile.txt > outputFile.txt
$ cat outputFile.txt
200
33
40000
对于足够小的输入,可以将行保存在数组中并打印所需的索引。请注意,作为索引的调整以0
$ seq 50000 | perl -e '$l[0]=0; push @l,<>; print @l[200,33,40000]'
200
33
40000
使用head
和tail
组合的解决方案:
$ for i in 200 33 40000; do head -"${i}" inputFile.txt | tail -1 ; done
200
33
40000
输入文件seq 50000 > inputFile.txt
$ time perl -nle 'BEGIN{@l=(200,33,40000)} $a{$.}=$_ if(grep {$_ == $.} @l); END { $a{$_} and print $a{$_} foreach (@l) }' inputFile.txt > outputFile.txt
real 0m0.044s
user 0m0.036s
sys 0m0.000s
$ time awk -v line_order="200 33 40000" '
BEGIN {
n = split(line_order, inorder)
for (i=1; i<=n; i++) linenums[inorder[i]]
}
NR in linenums {cache[NR]=$0}
END {for (i=1; i<=n; i++) print cache[inorder[i]]}
' inputFile.txt > outputFile.txt
real 0m0.019s
user 0m0.016s
sys 0m0.000s
$ time for i in 200 33 40000; do sed -n "${i}{p;q}" inputFile.txt ; done > outputFile.txt
real 0m0.011s
user 0m0.004s
sys 0m0.000s
$ time sed -n '33h; 200{p; g; p}; 40000p' inputFile.txt > outputFile.txt
real 0m0.009s
user 0m0.008s
sys 0m0.000s
$ time for i in 200 33 40000; do head -"${i}" inputFile.txt | tail -1 ; done > outputFile.txt
real 0m0.007s
user 0m0.000s
sys 0m0.000s
答案 2 :(得分:3)
你还可以使用其他bash命令吗?在这种情况下,这有效:
for i in 200 33 40000; do
sed -n "${i}p" inputFile.txt
done > outputFile.txt
可能这比在sed中使用数组要慢,但它更实用。