Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

The following script it's about monitoring some logs, the $timestamp is at log at every line that something happens.

Example:
03:19:13.4 Begin summary update for ads.doc.inventory.InventoryItemSummary
03:19:33.9 CronServer:: DailyJob ads.tools.UpdateSummaries@17c5d6cf failed with exception ads.util.AppError: Cannot create UnitName from keys: Each
ads.util.AppError: Cannot create UnitName from keys: Each
at ads.db.DBObjectDefault.createFromKeys(DBObjectDefault.java:42)
at ads.db.DBTable.createFromKeys(DBTable.java:227)
at ads.db.DBValue.getValue(DBValue.java:621)
at ads.dbmanager.DBObjectsManager.initObjects(DBObjectsManager.java:400)
at ads.dbmanager.DBObjectsManager.reload(DBObjectsManager.java:447)
at ads.dbmanager.DBObjectsManager.loadFromStore(DBObjectsManager.java:497)
at ads.doc.inventory.InventoryItemSummary.refreshSince(InventoryItemSummary.java:173)
at ads.db.DBSummaryTable.refreshAll(DBSummaryTable.java:67)
at ads.tools.CronServer$DailyThread.run(CronServer.java:271)
[SOAPException: faultCode=SOAP-ENV:Client; msg=Error opening socket: java.net.ConnectException: Connection refused; targetException=java.lang.IllegalArgumentException: Error opening socket: java.net.ConnectException: Connection refused]
at org.apache.soap.transport.http.SOAPHTTPConnection.send(SOAPHTTPConnection.java:354)
at org.apache.soap.rpc.Call.invoke(Call.java:248)
at ads.support.SupportCall.call(SupportCall.java:56)
at ads.tools.SupportThread.run(SupportThread.java:101)
03:46:42.5 Periodic support request failed: ads.support.SupportException: Error opening socket: java.net.ConnectException: Connection refused
06:31:36.1 Upload failed: java.io.FileNotFoundException: c:/tmp/cygwin1.dll (No such file or directory)
08:01:08.0 connect from /172.22.3.28

I have this perl script

#!/usr/bin/perl

use strict;
use warnings FATAL => qw(all);

my $timestamp = qr/^\d+:\d+:\d+/;

my $block = "";
my $exception = 0;
while (<STDIN>) {

if ($block) {
# $_ is the current input line in perl.
    if ($_ =~ $timestamp) {
        print "\n\n***EXCEPTION***\n$block" if $exception;
        $block = "";
        $exception = 0;
    }
# This isn't actually a second regexp, it's a substring search.
# But you could use a regexp.
    $exception = 1 if (index($_,"Exception") >= 0);
    $block .= $_;
    next;
}
$block = $_ if ($_ =~ $timestamp);
}

and I want to convert it to bash script.

Here's what I've done so far but didn't work, #!/bin/bash

timestamp=^[0-9][0-9]\:[0-9][0-9]\:[0-9][0-9]\.[0-9]

block=""

exception=false

except=.*Exception.*

while read line
do

if [[ -z $block ]] ;
   then

    if [[ $line =~ $timestamp ]]
       then

            if [[ $exception=false ]]
               then
                     echo "\n\n***EXCEPTION***\n$block"
            fi
block=""
exception=false
    fi

    if [[ $line =~ $except ]]
       then
            exception=true
    fi

block=$block$line

fi

if [[ $line =~ $timestamp ]]
   then
    block=$line
fi

done

Any help with that?

share|improve this question
    
what exactly is the problem you are having? –  suspectus Dec 23 '13 at 17:27
    
Bash doesn't handle regular expressions natively. What you propose is a lot more complex and involves using external commands. I wouldn't go so far as to say it's impossible, but it's almost certainly a bad idea. –  Ghodmode Dec 23 '13 at 17:31
    
The output is empty with the bash script! –  C Ts Dec 23 '13 at 17:31
1  
mywiki.wooledge.org/BashGuide/Patterns @Ghodmode. –  Mat Dec 23 '13 at 17:47
1  
Yes, exactly this. As input is a log file and I want to print all the block (timestamp to timestamp) if inside the block there is the word exception. –  C Ts Dec 23 '13 at 19:40

2 Answers 2

  1. you have to quote filename pattern metacharacters like * and [

    timestamp='^[0-9][0-9]:[0-9][0-9]:[0-9][0-9]\.[0-9]'
    except='.*Exception.*'
    
  2. the test command (otherwise known as [[) operates on the number of arguments it receives. It is therefore very sensitive to whitespace:

        if [[ $exception = false ]]
    
  3. there's a major logic error: you unset the block variable inside the [[ -z $block ]] block: once block is non-zero it can never be unset.

  4. Why are you rewriting a working script?

share|improve this answer

Edit: the following solution is closer to the original script than what I initially wrote (it checks the whole block body, not just the first line, for the word “Exception”):

block=()
newblock() {
    [[ ${block[*]} = *Exception* ]] && printf '%s\n' '' '' '***EXCEPTION***' "${block[@]}"
    block=("$line")
}
while IFS= read -r line; do
    case $line in
    ([0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9]\ *)
            newblock
            ;;
    (*)
            block+=("$line")
            ;;
    esac
done
newblock
share|improve this answer
    
You're the best, works fine, but I don't understand the block[], (*). Can't understand how it checks the whole block body and how block is defined. –  C Ts Jan 2 at 16:18
    
@CTs [[ ${block[*]} = *Exception* ]] checks the whole block body. block is an array, every array item is a line. –  mirabilos Jan 2 at 19:47
    
Inside the while loop you insert every line at the array (block+=("$line"))? What is (*) at the while loop? At the newblock method, block=("$line") what exactly does? Sorry for all the questions, but I'm new at bash and first time come across with array! –  C Ts Jan 3 at 9:55
    
(*) belongs to case and is, basically, the equivalent of the default statement in C switch. And x+=(y) appends to the array x, while x=(y) sets the array x empty before appending y. –  mirabilos Jan 3 at 11:22

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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