SysCrasher
SysCrasher

Reputation: 21

delete a specific line in file with powershell

I want to delete a complete line which contains a special word in a single .csv file in a powershell script.

I already found working code, that deletes the specific line, but writes all other lines into the first line. This shouldn't happen, because I linked the csv-file with an ms access table.

    $user = 'User2'
    $file = Get-Content c:\datei.txt
    $newLine = ""

    foreach($line in $file){

        if($line -match $User){
         }else{
            $newLine += $line
        }
    }
    $newLine | Out-File c:\datei.txt

The file looks like this, but with more data and lines:

User;computer;screen1;screen2;printer
User1;bla;bla;;bla
User2;bla;bla;bla;bla
User3;bla;bla;bla;bla

After running the code:

User;computer;screen1;screen2;printerUser1;bla;bla;;blaUser3;bla;bla;bla;bla

I use Powershell 5.1.x on Windows 7

Upvotes: 2

Views: 5878

Answers (2)

TessellatingHeckler
TessellatingHeckler

Reputation: 28993

It happens because you're doing string concatenation.

$newLine = ""
$newLine += $line

# result is exactly how it looks,  
# "" -> "line1" -> "line1line2" -> "line1line2line3" ...

The straightforward fix is to use an array:

$newLine = @()
$newLine += $line

# result is adding lines to an array  
# @() -> @("line1") -> @("line1","line2") -> @("line1","line2","line3") ...

but the proper PowerShell way is not to do that at all, and to stream the file through your code and out into another file:

$user = 'User2'
$file = Get-Content c:\datei.txt

foreach($line in $file){

    if($line -match $User){
     }else{
        $line   # send the line to the output pipeline
    }

} | Out-File c:\datei.txt

But you can invert the test -match to -notmatch and get rid of the empty {} part.

$user = 'User2'
$file = Get-Content c:\datei.txt

foreach($line in $file){

    if($line -notmatch $User){
        $line   # send the line to the output pipeline
    }

} | Out-File c:\datei.txt

And you can get rid of temporarily storing the file content:

$user = 'User2'
Get-Content c:\datei.txt | ForEach-Object {

    if ($_ -notmatch $User){
        $line   # send the line to the output pipeline
    }

} | Out-File c:\datei.txt

But then it's just acting as a filter, and you can change foreach-object / if() {} for a where-object filter:

$user = 'User2'
Get-Content c:\datei.txt | Where-Object {

    $_ -notmatch $User

} | Out-File c:\datei.txt

And then change Out-file for Set-Content (the pairing is get-content/set-content, and it gives more control over output encoding if you need it):

$user = 'User2'

Get-Content c:\datei.txt | 
    Where-Object { $_ -notmatch $User } | 
    Set-Content c:\datei.txt

Upvotes: 6

boxdog
boxdog

Reputation: 8432

You need to add a 'newline' to the end of each line of text. Change this line:

$newLine += $line

to:

$newLine += "$line`r`n"

Upvotes: 0

Related Questions