find-icons.sh (Source)

#!/bin/bash
##---------------------------------------------------------------------------##
#   Script:  find icons
#   Author:  Brian <genius@groupbcl.ca> :)
#   Date:    July 2018
#
#   Locates files in directories whose path includes 'icon' or 'icons' and
#   creates symlinks for them in $ICONS_DN/##x## (e.g $ICONS_DN/64x64) or
#   $ICONS_DN/unspecified, and another symlink in $ICONS_DN/$ALL_ICONS_DN.
#   Expects an extended regular expression describing icons to find (e.g.
#   '\bedit\b' will find 'edit' but not 'editor' or 'credit'), but without
#   one will find every icon it can on the system after confirming with the
#   user.
##---------------------------------------------------------------------------##
# BUUS: this script is part of Brian's Useful Utilities Set
COUNT_BY=10

function create_icon_symlink {
    local SOURCE_FN="$1" DIRNAME="$2" FILENAME="$3"

    [ -d "$DIRNAME" ] || mkdir -p "$DIRNAME"

    # Make the name of the symlink file easier to read
    FILENAME="${FILENAME//-/ }"             # Change '-' to ' '
    FILENAME="${FILENAME//_/ }"             # Change '_' to ' '

    # If file already exists, create filename.1.xxx, filename.2.xxx, etc
    if [ -L "$DIRNAME/$FILENAME" ]
    then
        P=$(( ${#FILENAME} - 4 ))   # Assume a 3 character extension
        [ ${FILENAME:$P:1} == '.' ] || P=$((P-1))   # Try 4
        [ ${FILENAME:$P:1} == '.' ] || FILENAME=''  # Give up
        if [ "$FILENAME" ]
        then
            FN_STUB="${FILENAME:0:$P}"
            FN_EXT="${FILENAME:$P}"
            for ((i=1; i<1024; i++)); do [ -L "$DIRNAME/$FN_STUB.${i}$FN_EXT" ] || break; done
            FILENAME="$FN_STUB.${i}$FN_EXT"
        fi
    fi

    if [ "$FILENAME" ]
    then
        ln -s "$SOURCE_FN" "$DIRNAME/$FILENAME"
        return 0
    else
        return 1
    fi
}

function handle_file {
    local FILE="$1" SIZE="$2"
    BASE_FN="$(basename "$FILE")"
    if create_icon_symlink "$FILE" "$ICONS_DN/$SIZE" "$BASE_FN"
    then
        [ "$FILTER" ] && create_icon_symlink "$FILE" "$ICONS_DN/$ALL_ICONS_DN" "$SIZE $BASE_FN"
        COUNTER=$((COUNTER+1))
        if [ $((COUNTER % COUNT_BY)) == 0 ]
        then
            echo -en " $COUNTER\r"
            [ $COUNTER == 500 ] && COUNT_BY=100
        fi
    fi
}

##---------------------------------------------------------------------------##
#                       M A I N   P R O C E S S I N G
##---------------------------------------------------------------------------##
FILTER=''
[ "$1" ] && FILTER=".*$1"
if [ ! "$FILTER" ]
then
    echo "No regular expression was supplied."
    echo -n "Are you sure you want to find all icons on the system [y/N]? "
    read YES_NO
    if [ "${YES_NO:0:1}" == 'y' -o "${YES_NO:0:1}" == 'Y' ]
    then
        echo "Searching for all icons"
        COUNT_BY=100
    else
        echo "Cancelled"
        exit
    fi
fi

ICONS_DN="/tmp/icons-$USER"
ALL_ICONS_DN='all'
[ -d $ICONS_DN ] && rm -rf $ICONS_DN
mkdir $ICONS_DN

UNSIZED_LIST_FN="/tmp/find-icons.unsized-list.$$.tmp"
exec 3>$UNSIZED_LIST_FN

# Find icons and put them into directories by size
SIG_INT=false; trap SIG_INT=true INT
locate icon | egrep -i "\bicons?/" | egrep -i "$FILTER" | awk '
    /\.(ico|bmp|gif|jpe?g|png)$/ {
        size = ""
        if (match($0, /([1-9]?[0-9][0-9]x[1-9]?[0-9][0-9])\//,a)) { size = a[1] }
        print "SIZE=\"" size "\" FILE=\"" $0 "\""
    }' | while read LINE
do
    eval "$LINE"
    [ -d "$FILE" ] && continue

    # Icons with a known size can be placed immediately
    if [ "$SIZE" ]
    then
        handle_file "$FILE" $SIZE
    else
        # Set aside icons with an unknown size for later processing
        echo "\"$FILE\"" >&3
    fi
    $SIG_INT && break
done
trap INT
if $SIG_INT; then echo -e "\b(Search cancelled by ctrl-c)"; fi

# Now handle icon files that we have to examine to determine their size
exec 3>&-   # Close FD 3
if [ -s $UNSIZED_LIST_FN ]
then
    N="$(wc -l $UNSIZED_LIST_FN | cut -f1 -d' ')"
    [ $N == 1 ] && FILE_S='file' || FILE_S='files'
    echo "Examining $N icon $FILE_S to determine their size"
    COUNT_BY=10
    # ('sort' removes multi-image GIFs)
    identify -format 'SIZE="%wx%h" FILE="%d/%f"\n' @$UNSIZED_LIST_FN |sort -u -k4  -t'"'|while read LINE
    do
        eval "$LINE"    # Get FILE and SIZE from line
        handle_file "$FILE" $SIZE
    done
fi
rm -f $UNSIZE_LIST_FN

# Count the icons in each directory and add that informaton the directory name
cd $ICONS_DN
COUNT=$(find . -type l | grep -v "/$ALL_ICONS_DN/" | wc -l)
[ $COUNT == 1 ] && ICON_S='icon' || ICON_S='icons'
echo "$COUNT $ICON_S found"
if [ $COUNT -gt 0 ]
then
    for DIR in $(ls --sort=version)
    do
        COUNT="$(ls $DIR | wc -l)"
        ICON_S='icon'; [ $COUNT -gt 1 ] && ICON_S='icons'
        [ "$DIR" != "$ALL_ICONS_DN" ] && echo "  $DIR: $COUNT $ICON_S"
        mv $DIR "$DIR ($COUNT $ICON_S)"
    done
fi
ln -s "all ($COUNT icons)" all

# vim: tabstop=4