0

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}'`"
Zheng Li
  • 30
  • 4

1 Answers1

2

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.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Thanks! I try this code below and it works well. ```shell bash -c "kill $(ps ax | grep '[t]cpdump' |awk '{print $1}')" ``` However, I still want to know what is the difference between the following two snippets: ```shell ps ax | grep '[t]cpdump' | kill `awk '{print $1}'` # which is non-blocking bash -c "ps ax | grep '[t]cpdump' | kill `awk '{print $1}'`" # which is blocking – Zheng Li Feb 13 '23 at 06:21
  • This is shell-dependent. If you run `cmd1 | cmd2 $(cmd3)` in either bash or dash, both `cmd2` and `cmd3` read from the pipe. But in zsh, only `cmd2` reads from the pipe (`cmd3` is essentially outside of the pipeline, and reads fom the terminal or whatever). However, the replacement suggested here should work in any sh-family shell. – Gordon Davisson Feb 13 '23 at 06:23