I need to find all files of the smallest size in a directory.

My code so far:

   printf "minimum file size: %s\n"
            du $dir -hab | sort -n -r |tail 

This code displays the smallest files but I need the least small file sizes should be display automatically.

My output:

file size:
15  testdir/subdir3/subdir4/file3.txt
15  testdir/subdir1/file5.txt

Actual output should display like:

file size: 15
  • 1
    What do you mean by least? Are you looking for the smallest file in a directory or all files that share the smallest size? Please edit your question and include a specific example so we can understand. – terdon May 11 '15 at 14:48
  • @Terdon Im looking for the all files that have smallest size in a directory. for example having same size for all 10 files(1. xxx.txt -4kb , 2.yyy.txt -4kb.........10. zzz.txt -4kb) in a directory – buddha sreekanth May 11 '15 at 14:51
  • 2
    Maybe instead of posting many variations on your original question, you could clarify why the answers you got on your original question are not satisfactory. – Stéphane Chazelas May 11 '15 at 15:12
  • Your code had it almost right -- just add -n 1 to tail. It's actually slightly more optimal to sort -n | head -1, especially if the du output is very large. – Otheus May 11 '15 at 18:25
  • 1
    Indeed. @StéphaneChazelas I had seen your answer, but I misread your code! :) Maybe after 1 week he forgot? Buddha, please go back to Stephane's answer and <<accept>> it. – Otheus May 11 '15 at 21:41

Perhaps like this:

find /some/dir -maxdepth 1 -type f -printf '%s\t%p\n' | \
    sort -n | \
    awk '
        NR == 1 { s = $1 }
        $1 != s { exit }

(assuming GNU find(1)).

Edit: How the awk part works:

  • awk receives a list of lines <size><tab><filename>, sorted by <size>; the smallest files are thus grouped at the beginning of the list
  • NR == 1 applies only to the first line; it initializes s to the common size of the smallest files
  • $1 != s applies when we find a file with a size bigger than s; since the list is sorted by size, all subsequent files are at least as big, so we can bail out
  • if we got to 1, the rule $1 != s didn't match, so the file has exactly size s; 1 is equivalent to { print }, so we print it.
  • Hope you don't mind. The l/L was hard to distinguish from 1 and I think the last 1 should have been to output the filename. Also maxdepth should come first to avoid the dreaded gnu warning. Oh, and \t to `` `` – Otheus May 11 '15 at 21:34
  • @Otheus: Your edit breaks if any of the filenames contain spaces. Thus, sorry, but no. I replaced l by s though. – lcd047 May 11 '15 at 21:46
  • Oops, you're right. I don't get the purpose of "1" on the last line. That outputs the file size and the filename. OP wanted just the filename. Still, swap maxdepth/type – Otheus May 11 '15 at 21:48
  • @Otheus: No, the OP wanted the filenames. There is no need for this dance if he just wanted the size, he could just replace tail by tail -1 in his initial command. And BTW, in order to keep just the filenames from my command above it's enough to pipe the results through cut -f 2-. That's the point of using a tab as separator in the -printf clause. – lcd047 May 11 '15 at 21:53
  • He wanted the filenames and originally in my comment I wrote size and then edited it. So the last line should be { print $2 }. Why another pipe? – Otheus May 11 '15 at 22:00

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.