在python中运行shell命令并读取输出
我有以下资料:在python中运行shell命令并读取输出,python,unix,Python,Unix,我有以下资料: cmd = "ps aux | grep 'java -jar' | grep -v grep | awk '//{print $2}'".split(' ') p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() print out 当我在控制台(python之外)中运行该命令时,我得到了所需的输出。在python中运行上述代码将
cmd = "ps aux | grep 'java -jar' | grep -v grep | awk '//{print $2}'".split(' ')
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
print out
当我在控制台(python之外)中运行该命令时,我得到了所需的输出。在python中运行上述代码将打印一个空行。我假设cmd
(特别是|
操作符)有问题,但我不能确定
我需要通过标准的Python 2.6.6安装(无其他模块)来实现这一点。您需要对原始命令的每一部分使用单个调用
Popen()
,如中所示
import subprocess
p1 = subprocess.Popen(["ps", "aux"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen(["grep", "java -jar"], stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p3 = subprocess.Popen(["grep", "-v", "grep"], stdin=p2.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p4 = subprocess.Popen(["awk", "//{print $2}"], stdin=p3.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p4.communicate()
print out
有一个深入的讨论。shell管道中只有一个命令,Python代码很难替换它。因此,您可以启动几个外部进程并连接它们的输入和输出,但我只需要启动
ps aux
,并添加一些Python代码来过滤和提取所需的数据:
from subprocess import PIPE, Popen
def main():
process = Popen(['ps', 'aux'], stdout=PIPE)
pids = [
line.split(None, 2)[1] for line in process.stdout if 'java -jar' in line
]
process.wait()
print '\n'.join(pids)
if __name__ == '__main__':
main()
Popen
默认情况下只执行可执行文件,不执行shell命令行。
当您将参数列表传递给Popen
时,它们应该调用one可执行文件及其参数:
import subprocess
proc = subprocess.Popen(['ps', 'aux'])
还请注意,您不应使用str.split
分割命令,因为:
>>> "ps aux | grep 'java -jar' | grep -v grep | awk '//{print $2}'".split(' ')
['ps', 'aux', '|', 'grep', "'java", "-jar'", '', '', '', '', '|', 'grep', '-v', 'grep', '|', 'awk', "'//{print", "$2}'"]
请注意:
- 引用的参数(例如,
被拆分'java-jar')
- 如果有多个连续空格,则会得到一些空参数
Popen
,因为Popen
将不默认情况下将|
解释为管道
如果要运行shell命令行(即使用任何shell功能,如管道、路径扩展、重定向等),必须传递shell=True
。在这种情况下,您应该不将字符串列表作为参数传递给Popen
,而只传递一个作为完整命令行的字符串:
proc = subprocess.Popen("ps aux | grep 'java -jar' | grep -v grep | awk '//{print $2}'", shell=True)
如果使用shell=True
传递字符串列表,其含义不同:第一个元素应该是完整的命令行,而其他元素作为选项传递给所使用的shell。例如,在我的机器上,默认shell(sh
)有一个-x
选项,该选项将显示在stderr
上执行的所有进程:
>>> from subprocess import Popen
>>> proc = Popen(['ps aux | grep python3', '-x'], shell=True)
>>>
username 7301 0.1 0.1 39440 7408 pts/9 S+ 12:57 0:00 python3
username 7302 0.0 0.0 4444 640 pts/9 S+ 12:58 0:00 /bin/sh -c ps aux | grep python3 -x
username 7304 0.0 0.0 15968 904 pts/9 S+ 12:58 0:00 grep python3
在这里,您可以看到启动了一个执行命令的/bin/sh
,该命令带有-x
选项
(这些都记录在的文档中)
也就是说,实现目标的一种方法是:
但是,这在python中不可用如果您的操作系统提供了pgrep命令,则可能的副本将不可用,使用该命令比以这种方式过滤ps的输出要好得多。可能的副本显然不是副本-具体问题是管道操作符。
>>> from subprocess import Popen
>>> proc = Popen(['ps aux | grep python3', '-x'], shell=True)
>>>
username 7301 0.1 0.1 39440 7408 pts/9 S+ 12:57 0:00 python3
username 7302 0.0 0.0 4444 640 pts/9 S+ 12:58 0:00 /bin/sh -c ps aux | grep python3 -x
username 7304 0.0 0.0 15968 904 pts/9 S+ 12:58 0:00 grep python3
subprocess.check_output("ps aux | grep 'java -jar' | grep -v grep | awk '//{print $2}'", shell=True)
proc = subprocess.Popen("ps aux | grep 'java -jar' | grep -v grep | awk '//{print $2}'", shell=True, stdout=subprocess.PIPE)
out, err = proc.communicate()
from subprocess import Popen, PIPE
ps = Popen(['ps', 'aux'], stdout=PIPE)
grep_java = Popen(['grep', 'java -jar'], stdin=ps.stdout, stdout=PIPE)
grep_grep = Popen(['grep', '-v', 'grep'], stdin=grep_java.stdout, stdout=PIPE)
awk = Popen(['awk', '//{print $2}'], stdin=grep_grep.stdout, stdout=PIPE)
out, err = awk.communicate()
grep_grep.wait()
grep_java.wait()
ps.wait()