You are not logged in.

#1 2010-06-04 23:16:03

evil
Member
From: Indianapolis, IN
Registered: 2010-03-06
Posts: 41
Website

Batch renaming script

UPDATED: Forum member dmz brought it to my attention that parsing with ls is a bad move. Thank you dmz for the helpful information. I have updated the script with the replacement

I dont know if this is the appropriate forum to post this under, but it seemed the most logical one. Anyway, I had a directory filled with JPEGS and needed to rename them all in sequential order. Therefore, I wrote this script to do it for me. If there is an easier way, please I beg you enlighten me. The learning process is never over and I try to keep an open mind. Anyway, here is the script:

EDIT: I am now using Python as the base language for performing this task. You can see the work-in-progress at http://bbs.archlinux.org/viewtopic.php?id=98461. Many thanks to those who have helped me with the bash scripting, however I see no point in having two threads for the same issue.


#!/bin/bash

# A script to rename a directory of JPEGS to sequential file names
# Since the directory I needed to name had over 1000 JPEGS
# I decided to append leading 0's in order for the file manager and ls
# to list the pictures in proper order. If I just did a simple increment
# the order would turn out like this
# pic1,pic10-19,pic2,pic20-29, etc
# Script written by Evil

# BTW, I know someone will say it. I know on the line that has
# $fCount -le 99 
# I could have done $fCount -lt 100
# Before I correct it, it was $fCount -lt 99 which was erroneous so I
# simply changed the comparison operator rather than the number
# considering it was less typing.. which is the Linux way ::wink::

fCount=1 # initialize the fCount variable

for i in `find *.jpg`; # this will go through file by file of ls in the CURRENT DIRECTORY
do
if [ $fCount -lt 10 ]; then  # basically, if the fCount variable is less than 10...
  mv ./$i ./pic000$fCount.jpg # ... then rename picture to pic000 + number from 1-9
elif [ $fCount -gt 9 ] && [ $fCount -le 99 ]; then # if fcount is greater than 9 and less than or equal to 99
  mv ./$i ./pic00$fCount.jpg #then only use two 00's
elif [ $fCount -gt 99 ] && [ $fCount -lt 1000 ]; then #if fcount is greater than 99 and less than 1000
  mv ./$i ./pic0$fCount.jpg # then use only one 0
else
  mv ./$i ./pic$fCount.jpg #everything else done use any 0's
fi
fCount=`expr $fCount + 1` # at the end of renaming a single file, increment the fCount variable by one
done

Last edited by evil (2010-06-10 11:50:51)


Site | Blog | Freenode Nick: i686

Offline

#2 2010-06-04 23:34:27

dmz
Member
From: Sweden
Registered: 2008-08-27
Posts: 881
Website

Offline

#3 2010-06-05 00:26:13

evil
Member
From: Indianapolis, IN
Registered: 2010-03-06
Posts: 41
Website

Re: Batch renaming script

Wow. Thanks for that information. Although I usually keep my files names clean (i.e. letters, numbers, no spaces) I can see the issue. what if I replaced `ls` with `find ./ *.jpg` ? That seems to essentially do what I needed when i was parsing ls

EDIT: just tested, with this script the proper replacement would be `find *.jpg`

Last edited by evil (2010-06-05 00:34:48)


Site | Blog | Freenode Nick: i686

Offline

#4 2010-06-05 00:47:33

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,111
Website

Re: Batch renaming script

The simplest solution is to use shell globbing.

for f in *.jpg; do
  # rename top secret goat pr0n
done

If you want to do something more complicated like iterate over the results of find, it's a bit more involved to make sure that you don't break anything. I usually use something like the following:

IFS=$'\n' read -r -d $'\0' -a files < <(find /path/to/junk -args -go -here)

for file in "${files[@]}"; do
  # invert the universe (ensure an even number of time)
done

