3

我有一个很长的单行 shell 命令要由 Python 调用。代码是这样的:

# "first way"
def run_cmd ( command ):
    print "Run: %s" % command
    subprocess.call (command, shell=True)
run_cmd('''sort -n -r -k5 {3} |head -n 500|awk 'OFS="\t"{{if($2-{1}>0){{print $1,$2-{1},$3+{1},$4,$5}}}}' > {2}'''.format(top_count,extend/2,mid,summit))

这些代码有效,但它总是这样抱怨:

sort: write failed: standard output: Broken pipe
sort: write error
awk: (FILENAME=- FNR=132) fatal: print to "standard output" failed (Broken pipe)

根据先前的答案,我需要使用更长的脚本来完成此操作,例如:

# "second way"
p1 = Popen("sort -n -r -k5 %s"%summit, stdout=PIPE)
p2 = Popen("head -n 500", stdin=p1.stdout, stdout=PIPE)
# and so on ..........

我的问题是:

(1)“第二种方式”是否会比“第一种方式”慢

(2)如果我必须以“第一种方式”写(因为写起来更快),我怎样才能避免像这样的抱怨broken pipe

(3) 我不应该以“第一方式”写作的最令人信服的理由是什么

4

3 回答 3

5

shell = True如果您的输入数据来自不受信任的来源,则使用可能会带来安全风险。例如,如果您的mid变量的内容是"/dev/null; rm -rf /". 在您的情况下似乎并非如此,所以我不会太担心。

在您的代码中,您将结果awk直接写入mid. 要调试问题,您可能需要在 python 程序中使用subprocess.check_output并读取调用的结果。awk

cmd = """sort -n -r -k5 %s |
      head -n 500|
      awk 'OFS="\t"{{if($2-{1}>0){{print $1,$2-{1},$3+{1},$4,$5}}}}'""".format(summit, top_count)

subprocess.check_call(cmd, shell=True, stdout=file)
于 2012-11-21T11:06:26.297 回答
2

(1)“第二种方式”是否会比“第一种方式”慢

启动一个新进程是一项昂贵的操作,因此在允许 shell 解析命令行并启动子进程与在 Python 中自己执行之间应该没有太大区别。唯一重要的基准是硬件上的代码。测量它。

(2)如果我必须以“第一种方式”写(因为写起来更快),我怎样才能避免像破管子一样的抱怨

第一个“损坏的管道”可能类似于:“是”报告错误与子进程通信()。尝试我在那里提供的解决方法

您可以通过将管道标准输出重定向到mid文件来修复第二个损坏的管道:

with open(mid, 'wb') as file:
    check_call(pipeline, shell=True, stdout=file)

> {2}在没有外壳的情况下在您的命令中实现。

(3) 我不应该以“第一方式”写作的最令人信服的理由是什么

如果任何top_count, extend, mid,summit来自不完全由您控制的来源,那么您就有可能在您的用户下运行任意命令。


plumbum模块提供安全性和可读性(如果在这种情况下对您很重要,请测量时间性能):

from plumbum.cmd import awk, head, sort

awk_cmd = 'OFS="\t"{if($2-%s>0){print $1,$2-%s,$3+%s,$4,$5}}' % (extend/2,)*3
(sort["-n", "-r", "-k5", summit] | head["-n", "500"] | awk[awk_cmd] > mid)()

请参阅,如何使用 subprocess.Popen 通过管道连接多个进程?

于 2014-09-10T04:59:50.320 回答
1

它不太可能变慢,但您始终可以使用timeit对其进行测试以确保它。不采用第一种方式有两个很好的理由。第一个是虽然第一次打字可能会稍微快一点,但可读性大大降低,可读性很重要。二是使用shell=True存在巨大的安全隐患,原则上应避免使用。

于 2012-11-21T11:11:19.230 回答