Регулярные выражения – Select-String

regexp-7 Итак, подведём итоги этого года🙂 В области регулярных выражений разумеется🙂 Мы успели познакомится с основами, отрицательными группами и якорями, квантификаторами, группами захвата, операторами –replace и –split, а так же с концепцией “жадности”. Пришло время познакомится с целым командлетом PowerShell, который использует регулярные выражения. Таким командлетом является Select-String. Он используется для поиска строк совпадающих с регулярным выражением. Строки для отбора можно передать из массива строк, например:

PS C:\> $lines = Get-Content C:\Windows\setupact.log
PS C:\> $lines | Select-String "error"

dispci.dll:  DispCIOpenDxgKrnlAndDisableNewReferences: D3DKMTOpenAdapterFromDeviceName failed with error 0xc000007a.
[10/24/2009 20:47.16.192] WudfCoInstaller: Final status: error(0) The operation completed successfully.
[10/26/2009 14:45.08.912] WudfCoInstaller: Final status: error(0) The operation completed successfully.
[10/27/2009 18:24.13.032] WudfCoInstaller: Final status: error(0) The operation completed successfully.
[10/27/2009 18:24.14.421] WudfCoInstaller: Final status: error(0) The operation completed successfully.
[11/02/2009 11:32.22.880] WudfCoInstaller: Final status: error(0) The operation completed successfully.
[11/13/2009 15:16.16.837] WudfCoInstaller: Final status: error(0) The operation completed successfully.

Еще можно указывать файлы для проверки содержащихся в них строк, просто указав их путь, или маску (с помощью обычных подстановочных знаков). Так в следующем примере я делаю поиск строки error: во всех файлах *.log в папке c:\Windows:

PS C:\> Select-String "error:" C:\Windows\*.log

TSSysprep.log:7:sysprep.cpp(314)ERROR: ResetTSPublicPrivateKeys() FAILED: 2
WindowsUpdate.log:2663:2009-10-31    15:11:26:983     896    13fc    PT    WARNING: PTError: 0x80072ee2
WindowsUpdate.log:3926:2009-11-01    19:09:14:748     896    548    PT    WARNING: PTError: 0x8024402c
WindowsUpdate.log:3930:2009-11-01    19:09:14:749     896    548    PT    WARNING: PTError: 0x8024402c
WindowsUpdate.log:3941:2009-11-01    19:09:28:778     896    548    PT    WARNING: PTError: 0x8024402c
WindowsUpdate.log:3945:2009-11-01    19:09:28:778     896    548    PT    WARNING: PTError: 0x8024402c
WindowsUpdate.log:3956:2009-11-01    19:09:42:808     896    548    PT    WARNING: PTError: 0x8024402c
WindowsUpdate.log:3960:2009-11-01    19:09:42:808     896    548    PT    WARNING: PTError: 0x8024402c

Select-String отличается от конструкции where {$_ -match "error:"} тем что выводит не просто совпадения строк, а полноценные объекты содержащие дополнительную информацию. В данном случае были выведены не только совпавшие строки, но и файлы в которых они были найдены (TSSysprep.log и WindowsUpdate.log), и номера строк. Полный список доступных свойств можно посмотреть следующей командой:

PS C:\> Select-String "error:" C:\Windows\*.log | 
>> Get-Member -MemberType property

   TypeName: Microsoft.PowerShell.Commands.MatchInfo

Name       MemberType Definition
----       ---------- ----------
Context    Property   Microsoft.PowerShell.Commands.MatchInfoContext Context {get;set;}
Filename   Property   System.String Filename {get;}
IgnoreCase Property   System.Boolean IgnoreCase {get;set;}
Line       Property   System.String Line {get;set;}
LineNumber Property   System.Int32 LineNumber {get;set;}
Matches    Property   System.Text.RegularExpressions.Match[] Matches {get;set;}
Path       Property   System.String Path {get;set;}
Pattern    Property   System.String Pattern {get;set;}

Давайте например выведем только имена файлов и номера совпавших строк:

PS C:\> Select-String "error:" C:\Windows\*.log | 
>> Format-Table Path, LineNumber -AutoSize

Path                         LineNumber
----                         ----------
C:\Windows\TSSysprep.log              7
C:\Windows\WindowsUpdate.log       2663
C:\Windows\WindowsUpdate.log       3926
C:\Windows\WindowsUpdate.log       3930
C:\Windows\WindowsUpdate.log       3941
C:\Windows\WindowsUpdate.log       3945
C:\Windows\WindowsUpdate.log       3956
C:\Windows\WindowsUpdate.log       3960

