PowerShell is awesome if you haven’t used it but it’s absolutely foreign if you’re used to Unix-like Bash-like shells. For instance, there’s no
ls -al won’t work (but
ls will and it’ll display all files with details!).
If you switch from Linux to Windows, you might be tempted to either install Cygwin or all of your GNU utilities. Or you might go the Linux subsystem route (which is a totally fair way to go) but if you want to go the PowerShell route, here’s a neat little tip!
Grep is basically a utility that lets you filter some data using various patterns. There’s a LOT more to it but my own common usage of it is:
$ cat .bash_history | grep ssh ssh firstname.lastname@example.org ssh email@example.com ssh firstname.lastname@example.org
This will filter out the output of
cat and return only commands that include
ssh. I use this to remind myself of IPs of servers I’ve recently used. Or I might do this:
$ cat package.json | grep webpack "start:dev": "webpack --config webpack/dev.config.js", "webpack": "3.8.1", "webpack-dev-server": "^2.9.4", "webpack-merge": "^4.1.1",
to get all of my webpack plugins, scripts, and figure out the latest version of webpack. It’s a handy utility, and I use it all the time. To filter lists of files in a folder and pipe them to another command or whatever else.
Grep is POWERFUL and it’s super featureful but I won’t get into that in this article.
So what does PowerShell have that’s the equivalent?
One thing that’s immediately apparent about PowerShell is that its commands have better naming conventions. In fact, PS script is more like a programming language than Bash.
PowerShell piping is like Bash piping though it has some differences that I won’t go into right now.
cat package.json | Select-String -Pattern webpack ls ./src/components/ | Select-String -Pattern View
Select-String supports regular expressions so you can also write more complicated stuff like:
C:\> cat post.md | Select-String -Pattern "^\w*:" title: How to "grep" in PowerShell published: false description: tags:
This will extract the front-matter from this post.
How about searching through multiple files?
Absolutely! Grep has a pretty easy syntax for it:
grep $PATTERN glob/pattern/**. An
-r flag will recursively search through a path.
You might use it to identify where you’re using
@select in your Angular application.
@select is a decorator provided by the angular-redux store.
$ grep -r "@select" *.ts comments-list.component.ts: @select(['comments']) comments: Observable<IComment>; comments-list.component.ts: @select(authorsSelector) authors: Observable<any>; comments-list.component.ts: @select(['topComment']) topComment: Observable<IComment>;
So what about PowerShell? In PowerShell, you have to specify an argument but the explicitness actually makes a lot of sense:
C:\> Select-String -Path *.ts -Pattern "@select" comments-list.component.ts:51: @select(['comments']) comments: Observable<IComment>; comments-list.component.ts:53: @select(authorsSelector) authors: Observable<any>; comments-list.component.ts:55: @select(['topComment']) topComment: Observable<IComment>;
Cool, what about recursion? Err…well, to have true recursion working and scan “n” levels deep, you’ll need to string a few commands together so we’ll skip that for now.
Before I leave, I’d like to impart some fun advanced commands. Like I said, PowerShell piping isn’t like Linux piping. One of the big differences is that PowerShell utilizes “objects”.
So here’s a great example:
C:\> Select-String -Path *.ts -Pattern "@select" | Select Filename, LineNumber, Line, Path | Format-Table
What this will do is: find files and matches to our pattern in all of TypeScript files in our current directory, select only the information we want to see, and transform it into a nice looking table like so (edited to fit site width):
Filename LineNumber Line Path -------- ---------- ---- ---- comments-list.component.ts 51 @select(['comme... C:\comments-list... comments-list.component.ts 53 @select(authors... C:\comments-list... comments-list.component.ts 55 @select(['topCo... C:\comments-list...
You can then save it into a file via
Out-File <filename> like so:
C:\> Select-String -Path *.ts -Pattern "@select" | Select Filename, LineNumber, Line, Path | Format-Table | Out-File selectors.txt
Or output to a CSV:
C:\> Select-String -Path *.ts -Pattern "@select" | Select Filename, LineNumber, Line, Path | Format-Table | Export-Csv -path selectors.csv -NoTypeInformation
What I love about PowerShell is that this stuff is built-in and it has sensible names. When I read bash scripts, it can be confusing. I mean, what does
awk do? What about
sed? Can you infer their jobs based on their names? Or what their flags mean?