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?

3
  • 1
    Have you tried anything? With what results? – user93353 Oct 17 '13 at 5: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 5: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 5:03
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).

2
  • 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 6: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 7:01
1

Regarding Joy.txt, this is an easy one:

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

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.