Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

To check a successfull migration I'm using find to count the number of files, directories, symbolic links and files with more than one hard link. As the directories to check contain a huge number of files, each find run takes several hours. Thus I search for a way to separately count number of files, directories, symbolic links and files with more than one hard link within a single find run.

Here's what I currently do

num_files=$(find $directory -type f | wc -l)
num_directories=$(find $directory -type d | wc -l)
num_symlinks=$(find $directory -type l | wc -l)
num_hardlinks=$(find $directory -type f -links +1 | wc -l)

How can I get those four counters within one find run?

share|improve this question
    
I'm not sure this is the best approach to comparing two directories. Are you sure this is what you should be asking? – Daniel Beck Jul 24 '13 at 7:28
    
The best way to compare two directories is probably a dry run of rsync. But I need to proof that rsync copied all files, directories, symbolic links and hard links and I don't know a better way than doing it with find. – Florian Feldhaus Jul 24 '13 at 7:33
up vote 1 down vote accepted

The following should do it. It requires GNU find; on OS X, install e.g. findutil using Homebrew.

find $directory -type d -printf d -o -type l -printf l -o -type f -links +1 -printf h -o -type f -printf f

This will print one character per encountered file system entry:

  • d if it's a file
  • l if it's a symbolic link
  • h if it's a file with hard links
  • f if it's a file (only if not h)

Output looks like this (actual excerpt on my system):

dfddfdfddfdfddfdfddfdfddfdfddfddfdfddfdffffffffddfdffdfffffffffddfdldfllfdlldffffdfllfdlllllldffffdffffldfllfddffdldfddddffffflllldllllldlffffldfllfdlldffffdfllfddffddfddddfffffldfddddfffffdfddddfffffdlllldffffldfffflflllldffflfdffflfdfllfddffffldffffdfffflldfffflllldffffdffffdfffflldfllfddffdldfddddfffffdllllddflfffflldfllfddffffdffffdffffldffffdffffdffffdffffllldffffldffffdffffldffffldffffdffffdffffllllllldffffldffffdfffflllllldfffflldffddldfllfdldfffflldfffflldffffdfffflldffffdffffdfllfdlldfffflllldfllfdlldffffdfllfdlllllldffffdffdldfllfdlldfffflldfffflldffffldffffldfffflldfllfdldffffldffffldffdldffdddffddffddffddldfllfdlldffffdffffdfffflldfffflldffffdffffllldffffdffffdfllfddffffldfffflllldffffldfffflllldffffdfllfddffdldddddfffdddddfffdddddfffdddddfffdldlfffflldlffffllldfffllldffffdlffffdlffffldfffflldffdldfllfdllldffffdffffdffffldfllfdlllldfffflldfllfdldfddffffffl

Redirect output to a file, and then it becomes simple string processing to count later.

share|improve this answer
    
It worked fine on Mac OS X for me, but unfortunately I have to run the command on SunOS 5.10 where find doesn't support printf. Any suggestions how to achieve the same without printf? – Florian Feldhaus Jul 24 '13 at 7:50
    
@FlorianFeldhaus You're on an almost decade old Solaris? You should probably add that to your question. Other than to compile and install a better find... no idea. FWIW OS X find does not support -printf, you probably installed something better already. – Daniel Beck Jul 24 '13 at 7:56
    
Yes, I currently have to use it. The tools on it are not that old, but Solaris find does not support printf. I will try to get a Linux server where I have a recent GNU find. – Florian Feldhaus Jul 24 '13 at 8:02

find $directory -type d -exec echo dirs \; -o -type l -exec echo symlinks \; -o -type f -links +1 -exec echo hardlinks \; -o -type f -exec echo files \; | sort | uniq -c

Produces output like:

 326 dirs
2164 files
  40 hardlinks
 164 symlinks
share|improve this answer

Using the answer from Daniel Beck I developed the following solution which should work for most versions of find and also provides the counting magic:

output=$(find $directory -type d -exec printf d \; -o -type l -exec printf l \; -o -type f -links +1 -exec printf h \; -o -type f -exec printf f \;)
num_files=$(echo $output | grep -o "f" | wc -l)
num_directories=$(echo $output | grep -o "d" | wc -l)
num_symlinks=$(echo $output | grep -o "l" | wc -l)
num_hardlinks=$(echo $output | grep -o "h" | wc -l)
share|improve this answer

You must log in to answer this question.

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