I have hundreds of folders with thousands subdirectories and files inside of them. The file names are currently in the format

sf{number}-{number} - {text}

and I need everything deleted until {text}.


sf012-05 - toto - africa.cdg 
sf012-05 - toto - africa.mp3


toto - africa.cdg
toto - africa.mp3

Additional formats:

SF-108 - 02 Johnny Hates Jazz Shattered Dreams[K].cdg
02 - David Essex - Rock On.cdg
SF0504 - 13 Walker Brothers, The  Make It Easy On Yourself.cdg
SFLY 051 - 07 America  A Horse With No Name.cdg
SF217-12 this love - maroon 5.cdg
SF262-13. Same Mistake - James Blunt.cdg
SF287 - 13 Luke Bryan Do I.cdg
SF355-01-15 - Tough Love - Pony.cdg
Track 11 Livin' La Vida Loca (Radio Edit) - Martin, Ricky.cdg
Sunfly Hits 275 - 07 SF275-7-Right Now (Na Na Na)-Akon.mp3
Second, Minute Or Hour - Jack Penate.mp3
SF057 - Karaoke Classics Vol.57 - 03 Abba Thank You For The Music.cdg

especially the last one is total crap.

That means I need a recursive regex bash script or something similar to go through these files and to rename them.

  • Please be more specific with an accual file name.
    – fd0
    May 20, 2016 at 17:11
  • sf012-05 - toto - africa.cdg sf012-05 - toto - africa.mp3 sf225-14 - duran duran - wild boys.cdg sf225-14 - duran duran - wild boys.mp3
    – Granolaboy
    May 20, 2016 at 17:12
  • What happens if two different files have the same {text}?
    – Law29
    May 20, 2016 at 17:12
  • Well two files are always going to have the same name since it's karaoke music, one is in cdg format and the other in mp3. they should all stay.
    – Granolaboy
    May 20, 2016 at 17:14
  • So in this case you want to remove sf012-05 - and keep, say, toto - africa.cdg?
    – Law29
    May 20, 2016 at 17:14

4 Answers 4


If you have the Perl-based rename utility (called prename on some distributions) you can use a Regular Expression to rename all the files in one go.

Your requirement asks for the removal of sf{number}-{number} but all the examples start with capitals, some of them contain only one {number}, {number}-{number}-{number}, or even {number}{space}-{space}{number}. I'm going to assume that you want to include the first two of these cases.

rename -n 's/^sf[0-9-]+\s+(-\s+)?//' [Ss][Ff]*

Remove the -n when you are ready for it to apply its changes , or change it to -v to see it process files as it goes.


The easiest tool here would be zsh (like bash, only better), with its fancy globbing and the zmv function. Run this from the toplevel directory where you want to rename files.

autoload -U zmv
zmv '(**/)[Ss][Ff][0-9]##-[0-9]##[- ]#(*)' '$1$2'

Explanation: **/ is any string of leading directories. Then there's a pattern of sf (case-insensitive) followed by one or more digits, a dash and another number, followed by dashes and spaces. Finally there can be any suffix *. The numbers in the replacement refer to the parenthesized groups in the pattern.

Alternatively, you can use prename (the Perl-based rename script, available on Debian and Arch Linux, might need to be installed separately on other distributions). You'll need to combine it with find to gather the list of files to rename. It doesn't matter if rename is passed non-matching files, it'll skip files for which there's no renaming to be done.

find -name '[Ss][Ff]*' -exec prename 's!/!sf[0-9]+-[0-9]+[- ]*!!i' {} +

Here is the code (replace directory by the main directory, or where you have the subdirs):

cd directory
find -type f | while IFS= read - file; do 
    name=$(echo "$file"  | rev | cut -d'/' -f1 | rev |  cut -d'-' -f3- | cut -d' ' -f2-) 
    path=$(dirname "$file")  
    echo mv "$file" "$newname" 

Where directory is the main directory where all the subdirectories is....

Please dont remove the "echo" from "mv", test it first.

Be carefully for not run that in the wrong dir, it can be very dangerous.

  • It returns "find: paths must precede expression: ."
    – Granolaboy
    May 20, 2016 at 17:49
  • Sorry Remove the '.' from find and it will work. May 20, 2016 at 17:50
  • I think the hyphen in the middle is not being removed. mv ./SF 003/sf003-03 - queen - bohemian rhapsody.cdg ./SF 003/03 - queen - bohemian rhapsody.cdg
    – Granolaboy
    May 20, 2016 at 17:55
  • Change -f2- to -f3-. and see what happens. (updated the post) May 20, 2016 at 17:56
  • Almost perfect, there's still a whitespace left after the directory though. ./SF 001/ seal - crazy.cdg
    – Granolaboy
    May 20, 2016 at 17:59

You say you need everything deleted until {text}, but your example doesn't show that. Rather than showing exact code, let me just suggest a plan.

1) Write a script that does what you want for one filename. Something like this might do:

#! /bin/sh
test -d ~/OK/${PWD} || mkdir -p ~/OK/${PWD}
ln "$1" "~/OK/${PWD}/$1"
echo "$1" | awk -F ' - ' '{print $NF}'

That breaks the name on the pattern ' - ' and prints the last field. And saves the original filename so you can retrieve it if something goes wrong. Test it a few times, and use mv to restore the names.

2) Invoke your script with find:

$ find dirname -exec script.awk {} +

That will bury your machine with many parallel invocations of your script. When it's done, you'll have a bunch of OK directories to remove, and you'll know how to use find to remove them.

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.