0

I have a directory with folder structure as follows:

-- DATA -- ABD 1231345 -- 01-08-12 // date in mm-dd-yy format
                       -- 03-09-12
                       -- 06-11-12

        -- DEF 4859480 -- 02-10-12
                       -- 05-10-12
                       -- 07-10-12

I would like to batch rename this DATA folder as follows

-- DATA -- ABD 1231345 -- 2012_01_08 // date in yyyy_mm_dd format with underscore
                       -- 2012_03_09
                       -- 2012_06_11

        -- DEF 4859480 -- 2012_02_10
                       -- 2012_05_10
                       -- 2012_07_10

Do you have a suggestion on how to accomplish using command line on Mac OSX / unix?

pepe
  • 9,799
  • 25
  • 110
  • 188

4 Answers4

2

You could use a for loop and awk, parsing each file-name into your specified format and then mv to rename the original to the new name:

for dir in DATA/*; do \
    pushd "$dir"; # change directory \
    for file in *; do \
        path=`echo $file | awk -F- '{print "20"$3"_"$1"_"$2}'`; \
        mv $file $path; # "rename" the file \
    done; \
    popd; # restore original directory \
done;

This can be executed in folder above DATA. If you want to execute it directly in DATA, update the first loop to read for dir in *; do instead of DATA/*. It tells awk to use the - as the delimiter (instead of whitespace), and then reconstructs a string from "mm-dd-yy" to "20yy_mm_dd".

Using pushd and popd will enable the script to change the current directory to each subdirectory inside DATA (pushd) and then, after moving all necessary files will change back to the original (popd). Doing this will save you a lot of parsing-effort trying to save directory paths / etc.

newfurniturey
  • 37,556
  • 9
  • 94
  • 102
  • I just noticed that if I'm in the parent folder `/DATA` I cannot run your solution - it only works if I'm in the next level `ABD 1231345` -- how can I get your code to work without `cd`'ing into each first-child folder? – pepe Sep 12 '12 at 20:56
  • @torr Updated to traverse the directories; I used `pushd` and `popd` to do so - both of which are mentioned in chepner & Mat's answers (the latter linking to another question with these commands) opposed to string-manipulations to save a headache =] – newfurniturey Sep 12 '12 at 21:39
  • a problem I'm having is that the folders have a space between `ABD` and `123143` -- for example `ABD 12314435`. That is causing the script to fail as it seems to get the folder name only before the space -- so I get multiple messages like `-bash: pushd: ./ABD: No such file or directory` – pepe Sep 13 '12 at 11:55
  • @torr Sorry, I should've expected that; try adding double-quotes around the `pushd "$dir";` (I've updated the answer to show too). – newfurniturey Sep 13 '12 at 12:11
1

You could use string manipulations and arrays to do that with bash only.

Something like:

for f in * ; do
  parts=(${f//-/ })
  mv "$f" "20${parts[2]}_${parts[1]}_${parts[0]}"
done

Search this site for various options to recurse into directories e.g.: Shell script to traverse directories

Community
  • 1
  • 1
Mat
  • 202,337
  • 40
  • 393
  • 406
1

Use the date command to convert the file name:

$ date -j -f %m-%d-%y 01-08-12 +%Y_%m_%d
2012_01_08

Getting to the files is a little tricker. We'll just switch directories to avoid dealing with long file paths.

for d in DATA; do
    pushd "$d"
    for f in *; do
        new_f=$(date -j -f %m-%d-%y $f +%Y_%m_%d)
        mv "$f" "$new_f"
    done
    popd
done
chepner
  • 497,756
  • 71
  • 530
  • 681
0

This site gives a good snippet

for i in *.avi; do j=`echo $i | sed 's/(\d{2})-(\d{2})-(\d{2})/20\3_\1_\2/g'`; mv "$i" "$j"; done
FrankieTheKneeMan
  • 6,645
  • 2
  • 26
  • 37