web-dev-qa-db-ja.com

サブプロセスによって呼び出されるコマンドラインを出力しますか?

私はsubprocess.Popen呼び出しを使用していますが、別の質問で、Pythonがコマンドラインの引数を生成していた方法を誤解していたことがわかりました。

私の質問
実際のコマンドラインが何であったかを知る方法はありますか?

サンプルコード:-

proc = subprocess.popen(....)
print "the commandline is %s" % proc.getCommandLine()

getCommandLineはどのように書きますか?

42
Brian Postow

Python使用しているバージョンに依存します。 Python3.3の場合 、引数は_proc.args_に保存されます:

_proc = subprocess.Popen(....)
print("the commandline is {}".format(proc.args))
_

Python2.7では、 argsは保存されません 、それは__execute_child_などの他の関数に渡されます。そのため、その場合、コマンドラインを取得する最善の方法は、コマンドラインがあるときに保存することです。

_proc = subprocess.Popen(shlex.split(cmd))
print "the commandline is %s" % cmd
_

引数のlistがある場合(shlex.split(cmd)によって返されるもののタイプなど)、コマンドを回復できることに注意してください。文書化されていない関数_subprocess.list2cmdline_を使用した行文字列cmd

_In [14]: import subprocess

In [15]: import shlex

In [16]: cmd = 'foo -a -b --bar baz'

In [17]: shlex.split(cmd)
Out[17]: ['foo', '-a', '-b', '--bar', 'baz']

In [18]: subprocess.list2cmdline(['foo', '-a', '-b', '--bar', 'baz'])
Out[19]: 'foo -a -b --bar baz'
_
58
unutbu

私の質問に対する正しい答えは、実際には[〜#〜] is [〜#〜]コマンドラインがないということです。サブプロセスのポイントは、IPCを介してすべてを実行することです。 list2cmdlineは予想どおりに機能しますが、実際には、「args」リストを見て、呼び出されたプログラムでargvになることを知っておくのが最善です。

3
Brian Postow

美しくスケーラブルな方法

私はこのようなものを使用しています:

#!/usr/bin/env python3

import os
import shlex
import subprocess
import sys

def run_cmd(cmd, cwd=None, extra_env=None, extra_paths=None, dry_run=False):
    if extra_env is None:
        extra_env = {}
    newline_separator = ' \\\n'
    out = []
    kwargs = {}
    env = os.environ.copy()

    # cwd
    if 'cwd' is not None:
        kwargs['cwd'] = cwd

    # extra_env
    env.update(extra_env)
    for key in extra_env:
        out.append('{}={}'.format(shlex.quote(key), shlex.quote(extra_env[key])) + newline_separator)

    # extra_paths
    if extra_paths is not None:
        path = ':'.join(extra_paths)
        if 'PATH' in env:
            path += ':' + env['PATH']
        env['PATH'] = path
        out.append('PATH="{}:${{PATH}}"'.format(':'.join(extra_paths)) + newline_separator)

    # Command itself.
    for arg in cmd:
        out.append(shlex.quote(arg) + newline_separator)

    # Print and run.
    kwargs['env'] = env
    print('+ ' + '  '.join(out) + ';')
    if not dry_run:
        subprocess.check_call(cmd, **kwargs)

run_cmd(
    sys.argv[1:],
    cwd='/bin',
    extra_env={'ASDF': 'QW ER'},
    extra_paths=['/some/path1', '/some/path2']
)

サンプル実行:

./a.py echo 'a b' 'c d' 

出力:

+ ASDF='QW ER' \
  PATH="/some/path1:/some/path2:${PATH}" \
  echo \
  'a b' \
  'c d' \
;
a b c d

機能の概要:

  • 1行に1つのオプションを指定して、巨大なコマンドラインを読み取り可能
  • +sh -xなどのコマンドに追加して、ユーザーがコマンドと出力を簡単に区別できるようにする
  • cd、およびコマンドに与えられている場合は追加の環境変数を表示します。これらは、指定された場合にのみ出力され、最小限のシェルコマンドを生成します。

これらすべてにより、ユーザーはコマンドを手動で簡単にコピーして、何かが失敗した場合にコマンドを実行したり、何が起こっているかを確認したりできます。

テスト済みPython 3.5.2、Ubuntu 16.04。 GitHubアップストリーム