如何在Python中逃避os.system()调用?

当使用os.system()时,通常需要将文件名和其他参数作为parameter passing给命令。 我该怎么做? 最好能在多个操作系统/ shell上工作,但特别是在bash上。

我目前正在做下面的事情,但肯定必须有一个库函数,或至less一个更优雅/健壮/高效的选项:

def sh_escape(s): return s.replace("(","\\(").replace(")","\\)").replace(" ","\\ ") os.system("cat %s | grep something | sort > %s" % (sh_escape(in_filename), sh_escape(out_filename))) 

编辑:我已经接受了使用引号的简单答案,不知道为什么我没有想到这一点; 我猜是因为我来自Windows,而且行为有点不同。

关于安全性,我理解这个问题,但是在这种情况下,我对os.system()提供的一个快速而简单的解决scheme感兴趣,而string的来源不是用户生成的,或者至less是由信任的用户(我)。

这是我使用的:

 def shellquote(s): return "'" + s.replace("'", "'\\''") + "'" 

shell将始终接受引用的文件名,并在将其传递给相关程序之前删除周围的引号。 值得注意的是,这避免了包含空格或任何其他types的恶意shell元字符的文件名的问题。

更新 :如果您使用的是Python 3.3或更高版本,请使用shlex.quote而不是自己的。

shlex.quote()做你想从python 3以来。

(使用pipes.quote来支持python 2和python 3)

也许你有使用os.system()的具体原因。 但是,如果没有,你应该使用subprocess模块 。 您可以直接指定pipe道,避免使用shell。

以下是来自PEP324 :

 Replacing shell pipe line ------------------------- output=`dmesg | grep hda` ==> p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) output = p2.communicate()[0] 

也许subprocess.list2cmdline是一个更好的镜头?

请注意,pipes.quote实际上在Python 2.5和Python 3.1中被破坏,并且不安全 – 它不处理零长度的参数。

 >>> from pipes import quote >>> args = ['arg1', '', 'arg3'] >>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args)) mycommand arg1 arg3 

请参阅Python问题7476 ; 它已经在Python 2.6和3.2以及更新版本中得到了修复。

我相信os.system只是调用为用户configuration的任何命令shell,所以我不认为你可以以独立于平台的方式来完成。 我的命令行可以是bash,emacs,ruby,甚至是quake3。 其中一些程序并不期望你传递给他们的那种论点,即使他们做了也不能保证他们以同样的方式逃避。

注意 :这是Python 2.7.x的答案。

根据来源 , pipes.quote()是“ 可靠地引用string作为/ bin / sh的单个参数 ”的一种方法。 (尽pipe从2.7版开始已经被弃用了,并且最终在Python 3.3中作为shelx.quote()函数公开了。)

另一方面 , subprocess.list2cmdline()是一种“ 将一系列参数转换为命令行string,使用与MS C运行时相同的规则 ”的方法。

在这里,我们是引用命令行string的平台独立方式。

 import sys mswindows = (sys.platform == "win32") if mswindows: from subprocess import list2cmdline quote_args = list2cmdline else: # POSIX from pipes import quote def quote_args(seq): return ' '.join(quote(arg) for arg in seq) 

用法:

 # Quote a single argument print quote_args(['my argument']) # Quote multiple arguments my_args = ['This', 'is', 'my arguments'] print quote_args(my_args) 

我使用的function是:

 def quote_argument(argument): return '"%s"' % ( argument .replace('\\', '\\\\') .replace('"', '\\"') .replace('$', '\\$') .replace('`', '\\`') ) 

那就是:我总是用双引号将参数括起来,然后用双引号将特殊字符中的唯一字符进行反斜杠引用。

真正的答案是:首先不要使用os.system() 。 使用subprocess.call来代替并提供未转义的参数。

如果您使用系统命令,我会尝试将os.system()调用的内容列入白名单。例如..

 clean_user_input re.sub("[^a-zA-Z]", "", user_input) os.system("ls %s" % (clean_user_input)) 

subprocess模块是一个更好的select,我会build议尽可能避免使用任何类似os.system / subprocess。