Count lines of code

5,399 views
Skip to first unread message

Archos

unread,
Mar 14, 2012, 7:27:49 PM3/14/12
to golang-nuts
go tool could have a flag to get the number of lines into a project.

In linux, you can use:
grep -v "^$" *.go | grep -v "//" | wc -l

but (1) windows user have not those tools, and (2) you need remember
that large line to get it.

Archos

unread,
Mar 14, 2012, 7:39:47 PM3/14/12
to golang-nuts
And (3) grep cann't remove comments in multiple lines (/* */).

As suggestion, it could be called using "go loc" (Lines Of Code)

Brad Fitzpatrick

unread,
Mar 14, 2012, 7:54:45 PM3/14/12
to Archos, golang-nuts
Or, rather than throw ever imaginable program into the go command, you could just write it yourself, in Go, and Windows users (as well as any other user) can "go get" it.

Archos

unread,
Mar 14, 2012, 8:05:29 PM3/14/12
to golang-nuts
I see it enough usefull like to be into the go command

On Mar 14, 11:54 pm, Brad Fitzpatrick <bradf...@golang.org> wrote:
> Or, rather than throw ever imaginable program into the go command, you
> could just write it yourself, in Go, and Windows users (as well as any
> other user) can "go get" it.
>

kortschak

unread,
Mar 14, 2012, 8:06:17 PM3/14/12
to golan...@googlegroups.com, Archos
O even just use a tool that already handles the problem well...

cloc <http://cloc.sourceforge.net/> handles Go code.


On Thursday, March 15, 2012 10:24:45 AM UTC+10:30, Brad Fitzpatrick wrote:
Or, rather than throw ever imaginable program into the go command, you could just write it yourself, in Go, and Windows users (as well as any other user) can "go get" it.

On Wed, Mar 14, 2012 at 4:39 PM, Archos wrote:

David Anderson

unread,
Mar 14, 2012, 8:06:28 PM3/14/12
to Archos, golang-nuts
I think the go command should support grepping through source code, in case the user doesn't have grep installed.

- Dave

Hotei

unread,
Mar 14, 2012, 8:08:31 PM3/14/12
to golan...@googlegroups.com
Actually windows versions of those tools (sh, grep and wc) have been around for decades.  You might have to search for them a bit but they're out there.   I like Brad's solution too, I just wanted to correct your assumption.

andrey mirtchovski

unread,
Mar 14, 2012, 8:08:52 PM3/14/12
to golang-nuts
so "no", then, on the "go" command being able to do my taxes?

Andrew Gerrand

unread,
Mar 14, 2012, 8:12:54 PM3/14/12
to andrey mirtchovski, golang-nuts
On 15 March 2012 11:08, andrey mirtchovski <mirtc...@gmail.com> wrote:
> so "no", then, on the "go" command being able to do my taxes?

I'm working on adding a web browser to the go command. It's blocked by
the upcoming emacs integration, though.

Sameer Ajmani

unread,
Mar 14, 2012, 9:11:10 PM3/14/12
to andrey mirtchovski, golang-nuts

I would prioritize "go domytaxes" way ahead of "go cloc".

Aram Hăvărneanu

unread,
Mar 14, 2012, 9:18:40 PM3/14/12
to Sameer Ajmani, andrey mirtchovski, golang-nuts
go cat -v

--
Aram Hăvărneanu

Francisco Souza

unread,
Mar 14, 2012, 9:28:36 PM3/14/12
to Andrew Gerrand, andrey mirtchovski, golang-nuts
Just integrate it with emacs, and we get the butterfly mode.

--
~f

Jesse McNelis

unread,
Mar 14, 2012, 9:31:49 PM3/14/12
to golang-nuts

That should have been in there from the start. How else are we
supposed to access godoc? What if my operating system doesn't have a
web browser!


--
=====================
http://jessta.id.au

Michael Jones

unread,
Mar 14, 2012, 7:49:17 PM3/14/12
to Archos, golang-nuts
Why not a "go stats" to count (and report as desired) doc content lines, exported symbols, function arguments and return types, line counts, and so on. Then in the spirit of "wc -l" you could get source code lines sans comments if that is what you want, or much more if that pleases you.

On Wed, Mar 14, 2012 at 4:39 PM, Archos <raul...@sent.com> wrote:



--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

jimmy frasche

unread,
Mar 14, 2012, 9:50:42 PM3/14/12
to Michael Jones, Archos, golang-nuts
I wrote something like that a while back.

I never got around to giving it a finishing polish and haven't updated
it against the changes to the go/* packages in almost a year.

And I'll probably never do so, but if anyone's interested the little
guy's free to a good home.

Whole thing's only 337 lines in the wc -l sense so it probably
shouldn't be too difficult to update it or use as a sketch for a
rewrite.

Scott Lawrence

unread,
Mar 14, 2012, 9:59:30 PM3/14/12
to Archos, golang-nuts
htttps://github.com/bytbox/sloc handles go, and so does ohcount. But sloc is
written in go, only 300 lines, and an order of magnitude faster, so use that.
(Disclaimer: it's mine!)

Note that your pipeline doesn't handle block comments.

--
Scott Lawrence

go version weekly.2012-03-04 +1f5208fb59ff
Linux jagadai 3.2.9-1-ARCH #1 SMP PREEMPT Thu Mar 1 09:31:13 CET 2012 x86_64 Intel(R) Core(TM)2 Duo CPU P8700 @ 2.53GHz GenuineIntel GNU/Linux

Mike Rosset

unread,
Mar 14, 2012, 11:03:26 PM3/14/12
to Archos, golang-nuts

IMO it would be great to have some unix tools that are written in pure
Go. mainly things like grep, cp, mv,wc etc. but the go tool is
probably not the best candidate.

Reinhard Wobst

unread,
Mar 15, 2012, 5:52:05 AM3/15/12
to golang-nuts
A long time ago I wrote such a tool for C/C++, then for Python, and
the adaption for Go was trivial. It is written in Python and should
work under Windows without change. It does a bit more - it searches
for files recursively from the current directory (this is what
interested me), skips blank lines (not only empty lines), and show the
longest file (for code hygiene). Since it has 57 lines only, I dare to
include it here:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# R.Wobst, @(#) Mar 15 2012, 10:43:46
#
# count Go source lines recursively excluding comments and blank lines
# usage:
# LOCgo
# (in top directory)

import os, os.path

## @brief count lines excluding empty lines and comments
#
# @param fn - name of source file
# @return - number of lines

def getsrclin(fn):
cnt = 0
comm = False
fd = open(fn, 'r')

for lin in fd:
lin = lin.strip()
if not lin or lin.startswith('//'):
continue
if lin.startswith('/*'):
comm = True
if comm and '*/' in lin:
comm = False
continue
if comm:
continue
cnt += 1
fd.close()
return cnt

total = 0
maxcnt = -1

for (path, dirs, files) in os.walk('.'):
for f in files:
if f.endswith('.go'):
pf = os.path.join(path, f)
cnt = getsrclin(pf)
total += cnt
if cnt > maxcnt:
maxcnt = cnt
maxfile = pf
fill = (30 - len(pf))*' '
if not fill:
fill = ' '
print '%s:%s%d' % (pf, fill, cnt)

print
print "total: %d lines" % total
if maxcnt > 0:
print "maximum: %d lines\n\tin file %s" % (maxcnt, maxfile)

Have fun!

Reinhard

Reinhard Wobst

unread,
Mar 15, 2012, 5:56:19 AM3/15/12
to golang-nuts
... it should be noted that it regards comments /* ... */ only if they
don't start after some statement, i..e.

a += BB(b) /* this comment
is continued in the next line, what is really bad style */

will not be regarded ...

Jan Mercl

unread,
Mar 15, 2012, 6:15:09 AM3/15/12
to golan...@googlegroups.com
It's possible to pipe the sources through gofmt -comments=false: http://weekly.golang.org/cmd/gofmt/

I use this (replace '.' with any other path of interest):

$ find . -name \*.go -execdir gofmt -comments=false {} \; | wc -l

Michael Jones

unread,
Mar 15, 2012, 9:40:43 AM3/15/12
to Jan Mercl, golan...@googlegroups.com
interesting!

On Thu, Mar 15, 2012 at 3:15 AM, Jan Mercl <0xj...@gmail.com> wrote:
find . -name \*.go -execdir gofmt -comments=false {} \; | wc -l

