Thursday, February 26, 2009

Episode #3 - Watching the File Count in a Directory

Ed Says:

On Windows, count the number of files in a directory every 5 sec:

 C:\> for /L %i in (1,0,2) do @dir /b | find /c /v "" & ping -n 6>nul 

I often use this one when doing analysis of an anti-malware solution, to take inventory of the number of specimens it's detected/nabbed/quarantined.

This command includes some useful constructs as well:
  • The for /L loop, which counts from one to two in steps of zero keeps it running forever, acting kind of like the Linux "watch" command.
  • The /b option makes the dir command drop the cruft from its output (., .., volume name, size, etc.) We want only one line per file, so we use /b.
  • The find /c /v "" means to find, and count (/c) the number of lines that do not have (/v) nothing (""). Lines that don't have nothing are all lines. Even a blank line has a Carriage Return / Line Feed, so it gets counted.
  • And, we ping ourselves 6 times to introduce a 5-second delay. First ping happens instantly, the remaining happen once per second. Bummer that there is no sleep in Windows. Vista does have the "timeout /t -[N]" command, but we want something that'll work on nearly all Windows boxen, so we ping.
Byte_bucket points out that dir, when used like this, doesn't show files that are marked with the system or read-only attributes, and he's right. He suggested replacing the dir /b command with the attrib command, which will show all files regardless of these attributes. However, call me old fashioned, but I like to see lists of files using the dir command. Thus, if I want to make sure that I see hidden, system, and read-only files, I use dir /a. The /a means show me files with a given set of attributes (which can be h for hidden, s for system, and r for read-only). If I don't provide an attribute list, it will show me files regardless of the attribute. Thus, the resulting command:

 C:\> for /L %i in (1,0,2) do @dir /b /a | find /c /v "" & ping -n 6>nul 
Thanks for the great point, Mr. Bucket. Or should I call you Byte? :)

Hal Comments:

*Yawn* Too easy, Ed:
$ while :; do ls | wc -l; sleep 5; done

This example does point out one of the more interesting properties of the ls command: ls is conscious of where its output is going. If the output is going to normal terminal output, then the ls command gives you multi-column output. But if the output is being piped into another command, it outputs one file per line (you can verify this by doing "ls | cat"). How can ls figure this out? Check out the manual page for isatty(3).

Paul's Comments:

A fellow Twitter (Sorry, I can't find the person's name) recommended the watch command, which you can run like this:

$ watch -n 5 'ls | wc -l'

This will first clear the screen, then display the command in the upper left hand corner, and the date/time the command was last run in the upper right hand corner, followed by the count. Its pretty neat, and seems to be included in most Linux distributions (however, in OS X I used MacPorts to install it with port install watch)