PowerShell equivalent for "head -n-3"?
Asked Answered
S

6

23

I've been able to track down basic head/tail functionality:

head -10 myfile <==> cat myfile | select -first 10
tail -10 myfile <==> cat myfile | select -last 10

But if I want to list all lines except the last three or all lines except the first three, how do you do that? In Unix, I could do "head -n-3" or "tail -n+4". It is not obvious how this should be done for PowerShell.

Stockstill answered 9/4, 2012 at 20:40 Comment(0)
E
10

Like the -First and -Last parameters, there is also a -Skip parameter that will help. It is worth noting that -Skip is 1 based, not zero.

# this will skip the first three lines of the text file
cat myfile | select -skip 3

I am not sure PowerShell has something that gives you back everything except the last n lines pre-built. If you know the length you could just subtract n from the line count and use the -First parameter from select. You could also use a buffer that only passes lines through when it is filled.

function Skip-Last {
  param (
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)][PsObject]$InputObject,
    [Parameter(Mandatory=$true)][int]$Count
  )

  begin {
    $buf = New-Object 'System.Collections.Generic.Queue[string]'
  }

  process {
    if ($buf.Count -eq $Count) { $buf.Dequeue() }
    $buf.Enqueue($InputObject)
  }
}

As a demo:

# this would display the entire file except the last five lines
cat myfile | Skip-Last -count 5
Ease answered 9/4, 2012 at 22:14 Comment(0)
S
23

Useful information is spread across other answers here, but I think it is useful to have a concise summary:

All lines except the first three

1..10 | Select-Object -skip 3
returns (one per line): 4 5 6 7 8 9 10

All lines except the last three

1..10 | Select-Object -skip 3 -last 10
returns (one per line): 1 2 3 4 5 6 7

That is, you can do it with built-in PowerShell commands, but there's that annoyance of having to specify the size going in. A simple workaround is to just use a constant larger than any possible input and you will not need to know the size a priori:

1..10 | Select-Object -skip 3 -last 10000000
returns (one per line): 1 2 3 4 5 6 7

A cleaner syntax is to use, as Keith Hill suggested, the Skip-Object cmdlet from PowerShell Community Extensions (the Skip-Last function in Goyuix's answer performs equivalently but using PSCX saves you from having to maintain the code):

1..10 | Skip-Object -last 3
returns (one per line): 1 2 3 4 5 6 7

First three lines

1..10 | Select-Object –first 3
returns (one per line): 1 2 3

Last three lines

1..10 | Select-Object –last 3
returns (one per line): 8 9 10

Middle four lines

(This works because the -skip is processed before the -first, regardless of the order of parameters in the invocation.)

1..10 | Select-Object -skip 3 -first 4
returns (one per line): 4 5 6 7
Sax answered 11/4, 2012 at 20:30 Comment(0)
E
10

Like the -First and -Last parameters, there is also a -Skip parameter that will help. It is worth noting that -Skip is 1 based, not zero.

# this will skip the first three lines of the text file
cat myfile | select -skip 3

I am not sure PowerShell has something that gives you back everything except the last n lines pre-built. If you know the length you could just subtract n from the line count and use the -First parameter from select. You could also use a buffer that only passes lines through when it is filled.

function Skip-Last {
  param (
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)][PsObject]$InputObject,
    [Parameter(Mandatory=$true)][int]$Count
  )

  begin {
    $buf = New-Object 'System.Collections.Generic.Queue[string]'
  }

  process {
    if ($buf.Count -eq $Count) { $buf.Dequeue() }
    $buf.Enqueue($InputObject)
  }
}

As a demo:

# this would display the entire file except the last five lines
cat myfile | Skip-Last -count 5
Ease answered 9/4, 2012 at 22:14 Comment(0)
F
2

If you're using the PowerShell Community Extensions, there is a Take-Object cmdlet that will pass thru all output except the last N items e.g.:

30# 1..10 | Skip-Object -Last 4
1
2
3
4
5
6
Forby answered 9/4, 2012 at 22:37 Comment(0)
S
2

All but the last n can be done with

... | select -skiplast $n
Solicit answered 9/11, 2017 at 19:22 Comment(0)
T
1

You can do it like this:

[array]$Service = Get-Service
$Service[0] #First Item
$Service[0..2] #First 3 Items
$Service[3..($Service.Count)] #Skip the first 3 lines
$Service[-1] #Last Item
$Service[-3..-1] #Last 3 Items
$Service[0..($Service.Count -4)] #Skip the last 3 lines
Tade answered 9/4, 2012 at 22:13 Comment(0)
M
0

All but the first n can be done with

... | Select -skip $n

However all "but the last m" has nothing inbuilt. It is doable loading the whole input into an array to get the length – of course for large input that can put unreasonable demands on memory.

Mutule answered 9/4, 2012 at 21:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.