Your Linux command packs a lot of functionality into a single pipeline.
Your lack of effort to solve the problem yourself notwithstanding, constructing an equivalent PowerShell command is an interesting exercise in contrasting
a Unix-utilities solution with a PowerShell solution:
To set the scene, let me explain what your command does:
grep Ban /var/log/fail2ban.log
case-sensitively finds lines that contain the word Ban
in file /var/log/fail2ban.log
and passes only those on.
grep -v 'Restore Ban'
further (case-sensitively) filters out (-v
) lines that contain the phrase 'Restore Ban'.
sed 's/\s\s*/ /g'
replaces all (g
) runs of 1 or more whitespace chars. (\s
; in a modern regex dialect you'd use \s+
) with a single space ...
... which then allows cut -d" " -f8
to reliably extract the 8th field from each line from the resulting space-separated list (e.g., 2*8.1*7.1*9.2*9
).
sort
then lexically sorts the resulting lines, and uniq -c
weeds out duplicates, while prepending each unique line with the count of duplicates (-c
), with 1
indicating a unique line.
Finally, sort -t ' ' -n -b
sorts the resulting lines numerically by duplicate count.
In short: your command filters a log file via regex matching, extracts the 8th field from each line, eliminates duplicates, and prints unique fields prefixed with their duplicate count, sorted by duplicate count in ascending order.
Below is a near-equivalent PowerShell command, which:
is more readable (and therefore, of necessity, more verbose)
involves fewer steps
ultimately offers much more flexibility, due to:
- sending objects through the pipeline, not just text that must often be (re)parsed - it is this feature that constitutes PowerShell's evolutionary quantum leap from traditional shells.
- far superior language features (compared to POSIX-like shells such as
bash
) that can easily be woven into a pipeline.
That said, the price you pay for the increased power is performance:
- Directly comparable commands perform much better using Unix utilities, though the usually higher level of abstraction and flexibility provided by PowerShell cmdlets may make up for that.
Here's the command, with the roughly corresponding Unix-utility calls in comments:
Select-String -CaseSensitive '(?<!Restore )Ban' /var/log/fail2ban.log | #grep,grep -v
ForEach-Object { (-split $_.Line)[7] } | # sed, cut -f8
Group-Object | # uniq -c
Select-Object Count, Name | # construction of output *objects*
Sort-Object Count, Name # sort, sort -n
The command outputs objects with a .Count
(duplicate count) and .Name
property (the 8th field from the log file), which:
- allow for robust additional processing (no parsing of textual output needed).
- render in a friendly manner to the console (see below).
Example output:
Count Name
----- ----
8 1*2.2*6.1*1.1*5
12 3*.1*.*4.*6
18 1*5.2*8.2*5.4
19 1*2.2*6.1*1.1*4
72 3*.1*6.2*.9*
For an explanation of the command, consult the following help topics, which are also available locally, as part of a PowerShell installation, via the Get-Help
cmdlet: