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
    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 '16 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 '16 at 21:47
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

  • 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 '16 at 5:11
  • @Ruslan It would be broken at stat stage then, thats why i mentioned no unusual filenames – heemayl Jun 20 '16 at 5:12
  • Why? Doesn't the shell glob expand to quoted/escaped names? – Ruslan Jun 20 '16 at 5:13
  • stat can not send output as NUL separated, thats why.. – heemayl Jun 20 '16 at 5:14
  • Well, I understand that newline in filename is unusual, but why would you assume that space is unusual? – Ruslan Jun 20 '16 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.

  • 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 '16 at 3:15
  • 1
    @Wildcard, of course there is :-). You could start with the User's Guide. – Stéphane Chazelas Jun 21 '16 at 8:30

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.