There are probably thousands of ways to do this, below is a quick and dirty example but it should work.
<#
For demo purposes my file has content like:
line 0
line 1
line 2
line 3
...
#>
$Content = Get-Content 'C: empNumberedLines.txt'
For($i = 0; $i -lt $Content.Length; $i += 2 )
{
$Content[$i]
}
Note: I started with Line 0 but you can change the initial value of $i
if you want to start at line 2 as your question / example suggests.
There is one case that might not work so well. If the file is very large and/or you otherwise don't have enough free RAM to store the data in $Content.
The For loop has the array pre-established because it's going to run until $i
is greater than or equal to $Content.Length
. However you could do this without storing the content in a variable, like below:
$i = 0
Get-Content 'C: empNumberedLines.txt' |
ForEach-Object{
If( !($i % 2) ) { $_ }
++$i
}
I prefer the first approach, but this is an alternate for aforementioned circumstances. Technically I don't have to do an initial assignment on $i
, but I think it's a good practice here, especially considering $i
is commonly used.
As before, you can initiate $i
to 2 (or whatever) as needed. Inside the ForEach-Object
loop I'm testing if $i
is even. If it is I'll output the current pipeline element.
Note: !($i % 2)
can also be expressed as $i % 2 -eq 0
like:
$i = 0
Get-Content 'C: empNumberedLines.txt' |
ForEach-Object{
If( $i % 2 -eq 0 ) { $_ }
++$i
}
A final note: Conceptually you may consider the file starting at 1 while array elements start at 0. In other words you may not want to print line zero. If that's the case, resist the urge to rebase or anything like that. In either example initiating $i
to 1 will rectify the issue. Because line 2 would be in array index 1.
Explanation of Алексей Семенов's Neat Answer:
param ( $exampleFileName = "d: mpexample.txt" )
@"
line 0
line 1
line 2
line 3
...
"@ | Out-File $exampleFileName
(Get-Content $exampleFileName | Group-Object {$Global:i % 2;$Global:i++} | Select-Object -First 1).Group
A neat usage of Group-Object
. However, it's confusing to the untrained eye. Questions and answers are not a single affair, and are meant to be discoverable and informative to users down the road. I think this is an interesting sample and worthy of explanation, and since @Алексей Семенов seems unwilling to do so, I'll reluctantly attempt it here.
Note: The Param(..)
block is completely unnecessary. It's only part of establishing the demo data/file.
Group-Object
can group objects based on the output of an expression. In fact a similar example is right in the Group-Object
help documentation. When an expression is used its output becomes "Name" property on the returned GroupInfo objects. Running Get-Content $exampleFileName | Group-Object {$Global:i % 2;$Global:i++}
by itself would return something like below.
Count Name Group
----- ---- -----
3 0 {line 0, line 2, Line 4}
3 1 {line 1, line 3, ...}
Since the increment of $i
inside the expression is 1 and the divisor is always 2 the remainder returned by the %
operator can only ever be 0 or 1, and therefore only 2 respective named groups are returned.
It appears that Group-Object
internally sorts on the Name property ensuring the group named "0" will be the first element in the returned array of GroupInfo objects. So selecting the first element and Dot referencing the Group property will return the grouped objects themselves which in this case are the even numbered lines.
Another slightly shorter way to write this would be:
(Get-Content $exampleFileName | Group-Object {$Global:i % 2;$Global:i++})[0].Group
Because this doesn't have the additional pipe to Select-Object
this is a little more efficient and competes better with some of my earlier examples.
Note: The $global:
scope modifier is required, because each instance of the script block is a child of the calling scope. Therefore, there's no variable visibility between the instances. Even if you predefined $i
in the parent scope it wouldn't increment in the parent scope unless $global:
is used. This is fundamental to scoping in PowerShell. See about_Scoping for more information.