5

I am working on a bash script to compress the images in my Wordpress folders. The wordpress folder structure is as follows:

> wp-content/uploads/2014/01/filename.jpg
> wp-content/uploads/2014/02/filename.jpg
> wp-content/uploads/2014/03/filename.jpg
> wp-content/uploads/2014/04/filename.jpg
> 
> i.e. wp-content/uploads/YEAR/MONTH/filename.jpg

In the uploads folder I have a number of other folders (which were created when plugins were installed), so I'm trying to loop through the folders with numeric names only and then compress the images. Here is what I have so far:

DIR_UPLOADS=/home/html/wp-content/uploads/
cd ${DIR_UPLOADS}    
for d in *; do                 # First level i.e. 2014, 2013 folders.
     regx='^[0-9]+$'           # Regular Expression to check for numerics.
     if [[$d =~ $regx]]; then  # Check if folder name is numeric.
       #echo "error: Not a number" >&2; exit 1
       cd $d
       for z in *; do          # Second level i.e. the months folders 01, 02 etc.
        cd $z
        for x in *; do         # Third level the actual file.              
          echo 'Compress Image'
        done
      done
     fi
    done

I'm trying to use reg ex to detect the numeric folders, this isn't quite right, but I think I'm close.

  • Yes, I could do that for the months alright. – Stephen Apr 14 '14 at 9:43
  • @bdowning Where do you live that has 13 months? – Gilles Apr 14 '14 at 21:46
  • force of habit to use zero offset, oops. IIRC the Zorastrian calendar does have 13 months. :) – bsd Apr 15 '14 at 10:48
  • The months don't change, why not loop over the actual values? 2nd level: for mon in {01..12}; do ... – bsd Apr 15 '14 at 10:48
5

You can use bash extended globbing for this:

shopt -s extglob
DIR_UPLOADS=/home/html/wp-content/uploads/
cd ${DIR_UPLOADS}

for dir in $PWD/+([0-9])/+([0-9]); do
  cd "$dir" &&
    for file in *; do
      echo 'Compress Image'
    done
done

From the man page:

+(pattern-list)
    Matches one or more occurrences of the given patterns

So putting a number range inside will match files/directories. Adding the && conditional will ensure that you only compress images if the match is a directory (and that you actually succeeded in entering it).

Without the extended globbing, you could even just do [1-2][0-9][0-9][0-9]/[0-1][0-9]. This is better than trying a brace expansion as you won't end up attempting to enter directories for every single year/month, even if you have no images from then.

  • I'm getting the following errors: – Stephen Apr 14 '14 at 10:28
  • @Stephen, I am not seeing your errors. Please add them to your question instead of posting them in comments. – Graeme Apr 14 '14 at 10:30
  • The error will probably be because you don't cd back from the subdirectory you moved into so the next loops will fail. – terdon Apr 14 '14 at 14:11
  • Sorry Graeme, I got sidetracked for a few hours. Terdon is correct that was the error I was getting, resolved now. – Stephen Apr 14 '14 at 15:40
  • @Stephen, updated. You can fix this by adding the PWD to the glob. – Graeme Apr 14 '14 at 18:50
2

I think I would've done this using find but just to help answer your scripting questions I've modified your example slightly.

#!/bin/bash

for d in *; do                # First level i.e. 2014, 2013 folders.
  regx='^[0-9]+$'             # Regular Expression to check for numerics.
  echo "dir: $d"
  if [[ $d =~ $regx ]]; then  # Check if folder name is numeric.
    echo "found num: $d"
    pushd $d >& /dev/null
    for z in *; do            # Second level i.e. the months folders 01, 02 etc.
      pushd $z >& /dev/null
      for x in *; do          # Third level the actual file.              
        echo "Compressing Image: $x"
      done
      popd >& /dev/null
    done
    popd >& /dev/null
  fi
done

Your approach seemed fine. I think part of your issue was the use of cd. You need to go back directory levels as you're "walking" the directory tree. I'll typically use pushd and popd instead, as I've added these to your example.

Example

Now when I run this on my Wordpress uploads directory:

$ pwd
/var/www/html/apps/wordpress/wp-content/uploads

A sample run:

$ ./asc.bash | head -15
dir: 2009
found num: 2009
Compressing Image: GURULABS-RPM-GUIDE-v1.0.pdf
Compressing Image: How_to_create_an_RPM_package.mht
Compressing Image: ss_mtr_1-150x150.png
Compressing Image: ss_mtr_1-300x146.png
Compressing Image: ss_mtr_1.png
Compressing Image: ss_mtr_2-150x150.png
Compressing Image: ss_mtr_2-300x115.png
Compressing Image: ss_mtr_2.png
Compressing Image: ss_mtr_3-150x150.png
Compressing Image: ss_mtr_3-300x117.png
Compressing Image: ss_mtr_3.png
Compressing Image: ss1_trac_gitplugin-1024x262.png
Compressing Image: ss1_trac_gitplugin-150x150.png

Improvements

I'd add some tests prior to looking through a given month in cases where that month's directory is empty. Otherwise you'll get this:

Compressing Image: *
Compressing Image: *
Compressing Image: *

Walking a directory tree like this can be tricky. Since the directory structure is fairly structured, why not walk it like this:

for dir in 20*/*; do
  echo "$dir"
  for files in $dir/*; do
    if [ -e $dir/$files ]; then
      echo "$dir/$files: ..compress.."
    fi
  done
done

Or like this:

for year in $(printf '%4d\n' {2000..2014}); do
  echo "$year"
  for mnth in $(printf '%02d\n' {00..12}); do
    if [ -e $year/$mnth ]; then
      echo "$mnth"
    fi
  done
done

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.