PythonでのBashコマンドの実行


299

私のローカルマシンで、この行を含むpythonスクリプトを実行します

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)

これは正常に動作します。

次に、サーバーで同じコードを実行すると、次のエラーメッセージが表示されます

'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import  diag
ImportError: No module named swap

それでprint bashCommand私がしたことは、それを実行する前にターミナルでコマンドよりも出力するを挿入することos.system()です。

もちろん、(が原因でos.system(bashCommand))エラーが再び発生しますが、そのエラーの前にターミナルにコマンドが出力されます。次に、その出力をコピーし、ターミナルにコピーして貼り付け、Enterキーを押すだけで動作します...

誰かが何が起こっているのか手掛かりがありますか?


2
走り方によって環境に違いがあるようですcwm。多分あなたはあなたの中.bashrcにインタラクティブbash使用のための環境を設定するいくつかの設定がありますか?
Sven Marnach、2011年

サーバーにログインしているときに、コマンドラインからコマンドを実行してみましたか?あなたの投稿は「ターミナルに貼り付けた」とだけ言っています。
Sven Marnach、2011年

@Sven:はい、サーバーのターミナルで直接コマンドを実行したことを意味しました
mkn

実行方法によってPYTHONPATHに違いがあるようですcwm。または、PATHに違いがあり、異なるバージョンのcwmが呼び出されている可能性があります。または、異なるバージョンのPython。マシンにアクセスせずにこれを理解するのは本当に難しい...
Sven Marnach 2010年

回答:


314

使用しないでくださいos.systemサブプロセスを支持して非推奨になりました。ドキュメントから:「このモジュールは、いくつかの古いモジュールと機能を置き換えることを目的としています:os.systemos.spawn」。

あなたの場合のように:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
import subprocess
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()

8
これはcd 'path\to\somewhere'、どこかで実行する必要がある別のbashコマンドを続けて実行する必要があるときに、私が望んでいたことを実行しませんでした。@ user225312
AWrightIV

36
あなたが特定の作業ディレクトリで実行されるように、あなたのサブプロセスが必要な場合は@AWrightIVは、使用することができますcwdpopenのに引数を:subprocess.Popen(..., cwd='path\to\somewhere')
防水

7
私のコマンドでは、次のようにshell = Trueが必要でした。stackoverflow.com/questions/18962785/…–
user984003

4
この場合、string.split()の代わりにshlex.split()を使用することをお勧めします
Alexey Sviridov

4
...(stdout=fileこの場合、出力をファイルにリダイレクトします。これはを実装します> file)。..., '>', 'file']リダイレクトを期待している最後のコマンドを渡すのは間違っています(シェルがないと動作しません。シェルを使用する場合は、コマンドを文字列として渡す必要があります)
jfs

186

ここで以前の回答をいくらか拡大するために、一般に見落とされている詳細がいくつかあります。

  • 好むsubprocess.run()以上subprocess.check_call()にわたり、友人subprocess.call()オーバーsubprocess.Popen()オーバーos.system()オーバーos.popen()
  • 理解し、おそらく使用text=True別名、universal_newlines=True
  • 意味を理解しshell=Trueたりshell=False、どのようにそれがシェルの便利の可用性を引用して変更を。
  • shとBashの違いを理解する
  • サブプロセスがその親からどのように分離されているかを理解し、通常は親を変更できません。
  • PythonインタープリターをPythonのサブプロセスとして実行しないでください。

これらのトピックについては、以下で詳しく説明します。

優先subprocess.run()またはsubprocess.check_call()

subprocess.Popen()、便利、すでに様々な目的のために、より高いレベルのラッパー関数の集合として標準ライブラリに存在する...機能は、低レベルの主力であるが、正しく使用するのが難しいですし、複数行のコードを貼り付ける/コピーを終わりますこれについては、以下で詳しく説明します。

ここにドキュメントの段落があります

サブプロセスを呼び出すための推奨されるアプローチは、run()処理できるすべてのユースケースで関数を使用することです。より高度な使用例では、基になるPopenインターフェースを直接使用できます。

