What's equation of `grep -Ern` in PowerShell? - powershell

I like to search string in all files with command grep -Ern on Bash, but what's equation on Windows PowerShell?
I've read alot about Select-String but I can't make it work as I expect, how should I write the params?

-Ern option stands for
Interpret PATTERNS(In this case Vue) as extended regular expressions(-E)
Read all files under each directory, recursively(-r)
Prefix each line of output with the 1-based line number
within its input file.(-n)
In PowerShell, You can construct the same pattern using the Get-ChildItem and Select-String Cmdlets
Get-ChildItem -path $your_path -Recurse | Select-String -Pattern "pattern"
-Recurse option is to get the items in the specified locations and in all child items of the locations.(equivalent to -r for grep)
Select-String automatically treat -Pattern "pattern" as regular expression(equivalent to -E for grep)
By default, Select-String finds the first match in each line and, for each match, it displays the file name, line number, and all text in the line containing the match(equivalent to -n for grep)

Related

Remove special characters from text file in Windows

I want to output text from a text file in Windows script like you can in Linux with grep:
grep -ve ^# -ve '^;' -ve ^$ /name of file.
I haven't had much success finding a solution. I am trying to use Powershell with little experience using it.
Use Select-String in place of grep:
Select-String -Path 'path/to/file' -Pattern '^[#;]|^$' -NotMatch
Select-String will output a Match object, if you just want to matched strings, grab the Line property:
Select-String ... |Select -Expand Line
Starting with PowerShell 7.0 you can also use the -Raw switch to have Select-String return only the matched strings and nothing else:
Select-String ... -Raw
This comes close. You can have an array of patterns seperated by commas. Just like in bash, the semicolon has to be quoted, because it means "end of statement" in powershell. The command avoids lines that start with "#", ";", or are blank.
'# comment',
'; semicolon',
'',
'one',
'two',
'three' | select-string ^#, '^;', ^$ -notmatch
one
two
three
This is what I used to output I was after; get-childitem zabbix_agentd.conf | select-string -pattern '^[#;]|^$' -notmatch
This is what I was after without all the lines that are commented out and spaces.
zabbix_agentd.conf:24:LogFile=C:\Program Files\Zabbix Agent\zabbix_agentd.log
zabbix_agentd.conf:88:Server=10.0.0.22
zabbix_agentd.conf:130:ServerActive=10.0.0.22
zabbix_agentd.conf:141:Hostname=RED-DOUG
zabbix_agentd.conf:257:Include=C:\Program Files\Zabbix Agent\zabbix_agentd.conf.d\
Thank you for the help, Doug

How to display the file a match was found in using get-content and select-string one liner

