count (niepuste) wiersze kodu w bash

151

Jak w Bash policzyć liczbę niepustych wierszy kodu w projekcie?

Jonathan Hartley
źródło
1
Wiele z poniższych rozwiązań działa tylko dla jednego pliku (np foo.c.). Jakieś przemyślenia na temat całkowitej liczby wierszy w projekcie (np. Wiele plików w strukturze katalogów, z wyłączeniem plików binarnych)?
rozwiązywanie łamigłówek
5
@solvingPuzzles Myślę, że mogę odpowiedzieć na tę część. W przypadku każdego rozwiązania, które działa na jednym pliku, np. „Cat FILE | sed blah”, można pracować na wielu plikach, zastępując „cat FILE” poleceniem, które zawiera listę nazw plików do wykonania, np. „Find. -Name” * .py '"i potokuj to do" xargs cat ". np. "find. -name '* .py' | xargs cat | sed '/ ^ \ s * $ / d' | wc -l"
Jonathan Hartley
2
@JonathanHartley @solvingPuzzles są też programy takie jak sloci, clocktóre służą do liczenia tych linii kodu.
AsTeR
OP tutaj: Kiedy po raz pierwszy zadałem ten problem, 'cloc' nie wykonał zbyt dobrej pracy w kodzie Pythona. Obecnie jest świetnie.
Jonathan Hartley
cloc jest również dostępny jako moduł npm i oszczędza dużo czasu.
Krishna Vedula

Odpowiedzi:

193
cat foo.c | sed '/^\s*$/d' | wc -l

A jeśli weźmiesz pod uwagę puste linie komentarzy:

cat foo.pl | sed '/^\s*#/d;/^\s*$/d' | wc -l

Chociaż jest to zależne od języka.

Michael Cramer
źródło
24
Nie jestem pewien, dlaczego używasz tam kota. Użyj foo.c lub foo.pl jako nazwy pliku, aby przekazać do seda. sed '/ ^ \ s * $ / d' foo.c | wc -l
Andy Lester
28
Po prostu nawyk. Potoki czytam od lewej do prawej, co oznacza, że ​​zwykle zaczynam od cat, potem akcja, akcja, akcja itd. Oczywiście, efekt końcowy jest taki sam.
Michael Cramer,
32
Aby to zrobić dla wszystkich plików we wszystkich podfolderach i wykluczyć komentarze z '//', rozszerz to polecenie do tego: find. -type f -name '* .c' -exec cat {} \; | sed '/ ^ \ s * # / d; / ^ \ s * $ / d; / ^ \ s * \ / \ // d' | wc -l
Benjamin Intal
11
Możesz czytać od lewej do prawej bez UUOC: < foo.pl sed 'stuff' | wc -l.
jw013
22
Ogólnie rzecz biorąc, UUOC nie jest ważny, ale czytelność jest.
andersand
52
#!/bin/bash
find . -path './pma' -prune -o -path './blog' -prune -o -path './punbb' -prune -o -path './js/3rdparty' -prune -o -print | egrep '\.php|\.as|\.sql|\.css|\.js' | grep -v '\.svn' | xargs cat | sed '/^\s*$/d' | wc -l

Powyższe daje całkowitą liczbę wierszy kodu (puste wiersze usunięte) dla projektu (bieżący folder i wszystkie podfoldery rekurencyjnie).

W powyższych "./blog" "./punbb" "./js/3rdparty" i "./pma" znajdują się foldery, które umieściłem na czarnej liście, ponieważ nie napisałem w nich kodu. Również .php, .as, .sql, .css, .js są rozszerzeniami przeglądanych plików. Wszystkie pliki z innym rozszerzeniem są ignorowane.

Gilles
źródło
1
odmiana aplikacji Railsowej: znajdź. -path './log' -prune -o -path './trunk' -prune -o -path './branches' -prune -o -path './vendor' -prune -o -path './tmp '-prune -o -print | egrep '\ .rb | \ .erb | \ .css | \ .js | \ .yml' | grep -v 'svn' | kot xargs | sed '/ ^ \ s * $ / d' | wc -l
poseid
1
Musisz dodać a $do grep ( ...\.js$|...), w przeciwnym razie będzie pasować feature.js.swp.
Xeoncross
Zapomniałeś o zakotwiczeniu, więc zawiera niewłaściwe pliki. I jeszcze prostsza wersja z zakotwiczeniem:find . | egrep '.\.c$|.\.h$' | xargs cat | sed '/^\s*$/d' | wc -l
Mark Jeronimus
36

Jeśli chcesz użyć czegoś innego niż skrypt powłoki, wypróbuj CLOC :

cloc liczy puste wiersze, wiersze komentarzy i fizyczne wiersze kodu źródłowego w wielu językach programowania. Został napisany w całości w Perlu bez żadnych zależności poza standardową dystrybucją Perla w wersji 5.6 i nowszej (kod z niektórych zewnętrznych modułów jest osadzony w cloc), a więc jest dość przenośny.