残念ながら、これらのラッパー関数の可用性はPythonバージョン間で異なります。

  • subprocess.run()Python 3.5で正式に導入されました。以下のすべてを置き換えることを意味します。
  • subprocess.check_output()Python 2.7 / 3.1で導入されました。基本的にはsubprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
  • subprocess.check_call()Python 2.5で導入されました。基本的にはsubprocess.run(..., check=True)
  • subprocess.call()Python 2.4の元のsubprocessモジュール(PEP-324)で導入されました。基本的にはsubprocess.run(...).returncode

高レベルAPIと subprocess.Popen()

リファクタリングおよび拡張subprocess.run()は、それが置き換える古いレガシー機能よりも論理的で用途が広いです。CompletedProcess終了ステータス、標準出力、およびその他のいくつかの結果と、終了したサブプロセスからのステータスインジケーターを取得できるさまざまなメソッドを持つオブジェクトを返します。

subprocess.run()実行して制御をPythonに戻すだけのプログラムが必要な場合に使用する方法です。より複雑なシナリオ(バックグラウンドプロセス、おそらくPythonの親プログラムとの対話型I / Oを使用)の場合も、使用subprocess.Popen()してすべての配管を自分で処理する必要があります。これには、すべての可動部分のかなり複雑な理解が必要であり、軽く行うべきではありません。より単純なPopenオブジェクトは、サブプロセスの存続期間の残りの間、コードから管理する必要がある(おそらく実行中の)プロセスを表します。

subprocess.Popen()単にプロセスを作成するだけであることをおそらく強調する必要があります。そのままにしておくと、Pythonと同時にサブプロセスが実行されるため、「バックグラウンド」プロセスになります。入力や出力を行う必要がない場合、または調整する必要がない場合は、Pythonプログラムと並行して有用な作業を行うことができます。

避けos.system()os.popen()

永遠に(まあ、Python 2.5以降)osモジュールのドキュメントには、次のような推奨事項が含まsubprocessれていos.system()ます。

このsubprocessモジュールは、新しいプロセスを生成して結果を取得するためのより強力な機能を提供します。この関数を使用するよりも、そのモジュールを使用する方が適切です。

の問題system()は、明らかにシステムに依存しており、サブプロセスと対話する方法を提供していないことです。単純に実行され、標準出力と標準エラーはPythonの範囲外です。Pythonが受け取る唯一の情報は、コマンドの終了ステータスです(ゼロは成功を意味しますが、ゼロ以外の値の意味もシステムによって多少異なります)。

PEP-324(すでに上で説明されています)には、なぜos.system問題があるのか​​、そしてsubprocessそれらの問題をどのように解決しようとするのかについてのより詳細な根拠が含まれています。

os.popen()かつてはより強く推奨されていませんでした

バージョン2.6で撤廃:この関数は廃止されました。subprocessモジュールを使用します。

ただし、Python 3のある時点から、単にを使用するようsubprocessに再実装され、subprocess.Popen()詳細についてはドキュメントにリダイレクトされます。

理解して通常使用する check=True

またsubprocess.call()、と同じ制限の多くがあることに気づくでしょうos.system()。通常の使用では、一般的にプロセスが正常に終了したかどうかを確認し、その必要があるsubprocess.check_call()subprocess.check_output()(後者はまた、完成したサブプロセスの標準出力を返す場合)を行います。同様に、サブプロセスがエラーステータスを返すことを特に許可する必要がない限り、通常はcheck=Truewithを使用するsubprocess.run()必要があります。

実際には、check=Trueまたはsubprocess.check_*を使用すると、サブプロセスがゼロ以外の終了ステータスを返す場合、PythonはCalledProcessError例外をスローします。

の一般的なエラーsubprocess.run()check=True、サブプロセスが失敗した場合、ダウンストリームコードが省略されて驚いたことです。

