【问题标题】:Perl script to search a word inside the directory用于在目录中搜索单词的 Perl 脚本
【发布时间】:2022-07-31 15:39:10
【问题描述】:

我正在寻找一个 perl 脚本来 grep 目录内所有文件中的字符串。

bash 命令。 代码: grep -r 'word' /path/to/dir

【问题讨论】:

  • grep 命令有什么问题?还有,关于“寻找perl脚本”,你写到什么程度了?有什么特别的问题吗?
  • 我必须从 html 表单中获取用户输入并在目录中搜索该单词,因此无法使用 grep.@zdim
  • 对于递归搜索(grep 命令中的-r)使用File::FindFile::Find::Rule 递归遍历所有文件,然后打开每个文件并逐行搜索短语。或者,所有这些都可以通过Path::Tiny 完成
  • 这种重复关闭完全没有意义——答案甚至不是递归的。至少找到一个真正的骗子,并且有更好的答案(我在发布之前搜索过)......投票重新开放。

标签: linux bash shell perl


【解决方案1】:

这是一项相当规范的任务,而我无法使用可能最简单的工具找到直接的答案,方便的Path::Tiny

use warnings;
use strict;
use feature 'say';

use Data::Dump;  # dd
use Path::Tiny;  # path 

my $dir = shift // '.';

my $pattern = qr/word/;

my $ret = path($dir)->visit( 
    sub { 
        my ($entry, $state) = @_; 
        return if not -f; 
     
        for ($entry->lines) {
            if (/$pattern/) {
                print "$entry: $_";
                push @{$state->{$entry}}, $_;  
            }   
        }   
    },  
    { recurse => 1 } 
); 

dd $ret;  # print the returned complex data structure

此处使用lines 读取文件的方式只是实现此目的的一种方式。它可能不适合非常大的文件,因为它一次读取所有行,最好逐行读取。

visit 方法基于iterator,同样干净利落地完成了这项任务

my $iter = path($dir)->iterator({ recurse => 1 });

my $info;

while (my $e = $iter->()) { 
    next if not -f $e; 
    
    # process the file $e as needed
    #/$pattern/ and push @{$info->{$e}}, $_ and print "$e: $_" 
    #    for $e->lines 
} 

这里我们必须提供一个数据结构来积累信息,但我们获得了更大的灵活性。

上面使用的-f filetest 是一个“普通”文件,仍然有些宽松;例如,它允许交换文件,某些编辑器在会话期间保留这些文件(例如 vim)。这些将导致各种匹配。要保留纯 ASCII 或 UTF-8 文件,请使用 -T 测试。

如果程序最终使用 input 作为正则表达式中的模式,那么请非常小心。


否则,还有用于递归遍历和搜索的库,例如File::Find(或File::Find::Rule)或Path::Iterator::Rule

为了完整起见,这里是核心File::Find

use warnings;
use strict;
use feature 'say';    

my $dirs_csv = shift // '.';        
my @dirs = split /,/, $dirs_csv;

my $pattern = qr/word/;

my %res;
find( sub {
        return if not -T;  # ASCII or UTF-8 only

        open my $fh, '<', $_ or do {
            warn "Error opening $File::Find::name: $!";
            return;
        };

        while (<$fh>) { 
            if (/$pattern/) { 
                chomp;
                push @{$res{$File::Find::name}}, $_
            }
        }
    }, @dirs
);

for my $k (keys %res) { 
    say "In file $k:";
    say "\t$_" for @{$res{$k}};
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-06
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 2013-04-10
    • 2013-09-26
    相关资源
    最近更新 更多