python - 仅针对大文件从 python 调用 zgrep 系统后出错

标签 python grep subprocess

我正在使用 python 脚本对 zgrep 进行系统调用,并且仅使用 -m1 选项打印第一个结果。

脚本:

#! /usr/bin/env python2.7

import subprocess

print subprocess.check_output("zgrep -m1 'a' test.txt.gz", shell=True)

错误:

在大文件 (+2MB) 上运行脚本时,会生成以下错误。

> ./broken-zgrep.py

gzip: stdout: Broken pipe
Traceback (most recent call last):
  File "./broken-zgrep.py", line 25, in <module>
    print subprocess.check_output("zgrep -m1 'a' test.txt.gz", shell=True)
  File "/usr/intel/pkgs/python/2.7/lib/python2.7/subprocess.py", line 537, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command 'zgrep -m1 'a' test.txt.gz' returned non-zero exit status 2

但是,如果我复制 python 提示的命令并直接在 shell 中运行它,它就可以正常工作。

> zgrep -m1 'a' test.txt.gz
0000000 8c82 524d 67a4 c37d 0595 a457 b110 3192

该命令在shell中手动运行后退出状态为0,表示成功。 Python 表示命令退出,错误代码为 2

> echo $?
0

这里是如何制作一个示例测试文件来重现错误。它创建一个 100000 行随机值的十六进制文件,并使用 gzip 压缩它。

cat /dev/urandom | hexdump | head -n 100000 | gzip > test.txt.gz

看似不相关的更改将防止错误:

  • 制作一个较小的测试文件

    cat/dev/urandom |十六进制转储 |头-n 100 | gzip > test.txt.gz

  • 在没有-m1 选项的情况下运行(警告:垃圾终端)

    print subprocess.check_output("zgrep 'a' test.txt.gz", shell=True)

  • 在未压缩的文件上使用 grep 而不是 zgrep

    cat/dev/urandom |十六进制转储 | head -n 100000 > 测试.txt

    print subprocess.check_output("grep -m1 'a' test.txt", shell=True)

  • perl 中运行等效命令

    perl -e 'print `zgrep -m1 'a' test.txt.gz`'


我不知道为什么 pythonzgrep-m 选项和大文件的组合会产生这个错误。如果消除了这些因素中的任何一个,那么就没有错误。

我对原因的最佳猜测是阅读有关 -m 选项的 grep man 页面。

   -m NUM, --max-count=NUM
          Stop reading a file after NUM matching lines.  If the  input  is
          standard  input  from a regular file, and NUM matching lines are
          output, grep ensures that the standard input  is  positioned  to
          just  after the last matching line before exiting, regardless of
          the presence of trailing context lines.  This enables a  calling
          process  to resume a search.  When grep stops after NUM matching
          lines, it outputs any trailing context lines.

我最初假设 -m 选项只会导致 grep 在找到 NUM 个匹配项后退出。但是也许 grep 和标准输入发生了一些有趣的事情。这仍然不能解释为什么错误只发生在大型压缩文件上。

我最终将我的脚本从 python 移植到 perl 来解决这个问题,所以没有任何立即需要解决方案。但我真的很想更好地理解为什么这种完美的环境 Storm 失败了。

最佳答案

zgrep 只是一个shell 脚本,它大致相当于gunzip test.txt.gz | grep -m1 'a'。 gunzip 只是提取 block 并将它们传递给 grep。然后,当 grep 找到模式时,它会退出。

如果 gunzip 到那时还没有完成解压缩文件,以后写入 gunzip 的标准输出(连接到 grep 的标准输入)将失败。这正是您的情况:

gzip: stdout: Broken pipe

关于python - 仅针对大文件从 python 调用 zgrep 系统后出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10939755/

相关文章:

python - 获取用于下载视频的 YouTube URL

Python 打包的 EXE 空白屏幕在 Windows 上一秒钟如何停止?

bash - 比较两个 greps 的输出

Python 子进程 block

python - subprocess.Popen 不是线程安全的?

python - 从子进程 stdout 可靠地非阻塞读取

python - Keras vs PyTorch LSTM 不同的结果

python - Django根据日期计算数据查询

linux - 如何并行化我的 bash 脚本以与 `find` 一起使用而不面临竞争条件?

grep 多个扩展当前文件夹和子文件夹