Perl就地编辑会产生垃圾

时间:2015-06-23 23:56:11

标签: perl in-place

我在使用就地文件编辑时遇到了问题,浏览网页几个小时没有结果。

我真的 不希望 使用常规临时文件方案,即将所有内容写入新文件并替换旧文件。我 需要 修改时间戳以反映实际更改,权限和所有权以保持不变等。

如果我理解正确,使用$I^只是临时文件示意图的简写 - 或者我错了吗?

“+<”模式应该打开文件进行读写。

到目前为止我的测试代码:

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

open(FILE, "+<", "testingfile") or die "$!";

while (<FILE>) {
    print;
    s/world/WORLD/;
    print FILE $_;
    print;
}

“testingfile”有三行,我现在只想用“WORLD”替换“world”:

hello
world
foo

结果

当我运行Perl脚本时,会产生垃圾,终端会一直挂起,直到被中断(Ctrl + C):

hello
hello
foo
foo
o
o
llo
llo
ÈÈ'>jËNgs}>¾ØKeh%P8*   *        +       +      p+      ÑÑÀ+    +       p+      p+      ¨° #!/u8in/puse ct;
ÈÈ'>jËNgs}>¾ØKeh%P8*   *        +       +      p+      ÑÑÀ+    +       p+      p+      ¨° #!/u8in/puse ct;

“testingfile”现在包含:

hello
world
foo
hello
hello
foo

我在SunOS(Solaris)生产系统上运行旧的Perl:

This is perl, v5.8.4 built for i86pc-solaris-64int

4 个答案:

答案 0 :(得分:3)

最直接的方法是使用Tie::File,它允许您通过简单地修改数组来编辑文本文件。它确实有慢的声誉,但只有自己尝试才能知道它是否太慢

您的示例代码将成为此

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

use Tie::File;

tie my @file, 'Tie::File', 'testingfile' or die $!;

s/world/WORLD/ for @file;

untie @file;

答案 1 :(得分:2)

您需要了解seek命令才能在文件中移动。您的文件句柄FILE只有一个游标。从FILE读取后,其光标指向刚刚读取的数据的末尾。然后你在FILE上写下你并没有覆盖你刚刚阅读的数据,而是你刚要阅读的数据。

这是你的档案。首次打开时,光标位于文件的开头。

 h e l l o \n w o r l d \n f o o \n EOF
^

接下来,您将使用<FILE>操作读取一行输入。这会加载文本&#34;你好\ n&#34;进入变量$_并移动FILE的光标:

 h e l l o \n w o r l d \n f o o \n EOF
             ^

接下来,您的替换失败并且不会更改$_,并且您将$_的内容打印到FILE。写作从光标开始,你得到

 h e l l o \n h e l l o \n f o o \n EOF
                          ^

下次阅读时,在foo\n中获得$_,将光标移动到文件末尾,然后在文件末尾重写$_

 h e l l o \n h e l l o \n f o o \n f o o \n EOF
                                            ^

使用seek命令移动光标。也许像是

open(FILE, "+<", "testingfile") or die "$!";

while (<FILE>) {
    print;
    if (s/world/WORLD/) {
        seek FILE, -length($_), 1;   # move back by length of $_
        print FILE $_;
    }
    print;
}

正如@Borodin指出的那样,如果你想要在浏览文件时延长或缩短$_,这会变得更加复杂。

答案 2 :(得分:1)

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

# getlines
open(FILE, "<", "testingfile") or die "$!";
my @lines = <FILE>;
my $line = "";
close(FILE);

# open file again but this time for writing
open(FILE, ">", "testingfile") or die "$!";

# write adjusted text
foreach $line (@lines) {
    $line =~s/world/WORLD/;
    print FILE "$line";
    print "$line";
}

答案 3 :(得分:0)

就地编辑不会做你正在做的事情。它重命名原始文件,然后打开一个具有原始名称的新文件。它从重命名的文件中读取并写入原始文件名。有关-I的解释,请参阅perlrun