Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

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:

TITLE(artist-track)-ID.mp3

So an actual filename looks like:

EPIC RAP BATTLE of MANLINESS-_EzDRpkfaO4.mp3

Some other file names in the folder look like:

EPIC RAP BATTLE of MANLINESS-_EzDRpkfaO4.mp3
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
share|improve this question
    
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 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 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 at 11:57
    
Solved already as in the accepted answer, I think I might use this if I need again :) –  Bodo Jun 12 at 11:58

5 Answers 5

up vote 0 down vote accepted

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.

share|improve this answer
    
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 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 at 15:29
    
Got it, thanks! –  Bodo Jun 11 at 15:36
    
-1, do not parse the output of ls. –  nyuszika7h Aug 13 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.

share|improve this answer
    
You could just use \. instead of [.]. –  nyuszika7h Aug 13 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).

share|improve this 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 at 15:21
    
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 at 15:36
    
Safer version: mv -- "$i" "$(basename "$i" .mp3 | cut -f 2 -d "-")".mp3. –  nyuszika7h Aug 13 at 13:53

You can check it with this command:

for i in $(ls); 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 $(ls)
do
  newname="$(echo $i|cut -d- -f1,2).mp3";
  mv $i $newname
done
share|improve this answer
    
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 at 14:36
    
You should edit your comment about cp vs mv into your answer –  chaskes Jun 11 at 14:40
    
Thanks for the note, I'll new it is 4 spaces... just have a problem counting sometimes :D –  Jakke Jun 11 at 14:44
    
-1, do not parse the output of ls. –  nyuszika7h Aug 13 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 at 14:01

A solution using only the shell:

filename=foo-bar-baz

while read -rd-; do
    newname="${newname:+$newname-}$REPLY"
done <<< "$filename"

mv "$filename" "$newname"

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

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.