mtj$ cd
mtj$ cd go
mtj$ find . -name \*.go -execdir gofmt -comments=false {} \; | wc -l
blank1.go:10:11: invalid package name _
char_lit1.go:16:8: escape sequence is invalid Unicode code point
char_lit1.go:17:8: escape sequence is invalid Unicode code point
char_lit1.go:18:8: escape sequence is invalid Unicode code point
char_lit1.go:19:8: escape sequence is invalid Unicode code point
char_lit1.go:20:8: escape sequence is invalid Unicode code point
char_lit1.go:23:8: escape sequence is invalid Unicode code point
char_lit1.go:25:11: escape sequence is invalid Unicode code point
char_lit1.go:26:8: escape sequence is invalid Unicode code point
const2.go:14:8: expected '=', found ';'
const2.go:15:1: expected operand, found ')'
const2.go:17:1: expected ';', found 'const'
const2.go:18:1: expected 'IDENT', found 'const'
const2.go:19:1: expected 'IDENT', found 'const'
const2.go:21:1: expected 'IDENT', found 'const'
ddd1.go:49:7: expected array length, found '...'
ddd1.go:50:6: expected expression
ddd1.go:52:2: expected ']', found 'EOF'
bug050.go:7:1: expected 'package', found 'func'
bug068.go:12:13: unknown escape sequence
bug083.go:7:1: expected 'package', found 'IDENT' ignored
bug088.go:7:1: expected 'package', found 'IDENT' ignored
bug106.go:7:1: expected 'package', found 'IDENT' ignored
bug121.go:12:3: expected ';', found ','
bug121.go:15:1: expected '}', found 'type'
bug133.go:7:1: expected 'package', found 'IDENT' ignored
bug160.go:7:1: expected 'package', found 'IDENT' nothing
bug163.go:10:3: illegal character U+229B '⊛'
bug163.go:11:3: expected '}', found 'EOF'
bug169.go:8:9: illegal character literal
bug217.go:12:6: expected exactly one receiver
bug217.go:14:6: expected exactly one receiver
bug222.go:7:1: expected 'package', found 'IDENT' ignored
bug228.go:11:25: expected type, found '...'
bug228.go:17:7: expected '=', found '...'
bug228.go:19:8: expected type, found '...'
bug248.go:12:1: expected 'package', found 'IDENT' ignored
bug274.go:24:2: expected statement, found 'case'
bug280.go:11:9: expected operand, found '...'
bug280.go:13:2: expected ']', found 'EOF'
bug282.go:7:1: expected 'package', found 'IDENT' ignored
bug287.go:11:14: expected operand, found '...'
bug298.go:10:2: expected declaration, found 'for'
bug299.go:16:2: expected anonymous field
bug299.go:17:2: expected anonymous field
bug299.go:18:2: expected anonymous field
bug299.go:25:9: expected (unqualified) identifier
bug299.go:26:10: expected (unqualified) identifier
bug299.go:27:9: expected (unqualified) identifier
bug300.go:23:6: expected expression
bug300.go:29:3: expected '}', found 'EOF'
bug302.go:6:2: expected 'package', found 'EOF'
bug306.go:7:1: expected 'package', found 'IDENT' ignored
bug322.go:8:1: expected 'package', found 'IDENT' ignored
bug324.go:8:1: expected 'package', found 'IDENT' ignored
bug335.go:10:1: expected 'package', found 'IDENT' unused
bug340.go:14:7: expected type, found 'INT' 0
bug349.go:12:14: expected ';', found 'FLOAT' 2.01
bug349.go:13:3: expected '}', found 'EOF'
bug351.go:12:2: expected identifier
bug358.go:19:9: expected expression
bug388.go:12:10: expected identifier
bug388.go:17:2: expected identifier
bug388.go:22:2: expected identifier
bug388.go:27:10: expected '=', found '.'
bug388.go:32:9: expected '=', found '.'
bug388.go:39:3: expected '}', found 'EOF'
bug394.go:10:1: expected declaration, found 'return'
func3.go:16:9: expected identifier
func3.go:17:13: expected identifier
func3.go:18:19: expected 'IDENT', found '*'
import5.go:24:8: expected 'STRING', found 'INT' 42
import5.go:25:8: expected 'STRING', found 'CHAR' 'a'
import5.go:26:8: expected 'STRING', found 'FLOAT' 3.14
import5.go:27:8: expected 'STRING', found 'IMAG' 0.25i
import5.go:34:8: invalid import path: ""
import5.go:35:8: invalid import path: ``
import5.go:36:8: invalid import path: "\x00"
import5.go:37:8: invalid import path: `\x00`
import5.go:38:8: invalid import path: "\x7f"
import5.go:39:8: invalid import path: `\x7f`
import5.go:40:8: invalid import path: "a!"
import5.go:41:8: invalid import path: `a!`
import5.go:42:8: invalid import path: "a b"
import5.go:43:8: invalid import path: `a b`
import5.go:44:8: invalid import path: "a\\b"
import5.go:45:8: invalid import path: `a\\b`
import5.go:46:8: invalid import path: "\"`a`\""
import5.go:47:8: invalid import path: `\"a\"`
import5.go:48:8: invalid import path: "\x80\x80"
import5.go:49:8: invalid import path: `\x80\x80`
import5.go:50:8: invalid import path: "\xFFFD"
import5.go:51:8: invalid import path: `\xFFFD`
import5.go:55:8: invalid import path: "c:/foo"
chan.go:11:1: expected type, found '}'
chan.go:13:1: expected '}', found 'func'
chan1.go:13:5: expected condition, found simple statement
chan1.go:17:11: expected ';', found '<-'
forvar.go:10:6: expected operand, found 'var'
if.go:13:5: expected operand, found '{'
if.go:16:2: expected '{', found 'if'
if.go:18:3: expected '}', found 'EOF'
import.go:10:6: expected ';', found ','
import.go:14:2: expected ')', found 'EOF'
interface.go:10:3: expected ';', found ','
interface.go:14:2: expected '}', found 'EOF'
semi1.go:10:11: expected '{', found newline
semi1.go:14:2: expected '}', found 'EOF'
semi2.go:10:14: expected '{', found newline
semi2.go:11:2: expected '}', found '{'
semi2.go:12:3: expected ';', found 'IDENT' z
semi2.go:14:2: expected '}', found 'EOF'
semi3.go:10:14: expected '{', found newline
semi3.go:14:2: expected '}', found 'EOF'
semi4.go:11:2: expected operand, found '{'
semi4.go:14:2: expected ';', found 'EOF'
semi5.go:10:1: expected declaration, found '{'
semi6.go:9:8: expected type, found newline
semi6.go:10:1: expected ';', found '{'
semi7.go:11:2: expected statement, found 'else'
semi7.go:14:2: expected '}', found 'EOF'
topexpr.go:9:1: expected declaration, found 'IDENT' fmt
typesw.go:10:9: expected identifier
vareq.go:10:25: expected ';', found '{'
vareq1.go:9:24: expected ';', found '{'
  367624

Michael Jones

unread,
Mar 15, 2012, 9:45:40 AM3/15/12
to Jan Mercl, golan...@googlegroups.com
...it is a showcase of all the tests. For the src directory, the count (at tip) s 301477. Builds in 34 seconds. ;-)
--

Jan Mercl

unread,
Mar 15, 2012, 5:48:18 PM3/15/12
to golan...@googlegroups.com, Jan Mercl
On Thursday, March 15, 2012 2:40:43 PM UTC+1, Michael Jones wrote:
interesting!

On Thu, Mar 15, 2012 at 3:15 AM, Jan Mercl <0x...@gmail.com> wrote:
find . -name \*.go -execdir gofmt -comments=false {} \; | wc -l

Oops, I forgot gofmt can handle the tree walk by itself - the above is an overkill. Enough is:

22:45 myname@tux64:~$ gofmt -comments=false $GOROOT/src | wc -l
301198
22:46 myname@tux64:~$ 

 

Robin J. Rogge

unread,
Mar 17, 2012, 8:42:26 AM3/17/12
to golang-nuts
how about "go away <package>" as alias for "goinstall -clean=true -install=false <package>" ;-)

Samuel Lampa

unread,
Jul 27, 2015, 5:52:07 AM7/27/15
to golang-nuts, raul...@sent.com, m...@google.com
On Thursday, March 15, 2012 at 12:49:17 AM UTC+1, Michael Jones wrote:
Why not a "go stats" to count (and report as desired) doc content lines, exported symbols, function arguments and return types, line counts, and so on. Then in the spirit of "wc -l" you could get source code lines sans comments if that is what you want, or much more if that pleases you.

+1. This is the kind of tool I'd have expected :)

Egon

unread,
Jul 27, 2015, 6:03:47 AM7/27/15
to golang-nuts, raul...@sent.com, m...@google.com, samuel...@gmail.com
I recently implemented a tool that counts lines https://github.com/loov/qloc. Although it doesn't give any comment related information. Shouldn't be difficult to add, but I simply didn't want to hardcode file-type information.

Samuel Lampa

unread,
Jul 27, 2015, 6:27:55 AM7/27/15
to Egon, golang-nuts, raul...@sent.com, m...@google.com
Nice, will use! :)

Staven

unread,
Jul 27, 2015, 6:58:09 AM7/27/15
to golang-nuts
Why is there no `go sandwich` command? I get hungry when coding sometimes,
I expected there to be a command for solving that problem.

Seriously though, let's not turn go into busybox.

Reply all
Reply to author
Forward
0 new messages