Why do my shell statements cause blocking? bash -c "ps ax | grep 'tcpdump' | grep -v grep | kill -9 $(awk '{print $1}')"

Question:

I am rewriting a function to alternate os.system() in Python to ensure that the output of the process is logged.

    def log_system(self, cmd: str):
        cmd = cmd.rstrip(' ')
        if cmd[-1] == '&' and cmd[-2] != '&':
            cmd = cmd[:-1]
            # Redirects standard error to standard output for logging
            executing = os.popen('bash -c ' + '"' + cmd + '"' + '>/dev/stdout 2>&1 &')
        else:
            executing = os.popen('bash -c ' + '"' + cmd + '"' + '>/dev/stdout 2>&1')
        res = executing.readlines()
        ret = executing.close()
        if len(res) > 0:  # print message if have some content
            msg = ''.join(res)
            if ret is None:  # None means process return successfully
                log.i(msg)  # print stdout
            else:
                log.e(f'cmd execute failed: {cmd}n' + msg)  # print stderr

The original statement works well and it is:

os.system("ps ax | grep 'tcpdump' | grep -v grep | kill `awk '{print $1}'` ")

After I use log_system(), the shell script could be:

bash -c "ps ax | grep 'tcpdump' | grep -v grep | kill `awk '{print $1}'`"

But, When I execute the code, it blocks, I don’t know what happened.

I use terminal to retry, this script is non-blocking:

ps ax | grep 'tcpdump' | grep -v grep | kill `awk '{print $1}'`

and this is also blocking:

bash -c "ps ax | grep 'tcpdump' | grep -v grep | kill -9 $(awk '{print $1}')"
bash -c "ps ax | grep 'tcpdump' | grep -v grep | kill `awk '{print $1}'`"
Asked By: Zheng Li

||

Answers:

The kill command does not take process IDs on standard input, it must be supplied as an argument.

Specifically, your current command snippet (regardless of what goes into the kill standard input) will hang forever because the awk is waiting on its standard input (the terminal), effectively:

kill `awk '{print $1}'`

Hence the command would need to be something like:

kill $(ps ax | grep 'tcpdump' | grep -v grep | awk '{print $1}')

with the $() capturing the standard output of its content and using that as a command line argument to kill.


However, you may also want to look at one of my earlier answers. There are better tools available for finding and/or killing processes, such as pgrep and pkill. If you have those available to you, they’re usually a better option than trying to do it with ps/grep/awk pipelines.

Answered By: paxdiablo
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.