Побочный эффект двойной кавычки в командной строке Windows

Я столкнулся с очень странной проблемой с командным интерпретатором Windows. Она возникает как в XP, так и в Windows 7. Мое описание ниже относится к скрипту Perl, но эта проблема применима к запуску любой программы в командной строке, которая принимает параметры командной строки.

Для проверки я использую Perl-скрипт check-params.pl, который просто выводит то, что он видит в качестве параметров -

use strict;
use warnings;
while (my $param = shift @ARGV) {
    print "Param: [$param]\n";
}

Таким образом, если я запускаю -

perl check-params.pl "a b|<>" c^|^<^>cc

то вывод будет

[Param: a b|<>]
[Param: c|<>cc]

как и ожидалось. Специальные символы | < > прекрасно работают внутри двойных кавычек, но когда они выходят за пределы кавычек, их нужно экранировать с помощью ^.

Однако когда двойная кавычка добавляется к кавычкам параметра, например, в

perl check-params.pl "a\" b|<>"

Тогда я получаю ошибку -

> was unexpected at this time.

Но если двойная кавычка идет после специального символа | < или >, то все работает нормально.

Вы можете легко исправить это, экранируя специальный символ | < > с помощью ^ внутри кавычек. Например

perl check-params.pl "a\" b^|"

Однако не только экранированная двойная кавычка влияет на специальные символы | < > в текущем параметре, но она влияет на эти специальные символы в любых последующих параметрах.

Например, если я сделаю так -

perl check-params.pl "aa \"bb" ccc | perl check-pipe.pl

(где check-pipe.pl просто выводит то, что получила труба -

use strict;
use warnings;
while (<STDIN>) {
    print "PIPE RECEIVED ---> $_";
}

)

то вывод будет -

Param: [aa "bb]
Param: [ccc]
Param: [|]
Param: [perl]
Param: [check-pipe.pl]

т.е. он рассматривает трубу | как литеральный символ, и никакой пересылки не происходит.

Кто-нибудь сталкивался с этой проблемой и знает какое-нибудь обходное решение?

Я написал несколько Perl-скриптов для обработки веб-журналов, и один из них использует regex'ы, которые я передаю в командной строке в кавычках. Regex может содержать такие символы, как | < >, а также двойную кавычку, которую я ввожу как \". Таким образом, возникает описанная выше проблема.

Любая помощь будет очень признательна, спасибо.


Спасибо за ответ, но при попытке сделать это на XP SP3, Perl скрипт видит два параметра командной строки.

Эта проблема не связана с Perl, например,

echo "a \"b|c"

выдает ошибку -

'c"' is not recognized as an internal or external command,
operable program or batch file.

но

echo "a b|\"c"

работает, потому что \" идет после специального символа |.

Это должно быть ошибка в командном интерпретаторе. Мне было бы интересно узнать больше об этом, и найти обходной путь, если это возможно. Эта проблема мешает запуску некоторых полезных скриптов. Это довольно серьезная проблема для командного интерпретатора. Я также пробовал на Windows 7, и там возникает та же проблема с приведенным выше эхо-тестом.


Дополнительная информация:

Я обновил скрипты check-params.pl и check-pipe.pl, чтобы дать больше полезной информации :-

check-params.pl :-

use strict;
use warnings;
while (my $param = shift @ARGV) {
    print "COMMAND LINE RECEIVED: [$param]\n";
}

check-pipe.pl :-

use strict;
use warnings;
while (<STDIN>) {
    print "PIPE RECEIVED: $_";
}

while (my $param = shift @ARGV) {
    print "COMMAND LINE RECEIVED: [$param]\n";
}

Например, запуск :-

perl pl/utils/check-params.pl l1 l1-b l1-c | perl pl/utils/check-pipe.pl l2 l2-b | perl pl/utils/check-pipe.pl l3 l3-b | perl pl/utils/check-pipe.pl united arsenal rangers raith

дает результат :-

PIPE RECEIVED: PIPE RECEIVED: PIPE RECEIVED: COMMAND LINE RECEIVED: [l1]
PIPE RECEIVED: PIPE RECEIVED: PIPE RECEIVED: COMMAND LINE RECEIVED: [l1-b]
PIPE RECEIVED: PIPE RECEIVED: PIPE RECEIVED: COMMAND LINE RECEIVED: [l1-c]
PIPE RECEIVED: PIPE RECEIVED: COMMAND LINE RECEIVED: [l2]
PIPE RECEIVED: PIPE RECEIVED: COMMAND LINE RECEIVED: [l2-b]
PIPE RECEIVED: COMMAND LINE RECEIVED: [l3]
PIPE RECEIVED: COMMAND LINE RECEIVED: [l3-b]
COMMAND LINE RECEIVED: [united]
COMMAND LINE RECEIVED: [arsenal]
COMMAND LINE RECEIVED: [rangers]
COMMAND LINE RECEIVED: [raith]

тем самым подтверждая, что эта командная строка будет работать, как ожидалось. Сценарии будут работать с любым количеством труб в командной строке.


Дополнительная информация:

Я обнаружил, что могу заставить это работать, используя многочисленные обходные пути - например, ^". Упомянутый Гарри - один из примеров. Иногда можно переделать regex, чтобы избежать использования ". Когда есть две последовательности \" перед специальным символом | < >, проблема не возникает. Перед выполнением любой команды я запускаю check-params.pl и check-pipe.pl, чтобы проверить, как Perl-скрипты будут воспринимать параметры командной строки, например, вышеприведенная правка к моему ОП описывает эти скрипты, которые я изменил после моего ОП.

7
задан Ross Ure Anderson 1 November 2011 в 15:23
поделиться