question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Get-Content -Head and -Tail should behave like head and tail with negative parameters

See original GitHub issue

Prerequisites

Steps to reproduce

SYSTEMATIC REVIEW by @mklement0

Get-Content -Head and -Tail should behave like head and tail with negative parameters, I checked the code and this is by design but I think its not the corect behaviour.

https://www.gnu.org/software/coreutils/manual/html_node/head-invocation.html https://www.gnu.org/software/coreutils/manual/html_node/tail-invocation.html

Create txt file:

@"
1
2
3
4
5
6
"@ | Set-Content file.txt

Expected behavior

Get-Content file.txt -Head -3
head file.txt -n-3

4
5
6

Get-Content file.txt -Tail -3
tail file.txt -n-3

1
2
3

Actual behavior

Get-Content file.txt -Head -3
Get-Content file.txt -Tail -3

1
2
3
4
5
6

Error details

No response

Environment data

Name                           Value
----                           -----
PSVersion                      7.3.4
PSEdition                      Core
GitCommitId                    7.3.4
OS                             Microsoft Windows 10.0.19045
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

Issue Analytics

  • State:open
  • Created 4 months ago
  • Reactions:1
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
mklement0commented, May 25, 2023

Here’s a systematic overview of what the head and tail do with negative numbers and what tail -n +$n does (explicit + prefix), along with the equivalent PowerShell commands:

# `tail`, curiously, treats negative numbers the same as
# unsigned positive ones: -n $n and -n -$n both mean:
# Get the last $n lines.
tail -n -3 file.txt # same as: tail -n 3 file.txt
# PowerShell equivalent
Get-Content file.txt -Last 3 
# Q: Should `-Last -3` be supported too, with the same meaning?

# `head` treats negative numbers (-n -$n) as: 
# Return all but the last $n lines. 
# (Not supported by the stock `head` utility on macOS)
head -n -3 file.txt
# PowerShell equivalent
Get-Content file.txt | Select-Object -SkipLast 3
# Q: Should `Get-Content -First -3 file.txt` be supported too, with the same meaning?
#      Not intuitive; introducing -SkipLast to Get-Content directly would be more PowerShell-idiomatic.
#     (Note that -First and -Last already duplicate Select-Object features).

# tail treats -n +$n, i.e. an explicit "+" prefix as:
# Skip the first $n-1(!) lines, i.e. start with line $n.
tail -n +3 file.txt
# PowerShell equivalent
Get-Content file.txt | Select-Object -Skip 2
# Q: Should `Get-Content -Last +3 file.txt`  be supported too, with the same meaning?
#      Not intuitive, and since -Last is [int]-typed, this wouldn't currently work, 
#      because the "+" wouldn't reach the cmdlet.
#      Introducing -Skip to Get-Content would be more PowerShell-idiomatic.

Note that in the syntax form head -5 and tail -5 the - doesn’t actually indicate a negative number, but is the option ID char - syntactic sugar that is a shortcut to head -n 5 and tail -n 5 (head --lines=5 and tail --lines=5).

One possible resolution:

  • Disallow negative numbers consistently.
  • For feature parity with head and tail, introduce -Skip and -SkipLast parameters to Get-Content
    • I know there’s concern about duplication of functionality, but we already have it in the -First and -Last parameters: in this case it isn’t just about convenience and concision, but also about performance.
1reaction
jhoneillcommented, May 25, 2023

Use -First and -Last aliases

At the moment head -5 or Or -First -5 return the whole file The problem is negative values are ignored .

Select-object gives an error if -index -first or -last is negative. Arguably
GC "foo.txt" -first $x and Gc "foo.txt | select -first $x should do the same for all values of $x. So EITHER Get-Content should validate the parameters and reject negative values OR both should be updated to process negative numbers

When I just tried head -5 is treated as head 5 but head -n -5 gives lines 0 to length -5.
however tail -5 and tail -n -5 both return the last 5 lines.
(in other words you can get first n lines, last n lines, and all but the last n lines, but not all but the first n)

So a user might reasonably expect any of:

  • error for numbers less than 0 -like select-object
  • -head x / -first x and -tail x / last x work with (abs(x) ) -like the head command without -n and the tail command with or without -n
  • -head -n / first -n is read as (length - n )" -like the head command with -n and -last/-tail does the same - which is different from the tail command.
  • half and half with -First/-Head doing (length -n) for negatives and -Last/-Tail doing abs().
  • -first -n is actually -last +n (and vice versa) -like (gc ...)[-1..-n] but unlike head and tail commands.

The first two give consistent behaviour. The last two are horrible and really just for completeness.
Whether making -Tail work like head -n and not like tail / tail -n is something people will doubtless argue over. I think modifying GC so it can easily get the first n, or remove the first n, get the last n or remove last n. is functionally better despite that. Technically it’s a breaking change but it’s unlikely anyone relies on current behaviour, bringing the same thing to Select-Object would also be useful but is a slightly worse breaking change (with $files | select -first $n | del if an error says $n is -1, nothing is selected, but if select-object treats -1 as ‘all but the last 1’ lots gets deleted).

I think the cmdlets wg should have a look at this and I’ll try to get in on the agenda.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Negative arguments to head / tail - shell script
Some implementations of head like GNU head support: head -n -12. but that's not standard. tail -r file | tail -n +13 |...
Read more >
Get last n lines or bytes of a huge file in Windows (like ...
If you have PowerShell 3 or higher, you can use the -Tail parameter for Get-Content to get the last n lines. Get-content -tail...
Read more >
Get-Content (Microsoft.PowerShell.Management)
Specifies the number of lines from the end of a file or other item. You can use the Tail parameter name or its...
Read more >
The head and tail commands in Linux
Both the head and the tail commands are members of the GNU coreutils package. They are, by default, installed in all Linux distributions....
Read more >
Opposite of tail: all lines except the last n lines
to print all but the last 5 lines of file.txt . If head -n takes no negative arguments, try head -n $(( $(wc...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found