I have a ton of files named this way: [name]_[phonenumber]_HH-mm-ss_dd-MM-yyyy.mp3. How can I shift [name] and [phonenumber] to the end of file name, and put the date in the beginning in form of yyyy-MM-dd_HH-mm-ss so I get yyyy-MM-dd_HH-mm-ss_[name]_[phonenumber]?

Here is an actual file name: [Unknown]_[+74999519075]_18-01-36_17-01-2014.mp3

I've tried rename, but due to lack of regexp knowledge I didn't come up with a working solution.

  • Can you give us some actual examples?
    – Oli
    Apr 29 '14 at 14:18
  • Yes, here is an actual file name: [Unknown]_[+74999519075]_18-01-36_17-01-2014.mp3
    – firun
    Apr 29 '14 at 14:35

This should work:

for i in *mp3; do rename 's/(.+?)_(.+?)_(.+?)-(.+?)-(.+?)_(.+?)-(.+?)-(.+?).mp3/$8-$7-$6_$3-$4-$5_$1_$2.mp3/' "$i"; done

The parentheses capture patterns. The 1st captured match is $1, the 2nd $2 etc. So, the command above:

  • will look for everything up to the first _
  • .+? means match the shortest pattern possible because of the ?,
  • then everything up to the 2nd _ etc.
  • and renames accordingly.

I tested it with:

$ touch [name]_[phonenumber]_HH-mm-ss_dd-MM-yyyy.mp3
$ ls
$ for i in *mp3; do rename 's/(.+?)_(.+?)_(.+?)-(.+?)-(.+?)_(.+?)-(.+?)-(.+?).mp3/$8-$7-$6_$3-$4-$5_$1_$2.mp3/' "$i"; done
$ ls

Just using your example, if we treat underscore as a reserved delimiter, you can rename them like this:

rename 's/^([^_]+)_([^_]+)_([^_]+)_(\d+)-(\d+)-(\d+)/$6-$5-$4_$3_$1_$2/' *.mp3 -vn

The -vn on the end means it'll just tell you what it would do in the real world. Remove that to make it run.

Here's my test harness using your example:

$ rename 's/^([^_]+)_([^_]+)_([^_]+)_(\d+)-(\d+)-(\d+)/$6-$5-$4_$3_$1_$2/' *.mp3 -vn
[Unknown]_[+74999519075]_18-01-36_17-01-2014.mp3 renamed as 2014-01-17_18-01-36_[Unknown]_[+74999519075].mp3

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