I use the command line utility youtube-dl to download videos from YouTube and make mp3s from them with avconv. I'm doing this under Ubuntu 14.04 and very happy with it.

The utility downloads the files and saves them with the following name scheme:


So an actual filename looks like:


Some other file names in the folder look like:

Martin Garrix - Animals (Official Video)-gCYcHz2k5x0.mp3
Stromae - Papaoutai-oiKj0Z_Xnjc.mp3

At first, this was no problem. It didn't bother me while listening to my music in Rhytmbox. But when moving to phone or other devices it is pretty confusing to see a so long name, and some players, like the Samsung ones, treat that last part (id after second dash) of the name as Album or something.

I'd like to create a bash script that removes what's after the second dash in the name for all files, so it'll make them like this:

From: Martin Garrix - Animals (Official Video)-gCYcHz2k5x0.mp3

To: Martin Garrix - Animals (Official Video).mp3

Is it also possible to instruct youtube-dl to exclude the ID from now on?

I am currently downloading with the command:

youtube-dl --extract-audio --audio-quality 0 --audio-format mp3 URL
  • If you don't insist on a bash script, Emacs' Dired mode (specifically its variant called WDired, for "Writable Dired") would help. See here: gnu.org/software/emacs/manual/html_node/emacs/Wdired.html . In WDired, you basically edit a buffer containing an ls output, then C-c C-c to commit those changes to the filesystem. And you can use all Emacs goodies, in particular query-replace and query-replace-regexp. (And also write a short Elisp helper function to automate it, or record a keyboard macro and save it, and then even call it from the shell like a bash script!)
    – mbork
    Jun 12 '14 at 7:48
  • Ok thanks for the tip. Might be useful. I was looking for a bash script for being able to run it easily under a bunch of directories.
    – Bodo
    Jun 12 '14 at 7:55
  • This link: masteringemacs.org/articles/2011/03/25/… has some info on operating on files from multiple directories in one Dired buffer, so if you can find (as in GNU find) all your files, you could even run the replacing engine only once!
    – mbork
    Jun 12 '14 at 11:57
  • Solved already as in the accepted answer, I think I might use this if I need again :)
    – Bodo
    Jun 12 '14 at 11:58

sed can accomplish this in a single line, albeit in a rather convoluted way.

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

This first lists the files in the current directory (assuming all the files you want to rename are in the current directory), and then uses sed's s/regex/replacement command to generate a sensible mv command which is then piped to bash which executes it. This assumes all of your files are something of the form "A-C.mp3" or "A - B-C.mp3". Here is how it works:

The regex part of the sed command is


this "groups" the name into two groupings (delimited with escaped parentheses): one matching ".*" (any number of any character) and another matching "-.*", a dash followed by any number of any character. Notice that this matches the entire filename (in two groups). Also note that since "greedy" regex is used, the first group will match "A" in "A-C.mp3" and "A - B", not just "A ", in "A - B-C.mp3", as wanted.

The replacement part of the sed command is

mv \"&\" \"\1.mp3\"/

Note that an & character instructs sed to insert the entire pattern that matched regex, in this case that is the entire filename, and the \1 instructs sed to insert the part of the filename that matched the first grouping ".*". These two are combined with an preceding mv and a trailing .mp3, with escaped quotation marks to produce a sensible rename command. For example, for "A - B-C.mp3", the full sed command will produce:

mv "A - B-C.mp3" "A - B.mp3"

And finally all of this is piped to bash, which happily executes the mv (rename) command.

  • Thanks, worked perfectly (tried other methods and game me "--NAME-- is not a directory"). Is there any way to do this recursively? (I have tracks arranged in subdirectories of my Music folder.
    – Bodo
    Jun 11 '14 at 15:18
  • You should be able to accomplish this recursively by simply instructing ls to recursively list all files with their full path. Using "ls -d -1 $PWD/**/*" instead of "ls" as the first command should work, this lists all the files with their full path using the recursive globbing operator ** in all subdirectories but not the current directory, although I would recommend testing it first to see that it is sane (i.e. running the entire command without the final piping to bash). Note that bash version >= 4 is needed for support for recursive globbing.
    – icasdri
    Jun 11 '14 at 15:29
  • -1, do not parse the output of ls.
    – nyuszika7h
    Aug 13 '14 at 13:54

I would use the Perl-based rename command - for example, to remove the shortest sequence of word-characters starting with - ahead of the .mp3 suffix, you could try

rename -nv -- 's/-\w+?[.]mp3$/.mp3/' *.mp3

The n option runs the command in 'dry run' mode - if the matches appear correct, remove the n option and run it again.

  • You could just use \. instead of [.].
    – nyuszika7h
    Aug 13 '14 at 13:55

The part you don't want is the video id. You can use youtube-dl's output template functionality:

--output "%(title)s"

this will use only the title and omit the id. Run youtube-dl with no parameters to see other options.

You can fix your existing downloads:

for i in *; do mv "$i" `basename "$i" .mp3 | cut -f -2 -d "-"`.mp3; done

(This is equivalent to Jakke's answer).

  • Thanks for the first command (to manipulate the output filename). I'd upvote if I could but don't have enough rep yet (I'll come back and upvote when I'll have). Not gave it accepted answer because the second command threw up "--NAME-- is not a directory" for every track. For fixing already downloaded @icasdri's answer worked. Again, thanks for the youtube-dl argument thingie.
    – Bodo
    Jun 11 '14 at 15:21
  • 1
    Coming back to correct something, I need to change "%(title)s" to "%(title)s.%(ext)s" because it was complaining about audio and video having the same name and not being able to convert. Cheers!
    – Bodo
    Jun 11 '14 at 15:36
  • Safer version: mv -- "$i" "$(basename "$i" .mp3 | cut -f 2 -d "-")".mp3.
    – nyuszika7h
    Aug 13 '14 at 13:53

You can check it with this command:

for i in *.mp3; do echo "$(echo $i|cut -d- -f1,2).mp3"; done

Note that you do have file names without 2 dashes, so it won't work for everything.

If you actually want to change the names,

for i in *.mp3
  newname="$(echo $i|cut -d- -f1,2).mp3";
  mv $i $newname
  • If you want to play it safe, do a cp instead of a mv. It will leave you with the original files, but you'll probably have to remove them manually later
    – Jakke
    Jun 11 '14 at 14:36
  • You should edit your comment about cp vs mv into your answer
    – chaskes
    Jun 11 '14 at 14:40
  • Thanks for the note, I'll new it is 4 spaces... just have a problem counting sometimes :D
    – Jakke
    Jun 11 '14 at 14:44
  • -1, do not parse the output of ls.
    – nyuszika7h
    Aug 13 '14 at 13:52
  • You should also double quote every variable expansion and command substitution. And don't use echo for anything other than plain text, it's unportable.
    – nyuszika7h
    Aug 13 '14 at 14:01

A solution using only the shell:


while read -rd-; do
done <<< "$filename"

mv "$filename" "$newname"

This works because the file name doesn't end with a dash, so the last token is ignored.

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.