python - 使用子进程获取 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
解决方案
我发现了这种奇怪行为的原因。我的错误:我忘记了我调用了一些目录,其名称包括我正在运行的字符串 grep -i以防止在使用其完整路径从其目录外部运行脚本时引发双重结果。原来脚本使用子进程运行得很好。
所以最后,我重命名了我想用 disp_ 而不是 lcd_ 终止的脚本,并将 shell=False 添加到我的子进程中,以确保在运行脚本时不会有意外地将输出发送到 bash 的风险。