Почему мои операторы оболочки вызывают блокировку? bash -c "ps ax | grep 'tcpdump' | grep -v grep | kill -9 $(awk '{print $1}')"

Я переписываю функцию для альтернативы os.system() в Python, чтобы гарантировать, что вывод процесса регистрируется.

    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

Исходное утверждение работает хорошо, и это:

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

После того, как я использую log_system(), сценарий оболочки может быть:

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

Но когда я выполняю код, он блокируется, я не знаю, что произошло.

Я использую терминал для повторной попытки, этот скрипт не блокирует:

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

и это тоже блокирует:

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}'`"

🤔 А знаете ли вы, что...
Python поддерживает параллельное и асинхронное программирование с помощью модулей asyncio и multiprocessing.


69
1

Ответ:

Решено

Команда kill не принимает идентификаторы процессов на стандартный ввод, их необходимо указывать в качестве аргумента.

В частности, ваш текущий фрагмент команды (независимо от того, что входит в стандартный ввод kill) будет зависать навсегда, потому что awk ожидает своего стандартного ввода (терминала), по сути:

kill `awk '{print $1}'`

Следовательно, команда должна быть примерно такой:

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

с $() захватом стандартного вывода своего содержимого и использованием его в качестве аргумента командной строки для kill.


Тем не менее, вы также можете посмотреть один из моих предыдущих ответов. Есть лучшие инструменты для поиска и/или уничтожения процессов, такие как pgrep и pkill. Если они у вас есть, они, как правило, лучше, чем попытки сделать это с помощью ps/grep/awk пайплайнов.