As practice I need to complete a script that orders all filles by size with a given extension(.txt for example) including those in subdirectories too.

For example; 
./ex1.sh einstein txt

I can't use du or other advanced commands. At some point I need to use find, I tried something like this

find -depth - type f -name "*.$extension" | sort ....

but this hasn't work really well, as i don't really know how to sort them by size, only result i get is sorted by name.

I was looking for an output similar to ls -lhS but including subdirectories.

  • 1
    If you can only use find, why are you using sort? Please edit your question and explain your requirements. What is your example? Is it the output of a command? Or is it your ex1.sh script? If so, what are the parameters (einstein and txt) that you are giving? – terdon Mar 15 '18 at 12:10

find includes an option -printf which allows you to format what to output about your results, and how to output them. One of possibilities listed in the documentation for that option (see the man page) is %s for a file's size in bytes. Thus, you can add to your find command something like `-printf "%s %p\n".

  • @terdon - yes. His answer had not been posted when I began writing my answer. – user1404316 Mar 15 '18 at 12:35
  • Ah, the classic race condition! :) – terdon Mar 15 '18 at 12:51

The only sorting that any of the finds can do AFAIK is to have contents appear before the containing directory (the -depth option). You will have use something else to sort on size.

If you have GNU find, try:

find . -type f -iname "*.$extension" -printf "%s %p\n" | sort -n | sed 's/^[0-9]* //'

-printf "%s %p\n" prints the size and file path, then we sort numerically, and then strip the size using sed.

  • 1
    (assuming file paths don't contain newlines and bytes not forming valid characters and that $extension doesn't contain wildcards) – Stéphane Chazelas Mar 15 '18 at 12:15
  • 1
    (in which case \0 with -printf and the -z options as needed, I think) – muru Mar 15 '18 at 12:16
  • yep, NUL terminated output is the solution - e.g. find . -type f -printf "%s %p\0" | sort -z -k1,1n | awk -v RS='\0' {print $2}' (non-portable - works with GNU awk, maybe some others). +1, was going to write an answer like this but you've already written it. – cas Mar 15 '18 at 12:48

With zsh:

printf '%s\n' **/*.$extension(D.oL)

To get a GNU ls -lh-type output, with GNU ls:

ls -Ulhd -- **/*.$extension(D.oL)

Or if the list is too large:

autoload zargs # best in ~/.zshrc
zargs --eof= -- **/*.$extension(D.oL) '' ls -Ulhd --


printf '%s\0' **/*.$extension(D.oL) | xargs -r0 ls -Ulhd --

If for some reason, you do need to use find, you can always do:

printf '%s\0' ./**/*.$extension(D.oL) | xargs -r0 sh -c '
  exec find "$@" -prune ...' sh
  • The OP needs to use find for some reason. – terdon Mar 15 '18 at 12:17

i use

   find . -type f -iname "*.$extension" -print0 | xargs -0 ls -lS

this works fine for me

  • Thank you! As macOS is based on BSD, and not GNU, this is the only one of the answers which works in bash on macOS. – Andrew Watson Apr 4 at 8:04

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.