web-dev-qa-db-ja.com

複数の引数にスペースが含まれている場合にサブプロセスを使用するにはどうすればよいですか?

仮想マシンの起動/シャットダウン/登録/登録解除アクションの自動化を可能にする、vmware実行可能ファイルを実行するラッパースクリプトに取り組んでいます。サブプロセスを使用して実行可能ファイルの呼び出しを処理しようとしていますが、実行可能ファイルのパスと実行可能ファイルのパラメーターのスペースがサブプロセスによって正しく処理されていません。以下はコードフラグメントです。

vmrun_cmd = r"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"
def vm_start(target_vm):
    list_arg = "start"
    list_arg2 = "hard"
    if vm_list(target_vm):
            p = Popen([vmrun_cmd, target_vm, list_arg, list_arg2],   stdout=PIPE).communicate()[0]
            print p
    else:
            vm_register(target_vm)
            vm_start(target_vm)
def vm_list2(target_vm):
    list_arg = "-l"
    p = Popen([vmrun_cmd, list_arg], stdout=PIPE).communicate()[0]
    for line in p.split('\n'):
            print line

Vm_list2関数を呼び出すと、次の出力が得られます。

$ ./vmware_control.py --list                                                
C:\Virtual Machines\QAW2K3Server\Windows Server 2003 Standard Edition.vmx
C:\Virtual Machines\ubunturouter\Ubuntu.vmx
C:\Virtual Machines\vacc\vacc.vmx
C:\Virtual Machines\EdgeAS-4.4.x\Other Linux 2.4.x kernel.vmx
C:\Virtual Machines\UbuntuServer1\Ubuntu.vmx
C:\Virtual Machines\Other Linux 2.4.x kernel\Other Linux 2.4.x kernel.vmx
C:\Virtual Machines\QAClient\Windows XP Professional.vmx

Path-to-vmパラメーターを必要とするvm_start関数を呼び出すと、次の出力が得られます。

$ ./vmware_control.py --start "C:\Virtual Machines\ubunturouter\Ubuntu.vmx"
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.

明らかに、スペースが埋め込まれた2番目のパラメーターの存在は、サブプロセスが最初のパラメーターを解釈する方法を変更しています。これを解決する方法について何か提案はありますか?

python2.5.2/cygwin/winxp

21
Rob Carr

パスにスペースがある場合、それらを正しく解釈するために私が見つけた最も簡単な方法はこれです。

subprocess.call('""' + path + '""')

なぜ正確に二重引用符が必要なのかわかりませんが、それが機能します。

5
Tofystedeth
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.

このメッセージを受け取るには、次のいずれかです。

  1. Shell=Trueの使用:

    vmrun_cmd = r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat"
    subprocess.Popen(vmrun_cmd, Shell=True)
    
  2. コードの他の部分でvmrun_cmdを変更する

  3. Vmware-cmd.bat内の何かからこのエラーを取得する

試すべきこと:

  • pythonプロンプトを開き、次のコマンドを実行します。

    subprocess.Popen([r"c:\Program Files\VMware\VMware Server\vmware-cmd.bat"])
    

それがうまくいくなら、引用の問題は問題外です。そうでない場合は、問題を特定しました。

5
nosklo

MSWindowsのPythonでは、subprocess.PopenクラスはCreateProcessAPIを使用してプロセスを開始します。 CreateProcessは、引数の配列のようなものではなく、文字列を取ります。 Pythonは、subprocess.list2cmdlineを使用して、引数のリストをCreateProcessの文字列に変換します。

私があなたなら、subprocess.list2cmdline(args)が何を返すかがわかります(ここで、argsはPopenの最初の引数です)。最初の引数を引用符で囲んでいるかどうかを確認するのは興味深いことです。

もちろん、この説明はCygwin環境には当てはまらない可能性があります。

そうは言っても、私はMSWindowsを持っていません。

2
Warren

リスト引数の処理を実行しているlist2cmdline()は、stringに二重引用符が含まれていない限り、空白の文字列引数を分割すると思います。だから私は期待します

vmrun_cmd = r'"c:/Program Files/VMware/VMware Server/vmware-cmd.bat"'

あなたが望むものになるために。

また、他の引数(target_vmなど)も、それぞれがコマンドラインに表示する個別の引数を表すと想定して、二重引用符で囲むことをお勧めします。何かのようなもの

r'"%s"' % target_vm

(例えば)合うべきです。

list2cmdlineドキュメント を参照してください

D'A

2
darch

1つの問題は、コマンドが引用符で囲まれ、スペースがない場合、シェルを混乱させる可能性があることです。

だから私はこれを行います:

if ' ' in raw_cmd:
    fmt = '"%s"'
else:
    fmt = '%s'

cmd = fmt % raw_cmd
1
Ryan Ginstrom

これは、最後の3つの問題にとって非常に難しい問題でした。これまでのところ、r ""もリスト付きのPopenも使用せず、何も機能しませんでした。最終的に機能したのは、フォーマット文字列とr ""の組み合わせでした。だから私の解決策はこれです:

subprocess.Popen("{0} -f {1}".format(pathToExe, r'"%s"' % pathToVideoFileOrDir))

ここで、変数pathToExeとpathToVideoFileOrDirの両方のパスに空白があります。フォーマットされた文字列内で\ "を使用すると機能せず、最初のパスが正しく検出されなくなるのと同じエラーが発生しました。

0