views:

266

answers:

3

Hi there,

I don't really know that much about bash scripts OR imagemagick, but I am attempting to create a script in which you can give some sort of regexp matching pattern for a list of images and then process those into new files that have a given filename prefix.

for example given the following dir listing:

allfiles01.jpg allfiles02.jpg allfiles03.jpg

i would like to call the script like so:

./resisemany.sh allfiles*.jpg 30 newnames*.jpg

the end result of this would be that you get a bunch of new files with newnames, the numbers match up,

so far what i have is:

IMAGELIST=$1
RESIEZFACTOR=$2
NUMIMGS=length($IMAGELIST)

for(i=0; i<NUMIMGS; i++)
  convert $IMAGELIST[i] -filter bessel -resize . RESIZEFACTOR . % myfile.JPG

Thanks for any help... The parts that I obviously need help with are 1. how to give a bash script matching criteria that it understands 2. how to use the $2 without having it match the 2nd item in the image list 3. how to get the length of the image list 4. how to create a proper for loop in such a case 5. how to do proper text replacement for a shell command whereby you are appending items as i allude to.

jml

+1  A: 

Probably the way a standard program would work would be to take an "in" filename pattern and an "out" filename pattern and perform the operation on each file in the current directory that matches the "in" pattern, substituting appropriate parts into the "out" pattern. This is pretty easy if you have a hard-coded pattern, when you can write one-off commands like

for infile in *.jpg; do convert $infile -filter bessel -resize 30% ${infile//allfiles/newnames}; done

In order to make a script that will do this with any pattern, though, you need something more complicated because your filename transformation might be something more complicated than just replacing one part with another. Unfortunately Bash doesn't really give you a way to identify what part of the filename matched a specific part of the pattern, so you'd have to use a more capable regular expression engine, like sed for example:

#!/bin/bash

inpattern=$1
factor=$2
outpattern=$3
for infile in *; do
    outfile=$(echo $infile | sed -n "s/$inpattern/$outpattern/p")
    test -z $outfile && continue
    convert $infile -filter bessel -resize $factor% $outfile
done

That could be invoked as

./resizemany.sh 'allfiles\(.*\).jpg' 30 'newnames\1.jpg'

(note the single quotes!) and it would resize allfiles1.jpg to newnames1.jpg, etc. But then you'd wind up basically having to learn sed's regular expression syntax to specify your in and out patterns. (It's not that bad, really)

David Zaslavsky
+1  A: 

Your script should be called using a syntax such as:

./resizemany.sh -r 30 -n newnames -o allfiles allfiles*.jpg

and use getopts to process the options. What you may not be aware of is that the shell expands the file glob before the script gets it so the way you had your arguments your script would never be able to distinguish the filenames from the other parameters.

Output files will be named using the rename script often found on systems with Perl installed. A file named "allfiles03.jpg" will be output as "newname03.jpg".

#!/bin/bash

options=":r:n:o:"
while getopts $options option
do
    case $option in
        n)
            newnamepattern=$OPTARG
            ;;
        o)
            oldnamepattern=$OPTARG
            ;;
        r)
            resizefacor=$OPTARG
            ;;

        \?)
            echo "Invalid option"
            exit 1
    esac
done
# a check to see if any options are missing should be performed (not implemented)
shift $((OPTIND - 1))
# now all that's left will be treated as filenames
for file
do
    convert (input options) "$file" -resize $resizefactor (output options) "${file}.out" 
    rename "s/$old/$new/;s/\.out$//" "${file}.out"
done

This is untested (obviously since most of the arguments to convert are missing).

Parameter validation such as range checks, missing required options and others are left as exercises for further development. Also absent are checks for successful completion of one step before continuing to the next one. Also issues such as locations of files and name collisions and others are not addressed.

Dennis Williamson
+1  A: 

You could eliminate the regex problem if you make a folder of all the files to be processed, and then run something like:

for img in `ls *.jpg`
do
  convert $img -filter bessel -resize 30% processed-$img
done

Then, if you need to rename them all later, you could do something like:

ls | nl -nrz -w2 | while read a b;  do mv "$b" newfilename.$a.jpg; done;

Also, If you are doing a batch process of the same operation, you might see if using mogrify might help (imagemagik's method for converting multiple files). Like the above example, it's always good to make a copy of the folder, and then run any processing so you don't destroy your original files.

gldunne