os.system() 呼び出しをエスケープするにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/35817

  •  09-06-2019
  •  | 
  •  

質問

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

役に立ちましたか?

解決

これが私が使っているものです:

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

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

アップデート:Python 3.3 以降を使用している場合は、次を使用します。 シュレックス引用 自分で巻く代わりに。

他のヒント

shlex.quote() Python 3以降はやりたいことを実行します。

(使用 pipes.quote Python 2 と Python 3 の両方をサポートする)

おそらく使用する特別な理由があるでしょう 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]

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

Pipes.quote は実際には Python 2.5 および Python 3.1 では壊れており、安全に使用できないことに注意してください。長さ 0 の引数は処理されません。

>>> 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 は、ユーザーに設定されているコマンド シェルを呼び出すだけだと思います。そのため、プラットフォームに依存しない方法で実行できるとは思いません。私のコマンド シェルは、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('`', '\\`')
    )

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

system コマンドを使用する場合は、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