135

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() が提供する迅速で簡単な解決策に興味があり、文字列のソースはユーザーが生成したものではないか、少なくとも信頼できるユーザー (私)。

4

9 に答える 9

91

これは私が使用するものです:

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

シェルは常に引用符で囲まれたファイル名を受け入れ、問題のプログラムに渡す前に周囲の引用符を削除します。特に、これにより、スペースやその他の種類の厄介なシェルメタ文字を含むファイル名の問題が回避されます。

更新:Python 3.3以降を使用している場合は、独自のロールを作成する代わりにshlex.quoteを使用してください。

于 2008-08-30T10:13:11.503 に答える
62

おそらく、を使用する特定の理由があります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]
于 2008-08-30T10:15:02.403 に答える
12

多分subprocess.list2cmdlineより良いショットですか?

于 2012-05-25T07:54:41.123 に答える
6

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 以降では修正されています。

于 2009-12-10T23:03:55.737 に答える
4

os.systemは、ユーザー用に構成されているコマンドシェルを呼び出すだけなので、プラットフォームに依存しない方法で呼び出すことはできないと思います。私のコマンドシェルは、bash、emacs、ruby、さらにはquake3まで何でもかまいません。これらのプログラムのいくつかは、あなたが彼らに渡すような種類の議論を期待していません、そして彼らがそうしたとしても、彼らが同じように彼らの脱出をするという保証はありません。

于 2008-08-30T09:43:50.123 に答える
3

注意: これは Python 2.7.x に対する回答です。

ソースによると、 「 /bin/shの単一の引数として文字列を確実に引用するpipes.quote()」方法です。(ただし、バージョン 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)
于 2015-04-13T03:26:35.380 に答える
1

私が使用する機能は次のとおりです。

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

つまり、私は常に引数を二重引用符で囲み、二重引用符内の特別な文字のみをバックスラッシュ引用符で囲みます。

于 2010-10-03T21:21:44.853 に答える