Perl: Searching Through Directory Trees

I had a need to scan a huge directory tree today, identifying the users and Unix groups owning all the files. The problem I faced was too long usernames and group names which meant the

find /directory -ls

command which I normally use for such tasks wasn't terribly useful because there was no space delimiter between a username and a group. Results of such scan of the directory tree will have to later be parsed by other tools, and that's why proper splitting of the output into separate fields is so important.


This issue was motivational enough to refresh my Perl skills and sketch the following script (based entirely on this Never Run Unix Find Again article).

It's a very simple piece of code which takes a directory to scan as a parameter.

How this works

As you can see, we're using the standard File:Find functionality, and the two parameters find function takes are the wanted function, where you put conditions for your search.

Within this function, you call lstat to obtain all the necessary information about each directory entry, and then output the necessary fields.

Perl code

use File::Find;
if ($ARGV[0] ne "") {
        $dir = $ARGV[0];
} else {
        print "Please specify a directory!";

find &wanted, $dir;

sub wanted {
  my $dev;         # the file system device number
  my $ino;         # inode number
  my $mode;        # mode of file
  my $nlink;       # counts number of links to file
  my $uid;         # the ID of the file's owner
  my $gid;         # the group ID of the file's owner
  my $rdev;        # the device identifier
  my $size;        # file size in bytes
  my $atime;       # last access time
  my $mtime;       # last modification time
  my $ctime;       # last change of the mode
  my $blksize;     # block size of file
  my $blocks;      # number of blocks in a file
  my $user;	# username
  my $group;	# unix group name

#Right below here your telling lstat to retrieve all this info on each and every file/directory. Each and every file/directory is written to $_.

  (($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat($_));
  $user = getpwuid($uid);
  $group = getgrgid($gid);

  print $File::Find::name . ":$mode:$size:$user:$group:$ctime:$mtimen";

Hope you find this useful. Good luck with finding all your files! 🙂

For further reading, please consult the Perldoc section on File:Find.