26

Is there any possible situation when

ls -l file.txt

is showing not the same number of bytes as

wc -c file.txt

In one script I found comparison of those two values. What could be the reason of that? Is it even possible to have different byte counts of the same file?

2

3 Answers 3

13

Yes, there are such cases.

In case of symlinks on Linux system with GNU ls, the ls -l will put out the size of the link, while wc -c will resolve the actual file and read number of bytes there. Below you can see that ls -l reports 29 bytes , while wc reports 172 bytes in the actual file.

$ ls -l /etc/resolv.conf                                                                                                 
lrwxrwxrwx 1 root root 29 1月  17  2016 /etc/resolv.conf -> ../run/resolvconf/resolv.conf
$ wc -c /etc/resolv.conf                                                                                                 
172 /etc/resolv.conf
$ wc -c /var/run/resolvconf/resolv.conf                                                                                  
172 /var/run/resolvconf/resolv.conf
$ ls -l /var/run/resolvconf/resolv.conf                                                                                  
-rw-r--r-- 1 root root 172 1月  15 15:49 /var/run/resolvconf/resolv.conf

In case of virtual filesystems, such as /proc or /sys , many files there will show as having size 0 ls -l. Under /dev filesystem we have variety of special files, such as character devices and block devices - wc -c hangs on those and ls -l shows major and minor numbers instead of size.

Named pipes will be reported as 0 bytes by ls -c, but wc -c will actually read the contents of the pipe, so technically it will tell you how much data is in the named pipe:

$ mkfifo named.pipe                                                                                                      
$ echo "This is a test" > named.pipe &
[1] 2129
$ ls -l named.pipe
prw-rw-r-- 1 xieerqi xieerqi 0 1月  16 08:40 named.pipe|
$ wc -c named.pipe
15 named.pipe
[1] + Done                 echo "This is a test" >named.pipe 

For a regular files, the size should be equal.


The point of ls -l and wc -c, and how they work also differs. wc -c actually opens file for reading ( you can see that if you run strace wc -c /etc/passwd for example). ls -l only performs stat() call on those. This also explains why in /proc ls -l shows 0 size - you can't stat those files because they aren't "real" or actually stored on the hard-drive/ssd. wc -c instead, reads the contents of that file, and calculates its size.

Finally, ls -l is only a tool for listing items interactively. It's rarely a good fit for scripting. When you actually need to read the data, use wc -c instead.

Please note, that for scripting and assessing size of a file, ls is not the best candidate. In fact , it is a one of the common practices to avoid parsing ls output. Please use du -b for finding out the size of a file.

1
  • 1
    A small clarification - virtual files (in /sys/, /proc/, etc) may provide stat information, if the implementer chooses to. Most of the time, there isn't a compelling reason to, so it's omitted. Examples include /proc/kcore which is reported as the size of addressable kernel memory (usually much more than the available physical memory). Jan 17, 2017 at 10:24
12

ls -l will return the size of the file reported by the filesystem.

wc -c will attempt to read the file to determine the 'actual' size. From my observations it appears to first try seeking to the end, and if this doesn't work, it will read out the entire file, counting the size as it goes.

This is a simple description as to what the two tools do, but it leads to a number of implications for the results:

ls will give an incorrect output for certain filesystems. For example, virtualised filesystems like /proc will report a size of zero for many files, because these "files" aren't physically stored anywhere; they are generated as required by software.

wc will not function at all for files without read permissions, whereas ls requires only permissions to list the directory (compare ls -l /etc/shadow to wc -c /etc/shadow).

As mentioned in other answers, the behaviour for symbolic links is also different. Because wc tries to read them, it ends up reading the file to which the symlink points, whereas because ls just queries the filesystem, it will report the size used to store the symbolic link itself.

I'm sure there are other differences that I haven't thought of yet, but I thought I'd give a clear and simple explanation as to the basic reason behind these differences.

2
  • +1 for mentioning read permissions and seek(). This appears to be the case , after running strace wc -l on a couple large files. Jan 16, 2017 at 15:51
  • +1 for adding much more detail than my answer!
    – Cyclic3
    Jan 16, 2017 at 18:04
6

For a normal file, ls and wc call stat. However, for a file of /proc or /sys, ls returns 0, but wc returns a different number:

$ ls -l /proc/modules
-r--r--r--  1 root root 0 Jan 16 14:56 modules
                        ^ this one
$ wc -c /proc/modules
7621 modules

This is probably some way of finding out if something is a special file.

1
  • 2
    wc -c for me at least does call fstat, but seemingly for other purposes. It finds the length of the file by lseeking to the end. In the event that this returns an error, it reads the whole file.
    – Muzer
    Jan 16, 2017 at 15:43

You must log in to answer this question.

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