Comment rechercher une chaîne dans plusieurs fichiers et retourner les noms des fichiers dans Powershell?

303

J'ai commencé à apprendre le powershell il y a quelques jours, et je n'ai rien trouvé sur google qui fasse ce dont j'ai besoin, veuillez donc répondre à ma question.

On m'a demandé de remplacer certaines chaînes de texte dans plusieurs fichiers. Je ne connais pas forcément l'extension des fichiers cibles possibles et je ne connais pas non plus leur emplacement. Jusqu'à présent, j'ai réussi à parcourir récursivement le répertoire ( get-ChildItem -recurse) et à trouver la chaîne que je cherchais avec get-content et select-string:

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

Le problème est que je peux voir les occurrences du texte que je recherche, mais je ne sais pas comment dire à PS de renvoyer le chemin et le nom de tous les fichiers correspondants.

Comment obtenir le nom et l'emplacement des fichiers contenant l'expression que je recherche?

Bluz
la source
2
Peut-être modifier la question pour être plus générique. La réponse à cette question n'a rien à voir avec JBoss ou votre application sur laquelle vous travaillez semble-t-il ...
Kolob Canyon
5
Je viens de repérer votre commentaire et de modifier ma question ... 2 ans plus tard! mieux vaut tard que jamais .. :)
Bluz

Réponses:

469

Cela devrait donner l'emplacement des fichiers qui contiennent votre modèle:

Get-ChildItem -Recurse | Select-String "dummy" -List | Select Path
jon Z
la source
3
Que faire si vous souhaitez également déplacer ces fichiers? ... Je reçois une erreur avec ceci lorsque je ne peux pas rejoindre un | Move-Item à la fin de cela.
rud3y
6
Move-Item n'a pas de nameparamètre. Essayez d'ajouter| %{Move-Item $_.name <destination>}
jon Z
49
Get-ChildItem -Recurse | Select-String "dummy" -List | Select Pathrenvoie uniquement la première correspondance pour chaque fichier, ce qui peut être un peu plus efficace et éviter d'avoir à les regrouper
ben
5
il convient de noter que vous ne pouvez filtrer que pour un certain type de fichier, par exemple des txtfichiers, si vous utilisez à la Get-ChildItem -Recurse -Filter *.txtplace
Girardi
@ rud3y Je vous suggère fortement de l'écrire dans un script en utilisant une foreachboucle si vous effectuez de grandes opérations comme ça. Cela devient très compliqué lorsque vous essayez de faire tout cela sur une seule ligne et il est très facile de faire une grosse erreur. Je parle d'expérience
Kolob Canyon
75

Il existe une variété de réponses précises ici, mais voici le code le plus concis pour plusieurs variantes différentes. Pour chaque variation, la ligne du haut montre la syntaxe complète et le bas montre la syntaxe laconique.

Le point (2) est une forme plus concise des réponses de Jon Z et manojlds, tandis que le point (1) est équivalent aux réponses de vikas368 et buygrush.

  1. Liste les objets FileInfo pour tous les fichiers contenant un modèle:

    Get-ChildItem -Recurse filespec | Where-Object { Select-String pattern $_ -Quiet }
    ls -r filespec | ? { sls pattern $_ -q }
    
  2. Liste des noms de fichiers pour tous les fichiers contenant un modèle:

    Get-ChildItem -Recurse filespec | Select-String pattern | Select-Object -Unique Path
    ls -r filespec | sls pattern | select -u Path
    
  3. Liste les objets FileInfo pour tous les fichiers ne contenant pas de modèle:

    Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }
    ls -r filespec | ? { !(sls pattern $_ -q) }
    
  4. Liste les noms de fichiers pour tous les fichiers ne contenant pas de modèle:

    (Get-ChildItem -Recurse filespec | Where-Object { !(Select-String pattern $_ -Quiet) }).FullName
    (ls -r filespec | ? { !(sls pattern $_ -q) }).FullName
    
Michael Sorens
la source
De plus, si vous recherchez simplement des fichiers contenant le modèle n'importe où, vous pouvez abandonner après avoir trouvé la première instance en utilisant le -Listparamètre deSelect-String
KyleMit
Je souhaite que le PO ait posé une légère variation de la question afin que ce soit l'AA. # 1 était très utile et il est évident que @Michael Sorens groks PS!
cBlaine
20

