Remove numbers from filenames

I’ve a problem modifying the files’ names in my Music/ directory.

I have a list of names like these:

$ ls
01 American Idiot.mp3
01 Articolo 31 - Domani Smetto.mp3
01 Bohemian rapsody.mp3
01 Eye of the Tiger.mp3
04 Halo.mp3
04 Indietro.mp3
04 You Can't Hurry Love.mp3
05 Beautiful girls.mp3
16 Apologize.mp3
16 Christmas Is All Around.mp3
Adam's song.mp3
A far l'amore comincia tu.mp3
All By My Self.MP3
Always.mp3
Angel.mp3

And similar and I would like to cut all the numbers in front of the filenames (not the 3 in the extension).

I’ve tried first to grep only the files with the number with find -exec or xargs but even at this first step I had no success. After being able to grep I’d like doing the actual name change.

This is what I tried by now:

ls > try-expression
grep -E '^[0-9]+' try-expression

and with the above I got the right result. Then I tried the next step:

ls | xargs -0 grep -E '^[0-9]+'
ls | xargs -d '\n' grep -E '^[0-9]+'
find . -name '[0-9]+' -exec grep -E '^[0-9]+' {} \;
ls | parallel bash -c "grep -E '^[0-9]+'" - {}

And similar but I got error like ‘File name too long’ or no output at all. I guess the problem is the way I’m using xargs or find as expressions in separate commands work well.

Thank you for your help

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

To list all files start with number in a directory,

find . -maxdepth 1 -regextype "posix-egrep" -regex '.*/[0-9]+.*\.mp3' -type f

Problem with your approach is that the find returns a relative path of a file and you are just expecting a filename itself.

Solution 2

Here’s something you could do using only bash, with a regex in a conditional:

#! /bin/bash

# get all files that start with a number
for file in [0-9]* ; do
    # only process start start with a number
    # followed by one or more space characters
    if [[ $file =~ ^[0-9]+[[:blank:]]+(.+) ]] ; then
        # display original file name
        echo "< $file"
        # grab the rest of the filename from
        # the regex capture group
        newname="${BASH_REMATCH[1]}"
        echo "> $newname"
        # uncomment to move
        # mv "$file" "$newname"
    fi
done

When run on your sample file names, the output is:

< 01 American Idiot.mp3
> American Idiot.mp3
< 01 Articolo 31 - Domani Smetto.mp3
> Articolo 31 - Domani Smetto.mp3
< 01 Bohemian rapsody.mp3
> Bohemian rapsody.mp3
< 01 Eye of the Tiger.mp3
> Eye of the Tiger.mp3
< 04 Halo.mp3
> Halo.mp3
< 04 Indietro.mp3
> Indietro.mp3
< 04 You Can't Hurry Love.mp3
> You Can't Hurry Love.mp3
< 05 Beautiful girls.mp3
> Beautiful girls.mp3
< 16 Apologize.mp3
> Apologize.mp3
< 16 Christmas Is All Around.mp3
> Christmas Is All Around.mp3

Solution 3

On Debian, Ubuntu and derivatives, use the rename perl script.

To simulate the rename operation:

    rename 's/^\d+ //' * -n

Remove the -n (no act) to perform the operation:

    rename 's/^\d+ //' *

With a little luck perl rename is installed as /usr/bin/rename on your distribution, too (Rumour has it that Fedora also uses perl rename).

See the perl rename man page for more details on other features.

Solution 4

It’s relatively easy in zsh with zmv:

zmv '[0-9]## #(*.mp3)' '$1'

Explanation: [0-9]## # is a pattern that matches one or more digits followed by zero or more spaces. The command above renames all files that begin with this pattern and end with .mp3 to the part caught by the parentheses.

Solution 5

I just wrote a few lines in object Rexx that removes the numbers from the beginning of files. My files were like:

Data:

003. Atomic Rooster.mp3
087. Crowded House.mp3

Code:

#!/bin/rexx
'rxqueue /clear'
'ls | rxqueue'
do while queued()>0
 parse pull fn
 parse var fn .'.'rest
 rest = strip(rest)
 if pos('.',rest)=0 then iterate
 "mv '"fn"' '"rest"'"
end

Solution 6

Using PowerShell:

Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '1','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '2','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '3','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '4','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '5','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '6','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '7','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '8','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '9','' }
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace '0','' }


+Add:
if your extension name contains number
*add this in the beginning->
Get-ChildItem '*.extension_name' | Rename-Item -NewName { $_.Name -Replace 'extension_name','noextension' }
***for this after this line you you must have to use "Get-ChildItem '*.noextension'|"
*add this in the ending->
Get-ChildItem '*.noextension' | Rename-Item -NewName { $_.Name -Replace 'noextension','extension_name' }


for example "mp3"

*add this in the beginning->
Get-ChildItem '*.mp3' | Rename-Item -NewName { $_.Name -Replace 'mp3','noextension' }

*add this in the ending->
Get-ChildItem '*.noextension' | Rename-Item -NewName { $_.Name -Replace 'noextension','mp3' }

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply