打开通过$ _命令行提供的文件名是否存在问题?

时间:2011-12-18 14:55:35

标签: perl file-io

我无法修改处理作为命令行参数传递的文件的脚本,仅用于复制这些文件,另外修改这些文件。以下perl脚本适用于复制文件:

use strict;
use warnings;

use File::Copy;

foreach $_ (@ARGV) {
   my $orig = $_;
   (my $copy = $orig) =~ s/\.js$/_extjs4\.js/;
   copy($orig, $copy) or die(qq{failed to copy $orig -> $copy});
}

现在我有名为“* _extjs4.js”的文件,我想将这些文件传递给一个脚本,该脚本同样从命令行获取文件名,并进一步处理这些文件中的行。到目前为止,我能够成功获得文件句柄,如下面的脚本,它的输出显示:

use strict;
use warnings;

foreach $_ (@ARGV) {
    print "$_\n";
    open(my $fh, "+>", $_) or die $!;
    print $fh;
    #while (my $line = <$fh>) {
    #    print $line;
    #}
    close $fh;
}

哪些输出(部分):

./filetree_extjs4.js
GLOB(0x1a457de8)
./async_submit_extjs4.js
GLOB(0x1a457de8)

我真正想要做的是打印文件句柄的内容,而不是打印文件句柄的表示。一个开始是打印文件行,我是我试过用上面注释掉的代码。

但是该代码没有效果,文件的行不会打印出来。我究竟做错了什么? $ _用于处理命令行参数和用于处理文件内容的参数之间是否存在冲突?

3 个答案:

答案 0 :(得分:6)

看起来这里有几个问题。


我真正想要做的是打印文件句柄的表示,而不是打印文件句柄的表示。

print $fh返回GLOB(0x1a457de8)的原因是因为标量$fh是文件句柄而不是文件本身的内容。要访问文件本身的内容,请使用<$fh>。例如:

while (my $line = <$fh>) {
    print $line;
}

# or simply print while <$fh>;

将打印整个文件的内容。

pelrdoc perlop中记录了这一点:

  

如果尖括号包含的是一个简单的标量变量(例如,   <$foo>),然后该变量包含文件句柄的名称   输入,或其typeglob,或对它的引用。


但已经尝试过了!

我可以看到。将打开模式更改为+<后尝试。

根据perldoc perlfaq5

  

为什么我打开文件读写会把它擦掉?

     

因为你正在使用这样的东西,它会截断文件   然后给你读写访问权限:

  open my $fh, '+>', '/path/name'; # WRONG (almost always)
     

糟糕。你应该使用它,如果文件将失败   不存在:

  open my $fh, '+<', '/path/name'; # open for update
     

始终使用">" clobbers或创建。使用"<"也不会。该   "+"并未改变这一点。

毫无疑问,强烈建议or die $!之后的open


但退后一步。

有一种更多的Perlish方式来备份原始文件并随后对其进行操作。事实上,它可以通过命令行本身(!)使用-i标志来实现:

$ perl -p -i._extjs4 -e 's/foo/bar/g' *.js

有关详细信息,请参阅perldoc perlrun


我无法满足我的需求。

如果操作对于命令行来说太多了,那么Tie::File模块值得一试。

答案 1 :(得分:1)

要阅读文件句柄的内容,您必须拨打readline read或将文件句柄放在尖括号<>中。

my $line = readline $fh;
my $actually_read = read $fh, $text, $bytes;
my $line = <$fh>; # similar to readline

要打印到STDIN以外的文件句柄,您必须将其作为print的第一个参数,然后是您要打印的内容,而不是它们之间的逗号。

print $fh 'something';

为了防止有人意外添加逗号,我更喜欢将文件句柄放在一个块中。

print {$fh} 'something';

你也可以select你的新手柄。

{
  my $oldfh = select $fh;
  print 'something';
  select $oldfh; # reset it back to the previous handle
}

同样是open的模式参数,会导致它破坏文件的内容。此时没有什么可读的。

请改为尝试:

open my $fh, '+<', $_ or die;

答案 2 :(得分:0)

我想为Zaid提出的使用单线的优秀建议添加一些内容。

当你刚接触perl并尝试一些棘手的正则表达式时,为它们使用源文件会很好,因为命令行可能会变得非常拥挤。即:

文件:

#!/usr/bin/perl
use warnings;
use strict;

s/complicated/regex/g;

在调整正则表达式时,请使用源文件,如下所示:

perl -p script.pl input.js
perl -p script.pl input.js > testfile
perl -p script.pl input.js | less

请注意,测试时不要使用-i标志。这些命令不会更改输入文件,只会将更改打印到stdout。

当您准备好执行(永久!)更改时,只需添加就地编辑-i标记,如果您愿意(推荐),请提供备份扩展,例如名为 “.bak”。

perl -pi.bak script.pl *.js