【问题标题】:Process files by extension instead of individually按扩展名而不是单独处理文件
【发布时间】:2013-11-15 01:52:48
【问题描述】:

我有多个扩展名为 .tdx 的文件。

目前我的程序使用$ARGV[0] 处理单个文件,但是文件数量正在增长,我想使用基于文件扩展名的通配符。

经过大量研究,我不知所措。

我想单独读取每个文件,以便用户识别文件中的提取。

#!C:\Perl\bin\perl.exe

use warnings;

use FileHandle;

open my $F_IN,  '<', $ARGV[0]     or die "Unable to open file: $!\n";
open my $F_OUT, '>', 'output.txt' or die "Unable to open file: $!\n";

while (my $line = $F_IN->getline) {
  if ($line =~ /^User/) {
    $F_OUT->print($line);
  }
  if ($line =~ /--FTP/) {
    $F_OUT->print($line);
  }
  if ($line =~ /^ftp:/) {
    $F_OUT->print($line);
  }
}
close $F_IN;
close $F_OUT;

所有文件都在一个目录中,所以我假设我需要打开该目录。

我只是不确定是否需要构建一个文件数组或构建一个列表并将其切碎。

【问题讨论】:

  • 我猜您是在 Windows 环境中执行此操作...您有类似 xargs 的工具吗?
  • 你想如何指定应该处理的文件集合?

标签: perl


【解决方案1】:

你有很多选择——

  1. 循环@ARGV,允许用户传入文件列表
  2. 使用glob 传递一个模式,perl 将扩展为一个文件列表(然后循环该列表,如#1 中所示)。这可能会很混乱,因为他们必须确保引用它,这样 shell 才不会首先插入它。
  3. 编写一些包装器来一遍又一遍地调用您现有的脚本。

还有第一个的变体,从&lt;&gt; 读取。这设置为 STDIN,或者它会自动打开以@ARGV 命名的文件。有关如何使用它的示例,请参阅eof

作为#2 的变体,您可以传入一个目录名称,并使用opendirreaddir 循环遍历列表(确保只抓取带有您的扩展名的文件,或者至少忽略...) 或附加 /*/*.tdx 并再次使用 glob

【讨论】:

  • 还有更多的可能性,而你的处方还为时过早。
  • @Borodin :对.. 我没有提到将它传递到目录中并从那里读取列表(或使用glob 来做)。如果我错过了其他人,请随时留下您自己的问题答案。
【解决方案2】:

glob 函数可以帮助您。试试看

my @files = glob '*.tdx';
for my $file (@files) {
    # Process $file...
}

在列表上下文中,glob 将其参数扩展为与模式匹配的文件名列表。详情请见glob in perlfunc

【讨论】:

  • 您应该描述它做了什么,并解释它解决了对所述问题的多种可能解释中的哪一种。
【解决方案3】:

我从来没有得到 glob 的工作。我最终做的是基于文件扩展名 .tdx 构建一个数组。从那里我将数组复制到文件列表并从中读取。我最终得到的是:

#!C:\Perl\bin\perl.exe
use warnings;
use FileHandle;
open my $F_OUT, '>', 'output.txt' or die "Unable to open file: $!\n";
open(FILELIST, "dir /b /s \"%USERPROFILE%\\Documents\\holding\\*.tdx\" |");
@filelist=<FILELIST>;
close(FILELIST);
foreach $file (@filelist)
            {
            chomp($file);
            open my $F_IN,  '<', $file     or die "Unable to open file: $!\n";
            while (my $line = $F_IN->getline) 
              {
Doing Something
              }
            close $F_IN;
            }
close $F_OUT;

感谢您在学习过程中提供的帮助。

【讨论】:

    【解决方案4】:

    如果您使用的是 Windows 计算机,则在命令行中输入 *.tdx 可能不起作用,过去使用 shell 的通配能力的 glob 也可能不起作用。 (现在看来,内置的glob 函数现在使用File::Glob,所以这可能不再是问题。

    您可以做的一件事是不要使用 glob,而是允许用户输入他们想要的目录和后缀。然后使用opendirreaddir 自己浏览目录。

    use strict;
    use warnings;
    use feature qw(say);
    use autodie;
    use Getopt::Long;      # Why not do it right?
    use Pod::Usage;        # It's about time to learn about POD documentation
    
    my @suffixes;  # Hey, why not let people put in more than one suffix?
    my @directories;       # Let people put in the directories they want to check
    my $help;
    
    GetOptions (
        "suffix=s"     => \@suffixes,
        "directory=s"  => \@directories,
        "help"         => \$help,
    ) or pod2usage ( -message => "Invalid usage" );
    
    if ( not @suffixes ) {
        @suffixes = qw(tdx);
    }
    
    if ( not @directories ) {
        @directories = qw(.);
    }
    
    if ( $help ) {
        pod2usage;
    }
    
    my $regex = join, "|",  @suffixes;
    $regex = "\.($regex)$";   #  Will equal /\.(foo|bar|txt)$/ if Suffixes are foo, bar, txt
    
    for my $directory ( @directories ) {
        opendir my ($dir_fh), $directory;   # Autodie will take care of this:
        while ( my $file = readdir $dir_fh ) {
            next unless -f $file;
            next unless $file =~ /$regex/;
            ... Here be dragons ...
        }
    }
    

    这将遍历用户输入的所有目录,然后检查每个条目。它使用用户输入的后缀(.tdx 是默认值)来创建正则表达式来检查文件名。如果文件名与正则表达式匹配,请对该文件执行任何您想要执行的操作。

    【讨论】:

      猜你喜欢
      • 2020-03-30
      • 1970-01-01
      • 1970-01-01
      • 2018-02-26
      • 2014-08-13
      • 2021-04-11
      • 2017-01-27
      • 2011-03-14
      • 1970-01-01
      相关资源
      最近更新 更多