Perl 就地编辑产生垃圾
Perl in-place editing produces garbage
我在就地文件编辑方面遇到了问题,我浏览了几个小时的网页却没有结果。
我真的不想使用一般的临时文件方案,即将所有内容写入新文件并替换旧文件一。我需要修改时间戳以反映实际变化,权限和所有权保持不变等
如果我没理解错的话,使用 $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
最直接的方法是使用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;
#!/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";
}
您需要了解 seek
命令以在文件中四处移动。您的文件句柄 FILE
有一个光标。从FILE
读取后,它的光标指向刚刚读取的数据的末尾。然后你在 FILE
上写,你并没有覆盖你刚刚读取的数据,而是覆盖你正要读取的数据。
这是您的文件。第一次打开时,光标在文件开头。
h e l l o \n w o r l d \n f o o \n EOF
^
接下来您使用 <FILE>
操作读取一行输入。将文本 "hello\n" 加载到变量 $_
并移动 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 指出的那样,如果您想在文件中移动时延长或缩短 $_
,这会变得更加复杂。
就地编辑不符合您的要求。它重命名原始文件,然后使用原始名称打开一个新文件。它从重命名的文件中读取并写入原始文件名。 -I
的解释参见perlrun。
我在就地文件编辑方面遇到了问题,我浏览了几个小时的网页却没有结果。
我真的不想使用一般的临时文件方案,即将所有内容写入新文件并替换旧文件一。我需要修改时间戳以反映实际变化,权限和所有权保持不变等
如果我没理解错的话,使用 $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
最直接的方法是使用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;
#!/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";
}
您需要了解 seek
命令以在文件中四处移动。您的文件句柄 FILE
有一个光标。从FILE
读取后,它的光标指向刚刚读取的数据的末尾。然后你在 FILE
上写,你并没有覆盖你刚刚读取的数据,而是覆盖你正要读取的数据。
这是您的文件。第一次打开时,光标在文件开头。
h e l l o \n w o r l d \n f o o \n EOF
^
接下来您使用 <FILE>
操作读取一行输入。将文本 "hello\n" 加载到变量 $_
并移动 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 指出的那样,如果您想在文件中移动时延长或缩短 $_
,这会变得更加复杂。
就地编辑不符合您的要求。它重命名原始文件,然后使用原始名称打开一个新文件。它从重命名的文件中读取并写入原始文件名。 -I
的解释参见perlrun。