I'm trying to get a per-directory total size of all the .jpg/.jpeg images in each directory that contains such images. And showing the full directory path.

I've managed to cobble this together from various bits I've found.

for i in $(tree -dfi --noreport); do
  find . \( -iname "*.jpg" -or -iname "*.jpeg" \) -type f -exec du -c {} \; $i

However I'm getting an error:

find: paths must precede expression

Anyone know what I've done wrong?
Or can suggest any alternatives with bash that might do what I'm looking for?

I get the same error when changing it to this:

for i in $(tree -dfi --noreport); do
  find $i \( -iname "*.jpg" -or -iname "*.jpeg" \) -type f -exec du {} \; $i
  • 2
    Is $i the directory where you want to search for jp[e]g images, that is, the path? If so, "[the] path[s] must precede the expression" (the bit where you put the -inames). Why do you have a . after find instead of $i? – njsg Jan 9 '13 at 16:21
  • Question edited. Still getting the same error. – batfastad Jan 9 '13 at 17:28
  • 1
    Remove the $i at the end... – njsg Jan 9 '13 at 17:33
for i in $(tree -dfi --noreport); do
    find $i -type f \( -iname "*.jpg" -or -iname "*.jpeg" \) -exec du {} \;

Drop the path name at the end of the find command and -type option should appear before any other options to make search a bit faster. This should do it.

By the way, to help you a bit, I would have done this in this way:

for i in $( tree -dfi --noreport ); do 
    find $i -maxdepth 1 -type f \( -iname "*.jpg" -or -iname "*.jpeg" \) -exec du '{}' \; | awk -v d=$i '{ j+=$1; } END{ printf("%s: %d\n", d, j) }' | grep -Ev ": 0$"
| improve this answer | |
  • Thanks for that. Though it doesn't do what I was hoping. Also I think it borks on dir names containing spaces. A fault in my original approach. – batfastad Jan 10 '13 at 10:58

Your immediate error is that extra $i at the end of the find invocation — just remove it. The order of arguments for find is first the directories to traverse, then the expression to match.

I don't get the point of the call to tree: find can do this. With GNU find (i.e. on Linux or Cygwin), assuming your directories don't contain insanely many .jpg files, the -execdir primary on find lets you run a command on all the matching files in a directory.

find . \( -name '*.jpg' -o -name '*.jpeg' \) -execdir sh -c 'echo "$(du -c "$@" | sed -n "\$s/\\t.*//p") ${PWD#$0/}"' $PWD {} +

Note that versions of GNU find prior to 4.5.9 have a bug that causes -execdir … {} + to run one command per file, which is no good here. So you may have to work harder.

You can traverse the directory tree in bash. Set the globstar option to enable the pattern **/, which matches any number of subdirectory levels, i.e. it enumerates subdirectories recursively. In each subdirectory, if there are JPEG files, call du to compute their total size.

shopt -s globstar
for d in **/*/; do
  files=("$d/"*.jpg "$d/"*.jpeg)
  total=$(du -s -- "$files" 2>/dev/null | tail -n 1)
  echo "$total"$'\t'"$d"
| improve this answer | |
  • Nice one... that one liner works beautifully. Nice tip on -execdir as well. Also seems to work with dir names containing spaces. I'm only just getting started with bash but I love how there are so many ways to do things like this. I couldn't find a way to do this under Windows so mounted the SMB share and ran this command. Nice! – batfastad Jan 10 '13 at 10:55
  • Also I did need -iname though as it was missing some directories containing .JPG/.JPEG files – batfastad Jan 10 '13 at 11:05
  • Actually I just noticed one thing, the same directory often appears twice with different sizes reported – batfastad Jan 10 '13 at 13:06
  • @benbradley The -execdir one-liner unfortunately only works on very recent (and IIRC a few older versions) of GNU find. I think most currently deployed systems have a buggy version where this reports every file independently. Try the bash loop (beware that I haven't tested it). – Gilles 'SO- stop being evil' Jan 10 '13 at 13:14

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.