Побочный эффект двойных кавычек в командной строке Windows - PullRequest
7 голосов
/ 29 октября 2011

Я столкнулся с очень странной проблемой с интерпретатором команд 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^|"

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

например, если я сделаю это -

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 для обработки файлов веб-журнала, и одиниспользует регулярные выражения, которые я передаю в кавычках в командной строке.Регулярное выражение может содержать такие символы, как |<>, и в нем также может быть двойная кавычка, которую я ввожу как \ ". Таким образом, вышеупомянутая проблема обостряется.

Любая помощь очень ценится, спасибо.


Спасибодля ответа, но при попытке сделать это в 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, и та же проблема возникает там с вышеупомянутым эхо-тестом.


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

Я обновил контрольные параметры сценариев.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]

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


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

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

1 Ответ

2 голосов
/ 30 октября 2011

Двойная кавычка в \ "считается совпадающей с начальной двойной кавычкой, заканчивающейся параметром в кавычках. Для включения двойной кавычки в параметр в кавычках используйте две двойные кавычки:

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

должен дать ожидаемый результат, в зависимости от того, как perl.exe анализирует параметры командной строки (я тестировал с использованием командных сценариев, так как у меня не установлен Perl). Вам нужно будет изменить свой сценарий, чтобы "" вместо \ "обрабатывалось как двойная кавычка.

Дополнительно : эта командная строка

echo "a \"b|c"

приводит к сообщению об ошибке, начиная с c" is not recognized. Это не ошибка.

Обратная косая черта не является escape-символом, поэтому командная строка содержит одну строку в кавычках ("a \"), за которой следует символ (|), который делает остальные (c") дополнительной командой, которую выводит команда echo передается по каналу.

Если вы вместо этого скажете

echo "a ""b|c"

тогда есть только одна строка в кавычках ("a ""b|c"), и она будет работать как положено.

К сожалению, теперь я могу подтвердить, что анализ ActivePerl из командной строки вызывает

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

для разделения на два параметра. Вам может потребоваться получить всю командную строку (если есть способ сделать это в Perl) и проанализировать ее самостоятельно.

Дополнительный

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

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

...