需要perl就地编辑不在命令行上的文件

Wex*_*xor 15 perl file in-place

我有一个程序,内部配置了许多文件名.该程序编辑与数据库帐户关联的一组配置文件,然后更改数据库帐户的数据库密码.配置文件列表通过内部列表与数据库帐户的名称相关联.当我处理这些文件时,我的程序中有以下循环:

BEGIN { $^I = '.oldPW'; }  # Enable in-place editing
...
foreach (@{$Services{$request}{'files'}})
{
    my $filename = $Services{$request}{'configDir'} . '/' . $_;
    print "Processing ${filename}\n";
    open CONFIGFILE, '+<', $filename or warn $!;
    while (<CONFIGFILE>)
    {
        s/$oldPass/$newPass/;
        print;
    }
    close CONFIGFILE;
}
Run Code Online (Sandbox Code Playgroud)

问题是,这会将修改后的输出写入STDOUT,而不是CONFIGFILE.如何让它实际编辑到位?在循环中移动$ ^ I?打印CONFIGFILE?我很难过.

更新:我发现了我在perlmonks上寻找的东西.您可以在循环内使用本地ARGV以正常的perl方式进行就地编辑.上面的循环现在看起来像:

foreach (@{$Services{$request}{'files'}})
{
    my $filename = $Services{$request}{'configDir'} . '/' . $_;
    print "Processing ${filename}\n";
    {
        local @ARGV = ( $filename);
        while (<>)
        {
            s/$oldPass/$newPass/;
            print;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果不是在开始时修改configDir,我可以将整个列表扔到本地@ARGV,但这足够有效.

感谢Tie :: File的有用建议,如果这样做,我可能会这样做.我正在编辑的配置文件长度不超过几千字节,因此Tie不会占用太多内存.

Grr*_*rrr 16

最近的版本File::Slurp提供了方便的功能,edit_file以及edit_file_lines.代码的内部部分将是:

use File::Slurp qw(edit_file);
edit_file { s/$oldPass/$newPass/g } $filename;
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记备份文件. (2认同)

mob*_*mob 11

$^I变量仅对$ARGV使用空<>构造保存的文件名序列进行操作.也许这样的事情会起作用:

BEGIN { $^I = '.oldPW'; }  # Enable in-place editing
...

local @ARGV = map {
    $Services{$request}{'configDir'} . '/' . $_ 
} @{$Services{$request}{'files'}};
while (<>) {
   s/$oldPass/$newPass/;

   # print? print ARGVOUT? I don't remember
   print ARGVOUT;
}
Run Code Online (Sandbox Code Playgroud)

但如果它不是一个简单的脚本而你需要@ARGVSTDOUT其他目的,你可能最好使用类似Tie::File的任务:

use Tie::File;
foreach (@{$Services{$request}{'files'}})
{
    my $filename = $Services{$request}{'configDir'} . '/' . $_;

    # make the backup yourself
    system("cp $filename $filename.oldPW");   # also consider File::Copy

    my @array;
    tie @array, 'Tie::File', $filename;

    # now edit @array
    s/$oldPass/$newPass/ for @array;

    # untie to trigger rewriting the file
    untie @array;
}
Run Code Online (Sandbox Code Playgroud)