Cela affichera le chemin, le nom de fichier et la ligne de contenu trouvée correspondant au modèle.

Get-ChildItem -Path d:\applications\*config -recurse |  Select-String -Pattern "dummy" 
user5000502
la source
Si seulement une ligne pouvait être ajoutée entre les résultats :)
cladelpino
15

Canalisez le contenu de votre

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

à fl *

Vous verrez que le chemin est déjà renvoyé en tant que propriété des objets.

SI vous voulez juste le chemin, utilisez select pathou select -unique pathpour supprimer les doublons:

Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy" | select -unique path
manojlds
la source
1
Merci à vous deux, c'est exactement ce que je recherche. Malheureusement, quand il y a beaucoup de sous-répertoires impliqués dans le chemin, PS coupe le chemin absolu et ajoute trois points à la fin de la ligne comme \ dir1 \ dir2 \ dir3 \ path ... donc je ne sais pas quel fichier est retourné . Existe-t-il un moyen de dire à PS d'être moins gourmand sur les personnages et de prendre la peine de montrer le chemin complet? :) Merci beaucoup !
Bluz
3
Vous devez ajouter le -Filecommutateur à Get-ChildItemou vous vous retrouvez avec une cascade sans fin d'erreurs d'essayer d'appeler des Get-Contentrépertoires.
RubberDuck
Si vous avez besoin du chemin complet, vous pouvez le faire. Les (Get-ChildItem -recurse | Get-Content | Select-String -pattern "dummy").FullNamegens semblent oublier que PowerShell est orienté objet; en cas de doute, recherchez une propriété
Kolob Canyon
10

Voici comment je le ferais, vous n'avez pas besoin de get-content:

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

ou

ls -r | Select-String dummy | fl *

Pour voir quelles sont les différentes propriétés ...

C'est plus rapide. Le deuxième argument est -filter:

ls -r . *.bat | select-string netsh
js2010
la source
2
+1, cela fonctionne parfaitement pour mon cas, mais utilisez-le select Pattern, LineNumber, Filenamepour une sortie plus concise. La ligne renvoie TOUT sur la ligne contenant votre chaîne de modèle. Vous pouvez également facilement le transmettre à un fichier csv si vous le souhaitez.
Protonova
9
Get-ChildItem -r | ? {$_.psiscontainer -eq $false} | ? {gc $_.pspath |select-string -pattern "dummy"}

Cela vous donnera tous les détails de tous les fichiers

vikas368
la source
Je ne savais absolument pas que cela -rfonctionnait. Je pensais que vous deviez toujours le faire-Recurse
Kolob Canyon
5

Pour conserver les détails complets du fichier dans le tableau résultant, vous pouvez utiliser une légère modification de la réponse publiée par vikas368 (qui ne semble pas bien fonctionner avec la saisie semi-automatique ISE):

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

ou en bref:

ls -r | ?{ $_ | Select-String -Pattern "dummy" }
buygrush
la source
5

Si vous recherchez dans un répertoire, vous pouvez le faire:

select-string -Path "c:\temp\*.*" -Pattern "result"  -List | select Path
Esperento57
la source
4

Cela affichera une liste du chemin d'accès complet à chaque fichier qui contient la chaîne de recherche:

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

Notez qu'il n'affiche pas d'en-tête au-dessus des résultats et n'affiche pas les lignes de texte contenant la chaîne de recherche. Tout ce qu'il vous indique, c'est où vous pouvez trouver les fichiers qui contiennent la chaîne.

Petite fille
la source
2
Une idée comment afficher le numéro de ligne où le motif a été trouvé, ainsi que le nom du fichier?
Piotr L
4

J'ai modifié l'une des réponses ci-dessus pour me donner un peu plus d'informations. Cela m'a épargné une deuxième requête plus tard. C'était quelque chose comme ça:

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"

Je peux spécifier le chemin et les caractères génériques de fichier avec ces structures, et il enregistre le nom de fichier, le numéro de ligne et la ligne pertinente dans un fichier de sortie.

RenoGreg
la source
Cool! Merci pour cette solution supplémentaire :) Cependant, pourriez-vous s'il vous plaît lier à la réponse sur laquelle vous avez basé votre solution et nommer l'auteur de cette réponse pour rendre hommage? Merci!
Max Vollmer