1

I wanna loop through jpg files, using find to locate them.

The result is the full path name including ./ in front. I want to remove the replace ./ with ./newsubdir/ so I can use that as the output file name in a process, creating a modified copy of the original in newsubdir using the same folder structure.

This is what I tried.

#!/bin/bash

find . -type f -name '*jpg' 
    for file do
        echo ${file:1}
    done

However the substring extraction didn't seem to work at all. Is there a reason for that or a different way to do this. Very new to Bash.

I was going for something like this as a end result. Trying to square a bunch of pictures but keep the folder structure.

#!/bin/bash

find . -type f -name '*jpg' 
    for file do
        convert '$file[2048x2048]' -gravity center -extent 2048x2048 "./newsubdir${file:1}"
    done
Ingó Vals
  • 4,788
  • 14
  • 65
  • 113

2 Answers2

3

You were close! Sticking a little closer to the original code (and thus avoiding starting more shells than necessary):

#!/bin/bash

find . -type f -name '*.jpg' -exec bash -c '
    for file do
        convert "$file[2048x2048]" -gravity center -extent 2048x2048 "./newsubdir${file:1}"
    done
' _ {} +

...or, using your original shell and avoiding -exec entirely:

#!/bin/bash
while IFS= read -r -d '' file; do
    convert "$file[2048x2048]" -gravity center -extent 2048x2048 "./newsubdir${file:1}"
done < <(find . -type f -name '*.jpg' -print0)

These patterns and more are part of UsingFind.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Yes, `_ {} +` is definitely an improvement. (Unless you're stuck with a `find` that doesn't support it!) – William Pursell Jan 31 '19 at 18:18
  • 1
    It's part of the POSIX spec since 2008, so any system that claimed to be compliant within the last decade should have it. – Charles Duffy Jan 31 '19 at 18:18
  • Unless you are stuck with an ancient version of `bash` (and don't feel like writing a recursive function to traverse the directory), `for file in **/*.jpg; do [[ -f $file ]] || continue; convert ...; done` would be simpler. – chepner Jan 31 '19 at 18:24
  • This seems to push me in the right direction, still having some troubles though. I think its because the folder structure might have spaces in them. `convert-im6.q16: unable to open image \`./newsubdir/some images/directories with spaces/filename with spaces.jpg': No such file or directory @ error/blob.c/OpenBlob/2701.` Notice different quotation markers. – Ingó Vals Jan 31 '19 at 18:35
  • @IngóVals, ...the code I gave above doesn't have any space-specific bugs. Are you quite sure `[2048x2048]` is correct when given as part of the input file name, though? I copied that from the original, but it looks suspicious. Also worth making sure whatever other wrappers you've got around the `convert` command function properly (quoting where necessary, etc). – Charles Duffy Jan 31 '19 at 18:36
  • @IngóVals, ...btw, consider running `bash -x scriptname` to have the script print every command it runs so you can inspect those commands individually and figure out how they would need to change for correct operation. – Charles Duffy Jan 31 '19 at 18:38
  • @CharlesDuffy No, I've confirmed that works, opens the image in that size. Maybe imagemagick doesn't create directories? What about the tick versus single quotation in the beginning and end of the error message path. – Ingó Vals Jan 31 '19 at 18:39
  • @IngóVals, the single-ticks in the output you quoted are part of error-message formatting, not part of the content. Once again, use `bash -x yourscript` to have the shell log the actual commands it runs to stderr; that way you can copy-and-paste that command to run it yourself and figure out how it needs to be modified. – Charles Duffy Jan 31 '19 at 18:41
  • @IngóVals, ...and yes, you probably *do* need to create the output directory yourself. – Charles Duffy Jan 31 '19 at 18:41
  • @CharlesDuffy Ok Charles, I will try to `mkdir` the directories from the filepath by removing the filename. Thanks for your help. `bash -x script` only seems to output the content of the script similar to how I see it in editor but wrapped in + – Ingó Vals Jan 31 '19 at 18:48
  • Ahh, I assumed you were using the (better) second form instead of the first one; for the first, make it `-exec bash -xc '...`, thus putting the `-x` flag on the inner shell, not only the outer one. – Charles Duffy Jan 31 '19 at 18:51
1
find . -type f -name '*jpg' -exec bash -c '
    file=$1; convert "${file}[2048x2048]" -gravity \
    center -extent 2048x2048 "./newsubdir/${file:1}"' _ {} \;

Frankly, I think you're much better off writing a script to do the conversion and just calling it with find . -type f -name '*.jpg' -exec script {} \;. Doing that will help to avoid inevitable quoting problems.

William Pursell
  • 204,365
  • 48
  • 270
  • 300