0

I have the following Unix shell script. I would like to convert this into a Windows .bat file (I know I can use Cygwin instead of adapting it to a Windows environment. But Cygwin is not an option for me).

I know I can use Windows PowerShell reading material online. But I don't want to spend hours online learning from basics for this one time requirement. Please don't bash me for being lazy. I am sure this helps others as well by being a quick guide for someone searching online in the future.

Here is the script:

#!/bin/bash
echo ""
cat $1 | grep -A4 "Device_name"; echo ""
cat $1 | grep -A45 "Device_Oops"; echo ""
cat $1 | grep -A150 "Processes:" | sed '/Radar/q'; echo ""
cat $1 | grep -E '[0-9][0-9]:[0-9][0-9]:[0-9][0-9]' | grep -i -E 'error|restart' 

To answer questions on what I tried, I have trouble running the "find" command which is the equivalent of grep per this website http://tldp.org/LDP/abs/html/dosbatch.html

Here is my Joy.txt file (next two lines):

Device_name router@home
testing only

Then at the PowerShell prompt I ran the following command:

cat Joy.txt | find "Device_name"

I was expecting to see the first line in the above file. But instead I get the parameter format not correct error. Can someone help please?

Dale
  • 1,903
  • 1
  • 16
  • 24
Kalyan
  • 257
  • 2
  • 5
  • 13
  • 1
    Have you tried anything? With what results? – user93353 Oct 17 '13 at 05:01
  • Windows batch files and Powershell are not the same. Batch files have existed for 20+ years, I think and learning it enough to do the above will take probably an hour or two – user93353 Oct 17 '13 at 05:02
  • You shouldn't post here because you want to educate others. Show us what you have done so far and we will help you. – ravikanth Oct 17 '13 at 05:03

2 Answers2

5

A more or less direct equivalent of grep -A does not exist in findstr (or find), Windows' native grep equivalent. However, Select-String in PowerShell has this with the -Context parameter.

If I understand your script correctly, it means:

  • Write an empty line
  • Write all lines containing "Device_name", followed by four lines of context, followed by an empty line
  • Write all lines containing "Device_Oops", followed by 45 lines of context, followed by an empty line
  • Write all lines containing "Radar" if they either contain "Processes:" too or are within the first 150 lines following a line containing "Processes:"
  • Write all lines containing three pairs of digits, separated by a colon that also contain either "error" or "restart", case-insensitively.

So it more or less comes down to something like:

$f = Get-Content $args[0]
function Emulate-Grep {
    begin { $first = $true }
    process {
      if (!$first) { '--' }
      $_.Line
      $_.Context.PostContext
      $first = false
    }
}

Write-Host
$f | Select-String -CaseSensitive -Context 0,4 'Device_name' | Emulate-Grep; Write-Host
$f | Select-String -CaseSensitive -Context 0,45 'Device_Oops' | Emulate-Grep; Write-Host
[string[]]($f | Select-String -CaseSensitive -Context 0,150 'Processes:' | Emulate-Grep) -split "`n" -cmatch 'Radar'; Write-Host
$f -match '\d{2}(:\d{2}){2}' -match 'error|restart'

(Untested)

Note that this is slightly ugly due to the attempt to emulate grep's output behaviour.

If you just need matching lines and the following, then I'd simply write a small function:

function Get-Matching([array]$InputObject, [string]$Pattern, [int]$Context = 0) {
    $n = $InputObject.Length - 1
    0..$n |
      where { $InputObject[$_] -cmatch $Pattern } |   
      foreach { $InputObject[$_..($_+$Context)] }
}

And then use it in a script that isn't so complex anymore (still trying to recreate some of your output choices, e.g. empty lines):

$f = gc $args[0]
Write-Host
Get-Matching $f Device_name 4; Write-Host
Get-Matching $f Device_Oops 45; Write-Host
Get-Matching $f 'Processes:' 150 | ? { $_ -cmatch 'Radar' }; Write-Host
Get-Matching $f '\d{2}(:\d{2}){2}' | ? { $_ -match 'error|restart' }

You'll also notice that I got rid of Select-String, a cmdlet I never really understood the purpose of (except providing a close match of grep/findstr, but usually I find other means more flexible).

Joey
  • 344,408
  • 85
  • 689
  • 683
  • Appreciate your input. But that's such a complicated script to achieve such simple task of printing a matching line. Can a Windows script be simple like the above bash script? All I need to do is print a matching line (and its following lines) from an input file. Thank you in advance. – Kalyan Oct 21 '13 at 06:18
  • Of course it can. I just more or less assumed that you wanted identical behaviour. I updated the answer. – Joey Oct 21 '13 at 07:01
1

Regarding Joy.txt, this is an easy one:

cat .\Joy.txt | Select-String "Device_Name"

enter image description here

KERR
  • 1,312
  • 18
  • 13