Как найти строку в нескольких файлах и вернуть имена файлов в Powershell?


303

Я начал изучать PowerShell пару дней назад, и я не смог найти в Google ничего, что могло бы сделать то, что мне нужно, поэтому, пожалуйста, ответьте на мой вопрос.

Меня попросили заменить некоторые текстовые строки на несколько файлов. Я не обязательно знаю расширение возможных целевых файлов и не знаю, где они находятся. До сих пор мне удалось рекурсивно просмотреть каталог ( get-ChildItem -recurse) и найти искомую строку с помощью get-content и select-string:

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"

Проблема в том, что я вижу вхождения искомого текста, но я не знаю, как сказать PS, чтобы он возвращал путь и имя для каждого соответствующего файла.

Как я могу получить имя и расположение файлов, которые содержат искомое выражение?


2
Возможно, отредактируйте вопрос, чтобы он был более общим. Кажется, что ответ на этот вопрос не имеет ничего общего с JBoss или вашим приложением, над которым вы работаете ...
Kolob Canyon

5
Я только заметил ваш комментарий и отредактировал мой вопрос ... 2 года спустя! лучше поздно, чем никогда .. :)
Bluz

Ответы:


469

Это должно дать расположение файлов, которые содержат ваш шаблон:

Get-ChildItem -Recurse | Select-String "dummy" -List | Select Path

3
Что делать, если вы также хотите переместить эти файлы? ... Я получаю сообщение об ошибке, когда не могу присоединиться к | Move-Item до конца этого.
rud3y

6
Move-Item не имеет nameпараметра. Попробуйте добавить| %{Move-Item $_.name <destination>}
Джон Z

49
Get-ChildItem -Recurse | Select-String "dummy" -List | Select Pathвозвращает только первое совпадение для каждого файла, поэтому может быть немного более эффективным и избавляет от необходимости группировать их
Бен

5
Стоит заметить, что вы можете фильтровать только файлы определенного типа, скажем, txtфайлы, если вы используете Get-ChildItem -Recurse -Filter *.txtвместо этого
Girardi

@ rud3y Я настоятельно рекомендую вам записать это в сценарии с использованием foreachцикла, если вы делаете такие большие операции. Это становится очень запутанным, когда вы пытаетесь сделать все это в одной строке, и очень легко сделать большую ошибку. Я говорю из опыта
Колоб Каньон

75

Здесь есть множество точных ответов, но здесь приведен наиболее краткий код для нескольких различных вариантов. Для каждого варианта в верхней строке показан полный синтаксис, а в нижней - краткий синтаксис.

Пункт (2) является более сжатой формой ответов от Jon Z и manojlds, тогда как пункт (1) эквивалентен ответам от vikas368 и buygrush.

  1. Список объектов FileInfo для всех файлов, содержащих шаблон:

    Get-ChildItem -Recurse filespec | Where-Object { Select-String pattern $_ -Quiet }
    ls -r filespec | ? { sls pattern $_ -q }
    
  2. Список имен файлов для всех файлов, содержащих шаблон:

    Get-ChildItem -Recurse filespec | Select-String pattern | Select-Object -Unique Path
    ls -r filespec | sls pattern | select -u Path
    
  3. Список объектов FileInfo для всех файлов, не содержащих шаблон:

    Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }
    ls -r filespec | ? { !(sls pattern $_ -q) }
    
  4. Список имен файлов для всех файлов, не содержащих шаблон:

    (Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }).FullName
    (ls -r filespec | ? { !(sls pattern $_ -q) }).FullName
    

Кроме того, если вы просто ищете файлы, которые содержат шаблон в любом месте, вы можете отказаться от поиска первого экземпляра, используя -ListпараметрSelect-String
KyleMit

Я хотел бы, чтобы ФП задал небольшую вариацию вопроса, чтобы это был АА. # 1 был очень полезен, и очевидно, что @Mikhael Sorens засовывает PS!
cBlaine

