Shell – Best way to work through / display a tree of images sorted by size

findosxscriptingshell-script

I've got a deep directory tree containing .PNG files. I'd like to find all the .PNG files in the directory, sort them in order of size from smallest to largest, and then display every 50th image.

(I'm analyzing data and trying to find the best size cutoff between "potentially useful" and "random noise" so I want an easy way to skim through these thousands of images….)

Any scripting help is appreciated. I know how to use 'find' to search by size, but not how to sort the results or run a display program to display every 50th without having it pause the process waiting.

I am using MacOS Snow Leopard, btw.

Thanks!

Best Answer

Is that size as in file size, or size as in image dimensions?

In zsh, to see all .png files in the current directory and its subdirectories, sorted by increasing file size:

echo **/*.png(oL)

There's no convenient glob qualifier for grabbing every N files. Here's a loop that sets the array $a to contain every 50th file (starting with the largest).

a=() i=0
for x in **/*.png(OL); do
  ((i%50)) || a+=$x
  ((++i))
done
my-favorite-image-viewer $a

Without zsh or GNU find, there's no easy way of sorting find output by metadata (there's find -ls or find -exec ls or find -exec stat, but they might not work with files containing non-printable characters, so I don't like to recommend them). Here's a way to do it in Perl.

find . -name '*.png' |
perl -e '
    $, = "\n";  # separate elements by newlines in the output
    print  # print…
        sort {-s $a <=> -s $b}  # …sorted by file size…
            map {chomp;$_} <>  #…the input lines (with the newline bitten off)
'

And here's a way to view every 50th file (starting with the largest):

find . -name '*.png' |
perl -e '
    $, = "\n";
    exec "my-favorite-image-viewer",
        map {$i++ % 50 ? () : $_}  # every 50
            sort {-s $b <=> -s $a} map {chomp;$_} <>
'

Another approach would be to create symbolic links in a single directory, with names ordered by file size. In zsh:

mkdir tmp && cd tmp
i=1000000  # the extra 1 on the left ensures alignment
for x in ../**/*(oL); do
    ((++i))
    ln -s $x ${i#1}.png
done

With Perl:

mkdir tmp && cd tmp
find .. -name '*.png' |
perl -e '
    $, = "\n";
    for $x (sort {-s $a <=> -s $b} map {chomp;$_} <>) {
        symlink $x, sprintf("%06d", ++$i);
    }
'