シェルコマンドを実行して出力をキャプチャする


908

シェルコマンドを実行してその出力を返す関数を書きたい エラーメッセージでも成功メッセージでもを文字列として。コマンドラインで取得したのと同じ結果を得たいだけです。

そのようなことをするコード例は何でしょうか?

例えば:

def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'

回答:


1138

この質問に対する答えは、使用しているPythonのバージョンによって異なります。最も簡単な方法は、subprocess.check_output関数を使用することです。

>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_output入力として引数のみを取る単一のプログラムを実行します。1に出力されたとおりに結果を返しますstdout。に入力を書き込む必要がある場合stdinrunPopenセクションまたはセクションに進んでください。複雑なシェルコマンドを実行する場合shell=Trueは、この回答の最後にあるを参照してください。

このcheck_output関数は、Pythonのほとんどすべてのバージョンで機能します(2.7以上)。2しかし、最近のバージョンでは、これは推奨されるアプローチではなくなりました。

最新バージョンのPython(3.5以降): run

Python 3.5以降を使用していて、下位互換性が必要ない場合は、新しいrun関数をお勧めします。subprocessモジュールに非常に一般的な高レベルAPIを提供します。プログラムの出力をキャプチャするには、subprocess.PIPEフラグをstdoutキーワード引数に渡します。次にstdout、返されたCompletedProcessオブジェクトの属性にアクセスします。

>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

戻り値はbytesオブジェクトであるため、適切な文字列が必要な場合はdecodeそれを行う必要があります。呼び出されたプロセスがUTF-8エンコードされた文字列を返すと仮定します。

>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

これはすべてワンライナーに圧縮できます:

>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

プロセスのに入力を渡す場合は、キーワード引数にオブジェクトをstdin渡します。bytesinput

>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'

stderr=subprocess.PIPE(capture to result.stderr)またはstderr=subprocess.STDOUT(capture to result.stdoutと通常の出力)を渡すことでエラーをキャプチャできます。セキュリティが問題にならない場合はshell=True、以下の注で説明するように渡すことで、より複雑なシェルコマンドを実行することもできます。

これにより、従来の方法と比較すると、少しだけ複雑になります。しかし、それは見返りの価値があると私は思います:これで、run関数だけで行う必要があるほとんどすべてのことを実行できます。

古いバージョンのPython(2.7-3.4): check_output

古いバージョンのPythonを使用している場合、またはわずかな下位互換性が必要な場合は、check_output上で簡単に説明した関数を使用できます。Python 2.7以降で利用可能です。

subprocess.check_output(*popenargs, **kwargs)  

Popen(以下を参照)と同じ引数を取り、プログラムの出力を含む文字列を返します。この回答の冒頭には、より詳細な使用例があります。Pythonの3.5およびそれ以上では、check_output実行するのと同じですruncheck=Trueしてstdout=PIPE、とだけ返すstdout属性を。

stderr=subprocess.STDOUTエラーメッセージが返される出力に確実に含まれるように渡すことができますが、Pythonの一部のバージョンでは、に渡すとデッドロックが発生stderr=subprocess.PIPEするcheck_output可能性があります。セキュリティが問題にならない場合は、以下の注で説明するように渡すことで、より複雑なシェルコマンドを実行することもできます。shell=True

stderrプロセスからパイプするか、プロセスに入力を渡す必要がある場合はcheck_output、タスク次第ではありません。Popenその場合は、以下の例を参照してください。

複雑なアプリケーションとPythonのレガシーバージョン(2.6以下): Popen

下位互換性が必要な場合、またはcheck_output提供されているよりも高度な機能が必要な場合は、Popenサブプロセスの低レベルAPIをカプセル化するオブジェクトを直接操作する必要があります。

Popenコンストラクタは、いずれかの受け入れつのコマンド引数なし、またはリスト任意の数の引数リスト内の別個の項目として各続いて、その最初の項目としてコマンドを、含有します。shlex.split文字列を適切にフォーマットされたリストに解析するのに役立ちます。Popenオブジェクトは、プロセスIO管理および低レベル構成のためのさまざまな引数のホストも受け入れます。

