问题:如何逃避os.system()调用?
使用os.system()时,通常必须转义文件名和其他作为参数传递给命令的参数。我怎样才能做到这一点?最好是可以在多个操作系统/ shell上运行的东西,尤其是bash。
我目前正在执行以下操作,但是请确保为此必须有一个库函数,或者至少是一个更优雅/更强大/更有效的选项:
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()提供的一种快速简便的解决方案感兴趣,并且字符串的来源不是用户生成的,或者至少是由受信任的用户(我)。
回答 0
这是我用的:
def shellquote(s):
return "'" + s.replace("'", "'\\''") + "'"
外壳程序将始终接受带引号的文件名,并在将其传递给相关程序之前删除引号。值得注意的是,这避免了文件名包含空格或其他任何讨厌的shell元字符的问题。
更新:如果您使用的是Python 3.3或更高版本,请使用shlex.quote而不是自己滚动。
回答 1
shlex.quote()
从python 3开始做你想要的事情。
(用于pipes.quote
同时支持python 2和python 3)
回答 2
也许您有使用的特定原因os.system()
。但是,如果不是这样,您可能应该使用该subprocess
模块。您可以直接指定管道,并避免使用外壳。
以下是来自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]
回答 3
也许subprocess.list2cmdline
是更好的选择?
回答 4
请注意,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及更高版本中修复。
回答 5
注意:这是Python 2.7.x的答案。
根据消息来源,这pipes.quote()
是“ 可靠地将字符串作为/ bin / sh的单个参数引用 ”的一种方法。(尽管从2.7版开始不推荐使用,但最终在Python 3.3中公开公开为shlex.quote()
函数。)
上另一方面,subprocess.list2cmdline()
是一种方法,“ 翻译的参数的序列到命令行串,使用同样的规则作为MS C运行时 ”。
在这里,我们为平台提供了引用命令行字符串的方式。
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)
回答 6
我相信os.system只会调用为用户配置的任何命令外壳,因此我认为您不能以与平台无关的方式进行操作。我的命令外壳可以是bash,emacs,ruby甚至quake3中的任何东西。这些程序中的某些程序并不期望您传递给它们的参数的种类,即使它们这样做了,也无法保证它们以相同的方式进行转义。
回答 7
我使用的功能是:
def quote_argument(argument):
return '"%s"' % (
argument
.replace('\\', '\\\\')
.replace('"', '\\"')
.replace('$', '\\$')
.replace('`', '\\`')
)
即:我总是将参数用双引号引起来,然后用反斜杠将双引号内的特殊字符引起来。
回答 8
如果您确实使用了system命令,我将尝试将os.system()调用中的内容列入白名单。
clean_user_input re.sub("[^a-zA-Z]", "", user_input)
os.system("ls %s" % (clean_user_input))
子进程模块是一个更好的选择,我建议尽量避免使用os.system / subprocess之类的东西。
回答 9
真正的答案是:首先不要使用os.system()
。请subprocess.call
改用并提供未转义的参数。