![](/img/trans.png)
[英]Python: Exporting environment variables in subprocess.Popen(..)
[英]Python - Using variables in subprocess.Popen command
我是編碼新手,需要一些幫助。 我正在編寫一個python腳本,它將遍歷目錄的內容,並在遍歷目錄時將每個文件發送到Bluetooth設備。
如果我指定文件名,它可以很好地工作,但是我不能通過使用文件名作為變量來使其工作。 這是下面的代碼
import os
import time
import subprocess
indir = '\\\\10.12.12.218\\myshare'
for root, dirs, filenames in os.walk(indir):
for file in filenames:
print (file)
subprocess.Popen('ussp-push /dev/rfcomm0 image1.jpg file.jpg', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print ('end')
我試圖將命令中的“ image1.jpg”替換為變量“ file”,如下所示,但未成功。
subprocess.Popen('ussp-push /dev/rfcomm0', file, 'file.jpg', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
會非常感謝您的幫助。
有幾個問題:
shell=True
是不必要的。 刪除它並使用列表參數:
import shlex args = shlex.split('ussp-push /dev/rfcomm0 image1.jpg file.jpg')
您試圖將命令行參數作為Popen
單獨參數傳遞。 使用Popen(['echo', 'a'])
代替Popen('echo', 'a')
。 后者是完全錯誤的。 請參閱文檔中的Popen()
函數簽名
除非您從p.stdout
/ p.stderr
管道讀取,否則請勿使用stdout=PIPE
和/或stderr=PIPE
否則,如果子進程填充了任何OS管道緩沖區,則子進程可能會永遠阻塞
保存對Popen()
的引用,以稍后等待其狀態。 它是可選的,但有助於避免創建過多的僵屍
您可以將文件生成部分提取到單獨的函數中:
import os
def get_files(indir, extensions=('.jpg', '.png')):
"""Yield all files in `indir` with given `extensions` (case-insensitive)."""
for root, dirs, files in os.walk(indir):
for filename in files:
if filename.casefold().endswith(extensions):
yield os.path.join(root, filename)
然后並行執行每個文件的命令:
from subprocess import CalledProcessError, Popen
indir = r'\\10.12.12.218\myshare'
commands = [['ussp-push', '/dev/rfcomm0', path] for path in get_files(indir)]
# start all child processes
children = [Popen(cmd) for cmd in commands]
# wait for them to complete, raise an exception if any of subprocesses fail
for process, cmd in zip(children, commands):
if process.wait() != 0:
raise CalledProcessError(process.returncode, cmd)
如果您不想並行運行命令,則只需使用subprocess.call
而不是subprocess.Popen
:
import subprocess
indir = r'\\10.12.12.218\myshare'
statuses = [subprocess.call(['ussp-push', '/dev/rfcomm0', path])
for path in get_files(indir)]
if any(statuses):
print('some commands have failed')
它一次運行一個命令。
嘗試這個:
subprocess.Popen(
['ussp-push', '/dev/rfcomm0', file, 'file.jpg'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
您想將一個字符串列表傳遞給Popen()
。 一種替代方法是構建一個空格分隔的命令,例如:
subprocess.Popen(
'ussp-push /dev/rfcomm0 "{0}" file.jpg'.format(file) # replace {0} with file
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
關於shell=True
的使用,我想提出幾點。
shell=True
是不安全的。 例如,如果您從用戶輸入中獲取命令,那么用戶可以向您傳遞諸如sudo rm -fr /
。 PATH
可能會有所不同。 當發出ls
的命令時,它可能不是來自通常的位置( /bin/ls
),而是來自一些惡意的位置,例如/home/evil/bin
話雖如此,如果您可以控制命令(在這種情況下為/dev/rfcomm0
,則shell=True
是安全的-您可以定義命令的/dev/rfcomm0
,而不是從其他位置接收命令。 謝謝m.wasowski提出這一點。
刪除shell=True
。 看評論。
因此,有一堆文件,您希望以每個文件為參數運行一次命令。 我認為以下方法應該可以正常工作。
import os
import time
import subprocess
indir = '\\\\10.12.12.218\\myshare'
for root, dirs, filenames in os.walk(indir):
for file in filenames:
print 'Sending', os.path.join(root, file)
subprocess.check_call(['ussp-push', '/dev/rfcomm0', os.path.join(root, file), 'file.jpg'])
print ('end')
這是我所做的更改:
check_call
函數,而不是Popen
如你想在並行順序,而不是運行命令。 該check_call
函數有相同的參數Popen
,而是等待進程完成,如果過程失敗,會引發異常。 check_call
命令。 這也意味着不需要外殼程序來解釋命令字符串,因此我刪除了shell=True
。 該數組中的第一項是命令,其余是傳遞給它的命令。 file
變量僅保存文件名。 但是我們需要它的路徑,因為它可能位於文件夾內的某個深處(當您遞歸walk
)。 os.path.join
在平台中使用\\
或/
連接兩個字符串。 stdout
和stderr
參數。 這意味着命令的輸出和錯誤將在命令行中出現,這可能是您想要的。 當您想讀取命令的輸出並自己處理而不是在終端中顯示時, stdout
和stderr
參數才有意義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.