3 ms·
I had been a full-time Linux (desktop) user for more than 10 years, and only recently made a transition to Windows. As I'm nowhere proficient at using PowerShel
by yokohummer7 10y ago
I had been a full-time Linux (desktop) user for more than 10 years, and only recently made a transition to Windows. As I'm nowhere proficient at using PowerShell I might be overrating it a bit, as the grass is always greener on the other side. Anyways, what I found to be satisfying while using PS were:
1. The input/output is done using objects. I know that "inter-process communication should be done with text" is the UNIX philosophy, and I appreciated that when using Linux, but after using PS I started to have mixed feelings about that. When using bash/zsh, I typically used awk to extract the data I wanted from the text emitted by an external process. Doing so isn't hard, mostly as simple as using `awk {print $3}` or something like that, but it is still a bit annoyance and more importantly, vulnerable to the changes in the output format.
PS cmdlets communicate with themselves using objects, so it is very easy to extract some columns out of the command results. For example, when I query about a process in PS:
PS> Get-Process -Name chrome
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
362 80 169636 109896 36,411.16 484 1 chrome
497 113 274988 132544 5,161.00 656 1 chrome
404 84 87444 55356 303.56 764 1 chrome
If I want to extract CPU time and process ID:
PS> Get-Process -Name chrome | Format-Table -Property cpu,id
CPU Id
--- --
36441.265625 484
5163.09375 656
303.5625 764
Let's see what processes consumed the CPU most!
PS> ps chrome | sort cpu -descending | select -first 3
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1186 317 1876160 1055016 88,462.64 10524 1 chrome
1023 88 1825008 668684 37,740.92 6128 1 chrome
362 80 155776 64560 36,848.00 484 1 chrome
As you can see, I can simply specify the column name(s).
This is probably why many Linux commands have detailed options to limit displayed information. For example, `uname` has -s, -r, -m, -p, and many others that are just portions of -a. If it were in PS there would be no other options than -a and users could utilize it accordingly. Likewise `ps` has many options just to control the output which is again not necessary in the PS's side.
Also due to the probable scripts that may be reliant on the column orders (e.g. my script assumes the third column to be always the one I wanted, because I hard-coded `awk {print $3}` in there), it is very hard to change the layout of the output in Linux commands. In PS there is no layout in the first place, so this backward compatibility concern doesn't exist.
2. Command names are much clearer. Many names are pretty descriptive so I don't have to remember the exact abbreviated forms, but at the same time they provide shorter aliases. For example `Get-Process` can also be called `ps`. bash/zsh can also benefit from this by manually assisning aliases, but I believe "sane defaults" should be long-descriptive names first, and abbreviated forms later.
3. Much more objected-oriented design. Say for example you want to get the last modified date of a file. In Linux I'd use `stat` and somehow extract information from it. Or, `stat` may have some option to print mtime so I may have to google for it. In PowerShell, I can use this instead:
$file = Get-Item C:\Windows\notepad.exe
$file.LastWriteTime
This also applies to the process example above:
$processes = Get-Process -Name chrome
$processes[0].CPU
All of these are benefited by tab completion, so you can easily find what properties any object has. This greatly improves discoverability, so that I don't need to rely on documentations (man pages on Linux, MSDN on Windows).
Not only that, but PS is much closer to a general-purpose programming language than bash/zsh. It has built-in calculations (no need to rely on expr/bc), and it even has some basic type safety, such as:
PS> 1 + 2
3
PS> 1 + "a"
Cannot convert value "a" to type "System.Int32". Error: "Input string was not in a correct format."
+ 1 + "a"
+ ~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
which might be silently ignored in bash/zsh in most cases. As you can see it even has fixed-width integer types (Int32), which is rarely seen in dynamic languages!
When the logic of my scripts got complicated, I tended to abandon shell scripts and start programming in Python. But after learning PowerShell I'm starting to have a confidence that typical workflows can be implemented in PowerShell, in a readable way. I even think that PS can be utilized as a general-purpose programming language, like, "Python without dependencies", because PS is installed by default on Windows nowadays.
Whoa, my response got unintentionally huge O.o. Hope this helps anyone.
- hashhar 10y agoYou seem to have articulated all my thoughts perfectly. The thing about parsing text is a very huge pain point for me because I've had some tool change their output (and unicode issues) which broke some scripts. The structured nature of PS makes it very powerful and allowed me to write a script that checks the latest versions of some software upstream and tells me if there are updates. I have that on bash as well but it's comparatively unmaintainable.
- itaysk 10y agoi agree with the fact that PS object oriented communication between commands is much better then text. But I disagree about your point (2) saying that command names are more discoverable. with linux style conventions, there is a hierarchy that helps you navigate between command's features. for example `docker image ls` you can type docker, see that there is an images subtree, type docker images, see that there is an ls command, and run it. With Powershell you kind of have to guess and type `get-docker` and tab through commands. Also some times the verb is not easy to guess. So in terms not relying on documentation as you called it, I think PS is worse. That being sayd, once you do know the command you need, using it is much easier with PS as you nicely described. tip - if you liked tab completion, try ctrl+space :)
- yokohummer7 10y agoI was thinking more about the "proper noun" aspect of the UNIX commands. I mean, what do `awk`, `sed`, `tar`, `xargs`, `df` mean? Why does `free` only print the remaining memory, not the disk space? Why is `top` even related to processes? They are all like that because Unix has had a long way until today. In the beginning `grep` would have been enough, but suddenly someone wanted to improve the state of affairs, and made a new command named `awk`. Probably there had only been `ar`, and then later the necessity of `tar` was found. `free` is not `mf` and `df` is not `free`, because the original designer thought the free space of the main memory was more important. All these inconsistency/idiosyncrasy do make learning the UNIX command hierarchy harder. We developers don't feel that way because we all are very used to such commands, but there might be some memory in our inside when we tried really hard to memorize all of the useful commands just to do basic things. PowerShell didn't have this backward compatibility concern so it built up its own vocabulary from the scratch. While it is nowhere near to perfect (as your example shows, the VERB-NOUN naming scheme can be a bit cumbersome when some functionalities need to be grouped), I'd say it is at least much more consistent regarding basic file/device management, because there was simply no baggage to consider when they designed PowerShell for the first time. Ah, and thanks for suggesting `Ctrl-Space`! I thought it would have been better if PowerShell had a GUI widget listing possible candidates, so I was considering sending a patch. It turns out that the MS people are definitely more clever than me. :)