1

I would like to delete a certain number of the largest files in a directory.

I can get the filenames of the first ten with:

ls -S | head (or a richer albeit more complex to parse ls -lS | head)

How would I pass those to rm ? via xargs ?

So would ls -S | head | xargs rm work (even with filenames with spaces etc?)

Is there a better / safer way ?

Sorry but I could not test this myself in fear of goofing (the directory has stuff I really don't want to zap).

I use macOS.

3
  • "I could not test this myself in fear of goofing". Use echo. E.G. ls -S | head | xargs echo rm – phemmer Oct 23 '16 at 18:22
  • @Patrick: In case you haven’t seen ilkkachu’s answer (which looks almost as if it is partially meant for you), this could provide a false (misleading) sense of security. The OP expresses a concern with filenames with spaces. If he has a large file called foo bar, which he wants to delete, the command you suggest will not alert him to the fact that his command will delete his smaller files foo and bar (which he wants to retain). – Scott Oct 23 '16 at 19:18
  • @Scott my comment wasn't mean to be answer, which is why I made it as a comment.. It's meant to be a starting point (which is also why I used E.G.). As for your objection, you can easily overcome this with xargs -n 1. – phemmer Oct 23 '16 at 20:38
2

So would ls -S | head | xargs rm work (even with filenames with spaces etc?)

Nope. xargs by default splits on any whitespace, not just newlines. And you can't see that with | xargs echo, since echo prints all its arguments, separated by spaces. (Something like | xargs printf "%s\n" would print them separated by newlines, so you'll see if the split happens in the middle of a file name.)

At least GNU xargs has -d '\n' to split only on newlines, and many versions of xargs have -0 to split on NUL characters (it goes with find -print0). You'll want the first one at least, but in the general case file names could contain newlines too, in which case head won't do much good either.

I'm obligated to warn you that parsing the output of ls is consider wrong, apparently at least some versions will mangle the output even without the presence of newlines. (You might be safe if you don't have newlines or unprintable characters, though. Maybe.)

1

I would use a different approach. Something like this:

size=20000 # set a limit (in bytes), above these we will delete

for file in *
do
  [[ -f "$file" ]] || continue

  fileSize=$(stat --format "%s" "$file")

  if (( $fileSize > $size )) # if file is bigger than 20000 bytes
  then
    rm "$file" # delete the file
  fi          
done

This way, you will be able to delete files with spaces in them, and can decide with the $size variable which files actually are "big". If you want to be prompted before each deletion, use the -i switch: rm -i

Edit:
I just now realized you are running this under OS X. I don't have access to any machine with OS X at the moment, there might be a risk that OS X stat has a different format for getting the size. In other words, the --format "%s" option might not work. Check man stat in OS X!

0

i'd go with;

find . -type f -size +10M -delete -print

If you really want to go with the ls way, perhaps;

ls -S | head -1 | while read af; do rm "$af"; done
2
  • Since the question is about a directory, and not a directory tree, you might want to mention -maxdepth.   And why are you suggesting head -1? – Scott Oct 23 '16 at 19:26
  • maxdepth could be used dependent on if there are subdirectories... if there are i wouldn't use the ls approach incase someone changed the alias for rm to rm -rf... and head -1 as an example, replace with head -10 for for 10 files... – mikejonesey Oct 23 '16 at 19:36
0

It will work, but the following things need to be kept in mind:

  • Here rm is not going to ask you whether you really want to delete the file.
  • This will not delete files which contain space in their name.
1
  • The question asks, will this work (even with filenames with spaces, etc.)?  So you're saying, "No, it will not work (with filenames with spaces)."  You might want to revise your first sentence to better reflect what your answer is actually saying.  And, rather than just saying that rm won't ask for confirmation, how about telling the user how to get rm to do that? – Scott Oct 23 '16 at 19:02
0

Use zsh. It has a method for sorting and selecting files by size (and by date, which is used more often). Zsh is part of the standard installation on OSX/macOS but may need to be installed separately on other Unix variants.

The way to select (and sort) files using criteria other than the name is glob qualifiers. For example, to list the 10 largest files in a directory, use OL to sort by decreasing size (length) and [1,10] to list the first 10:

ls -ldU *(OL[1,10])

Doing this without zsh is more complicated, especially if you need to cope with file names containing special characters. As long as your file names don't contain unprintable characters or newlines, you can parse the output of ls.

ls -S | head -n 10 | while read -r filename; do echo rm -- "$filename"; done

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.