私は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 が文句を言うコマンドをコピーしてシェルで直接実行すると、問題なく動作します。
> zgrep -m1 'a' test.txt.gz
0000000 8c82 524d 67a4 c37d 0595 a457 b110 3192
コマンドの終了ステータスは0
、シェルで手動で実行した後のものであり、成功を示しています。Python は、コマンドがエラー コードで終了すると言います2
。
> echo $?
0
エラーを再現するためのサンプル テスト ファイルの作成方法を次に示します。ランダム値の 100000 行の 16 進ファイルを作成し、gzip
圧縮に使用します。
cat /dev/urandom | hexdump | head -n 100000 | gzip > test.txt.gz
エラーを防ぐ一見無関係な変更:
小さいテスト ファイルを作成する
cat /dev/urandom | hexdump | head -n 100 | gzip > test.txt.gz
オプションなしで実行する
-m1
(警告: 端末にスパムを送信します)print subprocess.check_output("zgrep 'a' test.txt.gz", shell=True)
圧縮されていないファイル
grep
の代わりに使用するzgrep
cat /dev/urandom | hexdump | head -n 100000 > test.txt
print subprocess.check_output("grep -m1 'a' test.txt", shell=True)
で同等のコマンドを実行する
perl
perl -e 'print `zgrep -m1 'a' test.txt.gz`'
python
、zgrep
、-m
オプション、および大きなファイルの組み合わせでこのエラーが発生する理由がわかりません。これらの要因のいずれかが取り除かれれば、エラーは発生しません。
原因についての私の最善の推測は、オプションgrep
man
に関するページを読むことです。-m
-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 に移植することになったので、すぐに解決策を講じる必要はありません。しかし、この完璧な状況の嵐がなぜ失敗するのかをもっとよく理解したいと思っています。