Нужно Perl редактировать файлы не в командной строке - PullRequest
16 голосов
/ 19 мая 2011

У меня есть программа, которая имеет несколько имен файлов, настроенных внутри.Программа редактирует набор файлов конфигурации, связанных с учетной записью базы данных, а затем изменяет пароль базы данных для учетной записи базы данных.

Список файлов конфигурации связан с именем учетной записи базы данных через внутренний список.Когда я обрабатываю эти файлы, в моей программе появляется следующий цикл:

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;
}

Проблема в том, что записывает измененный вывод в STDOUT, а не в CONFIGFILE.Как мне получить это на самом деле редактировать на месте?Переместить $ ^ I внутри цикла?Печатать КОНФИФИЛЬ?Я в тупике.

>

Обновление: Я нашел то, что искал в PerlMonks .Вы можете использовать локальный ARGV внутри цикла для редактирования на месте обычным способом Perl.Вышеприведенный цикл теперь выглядит следующим образом:

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

Если бы не было привязки configDir в начале, я мог бы просто выбросить весь список в локальный @ARGV, но это достаточно эффективно.

Спасибо за полезные советы по Tie::File.Я бы, наверное, пошел по этому пути, если бы закончил.Файлы конфигурации, которые я редактирую, никогда не превышают нескольких килобайт, поэтому Tie не будет использовать слишком много памяти.

Ответы [ 3 ]

16 голосов
/ 20 мая 2011

Последние версии File::Slurp предоставляют удобные функции edit_file и edit_file_lines.Внутренняя часть вашего кода будет выглядеть так:

use File::Slurp qw(edit_file);
edit_file { s/$oldPass/$newPass/g } $filename;
11 голосов
/ 19 мая 2011

Переменная $^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;
}

но если это не простой сценарий и вам нужны @ARGV и STDOUT для других целей, вам, вероятно, лучше использовать что-то вроде 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;
}
2 голосов
/ 20 мая 2011

Tie :: File уже упоминался и очень прост.Отключение ключа -i, вероятно, является хорошей идеей для сценариев, не связанных с командной строкой.Если вы хотите избежать Tie :: File, стандартное решение таково:

  • Открыть файл для ввода
  • Открыть временный файл для вывода
  • Прочитайте строку из входного файла.
  • Измените строку так, как вам нравится.
  • Запишите новую строку во временный файл.
  • Переход к следующей строке и т. Д..
  • Закрытие входных и выходных файлов.
  • Переименование входного файла с некоторым именем резервной копии, например добавление .bak к имени файла.
  • Переименование временного выходного файла в исходное имя файла ввода.

По сути, это то, что происходит за кулисами с параметром -i.bak, но с дополнительной гибкостью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...