回答:
この単純なワンライナーは、bashだけでなく、どのシェルでも機能するはずです。
ls -1q log* | wc -l
ls -1qは、空白や改行などの特殊文字が含まれている場合でも、ファイルごとに1行を提供します。
出力はwc -lにパイプされ、行数がカウントされます。
ls
子プロセスを作成するため、私はを使用しません。 log*
シェルではなくによって展開されるls
ので、シンプルecho
に実行できます。
logs
問題のディレクトリに呼び出されたディレクトリがある場合、そのログディレクトリの内容もカウントされます。これはおそらく意図的なものではありません。
これは\n
、bashを使用して安全に(つまり、スペースやファイル名に含まれるファイルによってバグが発生することはありません)実行できます。
$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
一致するファイルがない場合に配列内のnullglob
リテラル*.log
を取得しないように有効にする必要があります。(安全にリセットする方法の例については、「set -x」を「元に戻す」方法を参照してください。)$logfiles
shopt -u nullglob
がnullglob
設定されていない場合は、スキップして、開始します。
*.log
と、*
ディレクトリがカウントされます。列挙するファイルに従来の命名規則がname.extension
ある場合は、を使用します*.*
。
ここにはたくさんの答えがありますが、いくつかは考慮に入れていません
-l
)*.log
代わりにlog*
logs
と一致するディレクトリ(たとえば、と呼ばれるディレクトリlog*
)これらすべてを処理するソリューションは次のとおりです。
ls 2>/dev/null -Ubad1 -- log* | wc -l
説明:
-U
原因ls
それを意味しないソートのエントリには、メモリ内にリストディレクトリ全体をロードする必要はありません。-b
非グラフィック文字のCスタイルのエスケープを印刷し、改行がとして印刷されることを決定的にし\n
ます。-a
隠しファイルも含めてすべてのファイルを出力します(グロブlog*
が隠しファイルを含まない場合は厳密には必要ありません)-d
ディレクトリーの内容をリストすることを試みずにディレクトリーを印刷しls
ます。これは通常行うことです-1
それが1つの列にあることを確認します(パイプに書き込むときにlsがこれを自動的に行うので、厳密には必要ありません)2>/dev/null
stderrをリダイレクトするので、ログファイルが0の場合、エラーメッセージは無視されます。(代わりに、作業ディレクトリ全体がリストさshopt -s nullglob
れることls
に注意してください。)wc -l
生成されているディレクトリリストを消費するため、の出力はls
いつでもメモリに保存されません。--
--
への引数として理解されないように、ファイル名はコマンドから分離されていますls
(log*
削除された場合)シェルはlog*
ファイルの完全なリストに展開します。ファイルの数が多い場合、メモリが使い果たされる可能性があるため、grepを介して実行することをお勧めします。
ls -Uba1 | grep ^log | wc -l
最後の1つは、大量のメモリを使用せずに非常に大きなファイルのディレクトリを処理します(サブシェルを使用します)。-d
それは、現在のディレクトリの内容をリストているため、もはや必要ではありません。
再帰検索の場合:
find . -type f -name '*.log' -printf x | wc -c
wc -c
出力の文字数をカウントするfind
一方で、-printf x
伝えfind
シングルを印刷しますx
、各結果のために。
非再帰的な検索の場合は、次のようにします。
find . -maxdepth 1 -type f -name '*.log' -printf x | wc -c
-name '*.log'
すると、すべてのファイルがカウントされます。これは、私のユースケースで必要なものです。また、-maxdepthフラグは非常に便利です。
find
です。逐語的ファイル名以外のものを印刷するだけです。
この質問に対する受け入れられた回答は間違っていますが、私は担当者が少ないため、コメントを追加できません。
この質問に対する正しい答えは、Matによって与えられます。
shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}
受け入れられた回答の問題は、wc -lが改行文字の数をカウントし、端末に「?」として出力された場合でもそれらをカウントすることです。'ls -l'の出力。これは、ファイル名に改行文字が含まれていると、受け入れられた回答が失敗することを意味します。提案されたコマンドをテストしました:
ls -l log* | wc -l
名前に改行文字が含まれているパターンに一致するファイルが1つしかない場合でも、誤って値2が報告されます。例えば:
touch log$'\n'def
ls log* -l | wc -l
多くのファイルがあり、エレガントshopt -s nullglob
でbashの配列ソリューションを使用したくない場合は、ファイル名(改行が含まれている可能性がある)を印刷しない限り、findなどを使用できます。
find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l
これは、log *に一致し、かつで始まらないすべてのファイルを検索します.*
—「not name。*」は冗長ですが、「ls」のデフォルトはドットファイルを表示せず、デフォルトを表示することに注意することが重要です検索のためにそれらを含めることです。
これは正解であり、コマンド間でファイル名が渡されることはないため、投げることができるすべてのタイプのファイル名を処理します。
しかし、shopt nullglob
答えは最良の答えです!
find
使用して対ls
問題を解決するための2種類の方法があります。 find
常にマシン上に存在するわけではありませんが、ls
通常は存在します
find
おそらくそれらのすべての豪華なオプションがありませんls
。
-maxdepth 1
find
デフォルトでこれを行います。これは、非表示の子フォルダーがあることに気付いていない場合に混乱を招く可能性がありls
、デフォルトでは非表示のファイルを報告しない状況で使用すると便利な場合があります。
これが私の1つのライナーです。
file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)
set --
準備ができている以外は何もしていません$#
(コメントするには評判が足りません)
これはバギーです:
ls -1q some_pattern | wc -l
shopt -s nullglob
たまたま設定された場合は、パターンを持つファイルだけでなく、すべての通常のファイルの数が出力されます(CentOS-8およびCygwinでテスト済み)。他の無意味なバグが何か知っている人はls
いますか?
これは正しく、はるかに高速です。
shopt -s nullglob; files=(some_pattern); echo ${#files[@]};
それは期待された仕事をします。
0.006
CentOSと0.083
Cygwin(注意して使用する場合)。
0.000
CentOSと0.003
Cygwin。
このようなコマンドは、シェル関数を使用して簡単に定義できます。このメソッドは、外部プログラムを必要とせず、子プロセスを生成しません。危険なことはしませんls
解析を、「特殊」文字(空白、改行、バックスラッシュなど)を適切に処理します。シェルが提供するファイル名拡張メカニズムのみに依存します。少なくともsh、bash、zshと互換性があります。
以下の行は、呼び出されcount
た引数の数を出力するという関数を定義しています。
count() { echo $#; }
必要なパターンを指定して呼び出すだけです。
count log*
グロビングパターンが一致しない場合に正しい結果を得るには、展開が発生するときにシェルオプションnullglob
(またはfailglob
zshのデフォルトの動作)を設定する必要があります。次のように設定できます。
shopt -s nullglob # for sh / bash
setopt nullglob # for zsh
何を数えたいかに応じて、シェルオプションにも興味があるかもしれませんdotglob
。
残念ながら、少なくともbashでは、これらのオプションをローカルで設定するのは簡単ではありません。それらをグローバルに設定したくない場合、最も簡単な解決策は、このより複雑な方法で関数を使用することです。
( shopt -s nullglob ; shopt -u failglob ; count log* )
軽量の構文を復元したい場合count log*
、またはサブシェルの生成を避けたい場合は、次のようにハッキングすることができます。
# sh / bash:
# the alias is expanded before the globbing pattern, so we
# can set required options before the globbing gets expanded,
# and restore them afterwards.
count() {
eval "$_count_saved_shopts"
unset _count_saved_shopts
echo $#
}
alias count='
_count_saved_shopts="$(shopt -p nullglob failglob)"
shopt -s nullglob
shopt -u failglob
count'
おまけとして、この関数はより一般的な使用法です。例えば:
count a* b* # count files which match either a* or b*
count $(jobs -ps) # count stopped jobs (sh / bash)
関数をスクリプトファイル(または同等のCプログラム)に変換することで、PATHから呼び出すことができ、find
and などのプログラムで構成することもできますxargs
。
find "$FIND_OPTIONS" -exec count {} \+ # count results of a search
私はこの答えをたくさん考えました、特にdon't-parse-lsのものを考えると。最初に、私は試しました
<警告!うまくいきませんでした>
du --inodes --files0-from=<(find . -maxdepth 1 -type f -print0) | awk '{sum+=int($1)}END{print sum}'
</警告!うまくいきませんでした>
これは、次のようなファイル名しかなかった場合に機能しました
touch $'w\nlf.aa'
このようなファイル名を作成すると失敗しました
touch $'firstline\n3 and some other\n1\n2\texciting\n86stuff.jpg'
私は最終的に私が下に置くものを思いつきました。注(サブディレクトリは含めずに)ディレクトリ内のすべてのファイルの数を取得しようとしていました。@Matと@Dan_Yardの回答に加えて、@ mogsieによって設定された要件の少なくともほとんどを持っていると思います(メモリについてはわかりません)。@ mogsieの回答は正しいと思います。しかし、それがls
非常に特殊な状況でない限り、私は常に解析を避けようとします。
awk -F"\0" '{print NF-1}' < <(find . -maxdepth 1 -type f -print0) | awk '{sum+=$1}END{print sum}'
より読みやすく:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -print0) | \
awk '{sum+=$1}END{print sum}'
これは、特にファイルの検索を実行し、出力をnull文字で区切って(スペースと改行の問題を回避するため)、null文字の数を数えます。末尾にヌル文字があるため、ファイルの数はヌル文字の数より1つ少なくなります。
OPの質問に答えるために、考慮すべき2つのケースがあります。
1)非再帰的検索:
awk -F"\0" '{print NF-1}' < \
<(find . -maxdepth 1 -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
2)再帰的検索。-name
少し異なる動作(隠しファイルなど)を使用するには、パラメーターの内容を変更する必要がある場合があります。
awk -F"\0" '{print NF-1}' < \
<(find . -type f -name "log*" -print0) | \
awk '{sum+=$1}END{print sum}'
これらの回答が、この回答で述べた回答とどのように比較されるかについてコメントしたい場合は、どうぞ。
ls -1 log* | wc -l
つまり、1行に1つのファイルをリストしてから、それをワードカウントコマンドにパイプし、パラメーターを行数に切り替えます。
-l
これはstat(2)
、各ファイルに必要であり、カウントの目的では何も追加されないためです。