1

I have images, I need to delete some files with the same size. But no need to remove all such images, but only the next in the queue (in alphabetical order):

1.png    # 23,5 Kb
2.png    # 24,6 Kb
4.png    # 24,6 Kb > remove
8.png    # 24,6 Kb > remove
16.png   # 23,5 Kb
2
  • Please edit your question and tell us what operating system you are running. The tools available depend on it.
    – terdon
    Jun 19 '16 at 14:40
  • Are you trying to delete duplicates (with same content), or any files that happen to have the same size? Jun 19 '16 at 15:09
4

If you're on Linux or otherwise have access to GNU tools, you can do this:

last=-1; find . -type f -name '*.png' -printf '%f\0' | sort -nz | 
    while read -d '' i; do 
        s=$(stat -c '%s' "$i"); 
        [[ $s = $last ]] && rm "$i"; 
    last=$s; 
done

Explanation

  • last=-1 : set the variable $last to -1.
  • find . -type f -name '*.png' -printf '%f\0' : find all files in the current directory whose name ends in .png and print their name followed by the NULL character.
  • sort -gz : sort \0-separated input (-z) numerically (-n). This results in a sorted list of file names.
  • while read -d '' i; do : read the list of file names. The -d '' sets the field delimiter to \0 which is needed to process NULL-separated data correctly.
  • s=$(stat -c '%s' "$i"); : the variable $s now holds the size of the current file ($i).
  • [[ $s = $last ]] && rm "$i"; : if the current file's size is the same as the last file's size, delete the file.
  • last=$s : set $last to the current file's size. Now, if the next file has the same size, the previous step will delete it.
4

POSIX implementations of ls support a -S option to provide a listing ordered by size (and it appears, sorted by name within equal sizes). You could pipe a listing into a shell loop, remembering the size for the preceding item and removing "duplicates".

That has the drawback of getting the filename (if you happen to like using spaces in your filenames).

Alternatively, if you use one of the platforms (such as Linux or BSD) which have a stat utility, you could use that to make a fixed-format listing with only size and filename, and sort that, piping it to a simple(r) script that checks for duplicate sizes.

One complication in the question is that the example does not use the shell-order for "alphabetic", since 16.png follows 8.png. The -g option of the GNU and BSD sort utilities handles that (but it is not in POSIX).

Given those issues with sort, your script probably should get the list of sorted names (in your preferred order) and use stat to obtain the size for each file, in succession.

Here is a quick example to illustrate (with the "rm" changed to an "echo"), using the GNU stat:

#!/bin/sh
last=x
# the sed command strips a leading "./", which confuses "sort -g"
find . -name '*.png' |sed -e 's,^./,,' | sort -g | while true
do
    read item
    [ -z "$item" ] && break
    size=$(stat -c '%s' "$item")
    echo "$size>$item"
    if [ "x$size" = "x$last" ]
    then
        echo "rm -f \"$item\""
    fi
    last="$size"
done
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.