3

I'm quite new to bash, and I'm trying to count the number of chars in a file. I wrote the following function:

function chars(){
    m=$(cat $1)
    m=${#m}
    echo $m
}

calling it with echo $(chars $2) results on a file the number 524, while calling wc -c on the same file results 525. What causes the difference? How can I get the same result? (and as a side question - can I combine the two first lines of my function into one?)

2
  • 1
    check man wc and you can avoid cat by using m=$(< $1) Commented Nov 3, 2013 at 12:01
  • your first line m=$(cat $1) puts the whole file inside $m EXCEPT FOR ANY TRAILING NEWLINE. So I guess your file has a trailing(=last) newline, hence the 1 byte difference. The shell act this way as it's usually what people want. Ex: when we do match=$(grep something somefile) ; echo "$match" ; : Echo adds a newline on its own, and if the shell kept the matching-line's newline you'd have 2 newlines in a row. But we don't expect to have an additionnal newline if the matched line had one... we usually just want the line without its terminating newline. So it's the shell's default behavior. Commented Nov 4, 2013 at 13:51

3 Answers 3

3

wc -c returns the byte counts.

wc -m returns the character counts.

Since your function calculates the number of characters, I think the output number of your function should match the output of wc -m instead.

4
  • wc -m returns the same as wc -c on that file.
    – elyashiv
    Commented Nov 3, 2013 at 12:10
  • @elyashiv: that's because for that file, characters are encoded each with 1 byte. This is NOT always the case (ie, if you use utf8, for example, some characters will be encoded with 1 byte, some with 2 bytes, some even more than that! And other encoding have also different sizes. That's why they provide 2 options, -c to count bytes, -m to count characters) Commented Nov 4, 2013 at 13:49
  • @elyashiv: would it be possible for you to share your input file? I tried this on multiple files on my system, and wc -m output always returned the same as your function did. Commented Nov 4, 2013 at 14:09
  • @chirag64: the 1 byte diff is probably an additional newline at the end of the file (lost by hist first line, see my comment under the question) Commented Nov 4, 2013 at 14:13
1

You can try wc command as follows:

echo -n file | wc -m 

This way the added extra newline character wont be counted by wc. Usually there is a newline character (added by the editor) at the end of files which is counted by wc. So if you want to count that character as well you should modify your solution otherwise your function works fine.

0

Without seeing your file it's difficult to say why conclusively but here's a little sample file I put together that shows one problem with counting in Bash in this manner:

Example

$ cat afile 
blah
blah


<EOF>

The <EOF> isn't really in the file, it's just there to show everyone that this file has 2 blank lines at the end. So just by hand counting this file it has 12 characters in it, assuming 8 + 4 (line feeds).

Counting this file using the typical methods:

$ wc -m afile 
12 afile

Number of bytes:

$ wc -c afile 
12 afile

Using your method:

$ m=$(< afile)
$ echo ${#m}
9

It would appear that this method of counting doesn't work as you're expecting. It can't count the end of line characters (\n) that are present on lines that contain no other characters.

Your problem

Based on your explanation of the problem, 524 vs. 525, sounds like the sample file has a blank line in it.

I would use wc in this application and not try and roll my own solution. These tools exist for a reason, don't reinvent the wheel. Unix has slick mag ones already made for your car.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .