Search code examples
powershellpowershell-5.0

Powershell searching for line termination using Select-String


I'm using PS v5.1

Normally, if I want to search for files containing a string I use this pattern:

Get-ChildItem -recurse | Select-String "searchstring"

This doesn't seem to work if what I'm searching for are line termination characters (\r\n). The Select-String docs state:

Select-String is based on lines of text. By default, Select-String finds the first match in each line and, for each match, it displays the file name, line number, and all text in the line containing the match.

So it seems that sls is 'helpfully' removing my line termination characters. I can do something like this:

gci *|get-content -raw|sls "\r\r\n" -list

but that really isn't the same at all since it loses the filename. I know I could write a much longer foreach construction such as:

foreach ($f in (gci -recurse *)) {
    if ($f.PSIsContainer) {
        continue
        }
    $c = Get-Content -raw $f.FullName
    if ($c.Length -ne 0) {
        $i = $c.IndexOf("`r`r`n")
        if ($i -gt 0) {
            Write-Output $f.FullName
            }
        }
    }

But that seems rather verbose and complex for what I want to do.

Is there a better (like a concise one liner) way to do this type of search?


Solution

  • Indeed, Select-String by design operates on individual lines when give file-information objects as input, so you cannot inspect newlines that way.

    Get-Content -Raw allows you to read a file as a whole, as a single string, and PowerShell's file-system provider also adds NoteProperty members to that string, notably a .PSPath property that reflects the input file path.

    Instead of Select-String, you can then use the -match operator on each file-contents string to look for the sequence of interest, and echo the .PSPath property value in case of a match:

    Get-ChildItem -File -Recurse | Get-Content -Raw | ForEach-Object {
      if ($_ -match '\r\r\n') { Convert-Path $_.PSPath }
    }
    

    Note that Convert-Path is need to convert the PowerShell provider-qualified path reported in .PSPath (e.g, Microsoft.PowerShell.Core\FileSystem::C:\Users\jdoe\file.txt) to a native filesystem path (e.g., C:\Users\jdoe\file.txt).
    (This is only necessary because the input file-information objects are supplied via the pipeline.)