Windows在subprocess.call()函数中找不到文件。
在Windows系统上,使用subprocess模块时,如果不传递shell=True参数,它不会在PATH环境变量中查找可执行文件。这是因为subprocess模块在后台使用CreateProcess()函数。然而,如果你从程序外部传递参数,使用shell=True参数可能存在安全风险。为了让subprocess模块能够找到正确的可执行文件,可以使用shutil.which函数。假设你的PATH环境变量中存在一个名为frob的可执行文件,你可以这样使用subprocess.call函数调用它:
subprocess.call([shutil.which('frob'), arg1, arg2])
(这个方法适用于Python 3.3及以上版本)
有没有适用于Python 2的方法呢?可以尝试使用from distutils.spawn import find_executable as which
。这行代码是从pre-commit的钩子脚本中复制过来的。
然而,上述说法是不正确的。即使不使用shell=True参数,系统仍会检查PATH环境变量。但是,shell内置命令(如cd和dir)不在PATH中,因为它们根本不是可执行文件。这就是内置于shell中的含义;这些命令由shell自身理解和执行,不存在作为单独的二进制文件。
在Windows系统中,如果想要调用命令行操作,需要通过cmd.exe来实现。因为Windows的命令是在cmd.exe中实现的,而不是作为单独的可执行文件存在。
举个例子,如果想要在Python中调用dir命令,可以使用以下代码:
subprocess.call(['cmd', '/c', 'dir'])
其中,/c参数告诉cmd.exe要运行后面的命令。
这种方式相对于使用shell=True更安全,因为shell=True允许进行shell注入攻击。
如果想要保持命令行窗口打开,可以尝试使用/k参数而不是/c。在命令行中输入cmd /?
可以查看更多详情。
当在Windows 10上使用powershell时,如果遇到WinError 5权限被拒绝的错误,以上的方法也可以帮助解决。
上述的方法其实是间接实现了shell=True的效果,但更加安全可靠。
Windows在使用subprocess.call()函数时无法找到文件的原因是由于Windows系统下的命令是内置的命令,而不是一个可执行文件。因此,需要在调用中添加shell=True
参数。例如,对于dir
命令,可以这样写:
import subprocess subprocess.call('dir', shell=True)
根据官方文档(链接)的解释:
只有在需要执行的命令是shell内置命令(例如dir或copy)时,才需要在Windows上指定
shell=True
。如果要运行批处理文件或基于控制台的可执行文件,则不需要使用shell=True
。
这是因为在Windows系统中没有名为dir.exe
的可执行文件,而*nix系统中有一个/bin/ls
。在Windows中,dir
是由CMD.EXE实现的,类似于bash实现了cd
。
然而,这种做法是不被推荐的。根据官方文档(链接)的建议,只有在“命令字符串是由外部输入构造的”情况下才应使用shell=True
参数。对于外部输入,更安全的替代方法是从os.environ
中获取PATH
并手动搜索。