RegEx для сопоставления строки между двумя строками в Powershell - PullRequest
0 голосов
/ 16 ноября 2018

Вот мои примеры данных:

Опция failonnomatch на
Опция пакета на
Опция подтверждения Выкл.
open sftp: // username: password@host.name.net: 22 hostkey = "ssh-rsa 1024 00: 00: 00: 00: 00: 00: 00: 00: 00: 00: 00: 00: 00: 00: 00: 00"

получить файл *.txt \ local \ path \ Client \ File.txt
mv File * .txt / remote / archive /

закрыть
exit

Я хочу создатьскрипт powershell для извлечения фрагментов информации из этого текстового файла.

Список необходимых мне предметов:

  • Имя пользователя
  • Пароль
  • Хост
  • Порт
  • sshклавиша
  • Имя файла
  • Локальный путь
  • Удаленный путь

Я надеюсь, что если я научусь делать пару из них,метод будет применим ко всем пунктам.Я попытался извлечь ключ ssh с помощью следующего powershell / regex:

$doc -match '(?<=hostkey=")(.*)(?=")' 

$ doc, являющийся примером данных

, но, похоже, он возвращает всю строку,Любая помощь будет принята с благодарностью.Спасибо.

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

это использует именованные совпадения с флагами, установленными на singleline, multiline, case insensitive, а затем использует $Matches.MatchName, чтобы получить элементы в пользовательский объект.

# fake reading in a text file as one string
#    in real life, use Get-Content -Raw
$InStuff = @'
open sftp://username:password@host.name.net:22 hostkey="ssh-rsa 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"

get File*.txt \SERVER\Path\Client\File.txt
'@

$Null = $InStuff -match '(?smi).+//(?<UserName>.+):(?<Password>.+)@(?<HostName>.+):(?<Port>.+) hostkey="(?<SshKey>.+)".+get .+ (?<FullFileName>\\.+)$'

[PSCustomObject]@{
    UserName = $Matches.UserName
    Password = $Matches.Password
    Port = $Matches.Port
    SshKey = $Matches.SshKey
    PathName = Split-Path -Path $Matches.FullFileName -Parent
    FileName = Split-Path -Path $Matches.FullFileName -Leaf
    }

вывод ...

UserName : username
Password : password
Port     : 22
SshKey   : ssh-rsa 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
PathName : \SERVER\Path\Client
FileName : File.txt
0 голосов
/ 16 ноября 2018

Если -match возвращает всю строку , это означает, что LHS вашей -match операции представляет собой массив , , что, в свою очередь, предполагает, что вы использовали Get-Content без -Raw, что дает входные данные в виде массива из строк , в какой случай -match действует как фильтр .

Вместо этого читайте ваш файл как одну многострочную строку с Get-Content -Raw; с скаляром LHS,
-match затем возвращает [bool]
, и результаты операции сопоставления сообщаются в автоматической переменной $Matches (хеш-таблица, чья запись 0 содержит общее совпадение, 1 соответствует первой группе захвата, ...):

# Read file as a whole, into a single, multi-line string.
$doc = Get-Content -Raw file.txt 

if ($doc -match '(?<=hostkey=")(.*)(?=")') {
   # Output what the 1st capture group captured
   $Matches[1]
}

При вводе пробы приведенное выше дает
ssh-rsa 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00


Затем вы можете расширить подход для захвата нескольких токенов, и в этом случае я предлагаю , используя с именем Группы захвата ((?<name>...)); В следующем примере такие именованные группы захвата используются для извлечения нескольких токенов:

if ($doc -match '(?<=sftp://)(?<username>[^:]+):(?<password>[^@]+)@(?<host>[^:]+)'){
  # Output the named capture-group values.
  # Note that index notation (['username']) and property
  # notation (.username) can be used interchangeably.
  $Matches.username
  $Matches.password
  $Matches.host
}

При вводе пробы приведенные выше значения:

username
password
host.name.net

Вы можете расширить вышеупомянутое, чтобы захватить все токенов интереса.
Обратите внимание, что . по умолчанию не соответствует \n (новая строка) символов.


Необязательное чтение: использование опции x (IgnoreWhiteSpace), чтобы сделать регулярные выражения более читабельными:

Извлечение такого количества токенов может привести к сложному регулярному выражению, которое трудно прочитать, и в этом случае может помочь опция x (IgnoreWhiteSpace) regex (в качестве встроенного параметра, (?x) в начале регулярное выражение):

if ($doc -match '(?x)
    (?<=sftp://)(?<username>[^:]+)
    :(?<password>[^@]+)
    @(?<host>[^:]+)
    :(?<port>\d+)
    \s+hostkey="(?<sshkey>.+?)"
    \n+get\ File\*\.txt\ (?<localpath>.+)
    \nmv\ File\*\.txt\ (?<remotepath>.+)
  '){
    # Output the named capture-group values.
    $Matches.GetEnumerator() | ? Key -ne 0
}

Обратите внимание, что пробел, используемый для того, чтобы сделать регулярное выражение более читабельным (разбрасывая его по нескольким строкам), игнорируется при сопоставлении, тогда как пробел для сопоставления во входных данных должен быть , экранированный ( например, чтобы соответствовать одному пробелу, \ или [ ], или \s, чтобы соответствовать любому символу пробела.)

С вашим примером ввода приведенное выше дает следующее:

Name                           Value
----                           -----
host                           host.name.net
localpath                      \local\path\Client\File.txt
port                           22
sshkey                         ssh-rsa 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
remotepath                     /remote/archive/
password                       password
username                       username

Обратите внимание, что причина, по которой группы захвата вышли из строя, заключается в том, что $Matches является хеш-таблицей (типа [hashtable]), чей порядок перечисления ключей является реализацией Артефакт: особый порядок перечисления не гарантируется.

Однако произвольный доступ к группам захвата работает просто отлично; например, $Matches.port вернет 22.

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