Perl:用list中的值替换文本字符串(文本文件或标量上下文)

时间:2013-03-25 10:07:14

标签: perl list foreach substitution

我是一个perl新手,但是已经读过Schwartz,foy和Phoenix的“Learning Perl”并对该语言的理解不足。即使在使用书籍和网络之后,我仍在苦苦挣扎。

我的目标是能够做到以下几点:

  1. 搜索特定文件夹(当前文件夹)并使用完整路径获取文件名。使用完整路径和当前foldername保存文件名。

  2. 打开一个模板文件并在特定位置插入带有完整路径的文件名(例如使用替换)以及当前的foldername(在同一文本文件中的另一个位置,我还没有到目前为止)。

  3. 将新修改的文​​件保存到特定位置(当前文件夹)中的新文件。

  4. 我有许多文件/文件夹要处理,并计划将perl程序复制到每个文件夹中,以便perl程序可以创建新文件。

    我到目前为止......:

    use strict;
    use warnings;
    use Cwd;
    use File::Spec;
    use File::Basename;
    my $current_dir = getcwd;
    open SECONTROL_TEMPLATE, '<secontrol_template.txt' or die "Can't open SECONTROL_TEMPLATE: $!\n";
    my @secontrol_template = <SECONTROL_TEMPLATE>;
    close SECONTROL_TEMPLATE;
    opendir(DIR, $current_dir) or die $!;
    my @seq_files = grep {
        /gz/
        } readdir (DIR);
    open FASTQFILENAMES, '> fastqfilenames.txt' or die "Can't open fastqfilenames.txt: $!\n";
    my @fastqfiles;
    foreach (@seq_files) {
        $_ = File::Spec->catfile($current_dir, $_);
        push(@fastqfiles,$_);
    }
    print FASTQFILENAMES @fastqfiles;
    open (my ($fastqfilenames),  "<", "fastqfilenames.txt") or die "Can't open fastqfilenames.txt: $!\n";
    my @secontrol;
    foreach (@secontrol_template) {
        $_ =~ s/@/$fastqfilenames/eg;
        push(@secontrol,$_);
    }
    open SECONTROL, '> secontrol.txt' or die "Can't open SECONTROL: $!\n";
    print SECONTROL @secontrol;
    close SECONTROL;
    close FASTQFILENAMES;
    

    我的问题是我无法弄清楚如何使用我的文件列表替换模板文本文件中的“@”:

    my @secontrol;
    foreach (@secontrol_template) {
        $_ =~ s/@/$fastqfilenames/eg;
        push(@secontrol,$_);
    }
    

    替换函数不会将“@”替换为$ fastqfilenames中列出的文件列表。我将“@”替换为GLOB(0x8ab1dc)。

    我这样做是错误的吗?我不应该使用替代品,因为这不能做,然后在template.txt文件中插入文件列表($ fastqfilenames)?我可以用文件内容(例如s / A / {r file.txt ...)替换$ fastqfilenames而不是$ fastqfilenames。有什么建议吗?

    干杯,

    JamesT

    修改

    这使一切变得更好。

    foreach (@secontrol_template) {
        s/@/$fastqfilenames/g;
        push @secontrol, $_;
    }
    

    作为两个建议,$ fastqfiles是一个文件句柄。

    替换了这个: open(my($ fastqfilenames),“&lt;”,“fastqfilenames.txt”)或者死掉“无法打开fastqfilenames.txt:$!\ n”;

    用这个:

    my $fastqfilenames = join "\n", @fastqfiles; 
    

    一切都很好。谢谢你们两个。

2 个答案:

答案 0 :(得分:0)

$fastqfilenames是一个文件句柄。您必须先从文件句柄中读取信息,然后才能使用它。

但是,您还有其他问题。

您正在将所有文件名打印到文件中,然后将其从文件中读回。这不仅是一个有问题的设计(为什么再次从文件中读取,因为你已经拥有了数组中你需要的东西?),它甚至不会工作:

出于性能原因,Perl缓冲文件I / O.您写入文件的行可能实际上还没有,因为Perl正在等待,直到它保存了大量数据,才能一次写入。

您可以通过几种不同的方式覆盖此缓冲行为(如果您已完成写入,则关闭文件句柄是最简单的),但正如我所说,没有理由再次重新打开文件并从中读取它

另请注意,正则表达式替换中的/e选项会将替换值评估为Perl代码。在您的情况下,这不是必需的,因此您应该将其删除。

解决方案:只需使用您在模板中替换时创建的@fastqfiles变量,而不是重新打开文件并将其读取。用文件名替换@并不清楚你的意思。

  • 您是否要将每个@替换为所有文件名列表?如果是这样,在替换之前,您可能需要以某种方式join the filenames

  • 您是否要为每个文件名创建单独的模板文件版本?如果是这样,您需要一个内部for循环遍历每个模板的每个文件名。而且你需要的不仅仅是一个简单的替换,因为替换将在第一次改变原始字符串。如果您使用的是Perl 5.16,则可以使用/r选项非破坏性地替换:push(@secontrol,s/@/$file_name/gr);否则,您应该在替换之前复制到另一个变量。

答案 1 :(得分:0)

$_ =~ s/@/$fastqfilenames/eg;

$fastqfilenames是文件句柄,而不是文件内容。

无论如何,我建议使用Text::Template模块来完成这种工作(文件替换)。