Perl - начать чтение с определенной строки и получить только первый столбец этой строки до конца

У меня есть текстовый файл, который выглядит следующим образом:

Line 1
Line 2
Line 3
Line 4
Line 5
filename2.tif;Smpl/Pix & Bits/Smpl are missing.

Есть 5 строк, которые всегда одинаковы, и в 6-й строке я хочу начать чтение данных. При чтении данных каждая строка (начиная со строки 6) разделяется точкой с запятой. Мне нужно просто получить первую запись каждой строки (начиная со строки 6).

Например:

Line 1
Line 2
Line 3
Line 4
Line 5
filename2.tif;Smpl/Pix & Bits/Smpl are missing.
filename4.tif;Smpl/Pix & Bits/Smpl are missing.
filename6.tif;Smpl/Pix & Bits/Smpl are missing.
filename8.tif;Smpl/Pix & Bits/Smpl are missing.  

Желаемый результат:

filename2.tif
filename4.tif
filename6.tif
filename8.tif

Возможно ли это, и если да, то с чего начать?


person drewrockshard    schedule 24.11.2010    source источник
comment
Это возможно. У вас еще нет кода?   -  person aschepler    schedule 25.11.2010
comment
Да и нет. Пока не для этого, но у меня есть более 300 строк кода, в которые я пытаюсь это реализовать. По сути, это новая функция, которую я пытаюсь реализовать для обработки файлов из уже существующего текстового файла.   -  person drewrockshard    schedule 25.11.2010
comment
Ответ на ̲a̲l̲l̲ вопросы, начинающиеся с «Могу ли я сделать в Perl…?», будет «¡Да!» Однако ответ на некоторые из них продолжается с "Да, но..."   -  person tchrist    schedule 25.11.2010


Ответы (3)


Это использует режим Perl "autosplit" (или "awk"):

perl -n -F'/;/' -a -e 'next if $. <= 5; print "$F[0]\n";' < data.file

См. 'perlrun' и 'perlvar'.


Если вам нужно сделать это в функции, которой дан дескриптор файла и несколько строк для пропуска, то вы не будете использовать режим «авторазбиения» Perl.

sub skip_N_lines_read_column_1
{
    my($fh, $N) = @_;
    my $i = 0;
    my @files = ();
    while (my $line = <$fh>)
    {
        next if $i++ < $N;
        my($file) = split /;/, $line;
        push @files, $file;
    }
    return @files;
}

Это инициализирует цикл, считывает строки, пропуская первые N из них, затем разбивает строку и фиксирует только первый результат. Эта линия с my($file) = split... тонкая; круглые скобки означают, что разделение имеет контекст списка, поэтому он генерирует список значений (а не количество значений) и присваивает первое значение переменной. Если бы круглые скобки были опущены, вы предоставили бы скалярный контекст оператору списка, поэтому вы получили бы количество полей в разделенном выводе, назначенное $file, а не то, что вам нужно. Имя файла добавляется в конец массива, и массив возвращается. Поскольку код не открыл дескриптор файла, он его и не закрывает. Альтернативный интерфейс передал бы имя файла (вместо дескриптора открытого файла) в функцию. Затем вы открываете и закрываете файл в функции, беспокоясь об обработке ошибок.

И если вам нужна помощь с открытием файла и т. д., то:

use Carp;

