2016-10-12 20 views
0

フォルダをループするPythonスクリプトがあり、ファイルごとにシェルコマンドが作成されます。サブプロセスを使用してシェルスクリプトを呼び出すと、シェルスクリプト内のすべてのコマンドが実行されない

各コマンドはシェルスクリプトに書き込まれ、このスクリプトはsubprocess.Popenを使用して実行されます。 (コマンドを実行する前に環境を設定する必要があるため、これを行う必要があります)。ここで

は、いくつかの擬似コードです:私はこのPythonスクリプトを実行すると

def create_shell_script(self): 
    '''loop through a folder, create a command for each file and write this to a shell script''' 
    # command to run 
    base_command="run this" 

    #list of files 
    command_list=[] 

    #loop through the files to create a folder 
    for file in my_folder: 
     command_list.append(base_command+" "+file) 

    # open the shell script 
    scriptname="shell.sh" 
    shellscript = open(scriptname,'w') 
    # set the environment using '.' as using bash below to run shell script 
    shellscript.write("#!/bin/bash\n. /etc/profile.d/set_environment\n") 

    #loop through commands and write to shellscript 
    for command in command_list: 
     shellscript.write(command+"\n") 

    # use subprocess to run the shell script. Use bash to interpret the environment 
    cmd="bash "+scriptname 
    proc = subprocess.Popen([cmd], stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=True) 

のみシェルスクリプト内で最初の6つのコマンドが実行されます。コマンドからのエラーメッセージは、コマンドがサブプロセスによって読み取られるときに切り捨てられることを示しています。

シェルスクリプトを手動で実行すると、すべてのコマンドが期待通りに実行されるので、シェルスクリプトが正しいことがわかります。

各コマンドはかなり瞬時ですが、問題の原因となるスピードは想像できません。

ファイルごとにサブプロセスコマンドを実行しようとしましたが、環境を設定するのが難しくなりました。ログファイルとしても機能するため、単一のshスクリプトを作成するアプローチが好きです。

私はサブプロセスのドキュメントを読んだことがありますが、何も発見されておらず、Googleは助けにはなりませんでした。

+0

は、ファイルへの書き込み後、それを実行する前に、シェルスクリプトファイルオブジェクトを閉じてみました:

最もエレガントな解決策は、ファイルを自動的に閉じコンテキストマネージャを使用することですか?そうしないと、実行時にファイルが完全に書き込まれないことがあります。 –

+0

それはそれを修正!ありがとうございました。あなたが答えとしてそれを追加するなら、私はそれを受け入れられたものとしてマークします – aledj2

答えて

2

shellscriptファイルオブジェクトは、コマンドを書き込んだ後、Popenで実行する前に閉じてください。そうしないと、ファイルを実行する前に完全に書き込まれないことがあります。

with open(scriptname, "w") as f: 
    f.write(...) 
2

何をするのかわからない場合はPopenを使用しないでください。 はプロセスをに作成しますが、追加の手順を実行するまで完了するとは限りません。

あなたはおそらく、subprocess.check_callを探しています。また、ファイルにコマンドを格納することは不要で、やや脆弱です。 subprocess.check_call(['bash', '-c', string_of_commands)を実行してください。ここで、string_of_commandsには改行またはセミコロンで区切られたコマンドがあります。

したいかPopenを使用する必要がない場合は、Popenオブジェクト上communicate()または少なくともwait()を呼び出す必要があります。

最後に、コマンドのリストを渡す場合はshell=Trueを避けてください。シェルの目的は、文字列引数を解析することであり、既に完了しているか、必要でない場合は何もしません(有用)。

ここでは、スクリプトをリファクタリングする試みがあります。

def create_shell_script(self): 
    '''loop through a folder, create a command for each file and write this to a shell script''' 

    command_list=['. /etc/profile.d/set_environment']  
    for file in my_folder: 
     command_list.append("run this "+file) 

    subprocess.check_call(['bash', '-c', ''.join(command_list)], 
     stderr=subprocess.PIPE, stdout=subprocess.PIPE) 

あなたはcheck_callは、個々のコマンドのいずれかのエラーをキャッチ-eオプションで渡すか、失敗する(しかし、多くの無実に見えるの構築物は技術的にエラーが発生していることに注意してはいけないコマンドの前set -eを含める場合例えば、falseまたはgrep nomatch file)。

the subprocess moduleにおける機能の大半は、使用して舞台裏Popenオブジェクトを操作するシンプルなラッパーです。あなたのシナリオに適した他の関数がない場合は、基本的なPopenに頼るだけです。

あなたは本当に、おそらくあなたがPopenが必要です、stderrstdoutの両方を必要とするが、その後、あなたの質問は、あなたのプログラムは、シェルの入力と出力を操作する方法を正確に記述する必要がある場合。

関連する問題