20

Это отобразит путь, имя файла и найденную им строку содержимого, которые соответствуют шаблону.

Get-ChildItem -Path d:\applications\*config -recurse |  Select-String -Pattern "dummy" 

Если бы между результатами можно было добавить только строку :)
cladelpino

15

Труба содержание вашего

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy"

в fl *

Вы увидите, что путь уже возвращается как свойство объектов.

Если вам нужен только путь, используйте select pathили select -unique pathдля удаления дубликатов:

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy" | select -unique path

1
Спасибо вам обоим, это именно то, что я ищу. К сожалению, когда в этом пути много подкаталогов, то PS обрезает абсолютный путь и добавляет три точки в конце строки, например \ dir1 \ dir2 \ dir3 \ path ... поэтому я не знаю, какой файл возвращается , Есть ли способ сказать PS быть менее жадным к персонажам и не показывать полный путь? :) Большое спасибо !
Блюз

3
Вам нужно добавить -Fileпереключатель Get-ChildItemили вы получите бесконечный каскад ошибок при попытке вызвать Get-Contentкаталоги.
RubberDuck

Если вам нужен полный путь, вы можете сделать это. (Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy").FullNameЛюди, кажется, забывают, что PowerShell является объектно-ориентированным; если сомневаетесь, ищите недвижимость
Колоб Каньон

10

Вот как я бы это сделал, вам не нужен get-контент:

ls -r | Select-String dummy | select line,path

или

ls -r | Select-String dummy | fl *

Чтобы увидеть, что различные свойства ...

Это быстрее Второй аргумент -filter:

ls -r . *.bat | select-string netsh

2
+1, это прекрасно работает для моего случая, однако используйте select Pattern, LineNumber, Filenameдля более краткого вывода. Строка возвращает ВСЕ в строке, содержащей строку шаблона. Вы также можете легко вывести это в CSV, если хотите.
Протонова

9
Get-ChildItem -r | ? {$_.psiscontainer -eq $false} | ? {gc $_.pspath |select-string -pattern "dummy"}

Это даст вам полную информацию обо всех файлах


Совершенно не знал, что -rсработало. Я подумал, что ты всегда должен был это делать-Recurse
Каньон Колоб

5

Чтобы сохранить полную информацию о файле в результирующем массиве, вы можете использовать небольшую модификацию ответа, опубликованного vikas368 (который, похоже, плохо работает с автозаполнением ISE):

Get-ChildItem -Recurse | Where-Object { $_ | Select-String -Pattern "dummy" }

или короче говоря:

ls -r | ?{ $_ | Select-String -Pattern "dummy" }

5

Если вы ищете в одном каталоге, вы можете сделать это:

select-string -Path "c:\temp\*.*" -Pattern "result"  -List | select Path

4

Это отобразит список полного пути к каждому файлу, который содержит строку поиска:

foreach ($file in Get-ChildItem | Select-String -pattern "dummy" | Select-Object -Unique path) {$file.path}

Обратите внимание, что он не отображает заголовок над результатами и не отображает строки текста, содержащие строку поиска. Все, что он говорит вам, это где вы можете найти файлы, которые содержат строку.


2
Любая идея, как отобразить номер строки, где шаблон был найден, вместе с именем файла?
Петр Л

4

Я изменил один из ответов выше, чтобы дать мне немного больше информации. Это избавило меня от второго запроса позже. Это было что-то вроде этого:

Get-ChildItem `
        -Path "C:\data\path" -Filter "Example*.dat" -recurse | `
    Select-String -pattern "dummy" | `
    Select-Object -Property Path,LineNumber,Line | `
    Export-CSV "C:\ResultFile.csv"

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


Прохладно! Спасибо за это дополнительное решение :) Однако, не могли бы вы дать ссылку на ответ, на котором вы основали свое решение, и назвать автора этого ответа, чтобы отдать ему должное? Спасибо!
Макс Воллмер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.