I've got the following pipeline:
dir -recurse *.* | sls -pattern "matching_pattern" | select -unique path
Which gives me an output like this:
Path
----
D:\code\a.txt
D:\code\b.txt
I want it to call the command gvim a.txt b.txt.
How do I do this?
Use Where-Object instead of Select-String for filtering the files, expand the FullName (or Name) property, so you get an array of paths or filenames, and splat it when calling gvim:
$files = Get-ChildItem -Recurse *.* |
Where-Object { (Get-Content $_.FullName) -match "matching_pattern" } |
Select-Object -Unique -Expand FullName
& gvim #files
Replace FullName with Name in the Select-Object statement to get just the filenames without path.
If you want to stick with Select-String the approach would be similar:
$files = Get-ChildItem -Recurse *.* |
Select-String -Pattern "matching_pattern" |
Select-Object -Unique -Expand Path
& gvim #files
Replace Path with Filename in the Select-Object statement to get just the filenames without path.
You could access the two results by index:
$result = dir -recurse *.* | sls -pattern "matching_pattern" | select -unique path
gvim $result[0].FullName $result[1].FullName
Related
I spent quite some time searching for the solution of my problem, but found nothing. I have one single folder with mostly .html files, and I frequently need to search to find the files that contain certain strings. I need the search result to be displayed with just the file name (as the file will only be in that one folder) and file's last write time. The list needs to be sorted by the last write time. This code works perfectly for finding the correct files
Get-ChildItem -Filter *.html -Recurse | Select-String -pattern "keyWord string" | group path | select name
The problem with it is that it displays the entire path of the file (which is not needed), it does not show the last write time, and it is not sorted by the last write time.
I also have this code
Get-ChildItem -Attributes !Directory *.html | Sort-Object -Descending -Property LastWriteTime | Select-Object Name, LastWriteTime
That code prints everything exactly as I want to see it, but it prints all the file names from the folder instead of printing only the files that I need to find with a specific string in them.
Since you are only using Select-String to determine if the text exists in any of the files move it inside a Where-Object filter and use the -Quiet parameter so that it returns true or false. Then sort and select the properties you want.
Get-ChildItem -Filter *.html |
Where-Object { $_ | Select-String -Pattern 'keyWord string' -Quiet } |
Sort-Object LastWriteTime |
Select-Object Name, LastWriteTime
For multiple patterns one way you can do it is like this
Get-ChildItem -Filter *.html |
Where-Object {
($_ | Select-String -Pattern 'keyWord string' -Quiet) -and
($_ | Select-String -Pattern 'keyWord string #2' -Quiet)
} |
Sort-Object LastWriteTime |
Select-Object Name, LastWriteTime
And another way using Select-String with multiple patterns which may be a bit faster
$patterns = 'keyword 1', 'keyword 2', 'keyword 3'
Get-ChildItem -Filter *.html |
Where-Object {
($_ | Select-String -Pattern $patterns | Select-Object -Unique Pattern ).Count -eq $patterns.Count
} |
Sort-Object LastWriteTime |
Select-Object Name, LastWriteTime
If you don't care about it being a bit redundant, you can Get-ChildItem the results after your searching:
Get-ChildItem -Filter *.html -Attributes !Directory -Recurse | Select-String -Pattern "keyWord string" | group path | foreach {Get-ChildItem $_.Name } | Sort-Object -Descending LastWriteTime | Select Name,LastWriteTime
After you Select-String you get the attributes of that object instead of the original, so we're taking the results of that object and passing it back into the Get-ChildItem command to retrieve those attributes instead.
The following snippet extracts only the matching lines, I also want the path and line number:
Get-ChildItem $thePath\ -Include "*.txt" -Recurse | Get-Content | Select-String -Pattern 'THE_PATTEN' | Set-Content "output.txt"
I tried with this method and still it only extracts the matching lines:
Get-ChildItem $thePath\ -Include "*.txt" -Recurse | Get-Content | Select-String -Pattern 'THE_PATTEN' | Select-Object -ExpandProperty Line | Set-Content "output.txt"
How can I extract the path:filename:line number: matching line?
You don't need get-content. The path is passed over the pipe. (. is for -path, and *.txt is for -filter for speed)
get-childitem -recurse . *.txt | select-string hi
foo2\file3.txt:1:hi
file1.txt:1:hi
file2.txt:1:hi
First note that Get-ChildItem -Filter is way more efficient than Get-ChildItem -Include (see help get-childitem). Next is that Select-String accepts files. No need to get the content first. Now just Select the properties you need and export your file. (Note that the variable $match and $matches are system variables so you might not want to use them.)
$Patterns = Get-ChildItem $thePath -Filter "*.txt" -Recurse| Select-String -Pattern 'THE_PATTEN' | select Path,Filename,LineNumber,Line
# Export to csv (usable in excel)
$Patterns | Export-Csv output.csv -NoTypeInformation # -Delimiter ";" # the delimiter is optinal and depending of your region
# Exporting txt
foreach ($Pattern in $Patterns){
('{0} : {1} : {2}' -f ($Pattern.Path),($Pattern.LineNumber),($Pattern.Line)) | Add-Content "output.txt"
}
Yea, you can get line number and file name from the output of Select-String:
ls *.txt | % { Select-String -Path $_ -Pattern "THE_PATTERN" | select-object LineNumber, Line, Path }
You'll notice this approach is also a touch faster.
Good luck!
I have a bunch of lists of documents generated in powershell using this command:
Get-ChildItem -Recurse |
Select-String -Pattern "acrn164524" |
group Path |
select Name > test.txt
In this example it generates a list of files containing the string acrn164524 the output looks like this:
Name
----
C:\data\logo.eps
C:\data\invoice.docx
C:\data\special.docx
InputStream
C:\datanew\special.docx
I have been using
Get-Content "test.txt" | ForEach-Object {
Copy-Item -Path $_ -Destination "c:\destination\" -Recurse -Container -Force
}
However, this is an issue if two or more files have the same name and also throws a bunch of errors for any lines in the file that are not a path.
sorry if I was not clear enough I would like to keep files with the same name by appending something to the end of the file name.
You seem to want the files, not the output of Select-String. So let's keep the files.
Get-ChildItem -Recurse -File | Where-Object {
$_ | Select-String acrn164524 -Quiet
} | Select-Object -ExpandProperty FullName | Out-File test.txt
Here
-File will make Get-ChildItem only return actual files. Think
about using a filter like *.txt to reduce the workload more.
-Quiet will make Select-String return $true or $false, which
is perfect for Where-Object.
Instead of Select-Object -ExpandProperty X in order to retrieve an array of raw property values (as opposed to an array of PSObjects, which is what Select-Object would normally do), it's simpler to use ForEach-Object X instead.
Get-ChildItem -Recurse -File | Where-Object {
$_ | Select-String acrn164524 -Quiet
} | ForEach-Object FullName | Out-File test.txt
I'm trying to write a one-liner in Powershell that lists all filetypes in a folder (and its sub-folders).
I've got this so far:
Get-ChildItem D:\Audio -Recursive | Select-Object PSParentPath, Extension | Export-Csv D:\Test.csv
However, I'd like to do better and display, for each folder, every found extension only once.
For example, let's say I have ten mp3 files and 1 jpg file in D:\Audio\foo and 5 flac files and 1 txt file in D:\Audio\bar. I'd like the output to be :
foo .mp3
foo .jpeg
bar .flac
bar .txt
I guess I should use Get-Unique but how do I specify it on the Extension property and NOT on the Path property?
Just add -Unique to Select-Object:
Get-Childitem -Recurse | Select-Object PSParentPath,Extension -Unique
(Also, DirectoryName might be better than PSParentPath here)
i complet solution of Jimmeh, use -file for take only file
Get-ChildItem "c:\temp" -Recurse -file | select directoryname, Extension -Unique
Try this:
Get-ChildItem D:\Audio -Recurse | Group-Object psparentpath, extension | ? {(($_.Name -split ", .")[1]) -ne $Null } | ft -AutoSize #{Expression={(($_.Name.Split("\"))[$_.Name.Split("\").Length -1] -split ",")[0]};Label="Folder"}, #{Expression={($_.Name -split ", .")[1]};Label="Extension"}
To show full path to folder + extension, try the following.
Get-ChildItem D:\Audio -Recurse | Group-Object psparentpath, extension | ? {(($_.Name -split ", .")[1]) -ne $Null } | ft -AutoSize #{Expression={($_.Name.Replace("Microsoft.PowerShell.Core\FileSystem::","") -split ", .")[0]};Label="Folder"}, #{Expression={($_.Name -split ", .")[1]};Label="Extension"}
I am curious how to produce a distinct file list based on this example.
** This example produces a list of all .ps1 and .psm1 files that contain the text "folders", but without the text ".invoke" on the same line.
$text='folders'
dir C:\Workspace\mydirectorytosearch1\ -recurse -filter '*.ps*1' | Get-ChildItem | select-string -pattern $text | where {$_ -NotLike '*.invoke(*'}
dir C:\Workspace\mydirectorytosearch2\ -recurse -filter '*.ps*1' | Get-ChildItem | select-string -pattern $text | where {$_ -NotLike '*.invoke(*'}
This is cool and works well but I get duplicate file output (same file but different line numbers).
How can I keep my file output distinct?
The current undesirable output:
C:\Workspace\mydirectorytosearch1\anonymize-psake.ps1:4:. "$($folders.example.test)\anonymize\Example.vars.ps1"
C:\Workspace\mydirectorytosearch1\anonymize-psake.ps1:5:. "$($folders.missles)\extract\build-utilities.ps1"
The desired output:
C:\Workspace\mydirectorytosearch1\anonymize-psake.ps1
Help me tweak my script??
You can eliminate duplicates wit Select-String and the Unique parameter:
$text='folders'
Get-ChildItem C:\Workspace\mydirectorytosearch1\,C:\Workspace\mydirectorytosearch2\ -Recurse -Filter '*.ps*1' |
Select-String -Pattern $text | Where-Object {$_ -NotLike '*.invoke(*'} |
Select-Object Path -Unique