web-dev-qa-db-ja.com

サブディレクトリを含むコードの行を数える方法

プロジェクト内のコードの行を数えたいとします。すべてのファイルが同じディレクトリにある場合、実行できます:

cat * | wc -l

ただし、サブディレクトリがある場合、これは機能しません。これが機能するには、猫は再帰モードを使用する必要があります。これはxargsの仕事かもしれないと思うが、もっとエレガントな解決策があるのだろうか?

88
speciousfool

まず、行をカウントするためにcatを使用する必要はありません。これは 猫の役に立たない使用と呼ばれるアンチパターン (UUoC)です。現在のディレクトリ内のファイルの行をカウントするには、 wc を使用します。

wc -l * 

次に、findコマンドがサブディレクトリを再帰します。

find . -name "*.c" -exec wc -l {} \;
  • .は、検索を開始するトップディレクトリの名前です

  • -name "*.c"は、関心のあるファイルのパターンです

  • -execは実行するコマンドを提供します

  • {}は、コマンドに渡される検索コマンドの結果です(ここではwc-l

  • \;はコマンドの終わりを示します

このコマンドは、見つかったすべてのファイルとその行数のリストを生成します。見つかったファイルのallの合計を取得する場合は、findを使用して、ファイルをリストし(-printオプションを使用)、xargsを使用してwc-lの引数としてこのリストを渡します。

find . -name "*.c" -print | xargs wc -l 

ロバート・ギャンブルのコメントに対処するための編集(感謝):ファイル名にスペースまたは改行(!)がある場合、-print0および-printの代わりにxargs -nullオプションを使用する必要がありファイル名のリストはヌル終了文字列と交換されます。

find . -name "*.c" -print0 | xargs -0 wc -l

Unixの哲学は、1つのことだけを行い、それをうまく実行するツールを持つことです。

154
philant

コードゴルフの答えが必要な場合:

grep '' -R . | wc -l 

Wc -lを単独で使用する場合の問題は、うまく下降できないことです。

find . -exec wc -l {} \;

ファイルごとにwcを1回実行するため(loL!)、合計行数は表示されません。

find . -exec wc -l {} + 

Findが〜200kをヒットするとすぐに混乱します 12 パラメータの文字引数制限で、代わりにwcmultipleを呼び出します。そのたびに部分的な要約のみが表示されます。

さらに、上記のgrepトリックは、バイナリファイルが検出されても出力に1行以上は追加しません。これは、非常に有益です。

余分なコマンド文字が1つ必要なため、バイナリファイルを完全に無視できます。

 grep '' -IR . | wc -l

バイナリファイルでも行カウントを実行する場合

 grep '' -aR . | wc -l 

ドキュメントは、そのstringサイズ制限かトークンの数制限。

cd /usr/include;
find -type f -exec Perl -e 'printf qq[%s => %s\n], scalar @ARGV, length join q[ ], @ARGV' {} + 
# 4066 => 130974
# 3399 => 130955
# 3155 => 130978
# 2762 => 130991
# 3923 => 130959
# 3642 => 130989
# 4145 => 130993
# 4382 => 130989
# 4406 => 130973
# 4190 => 131000
# 4603 => 130988
# 3060 => 95435

これは、非常に簡単にチャンクすることを意味します。

30
Kent Fredric

おそらくxargsで立ち往生していると思います

find -name '*php' | xargs cat | wc -l

chromakode のメソッドは同じ結果をもたらしますが、はるかに遅いです。 xargsを使用する場合、catingとwcingはすぐに開始できますasfindが検索を開始します。

Linux:xargs vs. exec {} で良い説明

13
Ken

デフォルトでディレクトリを再帰するfindコマンドを使用してみてください。

find . -type f -execdir cat {} \; | wc -l

10
chromakode

正しい方法は次のとおりです。

find . -name "*.c" -print0 | xargs -0 cat | wc -l

Unixファイル名には無効な文字が2つしかないため、-print0を使用する必要があります:nullバイトと「/」(スラッシュ)。たとえば、「xxx\npasswd」は有効な名前です。ただし、実際には、スペースを含む名前に遭遇する可能性が高くなります。上記のコマンドは、各Wordを個別のファイルとしてカウントします。

また、-nameの代わりに "-type f"を使用して、検索をファイルに制限することもできます。

10
Aaron Digulla

比較的最近のGNU Bashを含むツールを使用できる場合、上記のソリューションでcatまたはgrepを使用するのは無駄です。

 wc -l --files0-from = <(find。-name\*。c -print0)

これにより、コマンドラインの長さの制限を超えた場合でも、スペース、任意の再帰、および一致する任意の数のファイルを含むファイル名が処理されます。

8
Idelic

私はfindheadを一緒に「再帰的な猫」に使用したいプロジェクトディレクトリ内のすべてのファイルで、たとえば:

find . -name "*rb" -print0 | xargs -0 head -10000

利点は、headがファイル名とパスを追加することです:

==> ./recipes/default.rb <==
DOWNLOAD_DIR = '/tmp/downloads'
MYSQL_DOWNLOAD_URL = 'http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.10-debian6.0-x86_64.deb'
MYSQL_DOWNLOAD_FILE = "#{DOWNLOAD_DIR}/mysql-5.6.10-debian6.0-x86_64.deb"

package "mysql-server-5.5"
...

==> ./templates/default/my.cnf.erb <==
#
# The MySQL database server configuration file.
#
...

==> ./templates/default/mysql56.sh.erb <==
PATH=/opt/mysql/server-5.6/bin:$PATH 

ここでの完全な例については、私のブログ投稿をご覧ください:

http://haildata.net/2013/04/using-cat-recursively-with-nicely-formatted-output-include-headers/

注:「head -10000」を使用しました.10,000行を超えるファイルがある場合、これは出力を切り捨てますが、head 100000を使用できますが、「非公式プロジェクト/ディレクトリブラウジング」の場合、このアプローチは非常にうまく機能します。

2
Dave Pitts

合計行数のみを生成し、各ファイルの行数を生成しない場合は、次のようにします。

find . -type f -exec wc -l {} \; | awk '{total += $1} END{print total}'

うまくいきます。これにより、スクリプトでさらにテキストフィルタリングを行う必要がなくなります。

1
abalmos
wc -cl `find . -name "*.php" -type f`
1
PMD
find . -name "*.h" -print | xargs wc -l
0
SD.

プロジェクト内のコード行をカウントするBashスクリプトを次に示します。ソースツリーを再帰的に走査し、「//」を使用する空白行と単一行コメントを除外します。

# $excluded is a regex for paths to exclude from line counting
excluded="spec\|node_modules\|README\|lib\|docs\|csv\|XLS\|json\|png"

countLines(){
  # $total is the total lines of code counted
  total=0
  # -mindepth exclues the current directory (".")
  for file in `find . -mindepth 1 -name "*.*" |grep -v "$excluded"`; do
    # First sed: only count lines of code that are not commented with //
    # Second sed: don't count blank lines
    # $numLines is the lines of code
    numLines=`cat $file | sed '/\/\//d' | sed '/^\s*$/d' | wc -l`
    total=$(($total + $numLines))
    echo "  " $numLines $file
  done
  echo "  " $total in total
}

echo Source code files:
countLines
echo Unit tests:
cd spec
countLines

my project の出力は次のようになります。

Source code files:
   2 ./buildDocs.sh
   24 ./countLines.sh
   15 ./css/dashboard.css
   53 ./data/un_population/provenance/preprocess.js
   19 ./index.html
   5 ./server/server.js
   2 ./server/startServer.sh
   24 ./SpecRunner.html
   34 ./src/computeLayout.js
   60 ./src/configDiff.js
   18 ./src/dashboardMirror.js
   37 ./src/dashboardScaffold.js
   14 ./src/data.js
   68 ./src/dummyVis.js
   27 ./src/layout.js
   28 ./src/links.js
   5 ./src/main.js
   52 ./src/processActions.js
   86 ./src/timeline.js
   73 ./src/udc.js
   18 ./src/wire.js
   664 in total
Unit tests:
   230 ./ComputeLayoutSpec.js
   134 ./ConfigDiffSpec.js
   134 ./ProcessActionsSpec.js
   84 ./UDCSpec.js
   149 ./WireSpec.js
   731 in total

楽しい! -- カラン

0
curran