2014-12-18 1 views
0

У меня есть 100 подпапок в основной папке. У них есть имена разниц. Каждая подпапка содержит .txt-файл, который имеет 10 столбцов. Я хочу получить новый .txt-файл для каждой подпапки. Каждый новый .txt-файл должен находиться в собственной папке. То есть у меня будут файлы 2.txt (старые и новые) в каждой подпапке. Я пытаюсь выбрать строки, начинающиеся с «ATOM» и некоторые столбцы 2,6,7 и 8 из каждого .txt-файла. Мой код следующий. Он работает неправильно. Он не создает новый .txt-файл. Как я могу понять эту проблему?Как создать новый выходной файл для каждой подпапки под основной папкой с помощью perl?

#!/usr/bin/perl 

$search_text = "ATOM"; 
@files = <*/*.txt>; 
foreach $file (@files) { 
    print $file . "\n"; 

    open(DATA, $file);  
    open(OUT_FILE, ">$file a.txt"); 

    while ($line = <DATA>) 
    { 
     @fields = split /\s+/, $line; 
     if ($line =~ m/$search_text/) 
     { 

      print OUT_FILE "$fields[2]\t$fields[6]\t$fields[7]\t$fields[8]\n"; 
     } 

    } 

} 
close(OUT_FILE); 
+0

Проверьте успешность вызовов 'open':' use autodie; ' – toolic

+1

Работает для меня. Вы действительно хотите, чтобы выходной файл назывался 'something.txt a.txt' с пространством? – choroba

+0

Нет. Мне нужно, чтобы новый выходной файл назывался a.txt для каждой подпапки отдельно. – perlselami

ответ

1

Чтобы поместить выходной файл a.txt в том же каталоге, что и входной файл, необходимо извлечь имя каталога из имени входного файла, и предварять его имя выходного файла (a.txt). Есть несколько способов сделать это; вероятно, проще всего использовать dirname() из стандартного модуля File::Basename:

use File::Basename; 
my $dir = dirname($file); 
open(OUT_FILE, ">", "$dir/a.txt") or die "Failed to open $dir/a.txt: $!"; 

или вы могли бы использовать File::Spec непосредственно:

use File::Spec; 
my ($volume, $dir) = File::Spec->splitpath($file); 
my $outname = File::Spec->catpath($volume, $dir, 'a.txt'); 
open(OUT_FILE, ">", $outname) or die "Failed to open $outname: $!"; 

или вы могли бы просто использовать regexp substitution:

my $outname = ($file =~ s![^/]+$!a.txt!r); 
open(OUT_FILE, ">", $outname) or die "Failed to open $outname: $!"; 

Пс. В любом случае, я бы рекомендовал принятие несколько хороших привычек, которые помогут вам лучше писать сценарии Perl:

  1. Всегда начинайте ваши скрипты с use strict; и use warnings;. Исправьте любые ошибки и предупреждения, которые они создают. В частности, объявите все свои локальные переменные с помощью my, чтобы сделать их лексически охваченными.

  2. Проверьте возвращаемое значение таких функций, как open(), и прекратите выполнение сценария, если они не сработают. (Я сделал это в своих примерах выше.)

  3. Используйте форму с тремя аргументами open(), как я уже говорил в приведенных выше примерах. Это гораздо меньше шансов сломаться, если ваши имена файлов содержат забавные символы.

  4. Рассмотрите возможность использования лексических файловых дескрипторов (open my $out_file, ...) вместо глобальных файловых дескрипторов (open OUT_FILE, ...). Я не делал этого в своих фрагментах кода выше, потому что я хотел сохранить их совместимыми с остальной частью вашего кода, но это была бы хорошая практика.

  5. Если вы предварительно объявив регулярное выражение, как ваши $search_text, использовать qr// вместо простой строки, например:

    my $search_text = qr/ATOM/; 
    

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

  6. Для печати нескольких столбцов из массива, следует использовать join() и кусочек списка, например:

    print OUT_FILE join("\t", @fields[2,6,7,8]), "\n"; 
    

Наконец, если бы я тебя, я бы пересмотреть мой файл схема именования: имя выходного файла a.txt соответствует вашему имени входного файла glob *.txt, поэтому ваш скрипт, скорее всего, сломается, если вы запустите его дважды подряд.

+0

Окончательный код: '#!/Usr/bin/perl use strict; использовать предупреждения; Использование File :: Basename; my $ search_text = qr/ATOM /; @files = <*/*.pdb>; foreach $ file (@files) { print $ file. "\ П"; my $ dir = dirname ($ file); open (DATA, $ file); open (out_file, ">", "$ dir/a.log") или die "Не удалось открыть $ dir/a.log: $!"; while ($ line = ) { @fields = split/\ s + /, $ line; if ($ line = ~ m/$ search_text /) {print out_file join ("\ t", @fields [2,6,7,8]), "\ n"; }}} закрыть (OUT_FILE); ' – perlselami

+0

' @Ilmari Karonen' Во-первых, спасибо за ваш ответ/рекомендации. Ваши рекомендации очень полезны. Я пересмотрел сценарий, как вы сказали. В начале он работал и правильно создавал выходные файлы. Я побежал 5-6 раз. Но теперь он дает ошибку об этой строке: @files = <*/*.pdb>;. Ошибка: Глобальный символ «@files» требует наличия явного имени пакета на .pl строке 9. BEGIN небезопасно после ошибок .. Думаю, я должен пересмотреть эту строку. Каково ваше предложение? Наконец, мои .pdb-файлы имеют обычный формат. Но минус-номера имеют некоторый сдвиг в выходных файлах (.log). Как я могу получить их как в .pdb-файле? – perlselami

+0

Вам понадобится еще несколько 'my', чтобы передать 'use strict'. В частности, 'my @files = <*/*.pdb>' и 'foreach my $ file (@files)' и 'while (my $ line = )' и 'my @fields = split ...'. Кроме того, имена дескрипторов файлов чувствительны к регистру, поэтому 'out_file' и' OUT_FILE' не являются тем же файловым дескриптором (и '$ out_file' будет отличаться от обоих). Соглашение относится к именам пользователей верхнего регистра для глобальных дескрипторов файлов ('open OUT_FILE, ...'), но строчные для локальных ссылок на дескриптор файла ('open my $ out_file, ...'). –

 Смежные вопросы

  • Нет связанных вопросов^_^