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
--
aftermv
indicates the end of options formove
and makes sure that filenames starting with-
aren’t interpreted as options.The
*()
expression requires theextglob
shell option. As pointed out, if you don’t want extended globs later, you have to unset it again withshopt -u extglob
.As per Gordon Davisson‘s comment: this will clobber files if you have, for example, something like
1file.mp3
and2file.mp3
. To avoid that, you can either usemv -i
(or--interactive
), which will prompt you before overwriting a file, ormv -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.