Подшаблон
(?<name> .+?)\s+
в вашем регулярном выражении означает «сопоставьте и запомните один или несколько символов, не являющихся символом новой строки, но остановитесь, как только вы найдете пробел», поэтому $name
содержит TEST
, поскольку шаблон прекратил совпадение, когда увидел пространство незадолго до этого. Box
.
Вики VI Toolkit дает пример вывода подкоманды getallvms:
# vmware-vim-cmd -H 10.10.10.10 -U root -P password /vmsvc/getallvms
Vmid Name File Guest OS Version Annotation
64 bartPE [store] BartPE/BartPE.vmx winXPProGuest vmx-04
96 trustix [store] Trustix/Trustix.vmx otherLinuxGuest vmx-04
Случай немного отличается от примера в вашем вопросе, но, похоже, мы можем посмотреть [store]
как бампер для совпадения:
/^(?<id> \d+) \s+ (?<name> .+?) \s+ \[store]/mix
Нежадный квантификатор +?
означает совпадение одного или нескольких объектов, но совпадение хочет передать управление остальной части шаблона как можно быстрее. Помните, что [
имеет особое значение в регулярных выражениях, но шаблон \[
соответствует литералу, а не представляет класс символов.
Я думаю об этой технике, как обманывающий или растягивающий. Если вы хотите извлечь фрагмент текста, который трудно охарактеризовать, ищите окружающие функции, которые легко сопоставить - часто так просто, как ^
или $
. Затем используйте растягивающийся узор, чтобы захватить все промежуточное, обычно (.+)
или (.+?)
. Прочитайте раздел «Квантификаторы» документации perlre для объяснения множества вариантов.
Это решает непосредственную проблему, и вы также можете добавить полировку в нескольких областях.
Не используйте $1
, $2
и друзей безоговорочно! Всегда проверяйте соответствие шаблона перед использованием переменных захвата. Например
if (/(foo|bar|baz)/) {
print "got $1\n";
}
else {
print "no match\n";
}
Незащищенный print $1
может привести к неожиданным результатам, которые трудно отладить.
Разумное использование значений по умолчанию в Perl может помочь подчеркнуть вычисления и позволить механизму отойти на задний план. Отбрасывание $vm
в пользу $_
в качестве переменной неявного цикла и цели неявного соответствия приводит к более хорошему результату.
Ваши комментарии просто переводят с Perl на английский. Самые полезные комментарии объясняют почему , а не что. Также имейте в виду совет Роба Пайка о комментировании :
Если вашему коду нужен комментарий для понимания, было бы лучше переписать его, чтобы его было легче понять.
В заданиях от %+
кавычки не делают ничего полезного. Значения уже являются строками, поэтому удалите кавычки.
my $id = $+{id};
my $name = $+{name};
Ниже приведена модифицированная версия вашего кода, которая фиксирует все после числа, но до [store]
в $name
. utf8 pragma объявляет, что ваш исходный код - не так, как с обычной ошибкой - ваш ввод - содержит UTF-8. Приведенный ниже тест имитирует с помощью echo
вывода из vim-cmd
на шведской ВМ.
Как предположил Том, я использую модуль Encode для декодирования вывода, который поступает через соединение SSH, и кодирования его в интересах локального хоста перед его распечаткой.
Документация perlunifaq рекомендует декодировать внешние данные во внутренний формат Perl и затем кодировать любой вывод непосредственно перед его записью. Я предполагаю, что значение, возвращаемое из $ssh->capture(...)
, использует кодировку UTF-8, то есть удаленный хост отправляет UTF-8. Мы видим ожидаемый результат, потому что я работаю с современным дистрибутивом Linux и возвращаюсь к нему по ssh, но в дикой природе вы можете иметь дело с какой-то другой кодировкой.
Вы можете обойтись без пропуска вызовов на decode
и encode
, потому что внутренний формат Perl совпадает с форматом используемых вами хостов. В целом, однако, срезание углов может привести к неприятностям:
Наконец-то код!
#! /usr/bin/env perl
use strict;
use utf8;
use warnings;
use Encode;
use Net::OpenSSH;
my %ssh_options = ();
my $ssh = Net::OpenSSH->new('localhost', %ssh_options);
# Create an array and capture the ESX\ESXi output from the current server
#my @getallvms = $ssh->capture('vim-cmd vmsvc/getallvms');
my @getallvms = $ssh->capture(<<EOEcho);
echo -e 'JUNK\n416 TEST Box åäö!"'\\'\\''*# [Store] TEST Box +w6XDpMO2IQ-_''_+Iw/TEST Box +w6XDpMO2IQ _''_+Iw.vmx slesGuest vmx-04'
EOEcho
shift @getallvms;
for (@getallvms) {
$_ = decode "utf8", $_, Encode::FB_CROAK;
if (/^(?<id> \d+) \s+ (?<name> .+?) \s+ \[store]/mix) {
my $id = $+{id};
my $name = $+{name};
print encode("utf8", $id), "\n",
encode("utf8", $name), "\n",
"\n";
}
else {
print "no match\n";
}
}
Выход:
416
TEST Box åäö!"''*#