当subprocess.Popen(args, shell=True)
用于运行" gcc --version
"(仅作为示例)时,在Windows上我们得到:
>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc (GCC) 3.4.5 (mingw-vista special r3) ...
Run Code Online (Sandbox Code Playgroud)
因此,按照我的预期很好地打印出版本.但是在Linux上我们得到了这个:
>>> from subprocess import Popen
>>> Popen(['gcc', '--version'], shell=True)
gcc: no input files
Run Code Online (Sandbox Code Playgroud)
因为gcc还没有收到--version
选项.
文档没有明确指出Windows下args应该发生什么,但它确实说,在Unix上,"如果args是一个序列,第一个项目指定命令字符串,任何其他项目将被视为额外的shell参数".恕我直言,Windows方式更好,因为它允许您将Popen(arglist)
呼叫视为Popen(arglist, shell=True)
一个.
为什么Windows和Linux之间存在差异?
众所周知的创建fstream
对象的方法是:
ifstream fobj("myfile.txt");
Run Code Online (Sandbox Code Playgroud)
即.使用文件名.
但我想使用文件描述符创建一个ifstream对象.
原因:我想使用执行命令
_popen()
._popen()
将输出返回为FILE*
.所以有一个FILE*指针涉及但没有文件名.
我想通过python程序调用一个进程,但是,这个进程需要一些由另一个进程设置的特定环境变量.如何获取第一个进程环境变量以将它们传递给第二个?
这就是程序的样子:
import subprocess
subprocess.call(['proc1']) # this set env. variables for proc2
subprocess.call(['proc2']) # this must have env. variables set by proc1 to work
Run Code Online (Sandbox Code Playgroud)
但是进程不共享相同的环境.请注意,这些程序不是我的(第一个是大而丑陋的.bat文件,第二个是专有软件)所以我无法修改它们(好吧,我可以从.bat中提取我需要的所有东西,但它非常简洁).
注意:我使用的是Windows,但我更喜欢跨平台的解决方案(但我的问题不会发生在类似Unix的问题上......)
我想在使用管道从python脚本启动的独立应用程序中执行多个命令.我能够可靠地将命令传递给程序的stdin的唯一方法是使用Popen.communicate,但它会在命令执行后关闭程序.如果我使用Popen.stdin.write而不是命令只执行5次左右,那么它就不可靠.我究竟做错了什么?
详细说明:
我有一个应用程序,它监听stdin的命令并逐行执行它们.我希望能够运行应用程序并根据用户与GUI的交互向其传递各种命令.这是一个简单的测试示例:
import os, string
from subprocess import Popen, PIPE
command = "anApplication"
process = Popen(command, shell=False, stderr=None, stdin=PIPE)
process.stdin.write("doSomething1\n")
process.stdin.flush()
process.stdin.write("doSomething2\n")
process.stdin.flush()
Run Code Online (Sandbox Code Playgroud)
我希望看到两个命令的结果,但我没有得到任何回应.(如果我多次执行其中一条Popen.write行,它偶尔会有效.)
如果我执行:
process.communicate("doSomething1")
Run Code Online (Sandbox Code Playgroud)
它完美地工作但应用程序终止.
我正在用C++(主要是C)在模拟文件系统上实现管道.它需要在主机shell中运行命令,但在模拟文件系统上执行管道本身.
我可以与实现这一目标pipe()
,fork()
和system()
系统调用,但我宁愿使用popen()
(它处理创建一条管道,把一个进程,并通过一个命令外壳).这可能是不可能的,因为(我认为)我需要能够从管道的父进程写入,在子进程结束时读取,从子进程写回输出,最后从父进程读取该输出.popen()
我的系统上的手册页说明了双向管道,但是我的代码需要在一个只支持单向管道的旧版本的系统上运行.
通过上面的单独调用,我可以打开/关闭管道来实现这一目标.这有可能popen()
吗?
对于一个简单的例子,要运行ls -l | grep .txt | grep cmds
我需要:
ls -l
在主机上运行进程; 读回它的输出ls -l
传回我的模拟器grep .txt
在管道输出上的主机上运行ls -l
grep cmds
在管道输出上的主机上运行grep .txt
男人popen
从Mac OS X:
该
popen()
函数通过创建双向管道,分叉和调用shell来"打开"一个过程.由popen()
父进程中先前调用打开的任何流都将在新的子进程中关闭.历史上,popen()
使用单向管道实施; 因此,许多实现popen()
只允许mode参数指定读或写,而不是两者.因为popen()
现在使用双向管道实现,mode参数可以请求双向数据流.mode参数是一个指向以null结尾的字符串的指针,该字符串必须为'r'表示读取,'w'表示写入,或'r +'表示读写.
当subprocess.Popen()
我使用线程让我们同时运行它们从我的python脚本生成同一个应用程序的几个实例时,我遇到了一些问题.在每个线程中,我使用popen()
调用运行应用程序,然后我等待它通过调用完成wait()
.问题似乎是wait()
-call实际上并不等待进程完成.我只使用一个线程进行实验,并在进程启动时和完成时打印出文本消息.所以线程函数看起来像这样:
def worker():
while True:
job = q.get() # q is a global Queue of jobs
print('Starting process %d' % job['id'])
proc = subprocess.Popen(job['cmd'], shell=True)
proc.wait()
print('Finished process %d' % job['id'])
job.task_done()
Run Code Online (Sandbox Code Playgroud)
但即使我只使用一个线程,它也会在出现任何"完成进程..."消息之前打印出几个"正在启动进程..."消息.有wait()
没有实际上没有等待的情况?我有几个不同的外部应用程序(C++控制台应用程序),它们将同时运行多个实例,对于其中一些我的代码可以工作,但对于其他实例,它不会.外部应用程序是否存在某些问题会以某种方式影响调用wait()
?创建线程的代码如下所示:
for i in range(1):
t = Thread(target=worker)
t.daemon = True
t.start()
q.join() # Wait for the queue to empty
Run Code Online (Sandbox Code Playgroud)
更新1:我还应该补充一点,对于某些外部应用程序,我有时会得到proc.returncode
-1073471801 的返回码().例如,其中一个外部应用程序将给出前两次Popen
调用的返回代码,但不是后两个(当我有四个作业时).
更新2:为了清理,现在我在队列中有四个作业,这是四个不同的测试用例.当我运行我的代码时,对于其中一个外部应用程序,前两个 - Popen
调用生成返回代码-1073471801.但是如果我打印出Popen
调用的确切命令,并在命令窗口中运行它,它会毫无问题地执行.
解决了! 我设法解决了我遇到的问题.我认为问题在于我缺乏线程编程的经验.我错过了这样一个事实:当我创建了我的第一个工作线程时,他们会一直活着直到python脚本退出.错误的是,每次我将新项目放入队列时,我都会创建更多的工作线程(我会为每个要运行的外部程序批量执行此操作).所以当我进入第四个外部应用程序时,我有四个线程同时运行,即使我只认为我有一个.
我有以下大量的Python代码(运行v2.7)导致在MemoryError
处理大(几GB)文件时抛出异常:
myProcess = Popen(myCmd, shell=True, stdout=PIPE, stderr=PIPE)
myStdout, myStderr = myProcess.communicate()
sys.stdout.write(myStdout)
if myStderr:
sys.stderr.write(myStderr)
Run Code Online (Sandbox Code Playgroud)
在阅读文档时Popen.communicate()
,似乎有一些缓冲:
注意读取的数据缓冲在内存中,因此如果数据大小很大或不受限制,请不要使用此方法.
有没有办法禁用此缓冲,或强制缓存在进程运行时定期清除?
我应该在Python中使用什么替代方法来运行将千兆字节数据流式传输到的命令stdout
?
我应该注意,我需要处理输出和错误流.
我可以成功地将输出重定向到文件,但是这似乎覆盖了文件的现有数据:
import subprocess
outfile = open('test','w') #same with "w" or "a" as opening mode
outfile.write('Hello')
subprocess.Popen('ls',stdout=outfile)
Run Code Online (Sandbox Code Playgroud)
将从'Hello'
文件中删除该行.
我想一个解决方法是将输出存储在别处作为字符串或其他东西(它不会太长),并手动附加outfile.write(thestring)
- 但我想知道我是否遗漏了模块内的一些方便这一点.
我试图使用Python函数计算文件中的行数.在当前目录中,当os.system("ls")
找到文件时,命令subprocess.Popen(["wc -l filename"], stdout=subprocess.PIPE
)不起作用.
这是我的代码:
>>> import os
>>> import subprocess
>>> os.system("ls")
sorted_list.dat
0
>>> p = subprocess.Popen(["wc -l sorted_list.dat"], stdout=subprocess.PIPE)File "<stdin>", line 1, in <module>
File "/Users/a200/anaconda/lib/python2.7/subprocess.py", line 710, in __init__
errread, errwrite)
File "/Users/a200/anaconda/lib/python2.7/subprocess.py", line 1335, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Run Code Online (Sandbox Code Playgroud) 说我有两个文件:
# spam.py
import library_Python3_only as l3
def spam(x,y)
return l3.bar(x).baz(y)
Run Code Online (Sandbox Code Playgroud)
和
# beans.py
import library_Python2_only as l2
...
Run Code Online (Sandbox Code Playgroud)
现在假设我想spam
从内部打电话beans
.这不是直接可能的,因为两个文件都依赖于不兼容的Python版本.当然我可以Popen
使用不同的python进程,但是如何在没有太多流解析的情况下传入参数并检索结果呢?