入力を送信して出力をキャプチャすることcommunicateは、ほとんどの場合、推奨される方法です。のように:

output = subprocess.Popen(["mycmd", "myarg"], 
                          stdout=subprocess.PIPE).communicate()[0]

または

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

を設定するとstdin=PIPEcommunicate次を介してプロセスにデータを渡すこともできますstdin

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo

アーロン・ホールの答え一部のシステムでは、あなたが設定する必要性があることを示し、stdoutstderr、およびstdinすべてにPIPE(またはDEVNULL取得する)communicateすべての仕事に。

まれに、複雑なリアルタイムの出力キャプチャが必要になる場合があります。Vartecの回答は前進する方法を示唆していますが、communicate注意深く使用しないと、それ以外の方法ではデッドロックが発生しやすくなります。

上記のすべての関数と同様に、セキュリティが問題にならない場合は、を渡すことで、より複雑なシェルコマンドを実行できますshell=True

ノート

1.シェルコマンドの実行:shell=True引数

通常、各呼び出しruncheck_outputまたはPopenコンストラクタが実行される単一のプログラムを。つまり、派手なbashスタイルのパイプはありません。複雑なシェルコマンドを実行する場合はshell=True、3つの関数すべてがサポートするを渡すことができます。

ただし、これを行うとセキュリティ上の問題が発生します。軽いスクリプト以外のことをしている場合は、各プロセスを個別に呼び出して、各プロセスの出力を入力として次のプロセスに渡すことをお勧めします。

run(cmd, [stdout=etc...], input=other_output)

または

Popen(cmd, [stdout=etc...]).communicate(other_output)

パイプを直接接続する誘惑は強いです。それに抵抗します。そうしないと、おそらくデッドロックが発生したり、このようなハックなことをしたりする必要があります。

2. Unicodeに関する考慮事項

check_outputPython 2では文字列が返されますが、bytesPython 3ではオブジェクトが返されます。Unicodeについてまだ理解していない場合は、少し時間をかけて学ぶ価値があります。


5
との両方で、プロセスが完了するまで待機する必要がcheck_output()ありcommunicate()ますpoll()。本当に必要なものに依存します。
vartec 2012

2
これが新しいバージョンのPythonにのみ当てはまるかどうかはわかりませんが、変数out<class 'bytes'>私にとっては型でした。:文字列として出力を得るために、私はそうのように印刷する前に、それを解読しなければならなかったout.decode("utf-8")
あるpolyMesh

1
@parあなたが合格したときそれはあなたのために機能しませんshell=Trueか?わたしにはできる。shlex.split合格時に必要ありませんshell=Trueshlex.split非シェルコマンド用です。これは水を濁らせているので、私はそれを少し取り除くつもりだと思います。
センダーレ

2
Python 3.5以降universal_newlines=Trueでは、システムのデフォルトのエンコーディングでUnicode文字列を渡したり取り出したりできるキーワード引数を使用できます。3.7では、これはより適切な名前に変更されましたtext=True
Tripleee

2
Python 3.6以降では、encodingsubprocess.run代わりにのパラメータをresult.stdout.decode('utf-8')使用できますsubprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8')
ピエール

191

これは簡単ですが、Unix(Cygwinを含む)とPython2.7でのみ機能します。

import commands
print commands.getstatusoutput('wc -l file')

(return_value、output)のタプルを返します。

Python2とPython3の両方で機能するソリューションの場合は、subprocess代わりにモジュールを使用します。

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response

31
現在は非推奨ですが、subprocess.check_outputのない古いバージョンのpythonには非常に役立ちます
static_rtti

22
これはUnix固有のものであることに注意してください。たとえば、Windowsでは失敗します。
Zitrax 2013年

4
+1 Python 2.4の古いバージョンで作業する必要があり、これは非常に役に立ちました
javadba

1
完全なコードを示すPIPEの男とは何ですか?subprocess.PIPE
カイルブリデンスティン2018年

@KyleBridenstine回答を編集できます。
ボリス

