1

I'm aware that Get-Content has a -Tail parameter, but as far as I can tell, there's simply no way to get it to accept piped input.

So how do I get something like this to work? I just want to be able to select first X or last X lines from any preceding command, without the hassle of creating temp files simply so I can grab the first/last lines from it.

# This won't work as Get-Content demands a -Path to a file
Get-Item .\* | Get-Content -Tail 10

Some added finagling will likely be required depending on whether the first command is providing objects or strings as output; if you can include such intermediary steps in your reply, that'd be awesome. I expect something like Out-String -stream might be the done thing?

I've scoured the internet and came up empty-handed. Thanks in advance for any help.

Cardgage
  • 13
  • 2
  • Have you tried the piping the path in a ForEach-Object? `Get-Item .\* | ForEach-Object { Get-Content -Path $_.FullName -Tail 10 }` – Grok42 Jul 26 '23 at 12:23
  • @Grok42 Thanks for chipping in, but this is slightly askance to what I asked; see the 2 answers below my post - that is what I wanted to accomplish, and issue is solved. – Cardgage Jul 27 '23 at 13:22

2 Answers2

2

You can use the Select-Object cmdlet to shape a piped input stream by using the -First/-Last parameters parameters, much like head/tail works in a Unix shell:

PS ~> 1..100 |Select-Object -First 5
1
2
3
4
5
PS ~> 1..100 |Select-Object -Last 5
96
97
98
99
100
mklement0
  • 382,024
  • 64
  • 607
  • 775
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
1

PowerShell's pipeline is based on objects rather than lines of text, and Mathias R. Jessen's helpful answer has the object-oriented angle covered:

  • Select-Object -First / -Last selects only the first / last N objects - whatever their type - and then renders them to the display using PowerShell's rich for-display output-formatting system.

  • Given that the formatting of a single object can span multiple lines (consider the display output when you submit $PSVersionTable), there's no guarantee that the output will be limited to N lines.

If, by contrast, your intent is to limit the output to a given number of display lines - irrespective of how many objects the result corresponds to:

  • Insert an Out-String call with the -Stream switch parameter before the Select-Object call. PowerShell v5+ even has a built-in wrapper function for this, oss.

  • This performs the for-display formatting to a string, with -Stream then emitting the lines of the result one by one.


A simple example that illustrates the two approaches and how they differ:

# Create 10 sample objects that render with Format-List
# (each property on its own line)
$objects = 
  1..10 | ForEach-Object { [pscustomobject] @{ a=1*$_; b=2*$_; c=3*$_; d=4*$_; e=5*$_ } }

Write-Verbose -Verbose 'First 2 *objects*:'
# Select the first 2 *objects*, which are then rendered, 
# each with multiple lines.
$objects | Select-Object -First 2

Write-Verbose -Verbose 'First 2 *lines*:'
# Create the for-display representation as a string up front, 
# then select the first 2 *lines*
$objects | oss | Select-Object -First 2

This outputs the following:

VERBOSE: First 2 *objects*:

a : 1
b : 2
c : 3
d : 4
e : 5

a : 2
b : 4
c : 6
d : 8
e : 10

VERBOSE: First 2 *lines*:

a : 1

Note:

  • PowerShell's output formatting often involves a leading and trailing empty line, which is why the output from the oss-based command starts with an empty line and only shows one property value (you could address that by eliminating blank lines as follows:
    $objects | oss | Where-Object { $_.Trim() } | Select-Object -First 2)

  • An important use case for oss is quick-and-dirty text searches in object output via Select-String:

    • E.g., the following would show only the lines that contain the digit (string) 3:

      $objects | oss | Select-String '3'
      
      • Note that this technique is meant for convenient, interactive use only; for robustness, especially in scripts, using OO techniques for filtering, notably via Where-Object, is the right approach.
    • Sadly, Select-String doesn't have the oss stringification logic built in, even though it arguably should - see GitHub issue #10726.

mklement0
  • 382,024
  • 64
  • 607
  • 775