I am trying to write a bash shell script in Mac OS X 10.6 (which is called by an Automator Action) to rename TV show DVD rips that I have named badly over the years. I want to remove part of the text in the filenames. I want to remove the text that appears after a specific series of characters that I know will always appear in the filename. But I do not know how many characters will appear before or after the known series of characters. I also don't know if the before or after text will contain multiple periods or dashes. An example would probably help:


I know that each file will always contain a string in the format of SxxExx where the x's are always numbers. But I do not know what the numbers will be. I want to get the filename up to and including the SxxExx string and the file extension but strip out everything else. So for the above example I would end-up with:


I have tried using bash's built-in string replacement commands. I thought the expr index command would give me the start point of the SxxExx string and then I could use ${filename:offset:length} to extract only the required part of the filename (I already know the extension so that can be re-added). But it seems the OS X version of expr doesn't include the index functionality. I have only scripted in Basic and LotusScript before. In those environments this would have been fairly easy using commands such as 'Like' and 'Instr' or 'Mid'. But in bash I just can't figure it out. I have spent hours googling trying to understand how to use regular expressions to locate the 'SxxExx' substring in the filename but I just can't figure it out. I hope some clever UNIX scripters will be able to help me!


Try this:

newname=`echo "$filename" | sed -e 's/\(S[0-9][0-9]E[0-9][0-9]\).*\.mp4/\1.mp4/'`

The regular expression is:

  • start a group ( \( )
  • match SXXEXX where X is a numeral between 0 and 9
  • end group ( \) )
  • match any number of any character (except a newline)
  • match a explicit string ( .mp4 )

In the replacement expression:

  • replace with string matched in first group ( \1 )
  • replace with explicit string ( .mp4 )
  • Thanks. That worked perfectly. Thank you so much. I knew the sed command would be the key but I just couldn't understand how to use it, despite reading several 'beginners' guides to sed. Thanks again. Are 'S' and 'E' case sensitive? If so, how would I allow it to match either upper or lower case - e.g. Ss or Ee?
    – Stu
    Aug 22 '11 at 12:43
  • 1
    @Stu, use \([sS][0-9][0-9][eE][0-9][0-9]\) Aug 22 '11 at 14:02

Supposing you have a list of filenames with paths in the file-list file, try the following

while IFS= read -r path; do
  newpath=$(printf '%s\n' "$path" |
    sed 's/\(.*S[0-9]*E[0-9]*\.\).*\.\([^.]*\)$/\1\2/')
  echo mv -- "$path" "$newpath"
done <file-list

Meaning of sed regular expression used, also compared with example input "The.Big.Bang.Theory.S01E01.xxxxxxxxxxx.mp4"

\(                               start of group 1
.*        The.Big.Bang.Theory.   any sequence of characters
S[0-9]*   S01                    a capital S followed by 0 or more digits
E[0-9]*   E01                    a capital E followed by 0 or more digits
\.        .                      a dot
\)                               end of group 1
.*        xxxxxxxxxxx            any sequence of characters
\.        .                      a dot
\(                               start of group 2
[^.]*     mp4                    a sequence of 0 or more non-dot characters
\)                               end of group 2
$                                end of line

In the output, the string \1\2 means "output group1 followed by group2 (so to remove xxxxxxxxxxx.)

Remove the echo if satisfied.

  • Thank you. I tried Arcege's suggestion because I saw it first but I think this would work just as well. Thanks so much for your quick response. I really appreciate.
    – Stu
    Aug 22 '11 at 12:44
  • 1
    @stu: You can use S[0-9]{2}E[0-9]{2} instead of S[0-9]*E[0-9]* if you want to match exactly 2 digits after the S and E.
    – Peter.O
    Aug 22 '11 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.