在subprocess.Popen()中挣扎 - 为什么First和Third按预期工作,而第二个没有找到任何多个文件或目录?错误信息是:
>ls: Zugriff auf * nicht möglich: Datei oder Verzeichnis nicht gefunden
英文翻译:
File not found or directory: access to * not possible
这是代码。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import subprocess
args = []
args.append ('ls')
args.append ('-al')
# First does work
cmd1 = subprocess.Popen(args)
cmd1.wait()
# Second does NOT work
args.append ('*')
cmd2 = subprocess.Popen(args)
cmd2.wait()
# Third does work
shellcmd = "ls -al *"
cmd3 = subprocess.Popen(shellcmd, shell=True )
cmd3.wait()
答案 0 :(得分:1)
这是因为默认情况下subprocess.Popen()
没有shell解释命令,因此"*"
不会扩展到所需的文件列表中。尝试添加shell=True
作为呼叫的最终参数。
另请注意the warning in the documentation关于不信任以这种方式处理的用户输入。
答案 1 :(得分:1)
这是因为shell globbing而发生的。
基本上,*
中的ls -al *
会被您的shell扩展,以匹配所有可用文件。
当您运行没有shell=True
标志的子进程时,python无法自己解析*
,因此会显示错误消息ls: cannot access *: No such file or directory
。
当您使用shell=True
运行命令时,python实际上将控件传递给shell,因此显示正确的输出。
顺便说一句,执行包含来自不受信任来源的未经过处理的输入的shell命令会使程序容易受到shell注入攻击,这是一个严重的安全漏洞,可能导致任意命令执行,因此应谨慎使用({{3} })。
编辑1
shell globbing和Popen
消耗args
的方式导致此问题
class subprocess.Popen
args
应该是一系列程序参数,或者是一个字符串。如果
shell is
True, it is recommended to pass
argsas a
字符串`而不是序列。
要理解shell globbing以及Popen
消耗args
的方式是问题,请比较以下输出。请注意,在2个案例中,当shell=True
时,由于传递的输入是ls
而不是list
,因此只执行string
subprocess.Popen(['ls']) #works
subprocess.Popen('ls') #works
subprocess.Popen(['ls', '-al']) #works
subprocess.Popen(['ls -al']) #doesn't work raises OSError since not a single command
subprocess.Popen('ls -al') #doesn't work raises OSError since not a single command
subprocess.Popen(['ls -al'], shell=True) #works since in shell mode
subprocess.Popen('ls -al', shell=True) #works since in shell mode & string is single command
subprocess.Popen(['ls', '-al'], shell=True) #output corresponds to ls only, list passed instead of string, against recommendation
subprocess.Popen(['ls', '-al', '*']) #doesn't work because of shell globbing for *
subprocess.Popen(['ls -al *']) #doesn't work raises OSError since not a single commandfor *
subprocess.Popen('ls -al *') #doesn't work raises OSError since not a single commandvalid arg
subprocess.Popen(['ls', '-al', '*'], shell=True) #output corresponds to ls only, list passed instead of string, against recommendation
subprocess.Popen(['ls -al *'], shell=True) #works
subprocess.Popen('ls -al *', shell=True) #works
答案 2 :(得分:0)