remove first characters if its “0” from all files

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
1
down vote

favorite
2












i have few folder:



1
2
3
4
5


so in each folder i have files like



00123.mp3
00133.mp3
00150.mp3


so i want to remove all 0 if they are at beginning of filename



i tried this



for file in *; do echo mv "$file" "$file//[ ()@0]/"; done


but it remove all 0 in begenning and inside filename (i need just in begining)
also this is not working in subdirectory







share|improve this question
















  • 2




    Which shell are you using? bash with shell option extglob enabled supports "$file##+(0)" to remove a leading sequence of one or more 0s I think
    – steeldriver
    Feb 7 at 21:17






  • 1




    Note that it doesn't work in subdirectories because the asterisk wildcard is not recursive - it will always match items in the specified directory only. This is one thing all shells I'm aware of agree on. If you want to go into subdirectories, you need to figure out (and possibly enable) your shell's equivalent of globstar - likely some variation on **.
    – brhfl
    Feb 7 at 21:24














up vote
1
down vote

favorite
2












i have few folder:



1
2
3
4
5


so in each folder i have files like



00123.mp3
00133.mp3
00150.mp3


so i want to remove all 0 if they are at beginning of filename



i tried this



for file in *; do echo mv "$file" "$file//[ ()@0]/"; done


but it remove all 0 in begenning and inside filename (i need just in begining)
also this is not working in subdirectory







share|improve this question
















  • 2




    Which shell are you using? bash with shell option extglob enabled supports "$file##+(0)" to remove a leading sequence of one or more 0s I think
    – steeldriver
    Feb 7 at 21:17






  • 1




    Note that it doesn't work in subdirectories because the asterisk wildcard is not recursive - it will always match items in the specified directory only. This is one thing all shells I'm aware of agree on. If you want to go into subdirectories, you need to figure out (and possibly enable) your shell's equivalent of globstar - likely some variation on **.
    – brhfl
    Feb 7 at 21:24












up vote
1
down vote

favorite
2









up vote
1
down vote

favorite
2






2





i have few folder:



1
2
3
4
5


so in each folder i have files like



00123.mp3
00133.mp3
00150.mp3


so i want to remove all 0 if they are at beginning of filename



i tried this



for file in *; do echo mv "$file" "$file//[ ()@0]/"; done


but it remove all 0 in begenning and inside filename (i need just in begining)
also this is not working in subdirectory







share|improve this question












i have few folder:



1
2
3
4
5


so in each folder i have files like



00123.mp3
00133.mp3
00150.mp3


so i want to remove all 0 if they are at beginning of filename



i tried this



for file in *; do echo mv "$file" "$file//[ ()@0]/"; done


but it remove all 0 in begenning and inside filename (i need just in begining)
also this is not working in subdirectory









share|improve this question











share|improve this question




share|improve this question










asked Feb 7 at 20:33









arlind

82




82







  • 2




    Which shell are you using? bash with shell option extglob enabled supports "$file##+(0)" to remove a leading sequence of one or more 0s I think
    – steeldriver
    Feb 7 at 21:17






  • 1




    Note that it doesn't work in subdirectories because the asterisk wildcard is not recursive - it will always match items in the specified directory only. This is one thing all shells I'm aware of agree on. If you want to go into subdirectories, you need to figure out (and possibly enable) your shell's equivalent of globstar - likely some variation on **.
    – brhfl
    Feb 7 at 21:24












  • 2




    Which shell are you using? bash with shell option extglob enabled supports "$file##+(0)" to remove a leading sequence of one or more 0s I think
    – steeldriver
    Feb 7 at 21:17






  • 1




    Note that it doesn't work in subdirectories because the asterisk wildcard is not recursive - it will always match items in the specified directory only. This is one thing all shells I'm aware of agree on. If you want to go into subdirectories, you need to figure out (and possibly enable) your shell's equivalent of globstar - likely some variation on **.
    – brhfl
    Feb 7 at 21:24







2




2




Which shell are you using? bash with shell option extglob enabled supports "$file##+(0)" to remove a leading sequence of one or more 0s I think
– steeldriver
Feb 7 at 21:17




