'find' の出力を 'xargs wc' にパイプすると、不合理な合計が算出される

'find' の出力を 'xargs wc' にパイプすると、不合理な合計が算出される

何千ものファイルがあるプロジェクトで、コードの総行数と PHP のみのコード行数(CSS、JavaScript などは除外)を比較したいと考えました。

走るとき

find . -type f | xargs wc -l

最後の行の合計はより低い走るときよりも

find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l

2 番目はfind1 番目よりも小さいファイル リスト (厳密にはサブセット) でなければならないことを考慮すると、 2 番目のケースでより高い合計を報告するにはfindどうすればよいでしょうか。wc

答え1

xargs通過することしかできない 最大値への引数のバイトwc

私のMacでは、ARG_MAXはプロジェクト全体のファイルの完全なファイル名と相対パスよりも小さいので、初めコマンドは、のxargs結果をダンプしましたfindwc 2回に分けてwcつまり、合計2つ数千のファイル名に囲まれています。しかし、ARG_MAXは2番 find出力は2番目の小さいfind allが1つ wc合計。

修正方法は、次のコマンドを使用することです。これにより、(退屈な)個々のファイルカウント行なしですべての合計を確認できるようになりました。

find . -type f | xargs wc -l | grep total
find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l | grep total

次に、いくつかの「合計」行を手動で合計します。

答え2

これを行うには多くの方法がありますが、xargs最善の方法ではありません。次にいくつか例を挙げます。

  1. 最も簡単な方法は、cat見つかった各ファイルをfind調べて行数を数えることです。ファイル名にスペースや奇妙な文字が含まれていない場合にのみ機能します。注意してください。

    find . -type f | while read n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while read n; do cat $n; done | wc -l 
    

    ファイル名に奇妙な文字 (スラッシュ、スペースなど) が含まれる可能性がある場合は、代わりにこれを使用します。

    find . -type f | while IFS= read -r n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while IFS= read -r n; do cat $n; done | wc -l 
    
  2. より良い方法は、find の-execオプションを使用することです。

    find . -name "*.pep" -exec cat {} \; | wc
    find -E . -regex '.+\.(php|inc)' -type f -exec cat {} \; | wc
    

答え3

awk出力のさまざまな「合計」数を合計するために使用しますwc -l

(注:wc -lは改行文字の数を返します。つまり、または の\n場合と同様に、最終文字のない最終「行」はカウントされません。)awksed

export LC_ALL=C
find . -type f -print0 | xargs -0 wc -l | 
    awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'


# xargs alternatives using: find ... -exec <wc|awk|sed> ... '{}' +
#man find | less -p '{} \+'

# wc
find . -type f -exec wc -l '{}' + 2>/dev/null | 
   awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'

# awk
find . -type f -exec awk 'END {print NR}' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

# sed
find . -type f -exec sed -n '$=' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

関連情報