I am attempting to search a directory of perl scripts and compile a list of all the other perl scripts executed from those files(intentionally trying to do this through Powershell). A simplistic dependency mapper, more or less.
With the below line of code I get output of every line where a reference to a perl file is found, but what I really need is same output AND the file in which each match was found.
Get-Content -Path "*.pl" | Select-String -Pattern '\w+\.pl' | foreach {Write-Host "$_"}
I have succeeded using some more complicated code but I think I can simplify it and accomplish most of the work through a couple lines of code(The code above accomplishes half of that).
Running this on a windows 10 machine powershell v5.1
I do things like this all the time. You don't need to use get-content.
ls -r *.pl | Select-String \w+\.pl
file.pl:1:file2.pl
You don't need to use ls or Get-ChildItem either; Select-String can take a path parameter:
Select-String -Pattern '\w+\.pl' -Path *.pl
which shortens to this in the shell:
sls \w+\.pl *.pl
(if your regex is more complex it might need spaces around it).
For the foreach {write-host part, you're writing a lot of code to turn useful objects back into less-useful strings, and forcibly writing them to the host instead of the standard output stream. You can pick out the data you want with:
sls \w+\.pl *.pl | select filename, {$_.matches[0]}
which will keep them as objects with properties, but render by default as a table.

Strip lines from text file based on content

I like to use one of the packaged HOSTS (MVPS,) files to protect myself from some of the nastier domains. Unfortunately, sometimes these files are a bit overzealous for me (blocking googleadsservices is a pain sometimes). I want an easy way to strip certain lines out of these files. In Linux I use:
cat hosts |grep -v <pattern> >hosts.new
And the file is rewritten minus the lines referencing the pattern I specified in the grep. So I just set it up to replace hosts with hosts.new on reboot and I'm done.
Is there an easy way to do this in PowerShell?
In PowerShell you'd do
(Get-Content hosts) -notmatch $pattern | Out-File hosts.new
or
(cat hosts) -notmatch $pattern > hosts.new
for short.
Of course, since Out-File (and with it the redirection operator) default to Unicode format, you may actually want to use Set-Content instead of Out-File:
(Get-Content hosts) -notmatch $pattern | Set-Content hosts.new
or
(gc hosts) -notmatch $pattern | sc hosts.new
And since the input file is read in a grouping expression (the parentheses around Get-Content hosts) you could actually write the output back to the source file:
(Get-Content hosts) -notmatch $pattern | Set-Content hosts
To complement Ansgar Wiechers' helpful answer (which offers pragmatic and concise solutions based on reading the entire input file into memory up-front):
PowerShell's grep equivalent is the Select-String cmdlet and, just like grep, it directly accepts a filename argument (PSv3+ syntax):
Select-String -NotMatch <pattern> hosts | ForEach-Object Line | Set-Content hosts.new
Select-String -NotMatch <pattern> hosts is short for
Select-String -NotMatch -Pattern <pattern> -LiteralPath hosts and is the virtual equivalent of
grep -v <pattern> hosts
However, Select-String doesn't output strings, it outputs [Microsoft.PowerShell.Commands.MatchInfo] instances that wrap matching lines (stored in property .Line) along with metadata about the match.
ForEach-Object Line extracts just the matching lines (the value of property .Line) from these objects.
Set-Content hosts.new writes the matching lines to file hosts.new, using "ANSI" encoding in Windows PowerShell - i.e., it uses the legacy code page implied by the active system locale, typically a supranational 8-bit superset of ASCII - and UTF-8 encoding (without BOM) in PowerShell Core.
Use the -Encoding parameter to specify a different encoding.
>, by contrast (an effective alias of the Out-File cmdlet), creates:
UTF16-LE ("Unicode") files by default in Windows PowerShell.
UTF-8 files (without BOM) in PowerShell Core - in other words: in PowerShell Core, using
> hosts.new in lieu of | Set-Content hosts.new will do.
Note: While both > / Out-File and Set-Content are suitable for sending string inputs to an output file, they are not generally suitable for sending other data types to a file for programmatic processing: > / Out-File output objects the way they would print to the console / terminal, which is pretty format for display, whereas Set-Content stringifies (simply put: calls .ToString() on) the input objects, which often results in loss of information.
For non-string data, consider a (more) structured data format such as XML (Export-CliXml), JSON (ConvertTo-Json) or CSV (Export-Csv).

Find Carriage Returns in Files Using Powershell

I want to see all the instances of files containing the Windows-style crlf instead of Unix-style lf in a set of files. Here's what I have so far:
sls -Path src/*.cs -Pattern "`r`n" | group Path | select name
This works if I search for any normal text, but it's not finding the carriage returns, even though (according to everything I can find online) that's the proper Powershell escape sequence for carriage returns and newlines. For the record \r\n doesn't work either.
sls (an alias for Select-String) works line by line, so it's already processing (consuming) the line breaks during the file reading process before it gets to the regex matching.
Use something that reads the entire file, and then look for it:
Get-ChildItem -Path src/*.cs | ForEach-Object {
$contents = [System.IO.File]::ReadAllText($_.FullName)
if ($contents -cmatch '\r\n') {
$_
}
} | Group-Object Directory | Select-Object Name
\r\n is used here instead of the backticks because you're escaping them for the regex engine, not for powershell.

piping files to get-content

I'm trying to find a single line of code recursively using powershell.
To look for the line "TODO" in a known file I can do:
get-content ActivityLibrary\Accept.cs | select-string TODO
But I don't want to explicitly type every directory\file. I would like to pipe a series of filenames from get-childitem like this:
gci -filter *.cs -name -recurse | gc | select-string TODO
But then I see this error:
Get-Content : The input object cannot be bound to any parameters for
the comman d either because the command does not take pipeline input
or the input and its properties do not match any of the parameters
that take pipeline input. At line:1 char:37
What am I doing wrong?
You need to remove the -Name switch. It outputs just file names, not file objects. And you can also pipe directly to Select-String and drop 'gc'.