Which shell are you using? bash with shell option extglob enabled supports "$file##+(0)" to remove a leading sequence of one or more 0s I think
– steeldriver
Feb 7 at 21:17




1




1




Note that it doesn't work in subdirectories because the asterisk wildcard is not recursive - it will always match items in the specified directory only. This is one thing all shells I'm aware of agree on. If you want to go into subdirectories, you need to figure out (and possibly enable) your shell's equivalent of globstar - likely some variation on **.
– brhfl
Feb 7 at 21:24




Note that it doesn't work in subdirectories because the asterisk wildcard is not recursive - it will always match items in the specified directory only. This is one thing all shells I'm aware of agree on. If you want to go into subdirectories, you need to figure out (and possibly enable) your shell's equivalent of globstar - likely some variation on **.
– brhfl
Feb 7 at 21:24










3 Answers
3






active

oldest

votes

















up vote
2
down vote



accepted










If you are using bash, this script will do what you ask for:



#!/bin/bash
shopt -s extglob
while IFS= read -d '' f ; do
file=$f##*/
dir="$f%/*/"
echo
mv "$dir$file" "$dir$file##+(0)"
done < <(find . -type f -name '0*.mp3' -print0)


comment the echo line to actually perform the mv command(s) once you agree with the list of files to move.



Or this sh version for portability:



#!/bin/sh

find . -type f -name '0*.mp3' -print |
while IFS= read f; do
file=$f##*/
dir="$f%/*/"
f2=$file; until [ "$f2" = "$f2#0" ]; do f2=$f2#0; done
echo
mv "$f" "$dir$f2"
done