一方、一般的な問題check_call()check_output()するときに例外が例えば上げた時に盲目的にこれらの機能を使用するユーザーが驚いたということでしたgrepマッチを見つけることができませんでした。(grepとにかく、以下で説明するように、おそらくネイティブPythonコードに置き換える必要があります。)

カウントされたすべてのものは、シェルコマンドがどのように終了コードを返すかを理解し、どのような条件下で非ゼロ(エラー)の終了コードを返すかを理解し、どのように処理するかを意識的に決定する必要があります。

理解し、おそらくtext=True別名を使用しますuniversal_newlines=True

Python 3以降、Python内部の文字列はUnicode文字列です。ただし、サブプロセスがUnicode出力または文字列を生成するという保証はありません。

(違いがすぐにわからない場合は、Ned BatchelderのPragmatic Unicodeをお勧めします。義務ではないので、読むことをお勧めします。必要に応じて、リンクの後ろに36分のビデオプレゼンテーションがありますが、自分でページを読むのにかかる時間は大幅に短縮されます。 )

深く掘り下げると、Pythonはbytesバッファをフェッチして、なんとかして解釈する必要があります。バイナリデータのblobが含まれている場合、それエラーが発生しやすく、バグを誘発する動作であるため、Unicode文字列にデコードしないください。正確に、多くのPython 2スクリプトをだらだらするような厄介な動作です。エンコードされたテキストとバイナリデータを適切に区別します。

を使用text=Trueすると、実際にはシステムのデフォルトのエンコーディングでテキストデータを予期し、Pythonの能力を最大限に発揮するようにPython(Unicode)文字列にデコードする必要があることをPythonに伝えます(通常、適度に日付システム、おそらくWindowsを除いて?)

それがならないあなたが戻って要求するものを、Pythonはあなたに与えるbytes内の文字列stdoutstderr文字列を。たぶん、いくつかの後の時点で、あなたはない、彼らはすべての後にテキスト文字列だったことを知って、あなたは自分のエンコーディングを知っています。その後、それらをデコードできます。

normal = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True,
    text=True)
print(normal.stdout)

convoluted = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))

Python 3.7では、text以前はやや誤解を招くように呼ばれていたキーワード引数に、より短くて説明的で理解しやすいエイリアスが導入されましたuniversal_newlines

理解shell=Trueshell=False

ではshell=True、あなたのシェルに単一の文字列を渡すと、シェルはそこからそれを取ります。

ではshell=False、あなたのシェルをバイパスし、OSに引数のリストを渡します。

シェルがない場合は、プロセスを保存して、かなりの量の隠れた複雑さを取り除きます。これにより、バグやセキュリティの問題が発生することもあれば、発生しないこともあります。

一方、シェルがない場合、リダイレクト、ワイルドカード拡張、ジョブ制御、およびその他の多数のシェル機能はありません。

よくある間違いは、shell=TruePythonにトークンのリストを使用してから渡すこと、またはその逆です。これは場合によってはうまくいきますが、実際には不明確であり、興味深い方法で壊れる可能性があります。

# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')

# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    shell=True)

# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
    shell=True)

correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    # Probably don't forget these, too
    check=True, text=True)

# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
    shell=True,
    # Probably don't forget these, too
    check=True, text=True)

一般的なレトルト「しかし、それは私にとっては機能します」は、どのような状況で機能しなくなるかを正確に理解しない限り、有用な反論ではありません。

リファクタリングの例

多くの場合、シェルの機能はネイティブのPythonコードで置き換えることができます。単純なAwkまたはsedスクリプトは、おそらく単に代わりにPythonに変換する必要があります。

これを部分的に説明するために、ここに、多くのシェル機能が関係する典型的で少しばかげた例を示します。

cmd = '''while read -r x;
   do ping -c 3 "$x" | grep 'round-trip min/avg/max'
   done <hosts.txt'''

# Trivial but horrible
results = subprocess.run(
    cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)

