Shell script to separate and move landscape and portrait images

You could use imagemagick's identify with the fx special operator to compare height and width e.g. h>w. If true it will output 1, if false it will output 0:

for f in ./*.jpg
do
  r=$(identify -format '%[fx:(h>w)]' "$f")
  if [[ r -eq 1 ]] 
  then
      mv "$f" /path/to/portraits
  else
      mv "$f" /path/to/landscapes
  fi
done

With zsh you could use the estring glob qualifier (to select only the files for which the code between quotes returns true) and do something like:

mv ./*.jpg(.e_'identify -format "%[fx:(h>w)]" $REPLY | grep 0 >/dev/null'_) /path/to/landscapes
mv ./*.jpg /path/to/portraits

so the first command moves all landscape images to /path/to/landscapes and the second one moves the remaining images to /path/to/portraits.


The above solutions will treat square images as landscapes and move them into the respective directory. You could introduce a second condition if you wanted to move them to their own directory:

mv ./*.jpg(.e_'identify -format "%[fx:(h<w)]" $REPLY | grep 1 >/dev/null'_) /path/to/landscapes
mv ./*.jpg(.e_'identify -format "%[fx:(h>w)]" $REPLY | grep 1 >/dev/null'_) /path/to/portraits
mv ./*.jpg /path/to/squares

or you could use a different condition (e.g. check h/w ratio) to separate the square images from the rest and leave them in the current directory:

for f in ./*.jpg
do
  r=$(identify -format '%[fx:(h/w)]' "$f")
  if [[ r -gt 1 ]] 
  then
      mv "$f" /path/to/portraits
  elif  [[ r -lt 1 ]]
  then
      mv "$f" /path/to/landscapes
  fi
done

This uses the fileinfo utility to get an image's width and height. If the height is greater than the width, the file is moved to the portraits/ directory. If not, it is moved to the landscape/ directory.

for f in ./*jpg
do
    if fileinfo "$f" 2>&1 | awk '/w =/{w=$3+0; h=$6+0; if (h>w) exit; else exit 1}'
    then
        mv "$f" portraits/
    else
        mv "$f" landscape/
    fi
done

The file name in this loop is double-quoted where needed so that this loop is safe to use even for image file names with spaces, newlines, or other difficult characters.

On a debian-like system, fileinfo can be installed via:

apt-get install leptonica-progs

Other similar utilities can be used as long as the awk command is modified appropriately.


Using identify from ImageMagick:

#! /bin/sh                                            
identify -format '%w %h %i\n' -- "$@" 2>/dev/null | \
    while read W H FN; do
        if [ $W -gt $H ]; then
            echo mv -f -- "$FN" /path/to/landscape/
        else
            echo mv -f -- "$FN" /path/to/portraits/
        fi
    done

This is not particularly efficient because it runs mv for each file, but you didn't ask for efficiency.