検索と検索を使用してソースファイルとLOCを計算すると、Pythonファイルが異なるように見えるのはなぜですか?

検索と検索を使用してソースファイルとLOCを計算すると、Pythonファイルが異なるように見えるのはなぜですか?

find理由は理解できず、locateCファイルとPythonソースファイルでは異なる動作をします。私の目標は、特定の言語のソースファイル数とそのソースコード行の合計を計算することです。 ANDを使用して出力を比較します(findANDを実行する直前に現在の結果が報告されていることを確認してください)。locateupdatedbsudolocate

Cファイルの場合、これは期待どおりに機能し、ソースファイルの数は同じです。

$ find / -name *.c |& grep -v "Permission denied" | wc -l
1056
$ locate *.c | wc -l
1056

を使用すると、xargsソースコード行の合計も同じです。

$ locate *.c | xargs wc -l | tail -3
     138 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/selinux/genheaders/genheaders.c
     147 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/selinux/mdp/mdp.c
  705376 total

$ find / -name *.c |& grep -v "Permission denied" | xargs wc -l | tail -3
    2994 /opt/Python-3.6.2/Objects/listobject.c
     821 /opt/Python-3.6.2/Objects/bytes_methods.c
  705376 total

テストのためだけに.java拡張子を持つファイルにも機能します。同じ一貫した結果が得られます。ただし、Pythonファイル(拡張子など)に対して.py同じ操作を繰り返すと

ソースファイル番号が一致します。

$ find / -name *.py |& grep -v "Permission denied" | wc -l
9249
$ locate *.py | wc -l
9249

しかし、Pythonファイルのコード行の合計は非常に異なる結果をもたらします。

$ locate *.py | xargs wc -l | tail -3
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template: No such file or directory
wc: (dev).py: No such file or directory
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template.py: No such file or directory
     220 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/rt-tester/rt-tester.py
     129 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/tracing/draw_functrace.py
  753350 total

$ find / -name *.py |& grep -v "Permission denied" | xargs wc -l | tail -3
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template: No such file or directory
wc: (dev).py: No such file or directory
wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory
wc: template.py: No such file or directory
    1919 /opt/Python-3.6.2/python-gdb.py
      69 /opt/Python-3.6.2/python-config.py
 1034101 total

なぜこれが起こるのか説明できますか? Pythonファイルとの違いは何ですか? (ファイル形式と関係があるという事実は本当に信じられませんが、混乱しています。)私はここで何を見逃していますか?

UbuntuとRHでも同じ奇妙な結果が現れます。

私はupdatedbrunを使用しますsudoが、これらすべてのコマンドを通常のユーザーとして実行します。

答え1

コマンドに問題がたくさんあります。

まず、名前が一致するファイルがないディレクトリで実行すると、一致するlocate *.cファイルのみが検索されます。それ以外の場合、シェルは一致するファイルのリストに展開されます。おそらく、このようなことが起こらないか、より少ない数の一致が得られますが、このように引用されていないワイルドカードを残すのは悪い習慣です。*.c*.c*.c〜するある日、お願いします。 (これはこのサイトの共通トピックです。)代わりfind -name *.cに同じことが当てはまります。

locate '*.c' …
find / -name '*.c' …

またはそのようなもの。

いくつかの一般的な原因があり、locateさまざまなfind結果が表示されることがあります。あなたの場合は同じクリック数が発生するため、該当するものは適用されないようですが、もう一度注意してください。

  • locate最後の実行結果をキャッシュしますupdatedb。通常、夕方に一度行われます。findコマンドが実行されるたびに計算される結果です。
  • システム、locate使用している実装、および構成方法に応じて、パブリックにアクセスできるファイル(mlocateやslocate以外のGNU findutilsなど)のみを表示したり、ユーザーが使用するファイルのコピーを作成したりできます。近似値を見ています。アクセスを許可します(たとえば、ファイルにアクセスしようとしているアプリケーションを区別するLinuxセキュリティモジュールに関連する複雑な設定があるため)。
  • toとtoはこのパターンで同じ意味を持ちますが*SUFFIX(スラッシュやワイルドカードが含まれていないと仮定)、他のパターンではそうではありません。たとえば、〜ではなく〜と同じです。locatefind -nameSUFFIXlocate foofind / -name '*foo*'find / -name 'foo'

find問題を引き起こす可能性がありますが、そうでない可能性があるもう1つの点は、コマンドのデータ処理部分にエラーメッセージをリンクしたことです。埋め込まれた行を削除すると、Permission denied名前の一部としてそれを含むファイルが欠落し(何もない場合があります)、含まれていないすべてのエラーメッセージがPermission denied入力行として解釈されます。データ出力とエラー出力を混在させることは良い考えではなく、ここでは言うまでもありません。エラーを無視するには、次にリダイレクトしてください/dev/null

find … 2>/dev/null | …

確かにあなたを迷惑にするのは、xargs予想される入力構文が生成された構文と異なることですfind。 input では、xargs改行文字だけでなく、すべてのスペースは項目を区切ります。これらの3文字\'"も特に解析されます。ファイル名はスペースが一般的で、/ヌルバイトを除くすべての文字を受け入れます。xargs入力を受け取る行の1つは次のとおりです。

/usr/lib/python2.7/site-packages/setuptools/script template (dev).py

の場合、およびxargsの3つの項目があります。これでエラーメッセージの原因が明らかになりました。/usr/lib/python2.7/site-packages/setuptools/scripttemplate(dev).pywc

これにはいくつかの解決策があります。 1つは、sumにfindnullで区切られた形式を使用することですxargs。これはすべてのファイル名に適用され、改行文字を含むファイル名にも適用されます(許可されていますが一般的ではありません)。

find / -name '*.py' -print0 | xargs -0 wc -l | tail -3

別のアプローチは、問題があることを忘れて、xargsコマンドfindを直接呼び出すことです。

find / -name '*.py' -exec wc -l {} + | tail -3

最初のソリューションはあなたのlocate実装に適しているかもしれません。オプションがあることを確認してください-0。 2番目の解決策はについてですfind。改行で区切られた出力を使用しようとしていて、locateGNUバージョンがある場合は、それを使用して、任意の形式の引用なしで改行で区切られた入力を解析することxargsができます。-d '\n'

locate '*.py' | xargs -d '\n' wc -l | tail -3

これがあなたの主な問題です。別の問題は、コマンドラインに最大長があることです。コマンドxargs(または-exec … {} +アクションfind)はコマンドラインにできるだけ多くのファイル名を入力し、すべてが合わない場合、コマンド(ここでwc -l)は各ファイルのバッチに対して一度に複数回実行されます。を使用すると、tail -3最後の2つのファイルと最後のバッチの合計数のみを表示できます(最後のバッチに少なくとも2つのファイルがあると仮定)。以前のバッチのファイルはこの出力に反映されません。findlocateファイルを同じ順序で報告しない可能性があるため、結果が異なる場合があります。

最大長の問題を解決する方法は、データとして実行する操作によって異なります。必要なものが完全な場合、1つのアプローチ(ファイル名に改行文字がないと仮定)はすべての行をtotal計算することです。

… | xargs -d '\n' wc -l | awk '/^[0-9]+\ttotal$/ {total += $1} END {print total}'

関連情報