106

そんな感じ:

def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
        # returns None while subprocess is running
        retcode = p.poll() 
        line = p.stdout.readline()
        yield line
        if retcode is not None:
            break

私はstderrをstdoutにリダイレクトしていることに注意してください。それはあなたが望むものではないかもしれませんが、エラーメッセージも必要です。

この関数は、行ごとに1行ずつ出力します(通常、出力を全体として取得するには、サブプロセスが完了するのを待つ必要があります)。

あなたの場合、使用法は次のようになります:

for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,

waitおよびcall関数の潜在的なデッドロックを回避するために、出力を取得するための何らかのアクティブループを実装してください。
アンドレ・キャノン

@Silver Light:プロセスはおそらくユーザーからの入力を待っています。PIPE値を指定しstdinPopen戻ったらすぐにそのファイルを閉じてみてください。
アンドレ・キャノン

4
-1:if retcodeが無限ループです0。チェックはである必要がありますif retcode is not None。あなたは空の文字列を生成するべきではありません(でも、空行は、少なくとも一つのシンボル「\ n」があります): if line: yield linep.stdout.close()最後に電話します。
jfs

2
ls -l / dirnameを使用してコードを試しましたが、ディレクトリにファイルがはるかに多いのに2つのファイルをリストした後、壊れます
Vasilis

3
@fuenfundachtzig:すべての出力が読み取ら.readlines()れるまで戻りません。そのため、メモリに収まらない大きな出力では壊れます。また、サブプロセスの終了後にバッファリングされたデータの欠落を回避するために、if retcode is not None: yield from p.stdout.readlines(); break
jfs

67

Vartecの答えはすべての行を読み取るわけではないため、次のようなバージョンを作成しました。

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

使い方は受け入れられた答えと同じです:

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)

6
return iter(p.stdout.readline, b'')whileループの代わりに使用することができます
jfs

2
それはiterのかなりクールな使い方です、それを知りませんでした!コードを更新しました。
Max Ekman

stdoutがすべての出力を保持すると確信しています。これはバッファ付きのストリームオブジェクトです。非常によく似た手法を使用して、Popenの完了後に残りのすべての出力を使い果たします。私の場合、実行中にpoll()とreadlineを使用して、ライブ出力もキャプチャします。
Max Ekman

誤解を招くコメントを削除しました。確認できます。p.stdout.readline()子プロセスがすでに終了している場合でも(p.poll()isでない場合)、以前にバッファリングされた空でない出力が返されることがありNoneます。
jfs 2014

このコードは機能しません。ここを参照してくださいstackoverflow.com/questions/24340877/...
タン

61

これは、多くの状況で機能するトリッキーです非常にシンプルなソリューションです。

import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()

コマンドの出力で一時ファイル(ここではtmp)が作成され、そこから希望の出力を読み取ることができます。

コメントからの補足:ワンタイムジョブの場合は、tmpファイルを削除できます。これを数回行う必要がある場合は、tmpを削除する必要はありません。

os.remove('tmp')

5
Hackyしかし超シンプル+はどこでも機能します..と組み合わせてmktemp、スレッド化された状況で機能させることができます
Prakash Rajagaopal

2
おそらく最速の方法かもしれませんが、os.remove('tmp')「ファイルレス」にするために追加する方が良いでしょう。
XuMuK 2017

@XuMuK一回限りの仕事の場合はそうです。反復作業の場合、削除する必要はないかもしれません
Mehdi Saman Booy 2017

1
同時実行性、リエントラント関数、システムが開始する前の状態のままにしないこと(クリーンアップなし)が
悪い

1
@ 2mia明らかに理由は簡単です!このファイルを、同時読み取りおよび書き込みの一種の共有メモリとして使用する場合、これは適切な選択ではありません。しかし、s.th。コマンドの出力(lsまたはfindまたは...など)があるように、これは適切で高速な選択です。ところで、単純な問題の迅速な解決策が必要な場合は、私が考える最高の方法です。パイプラインが必要な場合は、サブプロセスがより効率的に機能します。
Mehdi Saman Booy、2018

44

私は同じ問題を抱えていましたが、これを行う非常に簡単な方法を見つけました:

import subprocess
output = subprocess.getoutput("ls -l")
print(output)

それがお役に立てば幸い

注:このソリューションはPython2でsubprocess.getoutput()機能しないため、Python3固有です。


これはOPの問題をどのように解決しますか?詳しく説明してください。
RamenChef

4
これは、コマンドの出力を文字列として、そのように単純に返します
azhar22k

1
もちろん、printはPython 2のステートメントです。これがPython 3の答えであることがわかるはずです。

2
@Dev印刷はPython 2で有効です。subprocess.getoutputは無効です。
user48956 2017

2
ほとんどのユースケースでは、これはおそらく人々が望むものです。覚えやすく、結果をデコードする必要がないなどです。ありがとうございます。
bwv549

18

次のコマンドを使用して、任意のシェルコマンドを実行できます。私はubuntuでそれらを使用しました。

import os
os.popen('your command here').read()

注:これはpython 2.6から廃止されました。今すぐ使用する必要がありますsubprocess.Popen。以下は例です

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")

2
バージョン2.6以降非推奨– docs.python.org/2/library/os.html#os.popen
Filippo Vitale

1
@FilippoVitaleありがとうございます。それが非推奨であることを知りませんでした。
ムハンマドハッサン

1
raspberrypi.stackexchange.com/questions/71547/…に よるとos.popen()、Python 2.6では非推奨ですが、3.xではを使用して実装されているため、Python 3.xでは非推奨ではありませsubprocess.Popen()
JL

12

あなたのマイレージが異なる場合があります。Python2.6.5のWindowsでVartecのソリューションを@senderleのスピンで試しましたが、エラーが発生し、他のソリューションは機能しませんでした。私のエラーは:WindowsError: [Error 6] The handle is invalidでした。

すべてのハンドルにPIPEを割り当てて、期待した出力を返すようにする必要があることがわかりました。次の方法でうまくいきました。

import subprocess

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

次のように呼び出します([0]タプルの最初の要素を取得しますstdout):

run_command('tracert 11.1.0.1')[0]

詳細を学んだ後、異なるハンドルを使用するカスタムシステムで作業しているため、これらのパイプ引数が必要だと思います。そのため、すべてのstdを直接制御する必要がありました。

(Windowsで)コンソールポップアップを停止するには、次の操作を行います。

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    return subprocess.Popen(cmd,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE, 
                            startupinfo=startupinfo).communicate()

run_command('tracert 11.1.0.1')

1
興味深い-これはWindowsのものでなければならない。同様のエラーが発生する場合に備えて、これを指摘するメモを追加します。
sendle

パイプから読み書きしない場合は、DEVNULL代わりに使用してsubprocess.PIPEください。そうしないと、子プロセスがハングする可能性があります。
jfs

10

私は次の要件で同じ問題の少し異なる風味を持っていました:

  1. STDOUTメッセージがSTDOUTバッファーに蓄積されると(リアルタイムで)、キャプチャして返します。
    • @vartecは、ジェネレーターと上記の「yield」
      キーワードを使用して、Pythonでこれを解決しました
  2. すべてのSTDOUT行を出力します( STDOUTバッファーを完全に読み取る前にプロセスが終了した場合でも
  3. 高頻度でプロセスをポーリングするCPUサイクルを無駄にしないでください
  4. サブプロセスの戻りコードを確認してください
  5. ゼロ以外のエラー戻りコードを受け取った場合は、STDERR(STDOUTとは別)を出力します。

以前の回答を組み合わせて調整し、次のことを考えました。

import subprocess
from time import sleep

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)
    # Read stdout from subprocess until the buffer is empty !
    for line in iter(p.stdout.readline, b''):
        if line: # Don't print blank lines
            yield line
    # This ensures the process has completed, AND sets the 'returncode' attr
    while p.poll() is None:                                                                                                                                        
        sleep(.1) #Don't waste CPU-cycles
    # Empty STDERR buffer
    err = p.stderr.read()
    if p.returncode != 0:
       # The run_command() function is responsible for logging STDERR 
       print("Error: " + str(err))

このコードは、以前の回答と同じように実行されます。

for line in run_command(cmd):
    print(line)

1
sleep(.1)を追加してもCPUサイクルが無駄にならないことを説明してもらえますか?
Moataz Elmasry 2017

2
呼び出しのp.poll()間にスリープなしで呼び出しを続けると、この関数を数百万回呼び出すことでCPUサイクルを浪費することになります。代わりに、次の1/10秒間煩わされる必要がないことをOSに通知することでループを「抑制」し、他のタスクを実行できるようにします。(p.poll()もスリープして、sleepステートメントが冗長になる可能性があります)。
Aelfinn 2017

5

の最初のコマンドを分割するsubprocessことは、トリッキーで扱いにくいかもしれません。

shlex.split()自分を助けるために使用します。

コマンド例

git log -n 5 --since "5 years ago" --until "2 year ago"

コード

from subprocess import check_output
from shlex import split

res = check_output(split('git log -n 5 --since "5 years ago" --until "2 year ago"'))
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

なければshlex.split()、次のようなコードになります

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

1
shlex.split()特にシェルでの引用がどのように機能するか正確にわからない場合は便利です。しかし、['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']引用を理解していれば、この文字列を手動でリストに変換することは難しくありません。
Tripleee

4

複数のファイルでシェルコマンドを実行する必要がある場合は、これでうまくいきました。

import os
import subprocess

# Define a function for running commands and capturing stdout line by line
# (Modified from Vartec's solution because it wasn't printing all lines)
def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

# Get all filenames in working directory
for filename in os.listdir('./'):
    # This command will be run on each file
    cmd = 'nm ' + filename

    # Run the command and capture the output line by line.
    for line in runProcess(cmd.split()):
        # Eliminate leading and trailing whitespace
        line.strip()
        # Split the output 
        output = line.split()

        # Filter the output and print relevant lines
        if len(output) > 2:
            if ((output[2] == 'set_program_name')):
                print filename
                print line

編集:JFセバスチャンの提案でMax Perssonのソリューションを見ただけです。先に進んでそれを組み込んだ。


Popenは文字列を受け入れますが、が必要な場合shell=True、または引数のリストが必要な場合['nm', filename]は、文字列の代わりに渡す必要があります。シェルは、ここでは値を提供せずに複雑さを追加するため、後者が望ましいです。文字列をshell=True渡さずにWindowsで動作することは明らかですが、Pythonの次のバージョンでは変更される可能性があります。
tripleee

2

@senderleによると、私のようにpython3.6を使用している場合:

def sh(cmd, input=""):
    rst = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
    assert rst.returncode == 0, rst.stderr.decode("utf-8")
    return rst.stdout.decode("utf-8")
sh("ls -a")

bashでコマンドを実行するのとまったく同じように動作します


キーワード引数を再発明していますcheck=True, universal_newlines=True。言い換えればsubprocess.run()、コードが実行するすべてのことをすでに実行しています。
Tripleee

1

subprocesspythonモジュールを使用すると、STDOUT、STDERR、コマンドのリターンコードを個別に扱うことができます。コマンド呼び出し元の完全な実装の例を見ることができます。もちろん、必要にtry..except応じて拡張できます。

以下の関数は、STDOUT、STDERR、およびリターンコードを返すため、他のスクリプトでそれらを処理できます。

import subprocess

def command_caller(command=None)
    sp = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
    out, err = sp.communicate()
    if sp.returncode:
        print(
            "Return code: %(ret_code)s Error message: %(err_msg)s"
            % {"ret_code": sp.returncode, "err_msg": err}
            )
    return sp.returncode, out, err

の別の貧弱な再実装subprocess.run()。車輪を再発明しないでください。
tripleee

0

たとえば、execute( 'ls -ahl')は、3/4の可能なリターンとOSプラットフォームを区別しました。

  1. 出力はありませんが、正常に実行されます
  2. 空の行を出力し、正常に実行します
  3. 実行に失敗しました
  4. 何かを出力し、正常に実行します

