首页 / 知识

关于python:如何转义os.system()调用?

2023-04-13 16:56:00

关于python:如何转义os.system()调用?

How to escape os.system() calls?

使用os.system()时,通常需要转义文件名和其他作为参数传递给命令的参数。 我怎样才能做到这一点? 最好是可以在多个操作系统/外壳上运行的东西,尤其是bash。

我目前正在执行以下操作,但是请确保为此必须有一个库函数,或者至少是一个更优雅/更强大/更有效的选项:

1
2
3
4
5
6
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()提供的快速简便的解决方案感兴趣,并且字符串的来源不是用户生成的,或者至少是由a输入的 受信任的用户(我)。


自python 3起,shlex.quote()即可满足您的需求。

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


这是我用的:

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

外壳程序将始终接受带引号的文件名,并在将其传递给所涉及的程序之前删除其引号。值得注意的是,这避免了文件名包含空格或其他任何讨厌的shell元字符的问题。

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


也许您有使用os.system()的特定原因。但是,如果没有,您可能应该使用subprocess模块。您可以直接指定管道,并避免使用外壳。

以下来自PEP324:

1
2
3
4
5
6
7
8
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中已损坏,并且不安全使用-它不处理零长度参数。

1
2
3
4
>>> 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及更高版本中修复。


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

根据消息来源,pipes.quote()是"可靠地将字符串作为/ bin / sh的单个参数引用"的一种方法。 (尽管从2.7版开始不推荐使用,但最终在Python 3.3中作为shlex.quote()函数公开了。)

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

在这里,我们提供了平台无关的方式来引用命令行字符串。

1
2
3
4
5
6
7
8
9
10
11
12
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)

用法:

1
2
3
4
5
6
# Quote a single argument
print quote_args(['my argument'])

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


我相信os.system只会调用为用户配置的任何命令外壳,因此我认为您不能以独立于平台的方式进行操作。我的命令外壳可以是bash,emacs,ruby甚至quake3中的任何东西。这些程序中的某些程序并不期望您传递给它们的参数,即使它们这样做,也不能保证它们以相同的方式进行转义。


我使用的功能是:

1
2
3
4
5
6
7
8
def quote_argument(argument):
    return '"%s"' % (
        argument
        .replace('\', '\\\')
        .replace('
"', '\"')
        .replace('$', '\\$')
        .replace('`', '\\`')
    )

即:我总是将参数用双引号引起来,然后用反斜杠将双引号内的特殊字符引起来。


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


如果您确实使用了system命令,我将尝试将os.system()调用中的内容列入白名单。

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

subprocess模块??是一个更好的选择,我建议尽量避免使用os.system / subprocess之类的东西。


转义调用命令文件名

最新内容

相关内容

热门文章

推荐文章

标签云

猜你喜欢