I’ve used searching in my previous PowerShell posts, but I thought that it deserves a dedicated “Quick Tip” posting. I know that folks coming from a *nix background will be very familiar with using grep to search for pretty much anything and seemingly not having access to this tool can be disappointing for those trying to use Windows as their primary OS (for the one or two of you out there that have decided to come to the “dark side” 😎 ). But…do not fret! There are a number of ways to run equivalent searches within Windows out of the box. Since I’ve been on a PowerShell kick lately, let me introduce you to a decent grep alternative that is built into PowerShell: select-string.
Select-String is a built-in cmdlet in PowerShell that will allow you to search files, piped input, objects, etc for a pattern (which is, by default, a regular expression). Select-String can take in a number of options, but can be quite simple to use. For example, if you want to search for the text “evildoer” within all files in the current directory, you can use the following command:
select-string .\*.* -pattern "evildoer"
It is important to note that by default, select-string is case-insensitive; so, if you need a case sensitive search, add in the -CaseSensitive parameter.
Ok, now let’s do something a bit more complex. I want to look for anything that looks like an email address in all txt files recursively under C:\. So, to make that happen we need to do a little more work:
get-childitem c:\ -include *.txt -rec | select-string -pattern "\[email protected][a-zA-Z_]+?\.[a-zA-Z]{2,6}"
First, I need to use get-childitem (think DIR) to recursively go through the drive and return only files matching *.txt. Then I pipe these returned objects to select-string and search their contents by using a basic regex that will match on things that look like email addresses.
Of course, there are a number of other ways to use select-string but since this is a “quick tip” I’ll keep things brief. If you’d like more details, you can find additional information in the PowerShell documentation on TechNet.
Thanks! I was looking for the grep command equivalent on Windows and this answered my question.
One other thing to note, dir is an alias for get-childitem, and you don’t have to say -include, so your example can be shortened to
dir c:\ *.txt -rec | select-string -pattern “\[email protected][a-zA-Z_]+?\.[a-zA-Z]{2,6}”
Plus, get-alias | where-object {$_.Definition -match “Select-String”} tells us that we can use sls instead of select-string. And we can shorten -rec to -r as well.
dir c:\ *.txt -r | sls -pattern “\[email protected][a-zA-Z_]+?\.[a-zA-Z]{2,6}”
Thanks for the post!
Thomas, you are a good programmer to yourself but not a good teacher. If we are reading this tech quick note we are probably beginner so it much appreciated if things are more intuitive. Oh and by the way, sls won’t work on powershell 2.0.
That comment is rude and irrelevant. I found the post very “intuitive” and was able to use the suggested syntax right away.
Thanks for posting.
However select-string/sls is totally not = grep see following example. Please let me know if there is option to have it return the line that we are select-string/sls for.
grep will return the whole line that contain what you are greping for. but sls not. BUT, on windows with select-string/sls it will not give me the line that contain the failed. For example vssadmin list writes, this command usually return a full page, so I was hoping to do a | select-string “failed” but it only return State: [7] Failed State: [7] Failed. so how am I suppose to know which write failed.
on unix machine.
jli 4885 0.0 0.1 134652 2180 ? S Feb27 0:00 /usr/libexec/gvfsd-burn –spawner :1.7 /org/gtk/gvfs/exec_spaw/1
postfix 10486 0.0 0.1 78756 3212 ? S 13:24 0:00 pickup -l -t fifo -u
jli 10722 0.0 0.5 273172 12180 ? Sl 14:38 0:00 gnome-terminal
jli 10723 0.0 0.0 8280 688 ? S 14:38 0:00 gnome-pty-helper
jli 10724 0.0 0.0 108392 1820 pts/0 Ss 14:38 0:00 bash
root 10765 0.0 0.2 163056 4248 pts/0 S 14:43 0:00 su
root 10774 0.0 0.0 108392 1816 pts/0 S+ 14:43 0:00 bash
root 10843 0.0 0.2 77456 4976 ? S 14:45 0:00 /usr/sbin/packagekitd
root 10944 0.0 0.0 64412 1192 ? Ss 14:46 0:00 /usr/sbin/sshd
root 10948 0.3 0.2 98216 4468 ? Ss 14:47 0:00 sshd: jli [priv]
jli 10954 0.0 0.0 98216 1944 ? S 14:47 0:00 sshd: [email protected]/1
jli 10955 0.0 0.0 108392 1800 pts/1 Ss 14:47 0:00 -bash
jli 10985 3.0 0.0 110292 1160 pts/1 R+ 14:48 0:00 ps -aux
[[email protected] ~]$ ps -aux | grep postfix
Warning: bad syntax, perhaps a bogus ‘-‘? See /usr/share/doc/procps-3.2.8/FAQ
root 2257 0.0 0.1 78676 3252 ? Ss Feb27 0:00 /usr/libexec/postfix/master
postfix 2265 0.0 0.1 78928 3360 ? S Feb27 0:00 qmgr -l -t fifo -u
postfix 10486 0.0 0.1 78756 3212 ? S 13:24 0:00 pickup -l -t fifo -u
jli 10989 0.0 0.0 103304 852 pts/1 S+ 14:48 0:00 grep postfix
in windows
PS C:\Windows\system32> vssadmin list writers | select-string -pattern “failed”
State: [7] Failed
State: [7] Failed
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PS C:\Windows\system32> vssadmin list writers
vssadmin 1.1 – Volume Shadow Copy Service administrative command-line tool
(C) Copyright 2001-2005 Microsoft Corp.
Writer name: ‘Task Scheduler Writer’
Writer Id: {d61d61c8-d73a-4eee-8cdd-f6f9786b7124}
Writer Instance Id: {1bddd48e-5052-49db-9b07-b96f96727e6b}
State: [1] Stable
Last error: No error
Writer name: ‘VSS Metadata Store Writer’
Writer Id: {75dfb225-e2e4-4d39-9ac9-ffaff65ddf06}
Writer Instance Id: {088e7a7d-09a8-4cc6-a609-ad90e75ddc93}
State: [1] Stable
Last error: No error
Writer name: ‘Performance Counters Writer’
Writer Id: {0bada1de-01a9-4625-8278-69e735f39dd2}
Writer Instance Id: {f0086dda-9efc-47c5-8eb6-a944c3d09381}
State: [1] Stable
Last error: No error
Writer name: ‘System Writer’
Writer Id: {e8132975-6f93-4464-a53e-1050253ae220}
Writer Instance Id: {76f41b35-388e-44bb-9397-4a928afa624a}
State: [7] Failed
Last error: Timed out
Writer name: ‘ASR Writer’
Writer Id: {be000cbe-11fe-4426-9c58-531aa6355fc4}
Writer Instance Id: {2a3b459a-31a9-4905-a68e-ceec1ec81757}
State: [1] Stable
Last error: No error
Writer name: ‘IIS Config Writer’
Writer Id: {2a40fd15-dfca-4aa8-a654-1f8c654603f6}
Writer Instance Id: {753ab883-ea71-451d-9b32-2ab201344ad3}
State: [7] Failed
Last error: Timed out
oh, my bad, it does return the line where it has the pattern. am powershell out.
How about a grep -c equivalent? Thanks! Al
Hmm… old school CMD grep-ish functionality…
c:\> for %f /s in (*.txt) do @echo %f && @findstr /r “yourregexhere” “%f”
tl;dr wall of results text
c:\> help for
c:\> help findstr
to use the for loop in a .CMD file:
for /s %%f in (%1) do @@echo %f && @findstr /r “%2” “%%f”
the regular expression language for the CMD shell is kind of limited, but not totally lame, like T-SQL.
Ooops! Forgot to double-up the %f in the 2nd line. It should be:
for /s %%f in (%1) do @@echo %%f && @findstr /r “%2″ “%%f”
I was really frustrated by the fact that nobody has offered a way to “permanently” fix this issue, and all I wanted was a quick way to search for text matching my query. I ended up creating a simple function that does a vanilla grep.
function psgrep {gci *\*.* | sls -pattern $args[0]}
set-alias grep psgrep
I throw this in my $profile so I can use it wherever I need to quickly find some text (in a codebase for example).