Reputation: 132
When I invoke an if
comandlet in a foreach
loop:
$spisok = Get-Content "OmConv79_2.txt" -TotalCount 100
foreach ($i in $spisok) {
#Write-Host $i
$i -match "^(.*)\t(.+)\t?(.*)?" |
foreach { $Matches[1] + "----" + $Matches[2] + "----" + $Matches[3] } |
if ($Matches[1] -eq "^\d\d.\d\d.\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d") {
$Matches[0]
}
}
I'm getting this error:
if : The term 'if' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:7 char:9 + if ($Matches[1] -eq "^\d\d.\d\d.\d\d \d\d:\d\d:\d\d\.\d\d\d\d ... + ~~ + CategoryInfo : ObjectNotFound: (if:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException
"if" is not recognized? I'm confused. How is that possible?
Upvotes: 1
Views: 2391
Reputation: 439228
You cannot use an if
statement directly in a pipeline.
Your 2nd use of foreach
is not a loop, but a call to the ForEach-Object
cmdlet in a pipeline.
Regrettably, the ForEach-Object
cmdlet is aliased to foreach
, causing confusion with the foreach
keyword (loop construct).
To incorporate an if
statement (conditional) in a pipeline, you have two options, depending on your needs:
If the if
statement only performs filtering of the input while - selectively - passing it through, use the conditional in the script block of a Where-Object
call (aliases: where
, ?
)
If the if
statement also produces custom output, place it inside the script block of a ForEach-Object
call (aliases: foreach
, %
).
Simplified examples:
# !! These BREAK - you cannot use `if` directly in a pipeline.
'line 1', 'line 2' | if ($_ -match '1') { $_ } # filtering only
'line 1', 'line 2' | if ($_ -match '1') { $_ + '!' } # filtering + custom output
Filtering-only solution, using Where-Object
:
$ 'line 1', 'line 2' | Where-Object { $_ -match '1' }
line 1
Filtering + custom-output solution, using ForEach-Object
:
$ 'line 1', 'line 2' | ForEach-Object { if ($_ -match '1') { $_ + '!' } }
line 1!
As for your code:
From what I can tell (including based on later comments), this may be what you meant to do:
Get-Content "OmConv79_2.txt" -TotalCount 100 |
ForEach-Object { # process each line, represented as $_
if ($_ -match '^(.*)\t(.+)\t?(.*)?') {
# Is the first tab-separated field a date + time?
if ($Matches[1] -match '^\d\d.\d\d.\d\d \d\d:\d\d:\d\d\.\d\d\d\d\d\d') {
$Matches[0] # Output the first 3 tab-separated fields.
} else {
# Output line with default date prepended
}
}
}
Note the use of a single pipeline, with a single ForEach-Object
call to process each input line.
-eq
had to be replaced with -match
to match the ^\d...
regex.
The regexes are single-quoted, so that PowerShell's string interpolation doesn't get in the way.
Upvotes: 3