Perl: заменить текстовую строку значением из списка (текстовый файл или скалярный контекст)

Я новичок в Perl, но прочитал "Learning Perl" Шварца, Фоя и Феникса и плохо понимаю язык. Я все еще борюсь, даже после использования книги и Интернета.

Моя цель - сделать следующее:

  1. Найдите определенную папку (текущую папку) и получите имена файлов с полным путем. Сохраняйте имена файлов с полным путем и текущим именем папки.

  2. Откройте файл шаблона и вставьте имена файлов с полным путем в определенное место (например, с помощью замены), а также текущее имя папки (в другом месте в том же текстовом файле, я еще не зашел так далеко).

  3. Сохраните новый измененный файл в новый файл в определенном месте (в текущей папке).

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

Я зашел так далеко...:

use strict;
use warnings;
use Cwd;
use File::Spec;
use File::Basename;
my $current_dir = getcwd;
open SECONTROL_TEMPLATE, '<secontrol_template.txt' or die "Can't open SECONTROL_TEMPLATE: $!\n";
my @secontrol_template = <SECONTROL_TEMPLATE>;
close SECONTROL_TEMPLATE;
opendir(DIR, $current_dir) or die $!;
my @seq_files = grep {
    /gz/
    } readdir (DIR);
open FASTQFILENAMES, '> fastqfilenames.txt' or die "Can't open fastqfilenames.txt: $!\n";
my @fastqfiles;
foreach (@seq_files) {
    $_ = File::Spec->catfile($current_dir, $_);
    push(@fastqfiles,$_);
}
print FASTQFILENAMES @fastqfiles;
open (my ($fastqfilenames),  "<", "fastqfilenames.txt") or die "Can't open fastqfilenames.txt: $!\n";
my @secontrol;
foreach (@secontrol_template) {
    $_ =~ s/@/$fastqfilenames/eg;
    push(@secontrol,$_);
}
open SECONTROL, '> secontrol.txt' or die "Can't open SECONTROL: $!\n";
print SECONTROL @secontrol;
close SECONTROL;
close FASTQFILENAMES;

Моя проблема в том, что я не могу понять, как использовать мой список файлов для замены "@" в моем текстовом файле шаблона:

my @secontrol;
foreach (@secontrol_template) {
    $_ =~ s/@/$fastqfilenames/eg;
    push(@secontrol,$_);
}

Функция замены не заменит "@" списком файлов, перечисленных в $fastqfilenames. Я заменяю "@" на GLOB(0x8ab1dc).

Я делаю это неправильно? Не использовать ли замену, так как этого сделать нельзя, а затем вставить список файлов ($fastqfilenames) в файл template.txt? Могу ли я вместо $fastqfilenames заменить содержимое файла (например, s/A/{r file.txt...). Какие-либо предложения?

Ваше здоровье,

ДжеймсТ

ИЗМЕНИТЬ:

Это сделало все лучше.

foreach (@secontrol_template) {
    s/@/$fastqfilenames/g;
    push @secontrol, $_;
}

И как оба предложения, $fastqfiles — это дескриптор файла.

заменил это: open (my ($fastqfilenames), "‹", "fastqfilenames.txt") или die "Не удается открыть fastqfilenames.txt: $!\n";

с этим:

my $fastqfilenames = join "\n", @fastqfiles; 

сделал все хорошо. Спасибо вам обоим.


person JamesT    schedule 25.03.2013    source источник


Ответы (2)


$fastqfilenames — это дескриптор файла. Вы должны прочитать информацию из дескриптора файла, прежде чем сможете ее использовать.

Однако у вас другие проблемы.

Вы печатаете все имена файлов в файл, а затем читаете их обратно из файла. Это не только сомнительный дизайн (зачем снова читать из файла, если у вас уже есть то, что вам нужно в массиве?), он еще и не будет работать:

Perl буферизует файловый ввод-вывод из соображений производительности. Строк, которые вы записали в файл, на самом деле может еще не быть, потому что Perl ждет, пока не будет сохранен большой кусок данных, чтобы записать их все сразу.

Вы можете переопределить это поведение буферизации несколькими различными способами (закрытие дескриптора файла является самым простым, если вы закончили запись в него), но, как я уже сказал, нет причин снова открывать файл и читать из него в любом случае.

Также обратите внимание, что параметр /e в замене регулярного выражения оценивает замену как код Perl. Это не обязательно в вашем случае, поэтому вы должны удалить его.

Решение. Вместо повторного открытия файла и его чтения просто используйте переменную @fastqfiles, созданную ранее при замене в шаблоне. Не совсем понятно, что вы имеете в виду, заменяя @ именами файлов.

  • Вы хотите заменить каждое @ списком всех имен файлов вместе? Если это так, вам, вероятно, нужно каким-то образом join имена файлов соединить вместе перед выполнением замены .

  • Вы хотите создать отдельную версию файла шаблона для каждого имени файла? Если это так, вам нужен внутренний цикл for, который проходит по каждому имени файла для каждого шаблона. И вам понадобится нечто иное, чем простая замена, потому что замена изменит исходную строку в первый раз. Если вы используете Perl 5.16, вы можете использовать опцию /r для неразрушающей замены: push(@secontrol,s/@/$file_name/gr); В противном случае вам следует скопировать в другую переменную перед выполнением замены.

person Community    schedule 25.03.2013
comment
Я новичок и, следовательно, дизайн моей программы плохой. Это связано с тем, что я использую то, что я понимаю, как использовать, или то, что я выясняю. Список имен файлов в @fastqfiles можно использовать для замены символа @ в файле шаблона, но я не знаю, как это сделать (за исключением некоторых базовых знаний в Unix sed/awk, отсюда и попытка замены). Я не знаю, как зациклить и сохранить содержимое @fastqfiles в моем файле шаблона (хранящемся в @secontrol_template). Я думал, что смогу понять, как использовать скаляр/список массива @fastqfiles вместо замены. Возможно, это часть конструктивного недостатка. - person JamesT; 25.03.2013

$_ =~ s/@/$fastqfilenames/eg;

$fastqfilenames — это дескриптор файла, а не его содержимое.

В любом случае я рекомендую использовать модуль Text::Template, чтобы выполнить такую ​​работу (подстановка текста файла).

person Miguel Prz    schedule 25.03.2013
comment
[Текст::Шаблон] (search.cpan.org/perldoc?Text%3a% 3aTemplate) была очень полезной. Я мог бы использовать его для изменения моего файла шаблона. Абсолютно то, на что стоит обратить внимание. Спасибо :) - person JamesT; 25.03.2013