2017-09-11 116 views
0

再次編程與Python DOS批處理命令Python多線程多個bash子進程。但是設置一個環境變量?

有一個偉大的答案Python threading multiple bash subprocesses?

我敢肯定,這將解決我的問題,但我都試過了Popenmultiprocessing方法並且都不起作用。

這是我的問題:我想爲每個進程中使用的Windows環境變量(如TMP)設置一個唯一值。因此,進程1將寫入文件夾1,進程2將寫入文件夾2 - 並且就環境變量而言,進程1不會看到進程2看到的是什麼。我的代碼是answer above。變體1使用Windows set VAR=abc method。 Variant 2使用Python的os.environ['TMP']=abc方法,並且不應該工作,因爲在由dos設置之前,python會訪問TMP。 1和2都不起作用。變體3是一個全面的檢查,以及工作,但並沒有解決我的問題

from subprocess import Popen 
import os 

commands = [ 
    # variant 1: does not work 
    'set TMP=C:\\Temp\\1 && echo abc1 > %TMP%\\1.log', 'set TMP=C:\\Temp\\2 && echo abc2 > %TMP%\\2.log' 

    # variant 2: does not work 
    # 'set TMP=C:\\Temp\\1 && echo abc1 > '+os.environ['TMP']+'\\1.log', 'set TMP=C:\\Temp\\2 && echo abc2 > '+os.environ['TMP']+'\\2.log' 

    # variant 3: works, but does not set TMP environmental variable 
    # 'echo abc1 > C:\\Temp\\1\\1.log', 'echo abc2 > C:\\Temp\\2\\2.log' 
] 

# run in parallel 
processes = [Popen(cmd, shell=True) for cmd in commands] 
# do other things here.. 
# wait for completion 
for p in processes: p.wait() 

這裏是我的multiprocessing方法(Python變量commands在上面的腳本所定義的)代碼:

from functools import partial 
from multiprocessing.dummy import Pool 
from subprocess import call 
import os 

pool = Pool(2) # two concurrent commands at a time 
for i, returncode in enumerate(pool.imap(partial(call, shell=True), commands)): 
    if returncode != 0: 
     print("%d command failed: %d" % (i, returncode)) 

(我也嘗試set TMP=\"C:\\Temp\\1\"與文件夾周圍雙引號)

((Python的2.7.13 64位的Windows 10))


並沒有涉及到我參考答案,我試過這個功能:

import os 
from subprocess import check_output 

def make_tmp(tmp_path): 

    os.environ['TMP'] = tmp_path 
    dos = 'echo '+tmp_path+' > '+os.environ['TMP']+'\\output.log' 
    check_output(dos, shell=True) 


from multiprocessing.dummy import Pool as ThreadPool 
pool = ThreadPool(2) 

print os.environ['TMP'] 
path_array = ['\"C:\\Temp\\1\"', '\"C:\\Temp\\2\"'] 

用下面的回溯:

Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.* 
Traceback (most recent call last): 
    File "C:\Users\project11\Dropbox\project11\code_current\dev_folder\google_sheets\test_windows_variables.py", line 32, in <module> 
    results = pool.map(make_tmp, path_array) 
    File "C:\ProgramData\Anaconda2\lib\multiprocessing\pool.py", line 251, in map 
    return self.map_async(func, iterable, chunksize).get() 
    File "C:\ProgramData\Anaconda2\lib\multiprocessing\pool.py", line 567, in get 
    raise self._value 
subprocess.CalledProcessError: Command 'echo "C:\Temp\1" > "C:\Temp\2"\output.log' returned non-zero exit status 1 

*該進程無法訪問該文件因爲它正在被另一個進程使用。


也試過another answer to the same question,沒有運氣。

+1

你想使你的電話之前更新您的環境,然後使用'POPEN更新後的環境()'在https://stackoverflow.com/questions/2231227/python-subprocess-popen-with-a看到修改環境 – JohanL

+0

謝謝。我想修改os.environ [「TMP」]在這個過程中 - 所以我想你參考答案將無法正常工作 – philshem

+0

OK,你爲什麼要這麼做?要在原始程序中使用更新的值?因爲這不能通過使用子過程來完成。 – JohanL

回答

1

這裏是工作的代碼,這要歸功於ChepnerJohanL評論

import subprocess, os 

def make_tmp(tmp_path): 

    my_env = os.environ.copy() 
    my_env['TMP'] = tmp_path 
    dos = 'echo '+tmp_path[-1]+' > '+my_env['TMP']+'\\output.log' 
    # or run a bat script 
    # dos = 'C:\\Temp\\launch.bat' 
    subprocess.Popen(dos, env=my_env, stdout=subprocess.PIPE, shell=True) 

from multiprocessing.dummy import Pool as ThreadPool 
pool = ThreadPool(2) 

path_array = ['C:\\Temp\\1', 'C:\\Temp\\2', 'C:\\Temp\\3'] 

results = pool.map(make_tmp, path_array) 

注意,path_array必須被現有的文件夾

+0

這應該不需要'subprocess.PIPE',雖然。這在Python本身中是更好的(然後,它將需要'subprocess.PIPE',而不是'shell = True')。 – JohanL

1

如果你的使用情況是隻輸出捕獲到文件,你可以讓Python爲你做,通過將命令輸出重定向到subprocess.PIPE,然後存儲來自Python的數據。這樣做的好處是您不需要使用shell=True,從而爲您自己節省一個可能的漏洞並創建額外的流程。這可以寫成:

import subprocess, os 

def make_tmp(tmp_path): 
    dos = ['echo', tmp_path[-1]] 
    outfile = os.path.join(tmp_path, 'output.log') 
    cmd_proc = subprocess.Popen(dos, stdout=subprocess.PIPE) 
    with open(outfile, 'w') as f: 
     f.write(cmd_proc.communciate[0]) 

from multiprocessing.dummy import Pool as ThreadPool 
pool = ThreadPool(2) 

path_array = ['C:\\Temp\\1', 'C:\\Temp\\2', 'C:\\Temp\\3'] 

results = pool.map(make_tmp, path_array) 

警告:我還沒有測試上面的代碼的時候,所以可能會有一些小錯誤。

+0

感謝您的回答。實際上,echo是一個測試用例,並且完整的python腳本環繞一個Windows可執行文件,該文件將臨時文件data.bin寫入TMP文件夾。我想運行這個Windows可執行文件的多個進程,但它們都引用相同的TMP文件夾和data.bin文件。這就是爲什麼我想更新每個流程的TMP。 – philshem

相關問題