Jak zliczyć wiersze kodu wraz z podkatalogami [duplikat]

To pytanie ma już odpowiedź tutaj:

Załóżmy, że chcę policzyć linie kodu w projekcie. Jeśli wszystkie pliki znajdują się w tym samym katalogu mogę wykonać:

cat * | wc -l

Jednakże, jeśli istnieją podkatalogi, to nie działa. Dla tego do pracy kot będzie musi mieć tryb rekurencyjny. Podejrzewam, że to może być praca dla xargsa, ale zastanawiam się, czy jest bardziej eleganckie rozwiązanie?

Author: madth3, 2008-11-25

11 answers

Najpierw nie musisz używać cat do liczenia linii. Jest to antypattern zwany bezużytecznym użyciem kota (UUoC). Aby zliczyć linie w plikach w bieżącym katalogu, użyj wc:

wc -l * 

Następnie find polecenie rekursuje podkatalogi:

find . -name "*.c" -exec wc -l {} \;
  • . jest to nazwa górnego katalogu, z którego można rozpocząć wyszukiwanie od

  • -name "*.c" jest wzorcem pliku, który Cię interesuje

  • -exec daje polecenie do być wykonane

  • {} jest wynikiem polecenia find, które ma zostać przekazane do polecenia (tutaj wc-l)

  • \; wskazuje koniec polecenia

To polecenie tworzy listę wszystkich znalezionych plików wraz z ich liczbą wierszy, jeśli chcesz mieć sumę dla wszystkich znalezionych plików, możesz użyć find, aby wyświetlić listę plików (z opcją -print) i następnie użyć xargs, aby przekazać tę listę jako argument do wc-l.

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

Edytuj do adres Robert Gamble komentarz (dzięki): Jeśli masz spacje lub nowe linie (!) w nazwach plików musisz użyć opcji -print0 zamiast -print i xargs -null, aby lista nazw plików była wymieniana z zakończonymi znakiem null łańcuchami.

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

Filozofia Uniksa polega na tym, aby mieć narzędzia, które robią tylko jedną rzecz i robią to dobrze.

 150
Author: philant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-29 03:09:05

Jeśli chcesz Kod-ODPOWIEDŹ:

grep '' -R . | wc -l 

Problem z samym używaniem wc-l polega na tym, że nie można go używać, a jeden z nich używa

find . -exec wc -l {} \;

Nie da ci całkowitej liczby linii, ponieważ uruchamia wc raz dla każdego pliku, (loL! ) oraz

find . -exec wc -l {} + 

Będzie się mylić, jak tylko znaleźć hits ~200k1,2 limit argumentów znakowych dla parametrów i zamiast tego wywołuje wc wiele razy, za każdym razem daję Ci tylko częściowe podsumowanie.

Dodatkowo, powyższa sztuczka grepa nie doda więcej niż 1 linii do wyjścia, gdy napotka plik binarny, co może być okolicznościowo korzystne.

Za koszt 1 dodatkowego znaku polecenia można całkowicie zignorować pliki binarne:

 grep '' -IR . | wc -l

Jeśli chcesz uruchomić linijki również na plikach binarnych

 grep '' -aR . | wc -l 
Przypisy:

Dokumenty są nieco niejasne, czy jest to string limit rozmiaru, czy ilość żetonów limit.

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

To oznacza, że bardzo łatwo się rozpadnie.

 29
Author: Kent Fredric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:15

Myślę, że prawdopodobnie utknąłeś z xargs

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

Metoda Chromakode daje ten sam wynik, ale jest znacznie wolniejsza. Jeśli używasz xargs, Twój cating i wcing może rozpocząć pracę, gdy tylko find zacznie szukać.

Dobre wyjaśnienie w Linux: xargs vs. exec {}

 13
Author: Ken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:25:58

Spróbuj użyć polecenia find, które domyślnie rekursuje katalogi:

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

 10
Author: chromakode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-25 07:41:51

Prawidłowy sposób to:

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

Musisz użyć -print0, ponieważ w nazwach plików Uniksa są tylko dwa nieprawidłowe znaki: bajt null i " / " (Ukośnik). Na przykład "xxx\npasswd" jest poprawną nazwą. W rzeczywistości bardziej prawdopodobne jest jednak napotkanie nazw ze spacjami. Powyższe polecenia liczyłyby każde słowo jako osobny plik.

Możesz również użyć "- type f " zamiast-name, aby ograniczyć wyszukiwanie do plików.

 9
Author: Aaron Digulla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-25 16:12:53

Używanie cat lub grep w powyższych rozwiązaniach jest marnotrawstwem, jeśli można używać stosunkowo najnowszych narzędzi GNU, w tym Basha:

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

Obsługuje nazwy plików ze spacjami, dowolną rekurencją i dowolną liczbą pasujących plików, nawet jeśli przekraczają limit długości wiersza poleceń.

 8
Author: Idelic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-09 06:07:42

Lubię używać findi head RAZEM DLA "KOTA rekurencyjnego" na wszystkich plikach w katalogu projektu, na przykład:

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

Zaletą jest to, że head doda nazwę pliku i ścieżkę:

==> ./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 

Pełny przykład tutaj, proszę zobaczyć mój wpis na blogu:

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

Uwaga użyłem 'head -10000', oczywiście jeśli mam pliki nad 10,000 linii to obetnie wyjście ... jednak mógłbym użyć head 100000, ale dla "nieformalnego przeglądania projektu / katalogu" to podejście działa bardzo dobrze dla mnie.

 2
Author: Dave Pitts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-28 11:10:07

Jeśli chcesz wygenerować tylko całkowitą liczbę linii, a nie liczbę linii dla każdego pliku, coś w stylu:

find . -type f -exec wc -l {} \; | awk '{total += $1} END{print total}'
Działa dobrze. To oszczędza potrzebę dalszego filtrowania tekstu w skrypcie.
 1
Author: abalmos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-07 05:29:04
wc -cl `find . -name "*.php" -type f`
 1
Author: PMD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-23 10:32:23

Oto skrypt Bash, który liczy linie kodu w projekcie. Porusza się rekurencyjnie po drzewie źródłowym i wyklucza puste linie i pojedyncze komentarze, które używają "//".

# $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

Oto jak wygląda wyjście dla mojego projektu :

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
Smacznego! -- Curran
 0
Author: curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-31 23:58:48
find . -name "*.h" -print | xargs wc -l
 0
Author: SD.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-27 13:02:05