Locateコマンドで渡された非シンボリックファイルの数を数えようとしています。私はいくつかのオプションを試しましたが、これが最も有望だと思います。
locate -r "$PWD.*\.c$" | xargs -0 -I{} test -f {} && echo "regular file" | wc -l
問題はそれがうまくいかないことです。
合計30個のファイルがあり、そのうちの1つはシンボリックリンクwc -l
なので29
。
私はxargs
それを完全にスキップしようとしました。
locate -r "$PWD.*\.c$" | test -f && echo "regular file" | wc -l
頑張ったいいえシンボリックリンク:
locate -r "$PWD.*\.c$" | test ! -h && echo "regular file" | wc -l
locate -r "$PWD.*\.c$" | test ! -L && echo "regular file" | wc -l
locate
出力をパイプし、通常のファイル数とシンボリックリンク数を計算する最も効率的な方法は何ですか?
コメントに返信する
一部の人々は演出が好きですlocate
。find
不可知論者であればいいのですが、できればlocate
使いたいです。コメントが投稿されており、質問に回答したいと思います。
updatedb
最初の実行には30秒かかりますが、後続の実行には4秒しかかかりません。 5分ごとに走るのは、1cron
日1回というデフォルト値に対する無謀な反応です。しかし、ノートパソコンのCPU使用量は10~20%に過ぎず、レックもまったくありません。- キャッシュを削除した後、ファイルを
find
探すのに1分9秒かかります。 - キャッシュを削除した後、
locate
同じファイルを見つけるのに1秒かかります。
以下は、システムに複製できるいくつかのベンチマークです。
$ sudo -i
# sync; echo 1 > /proc/sys/vm/drop_caches; sync; echo 2 > /proc/sys/vm/drop_caches; sync; echo 3 > /proc/sys/vm/drop_caches; exit
logout
$ time locate .hidden.c | wc -l
1
real 0m0.790s
user 0m0.758s
sys 0m0.028s
$ sudo -i
# sync; echo 1 > /proc/sys/vm/drop_caches; sync; echo 2 > /proc/sys/vm/drop_caches; sync; echo 3 > /proc/sys/vm/drop_caches; exit
logout
$ time find / iname '.hidden.c' 2>/dev/null | wc -l
1888926
real 1m9.044s
user 0m5.158s
sys 0m15.004s
$ sudo -i
# sync; echo 1 > /proc/sys/vm/drop_caches; sync; echo 2 > /proc/sys/vm/drop_caches; sync; echo 3 > /proc/sys/vm/drop_caches; exit
logout
$ time sudo updatedb
real 0m29.323s
user 0m1.267s
sys 0m4.784s
$ time sudo updatedb
real 0m3.592s
user 0m0.479s
sys 0m1.211s
find
間違いなくそれよりも強力ですlocate
が、locate
数倍速く、構文も覚えやすくなります。
実際に、今日生成されたファイルを含めるか、今日削除されたファイルを除外するようにデータベースを更新するには、コマンドの引数を一度sudo updatedb
に実行または渡す必要があることに注意してください。しかし、一方でパラメータを渡すことを覚えておく必要があります。-u
locate
find
2>/dev/null
まず、私のラップトップは正しく動作せず、2番目に怠惰なので、5分ごとにcron
実行することにしました。updatedb
答え1
このコマンドは閉じます。
locate -r "$PWD.*\.c$" | xargs -0 -I{} test -f {} && echo "regular file" | wc -l
質問:
- xargsと一緒にNULLで区切られた入力を使用しますが、
locate
NULLで区切られた出力は提供しません。 - 単一のパイプラインではなく、パイプライン全体に対して実行され
&& echo
ます。locate | xargs
test
努力する:
locate -0r "$PWD.*\.c$" | xargs -0 -I{} sh -c 'test -f "$1" && echo "regular file"' _ {} | wc -l
locate
以下を使用して、Nullで区切られた出力を有効にします。-0
test
andと結合(各呼び出しが複数のファイルを処理するようにecho
パラメータループで改善することができます)sh -c
sh
にはまだ正規表現演算子があります$PWD
。
答え2
そしてzsh
:
set -o extendedglob # best in ~/.zshrc
c_regular_files=(
${(0)^"$(locate -0 "${${PWD%/}//(#m)[]\\*?]/\\$MATCH}/*.c")"}(N.)
)
echo there are at least $#c_regular_files regular files whose name ends in .c
- forで
[
、および?
をエスケープする必要があり、ワイルドカード演算子として解釈しないでください(ファイル名にcommon、を含むより多くの演算子を持つ正規表現の方が悪い)。\
*
$PWD
locate
-r
.
$PWD
==は/
特別に処理する必要があります。$PWD
代わりに使用すると、これを${PWD%/}
実行しlocate -0 "//*.c"
、何も返しません。-0
ファイルはNULで区切られています(ファイルパスに改行が許可されているため、改行は効果がありません)。.
ある定期的な文書。対照的に[ -f
、一般ファイルへのシンボリックリンクは除外されます。 Symlink以外のすべての.c
ファイル(ディレクトリ、fifo、ソケットなどの他の種類のファイルを許可する)が必要な.
場合^@
。
それにもかかわらず、locate
返されたリストはlocate
データベースが最後に更新された時刻に基づいているため、現実を反映していない可能性があります。
答え3
構文解析の代わりにlocate
(壊れやすく、データベースが最後に更新されてから変更されたアイテムまたは利用できないアイテムが見逃される可能性があります)みんなユーザー)find
、。
.c
次のコマンドは、現在のディレクトリ内のすべての一般ファイル(シンボリックリンクではない)のファイルを探します。
find . -type f -name '*.c'
与えられたディレクトリ構造
.
|-- file-a.c
|-- file-b.c
|-- file-c.c
|-- file-d.c
|-- link-b.c -> file-b.c
`-- link-d.c -> file-d.c
が返されます
./file-a.c
./file-b.c
./file-c.c
./file-d.c
カウントしてください:
find . -type f -name '*.c' | wc -l
またはファイル名に改行文字が含まれている場合
find .//. -name '*.c' -type f | grep -c //
シンボリックリンクで同じことを行うには-type f
に変更-type l
。
答え4
GNU Parallelを使用すると、次のようになります。
locate -r "$PWD.*\.c$" | parallel 'test -f {} && echo "regular file"' | wc -l
ご覧のとおり、元の試みに非常に近いです。
ヒット数が100個未満の場合は、GNU Parallelを使用して失敗したジョブの数を最大100個に設定できます(拡張されていません)。
ls *txt | parallel \! test -f {}
echo $?
より早く必要な場合:
locate -r "$PWD.*\.c$" |
perl -ne 'chomp; -l $_ or $s+= -f $_; END{print "$s\n"}'
または組み合わせ:
locate -r "$PWD.*\.c$" |
parallel --block 10k --pipe -q perl -ne 'chomp; -l $_ or $s+= -f $_; END{print "$s\n"}' |
awk '{s+=$1} END {print s}'