Friday, August 1, 2008

Formatting Strings in PowerShell

If you're a recovering Perl user, Pythonista, or C junkie, pretty soon you'll be sniffing around in PowerShell looking for a way to format strings.

Does this look familiar to you?

sprintf("%02.2f percent of %04d in %s", $percent, $from, $some_string); # Perl

"%02.2f percent of %04d of %s" % (percent, from, some_string) # Python


Never mind if it doesn't look familiar, but keep this in mind: the ability to choose the format that a variable will be printed in becomes very useful when scripting, especially when dealing with numbers.  Let me give you an example:

You do a dir on the current directory to get the size of a file, and the size is 16493253, but you want to output the number of MB,  so:

PS C:\> 16493253/1MB
15.7291917800903

Now that's a long, nasty number.  Really, you just want to show numbers to two places past the decimal.  PowerShell's way of doing it looks a bit obtuse at first, but it is actually very efficient.

PS C:\> "{0:#.00}" -f (16493253/1MB)
15.73

Note that the .NET string formatting rounds up the number when it sets the precision.  Anyway, let's look at what I just did.  According to Microsoft, Composite Formatting follows this syntax:

{ index[,alignment][:formatString]}

So for starters, any paired curly braces within the format string will be substituted with whatever strings are passed to it via the -f operator.  Consider the following example:

PS C:\> "I have a {0}.  My {0} is {1}." -f "name", "Tojo"
I have a name.  My name is Tojo.

As you can see, the "index" value inserts whatever string is in that position that is passed to the -f operator.  

If you want the string to be placed within a particular column width, you can optionally use the next value, the "alignment" value.  A positive number indicates a right-justified string at least n spaces wide, and a negative number indicates a left-justified string.

PS C:\> ":{0, 20}:" -f "Tojo"
:                Tojo:
PS C:\> ":{0, -20}:" -f "Tojo"
:Tojo                :

The last section of the Composite Format is the actual formatString value.  This is the part of the string that tells PowerShell how to format the string for output.  Let's take a look at the earlier example again:

PS C:\> "{0:#.00}" -f (.16493253/1MB)
15.73

What we have is a format that tells PowerShell that we want to replace the string between the braces with the string after the -f operator and put it into the following format: zero or more digits followed by the decimal with exactly two digits after the decimal.

I won't bother going through all of the possible variations for now, I'll just point you to some useful resources on the Internet, but there is one more thing I should mention.  For any object that supports the ToString() method, you have the option of calling ToString() and passing it the format string directly rather than using the "formatString -f Variable" syntax.

Here are some invaluable resources for when you can't remember the format you're looking for, whether it's a date, percent, currency, or whatever:

MSDN Resources

Other Internet Resources
Under The Stairs: Formatting with PowerShell -- another great writeup on formatting
Hey Scripting Guy!  -- an article on how to format a number as a phone number


1 comment:

Anonymous said...

Oh man.

Why does microsoft make things so difficult.

Why not something simple like:
| Format "%s%s%s", $_.