# Reimplement with shell=False
with open('hosts.txt') as hosts:
    for host in hosts:
        host = host.rstrip('\n')  # drop newline
        ping = subprocess.run(
             ['ping', '-c', '3', host],
             text=True,
             stdout=subprocess.PIPE,
             check=True)
        for line in ping.stdout.split('\n'):
             if 'round-trip min/avg/max' in line:
                 print('{}: {}'.format(host, line))

ここで注意すべきいくつかの点:

  • ではshell=False、あなたのシェルは、文字列の周りに必要であることを引用する必要はありません。とにかく引用符を付けることはおそらくエラーです。
  • 多くの場合、サブプロセスではできるだけ少ないコードを実行することが理にかなっています。これにより、Pythonコード内から実行をより詳細に制御できます。
  • そうは言っても、複雑なシェルパイプラインは退屈で、Pythonでの再実装が困難な場合があります。

リファクタリングされたコードは、非常に簡潔な構文でシェルが実際にどの程度機能するかを示しています。Pythonは、明示的が暗黙的よりも優れていると言いますが、Pythonコードかなり冗長であり、間違いなくこれは実際よりも複雑に見えます。一方、シェルコマンドの出力にホスト名を簡単に含めることができる拡張機能によって簡単に例示されているように、それは他の何かの途中で制御を取得できる多くのポイントを提供します。(これは、シェルで行うことも決して難しいことではありませんが、さらに別の迂回とおそらく別のプロセスを犠牲にして行われます。)

一般的なシェル構造

完全を期すために、これらのシェル機能のいくつかの簡単な説明と、おそらくネイティブPython機能でそれらを置き換える方法についてのいくつかの注意事項を示します。

  • ワイルドカード拡張として知られるグロビングは、のglob.glob()ような単純なPython文字列比較に置き換えることができますfor file in os.listdir('.'): if not file.endswith('.png'): continue。Bashには、.{png,jpg}ブレース展開や{1..100}チルダ展開(~ホームディレクトリに展開され、より一般的~accountには別のユーザーのホームディレクトリに展開される)のような他のさまざまな展開機能があります。
  • $SHELLまたはのようなシェル変数は、$my_exported_var単にPython変数に置き換えることができます。エクスポートされたシェル変数は、たとえばos.environ['SHELL'](変数の意味はexport、サブプロセスで変数を使用できるようにすることです-サブプロセスで使用できない変数は、シェルのサブプロセスとして実行されているPythonでは使用できません。その逆も同様です。env=キーワードメソッドへの引数をsubprocess使用すると、サブプロセスの環境をディクショナリとして定義できるため、Python変数をサブプロセスから見えるようにする1つの方法です)。ではshell=False、引用符を削除する方法を理解する必要があります。たとえば、ディレクトリ名を引用符で囲まないことcd "$HOME"と同じos.chdir(os.environ['HOME'])です。(よくcdとにかく便利でも必要でもありません、そして多くの初心者は変数を囲む二重引用符を省略し、1日までそれを避けます...
  • リダイレクトを使用すると、ファイルから標準入力として読み取り、標準出力をファイルに書き込むことができます。書き込み用と読み取り用にgrep 'foo' <inputfile >outputfile開きoutputfileinputfileその内容を標準入力としてに渡しgrep、その標準出力をに渡しoutputfileます。これは通常、ネイティブのPythonコードで置き換えるのは難しくありません。
  • パイプラインはリダイレクトの一種です。echo foo | nlの標準出力がecho標準入力である2つのサブプロセスを実行しますnl(OSレベルでは、Unixのようなシステムでは、これは単一のファイルハンドルです)。パイプラインの一方または両方の端をネイティブのPythonコードで置き換えることができない場合、特にパイプラインに2つまたは3つを超えるプロセスがある場合は、おそらくシェルの使用を検討してください(ただしpipes、Python標準ライブラリのモジュールまたは番号を見てください)よりモダンで用途の広いサードパーティの競合他社の)。
  • ジョブ制御を使用すると、ジョブを中断したり、バックグラウンドで実行したり、フォアグラウンドに戻したりできます。プロセスを停止して続行するための基本的なUnixシグナルは、もちろんPythonからも使用できます。しかし、ジョブはシェルでのより高いレベルの抽象化であり、Pythonからこのようなことをしたい場合に理解する必要があるプロセスグループなどを含みます。
  • すべてが基本的に文字列であることを理解するまで、シェルでの引用は混乱を招く可能性があります。これls -l /はと同等です'ls' '-l' '/'が、リテラルの引用は完全にオプションです。シェルのメタ文字を含む引用符で囲まれていない文字列は、パラメーターの展開、空白のトークン化、およびワイルドカードの展開を受けます。二重引用符は、空白のトークン化とワイルドカードの展開を防ぎますが、パラメーターの展開(変数置換、コマンド置換、およびバックスラッシュ処理)を許可します。これは理論的には簡単ですが、特に複数の解釈レイヤーがある場合(たとえば、リモートシェルコマンドなど)に戸惑うことがあります。

