There was a time when I would have laughed at the thought of a Microsoft shell going up against a Linux shell. In fact, when I first heard of PowerShell that’s exactly what I did. Given the horror that is cmd.exe, any other reaction is hard to imagine. I think it’s best stated by Matt Wrock at Hurry Up and Wait–“Friends don’t let friends use cmd.exe and you are my friend.” Because of this, PowerShell is often convicted of the same crimes and dismissed, by association, with varying degrees of prejudice. For example, Mike James, one of my favorite authors at iProgrammer.info, never fails to amuse me with grumpy PowerShell skepticism, but now that PowerShell is open-source and cross-platform, I think the tide may be turning. In fact, I was recently surprised by how easy it to get a working pwsh prompt on a fresh Antergos Linux installation.

1
2
pacman -S dotnet-sdk pacaur
pacaur -S powershell-bin

Unfortunately, I could not get PowerShell to work with the integrated terminal in VS Code, but I think problems like these will gradually disappear. There seems to be a lot of momentum in making this a first-class experience.

This leaves Linux users faced with an interesting choice. Like so many other dilemmas in software development, the question is not can we, but should we. For long time .NET programmers, like myself, PowerShell on Linux is an easy sell. For veteran Linux hackers, on the other hand…not so much. There is a major paradigm gap and I honestly don’t know which camp will carry the day. So in the interest of “science”, let’s consider an example for both.

I recently needed to query the file system for a list of unique filenames in a set of search directories. For example, given the following directory structure, I would expect the output to be file1, file2, file3.

parentDirectory
--subdir1
----searchDir
------file1
------file2
--subdir2
----searchDir
------file1
--subdir3
----searchDir
------file1
------file2
------file3

This can be accomplished as follows.

PowerShell:

1
Get-ChildItem "parentDirectory\*\searchDir\*" | Select-Object "Name" -Unique

Bash:

1
ls parentDirectory\*\searchDir\* | xargs -n 1 basename | uniq -u

I would argue that the PowerShell version is more intuitive and readable although many find the verbosity off-putting and prefer the terseness of Bash. Admittedly, there is beauty in the succinctness of many Bash commands, but it is a common misconception that PowerShell does not have similar capabilities. In many cases you can achieve a high degree of terseness simply by taking advantage of PowerShell’s support for aliases and partial parameter names. Here is the same command expressed tersely. Note that it is actually more compact than the Bash version although I almost always prefer gross verbosity, but hey that’s just me.

1
ls parentDirectory\*\searchDir\* | select Name -U

Another major difference is that many tasks in Bash involve piping text between various binaries programs. In the above example, four binaries are required to accomplish this task while PowerShell requires only two native cmdlets. Perhaps the most important difference, however, is how pipelines work. In traditional Linux shells, you usually work with binaries that pass text on the standard input and output channels. In PowerShell, you pass around objects in the full object-oriented sense. For example, if I was interested in CreationTime, Extension, IsReadOnly, Length or any of the other numerous FileInfo properties it would be a simple matter to integrate them in my query. Because of this, PowerShell is closer to a functional programming language than a traditional shell where complex queries involving data transforms are a lot harder and, depending on the scenario, usually involve some clever text parsing gymnastics.

Despite PowerShell’s arguable advantages, the traditional way of doing things in Linux is very mature, robust and has an enormous body of documentation around it to help developers become productive quickly. It will certainly be interesting to see how things unfold. I hope to see 12 exciting rounds. Let’s get ready to rumble! 🙂