48

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!

2

5 Answers 5

64

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.

9
  • 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. Sep 29, 2014 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. Sep 29, 2014 at 20:25
  • 2
    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. Sep 29, 2014 at 20:29
  • That makes sense. Thank you again for your help. Sep 29, 2014 at 20:30
  • 2
    @user2419571: tail -n 1 <(sort -n <(find . -type f -printf "%s\t%p\n")) ;)
    – Cyrus
    Sep 29, 2014 at 20:38
14

This command helps to list out defined size too.

find . -type f -size +100M -exec ls -lh {} \;
2
  • This is more readable than the top answer. Feb 24 at 1:45
  • This is the first one to work for me on Unix (MacOS)
    – Dawson B
    Apr 23 at 4:20
8

This works on BSD/macOS and uses fast but non-POSIX -ls extension to find utility:

find . -type f -ls | sort -k7 -r | head -n 3

This is slower but may work on POSIX systems where -ls extension is not available in find:

find . -type f -exec ls -al {} \; | sort -k5 -r | head -n3

How it works:

  • find is a powerful file search utility that will show you results based on a given query explained below.
  • find . will search in current working directory.
  • find . -type f will search only for a specified file type "f" that is a regular file (it means it will skip directories, special files, links, sockets, etc).
  • -ls switch will instruct find display full information about files found. However, according to man on BSD system, it is an extension to IEEE Std 1003.1-2001 ("POSIX.1") standard and may not be available on all platforms.
  • Alternatively if -ls extension is not available on your system you may -exec .. {} \; with ls -al command and use 5th field to sort the results. {} means the file name that has been found. \; encloses the -exec command.
  • | Unix symbol means "pipe" that is will redirect output from one program to input of another program. It will send find program output text as inpurt to sort program.
  • sort is a sorting utility. It gets lines of data and then sort those lines ascending order as result.
  • sort -k7 means take 7th field as the sorting parameter value. Parameters are split by spaces. 7th parameter is the file size produced by the find utility. If you use -exec ls -al {} \; instead of -ls then you will use 5th field -k5 to sort.
  • -r tells sort to use reverse sorting that is put biggest first. Because we want to see biggest files first.
  • In addition you can also pipe (|) output of the sort to head utility that will only show three first lines (as instructed with -n 3) of the resulting output if you do not really want to see hundrends of the lines.

Long story short: Use find to find recursively regular files only starting search in currently working directory, then display full information about that file using -ls extension (or execute ls -al). Later on pass the results from find to sort using unix pipe | and make it sort biggest first based on the 7th (or 5th) field. In addition you can limit results to n lines using head utility.

I mean "use brainz" to make you read "man" and search for solutions offline yourself that will train you in problems solving from scratch :-)

1
  • Not really working on MacOS as it fails to return size correctly and returns a huge number of columns.
    – sorin
    Aug 21, 2018 at 8:26
4

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.

3
  • ... 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... Nov 20, 2017 at 18:21
  • Possible to get the first ten files? (Without doing something stupid like a loop) Apr 24, 2019 at 3:01
  • 1
    @Wowfunhappy replace [1] with [1,10] Apr 24, 2019 at 5:44
0

In addition to Stéphane Chazelas' response, I wanted to add the following notes (I am unable to comment):

  1. To get the smallest regular file, use o instead of O:
ls -ld -- **/*(.DoL[1])
  1. You can filter by a concrete (or several) extensions by appending it/them to the **/* wildcard:
ls -ld -- **/*.png(.DoL[1])
ls -ld -- **/*.{png, jpg}(.DoL[1]) # this will give two results, one per extension

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.