Anzahl (nicht leere) Codezeilen in Bash zählen


150

Wie zähle ich in Bash die Anzahl der nicht leeren Codezeilen in einem Projekt?


1
Viele der folgenden Lösungen funktionieren nur für eine Datei (z foo.c. B. ). Irgendwelche Gedanken zur Gesamtzahl der Zeilen in einem Projekt (z. B. viele Dateien in der Verzeichnisstruktur und ohne Binärdateien)?
Lösen von Rätseln

5
@solvingPuzzles Ich denke, ich kann diesen Teil beantworten. Für jede Lösung, die mit einer Datei funktioniert, z. B. "cat FILE | sed blah", können Sie mit vielen Dateien arbeiten, indem Sie die "cat FILE" durch einen Befehl ersetzen, der die zu bearbeitenden Dateinamen auflistet, z. B. "find. -Name '* .py '"und leiten Sie das in" xargs cat ". zB "find. -name '* .py' | xargs cat | sed '/ ^ \ s * $ / d' | wc -l"
Jonathan Hartley

2
@JonathanHartley @solvingPuzzles Es gibt auch Programme wie slocund clocdiese sind hier, um diese Codezeilen zu zählen.
ASTeR

OP hier: Als ich dieses Problem zum ersten Mal stellte, hat 'cloc' bei Python-Code keine sehr gute Arbeit geleistet. Heutzutage ist es großartig.
Jonathan Hartley

cloc ist auch als npm-Modul erhältlich und spart viel Zeit.
Krishna Vedula

Antworten:


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

Und wenn Sie Kommentare als leere Zeilen betrachten:

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

Das ist allerdings sprachabhängig.


23
Ich bin mir nicht sicher, warum du dort Katze benutzt. Verwenden Sie foo.c oder foo.pl als Dateinamen, um an sed zu übergeben. sed '/ ^ \ s * $ / d' foo.c | wc -l
Andy Lester

27
Nur Gewohnheit. Ich lese Pipelines von links nach rechts, was bedeutet, dass ich normalerweise mit Katze beginne, dann mit Aktion, Aktion, Aktion usw. Das Endergebnis ist eindeutig dasselbe.
Michael Cramer

31
Um dies für alle Dateien in allen Unterordnern zu tun und Kommentare mit '//' auszuschließen, erweitern Sie diesen Befehl wie folgt: find. -type f -name '* .c' -exec cat {} \; | sed '/ ^ \ s * # / d; / ^ \ s * $ / d; / ^ \ s * \ / \ // d' | wc -l
Benjamin Intal

11
Sie können ohne UUOC von links nach rechts lesen : < foo.pl sed 'stuff' | wc -l.
jw013

22
Im Allgemeinen ist UUOC nicht wichtig, aber Lesbarkeit.
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

Oben sehen Sie die Gesamtzahl der Codezeilen (Leerzeilen entfernt) für ein Projekt (aktueller Ordner und alle Unterordner rekursiv).

In den obigen Abschnitten "./blog" "./punbb" "./js/3rdparty" und "./pma" sind Ordner, die ich auf die schwarze Liste gesetzt habe, da ich den Code nicht in sie geschrieben habe. Auch .php, .as, .sql, .css, .js sind die Erweiterungen der Dateien, die betrachtet werden. Alle Dateien mit einer anderen Erweiterung werden ignoriert.


1
Variation für eine Rails App: find. -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' | xargs cat | sed '/ ^ \ s * $ / d' | wc -l
Poseid

1
Sie müssen $dem grep ( ...\.js$|...) ein hinzufügen , sonst stimmt es überein feature.js.swp.
Xeoncross

Sie haben die Verankerung vergessen, daher enthält sie falsche Dateien. Und eine noch einfachere Version mit Verankerung:find . | egrep '.\.c$|.\.h$' | xargs cat | sed '/^\s*$/d' | wc -l
Mark Jeronimus

36

Wenn Sie etwas anderes als ein Shell-Skript verwenden möchten , versuchen Sie es mit CLOC :

cloc zählt in vielen Programmiersprachen Leerzeilen, Kommentarzeilen und physische Zeilen des Quellcodes. Es ist vollständig in Perl geschrieben, ohne Abhängigkeiten außerhalb der Standarddistribution von Perl v5.6 und höher (Code von einigen externen Modulen ist in cloc eingebettet) und daher recht portabel.


