Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Loop results of grep and perform action 1

Status
Not open for further replies.

paulobrads

Programmer
Jul 13, 2006
28
GB
I'm running tcpdump and piping the output into a shell script, I want to grep for a string within the packet and perform an action if I find a match.

How can I do stuff (write to file and execute a command) when a match is found?

So far I have:

#!/bin/bash
read -p 'Input:' in_stuff
grep 'ttl 64'

Cheers
 
Thanks, that? great.

My shell script now looks like this:

#!/bin/bash
grep 'ttl 64' -q && sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4 "" 6 23 ""
grep 'ttl 128' -q && sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8 "" 6 23 ""


You can see I fire a different SNMP trap depending on contents of the packet seen. However, this makes tcpdump quit after one of each of my grep commands has been found. Is there and easy way to keep this taking more input and processing it for the life of tcpdump running?

Thanks
 
Hi

Got it. Then it would be better this way :
Code:
#!/bin/bash
tcpdump | while read str; do
  echo "$str" | grep 'ttl 64' -q && sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4 "" 6 23 ""
  echo "$str" | grep 'ttl 128' -q && sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8 "" 6 23 ""
done

Feherke.
 
Since tcpdump can produce a hell of a lot of data, depending on how busy your network is, consider using some of its filter expressions to limit the amount of data processed. Also I'd recommend using something like this to avoid spawning grep processes to handle each line of input data:

Code:
#!/bin/bash
tcpdump | awk '
    /ttl 64/  { system("sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4 \"\" 6 23 \"\"") }
    /ttl 128/ { system("sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8 \"\" 6 23 \"\"") }
'

Annihilannic.
 
Thanks for your help. In particular feherke, that looks good but what I think I really need is a switch statement.

When the script receives input from tcpdump I need it to fire off a particular SNMP packet, with the solution above the SNMP packets seen to alternate between one for ttl64 and ttl128 as if it hangs after the ttl64 line waiting for a ttl128 before looping again - ignoring any further ttl64s.

I hope this makes sense, bit of a shell script newbie so thanks for the help.
 
That's the way it may appear, but the way awk works is that it tests all expressions in the script against every single line of input, so you can even have multiple conditions that will be true, and therefore multiple code sections that execute for that line of input. Have you tried it?

For example:
[tt]$ cat paulobrads
#!/bin/bash
echo 'ttl 64 test1
ttl 64 test2
ttl 128 test3
ttl 128 test4
ttl 64 test5
ttl 128 test6' | awk '
/ttl 64/ { system("echo sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1
.4.1.2011.0.6.4 \"\" 6 23 \"\"") }
/ttl 128/ { system("echo sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1
.4.1.2011.1.2.8 \"\" 6 23 \"\"") }
$ sh paulobrads
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4 6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4 6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8 6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8 6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4 6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8 6 23
$[/tt]

Annihilannic.
 
Cheers Annihilannic,

That looks good, below is my shell script now to send off a trap when the regex is matched. However it seems unreliable - when I send data that I know matches the regex no trap gets sent for about 6 or 7 packets then on the 8th all 8 traps are sent together. Its like the command is being buffered somewhere and not executed. Any ideas? Cheers.


#!/bin/bash
tcpdump -v -i lo | awk '
/E:2011.6.3.3.1.1.6.0=3/ { system("sudo snmptrap -v 1 -c private 10.215.189.91 1.3.6.1.4.1.594.9.9.9 \"\" 6 23 \"\"") }
'
 
Unfortunately a number of commands start buffering output when they are put into a pipeline. Well, not always unfortunate... it does improve performance, but if you want real-time fedback as in this scenario, it's not desirable.

The only workaround I found was to rewrite my filter in perl and use select(STDOUT); $| = 1; to make the output unbuffered (mentioned in the open section of the man perlfunc page). Don't ask me why making STDOUT unbuffered makes a difference... I'd expect to have to make a change to STDIN, but... it seems to.

Annihilannic.
 
Cheers for the advice Annihilannic, can you point me in the direction of an easy way of putting such a shell script into perl? Can you just inject system calls like tcpdump and pipes through that?

Cheers.
 
perl behaves very much like awk when using the -n option (see the perlrun man page), so only a few slight syntactic changes are required:

Code:
#!/bin/bash
echo 'ttl 64 test1
ttl 64 test2
ttl 128 test3
ttl 128 test4
ttl 64 test5
ttl 128 test6' | perl -nwe '
        /ttl 64/ && system("echo sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4 \"\" 6 23 \"\"");
        /ttl 128/ && system("echo sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8 \"\" 6 23 \"\"");
'
$ sh paulobrads.perl
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4  6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4  6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8  6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8  6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.0.6.4  6 23
sudo snmptrap -v 1 -c private 127.0.0.1 1.3.6.1.4.1.2011.1.2.8  6 23
$

Annihilannic.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top