Если весь этот "объектный мусор" вам не нужен, вы можете получить только строки, следующей командой:

PS C:\> Select-String "error:" C:\Windows\*.log | 
>> Select-Object -ExpandProperty line

sysprep.cpp(314)ERROR: ResetTSPublicPrivateKeys() FAILED: 2
2009-10-31      15:11:26:983     896    13fc    PT      WARNING: PTError: 0x80072ee2
2009-11-01      19:09:14:748     896    548     PT      WARNING: PTError: 0x8024402c
2009-11-01      19:09:14:749     896    548     PT      WARNING: PTError: 0x8024402c
2009-11-01      19:09:28:778     896    548     PT      WARNING: PTError: 0x8024402c
2009-11-01      19:09:28:778     896    548     PT      WARNING: PTError: 0x8024402c
2009-11-01      19:09:42:808     896    548     PT      WARNING: PTError: 0x8024402c
2009-11-01      19:09:42:808     896    548     PT      WARNING: PTError: 0x8024402c

У Select-String есть и несколько дополнительных возможностей. Так если вам не интересно знать какие строки совпали, а лишь необходимо выяснить были ли совпадения вообще, воспользуйтесь ключем -Quiet:

PS C:\> netsh advfirewall firewall show rule "Remote Desktop (TCP-In)" | 
>> select-string "Enabled:\s+Yes" -Quiet
True

Эта команда проверяет, содержится ли в выводе netsh строка совпадающая с Enabled:\s+Yes и если содержится, то выводит значение $True. Разумеется тут тоже можно указывать напрямую имя файла или несколько с помощью подстановочных символов, тогда True будет выдано в случае если хотя бы один из файлов содержит указанную строку.

Параметр -List говорит Select-String что нужно найти лишь по одному совпадению на каждый файл. Это может быть полезно если вам надо найти все файлы содержащие определенную строку:

PS C:\> Select-String "error:" C:\Windows\*.log -List | 
>> select -ExpandProperty path
C:\Windows\TSSysprep.log
C:\Windows\WindowsUpdate.log

В PowerShell 2.0 у Select-String появился еще один очень полезный ключ — -Context. Он позволяет вывести не только совпавшую строку, но еще и указанное количество строк до неё и после неё. В следующем примере выводится 3 строки предшествующих совпадению и одна после него:

PS C:\> Select-String "error:" C:\Windows\TSSysprep.log -Context 3,1

  Windows\TSSysprep.log:4:*******Version:Major=6, Minor=1, Build=7600, PlatForm=2, CSDVer=, Free
  Windows\TSSysprep.log:5:
  Windows\TSSysprep.log:6:sysprep.cpp(309)Entering RCMSysPrepRestore
> Windows\TSSysprep.log:7:sysprep.cpp(314)ERROR: ResetTSPublicPrivateKeys() FAILED: 2
  Windows\TSSysprep.log:8:sysprep.cpp(316)Leaving RCMSysPrepRestore

Непосредственно совпавшая строка помечается с помощью символа > в начале строки. Если указать в качестве аргумента не массив из двух элементов, а просто число, то будет выведено указанное количество строк с обоих сторон от совпадения:

PS C:\> netsh advfirewall firewall show rule "Remote Desktop (TCP-In)" | 
>> select-string "Enabled:" -Context 2

  Rule Name:                            Remote Desktop (TCP-In)
  ----------------------------------------------------------------------
> Enabled:                              Yes
  Direction:                            In
  Profiles:                             Domain,Private,Public

В Select-String тоже можно использовать группы захвата, хотя получить их содержимое несколько сложнее. Дело в том что тут не используется специальная переменная $Matches, а вместо неё результаты совпадаения, в виде объекта System.Text.RegularExpressions.Match помещаются в свойство Matches результирующего объекта. Подробнее устройство этого объекта мы рассмотрим позднее, когда будем изучать класс [Regex], а пока я просто покажу как же можно получить например значение первой группы захвата:

PS C:\> Select-String "error: (\S+)" C:\Windows\*.log | 
>> Format-table path,linenumber,{$_.Matches[0].groups[1].value}

