Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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:

The.Big.Bang.Theory.S01E01.xxxxxxxxxxx.mp4

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:

The.Big.Bang.Theory.S01E01.mp4

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!

share|improve this question
    
Looks like youll need regular expressions for that –  MaxMackie Aug 22 '11 at 11:36
    
Duplicate of apple.stackexchange.com/q/22796/7057 –  glenn jackman Aug 22 '11 at 13:58

2 Answers 2

up vote 3 down vote accepted

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 )
share|improve this answer
    
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]\) –  glenn jackman Aug 22 '11 at 14:02
    
@glenn jackman - thanks so much! –  Stu Aug 22 '11 at 14:14

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.

share|improve this answer
    
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
    
@fred - thank you for the hint –  Stu Aug 22 '11 at 12:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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