36コアシステムで10Mファイルのパターンをすばやく見つけたいです。これを試しました。
find . -name '*.xml' -type f | xargs -P 20 grep "username" >> output
しかし、その間に他の結果も得ました。
これを行うより良い方法はありますか?
よろしくお願いします。
答え1
データがRAIDではなくHDDにあることを考えると、並列化によってより良いパフォーマンスが得られるかどうか疑問です。ボトルネックはCPUではなくI/Oである可能性が高いです。
LC_ALL=C grep -rwF --include='*.xml' username . > /on/some/other/disk/output
おそらくあなたが得ることができる最高に近いです。
並列化するには、次のことが必要です。
LC_ALL=C find . -name '*.xml' -type f -print0 |
LC_ALL=C xargs -r0P20 -n 1000 grep -HFw --line-buffered username > output
4KiBより長い出力ライン(入力ライン+ファイルパス名)がないと仮定し、20本の同時grepラインが最終的にインターリーブされることに注意してください。
望むより:
もっと学ぶ。
答え2
パターンがあまりにも一般的なので、そうだと思います。通常、コマンドラインユーティリティはstderrまたは端末にエラーを出力します。出力ファイルに入ってはいけません。
答え3
このようにファイルをgrep
pingすると、xml
検索文字列を含む行全体が返されxml
ます。ファイルに改行文字がない場合は、ファイル全体の内容が返されます。 10Mファイルには「その他」がかなり多いです。
xml
@Kusalanandaのコメントによると、より良いツールを使用してパーサーを強制的に使用するのはgrep
良い習慣ではありませんが、主張するなら...xml
xmllint
戻り値を制限するオプションを確認して読み取り、man
それを使用して探している一致の全長を定義します。grep
-o
regex
username
属性の場合
grep -o 'username="[^"]*"'
またはより良い
xmllint --xpath "//@username"
ノードなら、username
次のようになります。
grep -o "username>[^<][^<]*"
またはより良い
xmllint --xpath "//username"
すべてのxmllint
クエリに対してクエリをラップしてstring()
属性またはノードテキストを抽出するだけです。
xmllint --xpath "string(//username)"
xmllint --xpath "string(//@username)"