就地编辑时读取整个文件然后打印?
就地编辑的大多数示例都是单行代码,它循环访问一个或多个文件,一次读取并打印一行。
我找不到任何将整个文件读入数组、根据需要修改数组,然后在使用 ^I 开关进行就地编辑时打印数组的示例。当我尝试从 Diamond 操作符读取整个文件、编辑内容并打印整个内容时,我发现打印转到 STDOUT 而不是 ARGVOUT,并且 ARGVOUT 已关闭。我可以打开相同的文件进行输出,然后打印到它,但我不确定我是否理解为什么这是必要的。下面是一个示例:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my $filename = 'test.txt';
push @ARGV, $filename;
$^I = ".bk";
my @file = <>; #Read all records into array
chomp @file;
push @file, qw(add a few more lines);
print join "\n", @file; #This prints to STDOUT, and ARGVOUT is closed. Why?
运行上面的命令会按预期备份 test.txt 文件,但将编辑后的 test.txt 保留为空,而是将编辑后的内容打印到 STDOUT。
Most examples of inplace editing are one-liners that iterate through a file or files, reading and printing one line at a time.
I can't find any examples of reading an entire file into an array, modifying the array as needed, and then printing the array while using the ^I switch to do an inplace edit. When I try to read the entire file from the diamond operator, edit the contents and print the entire contents, I find that the print goes to STDOUT instead of ARGVOUT and that ARGVOUT is closed. I can open the same file for output and then print to it, but I'm not sure I understand why that is necessary. Here is an example:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
my $filename = 'test.txt';
push @ARGV, $filename;
$^I = ".bk";
my @file = <>; #Read all records into array
chomp @file;
push @file, qw(add a few more lines);
print join "\n", @file; #This prints to STDOUT, and ARGVOUT is closed. Why?
Running the above makes a backup of the test.txt file as expected, but leaves the edited test.txt empty, printing the edited contents to STDOUT instead.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
请参阅
perlrun
。当
-i
开关被调用时,perl 使用ARGVOUT
作为默认文件句柄而不是STDOUT
来启动程序。如果有多个输入文件,则每次<>
或
或readline(ARGV)
操作都会以一个结束输入文件的名称,它会关闭ARGVOUT
并重新打开它以写入下一个输出文件名。一旦
<>
的所有输入都用完(当没有更多文件要处理时),perl 将关闭ARGVOUT
并将STDOUT
恢复为再次默认文件句柄。或者正如perlrun
所说,相当于
一旦你说
my @file = <>
并消耗了所有输入,Perl 就会关闭备份文件的文件句柄并开始定向输出再次到STDOUT
。我认为,解决方法是在标量上下文中调用
<>
并在每行之后检查eof(ARGV)
。当eof(ARGV)=1
时,您已读取该文件中的最后一行,并且在再次调用<>
之前有一次打印的机会:See
perlrun
.When the
-i
switch has been invoked, perl starts the program usingARGVOUT
as the default file handle instead ofSTDOUT
. If there are multiple input files, then every time the<>
or<ARGV>
orreadline(ARGV)
operation finishes with one of the input files, it closesARGVOUT
and reopens it to write to the next output file name.Once all the input from
<>
is exhausted (when there are no more files to process), perl closesARGVOUT
and restoresSTDOUT
as the default file handle again. Or asperlrun
saysis equivalent to
Once you say
my @file = <>
and consume all the input, Perl closes the filehandle to the backup files and starts directing output toSTDOUT
again.The workaround, I think, is to call
<>
in scalar context and checkeof(ARGV)
after each line. Wheneof(ARGV)=1
, you have read the last line in that file and you get one chance to print before you call<>
again:很糟糕。现在您已完成所有记录的读取,
*ARGV
已关闭,并且$^I
替换没有任何可处理的内容。这会一次读取一行文件,并在每个文件的末尾(在关闭之前)执行操作。
这一次将整个文件作为单个记录读取。
is bad. Now you're done slurping all the records,
*ARGV
is closed, and$^I
replacement doesn't have anything to work on.This read the file(s) line-at-a-time, and at the end of each file (before it's closed), performs the manipulation.
This reads entire files at a time as single records.
Tie::File 也可用于就地编辑文件。但是,它不会留下原始文件的备份副本。
Tie::File can also be used to edit a file in-place. It does not leave a backup copy of the original file, however.
Perl 的就地编辑比任何答案都简单得多:
如果您想创建备份,请将
local $^I = '';
更改为local $^I = '.bak';
Perl's inplace editing is much simpler than any of the answers:
if you want to create a backup then change
local $^I = '';
tolocal $^I = '.bak';