从Tkinter Entry获取cmd时subprocess执行失败问题
问题描述
直接使用列表形式的cmd调用subprocess.run可正常执行:
process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
对应的cmd定义为:
cmd = ['/usr/bin/mkvmerge', '-o', 'temp', '--audio-tracks', '4', '/home/test/Wingwommen (2023)/Wingwomen (2023).mkv', '--default-track', '4:1']
但将该cmd显示在Tkinter的Entry组件后,通过get()方法获取内容并传入subprocess.run时,触发FileNotFoundError,错误日志如下:
Exception in Tkinter callback Traceback (most recent call last): File "/usr/lib/python3.10/tkinter/__init__.py", line 1921, in __call__ return self.func(*args) File "/home/pi/scripts/tkinter/AUDIO/REMOVE_AUDIO.py", line 258, in rem_audio process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) File "/usr/lib/python3.10/subprocess.py", line 503, in run with Popen(*popenargs, **kwargs) as process: File "/usr/lib/python3.10/subprocess.py", line 971, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "/usr/lib/python3.10/subprocess.py", line 1863, in _execute_child raise child_exception_type(errno_num, err_msg, err_filename) FileNotFoundError: [Errno 2] No such file or directory: "['/usr/bin/mkvmerge', '-o', 'temp', '--audio-tracks', '4', '/home/pi/Torrents/test/Wingwommen (2023)/Wingwomen (2023).mkv', '--default-track', '4:1']"
原因分析
- 直接使用的
cmd是Python列表类型,subprocess.run会自动将列表中的每个元素拆分为命令的可执行文件路径和对应参数,正确识别每个部分。 - 从Entry组件
get()方法获取的内容是字符串类型,而非列表。此时subprocess.run会把整个字符串当作一个完整的可执行文件路径去查找,而这个字符串本身并不是合法的文件路径,因此抛出"找不到文件"的错误。
解决方案
方案1:解析列表格式的字符串
如果Entry中显示的是包含Python列表语法的字符串,使用ast.literal_eval()安全解析为列表:
import ast import subprocess from tkinter import Entry # 假设entry是你的Entry组件实例 cmd_str = entry.get() cmd = ast.literal_eval(cmd_str) process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
方案2:用标准命令格式拆分字符串
更稳妥的方式是将命令以空格分隔、带引号包裹含空格路径的格式显示在Entry中,再用shlex.split()正确拆分参数:
import shlex import subprocess from tkinter import Entry # Entry中显示的命令示例: # "/usr/bin/mkvmerge" -o temp --audio-tracks 4 "/home/test/Wingwommen (2023)/Wingwomen (2023).mkv" --default-track 4:1 cmd_str = entry.get() cmd = shlex.split(cmd_str) process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
方案3:避免字符串解析(最优)
不要将列表转为字符串显示在Entry中,而是直接保留原始的列表对象,在需要执行时直接传入subprocess.run,完全避免字符串解析的问题。
内容的提问来源于stack exchange,提问作者bob_the_bob
相关产品推荐
相关产品推荐

