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? Commented Oct 17, 2013 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 Commented Oct 17, 2013 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. Commented Oct 17, 2013 at 5:03

2 Answers 2

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).

Sign up to request clarification or add additional context in comments.

2 Comments

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.
Of course it can. I just more or less assumed that you wanted identical behaviour. I updated the answer.
1

Regarding Joy.txt, this is an easy one:

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

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.