shとBashの違いを理解する

subprocess/bin/sh特に要求しない限り、シェルコマンドを実行します(もちろん、WindowsではCOMSPEC変数の値を使用します)。つまり、配列[[などのBash専用のさまざまな機能は利用できません。

Bashのみの構文を使用する必要がある場合は、シェルへのパスを渡すことができますexecutable='/bin/bash'(もちろん、Bashが別の場所にインストールされている場合は、パスを調整する必要があります)。

subprocess.run('''
    # This for loop syntax is Bash only
    for((i=1;i<=$#;i++)); do
        # Arrays are Bash-only
        array[i]+=123
    done''',
    shell=True, check=True,
    executable='/bin/bash')

A subprocessはその親から分離されており、変更できません

やや一般的な間違いは次のようなことです

subprocess.run('foo=bar', shell=True)
subprocess.run('echo "$foo"', shell=True)  # Doesn't work

エレガンスの欠如は別として、「サブプロセス」という名前の「サブ」の部分に対する理解の根本的な欠如を裏付けています。

子プロセスはPythonから完全に分離して実行され、終了すると、Pythonはそれが何をしたのかわかりません(終了ステータスと子プロセスからの出力から推測できる漠然としたインジケーターは別として)。子供は通常、親の環境を変更できません。変数を設定したり、作業ディレクトリを変更したりできません。つまり、親からの協力なしに、親と通信することはできません。

この特定のケースでの即時の修正は、単一のサブプロセスで両方のコマンドを実行することです。

subprocess.run('foo=bar; echo "$foo"', shell=True)

ただし、この特定の使用例では、シェルをまったく必要としません。を介して、現在のプロセス(およびその子)の環境を操作できます。

os.environ['foo'] = 'bar'

または環境設定を子プロセスに渡します

subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})

(明白なリファクタリングは言うまでもありませんsubprocess.run(['echo', 'bar'])。しかし、echo当然の最初の場所でサブプロセスで実行するために何かの貧しい人々の一例です)。

PythonからPythonを実行しない

これは少し疑わしいアドバイスです。確かに、PythonスクリプトからサブプロセスとしてPythonインタープリターを実行することが理にかなっている、または絶対的な要件でさえある状況があります。しかし、非常に頻繁に、正しいアプローチはimport、他のPythonモジュールを呼び出してスクリプトに組み込み、その関数を直接呼び出すことです。

他のPythonスクリプトが制御下にあり、それがモジュールではない場合は、1つに変換することを検討してください。(この回答はすでに長すぎるため、ここでは詳しく説明しません。)

並列処理が必要な場合は、multiprocessingモジュールを使用してサブプロセスでPython関数を実行できます。threading単一のプロセスで複数のタスクを実行するもの もあります(より軽量で制御性が向上しますが、プロセス内のスレッドが密結合され、単一のGILにバインドされるため、より制約されます)。


2
Pythonをサブプロセスとして呼び出さないようにする方法の詳細については、接線方向に類似した質問でこの回答を
tripleee

