Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm pretty new to BASH scripting and I'm looking for an elegant way to solve my task:

In a given directory certain files regularly have to be sorted into subfolders. The name of the files has a fixed structure and the destination folder in which those files shall be put, depends on their names.

At the moment my scripts looks like this:

#!/bin/bash
declare -r SOURCEDIR=/some/dir/upload
declare -r DESTBASEDIR=/some/dir/archive

for year in "2009" "2010" "2011" "2012" "2013" "2014"; do
  for letter in {0..9} {A..Z}; do
      mkdir -p ${DESTBASEDIR}/${year}/${letter}
      mv ${SOURCEDIR}/123456789012_${letter}?_??_${year}????.dat ${DESTBASEDIR}/${year}/${letter}/
  done
done

The script does exactly what I want, but it creates destination folders even if mv won't find any file to move there. I'd like a mv with an option to create necessary directorys instead of creating them using mkdir.

I know this script will display errors when no file to move exists. I'll suppress error messages, when the script is completed.

Is there an easy and elegant way to create the directory structure on the fly without creating enpty directorys?

Thank you for your help!

Regards

Manuel


glenn jackman's Version inspired me to the following scripts which does the trick :)

#!/bin/bash
declare -r SOURCEDIR=/some/dir/upload
declare -r DESTBASEDIR=/some/dir/archive

cd "$SOURCEDIR"
for f in 1234567890_* ; do
  letter=${f:11:1}
  year=${f:21:4}

  dest="$DESTBASEDIR/$year/$letter"

  mkdir -p "$dest"
  mv "$f" "$dest"
done

Note that the offsets inside the filename have moved since I found out, the leading number at the beginning of the filename is shorter. The given solution was designed on my false example.

This approach is less safe, as it doesn't check, if the filenames of the files in the source directory are composed as supposed. In this case, I can rely on that, so I don't risk much by not verifying this.

The given line in glenn jackman's Version

for f in 123456789012_[A-Z]?_??_[0-9][0-9][0-9][0-9]????.dat ; do

didn't work. The value after "in" has been interpreted as a literal string on my bash. I don't know how to 'repair' this.

share|improve this question

1 Answer 1

This will only create the year/letter directories that are actually used in filenames.

cd "$SOURCEDIR"
for f in 123456789012_[A-Z]?_??_[0-9][0-9][0-9][0-9]????.dat ; do
    letter=${f:13:1}
    year=${f:19:4}
    dest="$DESTBASEDIR/$year/$letter"
    mkdir -p "$dest"
    mv "$f" "$dest"
done

Note that using ${braces} is not the same as using "$quotes" if the variable's value contains whitespace

share|improve this answer
    
Thank you! This is an interesting approach :) But: it doesn't do the trick. You've forgotten the digits in "for letter in {0..9} {A..Z}; do" and I'm not sure, how to add them into your version. –  Manuel Feb 12 at 13:03

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.