Bash mass file rename script

Ever run into a situation where you have a bunch of files that need to be renamed to a certain format? I constantly run into this and have been writing a quick bash for loop with a sed expression to mass rename the files. I noticed I was repeating this a lot, so I decided to make a little script out of it.

Anyone who downloads files that are named something like:
Something_-_01-01.ext,  Something_-_01-02.ext, etc..

.. and wants to mass-rename them in a very flexible manner, like this (just as an example):
01 – Something – 01.ext,  01 – Something – 02.ext, etc..

.. and has way too little free time to do this one by one, then check this out.

Requirements:

  • Linux or cygwin (Bash/sh interpreter + sed, tr)
  • Knowledge of what a bash script is, and how to run it.
  • Knowledge of sed and regex expressions.

Usage:

renamer.sh (-s<string>|-t<string>) [options]
 
   Options:
     -s      : SED expression (e.g. "s/_/-/g" will replace "_" with "-" for all filenames)
     -t      : Character translation map (e.g. "abc|def" will change "apple" to "dpple" )
     -m      : Move files, will not move files otherwise
     -r      : Recursive renaming in child directories
     -a<str> : Set file match condition (current: *)
     -h|-H   : Displays this usage screen

Examples:

  • Something_-_01-01.ext » 01 – Something – 01.ext 
    renamer.sh -s"s/\(.[^_]*\)_-_\([0-9]*\)-\([0-9]*\)/\2 - \1 - \3/"
  • Something_-_01_-_BlaBlaBla_-_01.ext » Something – 01 – BlaBlaBla - 01.ext 
    renamer.sh -t"_| "
     
    or..
     
    renamer.sh -s"s/_/ /g"

Script:

Download

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#!/bin/sh
 
APP=$0
search=""
translate=""
move=0
aFile="*"
aRecurse=0
 
doUsage() {
  echo
  echo " $APP (-s|-t) [options]"
  echo
  echo "   Options:"
  echo "     -s      : SED expression (e.g. \"s/_/-/g\" will replace \"_\" with \"-\" for all filenames)"
  echo "     -t      : Character translation map (e.g. \"abc|def\" will change \"apple\" to \"dpple\" )"
  echo "     -m      : Move files, will not move files otherwise"
  echo "     -r      : Recursive renaming in child directories"
  echo "     -a : Set file match condition (current: $aFile)"
  echo "     -h|-H   : Displays this usage screen"
  echo
}
 
transformSed() {
 
  # perform sed op
  F=`echo "$1" | sed "$search"`
 
  # see if we have problems with sed op
  if [ $? -gt 0 ]; then
    echo "Problem detected with sed expression." >&2
    return 1
  fi
 
  # echo out the new string
  echo "$F"
  return 0
}
 
transformTranslate() {
 
  INF=$1
 
  declare -a TSTR
 
  echo "$translate" | tr "|" "\n" | while read T
  do
 
    if [ -z "$T" ]; then
      T=' '
    fi
 
    TSTR[${#TSTR[@]}]="$T"
 
    if [ ${#TSTR[@]} -eq 2 ] ; then
 
      TF=${TSTR[0]}
      TT=${TSTR[1]} 
 
      F=`echo "$INF" | tr "$TF" "$TT"`
 
      # see if we have problems with sed op
      if [ $? -gt 0 ]; then
        echo "Problem detected with translate expression." >&2
        return 1
      fi
 
      echo "$F"
      return 0
    fi
  done
}
 
procFile() {
 
  F="$1"
 
  # skip dirs
  if [ -d "$F" ]; then
    return 1;
  fi
 
  # get original file path
  cpath=`dirname "$F"`
 
  # get original file name
  cfile=`basename "$F"`
 
  if [ ! -z "$search" ]; then # do sed transformation
    cfile=`transformSed "$cfile"`
    if [ $? -gt 0 ]; then return 2; fi
  fi
 
  if [ ! -z "$translate" ]; then # do translate transformation
    cfile=`transformTranslate "$cfile"`
    if [ $? -gt 0 ]; then return 2; fi
  fi
 
  # put filepath together again
  N="$cpath/$cfile"
 
  echo -e "\n BEFORE: '$F'\n  AFTER: '$N'"
 
  # optionally move files to replaced name
  if [ $move -eq 1 ]; then
 
    # only if files have changed
    if [ "$N" != "$F" ]; then
 
      mv "$F" "$N"
 
      if [ $? -eq 0 ]; then
        echo "Moved Successfully"
      else
        echo "Problem while moving.."
      fi;
 
    else
      echo "No filename change detected.."
    fi
 
  fi
}
 
findFiles() {
  if [ $aRecurse -eq 1 ] ; then
    find . -name '* *' -o -name '*' -a -name "$aFile"
  else
    find . -maxdepth 1 -name '* *' -o -name '*' -a -name "$aFile"
  fi
}
 
# read arguments
while getopts 'a:s:t:mrhH' o; do
  case $o in
    a)
      aFile="$OPTARG"
    ;;
    s)
      search="$OPTARG"
    ;;
    t)
      translate="$OPTARG"
    ;;
    m)
      move=1
    ;;
    r)
      aRecurse=1
    ;;
    h|H)
      doUsage
      exit 0
    ;;
    :|\?)
      doUsage >&2
      exit 1
    ;;
  esac
done
 
# validate arguments
if [ -z "$search" ] && [ -z "$translate" ]; then
  echo "No search/replace (-s ) or translate (-t ) operation was provided" >&2
  doUsage >&2
  exit 1
fi
 
# begin processing
findFiles | while read F
do
 
  # process file
  procFile "$F"
 
  # see if we have problems, if so exit early
  if [ $? -gt 1 ]; then
    exit 1
  fi
 
done
 
exit 0

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">