以下の機能

def execute(cmd, output=True, DEBUG_MODE=False):
"""Executes a bash command.
(cmd, output=True)
output: whether print shell output to screen, only affects screen display, does not affect returned values
return: ...regardless of output=True/False...
        returns shell output as a list with each elment is a line of string (whitespace stripped both sides) from output
        could be 
        [], ie, len()=0 --> no output;    
        [''] --> output empty line;     
        None --> error occured, see below

        if error ocurs, returns None (ie, is None), print out the error message to screen
"""
if not DEBUG_MODE:
    print "Command: " + cmd

    # https://stackoverflow.com/a/40139101/2292993
    def _execute_cmd(cmd):
        if os.name == 'nt' or platform.system() == 'Windows':
            # set stdin, out, err all to PIPE to get results (other than None) after run the Popen() instance
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        else:
            # Use bash; the default is sh
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable="/bin/bash")

        # the Popen() instance starts running once instantiated (??)
        # additionally, communicate(), or poll() and wait process to terminate
        # communicate() accepts optional input as stdin to the pipe (requires setting stdin=subprocess.PIPE above), return out, err as tuple
        # if communicate(), the results are buffered in memory

        # Read stdout from subprocess until the buffer is empty !
        # if error occurs, the stdout is '', which means the below loop is essentially skipped
        # A prefix of 'b' or 'B' is ignored in Python 2; 
        # it indicates that the literal should become a bytes literal in Python 3 
        # (e.g. when code is automatically converted with 2to3).
        # return iter(p.stdout.readline, b'')
        for line in iter(p.stdout.readline, b''):
            # # Windows has \r\n, Unix has \n, Old mac has \r
            # if line not in ['','\n','\r','\r\n']: # Don't print blank lines
                yield line
        while p.poll() is None:                                                                                                                                        
            sleep(.1) #Don't waste CPU-cycles
        # Empty STDERR buffer
        err = p.stderr.read()
        if p.returncode != 0:
            # responsible for logging STDERR 
            print("Error: " + str(err))
            yield None

    out = []
    for line in _execute_cmd(cmd):
        # error did not occur earlier
        if line is not None:
            # trailing comma to avoid a newline (by print itself) being printed
            if output: print line,
            out.append(line.strip())
        else:
            # error occured earlier
            out = None
    return out
else:
    print "Simulation! The command is " + cmd
    print ""

0

出力はテキストファイルにリダイレクトされ、それを読み返すことができます。

import subprocess
import os
import tempfile

def execute_to_file(command):
    """
    This function execute the command
    and pass its output to a tempfile then read it back
    It is usefull for process that deploy child process
    """
    temp_file = tempfile.NamedTemporaryFile(delete=False)
    temp_file.close()
    path = temp_file.name
    command = command + " > " + path
    proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    if proc.stderr:
        # if command failed return
        os.unlink(path)
        return
    with open(path, 'r') as f:
        data = f.read()
    os.unlink(path)
    return data

if __name__ == "__main__":
    path = "Somepath"
    command = 'ecls.exe /files ' + path
    print(execute(command))

もちろん可能ですが、なぜそうしたいのでしょうか。なぜ渡すのではなくシェルを使うのstdout=temp_fileですか?
tripleee

実際、一般的にはあなたの言う通りですが、私の例では、ecls.exe別のコマンドラインツールをデプロイしているように見えるため、単純な方法ではうまくいかない場合があります。
MR

0

curlを使用してこれを行うための小さなbashスクリプトを作成したところです

https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5

#!/usr/bin/env bash

# Usage: gdrive_dl.sh <url>

urlBase='https://drive.google.com'
fCookie=tmpcookies

curl="curl -L -b $fCookie -c $fCookie"
confirm(){
    $curl "$1" | grep jfk-button-action | sed -e 's/.*jfk-button-action" href="\(\S*\)".*/\1/' -e 's/\&amp;/\&/g'
}

$curl -O -J "${urlBase}$(confirm $1)"
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.