Perl one-liner to see who is hogging all the open filehandles

Posted by Chris on March 22nd, 2011 filed in programming, sysadmin

Helpful one-liner to help fix a problem we ran into the other day.

perl -e 'map{$c{(split(/\s+/))[2]}++} `lsof`;print "$_ $c{$_}\n" for (keys %c);'

The thinking is:

Use lsof to get all the open filehandles which conveniently also shows who has it open.

`lsof`

Loop through them, using the ` as a cheat that it inputs an array

map {   } `lsof`;

Splitting on whitespace.  The input to each iteration of the map{ } defaults to $_, and if you don't put anything to split in a perl split, it uses $_.  Neat.

split(/\s+/)

Since we just care about the count, only use the 3rd column by forcing the output of the split into an array and using a slice.

(split(/\s+/))[2]

Now, we just want the count for those users so we increment a hash with the user name as they key.

$c{ }++

Of course, the split is returning the name so that gives us the user name and hash key.

$c{(split(/\s+/))[2]}

And increment that.  Unlike python, for example, you can just increment it.

$c{(split(/\s+/))[2]}++

It will do that for every iteration of the map{ }.  i.e. every line in the output of the `lsof`.

After that, it's just a matter of printing out the key/value pairs using a easy hash printing line blatently stolen from an answer on Stack Overflow.


3 Responses to “Perl one-liner to see who is hogging all the open filehandles”

  1. oylenshpeegul Says:

    Ooh, I love one-liners! I’m not really much of a golfer, but here’s a few things you might do with flags:

    You can use -l to get Perl to put that newline on for you.

    perl -le ‘map{$c{(split(/\s+/))[2]}++} `lsof`;print “$_ $c{$_}” for keys %c;’

    If we move the lsof call outside, then we can use -n to do the map

    lsof | perl -nle ‘$c{(split(/\s+/))[2]}++; END{print “$_ $c{$_}” for keys %c}’

    Then we can use -a to do the split

    lsof | perl -anle ‘$c{$F[2]}++; END{print “$_ $c{$_}” for keys %c}’

    With a recent perl, we can use say instead of print with -l

    lsof | perl -anE ‘$c{$F[2]}++; END{say “$_ $c{$_}” for keys %c}’

    The -l does a chomp on the way in too, but we didn’t really make use of that here, so say is all we need.

  2. Simon Flack Says:

    perl has some nice switches to simplify this a bit:


    lsof | perl -anE '$c{$F[2]}++ }END{say "$_ $c{$_}" for (keys %c);'

    =) Which is essentially piping lsof into:


    use feature 'say';
    while (defined($_ = )) {
    our(@F) = split(' ', $_, 0);
    ++$c{$F[2]};
    }
    sub END {
    say "$_ $c{$_}" foreach (keys %c);
    }

    see `perldoc perlrun` for more info

  3. Chris Says:

    I’m so stealing both of those in the future – thanks both of you.

Leave a Comment