share|improve this answer






















  • Note that mv inherits the stdin of the loop, so the pipe from find. -i would cause it to read the answer to confirmation prompts from the output of find. You could read the output of find on another fd (read <&3... done 3< <(find...). Or use mv -i < /dev/tty...
    – Stéphane Chazelas
    Feb 8 at 0:15











  • @StéphaneChazelas Can not get the mv -i to work, just removed it.
    – Isaac
    Feb 8 at 1:56

















up vote
2
down vote













Since your question is tagged Linux, you could use rename or prename command (note that prename is not deprecated, though, but still works). In either case they're perl script for pattern-based renaming.



With group matching and using *.mp3 glob to pass only .mp3 files, you can do this:



$ prename -nv 's/(^0*)(.*).mp3/$2.mp3/' *.mp3
Deprecated program in use: rename as shipped with the Debian perl package will be removed after the release of stretch. Please install the separate 'rename' package which will provide the same command.
000004500.mp3 renamed as 4500.mp3
00123.mp3 renamed as 123.mp3
00133.mp3 renamed as 133.mp3
00150.mp3 renamed as 150.mp3


Note that -n and -v are for dry run and verbose output; testing only. Remove -n for actual renaming to take effect.



In case you are confused about rename vs prename , you can read the corresponding answer that clears up the confusion, but...I would recommend that you just don't bother with that. Too convoluted :) The point is that in either case it works as shown, unless you're using ksh shell.




Recursive way to rename files in subfolders would be via find, however that requires a bit of acrobatics with substitution pattern to handle preceding items in the file path as provided by find.



find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ;


The above command performed as follows in a test case:



$ find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ; 2>/dev/null
./testdir/000004500.mp3 renamed as ./testdir/4500.mp3
./testdir/00150.mp3 renamed as ./testdir/150.mp3
./testdir/00133.mp3 renamed as ./testdir/133.mp3
./testdir/00123.mp3 renamed as ./testdir/123.mp3


Minor improvement could be to specify d, the digit class:



find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's//0*(d*.mp3)//$1/' ;


Stéphane Chazelas mentioned in the comments possibility where /0/1.mp3 could be accidentally rename to .//1.mp3. I've taken couple test cases; ./testdir/0/000987.mp3 renamed as ./testdir/0/987.mp3 and ./testdir/007/00123.mp3 renamed as ./testdir/007/123.mp3 were the results. I think greedy matching of 0* does the trick.
He also suggested in the comments adding [^/] in filename pattern matching. This is a good idea since Unix filenames cannot have backslashes in them; paths can but not individual files. However, I am not quite sure how to better implement this and still have no suggestion on matching 0.mp3 or 000.mp3 types of filenames.






share|improve this answer






















  • The recursive one won't work because ^0 will never match because the paths start with ./.
    – Stéphane Chazelas
    Feb 8 at 0:12










  • @StéphaneChazelas Thank you, I entirely forgot about that. Will try to correct it
    – Sergiy Kolodyazhnyy
    Feb 8 at 0:16










  • @StéphaneChazelas Edited the answer. Please review.
    – Sergiy Kolodyazhnyy
    Feb 8 at 0:24










  • There's a risk it could rename things like ./0/1.mp3 to .//1.mp3 (or ./0.mp3 to ./mp3, see my answer). You may want something like s/0*([0-9][^/]*.mp3)z$2 (untested)
    – Stéphane Chazelas
    Feb 8 at 0:29











  • The greedy .* at the start will effectively force a match on the rightmost possible position, without it, it would take the leftmost. But I suppose you could sidestep the whole issue of accidentally matching the path by using -execdir instead of -exec.
    – ilkkachu
    Feb 8 at 8:46

















up vote
1
down vote













With zsh:



autoload zmv # best in ~/.zshrc
zmv -n '0#(*.mp3)' '$1'


(remove -n (dry-run) when happy).



The # glob operator in zsh is like the * regular expression operator.



Note that it would rename 0000.mp3 to .mp3. To avoid that you can change it do:



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


Recursively:



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


To also remove the () @ characters as your example suggests you may want to do:



zmv -n '(**/)0#([0-9]*.mp3)' '$1$2//[() @]'


(It would however not remove those characters from file names that don't start with a digit).






share|improve this answer






















    Your Answer







    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "106"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f422644%2fremove-first-characters-if-its-0-from-all-files%23new-answer', 'question_page');

    );

    Post as a guest






























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    If you are using bash, this script will do what you ask for:



    #!/bin/bash
    shopt -s extglob
    while IFS= read -d '' f ; do
    file=$f##*/
    dir="$f%/*/"
    echo
    mv "$dir$file" "$dir$file##+(0)"
    done < <(find . -type f -name '0*.mp3' -print0)


    comment the echo line to actually perform the mv command(s) once you agree with the list of files to move.



    Or this sh version for portability:



    #!/bin/sh

    find . -type f -name '0*.mp3' -print |
    while IFS= read f; do
    file=$f##*/
    dir="$f%/*/"
    f2=$file; until [ "$f2" = "$f2#0" ]; do f2=$f2#0; done
    echo
    mv "$f" "$dir$f2"
    done





    share|improve this answer






















    • Note that mv inherits the stdin of the loop, so the pipe from find. -i would cause it to read the answer to confirmation prompts from the output of find. You could read the output of find on another fd (read <&3... done 3< <(find...). Or use mv -i < /dev/tty...
      – Stéphane Chazelas
      Feb 8 at 0:15











    • @StéphaneChazelas Can not get the mv -i to work, just removed it.
      – Isaac
      Feb 8 at 1:56














    up vote
    2
    down vote



    accepted










    If you are using bash, this script will do what you ask for:



    #!/bin/bash
    shopt -s extglob
    while IFS= read -d '' f ; do
    file=$f##*/
    dir="$f%/*/"
    echo
    mv "$dir$file" "$dir$file##+(0)"
    done < <(find . -type f -name '0*.mp3' -print0)


    comment the echo line to actually perform the mv command(s) once you agree with the list of files to move.



    Or this sh version for portability:



    #!/bin/sh

    find . -type f -name '0*.mp3' -print |
    while IFS= read f; do
    file=$f##*/
    dir="$f%/*/"
    f2=$file; until [ "$f2" = "$f2#0" ]; do f2=$f2#0; done
    echo
    mv "$f" "$dir$f2"
    done





    share|improve this answer






















    • Note that mv inherits the stdin of the loop, so the pipe from find. -i would cause it to read the answer to confirmation prompts from the output of find. You could read the output of find on another fd (read <&3... done 3< <(find...). Or use mv -i < /dev/tty...
      – Stéphane Chazelas
      Feb 8 at 0:15











    • @StéphaneChazelas Can not get the mv -i to work, just removed it.
      – Isaac
      Feb 8 at 1:56












    up vote
    2
    down vote



    accepted







    up vote
    2
    down vote



    accepted






    If you are using bash, this script will do what you ask for:



    #!/bin/bash
    shopt -s extglob
    while IFS= read -d '' f ; do
    file=$f##*/
    dir="$f%/*/"
    echo
    mv "$dir$file" "$dir$file##+(0)"
    done < <(find . -type f -name '0*.mp3' -print0)


    comment the echo line to actually perform the mv command(s) once you agree with the list of files to move.



    Or this sh version for portability:



    #!/bin/sh

    find . -type f -name '0*.mp3' -print |
    while IFS= read f; do
    file=$f##*/
    dir="$f%/*/"
    f2=$file; until [ "$f2" = "$f2#0" ]; do f2=$f2#0; done
    echo
    mv "$f" "$dir$f2"
    done





    share|improve this answer














    If you are using bash, this script will do what you ask for:



    #!/bin/bash
    shopt -s extglob
    while IFS= read -d '' f ; do
    file=$f##*/
    dir="$f%/*/"
    echo
    mv "$dir$file" "$dir$file##+(0)"
    done < <(find . -type f -name '0*.mp3' -print0)


    comment the echo line to actually perform the mv command(s) once you agree with the list of files to move.



    Or this sh version for portability:



    #!/bin/sh

    find . -type f -name '0*.mp3' -print |
    while IFS= read f; do
    file=$f##*/
    dir="$f%/*/"
    f2=$file; until [ "$f2" = "$f2#0" ]; do f2=$f2#0; done
    echo
    mv "$f" "$dir$f2"
    done






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 8 at 1:51

























    answered Feb 7 at 23:31









    Isaac

    6,6381734




    6,6381734











    • Note that mv inherits the stdin of the loop, so the pipe from find. -i would cause it to read the answer to confirmation prompts from the output of find. You could read the output of find on another fd (read <&3... done 3< <(find...). Or use mv -i < /dev/tty...
      – Stéphane Chazelas
      Feb 8 at 0:15











    • @StéphaneChazelas Can not get the mv -i to work, just removed it.
      – Isaac
      Feb 8 at 1:56
















    • Note that mv inherits the stdin of the loop, so the pipe from find. -i would cause it to read the answer to confirmation prompts from the output of find. You could read the output of find on another fd (read <&3... done 3< <(find...). Or use mv -i < /dev/tty...
      – Stéphane Chazelas
      Feb 8 at 0:15











    • @StéphaneChazelas Can not get the mv -i to work, just removed it.
      – Isaac
      Feb 8 at 1:56















    Note that mv inherits the stdin of the loop, so the pipe from find. -i would cause it to read the answer to confirmation prompts from the output of find. You could read the output of find on another fd (read <&3... done 3< <(find...). Or use mv -i < /dev/tty...
    – Stéphane Chazelas
    Feb 8 at 0:15





    Note that mv inherits the stdin of the loop, so the pipe from find. -i would cause it to read the answer to confirmation prompts from the output of find. You could read the output of find on another fd (read <&3... done 3< <(find...). Or use mv -i < /dev/tty...
    – Stéphane Chazelas
    Feb 8 at 0:15













    @StéphaneChazelas Can not get the mv -i to work, just removed it.
    – Isaac
    Feb 8 at 1:56




    @StéphaneChazelas Can not get the mv -i to work, just removed it.
    – Isaac
    Feb 8 at 1:56












    up vote
    2
    down vote













    Since your question is tagged Linux, you could use rename or prename command (note that prename is not deprecated, though, but still works). In either case they're perl script for pattern-based renaming.



    With group matching and using *.mp3 glob to pass only .mp3 files, you can do this:



    $ prename -nv 's/(^0*)(.*).mp3/$2.mp3/' *.mp3
    Deprecated program in use: rename as shipped with the Debian perl package will be removed after the release of stretch. Please install the separate 'rename' package which will provide the same command.
    000004500.mp3 renamed as 4500.mp3
    00123.mp3 renamed as 123.mp3
    00133.mp3 renamed as 133.mp3
    00150.mp3 renamed as 150.mp3


    Note that -n and -v are for dry run and verbose output; testing only. Remove -n for actual renaming to take effect.



    In case you are confused about rename vs prename , you can read the corresponding answer that clears up the confusion, but...I would recommend that you just don't bother with that. Too convoluted :) The point is that in either case it works as shown, unless you're using ksh shell.




    Recursive way to rename files in subfolders would be via find, however that requires a bit of acrobatics with substitution pattern to handle preceding items in the file path as provided by find.



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ;


    The above command performed as follows in a test case:



    $ find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ; 2>/dev/null
    ./testdir/000004500.mp3 renamed as ./testdir/4500.mp3
    ./testdir/00150.mp3 renamed as ./testdir/150.mp3
    ./testdir/00133.mp3 renamed as ./testdir/133.mp3
    ./testdir/00123.mp3 renamed as ./testdir/123.mp3


    Minor improvement could be to specify d, the digit class:



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's//0*(d*.mp3)//$1/' ;


    Stéphane Chazelas mentioned in the comments possibility where /0/1.mp3 could be accidentally rename to .//1.mp3. I've taken couple test cases; ./testdir/0/000987.mp3 renamed as ./testdir/0/987.mp3 and ./testdir/007/00123.mp3 renamed as ./testdir/007/123.mp3 were the results. I think greedy matching of 0* does the trick.
    He also suggested in the comments adding [^/] in filename pattern matching. This is a good idea since Unix filenames cannot have backslashes in them; paths can but not individual files. However, I am not quite sure how to better implement this and still have no suggestion on matching 0.mp3 or 000.mp3 types of filenames.






    share|improve this answer






















    • The recursive one won't work because ^0 will never match because the paths start with ./.
      – Stéphane Chazelas
      Feb 8 at 0:12










    • @StéphaneChazelas Thank you, I entirely forgot about that. Will try to correct it
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:16










    • @StéphaneChazelas Edited the answer. Please review.
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:24










    • There's a risk it could rename things like ./0/1.mp3 to .//1.mp3 (or ./0.mp3 to ./mp3, see my answer). You may want something like s/0*([0-9][^/]*.mp3)z$2 (untested)
      – Stéphane Chazelas
      Feb 8 at 0:29











    • The greedy .* at the start will effectively force a match on the rightmost possible position, without it, it would take the leftmost. But I suppose you could sidestep the whole issue of accidentally matching the path by using -execdir instead of -exec.
      – ilkkachu
      Feb 8 at 8:46














    up vote
    2
    down vote













    Since your question is tagged Linux, you could use rename or prename command (note that prename is not deprecated, though, but still works). In either case they're perl script for pattern-based renaming.



    With group matching and using *.mp3 glob to pass only .mp3 files, you can do this:



    $ prename -nv 's/(^0*)(.*).mp3/$2.mp3/' *.mp3
    Deprecated program in use: rename as shipped with the Debian perl package will be removed after the release of stretch. Please install the separate 'rename' package which will provide the same command.
    000004500.mp3 renamed as 4500.mp3
    00123.mp3 renamed as 123.mp3
    00133.mp3 renamed as 133.mp3
    00150.mp3 renamed as 150.mp3


    Note that -n and -v are for dry run and verbose output; testing only. Remove -n for actual renaming to take effect.



    In case you are confused about rename vs prename , you can read the corresponding answer that clears up the confusion, but...I would recommend that you just don't bother with that. Too convoluted :) The point is that in either case it works as shown, unless you're using ksh shell.




    Recursive way to rename files in subfolders would be via find, however that requires a bit of acrobatics with substitution pattern to handle preceding items in the file path as provided by find.



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ;


    The above command performed as follows in a test case:



    $ find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ; 2>/dev/null
    ./testdir/000004500.mp3 renamed as ./testdir/4500.mp3
    ./testdir/00150.mp3 renamed as ./testdir/150.mp3
    ./testdir/00133.mp3 renamed as ./testdir/133.mp3
    ./testdir/00123.mp3 renamed as ./testdir/123.mp3


    Minor improvement could be to specify d, the digit class:



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's//0*(d*.mp3)//$1/' ;


    Stéphane Chazelas mentioned in the comments possibility where /0/1.mp3 could be accidentally rename to .//1.mp3. I've taken couple test cases; ./testdir/0/000987.mp3 renamed as ./testdir/0/987.mp3 and ./testdir/007/00123.mp3 renamed as ./testdir/007/123.mp3 were the results. I think greedy matching of 0* does the trick.
    He also suggested in the comments adding [^/] in filename pattern matching. This is a good idea since Unix filenames cannot have backslashes in them; paths can but not individual files. However, I am not quite sure how to better implement this and still have no suggestion on matching 0.mp3 or 000.mp3 types of filenames.






    share|improve this answer






















    • The recursive one won't work because ^0 will never match because the paths start with ./.
      – Stéphane Chazelas
      Feb 8 at 0:12










    • @StéphaneChazelas Thank you, I entirely forgot about that. Will try to correct it
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:16










    • @StéphaneChazelas Edited the answer. Please review.
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:24










    • There's a risk it could rename things like ./0/1.mp3 to .//1.mp3 (or ./0.mp3 to ./mp3, see my answer). You may want something like s/0*([0-9][^/]*.mp3)z$2 (untested)
      – Stéphane Chazelas
      Feb 8 at 0:29











    • The greedy .* at the start will effectively force a match on the rightmost possible position, without it, it would take the leftmost. But I suppose you could sidestep the whole issue of accidentally matching the path by using -execdir instead of -exec.
      – ilkkachu
      Feb 8 at 8:46












    up vote
    2
    down vote










    up vote
    2
    down vote









    Since your question is tagged Linux, you could use rename or prename command (note that prename is not deprecated, though, but still works). In either case they're perl script for pattern-based renaming.



    With group matching and using *.mp3 glob to pass only .mp3 files, you can do this:



    $ prename -nv 's/(^0*)(.*).mp3/$2.mp3/' *.mp3
    Deprecated program in use: rename as shipped with the Debian perl package will be removed after the release of stretch. Please install the separate 'rename' package which will provide the same command.
    000004500.mp3 renamed as 4500.mp3
    00123.mp3 renamed as 123.mp3
    00133.mp3 renamed as 133.mp3
    00150.mp3 renamed as 150.mp3


    Note that -n and -v are for dry run and verbose output; testing only. Remove -n for actual renaming to take effect.



    In case you are confused about rename vs prename , you can read the corresponding answer that clears up the confusion, but...I would recommend that you just don't bother with that. Too convoluted :) The point is that in either case it works as shown, unless you're using ksh shell.




    Recursive way to rename files in subfolders would be via find, however that requires a bit of acrobatics with substitution pattern to handle preceding items in the file path as provided by find.



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ;


    The above command performed as follows in a test case:



    $ find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ; 2>/dev/null
    ./testdir/000004500.mp3 renamed as ./testdir/4500.mp3
    ./testdir/00150.mp3 renamed as ./testdir/150.mp3
    ./testdir/00133.mp3 renamed as ./testdir/133.mp3
    ./testdir/00123.mp3 renamed as ./testdir/123.mp3


    Minor improvement could be to specify d, the digit class:



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's//0*(d*.mp3)//$1/' ;


    Stéphane Chazelas mentioned in the comments possibility where /0/1.mp3 could be accidentally rename to .//1.mp3. I've taken couple test cases; ./testdir/0/000987.mp3 renamed as ./testdir/0/987.mp3 and ./testdir/007/00123.mp3 renamed as ./testdir/007/123.mp3 were the results. I think greedy matching of 0* does the trick.
    He also suggested in the comments adding [^/] in filename pattern matching. This is a good idea since Unix filenames cannot have backslashes in them; paths can but not individual files. However, I am not quite sure how to better implement this and still have no suggestion on matching 0.mp3 or 000.mp3 types of filenames.






    share|improve this answer














    Since your question is tagged Linux, you could use rename or prename command (note that prename is not deprecated, though, but still works). In either case they're perl script for pattern-based renaming.



    With group matching and using *.mp3 glob to pass only .mp3 files, you can do this:



    $ prename -nv 's/(^0*)(.*).mp3/$2.mp3/' *.mp3
    Deprecated program in use: rename as shipped with the Debian perl package will be removed after the release of stretch. Please install the separate 'rename' package which will provide the same command.
    000004500.mp3 renamed as 4500.mp3
    00123.mp3 renamed as 123.mp3
    00133.mp3 renamed as 133.mp3
    00150.mp3 renamed as 150.mp3


    Note that -n and -v are for dry run and verbose output; testing only. Remove -n for actual renaming to take effect.



    In case you are confused about rename vs prename , you can read the corresponding answer that clears up the confusion, but...I would recommend that you just don't bother with that. Too convoluted :) The point is that in either case it works as shown, unless you're using ksh shell.




    Recursive way to rename files in subfolders would be via find, however that requires a bit of acrobatics with substitution pattern to handle preceding items in the file path as provided by find.



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ;


    The above command performed as follows in a test case:



    $ find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's/(.*)(/0*)(.*).mp3/$1/$3.mp3/' ; 2>/dev/null
    ./testdir/000004500.mp3 renamed as ./testdir/4500.mp3
    ./testdir/00150.mp3 renamed as ./testdir/150.mp3
    ./testdir/00133.mp3 renamed as ./testdir/133.mp3
    ./testdir/00123.mp3 renamed as ./testdir/123.mp3


    Minor improvement could be to specify d, the digit class:



    find ./testdir/ -type f -name "*.mp3" -exec prename -nv 's//0*(d*.mp3)//$1/' ;


    Stéphane Chazelas mentioned in the comments possibility where /0/1.mp3 could be accidentally rename to .//1.mp3. I've taken couple test cases; ./testdir/0/000987.mp3 renamed as ./testdir/0/987.mp3 and ./testdir/007/00123.mp3 renamed as ./testdir/007/123.mp3 were the results. I think greedy matching of 0* does the trick.
    He also suggested in the comments adding [^/] in filename pattern matching. This is a good idea since Unix filenames cannot have backslashes in them; paths can but not individual files. However, I am not quite sure how to better implement this and still have no suggestion on matching 0.mp3 or 000.mp3 types of filenames.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 8 at 3:16

























    answered Feb 7 at 20:51









    Sergiy Kolodyazhnyy

    7,63311547




    7,63311547











    • The recursive one won't work because ^0 will never match because the paths start with ./.
      – Stéphane Chazelas
      Feb 8 at 0:12










    • @StéphaneChazelas Thank you, I entirely forgot about that. Will try to correct it
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:16










    • @StéphaneChazelas Edited the answer. Please review.
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:24










    • There's a risk it could rename things like ./0/1.mp3 to .//1.mp3 (or ./0.mp3 to ./mp3, see my answer). You may want something like s/0*([0-9][^/]*.mp3)z$2 (untested)
      – Stéphane Chazelas
      Feb 8 at 0:29











    • The greedy .* at the start will effectively force a match on the rightmost possible position, without it, it would take the leftmost. But I suppose you could sidestep the whole issue of accidentally matching the path by using -execdir instead of -exec.
      – ilkkachu
      Feb 8 at 8:46
















    • The recursive one won't work because ^0 will never match because the paths start with ./.
      – Stéphane Chazelas
      Feb 8 at 0:12










    • @StéphaneChazelas Thank you, I entirely forgot about that. Will try to correct it
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:16










    • @StéphaneChazelas Edited the answer. Please review.
      – Sergiy Kolodyazhnyy
      Feb 8 at 0:24










    • There's a risk it could rename things like ./0/1.mp3 to .//1.mp3 (or ./0.mp3 to ./mp3, see my answer). You may want something like s/0*([0-9][^/]*.mp3)z$2 (untested)
      – Stéphane Chazelas
      Feb 8 at 0:29











    • The greedy .* at the start will effectively force a match on the rightmost possible position, without it, it would take the leftmost. But I suppose you could sidestep the whole issue of accidentally matching the path by using -execdir instead of -exec.
      – ilkkachu
      Feb 8 at 8:46















    The recursive one won't work because ^0 will never match because the paths start with ./.
    – Stéphane Chazelas
    Feb 8 at 0:12




    The recursive one won't work because ^0 will never match because the paths start with ./.
    – Stéphane Chazelas
    Feb 8 at 0:12












    @StéphaneChazelas Thank you, I entirely forgot about that. Will try to correct it
    – Sergiy Kolodyazhnyy
    Feb 8 at 0:16




    @StéphaneChazelas Thank you, I entirely forgot about that. Will try to correct it
    – Sergiy Kolodyazhnyy
    Feb 8 at 0:16












    @StéphaneChazelas Edited the answer. Please review.
    – Sergiy Kolodyazhnyy
    Feb 8 at 0:24




    @StéphaneChazelas Edited the answer. Please review.
    – Sergiy Kolodyazhnyy
    Feb 8 at 0:24












    There's a risk it could rename things like ./0/1.mp3 to .//1.mp3 (or ./0.mp3 to ./mp3, see my answer). You may want something like s/0*([0-9][^/]*.mp3)z$2 (untested)
    – Stéphane Chazelas
    Feb 8 at 0:29





    There's a risk it could rename things like ./0/1.mp3 to .//1.mp3 (or ./0.mp3 to ./mp3, see my answer). You may want something like s/0*([0-9][^/]*.mp3)z$2 (untested)
    – Stéphane Chazelas
    Feb 8 at 0:29













    The greedy .* at the start will effectively force a match on the rightmost possible position, without it, it would take the leftmost. But I suppose you could sidestep the whole issue of accidentally matching the path by using -execdir instead of -exec.
    – ilkkachu
    Feb 8 at 8:46




    The greedy .* at the start will effectively force a match on the rightmost possible position, without it, it would take the leftmost. But I suppose you could sidestep the whole issue of accidentally matching the path by using -execdir instead of -exec.
    – ilkkachu
    Feb 8 at 8:46










    up vote
    1
    down vote













    With zsh:



    autoload zmv # best in ~/.zshrc
    zmv -n '0#(*.mp3)' '$1'


    (remove -n (dry-run) when happy).



    The # glob operator in zsh is like the * regular expression operator.



    Note that it would rename 0000.mp3 to .mp3. To avoid that you can change it do:



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


    Recursively:



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


    To also remove the () @ characters as your example suggests you may want to do:



    zmv -n '(**/)0#([0-9]*.mp3)' '$1$2//[() @]'


    (It would however not remove those characters from file names that don't start with a digit).






    share|improve this answer


























      up vote
      1
      down vote













      With zsh:



      autoload zmv # best in ~/.zshrc
      zmv -n '0#(*.mp3)' '$1'


      (remove -n (dry-run) when happy).



      The # glob operator in zsh is like the * regular expression operator.



      Note that it would rename 0000.mp3 to .mp3. To avoid that you can change it do:



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


      Recursively:



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


      To also remove the () @ characters as your example suggests you may want to do:



      zmv -n '(**/)0#([0-9]*.mp3)' '$1$2//[() @]'


      (It would however not remove those characters from file names that don't start with a digit).






      share|improve this answer
























        up vote
        1
        down vote










        up vote
        1
        down vote









        With zsh:



        autoload zmv # best in ~/.zshrc
        zmv -n '0#(*.mp3)' '$1'


        (remove -n (dry-run) when happy).



        The # glob operator in zsh is like the * regular expression operator.



        Note that it would rename 0000.mp3 to .mp3. To avoid that you can change it do:



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


        Recursively:



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


        To also remove the () @ characters as your example suggests you may want to do:



        zmv -n '(**/)0#([0-9]*.mp3)' '$1$2//[() @]'


        (It would however not remove those characters from file names that don't start with a digit).






        share|improve this answer














        With zsh:



        autoload zmv # best in ~/.zshrc
        zmv -n '0#(*.mp3)' '$1'


        (remove -n (dry-run) when happy).



        The # glob operator in zsh is like the * regular expression operator.



        Note that it would rename 0000.mp3 to .mp3. To avoid that you can change it do:



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


        Recursively:



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


        To also remove the () @ characters as your example suggests you may want to do:



        zmv -n '(**/)0#([0-9]*.mp3)' '$1$2//[() @]'


        (It would however not remove those characters from file names that don't start with a digit).







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Feb 8 at 0:20

























        answered Feb 8 at 0:08









        Stéphane Chazelas

        281k53516847




        281k53516847






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f422644%2fremove-first-characters-if-its-0-from-all-files%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Bahrain

            Postfix configuration issue with fips on centos 7; mailgun relay