Есть ли проблема с открытием имен файлов, указанных в командной строке через $ _? - PullRequest
4 голосов
/ 18 декабря 2011

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

use strict;
use warnings;

use File::Copy;

foreach $_ (@ARGV) {
   my $orig = $_;
   (my $copy = $orig) =~ s/\.js$/_extjs4\.js/;
   copy($orig, $copy) or die(qq{failed to copy $orig -> $copy});
}

Теперь, когда у меня есть файлы с именем "* _extjs4.js", я хотел бы передать их в скрипт, который аналогичным образом берет имена файлов из командыстрока, и далее обрабатывает строки в этих файлах.Пока я могу успешно получить дескриптор файла, как показано в следующем скрипте, и его вывод показывает:

use strict;
use warnings;

foreach $_ (@ARGV) {
    print "$_\n";
    open(my $fh, "+>", $_) or die $!;
    print $fh;
    #while (my $line = <$fh>) {
    #    print $line;
    #}
    close $fh;
}

Какие выходные данные (частично):

./filetree_extjs4.js
GLOB(0x1a457de8)
./async_submit_extjs4.js
GLOB(0x1a457de8)

Что я на самом делехотя вместо того, чтобы печатать представление дескриптора файла, нужно работать с содержимым самих файлов. Для начала нужно было бы напечатать строки файлов, что я пытался сделать с закомментированным кодом.выше.

Но этот код не действует, строки файлов не печатаются.Что я делаю неправильно?Есть ли конфликт между $ _, используемым для обработки аргументов командной строки, и тем, который используется для обработки содержимого файла?

Ответы [ 3 ]

6 голосов
/ 18 декабря 2011

Похоже, здесь есть пара вопросов.


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

Причина, по которой print $fh возвращает GLOB(0x1a457de8), заключается в том, что скаляр $fh является дескриптором файла, а не содержимым самого файла. Чтобы получить доступ к содержимому самого файла, используйте <$fh>. Например:

while (my $line = <$fh>) {
    print $line;
}

# or simply print while <$fh>;

напечатает содержимое всего файла.

Это задокументировано в pelrdoc perlop:

Если то, что содержат угловые скобки, является простой скалярной переменной (например, <$foo>), тогда эта переменная содержит имя дескриптора файла для вход из, или его typeglob, или ссылка на то же самое.


Но это уже было опробовано!

Я это вижу. Попробуйте после изменения открытого режима на +<.

Согласно perldoc perlfaq5:

Почему, когда я открываю файл для чтения и записи, он стирает его?

Потому что вы используете что-то вроде этого, которое усекает файл затем дает вам доступ для чтения и записи:

  open my $fh, '+>', '/path/name'; # WRONG (almost always)

Упс. Вместо этого вы должны использовать это, что не получится, если файл не существует:

  open my $fh, '+<', '/path/name'; # open for update

Использование ">" всегда увеличивает или создает. Использование "<" никогда не помогает. "+" не меняет этого.

Само собой разумеется, что or die $! после open настоятельно рекомендуется.


Но сделайте шаг назад.

Существует более Perlish способ резервного копирования исходного файла и последующей манипуляции с ним. На самом деле, это можно сделать через саму командную строку (!), Используя флаг -i:

$ perl -p -i._extjs4 -e 's/foo/bar/g' *.js

Подробнее см. perldoc perlrun.


Я не могу вписать свои потребности в командную строку.

Если манипуляция слишком велика для командной строки, модуль Tie::File стоит попробовать.

1 голос
/ 18 декабря 2011

Чтобы прочитать содержимое файлового дескриптора, вы должны позвонить readline read или поместить файловый дескриптор в угловые скобки <>.

my $line = readline $fh;
my $actually_read = read $fh, $text, $bytes;
my $line = <$fh>; # similar to readline

Для печати в файловый дескриптор, отличный от STDIN, необходимо указать его в качестве первого аргумента print, за которым следует то, что вы хотите напечатать, беззапятая между ними.

print $fh 'something';

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

print {$fh} 'something';

Вы также можете select ваш новый дескриптор.

{
  my $oldfh = select $fh;
  print 'something';
  select $oldfh; # reset it back to the previous handle
}

Также ваш аргумент mode, равный open, заставляет его загромождать содержимое файла.В этот момент нечего читать.

Попробуйте вместо этого:

open my $fh, '+<', $_ or die;
0 голосов
/ 18 декабря 2011

Я хотел бы добавить кое-что к прекрасному предложению Zaid об использовании однострочного.

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

Файл:

#!/usr/bin/perl
use warnings;
use strict;

s/complicated/regex/g;

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

perl -p script.pl input.js
perl -p script.pl input.js > testfile
perl -p script.pl input.js | less

Обратите внимание, что выне используйте флаг -i здесь во время тестирования.Эти команды не изменят входные файлы, а только распечатают изменения в stdout.

Когда вы будете готовы выполнить (постоянные!) Изменения, просто добавьте флаг редактирования на месте -i, и еслиВы хотите (рекомендуется), укажите расширение для резервных копий, например ".bak".

perl -pi.bak script.pl *.js
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...