注意:这篇文章回答了如何从处理中排除输入文件/输入集合的第一行和最后一行。
Manu's helpful ... | Select-Object -Skip 1 | Select-Object -SkipLast 1 solution 在 PSv5+ 中效果很好(假设第一行和最后一行应该从输出中删除)。
但是,他们的 PSv4- 解决方案 不起作用(在撰写本文时),因为 Get-Content $file | Select-Object -Skip 1 返回的数组([System.Object[]] 实例)没有 .GetRange() 方法.
这是一个使用 PowerShell 范围运算符 (..) 的有效解决方案:
# Read lines of the input file into an array.
$allLines = Get-Content $file
# Using the range operator (..), get all elements except the first and the last.
$allLines[1..([Math]::Max(1, $allLines.Count-2))]
注意:
* 尝试 [1..-1] 很诱人,但 不 在 PowerShell 中工作,因为 1..-1 的计算结果为下标 1, 0, -1。
* 如果您知道至少有 3 个输入对象,则可以省略 [Math]::Max() 调用。
然而,上述解决方案并不总是一种选择,因为它需要首先收集所有输入对象在内存中,这消除了内存限制,基于管道的解决方案提供的一对一处理。
(尽管如果可行的话,内存中的解决方案会更快。)
要在 PSv4- 中解决这个问题,您可以以管道友好方式模拟Select-Object -SkipLast 1如下(Select-Object -Skip 1 - 从开始跳过 - PSv4支持-)。
# 'one', 'two', 'three' is a sample array. Output is 'one', 'two'
'one', 'two', 'three' | ForEach-Object { $notFirst = $False } {
if ($notFirst) { $prevObj }; $prevObj = $_; $notFirst = $True
}
每个输入对象的输出都会延迟一次迭代,这实际上忽略了最后一次。
这是对-SkipLast <n> 的概括,实现为高级函数Skip-Last,它使用[System.Collections.Generic.Queue[]] 实例来延迟<n> 对象的输出:
# Works in PSv2+
# In PSv5+, use `Select-Object -SkipLast <int>` instead.
Function Skip-Last {
<#
.SYNOPSIS
Skips the last N input objects provided.
N defaults to 1.
#>
[CmdletBinding()]
param(
[ValidateRange(1, 2147483647)] [int] $Count = 1,
[Parameter(Mandatory = $True, ValueFromPipeline = $True)]$InputObject
)
begin {
$mustEnumerate = -not $MyInvocation.ExpectingInput # collection supplied via argument
$qeuedObjs = New-Object System.Collections.Generic.Queue[object] $Count
}
process {
# Note: $InputObject is either a single pipeline input object or, if
# the -InputObject *parameter* was used, the entire input collection.
# In the pipeline case we treat each object individually; in the
# parameter case we must enumerate the collection.
foreach ($o in ((, $InputObject), $InputObject)[$mustEnumerate]) {
if ($qeuedObjs.Count -eq $Count) {
# Queue is full, output its 1st element.
# The queue in essence delays output by $Count elements, which
# means that the *last* $Count elements never get emitted.
$qeuedObjs.Dequeue()
}
$qeuedObjs.Enqueue($o)
}
}
}
注意:在上面的ValidateRange()属性中,使用2147483647而不是[int]::MaxValue,因为PSv2在这种情况下只支持常量。
示例调用:
PS> 'one', 'two', 'three', 'four', 'five' | Skip-Last 3
one
two