In Powershell, how do I list all files in a directory (recursively) that contain text that matches a given regex? The files in question contain really long lines of incomprehensible text, so I don't want to see the matching line -- just the filename.
4 Answers
You can use Select-String
to search for text inside files, and Select-Object
to return specific properties for each match. Something like this:
Get-ChildItem -Recurse *.* | Select-String -Pattern "foobar" | Select-Object -Unique Path
Or a shorter version, using aliases:
dir -recurse *.* | sls -pattern "foobar" | select -unique path
If you want just the filenames, not full paths, replace Path
with Filename
.
Explanation:
Get-ChildItem
-Recurse *.*
returns all files in the current directory and all its subdirectories.Select-String
-Pattern "foobar"
searches those files for the given pattern "foobar".Select-Object
-Unique Path
returns only the file path for each match; the-Unique
parameter eliminates duplicates.
-
select -Unique
... cool, learned something new. That works perfectly, thanks! Apr 15, 2014 at 18:55 -
Is . really needed? Get-ChildItem -Recurse works exactly the same I think. Jul 4, 2014 at 11:14
-
1or even more concisely, gci -r | sls "foobar" | select -unique path Jun 27, 2015 at 15:11
-
If there's no matches PowerShell seems to "hang", it won't return. How does one know when the search is done if there are no matches? Apr 11, 2019 at 15:56
Note, that in powershell v1.0 and v2.0 you need to specify first position parameter (path) to work with -Recursion
-Recurse
Gets the items in the specified locations and in all child items of the locations.
In Windows PowerShell 2.0 and earlier versions of Windows PowerShell, the Recurse parameter works only when the value of the Path parameter is a container that has child items, such as C:\Windows or C:\Windows*, and not when it is an item does not have child items, such as C:\Windows*.exe.
Use the below command inside the directory you would like to perform the "grep" and change [SEARCH_PATTERN]
to match what you would like to match. It's recursive, searching through all files in the directory.
dir -Recurse | Select-String - pattern [SEARCH_PATTERN]
Select-String has a -List
parameter for this purpose:
Return only the first match in each input file. By default, Select-String returns a MatchInfo object for each match found.
— ss64.com
You can use it like this:
gci -Recurse | sls -List FOOBAR
Here's what some sample results look like (searching the Windows SDK for ERROR_SUCCESS
):
shared\bthdef.h:576:#define BTH_ERROR(_btStatus) ((_btStatus) != BTH_ERROR_SUCCESS)
shared\netioapi.h:2254: ERROR_SUCCESS on success. WIN32 error code on error.
shared\rpcnterr.h:34:#define RPC_S_OK ERROR_SUCCESS
shared\winerror.h:214:// MessageId: ERROR_SUCCESS
um\advpub.h:40:// ERROR_SUCCESS_REBOOT_REQUIRED Reboot required.
um\bluetoothapis.h:243:// ERROR_SUCCESS
um\ClusApi.h:571:_Success_(return == ERROR_SUCCESS)
um\dsparse.h:102:_Success_(return == ERROR_SUCCESS)
um\eapmethodpeerapis.h:228:// If the function succeeds, it returns ERROR_SUCCESS. Otherwise, it is
um\eappapis.h:56:// If the functions succeed, they return ERROR_SUCCESS. Otherwise, it is
um\MapiUnicodeHelp.h:583: if ((hkeyPolicy && RegQueryValueExW(hkeyPolicy, szName, 0, &dwType, (LPBYTE)
&dwLcid, &dwSize) == ERROR_SUCCESS && dwType == REG_DWORD) ||
um\Mddefw.h:127: routine will return ERROR_SUCCESS and the inherited data even if
um\Msi.h:1693:// Returns ERROR_SUCCESS if file is a package.
um\MsiQuery.h:192:// Returns ERROR_SUCCESS if successful, and the view handle is returned,
um\msports.h:46: ERROR_SUCCESS if the dialog was shown
um\ncryptprotect.h:164: ERROR_SUCCESS
um\NTMSAPI.h:1761:_Success_ (return == ERROR_SUCCESS)
um\oemupgex.h:108:// Returns: ERROR_SUCCESS in case of success, win32 error otherwise
um\PatchWiz.h:90:// ERROR_SUCCESS, plus ERROR_PCW_* that are listed in constants.h.
um\Pdh.h:415:_Success_(return == ERROR_SUCCESS)
If you wanted to get back the actual FileInfo
objects (instead of the relative Path and a single match result), you might use it like this:
Get-ChildItem -Recurse -File | where { Select-String -Path $_ -List -Pattern FOOBAR }