3

If I have some TV Shows that are named badly and I need to clean them up

$ ls
Some_Series.1_Episode.1.mp4  'Some Series01.Episode02.mp4' SomeSeries1Episode03.mp4

I need to batch rename them to become

$ ls
S01E01.mp4  S01E02.mp4  S01E03.mp4

I have used the following script and it works but only when the original filenames contain Series and Episode numbers 01 02 03 and not 1 2 3

#!/bin/bash
# rename tv show filenames to be kodi friendly
cd /mnt/2tb_hd/con/
if [ $? == 1 ]; then 
    exit
fi
for filename in *; do
        if [[ "$filename" =~(\**).*(.*[0-9][0-9]).*([0-9][0-9]).*(\....)$ ]]; then
            result=$(echo mv \"$filename\" S${BASH_REMATCH[2]}E${BASH_REMATCH[3]}${BASH_REMATCH[4]}\") 

                if [[ $? == 0 ]] ; then 
                    mv "$filename" "S${BASH_REMATCH[2]}E${BASH_REMATCH[3]}${BASH_REMATCH[4]}"
                fi
            fi
        done
        exit

I need to make this code either change any 1 2 3 4 5 etc in the filenames to have a 0 padding before running the 2nd renaming loop or just alter the code I already have to change either 01 or 1 regardless of the 0 padding.

Sorry if this seems really obvious but I am new to bash so please forgive me.


I have updated the script and now I have issues with episode 8 and 9. I get the following error

line 10: printf: 08: invalid octal number

So episode 8 and 9 are missing but there is one extra file S02E00.mkv for each series with over 7 episodes.

The adapted script

#!/bin/bash
# rename tv show files to kodi friendly format S01E01 etc
cd /mnt/2tb_hd/Adults/TV_Shows/Breaking\ Bad/
if [ $? == 1 ]; then 
    exit
fi
reg='^([^0-9]*)([0-9][0-9]*)[^0-9]*([0-9][0-9]*).*(\....)$'
for filename in *.*; do
      if [[ $filename =~ $reg ]]; then
              printf -v newname 'S%02dE%02d%s' "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}" "${BASH_REMATCH[4]}"
                  mv "$filename" "$newname"
                fi
            done
        exit

See http://pastebin.com/2XRH85ua for the full outcome of the test run.

1 Answer 1

3

Use printf, with a format string that specifies field width and zero-padding for the integers e.g.

printf -v newname 'S%02dE%02d%s' "$((10#${BASH_REMATCH[2]}))" "$((10#${BASH_REMATCH[3]}))" "${BASH_REMATCH[4]}"

Note the use of $((10#${BASH_REMATCH[n]})) to force decimal evaluation in cases like 09

Testing (I modified your regular expression slightly BTW):

reg='^([^0-9]*)([0-9][0-9]*)[^0-9]*([0-9][0-9]*)(\....)$'
for filename in *.mp4; do
  if [[ $filename =~ $reg ]]; then
    printf -v newname 'S%02dE%02d%s' "$((10#${BASH_REMATCH[2]}))" "$((10#${BASH_REMATCH[3]}))" "${BASH_REMATCH[4]}"
    echo mv "$filename" "$newname"
  fi
done
mv Some Series01.Episode02.mp4 S01E02.mp4
mv SomeSeries1Episode03.mp4 S01E03.mp4
mv Some_Series.1_Episode.1.mp4 S01E01.mp4


Possibly more robust would be to use the regex only to match the first two sequences of digits, and use shell parameter substitution to handle the extension:

reg='([0-9][0-9]*)[^0-9]*([0-9][0-9]*)'
for filename in *.mp4 *.mkv; do
  name="${filename%.*}"
  ext="${filename##*.}"
  if [[ $name =~ $reg ]]; then
    printf -v newname 'S%02dE%02d.%s' "$((10#${BASH_REMATCH[1]}))" "$((10#${BASH_REMATCH[2]}))" "${ext}"
    echo mv "$filename" "$newname"
  fi
done
mv Some Series01.Episode02.mp4 S01E02.mp4
mv SomeSeries09Episode10.mp4 S09E10.mp4
mv SomeSeries1Episode03.mp4 S01E03.mp4
mv Some_Series.1_Episode.1.mp4 S01E01.mp4
mv Breaking.Bad.S01E01.576p.BluRay.DD5.1.x264-HiSD.mkv S01E01.mkv

Alternatively, if your system has the perl-based rename / prename command, you could so something like

prename -vn -- 's/.*(\d+).*(\d+)/sprintf "S%02dE%02d.mp4", $1, $2/e' *.mp4
9
  • Thanks, that seems to be working perfectly now. I'm not sure why you put the echo line in. I removed the echo and just have mv "$filename" "$newname" and it seems to be renaming files containing whitespaces and periods. I still need to fully test it on batches of files but time will tell. Thanks for your help
    – s7ntax
    Aug 25, 2016 at 20:44
  • It doesn't work on filenames like this 'Breaking.Bad.S01E01.576p.BluRay.DD5.1.x264-HiSD.mkv' could it be the periods or extra numbers in the filename? The problem is that files are always named really badly in an inconsistent way. I have changed the mp4 for mkv in the script.
    – s7ntax
    Aug 26, 2016 at 11:31
  • @s7ntax try changing the regex to reg='^([^0-9]*)([0-9][0-9]*)[^0-9]*([0-9][0-9]*).*(\....)$' to match (and discard) an extra sequence of arbitrary characters between the second sequence of digits and the extension. Aug 26, 2016 at 12:25
  • @s7ntax I've added a variant that I think may be more robust Aug 26, 2016 at 12:36
  • OK - just a note, you may want to add the -n or --no-clobber flag to your mv in case there are names that conflict once they are stripped of the other strings Aug 26, 2016 at 14:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .