James
James

Reputation: 11

Powershell v2. Delete or Remove lines of text. Regex Issue

I've been through so many posts today that offer Powershell examples of how to remove entire lines from a file by using line numbers. Unfortunately none of them do quite what I need, or they have some 'but' type clauses in them.

The closest example I found uses the -remove method. This managed to do the job, until I noticed that not all lines that I was trying to remove, were removed. After some more research I found that -remove is reliant on Regex and Regex does not like certain special characters which happen to be in some of the lines I wish to delete/remove.

The example I'm using is not my own work. user2233949 made it (cheers buddy) I found it very simple though, so I made it into a Function:

Function DeleteLineFromFile ($Path, $File, $LineNumber){
        $Contents = Get-Content $Path\$File
        $Contents -replace $Contents[$LineNumber -1],"" | Set-Content $Path\$File
        }

A great example I reckon. Only regex won't work with the special chars.

The goal is this: To make a function that doesn't care about what is in the line. I wan't to feed it a path, file and line, then have the function delete that line and save the file.

Upvotes: 1

Views: 1597

Answers (1)

Joey
Joey

Reputation: 354586

This is fairly easy and does not need regex at all.

Read the file:

$lines = Get-Content $Path\$File

We then have an array that contains the lines in the file. When we have an array we can use indexes to get elements from the array back, e.g.

$lines[4]

would be the fifth line. You can also pass an array into the index to get multiple lines back:

$lines[0,1,5]   # returns the first, second and 6th line
$lines[0..5]    # returns the first 6 lines

We can make use of that with a little trick. PowerShell's comparison operators, e.g. -eq work differently with an array on the left side, in that they don't return $true or $false, but rather all elements from the array matching the comparison:

1..5 -ge 3      # returns 3,4,5
0..8 -ne 7      # returns 0 through 8, *except* 7

You probably can see where this is going ...

$filteredLines = $lines[0..($lines.Length-1) -ne $LineNumber - 1]

Technically you can ignore the - 1 after $lines.Length because indexing outside of an array simply does nothing. This does actually remove the line you want to remove, though. If you just want it replaced by an empty line (which your code seems to be doing, but it doesn't sound like that's what you want), then this approach won't work.

There are other options, though, e.g. with a ForEach-Object:

Get-Content $Path\$File |
  ForEach-Object { $n = 1 } {
    if ($n -ne $LineNumber) { $_ } else { '' }
  }

A word of advice on writing functions: Usually you don't have separate $Path and $File parameters. They serve no real useful purpose. Every cmdlet uses only a $Path parameter that points to a file if needed. If you need the folder that file resides in, you can always use Split-Path -Parent $Path to get it.

Upvotes: 1

Related Questions