Perl: Weird Tie :: Файловое поведение в Windows в отличие от Unix - PullRequest
1 голос
/ 13 ноября 2011

У меня есть этот скрипт на Perl, который использует Tie::File.В Linux (Ubuntu), когда я вызываю скрипт через Bash, он работает как положено, но в Windows, когда я вызываю скрипт через Powershell, он ведет себя странно (см. PS ниже).

Код :

#!/usr/bin/perl -T

use strict;
use warnings;

use Tie::File;
use CommonStringTasks;

if ( @ARGV != 4 ) {
   print "ERROR:Inadequate/Redundant arguments.\n";
   print "Usage: perl <pl_executable> <path/to/peer_main.java> <peer_main.java>\n";
   print "       <score_file_index> <port_step_index>\n";
   print $ARGV[0], "\n";
   print $ARGV[1], "\n";
   print $ARGV[2], "\n";
   print $ARGV[3], "\n";
   exit 1;
}

my $PEER_DIR = $ARGV[0];
my $PEER_FILE = $ARGV[1];
my $PEER_PACKAGE = "src/planetlab/app";
my $PEER_PATH = "${PEER_DIR}/${PEER_PACKAGE}/${PEER_FILE}";

# Check if args are tainted ...

# Check $PEER_PATH file permissions ...

open(my $file, "+<", "$PEER_PATH")
   or
die("File ", $PEER_FILE, " could not be opened for editing:$!");

# Edit the file and change variables for debugging/deployment setup.
# Number demanglers:
# -flock -> arg2 -> 2 stands for FILE_EX
# Options (critical!):
# -Memory: Inhibit caching as this will allow record changes on the fly.
tie my @fileLines, 
    'Tie::File', 
    $file,
    memory => 0
      or 
    die("File ", $PEER_FILE, " could not be tied with Tie::File:$!");

flock $file, 2;

my $i = 0;
my $scoreLine = "int FILE_INDEX = " . $SCORE . ";";
my $portLine = "int SERVER_PORT = " . $PORT . ";";
my $originalScoreLine = "int FILE_INDEX =";
my $originalPortLine = "int SERVER_PORT =";

(tied @fileLines)->defer;

while (my $line = <$file>) {
   if ( ($line =~ m/($scoreLine)/) && ($SCORE+1 > 0) ) {
      print "Original line (score): ", "\n", $scoreLine, "\n";
      chomp $line;
      $line = substr($line, 0, -($scoreDigits+1));
      $line = $line . (++$SCORE) . ";";
      print "Editing line (score): ", $i, "\n",  trimLeadSpaces($fileLines[$i]), "\n";
      $fileLines[$i] = $line;
      print "Line replaced with:\n", trimLeadSpaces($line), "\n";
      next;
   }
   if ( ($line =~ m/($portLine)/) && ($PORT > 0) ) {
      print "Original line (port): ", "\n", $portLine, "\n";
      chomp $line;
      $line = substr($line, 0, -($portDigits+1));
      $line = $line . (++$PORT) . ";";
      print "Editing line (port): ", $i, "\n",  trimLeadSpaces($fileLines[$i]), "\n";
      $fileLines[$i] = $line;
      print "Line replaced with:\n", trimLeadSpaces($line), "\n";
      last;
   }

   # Restore original settings.
   if ( ($line =~ m/($originalScoreLine)/) && ($SCORE < 0) ) {
      print "Restoring line (score) - FROM: ", "\n", $fileLines[$i], "\n";
      $fileLines[$i] = "    private static final int FILE_INDEX = 0;";
      print "Restoring line (score) - TO: ", "\n", $fileLines[$i], "\n";
      next;
   }
   if ( ($line =~ m/($originalPortLine)/) && ($PORT < 0) ) {
      print "Restoring line (port) - FROM: ", "\n", $fileLines[$i], "\n";
      $PORT = abs($PORT);
      $fileLines[$i] = "    private static final int SERVER_PORT = " . $PORT . ";";
      print "Restoring line (port) - TO: ", "\n", $fileLines[$i], "\n";
      last;
   }
} continue {
   $i++;
}

(tied @fileLines)->flush;

untie @fileLines;
close $file;

Версия perl в обеих ОС - 5+ (в Windows Active-State Perl с модулями CPAN).Может ли это быть способом, которым я открываю дескриптор файла?Любые идеи кто-нибудь?

PS: первая версия имела while (<$file>) и вместо $line я использовал переменную $_, но когда я сделал это, у меня было поведение, где определенные строки не будут редактироваться, новместо этого к файлу добавляются сто новых строк или около того, за которыми следует (правильно) отредактированная строка и так далее.У меня также было предупреждение о неинициализации $fileLines[$i]. Очевидно, что-то не так со структурой Tie::File в Windows или с чем-то еще, о чем я не знаю.Такое же ошибочное поведение имеет место с изменениями, и в Linux (Ubuntu) поведение снова, как и ожидалось.

Ответы [ 2 ]

2 голосов
/ 13 ноября 2011

Вопрос ОП неясен, и в нем отсутствует ввод и ожидаемый вывод.Поэтому я просто отмечу некоторые из моих проблем:

Во-первых, использование Tie::File и <$file> и flock на одной и той же ручке кажется излишним и опасным.Я бы рекомендовал просто использовать Tie::File для итерации и редактирования, например:

#!/usr/bin/env perl

use strict;
use warnings;

use Tie::File;

tie my @lines, 'Tie::File', 'filename';

foreach my $linenum ( 0..$#lines ) {
  if ($lines[$linenum] =~ /something/) {
    $lines[$linenum] = 'somethingelse';
  }
}

Возможно, лучше, чем редактировать inline, так как Tie::File позволяет скопировать файл в резервную копию, выполнить итерации по строкам, используя<$file>, затем запишите в новый файл со старым именем.

#!/usr/bin/env perl

use strict;
use warnings;

use File::Copy 'move';

my $infile = $ARGV[0];

move( $infile, "$infile.bak");

open my $inhandle, '<', "$infile.bak";
open my $outhandle, '>', $infile;

while( my $line = <$inhandle> ) {
  if ($line =~ /something/) {
    $line = 'somethingelse';
  }
  print $outhandle $line; 
}

Во-вторых, флаг -MModule просто переводится в use Module; в верхней части скрипта.Следовательно, -MCPAN равен use CPAN;, однако загрузка модуля CPAN ничего не делает для скрипта.CPAN.pm дает сценарию возможность установки модулей.

В-третьих, мы сможем помочь вам лучше, если вы приведете пример ввода, ожидаемый результат и упрощенный сценарий, который четко показывает, как выполняется эта операция.выполнять при этом все равно не так, как реальный скрипт.

0 голосов
/ 13 ноября 2011

Я выяснил источник своих проблем.
Причиной стал разделитель записей !
В Windows Tie::File ожидается разделитель записей /r/n, поэтому он прочитает весь файл всего за один проход. Мои файлы в UTF-8 , с окончаниями строк Unix .
Вот почему, когда я перебирал $fileLines и обращался к любому индексу, кроме 0, я получил от perl предупреждение о том, что строка не была инициализирована. Исправлена ​​проблема и теперь я готов идти дальше! : D

P.S .: Мистер Джоэл Бергер Я отмечаю ваш ответ как действительный / уместный, потому что вы действительно пытались помочь мне, а я следовал вашему первому совету по поводу дескриптора файла :) Спасибо всем за помощь xD xD xD

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