使用os.system()时,通常需要将作为参数传递的文件名和其他参数转义为命令。我怎样才能做到这一点?优选地,某些东西可以在多个操作系统/外壳上工作,但特别适用于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 :(得分:141)
shlex.quote()
做了你想要的python 3。
(使用pipes.quote
支持python 2和python 3)
答案 1 :(得分:75)
这就是我使用的:
def shellquote(s):
return "'" + s.replace("'", "'\\''") + "'"
shell将始终接受带引号的文件名,并在将其传递给相关程序之前删除周围的引号。值得注意的是,这避免了包含空格或任何其他令人讨厌的shell元字符的文件名的问题。
更新:如果您使用的是Python 3.3或更高版本,请使用shlex.quote而不是自己滚动。
答案 2 :(得分:54)
也许您有使用os.system()
的具体原因。但如果不是,你应该使用subprocess
module。您可以直接指定管道,避免使用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]
答案 3 :(得分:9)
也许subprocess.list2cmdline
是一个更好的镜头?
答案 4 :(得分: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 issue 7476;它已在Python 2.6和3.2及更新版本中修复。
答案 5 :(得分:3)
我相信os.system只是调用为用户配置的命令shell,所以我认为你不能以独立于平台的方式来做。我的命令shell可以是来自bash,emacs,ruby甚至quake3的任何东西。其中一些程序并不期望你传递给他们的那种论点,即使他们这样做也不能保证他们以同样的方式逃避。
答案 6 :(得分:3)
注意:这是Python 2.7.x的答案。
根据source,pipes.quote()
是一种“可靠地引用字符串作为 / bin / sh 的单个参数的方法” 。 (尽管它是deprecated since version 2.7并最终在Python 3.3中作为shlex.quote()
函数公开公开。)
在the other hand上,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)
答案 7 :(得分:1)
我使用的功能是:
def quote_argument(argument):
return '"%s"' % (
argument
.replace('\\', '\\\\')
.replace('"', '\\"')
.replace('$', '\\$')
.replace('`', '\\`')
)
就是:我总是将参数括在双引号中,然后反斜杠引用双引号中唯一的特殊字符。
答案 8 :(得分:-3)
如果您确实使用了系统命令,我会尝试将进入os.system()调用的内容列入白名单。例如..
clean_user_input re.sub("[^a-zA-Z]", "", user_input)
os.system("ls %s" % (clean_user_input))
子进程模块是一个更好的选择,我建议尽可能避免使用像os.system / subprocess这样的东西。
答案 9 :(得分:-3)
真正的答案是:首先不要使用os.system()
。请改用subprocess.call
并提供未转义的参数。