4

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
einstein/copyright.txt
einstein/do-how.txt
einstein/etext9/bil11.txt
einstein/etext9/2ws271.txt
einstein/etext9/liber11.txt
einstein/etext0/bib0010h/Readme.txt
einstein/etext0/kknta10.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
  • 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
    Commented Mar 15, 2018 at 12:10

5 Answers 5

6

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.

3
  • 1
    (assuming file paths don't contain newlines and bytes not forming valid characters and that $extension doesn't contain wildcards) Commented Mar 15, 2018 at 12:15
  • 1
    (in which case \0 with -printf and the -z options as needed, I think)
    – muru
    Commented Mar 15, 2018 at 12:16
  • 1
    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
    Commented Mar 15, 2018 at 12:48
3

i use

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

this works fine for me

1
  • 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. Commented Apr 4, 2019 at 8:04
1

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 --

Or

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
1
  • The OP needs to use find for some reason.
    – terdon
    Commented Mar 15, 2018 at 12:17
0

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".

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

Addition to muru's answer

You can use -exec du '{}' ';' inplace of -printf "%s %p" and still produces same format. So the final command be like

find . -type f -iname "*.$extension" -exec du '--' '{}' ';' | sort -n | sed 's/^[0-9]* //'

Explanation for the -exec du '-b' '--' '{}' ';'

  1. -exec flag tells find to execute command (which is du) with {} occurence in arguments replaced with file path
  2. '-b' tells du command to output bytes amount instead in kilobytes
  3. '--' is a (flag? I need help about what this named) which signals ends of options and the rest of arguments is positional argument. One example where this needed is doing anything with file ambiguously named as option like -whatever
  4. '{}' going back to point 1. find will substitute this with file path
  5. ";" tells for find command that arguments for -exec is ended and can process the rest of arguments normally

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .