Как отфильтровать строки в powershell, которые взяты из консольной программы? - PullRequest
2 голосов
/ 08 апреля 2019

У меня есть консольная программа .exe, которая помещает результат в консоль в следующем формате:

 ------------------ ----------- ----------------
  CompanyName        CompanyId   CompanyType
 ------------------ ----------- ----------------
  test1              1           Root
  test2              2           Center
  test3              3           Company
 ------------------ ----------- ----------------

Я бы хотел получить это в скрипте PowerShell и отфильтровать по CompanyName.

Я попробовал это с:

MyTool.exe companies | where {$_.CompanyName -eq 'test1'}

но похоже, что это не работает.

Ответы [ 2 ]

3 голосов
/ 08 апреля 2019

Вот один из способов преобразовать выходные данные EXE в набор объектов powershell. что он делает ...

  • создает поддельную версию вывода вашего exe-файла
  • отфильтровывает строки с повторяющимися дефисами
  • заменяет начальные пробелы ничем
  • заменяет 2 или более пробелов запятой
  • преобразует этот строковый массив в стиле CSV в набор объектов powershell

вот код [ ухмылка ] ...

# fake getting string output from an EXE
$InStuff = @'
 ------------------ ----------- ----------------
  CompanyName        CompanyId   CompanyType
 ------------------ ----------- ----------------
  test1              1           Root
  test2              2           Center
  test3              3           Company
 ------------------ ----------- ----------------
'@ -split [environment]::NewLine

$CompanyInfo = $InStuff -notmatch '--{2,}' -replace '^ {1,}' -replace ' {2,}', ',' |
    ConvertFrom-Csv

$CompanyInfo
'=' * 30
$CompanyInfo -match 'Test1'

вывод ...

CompanyName CompanyId CompanyType
----------- --------- -----------
test1       1         Root       
test2       2         Center     
test3       3         Company    
==============================
test1       1         Root  
1 голос
/ 08 апреля 2019

PowerShell сообщает о выводе внешней программы в виде массива строк (строки).

Чтобы отфильтровать такой вывод с использованием анализа строки, используйте оператор -match:

# Extract the line of interest with -match and a regex
PS> @(MyTool.exe companies) -match '^\s+test1\s'
test1              1           Root

Примечание:

  • @(...), хотя здесь это не является строго необходимым, гарантирует, что вывод MyTool.exe станет массивом , даже если это произойдет свыведите только одну строку, так что -match выполняет фильтрацию для этого массива (при скалярном LHS -match возвращает логическое значение ).

  • Regex ^\s+test1\s соответствует одному или нескольким (+) пробельным символам (\s) в начале каждой строки (^), за ними следует литерал test1, за которым следуетсимвол пробела - тем самым ограничивая соответствие столбцу CompanyName.

Если вы хотите проанализировать результат в отдельных полях:

# Extract the line of interest with -match and a regex, 
# then split that line into whitespace-separated tokens and store
# them in individual variables.
PS> $name, $id, $type = -split (@(MyTool.exe companies) -match '^\s+test1\s')
PS> $name, $id, $type  
test1
1
Root

Ответ Ли Дейли :

  • показывает, как вместо этого анализировать вывод вашей внешней программы в custom objects , свойства которого вы можете запросить , сначала преобразовав вывод вашей программы в текст CSV, а затем проанализировав его в пользовательских объектах с помощью ConvertFrom-Csv.

    • Хотя это оченьво многом в духе PowerShell, вы неизбежно платите штраф за производительность, а для извлечения простых подстрок это может не стоить.
  • тогда, к сожалению, упускает преимущества наличияпроанализировал входные данные в объекты , вернувшись к сопоставлению строк, которое сводит на нет преимущества наличия сопоставления отдельных свойств в своем распоряжении:

    • применение -match - a * 1069оператор * string - для пользовательского объекта LHS приводит к хеш-таблице - как представление для display , то есть not подходит дляпрограммная обработка;Например:
      @{CompanyName=test1; CompanyId=1; CompanyType=Root}

    • поэтому - если говорить абстрактно - использование -match может привести к ложным срабатываниям - потому что соответствие не ограниченок интересующему объекту.

Вкратце: если вы столкнулись с проблемой разбора ввода в объекты - при необходимости вообще- используйте их свойства для надежной фильтрации, как вы пытались в своем вопросе:

  • $CompanyInfo | where {$_.CompanyName -eq 'test1'}
  • или, более кратко, используя синтаксис PSv3 +:
    $CompanyInfo | where CompanyName -eq test1
  • или, что более эффективно, в PSv4 + с использованием метода массива .Where() :
    $CompanyInfo.Where({ $_.CompanyName -eq 'test1'})
...