Perl文件写入问题

时间:2016-01-30 01:47:26

标签: perl

我对这个perl脚本有一个非常奇怪的问题。基本点是有时文件写入/追加不会发生。在程序运行时,要么所有的写入都会发生,要么都不会。这是子程序,有一些注释:

sub process_svs {
  my $F;
  open($F, '<', $_[0]);
  if($log_dups==1) {
    open($dfh, '>>',"./duplicates.txt");
  }
  while (my $line = <$F>) {
    chomp $line;
    if($line =~ /somepattern/) {
      if (! -e "somefile") {
        copy("source","dest") or warn ("couldn't copy");
      } elsif($log_dups==1) {
        system("touch ./duplicates.txt"); # ghetto workaround
        print $dfh "./".$_[0]."_files/".$1.",v already exists\n" or die("Couldn't write duplicate"); # problem line
      }
    }
  }
  close $F;
}

stdout的print语句总是有效,但如果删除touch ./duplicates.txt垃圾,则不会向duplicates.txt写入任何内容。

另一个“奇怪”的事情是,在程序的早期,我使用perl mkdir创建一个目录,如果程序运行时该目录存在,我需要解决方法,duplicates.txt写作工作正常。如果我删除目录,并让程序mkdir,它不起作用。看起来很相关,但我无法弄清楚由于目录和文本文件不在同一个位置,或以任何方式相关,我能想到的。

此外,我已通过调试器运行它,并且可以看到正在执行的写调用,但在写入后立即检查duplicates.txt没有显示任何内容。

非常感谢任何可能的原因。

如果您想查看经过修改但更完整的脚本版本,请访问:

use strict;
use warnings;
use File::Copy;
my $svs = $ARGV[0];
my $rhis_str = system("rhis $svs > ./tmp_history");
my $fh;
my $dfh;
my @versions;
my $all_revs = 0;
my $current_rev = "";
my $log_dups = 0;
sub process_svs {
  my $F;
  open($F, '<', $_[0]);
  if($log_dups==1) {
    open($dfh, '>>',"./duplicates.txt");
  }
  while (my $line = <$F>) {
    chomp $line;
    if($line =~ /something/) {
      if (! -e "something") {
        copy("source","dest") or warn ("couldn't copy ");
      } elsif($log_dups==1) {
        system("touch ./duplicates.txt"); # ghetto workaround
        print $dfh "something already exists\n" or die("Couldn't write duplicate");
      }
    }
  }
  close $F;
}
for(my $i = 0; $i <= scalar @ARGV; $i++) {
  my $arg = $ARGV[$i];
  if($arg eq "-a") {
    $all_revs = 1;
  } elsif($arg eq "-r") {
    $all_revs = 0;
    $current_rev = $ARGV[$i+1];
  } elsif($arg eq "--log-dups") {
    $log_dups = 1;
  }
}
open($fh, '<','./tmp_history') or die(">>> Failed to open ./tmp_history");;
mkdir "./".$svs."_files";
if($all_revs == 1) {
  print ">>> Processing all revisions of ".$svs;
  if($log_dups==1) {
    print" (and logging duplicates)\n";
  }
  while(my $line = <$fh>) {
    chomp $line;
    if ($line =~ /something/) {
      push @versions, $1;
    }
  }
}
  system("some_cmd &>/dev/null");
  process_svs($svs);
}

1 个答案:

答案 0 :(得分:4)

您没有检查您的文件是否已打开。这是一个非常非常基本的错误,你应该立即解决这个问题。在每个or die $!之后添加open,或者更好的是use autodie,它会为您捕获所有IO异常,并为您提供良好,一致的错误消息。

最重要的是,这会告诉你为什么无法打开。 $!告诉您为什么失败了。你在print的支票上没有这个。

    print $dfh "./".$_[0]."_files/".$1.",v already exists\n" or die("Couldn't write duplicate"); # problem line

您正在检查print是否失败,但您不包括$!。要么添加$! die "Couldn't write to duplicate: $!"use autodie,请删除or die子句,让autodie处理它。我推荐第二个。

我怀疑您会发现其他内容正在打开和打印之间删除duplicates.txt

引起我注意的第二件事就是在这里。

if($log_dups==1) {
  open($dfh, '>>',"./duplicates.txt");
}

您正在使用全局变量$log_dups来决定是否打开文件进行写入(而不是检查文件是否成功)。这应该是一个传递给函数的变量,它只是一个很好的编程实践。稍后您决定是否根据该全局变量打印到$dfh

  if (! -e "something") {
    copy("source","dest") or warn ("couldn't copy ");
  } elsif($log_dups==1) {
    system("touch ./duplicates.txt"); # ghetto workaround
    print $dfh "something already exists\n" or die("Couldn't write duplicate");
  }

由于$log_dups是全球性的,因此可能会在决定打开$log_dups和写入duplicates.txt之间改变$log_dups。为了避免所有这些问题,并使代码更简单,$dfh应该是传递给函数的参数。

此外,文件句柄duplicates.txt莫名其妙地是全局的。同样的问题,其他东西可能会关闭它。它也不会在函数结束时自动关闭,这可能会在程序退出之前将写入$dfh缓冲。 my $rhis_str = system("rhis $svs > ./tmp_history"); 应该是一个词汇。

其他问题......

$rhis_str

rhis将包含./file计划的退出状态。我不认为这就是你想要的。无论如何你都不会使用这个变量。

无需将open传递给file,只需传递$('.validation-summary-errors').append(response.Message.join('<br>')); 即可安全且易于阅读。隐含在当前工作目录中。

如果您修复了这些基本问题并仍然遇到问题,请使用修改后的代码编辑您的问题,我们可以再次查看。