Powershell, как захватить аргумент (ы) Select-String и включить с согласованным выводом - PullRequest
1 голос
/ 14 июля 2020

Спасибо @ mklement0 за помощь в достижении этого с ответом, приведенным в Каталог поиска Powershell для файлов кода с сопоставлением текста введите текстовый файл .

Powershell ниже работает хорошо для поиск вхождений длинного списка имен полей базы данных в папке исходного кода.

$inputFile = 'C:\DataColumnsNames.txt'
$outputFile = 'C:\DataColumnsUsages.txt'
Get-ChildItem C:\ProjectFolder -Filter *.cs -Recurse -Force -ea SilentlyContinue |
  Select-String -Pattern (Get-Content $inputFile) | 
    Select-Object Path, LineNumber, line | 
      Export-csv $outputfile

Однако многие строки исходного кода имеют несколько совпадений, особенно ADO. NET SQL операторов с большим количеством имен полей в одной строке. Если аргумент имени поля был включен в совпадающие выходные данные, результаты будут более полезными с меньшими дополнительными манипуляциями, такими как выравнивание всего с исходным списком имен полей. Например, если есть исходная строка «BatchId = NewId», она будет соответствовать элементу списка имен полей «BatchId». Есть ли простой способ включить в вывод как «BatchId», так и «BatchId = NewId»?

Проигрывал с объектом совпадений, но, похоже, у него нет информации. Также пробовал переменную конвейера, как здесь, но X имеет значение null.

$inputFile = 'C:\DataColumnsNames.txt'
$outputFile = 'C:\DataColumnsUsages.txt'
Get-ChildItem C:\ProjectFolder -Filter *.cs -Recurse -Force -ea SilentlyContinue |
  Select-String -Pattern (Get-Content $inputFile -PipelineVariable x) | 
    Select-Object $x, Path, LineNumber, line | 
      Export-csv $outputile

Спасибо.

Ответы [ 2 ]

1 голос
/ 14 июля 2020

Экземпляры Microsoft.PowerShell.Commands.MatchInfo, которые выходят Select-String, имеют свойство a Pattern, которое отражает конкретный образец c среди (потенциальных) массив шаблонов, переданных в -Pattern, который соответствует в данной строке .

предостережение - это if совпадение нескольких шаблонов, .Pattern сообщает только шаблон среди совпавших, который указан первый среди них в -Pattern аргументе .

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

'A fool and',
'his barn',
'are soon parted.',
'foo and bar on the same line' | 
  Select-String -Pattern ('bar', 'foo') | 
    Select-Object  Line, LineNumber, Pattern

Результат выше:

Line                         LineNumber Pattern
----                         ---------- -------
A fool and                            1 foo
his barn                              2 bar
foo and bar on the same line          4 bar

Обратите внимание, что 'bar' отображается как значение Pattern для последней строки, даже если 'foo' появилось первым в строке ввода , потому что 'bar' стоит перед 'foo' в массиве шаблонов .

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

  • Сформулируйте свой массив шаблонов как одиночное регулярное выражение с использованием чередования (|), заключенного в виде целого в группу захвата ((...)) - например, '(bar|foo)')

    • Примечание: выражение, используемое ниже, '({0})' -f ('bar', 'foo' -join '|'), создает это регулярное выражение динамически из массива (здесь литерал массива 'bar', 'foo', но можно подставить любую переменную массива или даже (Get-Content $inputFile)); если вы хотите обрабатывать входные шаблоны как литералы и они содержат метасимволы регулярных выражений (например, .), вам нужно сначала экранировать их с помощью [regex]::Escape().
  • Используйте вычисляемое свойство, чтобы определить настраиваемое свойство Pattern, которое сообщает значение группы захвата, которое является первым среди значений, встречающихся в каждой строке ввода:

'A fool and',
'his barn',
'are soon parted.',
'foo and bar on the same line' | 
  Select-String -AllMatches -Pattern ('({0})' -f ('bar', 'foo' -join '|')) | 
    Select-Object Line, LineNumber, 
                  @{ n='Pattern'; e={ $_.Matches[0].Groups[1].Value } }

Это дает (сокращенно, чтобы показать только последнее совпадение):

Line                         LineNumber Pattern
----                         ---------- -------
...

foo and bar on the same line          4 foo

Теперь 'foo' правильно отображается как совпадающий шаблон.

К сообщать все шаблоны, найденные в каждой строке :

  • Переключатель -AllMatches необходим, чтобы сообщить Select-String найти все совпадения в каждой строке, представленные в коллекции .Matches объектов вывода MatchInfo.

  • Затем необходимо перечислить коллекцию .Matches (через .ForEach() метод сбора) для извлечения значения группы захвата из каждого совпадения.

'A fool and',
'his barn',
'are soon parted.',
'foo and bar on the same line' | 
  Select-String -AllMatches -Pattern ('({0})' -f ('bar', 'foo' -join '|')) | 
    Select-Object Line, LineNumber, 
                  @{ n='Pattern'; e={ $_.Matches.ForEach({ $_.Groups[1].Value }) } }

Это дает (сокращенно, чтобы показать только последнее совпадение):

Line                         LineNumber Pattern
----                         ---------- -------
...

foo and bar on the same line          4 {foo, bar}

Обратите внимание, что и 'foo', и 'bar' теперь сообщаются в Pattern в том порядке, в котором они встречаются в строке.

0 голосов
/ 16 июля 2020

Информации solid и примеров из @ mklement0 было достаточно, чтобы указать мне правильное направление для исследования и понимания Powershell, конвейера объектов и вычисляемых свойств.

Я наконец-то смог достичь своих цели перекрестной ссылки на список имен таблиц и полей с базой кода C#. Входной файл - это просто имена таблиц и полей, разделенные вертикальной чертой. (один из моих сбоев заключался в том, что в разделении не использовалась труба, это была визуальная ошибка, которую потребовалось некоторое время, чтобы наконец увидеть, так что проверьте это). Результатом является имя таблицы, имя поля, имя файла кода, номер строки и фактическая строка. Это не идеально, но намного лучше, чем ручные усилия для нескольких сотен полей! И теперь есть возможности для дальнейшей автоматизации в проекте отображения и преобразования данных. Подумал об использовании C# служебных программ, но это могло занять столько же времени, чтобы выяснить и реализовать, и гораздо более громоздко, чем работающая Powershell.

Ключевым моментом для меня на данном этапе является «работа»! Мое первое более глубокое погружение в непонятный мир Powershell. Ключевыми моментами моего решения являются использование вычисляемого свойства для получения имен таблиц и полей в выходных данных, осознание того, что выражения могут использоваться в определенных местах, например, для создания шаблона, и что конвейер передает только определенные спецификации c объекты после каждой команды (возможно, это слишком ограниченное представление, но это лучше, чем то, что было у меня раньше).

Надеюсь, это поможет кому-то в будущем. Я не смог найти достаточно близких примеров, чтобы преодолеть горб, и поэтому задал свои самые первые вопросы по стековому потоку.

$inputFile = "C:\input.txt"
$outputFile = "C:\output.csv"
$results = Get-Content $inputfile
foreach ($i in $results) {
   Get-ChildItem -Path "C:\ProjectFolder"  -Filter *.cs  -Recurse -ErrorAction SilentlyContinue -Force |
   Select-String -Pattern  $i.Split('|')[1] |
    Select-Object   @{ n='Pattern'; e={ $i.Split('|')[0], $i.Split('|')[1]  -join '|'} },  Filename, LineNumber, line |
Export-Csv $outputFile -Append}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...