3

If anyone can point me to the direction of where I can learn more about this type of work I would appreciate it. I have some experience scripting with php more than anything and have been working on learning Linux (Ubuntu server CLI via SSH and SFTP for moving files in and out of my VM).

Trying to batch process multiple images in multiple directories. I am using imagemagick, which works on one file at a time.

I'd like for this to run starting at the top directory and then do this job to all the jpg files the script can find.

pseudo code -

for all folders in the directory
  open folder
  check if folder "drawings" (if !exists) then {start the loop over} else :
    open drawings folder
    for each file in drawings
      if file is a jpg
        run this program on it (convert image.jpg -crop 713x470+5+3 output.jpg)
  • Would this program only search one specific directory for any jpg files or that directory and subdirectories? – TheOdd Nov 10 '16 at 17:53
  • 1
    @OwenHines I have a main directory of folders [01,02,03,04 etc..]. Inside each of those has more specific directories example: 01 has directories [drawings, CAD, CSV etc..] and inside drawings are the actual files [image1.jpg, someText1.pdf, image2.jpg]. I would be trying to get down to the drawings folder in each of the main directory folders [01,02,03,04 etc..]. Thanks for your interest! – Edward S Bernstein Nov 10 '16 at 18:23
  • Ah, OK. Thanks for the example. I can't currently help as I'm a little bit busy, but I'm sure someone will help you get your answer soon. – TheOdd Nov 10 '16 at 18:29
  • @OwenHines Thanks! I am doing my own homework as well. So far in a .sh file I am able to loop through *.jpg within a directory and run the code. Just have to get the conditions and nested loops right. I might answer my own question in another hour! – Edward S Bernstein Nov 10 '16 at 18:35
  • @OwenHines well I RTFM =) – Edward S Bernstein Nov 10 '16 at 22:06
2

Figured out what I had to do loop-wise, just needed to get a hang of the loop syntax. Hope this helps someone else out that might need to loop through a sub-directory based on it's name.

for dir in */
do
    for subdir in $PWD/"$dir"*/
    do
        if [ "$subdir" == $PWD/"$dir""Drawings"*/ ]
        then
            for file in "$subdir"*.jpg
            do
                rm "$file"
            done

            for file in "$subdir"*.pdf
            do
                newName="${file/.pdf/}"
                convert -density 200 "$file" -append -resize 850 -background white -flatten "$newName".jpg
            done

            for file in "$subdir"*.jpg
            do
                newName="${file/.jpg/}"
                if [[ "$file" == *"insulation"* ]]
                then
                    convert "$file" -crop 820x710+15+97 "$newName-cropped.jpg"
                else
                    convert "$file" -crop 820x870+15+79 "$newName-cropped.jpg"
                fi
            done
        fi
    done
done
exit 0
1

This is what I came up with

#!/bin/bash
dnames=$(for i in $(ls -d $1*/); do echo ${i}; done)
if [ "$#" -eq "1" ]; then
    for dir in $dnames
    do
            cd $1
            cd $dir
            if [ -d "drawings" ]; then
                    cd drawings
                    jpgfiles=$(ls -p | grep -v / | awk '/.jp[e]?g/{print $0}')
                    if [ -z "$jpgfiles" ]; then
                            echo "Directory drawings exist in $dir but no .jpg images were found"
                    else
                            for jpgs in $jpgfiles
                            do
                                    echo "found $jpgs in ${dir}drawings" #convert $jpgs -crop 713x470+5+3 output.jpg
                            done
                    fi
            else
                    echo "Directory drawings cannot be found in $dir"
            fi
    done
else
    echo "A full path to the directory must be given"
    echo "For instance, /home/user1/Pictures/"
fi

This should be run with one parameter, in which the parameter is the full path to the directory. For example, if I'm going to look for that drawings folder that may be located in a subdirectory in my /home/joram/ directory

It would be like this

myprogram /home/joram/

The program loops in /home/joram/ through all the directories it contains. Then it visits every directory in /home/joram/ in hopes of finding drawings subfolder. When the program finds drawings folder that contains .jpg images, the commands are triggered. After finishing the commands, the program continues loop as long as all the directories are checked.

Example of an output of the program:

#Directory drawings cannot be found in /home/joram/Desktop/
#Directory drawings cannot be found in /home/joram/Documents/
#Directory drawings exist in /home/joram/Downloads/ but no .jpg images were found
#Directory drawings cannot be found in /home/joram/Music/
#Directory drawings cannot be found in /home/joram/my_scripts/
#found test2.jpeg in /home/joram/Pictures/drawings
#found test.jpg in /home/joram/Pictures/drawings
#Directory drawings cannot be found in /home/joram/Public/

NOTE: In it's current form, the program just prints the .jpg files it found and gives some other information as well (No other commands triggered). This way it can be tested before doing an actual thing. To make the program get what you want, delete the echo part and uncomment the command on line 16 (If that is the actual command you want to run).

Improvements could be made, hope this helps you anyway!

  • 1
    Thanks for your reply! I ran this in my Ubuntu VM and all was well. I ended putting my own answer together, but I have voted this up since it was helpful in better understanding regular expressions as I studied the script. – Edward S Bernstein Nov 10 '16 at 22:08
0

Does the algorithm have to be exactly the same or do you just care about the result? Because I think you could create much shorter and easier code if you use find for directory traversal and search:

find /path/to/search-root -path '*/drawings/*.jpg' -execdir convert -crop 713x470+5+3 {} output.jpg \;

This will find all *.jpg files that are (grand-)children of directories named drawings and run the convert command on them. The latter produces a file output.jpg in the same directory as the source file. If there are multiple source files in the same directory the previous output.jpg instance will be overwritten.

If you want to want different, “unique” output file names as to not overwrite previous results, you'll need to transform the output file name somehow. Unfortunately find can't do that, but we can delegate that task to a shell. There are multiple ways to achieve that, though I usually prefer a pipe to a while read loop because it's less annoying than escaping special characters:

find /path/to/search-root -path '*/drawings/*.jpg' -print0 |
while IFS= read -rd '' f; do
  convert -crop 713x470+5+3 "$f" "${f%.*}.output.jpg"
done

(This requires a shell with support for read -d like Bash. If you need a more portable alternative please say so.)

  • Thanks for your reply! Yes I edited my question to multiple files in multiple directories. I also ended up answering my own question after doing some research on the syntax. I just needed to create a bash script with a nested loop. Will mark answered tomorrow when I am allowed. – Edward S Bernstein Nov 11 '16 at 13:36

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.