xsl
źródło
2
Kiedy po raz pierwszy zadałem to pytanie, „cloc” liczył dokumenty Pythona jako wiersze kodu, co było nieoptymalnym IMHO. Współczesne wersje „cloc” liczą teraz ciągi dokumentacyjne Pythona jako komentarze, które lubię o wiele bardziej.
Jonathan Hartley
To jest poprawna odpowiedź! Właśnie wypróbowałem cloc i to działa dobrze.
LeeMobile
31

Można to zrobić na wiele sposobów, używając typowych narzędzi powłoki.

Moje rozwiązanie to:

grep -cve '^\s*$' <file>

Wyszukuje wiersze w <file> wiersze niedopasowania (-v) pasujące do wzorca (-e) '^ \ s * $', który jest początkiem wiersza, po którym następuje 0 lub więcej białych znaków, po których na końcu wiersza (tj. bez zawartości innej niż białe znaki) i wyświetla liczbę pasujących wierszy (-c) zamiast samych pasujących wierszy.

Zaletą tej metody w porównaniu z metodami wymagającymi potoku wcjest to, że możesz określić wiele plików i uzyskać oddzielną liczbę dla każdego pliku:

$ grep -cve '^\s*$' *.hh

config.hh:36
exceptions.hh:48
layer.hh:52
main.hh:39
SpoonMeiser
źródło
2
Dzięki! Nawiasem mówiąc, wc podaje liczbę dla każdego podanego pliku plus sumę.
Jonathan Hartley
1
Jednak nie, jeśli przepuszczasz do niego potok, ponieważ standardowo liczy się jako jeden plik.
SpoonMeiser
Moim zdaniem to najlepsza odpowiedź.
simhumileco
-eto nie jest konieczne. To normalne położenie wzorca i nie robisz z nim nic dziwnego. Ale nie ma nic złego w wyrażaniu się wprost, jeśli taki jest twój styl.
Jacktose
13

'wc' liczy linie, słowa, znaki, więc aby policzyć wszystkie linie (w tym puste) użyj:

wc *.py

Aby odfiltrować puste wiersze, możesz użyć grep:

grep -v '^\s*$' *.py | wc

`-v 'mówi grepowi, że ma wypisać wszystkie wiersze z wyjątkiem tych, które pasują do' ^ 'to początek linii' \ s * 'to zero lub więcej białych znaków' $ 'to koniec linii * .py to mój przykład dla wszystkie pliki, które chcesz policzyć (wszystkie pliki Pythona w bieżącym katalogu) potokują wyjście do wc. Dalej.

Odpowiadam na swoje (prawdziwe) pytanie. Nie udało się znaleźć wpisu przepełnienia stosu, który to obejmował.

Jonathana Hartleya
źródło
5
\ W nie pasuje do białych znaków, dopasowuje znaki niebędące słowami. To przeciwieństwo \ w, znaków słownych. \ W Będzie pasować do wszystkiego, co nie jest alfanumeryczne ani podkreślone, a zatem nie będzie robić tego, co twierdzisz, że robi tutaj. Masz na myśli \ s
SpoonMeiser,
9

To polecenie liczy liczbę niepustych wierszy.
cat fileName | grep -v ^$ | wc -l
grep -v ^ $ funkcja wyrażenia regularnego ignoruje puste wiersze.

linia brzegowa
źródło
Ta odpowiedź jest najprostsza
samthebest
2
W cattym łańcuchu nie ma potrzeby :grep -v ^$ fileName | wl -l
Aethalides
7
Nie ma też takiej potrzeby, wc -lponieważ grep ma -c:grep -vc ^$ fileName
Jacktose
6
cat file.txt | awk 'NF' | wc -l
Jaydillan
źródło
uwielbiam prostotę tego 👏🏼
Gerard
5
cat 'filename' | grep '[^ ]' | wc -l

powinien załatwić sprawę dobrze

curtisk
źródło
3
Po co używać cat i potokować plik do grep, skoro w pierwszej kolejności można przekazać nazwę pliku jako argument do grep?
SpoonMeiser
to prawda, to tylko stary alias, który mam w pobliżu ... zasadniczo robi to samo, co twoje rozwiązanie zamiast używać odwrotności
curtisk
4
awk '/^[[:space:]]*$/ {++x} END {print x}' "$testfile"
Ben Hoffstein
źródło
1
Zagłosowałbym za tym tylko dlatego, że dosłownie nigdy nie widziałem nikogo, kto używa preinkrementacji w skrypcie awk, ale niestety liczy to tylko puste wiersze. :) Masz na myśli awk '!/^[[:space:]]*$/{++x} END{print x}'. Lub, jeśli naprawdę nienawidzisz negatywów awk '{y++} /^[[:space:]]*$/{++x} END{print y-x}',;)
dannysauer
4
grep -cvE '(^\s*[/*])|(^\s*$)' foo

-c = count
-v = exclude
-E = extended regex
'(comment lines) OR (empty lines)'
where
^    = beginning of the line
\s   = whitespace
*    = any number of previous characters or none
[/*] = either / or *
|    = OR
$    = end of the line

Publikuję to, ponieważ inne opcje dały mi złe odpowiedzi. To działało z moim źródłem java, gdzie linie komentarzy zaczynają się od / lub * (używam * w każdym wierszu w komentarzu wielowierszowym).

sami
źródło
To wykonalne rozwiązanie. Jedyna rzecz, na którą należy zwrócić uwagę: nie obejmuje komentarzy wieloliniowych
Amol,
2

Oto skrypt Bash, który zlicza wiersze kodu w projekcie. Przechodzi rekurencyjnie przez drzewo źródłowe i wyklucza puste wiersze 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`

    # To exclude only blank lines and count comment lines, uncomment this:
    #numLines=`cat $file | 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 wynik 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

