web-dev-qa-db-ja.com

Python3サブプロセスの出力

LinuxのWordカウントユーティリティwcを実行して、/ var/log/syslogの現在の行数を確認したいので、増加していることを検出できます。さまざまなテストを試しましたが、wcから結果を取得している間に、行数とコマンド(たとえば、var/log/syslog)の両方が含まれています。

1338/var/log/syslogが返されますが、行数だけが必要なので、/ var/log/syslogの部分を取り除き、1338だけを保持します。

私はそれをバイト文字列から文字列に変換し、結果を削除しようとしましたが、喜びはありませんでした。文字列への変換、ストリッピング、デコードなどの同じ話-すべてが私が探している出力を生成できません。

これらは、syslogの1338行で得られるもののいくつかの例です。

  • b'1338/var/log/syslog\n '
  • 1338/var/log/syslog

以下に、このナットをクラックしようとするために作成したテストコードを示しますが、解決策はありません。

import subprocess

#check_output returns byte string
stdoutdata = subprocess.check_output("wc --lines /var/log/syslog", Shell=True)
print("2A stdoutdata: " + str(stdoutdata))
stdoutdata = stdoutdata.decode("utf-8")
print("2B stdoutdata: " + str(stdoutdata))    
stdoutdata=stdoutdata.strip()
print("2C stdoutdata: " + str(stdoutdata))    

これからの出力は次のとおりです。

  • 2A stdoutdata:b'1338/var/log/syslog\n '

  • 2B stdoutdata:1338/var/log/syslog

  • 2C stdoutdata:1338/var/log/syslog

  • 2D stdoutdata:1338/var/log/syslog

38
user2565677

subprocess.getoutput()を使用して、希望どおりに実行することをお勧めします。シェルでコマンドを実行し、 string outputbyte string =出力)。次に、 空白で分割 を実行し、返された文字列のリストから最初の要素を取得します。

これを試して:

import subprocess
stdoutdata = subprocess.getoutput("wc --lines /var/log/syslog")
print("stdoutdata: " + stdoutdata.split()[0])
58
Joseph Dunn

* nixでシェルを呼び出して任意のバイトシーケンス('\0'を除く)である可能性のあるファイル名をデコードしないようにするには、ファイルをstdinとして渡すことができます。

import subprocess

with open(b'/var/log/syslog', 'rb') as file:
    nlines = int(subprocess.check_output(['wc', '-l'], stdin=file))
print(nlines)

または、デコードエラーを無視することもできます。

import subprocess

stdoutdata = subprocess.check_output(['wc', '-l', '/var/log/syslog'])
nlines = int(stdoutdata.decode('ascii', 'ignore').partition(' ')[0])
print(nlines)
10
jfs

Python 3.6なので、check_output()encodingを与えることで、strの代わりにbytesを返すことができます。パラメータ:

_check_output('wc --lines /var/log/syslog', encoding='UTF-8')
_

ただし、カウントが必要なだけで、split()int()の両方がbytesで使用できるため、エンコードに煩わされる必要はありません。

_linecount = int(check_output('wc -l /var/log/syslog').split()[0])
_

外部プログラムを使用すると簡単になる場合がありますが(たとえば、journalctlによって出力されるログ行エントリをカウントする場合)、この特定の場合、外部プログラムを使用する必要はありません。最も単純なPythonのみのソリューションは次のとおりです。

_with open('/var/log/syslog', 'rt') as f:
    linecount = len(f.readlines())
_

これには、ファイル全体をメモリに読み込むという欠点があります。巨大なファイルの場合は、ファイルを開く前に_linecount = 0_を初期化し、readlines()の代わりに_for line in f: linecount += 1_ループを使用して、カウント時にファイルのごく一部のみをメモリに格納します。

5
Curt J. Sampson

Curt J. Sampsonの答えもこれと同じです(文字列を返します)。

subprocess.check_output('wc -l /path/to/your/file | cut -d " " -f1', universal_newlines=True, Shell=True)

ドキュメントから:

エンコードまたはエラーが指定されている場合、またはテキストがtrueの場合、stdin、stdout、およびstderrのファイルオブジェクトは、指定されたエンコードおよびエラーまたはio.TextIOWrapperのデフォルトを使用してテキストモードで開かれます。 universal_newlines引数はtextと同等であり、後方互換性のために提供されています。デフォルトでは、ファイルオブジェクトはバイナリモードで開かれます。

似たようなものですが、subprocess.run()を使用するともう少し複雑になります。

subprocess.run(command, Shell=True, check=True, universal_newlines=True, stdout=subprocess.PIPE).stdout

subprocess.check_output()はsubprocess.run()と同等である可能性があるため。

1
Catalin B.