I have a lot of video files with the following syntax:


where SXEY is not constant. X and Y are numbers depending on the file. I would like to rename them to

TV Show Title - SXEY - Episode Title.mkv

In order to do that I use the rename command as the following oneliner:

rename 's/\./\ -\ /;s/\./\ -\ /;s/\.(?!mkv)/\ /g;s/1080p.*(?=\.mkv)//g' *.mkv

The command first transforms the first two dots into ␣-␣, then transforms all the other dots into whitespaces and finally removes everything between the end of the episode title and the file extension.

Any idea to improve it? I suppose there is a way to transform the first two dots with only one regex. I believe rename is a GNU utility and therefore is not present on all Unix systems, I am looking for a more portable alternative.

  • 2
    If it works what is the problem? Why do you need to improve it, presumably once you run it you are done. Apr 18, 2020 at 13:57
  • I am looking for something more portable no using rename.
    – user400679
    Apr 18, 2020 at 13:58
  • Is SXEY invariable? Will it always be there in your files?
    – terdon
    Apr 18, 2020 at 14:55
  • rename is not a GNU utility, it's a perl utility but yes, it isn't available for all systems.
    – terdon
    Apr 18, 2020 at 15:09

5 Answers 5


Appreciated that the question is actually about the regex, presented with the same I would avoid breaking my brain and

for m in *.mkv; 
    do echo mv $m "$(awk -F'.' '{
        printf "%s %s %s - %s - %s %s.%s", $1, $2, $3, $4, $5, $6, $(NF)}' <<<$m)";

Predictable, easy to read, and also easy to modify your output string. Just remove the echo


Re your comment below about sed, you can use this same technique simply by processing your filename for output using sed instead of awk

for m in *.mkv; 
    do echo mv $m "$(sed 's/\./ /1;s/\./ /1;s/\./ - /1;s/\./ - /1;s/\./ /1;s/\..*\././' <<<$m)";

You could do this:

$ rename -n 's/.(S\d+E\d+)./ - $1 - /; s/\./ /g; s/\.1080p.+\././' *mkv
TV.Show.Title.SXEY.Episode.Title.1080p.Uploader.mkv -> TV Show Title - SXEY - Episode Title 1080p Uploader mkv

Or perhaps this:

$ rename -n 's/1080p.*\.//; s/\.(?!mkv)/ /g; s/S\d+E\d+/- $& -/' *mkv
TV.Show.Title.SXEY.Episode.Title.1080p.Uploader.mkv -> TV Show Title - SXEY - Episode Title.mkv

Note that there is no reason to escape the spaces. You could therefore simplify your command without actually changing anything in the regex logic:

rename 's/\./ - /;s/\./ - /;s/\.(?!mkv)/ /g;s/1080p.*(?=.mkv)//g' *.mkv

However, this adds a space before the .mkv (your original also did this) which you don't want. So maybe this instead:

rename -n 's/\./\ -\ /;s/\./\ -\ /;s/\.(?!mkv)/\ /g;s/ 1080p.*(?=.mkv)//g' *.mkv

If you want a more portable solution, you could just use perl directly (perl is available in almost, but not quite all, *nix systems):

perl -e 'for (@ARGV){$n=$_;s/1080p.*\.//;s/\.(?!mkv)/ /g;s/S\d+E\d+/- $& -/; rename($n,$_)}' *mkv

And for maximum portability, do the whole thing in the shell (with a tiny bit of sed):

for f in *mkv; do 
    k=${f//./ }
    k=$( printf '%s' "$k" | sed 's/S\([0-9][0-9]*E[0-9][0-9]\)/ - \1 -/')
    k=${k/ 1080p*/.mkv}
    mv -- "$f" "$k"

Important note: What you are trying to do is a very bad idea. Having spaces in your file names will just make your life harder and make any sort of operation you want to run on those files in the future more difficult. Please reconsider.

  • SXEY is not a constant, X and Y are numbers depending on the file.
    – user400679
    Apr 21, 2020 at 19:47
  • @New2OB then please edit your question and explain that. We need to know what is constant and what can change in your file names.
    – terdon
    Apr 21, 2020 at 19:48
  • Thanks for the very detailed answer, by the way, I like the maximum portability answer. Don't worry I don't keep all the spaces in the filename. After doing this I set the title metadata form the filename and then I rename it again to a more easy to manipulate filename.
    – user400679
    Apr 21, 2020 at 19:51
  • @New2OB ah, good to know! And you're very welcome. The updated answer should work for any S01E12 type string.
    – terdon
    Apr 21, 2020 at 20:09
  • @isaac you're quite right. I was thinking about how they cannot take things like .*, that aren't fixed length, and I got confused. Fixed now, thanks.
    – terdon
    Apr 21, 2020 at 22:20


rename -v -n \
  's/\./ /g;s/S[X0-9]*E[Y0-9]*/- $& -/;s/ \d*p .* mkv$/.mkv/' *.mkv

Output gives a trial run, showing what would happen, but not moving any files yet:

       TV Show Title - SXEY - Episode Title.mkv)

If the output looks good remove -v -n. Since the middle substitution is my ad hoc method of coping with the unlikely demo string "SXEY", (instead of "S02E23" or something), replace that with s/S\d*E\d*/- $& -/:

rename 's/\./ /g;s/S\d*E\d*/- $& -/;s/ \d*p .* mkv$/.mkv/' *.mkv


  • There's no need to escape spaces like so "\" when using single quotes "' '".

  • The above code replaces all the .s with spaces, then hunts for the Season/Episode string, then restores the last file extension .mkv. This avoids the need for fixed-length episode and show titles.

  • But maybe there's some perly way of replacing all the spaces but the last one in one shot...
    – agc
    Apr 18, 2020 at 16:25

you can use sed instead.

sed 's/\./ /1;s/\./ /1;s/\./ - /1;s/\./ - /1;s/\./ /1;s/\.1080p\.Uploader\.mkv/\.mkv/1;'

it replaces the first occurrence of dot each time.

  • How about sed 's/\./ /1;s/\./ /1;s/\./ - /1;s/\./ - /1;s/\./ /1;s/\..*\././'
    – bu5hman
    Apr 18, 2020 at 14:16
  • How can I rename using sed?
    – user400679
    Apr 18, 2020 at 14:26

Not really sure about whether capture groups are supported in your utility, but using them would be a viable strategy


Then you would substitute with

$1 $2 $3 - $4 - $5 $6.$7

An advantage to this strategy is that it actually parses the semantic meaning of your other naming scheme and would allow fields to be reordered or omitted. I prefer using character groups to escape characters when possible, it is easier to read [.] than \..

You must log in to answer this question.