Почему Perl жалуется на неопределенную строку здесь? - PullRequest
2 голосов
/ 29 декабря 2011

У меня есть сценарий Perl, который отлично работает под Perl 5.005 на HPUX 11i v3, и это вызывает небольшую проблему под Perl 5.10 на моем Ubuntu 11.04.

Это сводится к линии, как:

open (CMD, "do something | grep -E 'sometext$' |");

(на самом деле он захватывает ps -ef вывод, чтобы увидеть, работает ли процесс, но я не думаю, что это важно (a) ).

Теперь это нормально работает в среде HPUX, но, когда я пробую его в Ubuntu, я получаю:

sh: Syntax error: Unterminated quoted string

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

open (CMD, "do something | grep -E 'sometext\$' |");

и все работало нормально (во всяком случае, под Linux - я не проверял это на HPUX, поскольку у меня сегодня нет доступа к этой машине - если это сработает, я просто воспользуюсь этим подходом, но все равно хотел бы чтобы понять, почему это проблема).

Так что кажется очевидным, что $ "глотает" заключительную одинарную кавычку в моей среде Linux, но явно не в HPUX.

Мой вопрос просто: почему? Конечно, не было никаких массовых изменений между 5.005 и 5.10. Или мне не хватает какого-то элемента конфигурации?


(a) Но, если вы знаете лучший способ сделать это без внешних модулей CPAN (т. Е. Только с базовой установкой Perl 5.005), я был бы рад знать об этом.

Ответы [ 6 ]

7 голосов
/ 29 декабря 2011

$' - специальная переменная (см. perldoc perlvar). 5.005 было много версий назад, поэтому возможно, что в движке регулярных выражений что-то изменилось, чтобы изменить эту переменную (хотя, похоже, она и в 5.005)

Что касается лучшего способа, вы можете по крайней мере только запустить 'ps -ef' в конвейере и выполнить 'grep' в perl.

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

Используйте следующее !!!

use strict;
use warnings;

Вы бы получили

Use of uninitialized value $' in concatenation (.) or string
4 голосов
/ 29 декабря 2011

Символ, сопровождаемый любым символом пунктуации (на стандартной клавиатуре), является переменной в Perl, независимо от того, определен ли он или нет.Таким образом, строка в двойных кавычках [$@][symbol] всегда будет читаться как один токен и интерполироваться, если только не экранирован символ.

У меня такое ощущение, что различие, которое вы видите, связано с разными системными оболочками, а не с разнымиверсии perl.

Рассмотрим вашу строку:

open (CMD, "do something | grep -E 'sometext$' |");

Когда Perl увидит это, он интерполирует пустую переменную $' в строку в двойных кавычках, поэтому строка становится:

open (CMD, "do something | grep -E 'sometext |");

В этот момент ваша оболочка начинает обрабатывать строку, которая выглядит следующим образом:

do something | grep -E 'sometext

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

Если бы вы использовали прагму warnings в своем скрипте, вы, вероятно, получили бы предупреждение о интерполяции неопределенной переменной.


Более короткий и чистый способ чтения на выходе ps будет выглядеть так:

my @lines = grep /sometext\$/, `ps -ef`;

Или с использованием явного открытия:

my @lines = grep /sometext\$/, do {
   open my $fh, '|-', 'ps -ef' or die $!;
   <$fh>
};
3 голосов
/ 29 декабря 2011

Потому что $' - это специальная переменная в последних версиях Perl.

Из официальной документации ( perlvar ):

$': Строка, следующая за тем, что было найдено последним успешным совпадение с образцом (не считая совпадений, скрытых в БЛОКЕ или eval (), заключенный в текущий блок).

Если не было успешных совпадений с образцом, $' пусто, и ваше утверждение по существу интерполируется до

open (CMD, "do something | grep -E 'sometext |");

Выход из знака доллара (решение, которое работает для вас в Linux) должно работать и в HPUX.

Я не уверен, когда была добавлена ​​эта переменная, но я могу подтвердить, что она существует в Perl 5.8.5. Что нового в Perl 5.005 упоминает $' (не как новую функцию), так что я думаю, что он уже был там раньше.

2 голосов
/ 29 декабря 2011

Вы, вероятно, должны использовать одинарные кавычки, а не двойные кавычки вокруг строки, поскольку в строке нет ничего, что следует интерполировать:

open (CMD, q{do something | grep -E 'sometext$' |});

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

open my $cmd, '-|', q{do something | grep -E 'sometext$'} or die 'a horrible death';

У меня нет хорошего объяснения, почему $' распознается как специальная переменная в 5.10, а в 5.005 - нет.Это неожиданно.

Есть ли действительно веская причина, по которой вы не можете перейти на что-то вроде 5.14.1?Даже если вы не измените предоставляемый системой Perl, нет очевидной причины, по которой вы не можете установить последнюю версию в каком-либо другом месте и использовать ее для всей своей работы со сценариями.

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

$ ' - специальная переменная.

Если вы хотите избежать расширения переменной, просто используйте q():

open (CMD, q(do something | grep -E 'sometext$' |));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...