I have thousands of .mp3 files that have recently been required and were appended with a dash - and a series of various amounts of numbers. I would like to remove the last dash and the numbers to right of it.

Some examples are:


What I would like is:


I have tried this:

ls | sed 's/\(.*\)\(-.*\)/mv \"&\" \"\1.mp3\"/' | bash

But, I've been getting a

syntax error near unexpected token '('

I've tried escaping any / but that wasn't much help either. I have all these songs in one folder. And another folder with .wav files.

Thanks for taking the time and reading!


I think this shoud do it:

for f in *.mp3; do
  echo "Moving $f to ${f%-[0-9]*}.mp3"
  # below the action commented
  # mv "$f" "${f%-[0-9]*}.mp3"


moving songName(1973)-artistName-12345.mp3 to songName(1973)-artistName.mp3
moving songName-artistName-12345.mp3 to songName-artistName.mp3
moving songName-artistName12d-12345.mp3 to songName-artistName12d.mp3
  • while this is a valid solution, it does not answer the OP's question for why his does not work. – JayEye May 7 '20 at 18:03
  • @JayEye that's right, but I Ieft a comment on why you should not parse the output of ls. – schrodigerscatcuriosity May 7 '20 at 18:11

Not an Ubuntu-specific question, but anyway:

Recall that the shell still expands metacharacters inside double-quoted strings. In all likelihood, some filenames may contain shell metacharacters, such as $, which mess up the output, possibly compounded with some interaction of the locale and how ls likes to put filenames with non-alphanumeric characters in quotes (although it should not do that when the output is a pipe). Try using single quotes for your output, and enclosing the sed arguments in double quotes instead. For good measure, reset the locale to something neutral and use ls -N:

$ export LC_ALL=C
$ ls -N | sed "s/\(.*\)\(-.*\)/mv \'&\' \'\1.mp3\'/" |bash

Just in case you have different versions:

$ sed --version
sed (GNU sed) 4.4

$ bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

You need to make that middle match non-greedy or it will eat your artist name:

$ printf %s\\0 *.mp3 | \
  sed -znr 's|(.*)-[^-].*\.mp3$|mv \"&\" \"\1\.mp3\"|e'

However, rename will be much faster:

$ printf %s\\0 *.mp3 | \
  rename --null 's/(.*)-.*?\.mp3$/$1\.mp3/'

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.