In a somewhat recent post here — that I can’t remember off the top of my head — I put something together much like the below example. It completed a countdown from 10 to 1 seconds (or did it count up?), paying attention to whether it should use the word “second” or “seconds.” I’m not going to chase down that post, but do take a look at the example.
10..1 | ForEach-Object { If ($_ -eq 1) { "$_ second" } Else { "$_ seconds" } Start-Sleep -Seconds 1 }
Here’s what that looks like once it’s done executing. Do notice that each string includes seconds up until we get down to one second. It works as expected!
10 seconds 9 seconds 8 seconds 7 seconds 6 seconds 5 seconds 4 seconds 3 seconds 2 seconds 1 second
Before we move on, if you find this in my code, you’ll likely see it use substantially less amount of lines. Like one. While I pride on myself on readable code, something this simplistic and of little consequence need not be on full display at times — it’s up to your discretion.
10..1 | ForEach-Object {If ($_ -eq 1) {"$_ second"} Else {"$_ seconds"}; Start-Sleep -Seconds 1}
I got to thinking (due a project — which is typical), what if we didn’t move downward in the console as we did the count down? Is it possible to overwrite the last countdown indication? What I mean is, is it possible to overwrite 10 seconds, with 9 seconds, and so on? if you’re reading this, then yes, it’s possible.
10..1 | Foreach-Object { If ($_ -eq 10) { $Cursor = [System.Console]::CursorTop } [System.Console]::CursorTop = $Cursor '{0:d2}' -f $_ Start-Sleep -Seconds 1 }
The following gif indicates how the above code executes. You can see that the countdown occurs right over the top of itself. There’s no moving downward in the console, and for me, that’s preferred. Do notice that we’re using the the -f formatting operator. I bring this up, because it’s helping me deal with a bit of a problem. If we didn’t use it, and used single digits for the values 9 through 1, we’d have the left over zero from 10 to the right of each single digit. That would make 9, 90, it would make 8, 80, etc. There’s probably a better way to handle this obnoxiousness, but this is the option I went with this evening. I’ll keep this in mind, and perhaps update this post if I determine a better way to avoid double digit, single digits.
In this example, we’ve combined the previous two. We’re including the string values of “seconds,” and “second” in our countdown. I’ve also included a gif for this example further below.
10..1 | Foreach-Object { If ($_ -eq 10) { $Cursor = [System.Console]::CursorTop } [System.Console]::CursorTop = $Cursor If ($_ -eq 1) { "$('{0:d2}' -f $_) second" } Else { "$('{0:d2}' -f $_) seconds" } Start-Sleep -Seconds 1 }
Take a look at this gif, and then we’ll discuss it. Ugh.
Did you see it? The problem I mentioned previously is back. It needs to be dealt with now, not some time in the future, which was what was preferred. When it goes to 1 second remaining, our final “s,” in the plural form of seconds, sticks around and gives the appearance the code is failing in a manner different than one might expect at first.
I wanted to get this post published, so let me show you what I did. I’ll do my best to get back to this post later, but for now, here’s the “fix.”
10..1 | Foreach-Object { If ($_ -eq 10) { $Cursor = [System.Console]::CursorTop } [System.Console]::CursorTop = $Cursor "Seconds remaining: $('{0:d2}' -f $_)" Start-Sleep -Seconds 1 }
Yeah, you saw that correctly. I’ve moved the numeric values to the end, or right-most, portion of our string. This means that we’re not going to leave the final “s” in seconds. Even so, we do have to continue to use double digits for single digits (the whole leading-zero thing). I can live with that for now. Have a look. Now to add this to my project, so the user can have something to do while these seconds pass before a restart.
You could get around the problem by using something like:
If ($_ -eq 1) {
‘{0:d2} {1,-7}’ -f $_, ‘second’
…
Well done, Cliff. I had a good feeling that someone might come through with this one. I do appreciate not having to have figure it out myself.