如何遍历perl中的目录

时间:2015-02-01 14:30:02

标签: perl loops

我有一个包含数百个文件的目录dir1,这些文件将由名为HRest的语音程序迭代处理。该程序应该逐个获取每个文件,处理它并将其放在新目录中(如dir2进行第一次迭代),以便在下一次迭代中使用。我的问题是,我不知道我采用的方式来遍历dir1中的文件,以及我运行脚本(trainhmms.pl dir1 1)的方式是否正确。< / p>

如果dir1中的文件是L1,L2,L3,...,L500,我希望HRest执行为

HRest -T 1 -I timedlabels_train.mlf -t -i 20 -l dir1/L1 -M dir2 -S train.scp

表示第一个文件,

HRest -T 1 -I timedlabels_train.mlf -t -i 20 -l dir1/L2 -M dir2 -S train.scp

表示下一个文件,依此类推所有文件。然后在下一次调用脚本时,我希望将其更改为

HRest -T 1 -I timedlabels_train.mlf -t -i 20 -l dir2/L1 -M dir3 -S train.scp

表示第一个文件,依此类推..

这是第一次迭代的脚本:

#!/usr/bin/perl
use File::Slurp;

# Usage: trainhmms.pl dir1 1
# dir1:  Folder containing models after being initialised by HInit (L1,L2,..,L512)

$file = $ARGV[0];
$iter = $ARGV[1];


my @files = read_dir '/Users/negarolfati/Documents/Detection_rerun/AF_TIMIT/1_state//trainHMMs/dir1';

for my $file ( @files ) {


    $iter2 = $iter+1;
    $cmd = "HRest -T 1 -I timedlabels_train.mlf -t -i 20 -l '$dir[$iter]/$file' -M '$dir[$iter2]' -S train.scp ";

    system("$cmd");

}

2 个答案:

答案 0 :(得分:3)

您不能只在目录字符串上使用readdir。您必须opendir字符串,然后从您获得的目录句柄readdir,最后closedir句柄。

您还必须记住readdir返回目录名称和文件名,以及伪目录... 。要仅过滤掉文件,可以使用-f测试运算符。对于您正在阅读的目录,chdir通常最方便,这样您就不必在执行测试之前将readdir返回的每个文件名附加到路径。

我不知道HRest是什么,但如果您的命令行必须从特定的工作目录(可能是acccess timedlabels_train.mlftrain.scp)执行,那么请说明。我将不得不删除chdir声明。

这样的事情会让你前进。我使用了autodie,它自动检查文件系统操作。每次使用chdir时,每次明确检查opendiror die $!都可以节省费用。

#!/usr/bin/perl

use strict;
use warnings;
use autodie;

use File::Spec::Functions 'catdir';

my ($file, $iter) = @ARGV;

my $root = '/Users/negarolfati/Documents/Detection_rerun/AF_TIMIT/1_state/trainHMMs';
my $dir1 = catdir $root, 'dir'.$iter;
my $dir2 = catdir $root, 'dir'.($iter+1);

chdir $dir1;

opendir my ($dh), '.';
my @files = grep -f, readdir $dh;
closedir $dh;

for my $file ( @files ) {

    my $cmd = "HRest -T 1 -I timedlabels_train.mlf -t -i 20 -l '$dir1/$file' -M '$dir2' -S train.scp";

    system($cmd);
}

<强>更新

这是一个避免chdir的替代版本,以便当前工作目录保持不变。

我添加了bash脚本中的辅助循环。我还添加了一个print语句,以便您可以在执行之前查看每个命令。

要允许system调用继续,只需删除或注释掉next语句。

#!/usr/bin/perl

use strict;
use warnings;
use autodie;

use File::Spec::Functions qw/ catdir catfile /;

STDOUT->autoflush;

my $root = '/Users/negarolfati/Documents/Detection_rerun/AF_TIMIT/1_state/trainHMMs';

for my $iter (1 .. 4) {

  my $dir1 = catdir $root, 'dir'.$iter;
  my $dir2 = catdir $root, 'dir'.($iter+1);

  opendir my ($dh), $dir1;

  while (my $node = readdir $dh) {
    my $file = catfile($dir1, $node);
    next unless -f $file;

    my $cmd = "HRest -T 1 -I timedlabels_train.mlf -t -i 20 -l '$file' -M '$dir2' -S train.scp";
    print $cmd, "\n";
    next;               # Remove for full functionality

    system($cmd);
  }

  closedir $dh;
}

答案 1 :(得分:-1)

你可以这样做:

my @files = <$path/*>;
foreach my $filename ( reverse(@files) ) {
...
}