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

有帮助吗?

解决方案

这就是我使用的:

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

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

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

其他提示

shlex.quote() 从 python 3 开始做你想做的事。

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

也许您有特定的使用原因 os.system(). 。但如果没有,你可能应该使用 subprocess 模块. 。您可以直接指定管道并避免使用 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 只是调用为用户配置的任何命令 shell,所以我认为您不能以独立于平台的方式来完成它。我的命令 shell 可以是 bash、emacs、ruby 甚至 quake3 中的任何命令。其中一些程序并不期望您传递给它们的参数类型,即使它们期望,也不能保证它们会以相同的方式进行转义。

注意: :这是 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)

我使用的功能是:

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

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

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

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top