如何使用Python subprocess
模块执行以下shell命令?
echo "input data" | awk -f script.awk | sort > outfile.txt
输入数据将来自一个字符串,所以我实际上并不需要echo
.我已经走到这一步了,任何人都可以解释我是如何通过它来解决的sort
吗?
p_awk = subprocess.Popen(["awk","-f","script.awk"], stdin=subprocess.PIPE, stdout=file("outfile.txt", "w")) p_awk.communicate( "input data" )
更新:请注意,虽然下面接受的答案实际上没有回答问题,但我相信S.Lott是对的,最好避免首先解决这个问题!
你会对以下内容感到高兴.
import subprocess awk_sort = subprocess.Popen( "awk -f script.awk | sort > outfile.txt", stdin=subprocess.PIPE, shell=True ) awk_sort.communicate( b"input data\n" )
将部分工作委托给shell.让它用管道连接两个进程.
你可以更快乐地将'script.awk'改写成Python,消除awk和管道.
编辑.提出awk没有帮助的一些原因.
[有太多理由通过评论回复.]
Awk正在增加一个没有重大价值的步骤.关于awk的处理没有什么独特之处,Python无法处理.
对于大型数据集,从awk到sort的流水线操作可以改善经过的处理时间.对于短数据集,它没有显着的好处.快速测量awk >file ; sort file
和awk | sort
显示并发性有助于.使用sort,它很少有用,因为sort不是一次性过滤器.
"Python to sort"处理的简单性(而不是"Python to awk to sort")可以防止这里提出的确切类型的问题.
Python - 虽然比awk更啰嗦 - 也是明确的,其中awk具有某些隐含的规则,这些规则对新手不透明,并且对非专业人员造成混淆.
awk(就像shell脚本本身一样)添加了另一种编程语言.如果所有这些都可以用一种语言(Python)完成,那么取消shell和awk编程就会消除两种编程语言,允许某人专注于任务的价值生成部分.
底线:awk无法增加重要价值.在这种情况下,awk是净成本; 它增加了足够的复杂性,有必要提出这个问题.删除awk将是一个净收益.
侧边栏为什么构建管道(a | b
)非常困难.
当shell遇到a | b
它时,必须执行以下操作.
fork原始shell的子进程.这最终将成为b.
构建一个os管道.(不是Python subprocess.PIPE)但调用os.pipe()
返回两个通过公共缓冲区连接的新文件描述符.此时,进程具有来自其父级的stdin,stdout,stderr,以及将是"a的stdout"和"b的stdin"的文件.
叉一个孩子.孩子用新的标准替换它的标准输出.执行该a
过程.
b子关闭用新b的标准输入替换其标准输入.执行该b
过程.
b孩子等待a完成.
父母正在等待b完成.
我认为上面的内容可以递归地用于生成a | b | c
,但是你必须隐式地将长管道括起来,将它们视为它们a | (b | c)
.
因为Python有os.pipe()
,os.exec()
并且os.fork()
你可以替换,sys.stdin
并且sys.stdout
有一种方法可以在纯Python中执行上述操作.实际上,您可以使用os.pipe()
和编写一些快捷方式subprocess.Popen
.
但是,将该操作委托给shell更容易.
import subprocess some_string = b'input_data' sort_out = open('outfile.txt', 'wb', 0) sort_in = subprocess.Popen('sort', stdin=subprocess.PIPE, stdout=sort_out).stdin subprocess.Popen(['awk', '-f', 'script.awk'], stdout=sort_in, stdin=subprocess.PIPE).communicate(some_string)
要模拟shell管道:
from subprocess import check_call check_call('echo "input data" | a | b > outfile.txt', shell=True)
不调用shell(参见17.1.4.2.替换shell管道):
#!/usr/bin/env python from subprocess import Popen, PIPE a = Popen(["a"], stdin=PIPE, stdout=PIPE) with a.stdin: with a.stdout, open("outfile.txt", "wb") as outfile: b = Popen(["b"], stdin=a.stdout, stdout=outfile) a.stdin.write(b"input data") statuses = [a.wait(), b.wait()] # both a.stdin/stdout are closed already
plumbum
提供一些语法糖:
#!/usr/bin/env python from plumbum.cmd import a, b # magic (a << "input data" | b > "outfile.txt")()
类比:
#!/bin/sh echo "input data" | awk -f script.awk | sort > outfile.txt
是:
#!/usr/bin/env python from plumbum.cmd import awk, sort (awk["-f", "script.awk"] << "input data" | sort > "outfile.txt")()