4
質問からコマンドを慣用的に実行する方法を示すために、このような基本的な質問に対する新しい回答を投稿する必要があったことは、私の心を揺さぶります。あなたの答えは長いですが、私はそのような例を見ません。無関係:カーゴカルティングを避けてください。check_call()があなたのケースで機能する場合は、それを使用してください。run()盲目的に使用されたコードを修正する必要がありました。欠落check=Trueはバグを引き起こし、check_callが使用されている場合は回避されます—「check」が名前に含まれているため、それを失うことはありません—これは正しいデフォルトです:エラーを無視して無視しないでください。私はこれ以上読みませんでした。
jfs

1
@jfsフィードバックをありがとう、私は実際にBash vsに関するセクションを追加することを計画してshいましたが、あなたは私をそれに負けました。私はこれらの落とし穴が明らかでない初心者を助けるのに十分詳細に詳細を詳しく述べようとしているので、少し時間がかかります。それ以外の場合は十分です。+1
Tripleee '11

stderr/stdout = subprocess.PIPEデフォルトの設定よりも高いパフォーマンスのオーバーヘッドがありますか?
ストリンガー

1
@Stringers私はテストしていませんが、なぜそうすべきかわかりません。これらのパイプをなんらかの処理を行うものに接続する場合は、当然、その処理を実行する必要があります。しかし、それはパイプ自体では起こりません。デフォルトでは、stdoutやstderrはまったくキャプチャされません。つまり、と同様に、Pythonの可視性と制御の外に出力されるものはキャプチャされませんos.system()
tripleee

41

サブプロセスで呼び出す

import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")

サーバーにスワップモジュールがないため、エラーが発生しているようです。サーバーにスワップをインストールしてから、スクリプトを再度実行してください。


3
swapシェルの作品からのコマンドを実行するためのモジュールは、明らかにそこにあります。
Sven Marnach、2011年

2
サーバー上ではなく、サーバー上で実行するとインポートエラーが発生します。
Jakob Bowyer、2011年

@mkn:「その出力をコピーしてターミナルにコピーして貼り付け、Enterキーを押すだけで動作します...」-サーバーまたはマシンでこれを試しましたか?
Sven Marnach、2010年

スタンドアロンのコンピューターでこれを実行しても問題はありませんが、サーバーで実行すると機能しませんか?それとも、サーバー自体ではなくサーバーターミナルで実行できますか
Jakob Bowyer

1
それは間違っています。使用しない場合はshell=True、リストを使用して複数の引数を渡す必要があります。つまり、の['a', 'b', 'c']代わりに使用します'a b c'> fileただし、コマンドの(シェルリダイレクト)のため、単純な分割は機能しません。詳細
jfs 2018年

18

コマンドを実行するためのパラメーター-cを指定して、bashプログラムを使用することが可能です。

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])

2
subprocess.check_output(bashCommand, shell=True)同じことをします。コマンドが静的文字列の場合は、自分で構文解析してリストにしてみてくださいshell=True。ただし、この場合はリダイレクトにシェルが必要ですが、そうでない場合は純粋なPythonにリファクタリングする必要がありますwith open('test.nt', 'w') as dest: output = subprocess.check_output(['cwm' ,'--rdf', 'test.rdf', '--ntriples'], stdout=dest, shell=False)
tripleee

@tripleee注:(/bin/shサブプロセスで使用)は必ずしも必要ではありませんbash(bashismは使用できません)。executable='/bin/bash必要に応じて使用できますが。ここでのコード例だ
JFS