2
Als ich diese Frage zum ersten Mal stellte, zählte 'cloc' Python-Dokumentzeichenfolgen als Codezeilen, was meiner Meinung nach nicht optimal war. Moderne Versionen von 'cloc' zählen jetzt Python-Docstrings als Kommentare, was mir viel besser gefällt.
Jonathan Hartley

Das ist die richtige Antwort! Ich habe gerade Cloc ausprobiert und es macht den Job gut.
LeeMobile

30

Es gibt viele Möglichkeiten, dies mit gängigen Shell-Dienstprogrammen zu tun.

Meine Lösung ist:

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

Dies sucht nach Zeilen in <Datei>, die nicht mit (-v) Zeilen übereinstimmen, die mit dem Muster (-e) '^ \ s * $' übereinstimmen. Dies ist der Anfang einer Zeile, gefolgt von 0 oder mehr Leerzeichen am Ende einer Zeile (dh kein anderer Inhalt als Leerzeichen) und zeigen Sie eine Anzahl übereinstimmender Zeilen (-c) anstelle der übereinstimmenden Zeilen selbst an.

Ein Vorteil dieser Methode gegenüber Methoden, bei denen Pipings durchgeführt werden wc, besteht darin, dass Sie mehrere Dateien angeben und für jede Datei eine separate Anzahl erhalten können:

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

config.hh:36
exceptions.hh:48
layer.hh:52
main.hh:39

2
Vielen Dank! Übrigens liefert wc eine Zählung für jede gegebene Datei plus eine Summe.
Jonathan Hartley

1
Nicht, wenn Sie sich darauf einlassen, da standardmäßig nur eine Datei zählt.
SpoonMeiser

Dies ist meiner Meinung nach die beste Antwort.
Simhumileco

-eist nicht nötig. Das ist die normale Position des Musters und Sie machen nichts Ungewöhnliches damit. Aber nichts ist falsch daran, explizit zu sein, wenn das dein Stil ist.
Jacktose

13

'wc' zählt Zeilen, Wörter und Zeichen. Um alle Zeilen (einschließlich leerer) zu zählen, verwenden Sie:

wc *.py

Um die Leerzeilen herauszufiltern, können Sie grep verwenden:

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

'-v' weist grep an, alle Zeilen auszugeben, mit Ausnahme derjenigen, die mit '^' übereinstimmen. Dies ist der Anfang einer Zeile. '\ s *' ist null oder mehr Leerzeichen. '$' ist das Ende einer Zeile. * .py ist mein Beispiel für Alle Dateien, die Sie zählen möchten (alle Python-Dateien im aktuellen Verzeichnis), geben die Ausgabe an wc aus. Es kann losgehen.

Ich beantworte meine eigene (echte) Frage. Es konnte kein Stackoverflow-Eintrag gefunden werden, der dies abdeckte.


5
\ W stimmt nicht mit Leerzeichen überein, sondern mit Nicht-Wort-Zeichen. Es ist das Gegenteil von \ w, Wortzeichen. \ W Passt zu allem, was nicht alphanumerisch oder unterstrichen ist, und tut daher nicht das, was Sie hier behaupten. Du meinst \ s
SpoonMeiser

9

Dieser Befehl zählt die Anzahl der nicht leeren Zeilen.
cat fileName | grep -v ^$ | wc -l
Die Funktion grep -v ^ $ für reguläre Ausdrücke ignoriert Leerzeilen.


Diese Antwort ist die einfachste
samthebest

2
Es gibt keine Notwendigkeit catin dieser Kette:grep -v ^$ fileName | wl -l
Aethalides

7
Es gibt auch keine Notwendigkeit für, wc -lweil grep hat -c:grep -vc ^$ fileName
Jacktose


5
cat 'filename' | grep '[^ ]' | wc -l

sollte den Trick gut machen


3
Warum cat verwenden und die Datei in grep weiterleiten, wenn Sie den Dateinamen als Argument an grep übergeben können?
SpoonMeiser

wahr, es ist nur ein alter alias ich um sich zu haben ... es ist im Wesentlichen die gleiche wie Ihre Lösung anstelle der Verwendung der inversen
curtisk

4
awk '/^[[:space:]]*$/ {++x} END {print x}' "$testfile"

