aston_zh
aston_zh

Reputation: 6833

foreach loop mixes up result

I'm struggeling with following situation:

testfile.txt

1 a
2 b
3 c

Script:

$input = Get-Content "C:\Scripts\testfile.txt"

foreach ($line in $input) {
    $var1 = $line.Substring(2,1)
    $output = "$var1 is $var2"

    if ($line -match "1") {
        $var2 = "1"
        Write-Host $output
    } elseif ($line -match "2") {
        $var2 = "2"
        Write-Host $output
    } elseif ($line -match "3") {
        $var2 = "3"
        Write-Host $output
    } else {}
}

Result:

a is 3
b is 1
c is 2

Why is the result mixed up? It should be:

a is 1
b is 2
c is 3

Even if I put the $output at the end of the foreach loop?!

Upvotes: 0

Views: 45

Answers (1)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200233

You probably ran the code before, because normally your output should look like this:

a is
b is 1
c is 2

The 3 in your first output line is obviously retained from a previous attempt.

The reason for this behavior is that you only assign a value to $var2 after you assign "$var1 is $var2" to a variable. The variables in the string are already expanded upon assignment, so you get the value of $var2 from the previous iteration (or an empty value on the first run).

To get the output you want change your code to this:

foreach ($line in $input) {
    $var1 = $line.Substring(2,1)
    $output = "$var1 is {0}"

    if ($line -match '1') {
        Write-Host ($output -f '1')
    } elseif ($line -match '2') {
        Write-Host ($output -f '2')
    } elseif ($line -match '3') {
        Write-Host ($output -f '3')
    }
}

or like this:

foreach ($line in $input) {
    $var1 = $line.Substring(2,1)

    $var2 = if ($line -match '1') {
        '1'
    } elseif ($line -match '2') {
        '2'
    } elseif ($line -match '3') {
        '3'
    }

    if ($var2) {
        Write-Host "$var1 is $var2"
    }
}

Better yet, since you're using a regular expression match anyway, do something like this:

foreach ($line in $input) {
    $var1 = $line.Substring(2,1)

    if ($line -match '[1-3]') {
        Write-Host "$var1 is $($matches[0])"
    }
}

Upvotes: 4

Related Questions