2
これは、コマンドが正常に開始される最初の回答です(受け入れられた回答と2番目に人気のある回答は間違っています。軽微な問題: check_output()(出力は常にのために空にされ、ここで役に立たない> fileリダイレクト、使用をcheck_call()代わりに。
JFS

16

を使用することはできますsubprocessが、私はいつもそれを「Python的な」やり方ではないと感じていました。そこで、コマンドライン機能を簡単に実行できるSultan(恥知らずなプラグ)を作成しました。

https://github.com/aeroxis/sultan


3
よくやった!サブプロセスよりもはるかにクリーンで直感的です。
mjd2 2018

どうもありがとうございます!私はそれを聞いてうれしいです!
デビッドダニエル

2
これは正直に標準ライブラリに採用されるべきです。
Joshua Detwiler

1
Sultanを使用して端末からの出力をキャプチャする方法はありますか?
alvas

A:はい、あなたはここで@alvasが...それを行う方法についてのドキュメントであることができsultan.readthedocs.io/en/latest/...
デヴィッド・ダニエル

7

エラーによると、サーバーにswapという名前のパッケージがありません。これに/usr/bin/cwmはそれが必要です。Ubuntu / Debian python-swapを使用している場合は、aptitudeを使用してインストールします。


しかし、ターミナルで直接実行すると機能します...したがって、スワップはそこになければなりませんか?
mkn 2010年

2つのオプションがあります。見つからないかswap、そもそもインポートされるべきではありません。import swap手動でできますか?それは機能しますか?
kichik

できません。ターミナルでpythonと入力してpythonを開始し、次にimport swapと入力すると、「ImportError:No swapという名前のモジュール」というエラーが発生します。奇妙なことに、サーバーのターミナルで直接cwmコマンドを実行すると機能します
mkn

機能しているsys.path場所と機能していない場所で印刷してみてください。次に、表示されたフォルダーでswapフォルダーまたはswap.pyを探します。スヴェンが言ったように、それらのパスに問題がある可能性があり、これはそれを理解するのに役立ちます。
kichik

4

また、「os.popen」を使用することもできます。例:

import os

command = os.popen('ls -al')
print(command.read())
print(command.close())

出力:

total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root   77 ago 13 21:53 test.py

None

1
ドキュメントには大きな赤いボックスが含まれています:バージョン2.6で非推奨:この関数は廃止されました。subprocessモジュールを使用してください。」
tripleee

1
公平に言うと、os.popenこの警告はなくなり、subprocess.Popen()現在は単なるラッパーにすぎません。
Tripleee、

4

シェルなしでコマンドを実行するには、コマンドをリストとして渡し、Pythonでリダイレクトを実装し[subprocess]ます。

#!/usr/bin/env python
import subprocess

with open('test.nt', 'wb', 0) as file:
    subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
                          stdout=file)

注:> test.nt最後にはありません。stdout=fileリダイレクトを実装します。


Pythonのシェルを使用してコマンドを実行するには、コマンドを文字列として渡して有効にしshell=Trueます。

#!/usr/bin/env python
import subprocess

subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
                      shell=True)

ここにシェルが出力リダイレクトを担当します(> test.ntコマンドにあります)。


bashismsを使用するbashコマンドを実行するには、bash実行可能ファイルを明示的に指定します。たとえば、bashプロセスの置換エミュレートします

#!/usr/bin/env python
import subprocess

subprocess.check_call('program <(command) <(another-command)',
                      shell=True, executable='/bin/bash')

.split()引用符で囲まれた文字列などがある場合、これは適切ではないかもしれませんshlex.split()。任意に複雑なシェル構文に対処する別のルーチンがあります。
tripleee 2018年

.split()この場合、@ tripleeeが機能します。shlex.split()時々役立ちますが、場合によっては失敗することもあります。言及できることはたくさんあります。上記のサブプロセスタグの説明へのリンクから開始できます。
jfs

0

これを行うpythonicの方法は、 subprocess.Popen

subprocess.Popen 最初の要素が実行されるコマンドであり、その後にコマンドライン引数が続くリストを取得します。

例として:

import subprocess

args = ['echo', 'Hello!']
subprocess.Popen(args) // same as running `echo Hello!` on cmd line

args2 = ['echo', '-v', '"Hello Again"']
subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line

いいえ、最後の例はecho -v '"Hello Again!"'、二重引用符を単一引用符で囲んで実行する場合と同じです。
tripleee

また、を正しく使用subprocesss.Popenするには、結果のプロセスオブジェクトを管理する必要があります(少なくとも、wait()ゾンビプロセスに変換されないようにするには、a を実行します)。
Tripleee、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.