Norman Wigand
Norman Wigand

Reputation: 15

powershell foreach - changes to arrayitems don't update array

I'm currently writing a PowerShell script to help out a user.

I am reading a file which is generated by a program into an array.

I iterate through it with a foreach and make changes to it as necessary.

Then I want to write the text, including changes, into a new file.

Param(
    [Parameter(Mandatory=$true, Position=0, HelpMessage="pulse?")]
    [string]$pulse,

    [Parameter(Mandatory=$true, Position=1, HelpMessage="milimeter?")]
    [string]$milimeter
)

$textfile = Get-Content C:\11111_O.jbi

foreach($string in $textfile) {

    $string -match '(EC\d*=)'

    if($matches) {
        [string]$regex = $matches[1]
        [string]$replacement = ($regex + $pulse + ',')
        $string = $string -replace '(EC\d*=)', "$replacement"
    }
}

$textfile | Out-File -FilePath C:\new_file.jbi

But even though i have checked the code inside the foreach multiple times (it does what it's supposed to do to $string). The output of $textfile always stays the same.

How can I get $textfile to update and reflect the changes I want to do to it in my foreach?

Upvotes: 1

Views: 2646

Answers (3)

briantist
briantist

Reputation: 47792

The $string variable in the foreach statement refers to the "current" item in the collection, but it's a copy, not a reference to the original collection.

You should make a new array or make it a pipeline with the ForEach-Object cmdlet:

$textfile | ForEach-Object -Process {
    $string = $_
    if($string -match '(EC\d*=)')
    { 
        [string]$regex = $matches[1]
        [string]$replacement = ($regex + $pulse + ',')
        $string = $string -replace '(EC\d*=)', "$replacement"
    }
    $string    
} | out-file -filepath C:\new_file.jbi

Your regex stuff is also unnecessarily complex. You can just do the replace, using a backreference to refer to the matched part, so the whole thing can be further simplified to this:

$textfile | ForEach-Object -Process {
    $_ -replace '(EC\d*=)', "`${1}$pulse,"
} | out-file -filepath C:\new_file.jbi

Having done that, you no longer need ForEach-Object because -replace can work on arrays:

$textfile -replace '(EC\d*=)', "`${1}$pulse," | 
   out-file -filepath C:\new_file.jbi

Upvotes: 2

arco444
arco444

Reputation: 22831

Because you're using foreach, you get a copy of each line into the $string variable - that is what you modify on each iteration, so the contents of $textfile itself are never changed.

You can just use a for loop instead:

for ($i = 0; $i -lt $textfile.count; $i++) {
  $textfile[$i] -match '(EC\d*=)'
  if($matches) {
    [string]$regex = $matches[1]
    [string]$replacement = ($regex + $pulse + ',')
    $textfile[$i] = $textfile[$i] -replace '(EC\d*=)', "$replacement"
  }
}

$textfile | out-file -filepath C:\new_file.jbi

Upvotes: 5

Mike Garuccio
Mike Garuccio

Reputation: 2718

If you really need to update $textfile in place you would need to use a for loop, however if you are just outputting to a file there is no need to manipulate the array, you can just dump the manipulated contents straight to the file.

foreach($string in $textfile) {
  $string -match '(EC\d*=)'
  if($matches) { 
    [string]$regex = $matches[1]
    [string]$replacement = ($regex + $pulse + ',')
    $string -replace '(EC\d*=)', "$replacement"
  }
} | out-file -filepath C:\new_file.jbi

Upvotes: 0

Related Questions