I'm sure there are many ways to do this: how can I count the number of lines in a text file?
$ <cmd> file.txt
1020 lines
I'm sure there are many ways to do this: how can I count the number of lines in a text file?
$ <cmd> file.txt
1020 lines
The standard way is with wc
, which takes arguments to specify what it should count (bytes, chars, words, etc.); -l
is for lines:
$ wc -l file.txt
1020 file.txt
Steven D forgot GNU sed
:
sed -n '$=' file.txt
Also, if you want the count without outputting the filename and you're using wc
:
wc -l < file.txt
Just for the heck of it:
cat -n file.txt | tail -n 1 | cut -f1
grep -c ''
, or tr -dc '\n' | wc -c
, or nl -ba -nln | tail -n 1 |sed -e 's/[^0-9].*//'
... Is any of these useful in itself (as opposed to things to build upon to make a program that does more than counting lines), other than wc -l
and pure (ba)sh?
– Gilles 'SO- stop being evil'
Dec 03 '10 at 01:58
uniq
, with only POSIX tools to help you and no constraint on the line length?
– Gilles 'SO- stop being evil'
Dec 03 '10 at 02:21
cat -n
since before GNU existed. As a matter of fact, HP-UX has it (PDF), Solaris does, FreeBSD as early as 1.0 does, even 2.10 BSD (1986) ...
– Dennis Williamson
Dec 03 '10 at 02:27
--number
.
– Dennis Williamson
Dec 03 '10 at 02:35
uniq
, you're piping it into sed
).
– Gilles 'SO- stop being evil'
Dec 03 '10 at 08:10
uniq -c -w 0 file.txt
and you can cut -c -7
to keep only the number. Or, more POSIXly: uniq -c file.txt | awk '{c+=$1}END{print c}'
. How about dc
(even though it's not POSIX)? uniq -c file.txt | cut -c -7 | sed '$alax' | dc -e '[pq]sb[+z1=blax]sa' -
. bc
is POSIX: uniq -c file.txt | cut -c -7 | sed -n ':a;${s/\n/ + /gp;b};N;ba' | bc
. The easy answer if you assume a limited line length: uniq -c -f 100000 file.txt
.
– Dennis Williamson
Dec 03 '10 at 16:21
'$='
so it doesn't get expanded by the shell - the command above as is fails with zsh. (Would have edited it myself, but it's just 2 characters of difference...)
– Josip Rodin
Oct 17 '15 at 20:19
sed '$='
is not only GNU sed
, the =
is a SUSv4 sed
command and the address $
is also specified as the last line by SUSv4.
– Kusalananda
Jul 05 '16 at 09:49
As Michael said, wc -l
is the way to go. But, just in case you inexplicably have bash
, perl
, or awk
but not wc
, here are a few more solutions:
$ LINECT=0; while read -r LINE; do (( LINECT++ )); done < file.txt; echo $LINECT
$ perl -lne 'END { print $. }' file.txt
and the far less readable:
$ perl -lne '}{ print $.' file.txt
$ awk 'END {print NR}' file.txt
Word of warning when using
wc -l
because wc -l functions by counting \n, if the last line in your file doesn't end in a newline effectively the line count will be off by 1. (hence the old convention leaving newline at the end of your file)
Since I can never be sure if any given file follows the convention of ending the last line with a newline or not, I recommend using any of these alternate commands which will include the last line in the count regardless of newline or not.
sed -n $= filename
perl -lne 'END { print $. }' filename
awk 'END {print NR}' filename
grep -c '' filename
You can always use the command grep
as follows:
grep -c "^" file.txt
It will count all the actual rows of file.txt
, whether or not its last row contains a LF character at the end.
In case you only have bash and absolutely no external tools available, you could also do the following:
count=0
while read
do
((count=$count+1))
done <file.txt
echo $count
Explanation: the loop reads standard input line by line (read
; since we do nothing with the read input anyway, no variable is provided to store it in), and increases the variable count
each time. Due to redirection (<file.txt
after done
), standard input for the loop is from file.txt
.
If you're looking to count smaller files a simple wc -l file.txt
could work.
Looking for an answer to this question myself, working with large files that are several gigs, I found the following tool:
https://github.com/crioux/turbo-linecount
Also, depending on your system configuration--if you're using an older version of wc
you might be better off piping larger chunks with dd
like so:
dd if={file_path} bs=128M | wc -l
grep -c $
is very simple and works great.
I even saved it as an alias since I use it a lot (lc
stand for line count):
alias lc="grep -c $"
It can be used either this way:
lc myFile
Or that way:
cat myFile | lc
Note that this will not count the last line if it is empty. For my uses that is almost always OK though.
grep
implementation does not count the last line if it's empty, it's severely broken. On the contrary there are some grep
implementations that count the extra bytes found after the last newline in non-text files as an extra line. For instance, printf foo | grep -c $
outputs 1 with GNU grep
even though printf
outputs no line. printf foo | wc -l
correctly outputs 0.
– Stéphane Chazelas
Oct 30 '22 at 10:38
wc -l
will be off by 1 for files without a newline at the end of the file (in those cases it will not count the last line, even if it has text). Isn't that sort of more broken? For my personal use, I'd rather skip counting the newline at EOF than skip counting a line with actual stuff in it. But I guess everybody counts lines for different purposes, and wc -l
might be better for some! :)
– pitamer
Oct 30 '22 at 13:10
printf foo
does not form a text file.
– Stéphane Chazelas
Oct 30 '22 at 17:21
cat matlab.git.diff | sed -e '/^\+[ ]*.*\%$/d' | wc -l
./regexp/d
deletes a line if it matchesregexp
, and-e
turns on an adequate (IMNSHO) syntax forregexp
. – dbanet Nov 06 '13 at 21:29grep -v '^+ *%' matlab.git.diff | wc -l
? – celtschk Jul 06 '14 at 19:51grep
command in order to consider as comment cases like" + Hello"
(note the space(s) before the+
)? – Sopalajo de Arrierez Jan 18 '15 at 20:46grep -v '^ *+' matlab.git.diff | wc -l
(I'm assuming the quote signs were not actually meant to be part of the line; I also assume that both lines with and without spaces in front of the+
are meant to be comments; if at least one space is mandatory, either replace the star*
with\+
, or just add another space in front of the star). Probably instead of matching only spaces, you'd want to match arbitrary whitespace; for this replace the space with[[:space:]]
. Note that I've also removed matching the%
since it's not in your example. – celtschk Feb 14 '15 at 15:02