09 January 2008

PowerShell and Cat Extract Lines with Line Numbers

I wanted to extract some lines of text, each line prefixed with its line number, from a text file. Frustratingly, while IDEs such as Visual Studio and NetBeans and text editors such as Vim happily (if software were said to have emotion) show line numbers in their display, you can't select the line numbers with text! In the last century, I would use cat -n | head -n1 | tail -n2 and copy the required lines from the output. Fast forward to yesterday where I found myself using cat -n again in PowerShell. This time, I could use Select-Object to extract only the lines I wanted …

> cat -n <file> | select-object -first n1 | select-object -last n2
Get-Content : A parameter cannot be found that matches parameter name 'n'.
…

It turns out that cat is aliased to Get-Content, which doesn't process the -n parameter. Shay Levi and Richard Siddaway provided me with some solutions (see newsgroup microsoft.public.windows.powershell, topic "Temporarily ignore alias") and I was on my way again:

> cat.exe -n <file> | select-object -first n1 | select-object -last n2

Of course, since the first command creates an array of strings, you can slice it and end up with a much shorter statement:

> (cat.exe -n <file>)[r1..r2]

Note the following relationship: r1 = n1-n2 and r2 = n1.

But if you don't have cat.exe installed, you can reproduce the behaviour of cat -n with this PowerShell solution:

> get-content <file> | foreach-object { $i=1 } { "{0,4} {1}" -f $i, $_; $i++ }

Let's analyze the second command: -f is the PowerShell format operator which formats the right-hand argument ($i, $_) using the left-hand argument ("{0,4} {1}"). The first format control string ({0,4}) means "format input 0 in 4 spaces, right aligned". The second format control string ({1}) just writes each line without any formatting.