find
理由は理解できず、locate
CファイルとPythonソースファイルでは異なる動作をします。私の目標は、特定の言語のソースファイル数とそのソースコード行の合計を計算することです。 ANDを使用して出力を比較します(find
ANDを実行する直前に現在の結果が報告されていることを確認してください)。locate
updatedb
sudo
locate
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でも同じ奇妙な結果が現れます。
私はupdatedb
runを使用します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
(スラッシュやワイルドカードが含まれていないと仮定)、他のパターンではそうではありません。たとえば、〜ではなく〜と同じです。locate
find -name
SUFFIX
locate foo
find / -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/script
template
(dev).py
wc
これにはいくつかの解決策があります。 1つは、sumにfind
nullで区切られた形式を使用することです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
。改行で区切られた出力を使用しようとしていて、locate
GNUバージョンがある場合は、それを使用して、任意の形式の引用なしで改行で区切られた入力を解析することxargs
ができます。-d '\n'
locate '*.py' | xargs -d '\n' wc -l | tail -3
これがあなたの主な問題です。別の問題は、コマンドラインに最大長があることです。コマンドxargs
(または-exec … {} +
アクションfind
)はコマンドラインにできるだけ多くのファイル名を入力し、すべてが合わない場合、コマンド(ここでwc -l
)は各ファイルのバッチに対して一度に複数回実行されます。を使用すると、tail -3
最後の2つのファイルと最後のバッチの合計数のみを表示できます(最後のバッチに少なくとも2つのファイルがあると仮定)。以前のバッチのファイルはこの出力に反映されません。find
とlocate
ファイルを同じ順序で報告しない可能性があるため、結果が異なる場合があります。
最大長の問題を解決する方法は、データとして実行する操作によって異なります。必要なものが完全な場合、1つのアプローチ(ファイル名に改行文字がないと仮定)はすべての行をtotal
計算することです。
… | xargs -d '\n' wc -l | awk '/^[0-9]+\ttotal$/ {total += $1} END {print total}'