Zliczasz linie kodu?


24

jeśli chcę policzyć wiersze kodu, banalna rzecz

cat *.c *.h | wc -l

Ale co jeśli mam kilka podkatalogów?



3
Off-topic: Dlaczego niepotrzebne cat? wc -l *.c *.hrobi to samo.
Thomas Padron-McCarthy

5
@ ThomasPadron-McCarthy Nie, nie ma. Musisz wc -l *.c *.h | tail -n 1uzyskać podobny wynik.
Gilles „SO- przestań być zły”

2
Zauważ, że niektóre (być może nawet najbardziej) współczesne powłoki (Bash v4, Zsh, prawdopodobnie więcej) zapewniają mechanizm rekursywnego globowania **, dzięki czemu mógłbyś użyć wc -l **/*.{h,c}lub czegoś podobnego. Pamiętaj, że przynajmniej w Bash ta opcja (wywoływana globstar) jest domyślnie wyłączona . Ale również pamiętać, że w tym konkretnym przypadku, clocczy SLOCCountjest dużo lepszym rozwiązaniem. ( ackMoże być również lepszym rozwiązaniem do findłatwego znajdowania / wyświetlania plików źródłowych.)
Kyle Strand

5
wc -l zlicza wiersze, a nie wiersze kodu. 7000 pustych wierszy nadal będzie się wyświetlać w wc -l, ale nie będzie się liczyło w metodzie kodu. (komentarze też zwykle się nie liczą)
coteyr

Odpowiedzi:


49

Najprostszym sposobem jest użycie narzędzia o nazwie cloc. Użyj tego w ten sposób:

cloc .

to jest to! :-)


1
-1, ponieważ ten program nie ma żadnego sposobu na rozpoznanie linii kodu w językach poza swoim małym, nudnym mózgiem. Wie o Adach i Pascalu, C i C ++ oraz Javie, JavaScript i językach „korporacyjnych”, ale odmawia policzenia SLOC po prostu rozszerzenia pliku, a zatem jest całkowicie bezużyteczny dla DSL, a nawet języków, których po prostu nie zna o.
kot

21
@cat Nic nie jest idealne i nic nie może zaspokoić wszystkich Twoich przeszłych i przyszłych wymagań.
Ho1

2
Cóż, język programowania, którego CLOC odmawia uznania, rzeczywiście spełnia wszystkie moje przeszłe i przyszłe wymagania :)
cat

6
@cat zgodnie z dokumentacją CLOC może czytać w pliku definicji języka, więc istnieje sposób, aby rozpoznać kod w językach, których nie zdefiniował. Plus jest open source, więc zawsze możesz go rozszerzyć, aby był lepszy!
Centimane

39

Powinieneś użyć sloccount lub cloc do tego, są one zaprojektowane specjalnie do zliczania wierszy kodu źródłowego w projekcie, niezależnie od struktury katalogów itp .; zarówno

sloccount .

lub

cloc .

wygeneruje raport na temat całego kodu źródłowego, zaczynając od bieżącego katalogu.

Jeśli chcesz użyć findi wcGNU wcma ładny --files0-fromopcję:

find . -name '*.[ch]' -print0 | wc --files0-from=-

(Dzięki SnakeDoc za sugestią cloc !)


+1 za sloccount. Co ciekawe, uruchomienie sloccount /tmp/stackexchange(utworzone ponownie 17 maja po moim ostatnim ponownym uruchomieniu) mówi, że szacowany koszt opracowania znalezionych plików sh, perl, awk itp. Wynosi 11 029 USD. i nie obejmuje to jednowierszowych plików, które nigdy nie trafiły do ​​pliku skryptu.
cas

11
Oszacowanie kosztów na podstawie wierszy kodu? A co ze wszystkimi ludźmi zatrudnionymi do ponownego podziału spaghetti na coś, co można utrzymać?
Przestań krzywdzić Monikę

@OrangeDog zawsze możesz próbować uwzględnić to w kosztach ogólnych; zobacz dokumentację z wyjaśnieniem obliczeń (z bardzo starymi danymi dotyczącymi wynagrodzeń) i parametrami, które możesz modyfikować.
Stephen Kitt

5
clocjest również dobra: github.com/AlDanial/cloc
SnakeDoc

@StephenKitt> nadal głównym problemem jest to, że odlicza się wstecz. Podczas czyszczenia kodu często kończy się mniej linii. Pewnie, że możesz spróbować ręcznie narzucić narzut, aby ponieść resztę kodu, aby uwzględnić usunięty, ale nie rozumiem, dlaczego jest to lepsze niż odgadnięcie całej ceny.
spectras

10

Ponieważ wcpolecenie może przyjmować wiele argumentów, możesz po prostu przekazać wszystkie nazwy plików, wcużywając +argumentu -execakcji GNU find:

find . -type f -name '*.[ch]' -exec wc -l {} +

Alternatywnie, bashza pomocą opcji powłoki globstardo rekursywnego przeglądania katalogów:

shopt -s globstar
wc -l **/*.[ch]

Inne powłoki domyślnie przechodzą rekurencyjnie (np. zsh) Lub mają podobną opcję, jak globstarprzynajmniej większość.


1
+1 za brak konieczności instalowania niestandardowego oprogramowania na komputerze, na którym nie mam roota
Bamboomy

5

Można używać findrazem z xargsi wc:

find . -type f -name '*.h' -o -name '*.c' | xargs wc -l

2
(który zakłada, że ​​ścieżki do plików nie zawierają spacji, znaków nowej linii, pojedynczego cudzysłowu, podwójnego cudzysłowu znaków odwrotnego ukośnika. Może również generować kilka totalwierszy, jeśli wcwywoływanych jest kilka s).
Stéphane Chazelas

Być może wcproblem z kilkoma poleceniami można rozwiązać poprzez potokowanie finddo while read FILENAME; do . . .donestruktury. I w użyciu pętli while wc -l. Reszta sumuje sumę wierszy w zmiennej i wyświetla ją.
Sergiy Kolodyazhnyy

5

Jeśli jesteś w środowisku, w którym nie masz dostępu do clocitp. Sugeruję

find -name '*.[ch]' -type f -exec cat '{}' + | grep -c '[^[:space:]]'

Run-through: findwyszukiwań rekurencyjnie dla wszystkich zwykłych plików, których nazwa kończy się na jeden .calbo .hi działa catna nich. Dane wyjściowe są przesyłane potokowo, grepaby zliczać wszystkie niepuste linie (te, które zawierają co najmniej jeden znak spacji).


4

Jak wskazano w komentarzach, niecat file | wc -l jest równoważne, ponieważ pierwszy drukuje tylko liczbę, podczas gdy drugi drukuje liczbę i nazwę pliku. Podobnie wydrukuje tylko liczbę, a jednocześnie wydrukuje wiersz informacji dla każdego pliku.wc -l filecat * | wc -lwc -l *

W duchu prostoty powróćmy do pytania, które faktycznie zostało zadane:

jeśli chcę policzyć wiersze kodu, banalna rzecz

cat *.c *.h | wc -l

Ale co jeśli mam kilka podkatalogów?

Po pierwsze, możesz uprościć nawet trywialne polecenie, aby:

cat *.[ch] | wc -l

I na koniec, odpowiednikiem wielu podkatalogów jest:

find . -name '*.[ch]' -exec cat {} + | wc -l

Być może można to poprawić na wiele sposobów, na przykład ograniczając dopasowane pliki tylko do zwykłych plików (nie katalogów) poprzez dodanie -type f- ale podane findpolecenie jest dokładnym rekurencyjnym odpowiednikiem cat *.[ch].


3

Próbka za pomocą awk:

find . -name '*.[ch]' -exec wc -l {} \; |
  awk '{SUM+=$1}; END { print "Total number of lines: " SUM }'

Użyj +zamiast \;.
Jonathan Leffler,

@JathanathanLeffler Dlaczego?
Hastur

1
@Hastur: Działa wc -ldla grup plików, podobnie jak xargsrobi, ale obsługuje znaki o nieparzystej kuli (takie jak spacje) w nazwach plików, bez potrzeby używania albo xargs(niestandardowych) -print0i -0opcji odpowiednio findi xargs. To niewielka optymalizacja. Minusem byłoby to, że każde wywołanie wcgenerowałoby całkowitą liczbę linii na końcu, gdy podano wiele plików - awkskrypt poradziłby sobie z tym. Tak, to nie jest slam dunk-, ale bardzo często, stosując +w miejsce \;z finddobrym pomysłem.
Jonathan Leffler,

@JonathanLeffler Dziękuję. Zgadzam się. Moje obawy dotyczyły jednak długości przekazywanego ciągu parametrów wc. Jeśli nieznana a priori liczba plików, które zostaną znalezione , to czy istnieje ryzyko przekroczenia tego limitu, czy w jakiś sposób jest to obsługiwane przez find?
Hastur

2
@Hastur: findgrupuje pliki w pakiety o dogodnym rozmiarze, które nie przekroczą limitu długości listy argumentów na platformie, uwzględniając środowisko (które wynika z długości listy argumentów - więc długość listy argumentów plus wartość długość środowiska musi być mniejsza niż wartość maksymalna). IOW, findrobi to dobrze, podobnie jak xargsrobi to dobrze.
Jonathan Leffler,

1

łatwe polecenie:

find . -name '*.[ch]' | xargs wc -l

(który zakłada, że ​​ścieżki do plików nie zawierają spacji, znaków nowej linii, pojedynczego cudzysłowu, podwójnego cudzysłowu znaków odwrotnego ukośnika. Może również generować kilka totalwierszy, jeśli wcwywoływanych jest kilka s).
Stéphane Chazelas

0

Jeśli korzystasz z Linuksa, polecam własne narzędzie, polyglot . Jest znacznie szybszy cloci bardziej funkcjonalny niż sloccount.

Powinieneś także móc budować na BSD, chociaż nie ma żadnych dostarczonych plików binarnych.

Możesz to wywołać za pomocą

poly .

-2

find . -name \*.[ch] -print | xargs -n 1 wc -lpowinien załatwić sprawę. Istnieje również kilka możliwych wariantów, takich jak użycie -execzamiast przesyłania do wyjścia wc.


4
Ale find . -name \*.[ch] -printnie drukuje zawartości plików, tylko nazwy plików. Więc liczę liczbę plików, prawda? Czy potrzebuję `xargs '?
Niklas

@ Programmer400 tak, będziesz potrzebować xargs, a także będziesz musiał obserwować wiele wcwywołań, jeśli masz dużo plików; musisz poszukać wszystkich totallinii i zsumować je.
Stephen Kitt

Jeśli chcesz tylko całkowitą liczbę linii, musisz to zrobićfind . -name \*.[ch] -print0 | xargs -0 cat | wc -l
puszysty

Zauważ, że to ( find . -name \*.[ch] -print | wc -l) zlicza liczbę plików (chyba że nazwa pliku zawiera nowy wiersz - ale to bardzo niezwykłe) - nie zlicza liczby linii w plikach.
Jonathan Leffler,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.