微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我怎样才能打印在Unix文件的特定行?

我想从Unix的文本文件中打印某些行。 要打印的行号列在另一个文本文件中(每行一个)。

一个快速方法来做到这一点与Perl或shell脚本?

Perl:如何将编码添加到PAR打包的压缩文件

Perl使用哪种POSIX正则expression式?

使用Perl DBI模块或设置系统DSN并使用ODBC会更好吗?

如何将Parallel :: ForkManager和Capture :: Tiny一起使用?

产生perl脚本在彩色控制台

假设要打印的行号被排序。

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; }

$ 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

您可以通过在基本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{$.}; } }

猫-n foo | 加入foo2 – | 切-d“”-f2-

其中foo是要打印的行的文件,foo2是行号的文件

这里有一种方法可以在Perl中做到这一点,而不会sl anything任何东西,以使程序的内存占用与两个文件的大小无关(它假定要打印的行号是排序的):

#!/usr/bin/perl use strict; use warnings; use autodie; @ARGV == 2 or die "Supply src_file and filter_file as argumentsn"; 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:>猫过滤器

4

6

10

12

13

19

23

24

28

44

49

50

输出

C:> f src过滤器

广告

AF

AJ

上午

AW

斧头

BB

BR

BW

BX

要处理未排序的过滤器文件,可以修改while循环:

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

如果过滤器文件内容是相当随机的,这将浪费很多时间,因为它会一直倒转到源文件的开头。 在这种情况下,我会建议使用Tie :: File 。

我不会用大文件这样做,但(未经测试):

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;

我会这样做:

#!/bin/bash numbersfile=numbers datafile=data while read lineno < $numbersfile; do sed -n "${lineno}p" datafile done

我的方法不利的一面是,它会产生很多进程,所以它会比其他选项慢。 尽管它可读性更高。

这是一个简短的解决方案,使用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

$猫的输入

一切

$猫线

2

4

$ perl -ne'BEGIN {($ a,$ b)=`cat lines`}如果输入$。== $ a .. $。== $ $ b'

如果这对于一个班轮来说太多了,那就用

#! /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 |'

打印如果$。 == $ start .. $。 == $ stop;

while(<>){

这是使用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 argumentsn"; 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;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