我有一个~23000行的SQL转储,其中包含几个数据库的数据价值。我需要提取这个文件的某个部分(即单个数据库的数据),并将其放在一个新文件中。我知道我想要的数据的开始行号和结束行号。

谁知道一个Unix命令(或一系列命令)可以从文件中提取16224到16482行之间的所有行,然后将它们重定向到一个新文件中?


当前回答

我已经为sed、perl、head+tail和我自己的awk代码编译了一些最高评级的解决方案,并通过管道关注性能,同时使用LC_ALL=C确保所有候选程序以尽可能快的速度运行,并在两者之间分配2秒的睡眠间隔。

差距是显而易见的:

   abs time    awk/app speed ratio
 ----------------------------------
   0.0672 sec :   1.00x mawk-2
   0.0839 sec :   1.25x gnu-sed
   0.1289 sec :   1.92x perl
   0.2151 sec :   3.20x gnu-head+tail

还没有机会测试这些工具的python或BSD变体。

 (fg && fg && fg && fg) 2>/dev/null; 
 echo;
 ( time ( pvE0 < "${m3t}" 
        | LC_ALL=C  mawk2 '

           BEGIN {  
                     _=10420001-(\
                    __=10420256)^(FS="^$") 
           } _<NR { 
                   print

                   if(__==NR) { exit } 
     
     }' ) | pvE9) | tee >(xxh128sum >&2) | LC_ALL=C gwc -lcm | lgp3 ; 
    sleep 2;
    (fg && fg && fg && fg) 2>/dev/null
    echo; 
    ( time ( pvE0 < "${m3t}" 
           | LC_ALL=C gsed -n '10420001,10420256p;10420256q' 
    
     ) | pvE9 ) |  tee >(xxh128sum >&2) |  LC_ALL=C gwc -lcm  | lgp3 ;
     sleep  2; (fg && fg && fg && fg) 2>/dev/null
     echo
    ( time ( pvE0 < "${m3t}" 
           | LC_ALL=C perl -ne 'print if 10420001..10420256'
    
    ) | pvE9 ) |  tee >(xxh128sum >&2) |  LC_ALL=C gwc -lcm | lgp3 ;
    sleep  2; (fg && fg && fg && fg) 2>/dev/null
    echo
    ( time ( pvE0 < "${m3t}" 
           | LC_ALL=C ghead -n +10420256 
           | LC_ALL=C gtail -n +10420001 
    ) | pvE9 ) |  tee >(xxh128sum >&2) |  LC_ALL=C gwc -lcm  | lgp3 ; 


      in0: 1.51GiB 0:00:00 [2.31GiB/s] [2.31GiB/s] [============> ] 81%            
     out9: 42.5KiB 0:00:00 [64.9KiB/s] [64.9KiB/s] [ <=> ]
( pvE 0.1 in0 < "${m3t}" | LC_ALL=C mawk2 ; )
     
   0.43s user 0.36s system 117% cpu 0.672 total
    256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin

     out9: 42.5KiB 0:00:00 [51.7KiB/s] [51.7KiB/s] [ <=> ]
      in0: 1.51GiB 0:00:00 [1.84GiB/s] [1.84GiB/s] [==========> ] 81%            

   ( pvE 0.1 in0 < "${m3t}" |LC_ALL=C gsed -n '10420001,10420256p;10420256q'; )  
  
   0.68s user 0.34s system 121% cpu 0.839 total
    256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin


      in0: 1.85GiB 0:00:01 [1.46GiB/s] [1.46GiB/s] [=============>] 100%            
     out9: 42.5KiB 0:00:01 [33.5KiB/s] [33.5KiB/s] [  <=> ]

( pvE 0.1 in0 < "${m3t}" | LC_ALL=C perl -ne 'print if 10420001..10420256'; )
     
   1.10s user 0.44s system 119% cpu 1.289 total
    256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin

      in0: 1.51GiB 0:00:02 [ 728MiB/s] [ 728MiB/s] [=============> ] 81%            
     out9: 42.5KiB 0:00:02 [19.9KiB/s] [19.9KiB/s] [ <=> ]

 ( pvE 0.1 in0 < "${m3t}" 
   | LC_ALL=C ghead -n +10420256 
   | LC_ALL=C gtail -n ; )  
  
 1.98s user 1.40s system 157% cpu 2.151 total
 256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin

其他回答

站在拳击手的肩膀上,我喜欢这样:

sed -n '<first line>,$p;<last line>q' input

e.g.

sed -n '16224,$p;16482q' input

$表示“最后一行”,因此第一个命令使sed打印从第16224行开始的所有行,第二个命令使sed在打印第16428行之后退出。(在boxxar的解决方案中,为q范围添加1似乎没有必要。)

我喜欢这个变体,因为我不需要两次指定结束行号。而且我认为使用$不会对性能产生不利影响。

我们甚至可以在命令行检查:

cat filename|sed 'n1,n2!d' > abc.txt

例如:

cat foo.pl|sed '100,200!d' > abc.txt
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

使用head/tail非常简单:

head -16482 in.sql | tail -258 > out.sql

使用sed:

sed -n '16224,16482p' in.sql > out.sql

使用awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

艾德:使用

ed -s infile <<<'16224,16482p'

-s抑制诊断输出;实际的命令在一个here-string中。具体来说,16224,16482p在所需的行地址范围上运行p (print)命令。