#!/usr/bin/perl

use strict;

# note! by default this will count all open files, which includes
# dynamically linked libraries, sockets, directories, etc!!

# +c is for command column width
open (STDIN, '/usr/sbin/lsof +c 16 |') ||
	die "error reading from lsof pipe: $!";

my $line;
my %pid_filecount;
my %pid_cmdname;
<STDIN>; # discard first heading line of lsof output
while ($line=<STDIN>) {
 # lines look like   cmd pid user mem type ???  ??? ??? filename
	my ($cmd, $pid, $user, $fd, $type, $x2, $x3, $x4, $filename)
		= split(/\s+/, $line); # split on whitespace
	# only count REGular files. type can also be DIR, CHR, FIFO, unix,...
	# only count files opened by the process. Other types include
	# cwd, mem (memory mapped file), mmap (device) ...
#	if ($fd =~ /\d/ && $type eq "REG") {
		$pid_filecount{$pid}++;
#	}
	$pid_cmdname{$pid}=$cmd;
}

print "PID\tNAME\t\tOPENFILES\n";
# sort by open files count. swap $a and $b if you want descending order
foreach my $pid (sort {$pid_filecount{$a} <=> $pid_filecount{$b}}
		(keys %pid_filecount)) {
	printf "%d\t%-15s\t%d", $pid, $pid_cmdname{$pid}, $pid_filecount{$pid};
	print "\n";
}