Cieszyć się! - Curran

curran
źródło
1

To będzie zależało od liczby plików, które masz w projekcie. Teoretycznie możesz użyć

grep -c '.' <list of files>

Gdzie możesz wypełnić listę plików za pomocą narzędzia wyszukiwania.

grep -c '.' `find -type f`

Dałoby ci liczbę wierszy na plik.

Linor
źródło
1
. dopasowuje spacje. To rozwiązanie działa tylko wtedy, gdy uważasz, że linia zawierająca tylko białe znaki nie jest pusta, co technicznie jest takie, chociaż prawdopodobnie nie jest tym, czego szukasz.
SpoonMeiser
1

Skrypt do rekurencyjnego zliczania wszystkich niepustych wierszy z określonym rozszerzeniem pliku w bieżącym katalogu:

#!/usr/bin/env bash
(
echo 0;
for ext in "$@"; do
    for i in $(find . -name "*$ext"); do
        sed '/^\s*$/d' $i | wc -l ## skip blank lines
        #cat $i | wc -l; ## count all lines
        echo +;
    done
done
echo p q;
) | dc;

Przykładowe użycie:

./countlines.sh .py .java .html
Keith Pinson
źródło
Podziękowania dla @Andy Lester (+1 w komentarzu) za „niepustą” część przepisu.
Keith Pinson
Dziękuję również @Michaelowi Cramerowi (+1 w Twoim poście) za pierwotne opublikowanie (nieco bardziej rozwlekłego) rozwiązania „niepustego”.
Keith Pinson
1

Jeśli chcesz uzyskać sumę wszystkich niepustych wierszy dla wszystkich plików o danym rozszerzeniu w całym projekcie:

while read line
do grep -cve '^\s*$' "$line"
done <  <(find $1 -name "*.$2" -print) | awk '{s+=$1} END {print s}'

Pierwszy argument to katalog podstawowy projektu, drugi to rozszerzenie pliku. Przykładowe użycie:

./scriptname ~/Dropbox/project/src java

To niewiele więcej niż zbiór wcześniejszych rozwiązań.

Andy
źródło
Ten otrzymuje nagrodę za największą liczbę wywołań fork + exec, uruchamiając grep raz na wiersz w każdym pliku. ;)
dannysauer
0
grep -v '^\W*$' `find -type f` | grep -c '.' > /path/to/lineCountFile.txt

podaje łączną liczbę wszystkich plików w bieżącym katalogu i jego podkatalogach.

HTH!

holenderski
źródło
\ W to znaki niebędące słowami; nie będzie to pasowało ${-[*]} + $@na przykład do linii . Który z pewnością jest prawidłowym kodem gdzieś na świecie. ;) Masz na myśli przestrzeń.
dannysauer
0

To daje liczbę wierszy bez liczenia pustych wierszy:

grep -v ^$ filename wc -l | sed -e 's/ //g' 
mahesh
źródło
0
rgrep . | wc -l

podaje liczbę niepustych wierszy w bieżącym katalogu roboczym.

jean-emmanuel
źródło
-3

W Linuksie jest już program o nazwie „wc”.

Właśnie

wc -l *.c 

i daje całkowitą liczbę wierszy i wierszy dla każdego pliku.

G1i1ch
źródło
3
Hej. Samo „wc” nie przeszukuje podkatalogów i nie odfiltrowuje pustych wierszy, o które wyraźnie proszono w pytaniu.
Jonathan Hartley
wcliczy puste wiersze. Operator operacyjny chce liczyć niepuste wiersze. To prawda, że ​​będzie chciał użyć wc, ale dopiero po tym, jak został on sed
streamowany