Tuesday, September 17, 2013

A better "For" loop without using "For" in PowerShell

I hate the ugly For command in PowerShell.  It is ugly, inelegant and non-intuitive.  And it's ugly.

But this is PowerShell, and there is always another way to do everything.

Back when I was writing in BASIC, sometime in the Pleostine Era, I think, if you needed to loop ten times, with variable i incrementing for each loop, it looked like this:

For i = 1 to 10

Next I

(I left out the line numbers.  Are you old enough to remember line numbers?)

The PowerShell architects decided to make the same functionality look like this:

For ( $i = 1; $i -lt 11; $i++ )
{ }


Blech.  That may be intuitive to someone with a background in whatever predecessor language they borrow that from.  (I certainly hope they didn't come up with that completely on their own.)  It is also very flexible and allows you to do many fancy things.

But I don't need to do anything fancy; I just need to loop 10 times, and I need it to be readily apparent that that's what I'm doing, and I don't want it to be so damn ugly.

Instead of using For, what if we use ForEach?

(ForEach is an alias for ForEach-Object.  I mostly follow the best practice of not using aliases in scripts to help assure portability, but ForEach is one of my exceptions, especially in this context, as it improves the readability of the script, which is half the point of this tip.)

ForEach allows you to loop through a block of code, once for each object in a collection or array.  So we could use it to loop through an array containing the integers 1 through 10.

We don't want to have to build an array object and populate it with a bunch of integers.  That's too much work and even clunkier than the For command.  Especially if the number of loops we need is variable.

PowerShell shortcuts to the rescue!

From a PowerShell prompt, if I type:

1..4

I get:

1
2
3
4


Two integers separated by two periods is PowerShell shorthand for an array of integers from the first number to the second number, inclusive.

It even works with variables.

$LastOne = 5
1..$LastOne


Yields

1
2
3
4
5


It even works with nested commands.  For example:

1..( ( Get-ChildItem D:\TestFolder ).Count + 2 )

So if we combine that with the ForEach command, we get an elegant statement that is even more intuitive than the old BASIC For command, and far, far better than the ugly PowerShell For command.

ForEach ( $i in 1..10 )
{ }

No comments:

Post a Comment