Path                         LineNumber $_.Matches[0].groups[1].value
----                         ---------- -----------------------------
C:\Windows\TSSysprep.log              7 ResetTSPublicPrivateKeys()
C:\Windows\WindowsUpdate.log       2663 0x80072ee2
C:\Windows\WindowsUpdate.log       3926 0x8024402c
C:\Windows\WindowsUpdate.log       3930 0x8024402c
C:\Windows\WindowsUpdate.log       3941 0x8024402c
C:\Windows\WindowsUpdate.log       3945 0x8024402c
C:\Windows\WindowsUpdate.log       3956 0x8024402c
C:\Windows\WindowsUpdate.log       3960 0x8024402c

Другие полезные параметры командлета на которые стоит обратить внимание, это -CaseSensetive, -Encoding и -NotMatch. Их названия говорят сами за себя, поэтому не буду показывать примеры для каждого.

Продолжение следует, но уже в следующем году🙂

Пользуясь случаем хочу пожелать всем читателям моего блога успехов в следующем году. Чтобы скрипты экономили вам еще больше времени принося больше дохода, и доставляя всё больше удовольствия от работы. Ну и просто счастья и здоровья конечно🙂 До встречи в новом году!

комментариев 12 to “Регулярные выражения – Select-String”

  1. Регулярные выражения – Жадность « PowerShell и другие скрипты Says:

    […] Select-String Опубликовано в Regular Expressions. Метки: Regular Expressions. 1 […]

  2. Юрий Says:

    Большое спасибо за статью.
    Правда groups[0].
    Василий, если в предыдущую сатью вы добавите пример кода, демонстрирующий получение не единичного $matches, а множественного, в пайпе, для набора строк, то я вам буду весьма признателен. Для общего понимания так сказать.

    • Xaegr Says:

      Если мы хотим получить не всю совпавшую строку, а только содержимое группы захвата — то всё таки groups[1].
      Про несколько совпадений будет, но уже дальше.

  3. Юрий Says:

    Кроме того у меня частный вопрос.
    Я пытаюсь выделить из каждой строки набора длинных строк по 3 подстроки, но мне не удаётся разделить регулярное выражение на подвыражения, чтобы получить массив matches с глубиной, отличной от [1]. Какого синтаксиса необходимо придерживаться в select-string для этого?

    • Юрий Says:

      Как обычно, верить и ждать, про всё будет написанно позднее?🙂

    • Xaegr Says:

      Для двух подстрок:
      Select-String «(\d{3}).+error: (\S+)» C:\Windows\*.log |
      Format-table path,linenumber,{$_.Matches[0].groups[1].value}, {$_.Matches[0].groups[2].value}

      • Юрий Says:

        Оу, в самом деле скобки работают. А я то в Matches[]. индексы менял. Напрасно оказывается.
        Большое спасибо!

  4. Дима Says:

    как решить такую проблему
    $list = dir «c:\windows»
    но в данном наборе должно остаться все кроме например -like «*.txt», как я понимаю нельзя при where комбинировать -ne и -like
    заранее тнкс

  5. Xaegr Says:

    Во-первых всё кроме *.txt можно получить так:
    dir C:\Windows\ -exclude *.exe
    Во-вторых во where можно комбинировать что угодно, и как угодно. {} — это скриптблок, и там может быть всё, в том числе и несколько сравнений:
    dir C:\Windows\ | where {$_.extension -eq «.exe» -and $_.length -gt 50kb}
    Но вы наверное имели ввиду оператор -notlike ?🙂
    gps | where {$_.path -notlike «c:\windows\*»}
    У Select-String есть аналогичный по смыслу ключ -NotMatch, который инвернтирует действие командлета, то есть выводит всё то что не совпадает с заданной маской.

  6. Дмитрий Says:

    добрый день.
    Спасибо, или я не тот «мануал» читал, но -notlike в описании возможных операторов не видел.
    большое спасибо еще раз.

    • Xaegr Says:

      Не за что.
      В «правильном» мануале всё на месте🙂
      about_Comparison_Operators
      about_operators

  7. Регулярные выражения – Switch « PowerShell и другие скрипты Says:

    […] Регулярные выражения – Switch 24.2.2010 — Xaegr Ну чтож, пора новогодних каникул давно закончилась, и мне стало уже тяжело находить отмазки на вопросы о продолжении серии Так как времени с момента предыдущего поста прошло уже немало времени, да и для тех кто натолкнулся на этот пост случайно – вот ссылки на посты которые рекомендуется прочитать сначала: 1, 2, 3, 4, 5, 6, 7. […]


Обсуждение закрыто.

%d такие блоггеры, как: