13

I want to rename files in the format:

img_MM-DD-YY_XX.jpg

img_MM-DD-YY_XXX.jpg

to:

newyears_YYYY-MM-DD_XXX.jpg

Where:

  • YYYY = year
  • MM = month
  • DD = day
  • XXX or XX = photo number

I came up with this script but it isn't working:

for filename in ?*.jpg; do
        newFilename=$(echo $filename | \
        sed 's/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9]\)\./newyears_20\3-\1-\2_0\4./;
                s/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9][0-9]\)/newyears_20\3-\1-\2_\4/' -)
        mv $filename $newFilename
done

Any help would be greatly appreciated.

anubhava
  • 761,203
  • 64
  • 569
  • 643
tiagob
  • 1,088
  • 1
  • 11
  • 14
  • What happens when you run your script? What does `for filename in ?*.jpg; do echo $filename; done` return? – justarobert Apr 15 '11 at 02:39
  • I found the problem. Removing the backslash, "\", after the pipe, "|", makes it work. I guess newlines should not be escaped in bash scripts. Is this correct? – tiagob Apr 15 '11 at 02:43
  • the backslash isn't necessary, but shouldn't cause any trouble. Might there have been a space after it, or something like that? – Gordon Davisson Apr 15 '11 at 03:38

7 Answers7

17

You can try this script in bash:

for filename in *.jpg; do
  newFilename=$(sed -E 's#img_([0-9]{1,2})-([0-9]{1,2})-([0-9]{1,2})_(.*)$#newyears_20\3-\2-\1_\4#' <<< "$filename")
  mv "$filename" "$newFilename"
done

sed -E is supported by gnu sed also.

anubhava
  • 761,203
  • 64
  • 569
  • 643
3

Without a for loop.

ls | grep 'jpg$' | sed '
#Save the original filename
h
#Do the replacement
s/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9]\)\./newyears_20\3-\1-\2_0\4.//
s/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9][0-9]\)/newyears_20\3-\1-\2_\4//
#Bring the original filename back
x
G
s/^\(.*\)\n\(.*\)$/mv "\1" "\2"' | bash

Ommit piping to bash to see the results before mv

Thanks to http://www.gnu.org/software/sed/manual/sed.html#Rename-files-to-lower-case

earthdan
  • 388
  • 5
  • 12
1

This trivial variant works for me:

$ cat mapper
for filename in ?*.jpg
do
    newFilename=$(echo $filename | \
    sed -e 's/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9]\)\./newyears_20\3-\1-\2_0\4./' \
        -e 's/img_\(.*\)-\(.*\)-\(.*\)_\([0-9][0-9][0-9]\)/newyears_20\3-\1-\2_\4/')
    echo mv $filename $newFilename
done
$ echo > img_04-23-09_123.jpg
$ echo > img_08-13-08_33.jpg
$ sh mapper
mv img_04-23-09_123.jpg newyears_2009-04-23_123.jpg
mv img_08-13-08_33.jpg newyears_2008-08-13_033.jpg
$

The only difference is the use of the explicit -e options in place of a semi-colon.

Tested on MacOS X 10.6.7.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

I remember messing around with this sort of thing. I found it often useful to create a script that you execute to do what you want:

ie. output of your script would be a file like:

mv   file1 file2
mv   file3 file4
.....
mv   fileN fileM

To create this, just do a ls | grep date pattern | sed script to stick mv file1 to file2 > myscript

then just execute ./myscript

This way you have a better look at the intermediate output to figure out what's going wrong.

Larry Watanabe
  • 10,126
  • 9
  • 43
  • 46
0

It could be handled by a purely bash script.

for j in ?*.jpg
do
  n="newyears_20${j:10:2}-${j:4:2}-${j:7:2}";
  if [ ${j:15:1} = "." ];then
    n="${n}_0${j:13}"
  else
    n="${n}${j:12}"
  fi
  mv $j $n
done
Yi Zhao
  • 6,768
  • 1
  • 18
  • 18
-1

Ruby(1.9+)

$ ruby -e 'Dir["img*jpg"].each{|x|File.rename(x,x.gsub(/img_(.*?)-(.*?)-(.*?)\.jpg/,"newyears_20\\2-\\1-\\3.jpg") )}'
kurumi
  • 25,121
  • 5
  • 44
  • 52
-1
for f in *.jpg; do
  n=$(sed -r 's/^(.+)-([^_]+)_(.+)\.jpg/\2-\1_\3.jpg/' <<< "${f#img_}")
  mv "$f" "newyears_20$n"
done

The <<< is a bash feature called a here string and ${f#img_} removes the img_ prefix from $f. The sed expression turns img_MM-DD-YY_XX.jpg into YY-MM-DD_XX.jpg by isolating MM-DD into \1, YY into \2 and XX into \3 then forming \2-\1_\3.jpg. Note that no quoting is required in the n assignment.

For safety, for things like this I actually prefer to use echo mv instead of mv, so I can see the command this would generate. Then you can remove echo or pipe the output to sh.

Idelic
  • 14,976
  • 5
  • 35
  • 40
  • Seems too fragile. Need quoting – Gilles Quénot Jun 29 '20 at 14:11
  • 1
    Please add explanations to your answer for long term value, and so future visitors can learn from your solution, and apply th this knowledge to their own coding issues. Code only answers are frowned upon, and less likely to receive upvotes. – SherylHohman Jun 29 '20 at 20:22
  • Fixed the quoting, added explanation. Actually, rewrote the whole thing, since the output was all wrong. I guess I didn't test it at the time. – Idelic Jul 03 '20 at 16:40