39

I am trying to find the largest file in a directory recursively. If there is a subdirectory inside of that directory the function needs to go inside that directory and check to see if the largest file is there. Once the largest file is found the output is displayed with the relative path name and the name and size of the largest file.

EX:

dude@shell2 (~...assignment/solutions) % bash maxfile.sh ~/test
class/asn
dude.h.gch: 9481628

This is what I have:

#!/bin/sh
clear

recursiveS() {
    for d in *; do
        if [ -d $d ]; then
            (cd $d; echo $(pwd)/$line; du -a; recursiveS;)
        fi
    done
}
recursiveS

I have been stuck for a while now. I cannot implement this by pipelining a number of existing Unix tools. Any ideas would be nice!

50

use find (here assuming GNU find) to output file names with the file size. sort. print out the largest one.

find . -type f -printf "%s\t%p\n" | sort -n | tail -1

That assumes file paths don't contain newline characters.


Using a loop in bash with the GNU implementation of stat:

shopt -s globstar
max_s=0
for f in **; do
  if [[ -f "$f" && ! -L "$f" ]]; then
    size=$( stat -c %s -- "$f" )
    if (( size > max_s )); then
      max_s=$size
      max_f=$f
    fi
  fi
done
echo "$max_s $max_f"

This will be significantly slower than the find solution. That also assumes that file names don't end in newline characters and will skip hidden files and not descend into hidden directories.

If there's a file called - in the current directory, the size of the file open on stdin will be considered.

Beware that versions of bash prior to 4.3 followed symbolic links when descending the directory tree.

  • Thanks, it works! I appreciate the help. I am trying to get use to programming in shell. I do not know a whole lot right now so I appreciate you telling me what is happening with that line of code. – user2419571 Sep 29 '14 at 20:24
  • Quick question: Out of curiosity is there a way to do it without piping commands? I am curious because every example I have seen has used piping of some kind. – user2419571 Sep 29 '14 at 20:25
  • 1
    I'm sure there are other ways to do it. The UNIX philosophy is that tools should be single-purpose, and to chain them together so the output of one command is fed into the input of the next. – glenn jackman Sep 29 '14 at 20:29
  • That makes sense. Thank you again for your help. – user2419571 Sep 29 '14 at 20:30
  • 2
    @user2419571: tail -n 1 <(sort -n <(find . -type f -printf "%s\t%p\n")) ;) – Cyrus Sep 29 '14 at 20:38
9

This command helps to list out defined size too.

find . -type f -size +100M -exec ls -lh {} \;
4

This works on BSD/macOS:

find . -type f -ls | sort -k7 -r

You can also append | head -n 3 to display numer of interesting entries (3 in this case).

  • 1
    This answer could be improved by explaining how it works. Also, it looks very similar to the accepted answer (which doesn't fully explain how it works either). – dhag Jun 15 '17 at 18:07
  • man find and man sort, use brainz :-) – CeDeROM Jun 20 '17 at 21:13
  • Not really working on MacOS as it fails to return size correctly and returns a huge number of columns. – sorin Aug 21 '18 at 8:26
3

With zsh, for the biggest regular file:

ls -ld -- **/*(.DOL[1])

(of course you can replace ls -ld -- with any command. If using GNU ls or compatible see also the -h option for human readable sizes)

  • .: only regular files (not directories, symlinks, devices, fifos...)
  • D: include hidden ones and descend into hidden dirs
  • OL: reverse-ordered by size (Length).
  • [1]: only the first match.

If there are ties, you'll get any one of them at random. If you want the first in alphabetical order, add an extra on (order by name) to sort ties alphabetically.

Note that it considers the files size, not disk usage.

  • ... I start to believe that you are on zsh's payroll ;) (which it very well could be?). zsh is unfortunately not available on all systems... – Olivier Dulac Nov 20 '17 at 18:21
  • Possible to get the first ten files? (Without doing something stupid like a loop) – Wowfunhappy Apr 24 at 3:01
  • 1
    @Wowfunhappy replace [1] with [1,10] – Stéphane Chazelas Apr 24 at 5:44

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.