Now that I’m doing more Windows development, I’ve had a better chance to try out Windows Powershell in a day to day environment. I think I’m at the point where I see some of the advantages it has over traditional shells; why it has to be different than its predecessors ( not and upgraded cmd.exe, and not a port of the Unix bourne shell.) but at the same time annoyed at it for its own quirks, not just its differences.
First, to explain why its a big deal at all, and why I want to be using it instead of Cygwin’s bash port or cmd.exe: Cygwin has the nice tool and filter toolset, but since there are cases where the Cygwin Unix emulation interferes with the windows based utilities; and those are the ones that I eventually need to work with. I’m thinking of things like path its differing views of the filesystem when passed between Cygwin and Windows components. (If a Unix tool reads the PATH environment variable, it won’t be in the format it wants.) The cmd.exe shell that is included in windows quite have the power of the shell (even with the cmd.exe/e:on extensions) and doesn’t have nearly as good a toolset of utilties to string together.
I feel wary of the way I’m continuing making direct comparisons to the Bourne shell, but its an environment that I’ve long been comfortable and content with. Its a shame that I’m coloring Powershell with /bin/sh colored glasses, but I need some sort of frame of reference, and people with familiarity with the bourne shell would understand why a useful command line environment is important. So I guess in furthering down this path, I have this succinct explanation for someone who uses and appreciates a Unix shell environment.
When you have a Unix shell pipeline, and it has stages where it is building up a line (maybe with awk) doing some positional manipulation and then pulling of portions of the result, you may see a more elegant solution using Powershell. Since the items carries along the pipeline are objects and not text, the object can carry along additional information through the intermediate pipeline phases.
For example, if you wanted to take your current shell aliases, sort them by length, and then display their definition, you might do something like this:
alias|awk -F'[ ='"'"']' '{print $2, length($2),$4}'|sort -n -k2
Doing something similar in Powershell would be:
alias| sort { $_.name.length } | select name,{ $_.name.length },definition
where its sort takes something like a method, property name, or a block expression. The property “definition” is available at the end of the pipeline, even though it isn’t accessed or referenced in the intermediate stages. Since the values are typed (with conversions, like many dynamic languages) the advantages of Powershell can be seen with things that deal with dates or large numbers. (the GNU “du –human-readable” is nice, but you can’t sort or do arithmetic on it. Its tough to use “ls -l”‘s in computation too. )
Where I get annoyed with Powershell is actually when it follows the tool and filter paradigm to a fault. I’ve used older Unixes that used to have ls display in a single line, except maybe with a special ls -c flag (and often configured with an lc alias to do the same.) Eventually most Unix systems made a compromise between ease of use and the toolbox approach and made ls display in columns if the output is a terminal, otherwise display one filename per line. In Powershell, the get-childitem cmdlet (or its ls or dir aliases) presents a list of filenames. If you want it in multiple columns it needs to be piped through format-wide. For this example, ls|fw isn’t all that cumbersome to type, but the other ls switches, like the ones that sort by date turn into things like ls|sort LastWriteTime.