2010-07-23 114 views
4

我想在Unix中打印來自文本文件的某些行。要打印的行號列在另一個文本文件中(每行一個)。如何在Unix中打印文件中的特定行?

有沒有一個快速的方法來做到這一點與Perl或shell腳本?

+1

這將是很容易在Python中,如果你也接受這種語言。 – 2010-07-23 15:19:08

回答

3

假設行號要打印的排序。

open my $fh, '<', 'line_numbers' or die $!; 
my @ln = <$fh>; 
open my $tx, '<', 'text_file' or die $!; 
foreach my $ln (@ln) { 
    my $line; 
    do { 
    $line = <$tx>; 
    } until $. == $ln and defined $line; 
    print $line if defined $line; 
} 
+1

+1,以便始終使用最佳做法。很好的例子! – Ether 2010-07-23 16:20:55

+0

謝謝,再次感謝您的糾正 – Toto 2010-07-23 17:28:37

0

我不會和大文件做這種方式,但(未經測試):

open(my $fh1, "<", "line_number_file.txt") or die "Err: $!"; 
chomp(my @line_numbers = <$fh1>); 
$_-- for @line_numbers; 
close $fh1; 

open(my $fh2, "<", "text_file.txt") or die "Err: $!"; 
my @lines = <$fh2>; 

print @lines[@line_numbers]; 
close $fh2; 
+0

<3煎餅兔子 – Powerlord 2010-07-23 15:25:42

+0

下面是一個例子: 文件1具有這樣的數據: 安娜 鮑勃 凱西 達倫 文件2具有這樣的: 我想使用文件2以確定哪些行文件1被打印。在這種情況下,我想打印File 2的第2行和第4行,所以我的結果是: Anna Darren 謝謝! – itzy 2010-07-23 15:26:50

+0

嗯,評論的格式並不像預期的那樣...這些文件在每一行中都只有一個單詞或數字。 – itzy 2010-07-23 15:28:11

3
$ cat numbers 
1 
4 
6 
$ cat file 
one 
two 
three 
four 
five 
six 
seven 
$ awk 'FNR==NR{num[$1];next}(FNR in num)' numbers file 
one 
four 
six 
+0

+1不錯,乾淨:) – nico 2010-07-23 15:31:14

+0

爲GNU工具的答案,如何sed? – Cole 2010-07-23 16:22:15

0

我會做這樣的:

#!/bin/bash 
numbersfile=numbers 
datafile=data 

while read lineno < $numbersfile; do 
    sed -n "${lineno}p" datafile 
done 

下行到我的做法是,將產生大量的流程,這樣它會比其他選擇更慢。儘管它可讀性更高。

2

只需在基本while(<>)塊的上下文內使用eof,就可以避免其他一些答案(對排序行的要求)的限制。這會告訴你何時停止讀取行號並開始讀取數據。請注意,您需要在發生切換時重置$.

# Usage: perl script.pl LINE_NUMS_FILE DATA_FILE 

use strict; 
use warnings; 

my %keep; 
my $reading_line_nums = 1; 

while (<>){ 
    if ($reading_line_nums){ 
     chomp; 
     $keep{$_} = 1; 
     $reading_line_nums = $. = 0 if eof; 
    } 
    else { 
     print if exists $keep{$.};  
    } 
} 
0

這是使用bash短溶液和sed

sed -n -e "$(cat num |sed 's/$/p/')" file 

其中num是數字的文件和文件(測試OS/X雪豹)輸入文件

$ cat num 
1 
3 
5 

$ cat file 
Line One 
Line Two 
Line Three 
Line Four 
Line Five 

$ sed -n -e "$(cat num |sed 's/$/p/')" file 
Line One 
Line Three 
Line Five 
1

cat -n foo |加入foo2 - |切-d」「-f2-

其中foo是用線將文件打印和foo2的是你的行號的文件

+0

類似,但可能較慢(文本文件和行是2個文件): cat -n textfile | grep -f lines | cut -d''-f2 – dblu 2010-07-23 22:48:28

+0

那個打印錯誤的東西。如果行文件有3行,它將打印第3,13,23行等等,還有3行恰好是原始輸入的一部分 – frankc 2010-07-23 23:52:41

0
$ cat input 
every 
good 
bird 
does 
fly 

$ cat lines 
2 
4 

$ perl -ne 'BEGIN{($a,$b) = `cat lines`} print if $.==$a .. $.==$b' input 
good 
bird 
does

如果這是太多了一行代碼,使用

#! /usr/bin/perl 

use warnings; 
use strict; 

sub start_stop { 
    my($path) = @_; 
    open my $fh, "<", $path 
    or die "$0: open $path: $!"; 

    local $/; 
    return ($1,$2) if <$fh> =~ /\s*(\d+)\s*(\d+)/; 
    die "$0: $path: could not find start and stop line numbers"; 
} 

my($start,$stop) = start_stop "lines"; 

while (<>) { 
    print if $. == $start .. $. == $stop; 
} 

Perl的魔力開放允許創新的可能性,如

$ ./lines-between 'tac lines-between|' 
    print if $. == $start .. $. == $stop; 
while (<>) { 

1

這裏是一個辦法做到這一點在Perl沒有slurpin克任何從而程序的內存佔用量是獨立於文件的大小的(但是它假定要被打印的行號被排序):

#!/usr/bin/perl 

use strict; use warnings; 
use autodie; 

@ARGV == 2 
    or die "Supply src_file and filter_file as arguments\n"; 

my ($src_file, $filter_file) = @ARGV; 

open my $src_h, '<', $src_file; 
open my $filter_h, '<', $filter_file; 

my $to_print = <$filter_h>; 

while (my $src_line = <$src_h>) { 
    last unless defined $to_print; 
    if ($. == $to_print) { 
     print $src_line; 
     $to_print = <$filter_h>; 
    } 
} 

close $filter_h; 
close $src_h; 

生成源文件:

C:\> perl -le "print for aa .. zz" > src

生成過濾器文件:

C:\> perl -le "print for grep { rand > 0.75 } 1 .. 52" > filter
C:\> cat filter 
4 
6 
10 
12 
13 
19 
23 
24 
28 
44 
49 
50

輸出:

C:\> f src filter 
ad 
af 
aj 
al 
am 
as 
aw 
ax 
bb 
br 
bw 
bx

爲了對付一個未排序的過濾器文件,你可以修改while循環:

while (my $src_line = <$src_h>) { 
    last unless defined $to_print; 
    if ($. > $to_print) { 
     seek $src_h, 0, 0; 
     $. = 0; 
    } 
    if ($. == $to_print) { 
     print $src_line; 
     $to_print = <$filter_h>; 
    } 
} 

如果過濾器文件的內容是相當隨機的,因爲它會保持復卷這會浪費大量的時間到源文件的開頭。在這種情況下,我會建議使用Tie::File

0

這裏是一個辦法做到這一點使用Tie::File

#!/usr/bin/perl 

use strict; use warnings; 
use autodie; 
use Tie::File; 

@ARGV == 2 
    or die "Supply src_file and filter_file as arguments\n"; 

my ($src_file, $filter_file) = @ARGV; 

tie my @source, 'Tie::File', $src_file, autochomp => 0 
    or die "Cannot tie source '$src_file': $!"; 

open my $filter_h, '<', $filter_file; 

while (my $to_print = <$filter_h>) { 
    print $source[$to_print - 1]; 
} 

close $filter_h; 

untie @source; 
相關問題