The read builtin simply null terminates each line of find's output and adds it to an array. It's important to note that I'm using a combination of read and a for loop to avoid a while loop which creates a subshell. This allows you to assign variables inside the loop and still have access to that data after the loop terminates.

Offline

#5 2010-06-05 00:52:08

evil
Member
From: Indianapolis, IN
Registered: 2010-03-06
Posts: 41
Website

Re: Batch renaming script

falconindy wrote:

The simplest solution is to use shell globbing.

for f in *.jpg; do
  # rename top secret goat pr0n
done

If you want to do something more complicated like iterate over the results of find, it's a bit more involved to make sure that you don't break anything. I usually use something like the following:

IFS=$'\n' read -r -d $'\0' -a files < <(find /path/to/junk -args -go -here)

for file in "${files[@]}"; do
  # invert the universe (ensure an even number of time)
done

The read builtin simply null terminates each line of find's output and adds it to an array. It's important to note that I'm using a combination of read and a for loop to avoid a while loop which creates a subshell. This allows you to assign variables inside the loop and still have access to that data after the loop terminates.

Argh.. lol! I didn't know you could do " for variable in *.jpg " . (slaps forehead)
Thank you for the information smile


Site | Blog | Freenode Nick: i686

Offline

#6 2010-06-07 07:57:50

kmaglione
Member
Registered: 2009-07-03
Posts: 7

Re: Batch renaming script

You seem to make things very complicated. It's really a very simple
problem:

#!/bin/sh

base=$1
i=0
for f in *.jpg; do
    mv "$f" "$(printf "$base-%03d.jpg" $i)";
    i=$((i + 1))
done

Although, of course, this is unsafe if any of the filenames already
fit the pattern $base-000.jpg.

You might also have a look at zsh's zmv function, although it's
insanely complicated and therefore evil.

Offline

#7 2010-06-07 08:41:48

demian
Member
From: Frankfurt, Germany
Registered: 2009-05-06
Posts: 709

Re: Batch renaming script

zmv has a lazy mode:

(noglob) zmv -W diff* patch*
(noglob) zmv -W *.gif *.jpg

It's really simple und very very useful. I use it all the time (aliased to mmv).
I can only encourage trying out ZSH.

Here are a few zmv functions I use often, too:

  mmvlc() { # lowercase all files (-r = recursively)
    if [[ $1 = -r ]];then
      zmv '(**/)(*)' '$1${(L)2}'
    else
      zmv '(*)' '${(L)1}'
    fi
  }
  mmvsp() { # replace spaces with underscores (-r = recursively)
    if [[ $1 = -r ]];then
      zmv '(**/)(* *)' '$f:gs/ /_'
    else
      zmv '(* *)' '$f:gs/ /_'
    fi
  }
  mmvspecial() { # remove  / : ; * = " ' ( ) < > | from filenames
    unwanted="[(:);*?\"<>|']"
    zmv -Q "(**/)(*$~unwanted*)(D)" '$1${2//$~unwanted/}'
  }

There are also a lot of practical usage examples for zmv on these two pages:
http://grml.org/zsh/zsh-lovers.html
http://rayninfo.co.uk/tips/zshtips.html

Regards,
demian

Last edited by demian (2010-06-07 08:54:24)


no place like /home
github

Offline

#8 2010-06-10 11:26:46

evil
Member
From: Indianapolis, IN
Registered: 2010-03-06
Posts: 41
Website

Re: Batch renaming script

I would love to try out z shell but the fact remains that I am still a noob when it comes to Linux and I still have a lot to learn without putting more on my plate. I will keep that in mind though as I do love trying new things.

EDIT: I have actually moved from using bash to python as a project to further my knowledge in the Python language. So far, it seems very promising. Here is the link: http://bbs.archlinux.org/viewtopic.php?id=98461

Last edited by evil (2010-06-10 11:49:33)


Site | Blog | Freenode Nick: i686

Offline

Board footer

Powered by FluxBB