Skip to content
Advertisement

How to delete numbers, dashes and underscores in the beginning of a file name

I have thousands of mp3 files but all with unusual file names such as 1-2songone.mp3, 2songtwo.mp3, 2_2_3_songthree.mp3. I want to remove all the numbers, dashes and underscores in the beginning of these files and get the result:

songone.mp3
songtwo.mp3
songthree.mp3

Advertisement

Answer

This can be done using extended globbing:

$ ls
1-2songone.mp3  2_2_3_songthree.mp3  2songtwo.mp3
$ shopt -s extglob
$ for fname in *.mp3; do mv -- "$fname" "${fname##*([-_[:digit:]])}"; done
$ ls
songone.mp3  songthree.mp3  songtwo.mp3

This uses parameter expansion: ${fname##pattern} removes the longest possible match from the beginning of fname. As the pattern, we use *([-_[:digit:]]), where *(pattern) stands for “zero or more matches of pattern”, and the actual pattern is a bracket expression for hyhpens, underscores and digits.

Remarks:

  • The -- after mv indicates the end of options for move and makes sure that filenames starting with - aren’t interpreted as options.

  • The *() expression requires the extglob shell option. As pointed out, if you don’t want extended globs later, you have to unset it again with shopt -u extglob.

  • As per Gordon Davisson‘s comment: this will clobber files if you have, for example, something like 1file.mp3 and 2file.mp3. To avoid that, you can either use mv -i (or --interactive), which will prompt you before overwriting a file, or mv -n (or --noclobber), which will just not overwrite any files.

  • triplee points out that this needlessly moves files onto themselves if they don’t start with slash, underscore or digit. To avoid that, we can iterate only over matching files with

    for fname in [-_[:digit:]]*.mp3; do mv -- "$fname" "${fname##*([-_[:digit:]])}"; done
    

    which makes sure that there is something to rename.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement