psyched
psyched

Reputation: 1939

Linux shell kill command while still running based on output

I have a set of C++ projects in Code::Blocks and a script that builds all of them. The script looks as following:

codeblocks --build --target="release32" project1.cbp
codeblocks --build --target="release32" project2.cbp
codeblocks --build --target="release32" project3.cbp
...

Sometimes when building one of the projects, Code::Blocks fails to finish the process with an error: *** glibc detected *** codeblocks: corrupted double-linked list. This has nothing to do with the build being failed, this is just a bug in codeblocks, see here: https://bugs.launchpad.net/ubuntu/+source/codeblocks/+bug/764728 or here: http://forums.codeblocks.org/index.php?topic=16883.0

A workaround that I want to do is to parse the output of the command while it's still running, find the string "codeblocks: corrupted double-linked list", and kill the codeblocks to let the script build other projects and finish.

How can I do that?

Upvotes: 2

Views: 468

Answers (1)

Adrian Frühwirth
Adrian Frühwirth

Reputation: 45526

A little hacky but will this work for you (bash)?

This is just to simulate the codeblocks binary (./codeblocks):

$ cat codeblocks
#!/bin/bash

num=$RANDOM
((num %= 2))

case "$num" in
        0)
                echo "codeblocks finished successfully: $*"
                exit 0
                ;;
        1)
                echo "*** glibc detected *** codeblocks: corrupted double-linked list" 1>&2
                while true; do
                        sleep 1
                done
                ;;
esac

This is the actual test script (test.sh):

$ cat test.sh
#!/bin/bash

run_codeblocks()
{
        until (
                subshell_pid=$BASHPID
                echo "trying to run 'codeblocks $*'"
                ./codeblocks "$@" 2>&1 | while read line; do
                        echo "[${line}]"
                        [[ ${line} == *"*** glibc detected ***"* ]] && kill $subshell_pid
                done
                return 0
        ); do
                :
        done
}

echo "running codeblocks ..."
run_codeblocks 1
run_codeblocks 2
run_codeblocks 3
echo "... done"

You wrap the call to codeblocks in a subshell, grep its output and if a line matches the error you stated kills the subshell. Basically exactly what you described.

$ ./test.sh
running codeblocks ...
trying to run 'codeblocks 1'
[codeblocks finished successfully: 1]
trying to run 'codeblocks 2'
[*** glibc detected *** codeblocks: corrupted double-linked list]
./test.sh: line 4: 29889 Terminated              ( subshell_pid=$BASHPID; echo "trying to run 'codeblocks $*'"; ./codeblocks "$@" 2>&1 | while read line; do
    echo "[${line}]"; [[ ${line} == *"*** glibc detected ***"* ]] && kill $subshell_pid; return 0;
done )
trying to run 'codeblocks 2'
[*** glibc detected *** codeblocks: corrupted double-linked list]
./test.sh: line 4: 29892 Terminated              ( subshell_pid=$BASHPID; echo "trying to run 'codeblocks $*'"; ./codeblocks "$@" 2>&1 | while read line; do
    echo "[${line}]"; [[ ${line} == *"*** glibc detected ***"* ]] && kill $subshell_pid; return 0;
done )
trying to run 'codeblocks 2'
[codeblocks finished successfully: 2]
trying to run 'codeblocks 3'
[*** glibc detected *** codeblocks: corrupted double-linked list]
./test.sh: line 4: 29903 Terminated              ( subshell_pid=$BASHPID; echo "trying to run 'codeblocks $*'"; ./codeblocks "$@" 2>&1 | while read line; do
    echo "[${line}]"; [[ ${line} == *"*** glibc detected ***"* ]] && kill $subshell_pid; return 0;
done )
trying to run 'codeblocks 3'
[codeblocks finished successfully: 3]
... done

Upvotes: 2

Related Questions