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?
-
what exactly is the problem you are having?suspectus– suspectus2013年12月23日 17:27:03 +00:00Commented Dec 23, 2013 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.Vince– Vince2013年12月23日 17:31:07 +00:00Commented Dec 23, 2013 at 17:31
-
The output is empty with the bash script!C Ts– C Ts2013年12月23日 17:31:15 +00:00Commented Dec 23, 2013 at 17:31
-
1mywiki.wooledge.org/BashGuide/Patterns @Ghodmode.Mat– Mat2013年12月23日 17:47:00 +00:00Commented Dec 23, 2013 at 17:47
-
1Yes, 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– C Ts2013年12月23日 19:40:03 +00:00Commented Dec 23, 2013 at 19:40
2 Answers 2
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.*'
the
test
command (otherwise known as[[
) operates on the number of arguments it receives. It is therefore very sensitive to whitespace:if [[ $exception = false ]]
there's a major logic error: you unset the
block
variable inside the[[ -z $block ]]
block: onceblock
is non-zero it can never be unset.Why are you rewriting a working script?
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
-
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– C Ts2014年01月02日 16:18:54 +00:00Commented Jan 2, 2014 at 16:18
-
@CTs
[[ ${block[*]} = *Exception* ]]
checks the whole block body.block
is an array, every array item is a line.mirabilos– mirabilos2014年01月02日 19:47:27 +00:00Commented Jan 2, 2014 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– C Ts2014年01月03日 09:55:37 +00:00Commented Jan 3, 2014 at 9:55
-
(*)
belongs tocase
and is, basically, the equivalent of thedefault
statement in Cswitch
. Andx+=(y)
appends to the array x, whilex=(y)
sets the array x empty before appending y.mirabilos– mirabilos2014年01月03日 11:22:17 +00:00Commented Jan 3, 2014 at 11:22