如何在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。