sub open_skip_read
{
    my($name) = @_;
    open my $fh, '<', $name or croak "Failed to open file $name ($!)";
    my @list = skip_N_lines_read_column_1($fh, 5);
    close $fh or croak "Failed to close file $name ($!)";
    return @list;
}
person Jonathan Leffler    schedule 24.11.2010
comment
+1. Лучший ответ, правда. Я должен спасти perl часть моего мозга :) - person Diego Sevilla; 25.11.2010
comment
Как мне написать это в сценарии, а не в командной строке, и прочитать из открытого дескриптора файла, который уже существует? - person drewrockshard; 25.11.2010
comment
@Jonathan: Меня пугает, что Perl знает, как сожрать ваши разделители косой черты вокруг разделителя. Я не знал, что это так! - person tchrist; 25.11.2010
comment
@tchrist: См. perl run ... нет, я имею в виду, см. «perlrun» ... '-Fpattern указывает шаблон для разделения, если -a также действует. Шаблон может быть окружен // , или '' , иначе он будет заключен в одинарные кавычки. Вы не можете использовать буквальные пробелы в шаблоне». Мне действительно не нужны косые черты в этом примере. - person Jonathan Leffler; 25.11.2010
comment
Я приближаюсь. Я изменил последнюю часть подпрограммы open_skip_read на return $list[0];, и теперь она выводит имя файла. Проблема в том, что возвращается только одно имя файла, а результатов больше. Мне нужно, чтобы он возвращал каждое совпадение, с которым оно сталкивается. - person drewrockshard; 25.11.2010
comment
Догадаться; прогнал его через цикл foreach, и это помогло. Я очень ценю вашу помощь в этом - это определенно был лучший ответ. - person drewrockshard; 25.11.2010

Довольно некрасиво, но прочитайте фиктивные строки, а затем разделите их на ; для остальных.

my $logfile = '/path/to/logfile.txt';

open(FILE, $logfile) || die "Couldn't open $logfile: $!\n";

for (my $i = 0 ; $i < 5 ; $i++) {
   my $dummy = <FILE>;
}

while (<FILE>) {
   my (@fields) = split /;/;
   print $fields[0], "\n";
}

close(FILE);
person dmah    schedule 24.11.2010
comment
Это можно записать примерно так: my @dummy; @dummy[0..4] = <STDIN>;map {($a) = split /;/;print $a,"\n"} <STDIN>;. - person Diego Sevilla; 25.11.2010
comment
Что делать, если я пытаюсь прочитать из файла, но не из командной строки. У меня есть файл, который находится в относительном месте (например, я могу вызвать его, logfile.txt). Пока что у меня проблемы с чтением, мой код непрерывно запускает цикл while, и мне приходится нажимать CTRL + C из него. - person drewrockshard; 25.11.2010
comment
@Diego: Por desgracia это не сработает, потому что вы только что передали контекст списка оператору readline в назначении фрагмента, тем самым исчерпав ввод. Остальные строки были отброшены. - person tchrist; 25.11.2010
comment
@drewrockshard Я отредактировал ответ, чтобы открыть ваш файл logfile.txt. - person dmah; 25.11.2010
comment
Спасибо! Я также попробую этот - он мне изначально понравился больше всего, так как он казался самым простым из всех. - person drewrockshard; 25.11.2010
comment
@tchrist, ты прав! Ну, я просто хотел дать более функциональный подход... Похоже, мне нужно больше изучать функциональные возможности Perl :) - person Diego Sevilla; 25.11.2010

person    schedule
comment
Ребят, я еще запутался - **новичок в Perl**. У меня уже есть файл, который содержит все. Мне просто нужно открыть файл в моем скрипте, пропустить первые 5 строк и вывести первый столбец каждой строки после 5-й строки. - person drewrockshard; 25.11.2010
comment
@drewsrockhard: Это то, что делает моя программа. Попробуйте. - person tchrist; 25.11.2010
comment
Можете ли вы показать пример того, как это запустить и где разместить входной файл? - person drewrockshard; 25.11.2010
comment
@drew: Вы запускаете его, как и любой другой скрипт. И вы размещаете свой входной файл где угодно; Я не знаю его названия. perl this_program your_input_file, или perl this_program < your_input_file, или cat your_input_file | perl this_program, или gzcat your_input_file.gz | perl this_program, или wget -O - http://remote_url | perl this_program, или любой из бесконечного множества альтернативных составов того же типа и эффекта. - person tchrist; 25.11.2010
comment
Это моя точка зрения, и я продолжал понимать, что мне не нужен сценарий, мне нужен код для реализации в моей программе, который будет читать файл, который уже существует. Все ваши примеры, которые вы перечислили, выглядят так, что я запустить этот код и каким-то образом передать ему мой текстовый файл или наоборот. Пример Джонатана был кодом, который я мог внедрить в свой собственный скрипт, и я смог определить свой существующий файл. Я просто не знал, как это сделать с вашим скриптом. Я ценю вашу помощь, хотя. - person drewrockshard; 25.11.2010