1
Ich würde das abstimmen, nur weil ich buchstäblich noch nie jemanden gesehen habe, der Vorinkremente in einem awk-Skript verwendet, aber leider zählt dies nur die Leerzeilen. :) Du meinst awk '!/^[[:space:]]*$/{++x} END{print x}'. Oder, wenn Sie Negative wirklich hassen , 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

Ich poste dies, weil andere Optionen falsche Antworten für mich gaben. Dies funktionierte mit meiner Java-Quelle, bei der Kommentarzeilen mit / oder * beginnen (ich verwende * in jeder Zeile in mehrzeiligen Kommentaren).


Dies ist eine praktikable Lösung. Einzige Sache zu beachten: es zählt nicht mehrzeilige Kommentare
Amol

2

Hier ist ein Bash-Skript, das die Codezeilen in einem Projekt zählt. Es durchläuft einen Quellbaum rekursiv und schließt Leerzeilen und einzeilige Kommentare aus, die "//" verwenden.

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

So sieht die Ausgabe für mein Projekt aus :

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

Genießen! - Curran


1

Es wird irgendwie von der Anzahl der Dateien abhängen, die Sie im Projekt haben. Theoretisch könnte man verwenden

grep -c '.' <list of files>

Hier können Sie die Liste der Dateien mit dem Dienstprogramm find füllen.

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

Würde Ihnen eine Zeilenanzahl pro Datei geben.


1
. entspricht Leerzeichen. Diese Lösung funktioniert nur, wenn Sie eine Zeile, die nur Leerzeichen enthält, als nicht leer betrachten, was technisch gesehen der Fall ist, obwohl es wahrscheinlich nicht das ist, wonach Sie suchen.
SpoonMeiser

1

Skript zum rekursiven Zählen aller nicht leeren Zeilen mit einer bestimmten Dateierweiterung im aktuellen Verzeichnis:

#!/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;

Beispielnutzung:

./countlines.sh .py .java .html

Vielen Dank an @Andy Lester (+1 in Ihrem Kommentar) für den "nicht leeren" Teil des Rezepts.
Keith Pinson

Vielen Dank auch an @Michael Cramer (+1 in Ihrem Beitrag) für die ursprüngliche Veröffentlichung der (etwas ausführlicheren) "nicht leeren" Lösung.
Keith Pinson

1

Wenn Sie die Summe aller nicht leeren Zeilen für alle Dateien einer bestimmten Dateierweiterung in einem Projekt wünschen:

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

Das erste Argument ist das Basisverzeichnis des Projekts, das zweite die Dateierweiterung. Beispielnutzung:

./scriptname ~/Dropbox/project/src java

Es ist kaum mehr als eine Sammlung früherer Lösungen.


Dieser erhält die Auszeichnung für die größte Anzahl von Fork + Exec-Aufrufen, indem grep einmal pro Zeile in jeder Datei gestartet wird. ;)
dannysauer

0
grep -v '^\W*$' `find -type f` | grep -c '.' > /path/to/lineCountFile.txt

Gibt eine Gesamtanzahl für alle Dateien im aktuellen Verzeichnis und seinen Unterverzeichnissen an.

HTH!


\ W ist kein Wort Zeichen; Dies passt nicht zu einer Linie wie ${-[*]} + $@zum Beispiel. Welches ist sicherlich gültiger Code irgendwo auf der Welt. ;) Du meinst \ s für Raum.
Dannysauer

0

Dies gibt die Anzahl der Zeilen an, ohne die Leerzeilen zu zählen:

grep -v ^$ filename wc -l | sed -e 's/ //g' 

0
rgrep . | wc -l

Gibt die Anzahl der nicht leeren Zeilen im aktuellen Arbeitsverzeichnis an.


-3

Unter Linux gibt es dafür bereits ein Programm namens 'wc'.

Gerade

wc -l *.c 

und es gibt Ihnen die Gesamtzahl der Zeilen und die Zeilen für jede Datei.


3
Hallo. 'wc' selbst durchsucht keine Unterverzeichnisse und filtert keine Leerzeilen heraus, die beide in der Frage explizit angefordert werden.
Jonathan Hartley

wczählt leere Zeilen. Das OP möchte nicht leere Zeilen zählen. Es ist wahr, dass er verwenden möchte wc, aber erst, nachdem es mitsed
EhevuTov
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.