首页 > 解决方案 > 使用子进程获取 PID 并杀死它的 Python 脚本在从其当前目录之外启动时表现得很奇怪

问题描述

提前感谢您抽出时间阅读此问题。我正在学习Python,在问这里之前我查了很多资料,请原谅我的新手问题。

所以我在 python 3 中使用 subprocess 模块创建了这个脚本来搜索另一个 python 脚本的 PID,同时只知道脚本名称的开头并很好地终止它。

基本上,我通过 Raspberry 和 I2C 在 LCD 屏幕上运行 python 时钟,然后终止脚本,清除 LCD 并将其关闭。下面提供了这个“关闭”脚本代码。

问题是当我从它所在的目录运行它时,它带有:

python3 off.py

它完美地工作,解析和终止 PID,然后关闭 LCD 显示器。

理想情况下,我想通过电报 cli 触发它,因为我是在 bash 中完成的,而且效果很好,我发现它是一个不错的功能。在python中它失败了。

所以我进行了测试,似乎当我尝试从另一个目录启动它时:

python3 ~/code/off.py

当从脚本驻留目录启动时,grep 子进程返回的 PID 不止一个正常返回的 PID。例如(使用 python3 -v):

kill: failed to parse argument: '25977
26044'

第二个 PID 号来自脚本创建的子进程,我似乎无法找到它是什么,因为它在脚本结束时终止但未能达到最初的目的。

对于理解这里发生的事情的任何帮助将不胜感激。如下所示,我从两行丑陋的 bash 混合到一个虚拟的四行 python 脚本的调用中走了这么远,所以我真的觉得我正在接近实现我的第一个真正的 python 脚本的正确方法。

我试图在解释器中逐行分解脚本,但无法重现错误,一切都按预期运行。从外部位置运行脚本时,我只得到这个双 PID 结果。

预先感谢您对如何理解正在发生的事情提供任何有用的见解!

#!/usr/bin/env python3

import subprocess
import I2C_LCD_driver
import string

# Defining variables for searched strings and string encoding
searched_process_name = 'lcd_'
cut_grep_out_of_results = 'grep'
result_string_encoding = 'utf-8'
mylcd = I2C_LCD_driver.lcd()
LCD_NOBACKLIGHT = 0x00
run = True

def kill_script():
    # Listing processes and getting the searched process
    ps_process = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE)
    grep_process = subprocess.Popen(["grep", "-i", searched_process_name], stdin=ps_process.stdout, stdout=subprocess.PIPE)
    # The .stdout.close() lines below allow the previous process to receive a SIGPIPE if the next process exits.
    ps_process.stdout.close()
    # Cleaning the result until only the PID number is returned in a string
    grep_cutout = subprocess.Popen(["grep", "-v", cut_grep_out_of_results], stdin=grep_process.stdout, stdout=subprocess.PIPE)
    grep_process.stdout.close()
    awk = subprocess.Popen(["cut", "-c", "10-14"], stdin=grep_cutout.stdout, stdout=subprocess.PIPE)
    grep_cutout.stdout.close()
    output = awk.communicate()[0]
    clean_output = output.decode(result_string_encoding)
    clean_output_no_new_line = clean_output.rstrip()
    clean_output_no_quote = clean_output_no_new_line.replace("'", '')
    PID = clean_output_no_quote
    # Terminating the LCD script process
    subprocess.Popen(["kill", "-9", PID])

while run:
    kill_script()
    # Cleaning and shutting off LCD screen
    mylcd.lcd_clear()
    mylcd.lcd_device.write_cmd(LCD_NOBACKLIGHT)
    break

标签: pythonlinuxpython-3.xsubprocess

解决方案


我发现了这种奇怪行为的原因。我的错误:我忘记了我调用了一些目录,其名称包括我正在运行的字符串 grep -i以防止在使用其完整路径从其目录外部运行脚本时引发双重结果。原来脚本使用子进程运行得很好。

所以最后,我重命名了我想用 disp_ 而不是 lcd_ 终止的脚本,并将 shell=False 添加到我的子进程中,以确保在运行脚本时不会有意外地将输出发送到 bash 的风险。


推荐阅读