Home > Back-end >  Terminate command after keyword in output in Linux
Terminate command after keyword in output in Linux

Time:05-09

I want to send a SIGKILL if a certain keyword is shown in the output of the command. Eg, if issue the following command:

ubuntu@ip-172-31-24-250:~$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=109 time=0.687 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=109 time=0.704 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=109 time=0.711 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=109 time=0.809 ms
64 bytes from 8.8.8.8: icmp_seq=5 ttl=109 time=0.727 ms
64 bytes from 8.8.8.8: icmp_seq=6 ttl=109 time=0.835 ms
^C

After seeing the output "icmp_seq=6" I'd like the command to automatically halt. I know that ping 8.8.8.8 -c 6 will have the same results, but it's just for the example.

CodePudding user response:

One way you can do it is redirect the command output to a file, then set up a loop to grep the file for the particular string you want. If the grep succeeds, then end the loop and kill the process. Such a script for ping might look like this:

THIS HAS A BUG IN IT

ping www.google.com > output 2> error &

while [ true ]; do
    grep "icmp_seq=6" output
    
    if [ $? -eq 0 ]; then
        break
    fi
done

echo "sequence found, killing program"

pid=`pgrep ping` # get the PID of ping so we can kill it
kill -9 ${pid}

Update: It just occurred to me that this script has a downfall in that it will run infinitely if the search text never appears (and it will actually continue to run infinitely even after the candidate program terminates, or the program dies immediately on startup). Thus, here's an improved script that accounts for all of that:

ping www.google.com > output 2> error & # the & makes the command a background process so execution of other commands isn't blocked

pid=`pgrep ping`

while [ ! -z ${pid} ]; do # check if pid contains anything - if so, the ping command is still running
    grep "icmp_seq=6" output
    
    if [ $? -eq 0 ]; then
        echo "sequence found, killing program"
        kill -9 ${pid}
        exit 0
    fi

    pid=`pgrep ping`
done

echo "Sequence not found"

Optimization update: Because I'm OCD about this stuff, this script can get bogged down if there's a lot of output because grep has to sift through all of it. Thus, my optimization suggestion would be to use tail -1 output and then pipe the output to grep, resulting in this script:

ping www.google.com > output 2> error & # the & makes the command a background process so execution of other commands isn't blocked

pid=`pgrep ping`

while [ ! -z ${pid} ]; do # check if pid contains anything - if so, the ping command is still running
    tail -1 output | grep "icmp_seq=6"
    
    if [ $? -eq 0 ]; then
        echo "sequence found, killing program"
        kill -9 ${pid}
        exit 0
    fi

    pid=`pgrep ping`
done

echo "Sequence not found"

CodePudding user response:

Would you please try the following:

#!/bin/bash

ping 8.8.8.8 | while IFS= read -r line; do
    echo "$line"
    [[ $line =~ icmp_seq=6 ]] && kill -9 $(pidof ping)
done
  • Related