Python 通信 vs shell=True

标签 python shell subprocess

我试图通过移植一个 Python 脚本来做正确的事情,该脚本通过以下方式调用多个 shell 命令行

subprocess.call(... | ... | ... , shell=True) 

通过使用Popen来避免shell=True的安全风险。所以我写了一个小示例脚本来尝试一下。它执行命令行

awk '{print $1 " - " $2}' < scores.txt | sort | python uppercase.py > teams.txt

如下:

with open('teams.txt', 'w') as destination:
    with open('scores.txt', 'r') as source:
        p3 = Popen(['python', 'uppercase.py'], stdin=PIPE, stdout=destination)
        p2 = Popen(['sort'], stdin=PIPE, stdout=p3.stdin)
        p1 = Popen(['awk', '{print $1 " - " $2}'], stdin=source, stdout=p2.stdin)
        p1.communicate()

该程序适用于小型数据集。

现在我对 communicate 文档中的以下行感到震惊方法:

Note The data read is buffered in memory, so do not use this method if the data size is large or unlimited.

什么?但我有大量文件需要进行 awk'd 和排序等。我首先尝试使用 communicate 的原因是我看到了 subprocess.call 的警告:

Note Do not use stdout=PIPE or stderr=PIPE with this function as that can deadlock based on the child process output volume. Use Popen with the communicate() method when you need pipes.

我真的很困惑。看来我的选择是:

  • callshell=True 一起使用(他们说存在安全风险)
  • PIPEcall 结合使用(但存在死锁风险)
  • 使用Popen通信(但我的数据太大,有数百兆字节)。

我错过了什么?如何在没有 shell=True 的情况下在 Python 中为非常大的文件创建多个进程管道,或者 shell=True 可以接受吗?

最佳答案

只有当您使用诸如 stdout=PIPE 之类的内容时,有关“在内存中缓冲”的注释才有意义。它不适用于 stdout=file (os.dup2() 在操作系统文件描述符级别进行重定向,对于 .communicate( 没有任何作用) )方法)。

不要使用callPIPEcall() (简化)只是 Popen().wait() 即,它不从管道读取。不要使用 PIPE 除非您从管道中读取(写入)(没有意义)。

在您的代码中p1.communicate()不会读取任何数据。您可以将其替换为 p1.wait()。您的代码缺少 p3.stdin.close(); ...; p2.stdin.close(); ...; p3.wait(), p2.wait()

否则,该代码适用于大文件。

shell=True

如果命令是硬编码的(如您的问题所示),则不存在安全风险。如果该命令可能来自不受信任的源,那么如何运行该命令并不重要(在这种情况下,不受信任的源可能会运行它喜欢的任何命令)。如果只有一些参数来自不受信任的来源,那么您可以使用plumbum模块来避免自己重新实现管道:

from plumbum.cmd import awk, sort, python

(awk['{print $1 " - " $2}'] < untrusted_filename | sort |
 python["uppercase.py"] > "teams.txt")()

参见How do I use subprocess.Popen to connect multiple processes by pipes?

关于Python 通信 vs shell=True,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25777777/

相关文章:

python - Keras 训练 warm_start

python - 使用 Tkinter 在 while 循环中录制语音

java - 在 swt 的特定时间段后自动关闭 shell

python - 您如何从在 blender 外部运行的 python 脚本在 blender 中编写命令?

python - 无法在 subproces.call 中运行 ffmpeg

python subprocess - 如何检查 PIPE 中是否没有任何新数据?

python - 为什么返回 NotImplemented 而不是引发 NotImplementedError

linux - 使用 shell 脚本读取矩阵的所有条目

shell - 在构建 docker 镜像时运行 shell 脚本

python - 如何通过Python运行unix命令来就地编辑文件