Anzahl (nicht leere) Codezeilen in Bash zählen

150

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

Jonathan Hartley
quelle
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.

Michael Cramer
quelle
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.

Gilles
quelle
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.

xsl
quelle
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
SpoonMeiser
quelle
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.

Jonathan Hartley
quelle
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.

Küste
quelle
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
6
cat file.txt | awk 'NF' | wc -l
Jaydillan
quelle
liebe die Einfachheit dieses einen 👏🏼
Gerard
5
cat 'filename' | grep '[^ ]' | wc -l

sollte den Trick gut machen

Curtisk
quelle
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"
Ben Hoffstein
quelle
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).

Sami
quelle
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

curran
quelle
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.

Linor
quelle
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
Keith Pinson
quelle
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.

Andy
quelle
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!

Niederländisch
quelle
\ 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' 
Mahesh
quelle
0
rgrep . | wc -l

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

Jean-Emmanuel
quelle
-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.

G1i1ch
quelle
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