6

What is the best way to remove all the files in the current directory with some prefix, except the file with this prefix but having the largest size among all the files with this prefix?

(In the case when the largest one is not unique, just randomly keep one of them and remove the others.)

For example, the current directory contains the following files:

-rw-rw----  1 user user 3468 Jan 01 00:00 filea
-rw-rw----  1 user user 3434 Jan 01 00:00 pre_0
-rw-rw-r--  1 user user 9769 Jan 01 00:00 fileb
-rw-rw-r--  1 user user 1950 Jan 01 00:00 filec
-rw-rw-r--  1 user user 8654 Jan 01 00:00 pre_1
-rw-rw----  1 user user 6508 Jan 01 00:00 pre_2

After running the command or the script to remove all the files with prefix "pre_" except the largest one, the current directory should be listed as:

-rw-rw----  1 user user 3468 Jan 01 00:00 filea
-rw-rw-r--  1 user user 9769 Jan 01 00:00 fileb
-rw-rw-r--  1 user user 1950 Jan 01 00:00 filec
-rw-rw-r--  1 user user 8654 Jan 01 00:00 pre_1
2
  • 2
    I'm just wondering, what is the real world application for this? Is it managing log files, or files in a photo gallery that were resized into many different sizes (and now you want to delete the smaller files), or something else?
    – Kusalananda
    Jun 20, 2016 at 5:37
  • @Kusalananda Yes, the application in my case is log/record files management. The other application on photo gallery management you mentioned is also very interesting.
    – D. Chen
    Jun 20, 2016 at 21:47

2 Answers 2

7

You can use a combination of few utilities:

stat -c '%s %n' pre_* | sort -k1,1rn | tail -n +2 | cut -d' ' -f2 | xargs rm

Assuming GNU system and no unusual filenames.

  • stat gets the filesize and name separated by space for all pre_* files

  • sort sorts the file according to the file size, with highest sized one goes to top

  • tail -n +2 gets the rest of the files apart from the max sized one

  • cut -d' ' -f2 gets the file name only, and rm (xargs rm) does the removal

11
  • 1
    Isn't going to work with filenames with spaces. Would break at the stage of cut. At least that stage can be fixed if cut call is replaced by sed 's@^[^ ]\+ @@'. Not sure if xargs will work correctly.
    – Ruslan
    Jun 20, 2016 at 5:11
  • @Ruslan It would be broken at stat stage then, thats why i mentioned no unusual filenames
    – heemayl
    Jun 20, 2016 at 5:12
  • Why? Doesn't the shell glob expand to quoted/escaped names?
    – Ruslan
    Jun 20, 2016 at 5:13
  • stat can not send output as NUL separated, thats why..
    – heemayl
    Jun 20, 2016 at 5:14
  • Well, I understand that newline in filename is unusual, but why would you assume that space is unusual?
    – Ruslan
    Jun 20, 2016 at 5:16
7

With zsh:

rm -f pre*(OL[2,-1])
  • OL: reverse order by size
  • [2,-1]: second to last only

The equivalent with bash and GNU utilities would be something like:

eval "files=($(LC_ALL=C ls --quoting-style=shell-always -dS ./pre*))"
rm -f "${files[@]:1}"

You may want to limit it to regular files, as the size for non-regular files has generally not much relevance:

rm -f pre*(.OL[2,-1])

(no direct bash+GNU equivalent). You may want to include symlinks to regular files and consider the size of the target of the symlinks:

rm -f pre*(-.OL[2,-1])

With ls, add the -L option to consider the size of the targets of symlinks.

2
  • Wow, perhaps there really is something to zsh...I haven't actually learned it up to now. Haven't found any good starting point, either.
    – Wildcard
    Jun 21, 2016 at 3:15
  • 1
    @Wildcard, of course there is :-). You could start with the User's Guide. Jun 21, 2016 at 8:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .