遇到一个坑
从 window 环境的 Popen 复制粘贴到 Linux 使用,竟然无法使用,报错 No such file or directory
,把我搞郁闷了,完全一样的 code,怎么 linux 上就找不到文件了?
原来,linux 上 Popen 使用字符串命令,Popen 需要加上一个参数 shell=True
。
报错
Traceback (most recent call last):
File "case.py", line 138, in <module>
__tl.do_test()
File "case.py", line 119, in do_test
tp.start()
File "case.py", line 65, in start
self.__proc = Popen(self.__cmd)
File "/usr/lib/python3.8/subprocess.py", line 854, in __init__
self._execute_child(args, executable, preexec_fn, close_fds,
File "/usr/lib/python3.8/subprocess.py", line 1702, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'python do_test.py 3'
官方文档
args is required for all calls and should be a string, or a sequence of program arguments. Providing a sequence of arguments is generally preferred, as it allows the module to take care of any required escaping and quoting of arguments (e.g. to permit spaces in file names). If passing a single string, either shell must be True (see below) or else the string must simply name the program to be executed without specifying any arguments.
If shell is True, the specified command will be executed through the shell. This can be useful if you are using Python primarily for the enhanced control flow it offers over most system shells and still want convenient access to other shell features such as shell pipes, filename wildcards, environment variable expansion, and expansion of ~ to a user’s home directory. However, note that Python itself offers implementations of many shell-like features (in particular, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), and shutil).
第二个大坑
如上面官方文档所述,如果 shell=True
,那么会通过 shell 来启动进程。这意味着,一次 Popen 会启动两个进程,一个 shell 进程,一个命令进程。然后 Popen 返回的 pid 是 shell 进程的 pid,这会导致 Popen.kill()
等函数不起作用,进程还在正常运行,所以一定要使用参数列表的形式启动,不要通过命令行的形式,不要使用 shell=True
。
第三个坑
上面虽然解决了 kill()
不掉真实进程的问题,但是还有一坑。如何把一个命令行字符串转换成 list[str]
,使用 str.split()
?这是不行的,如果命令行里有引号之类的就会有问题。自己实现一个函数?可以,不过自己写的总是怕考虑不全的地方。好在 python 官方有词法分析器的库 shlex
,只需要 shlex.split()
就可以获得我们想要的格式了,Python Library - shlex 。