Can anyone explain to me how this script works?

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











up vote
0
down vote

favorite
1












I was looking for a script that changes the filename and directory name to lowercase and replaces any white spaces with "-". I managed to find the script below inside another script but I do not fully understand how it works. I would really appreciate it if someone could walk me through it.



find ./* -depth -type d -exec sh -c '
t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' ;






share|improve this question


















  • 1




    Which bits do you understand?
    – bu5hman
    Feb 1 at 17:05










  • I understand "find ./* -depth -type d" and "tr "[:upper:]" "[:lower:]"
    – Alex
    Feb 1 at 17:49














up vote
0
down vote

favorite
1












I was looking for a script that changes the filename and directory name to lowercase and replaces any white spaces with "-". I managed to find the script below inside another script but I do not fully understand how it works. I would really appreciate it if someone could walk me through it.



find ./* -depth -type d -exec sh -c '
t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' ;






share|improve this question


















  • 1




    Which bits do you understand?
    – bu5hman
    Feb 1 at 17:05










  • I understand "find ./* -depth -type d" and "tr "[:upper:]" "[:lower:]"
    – Alex
    Feb 1 at 17:49












up vote
0
down vote

favorite
1









up vote
0
down vote

favorite
1






1





I was looking for a script that changes the filename and directory name to lowercase and replaces any white spaces with "-". I managed to find the script below inside another script but I do not fully understand how it works. I would really appreciate it if someone could walk me through it.



find ./* -depth -type d -exec sh -c '
t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' ;






share|improve this question














I was looking for a script that changes the filename and directory name to lowercase and replaces any white spaces with "-". I managed to find the script below inside another script but I do not fully understand how it works. I would really appreciate it if someone could walk me through it.



find ./* -depth -type d -exec sh -c '
t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' ;








share|improve this question













share|improve this question




share|improve this question








edited Feb 1 at 16:51

























asked Feb 1 at 16:47









Alex

1104




1104







  • 1




    Which bits do you understand?
    – bu5hman
    Feb 1 at 17:05










  • I understand "find ./* -depth -type d" and "tr "[:upper:]" "[:lower:]"
    – Alex
    Feb 1 at 17:49












  • 1




    Which bits do you understand?
    – bu5hman
    Feb 1 at 17:05










  • I understand "find ./* -depth -type d" and "tr "[:upper:]" "[:lower:]"
    – Alex
    Feb 1 at 17:49







1




1




Which bits do you understand?
– bu5hman
Feb 1 at 17:05




Which bits do you understand?
– bu5hman
Feb 1 at 17:05












I understand "find ./* -depth -type d" and "tr "[:upper:]" "[:lower:]"
– Alex
Feb 1 at 17:49




I understand "find ./* -depth -type d" and "tr "[:upper:]" "[:lower:]"
– Alex
Feb 1 at 17:49










3 Answers
3






active

oldest

votes

















up vote
2
down vote



accepted










find ./* -depth -type d -exec sh -c ' ... ' ;


finds all directories (-type d) in the tree and runs that shell snippet for each of them, with $0 set to the current name. -depth makes it process the contents of each directory first, and the directory itself last. (otherwise the renaming messes things up.)



t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");


$0%/* removes the last slash and everything after it from $0, i.e. leaves the directory name. $0##*/ is basically the opposite. (They're types of parameter expansion) The printf | tr is used to change the final part of the name to lower case. The result is assigned to t. ($(...) is command substitution)



[ "$t" = "$0" ] || mv -i "$0" "$t"


Tests to see if the new name in t and the old name in $0 are the same, and if not, then calls mv on them.




The silly parts here are that find could be called just as find . -depth ..., there's no need for the filename wildcard (find ./*) since finding the file names is what find does. If they used -execdir instead of -exec, there would be no need to deal with the directory part of the file names. And using $0 for the target file name is a bit bad form, it's meant for the name of the script itself.




You mentioned renaming files and directories, and changing whitespace to dashes. As far as I can see, the command here does neither. find -type d only catches directories, you'd need to use -type f to catch only regular files, or leave it out to ignore the type. Also, there's nothing about whitespace in the tr, but you could change it to, say tr "[:upper:][:space:]" "[:lower:][-*]" to also change all whitespace to dashes.






share|improve this answer






















  • @steeldriver, ah, true, I'd already forgotten that when I reached the end...
    – ilkkachu
    Feb 1 at 18:34

















up vote
0
down vote













I would use larry walls rename, it is available on many distros. Including Debian, and probably derivatives.



rename -E 's/-//g' -E 's/(.*)/L$1/g' *


First expression search and replaces - with nothing. second expression search and replaces everything (.*) with the same thing $1 but converted to lowercase L






share|improve this answer






















  • The main problem with rename is it's inconsistent. The default rename is different between debian and red hat variants, and even Debian has multiple providers for /usr/bin/rename.
    – jordanm
    Feb 1 at 17:34










  • ... and is not recursive ... plus I was looking for an explanation not a different method. Thank you very much for your input!
    – Alex
    Feb 1 at 17:48

















up vote
0
down vote













The script you present does some things to extract the directory and changes it to lowercase. There is no change of white space to -.



To change space to - and lowercase the string, sed works fine:



sed -e 's/[[:space:]]/-/g' -e 's/(.*)/L1/'


So, this script should work:



find ./* -depth -type d -execdir sh -c '
t=$(printf %s "$1" | sed -e 's/[[:space:]]/-/g' -e "s/(.*)/L1/")
[ "$t" = "$1" ] || echo mv -i "$1" "$t"
' sh ;


Using -depth and -execdir avoids the need to extract the dir name.

The type d limits the selected elements to only directories.






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%2f421240%2fcan-anyone-explain-to-me-how-this-script-works%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










    find ./* -depth -type d -exec sh -c ' ... ' ;


    finds all directories (-type d) in the tree and runs that shell snippet for each of them, with $0 set to the current name. -depth makes it process the contents of each directory first, and the directory itself last. (otherwise the renaming messes things up.)



    t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");


    $0%/* removes the last slash and everything after it from $0, i.e. leaves the directory name. $0##*/ is basically the opposite. (They're types of parameter expansion) The printf | tr is used to change the final part of the name to lower case. The result is assigned to t. ($(...) is command substitution)



    [ "$t" = "$0" ] || mv -i "$0" "$t"


    Tests to see if the new name in t and the old name in $0 are the same, and if not, then calls mv on them.




    The silly parts here are that find could be called just as find . -depth ..., there's no need for the filename wildcard (find ./*) since finding the file names is what find does. If they used -execdir instead of -exec, there would be no need to deal with the directory part of the file names. And using $0 for the target file name is a bit bad form, it's meant for the name of the script itself.




    You mentioned renaming files and directories, and changing whitespace to dashes. As far as I can see, the command here does neither. find -type d only catches directories, you'd need to use -type f to catch only regular files, or leave it out to ignore the type. Also, there's nothing about whitespace in the tr, but you could change it to, say tr "[:upper:][:space:]" "[:lower:][-*]" to also change all whitespace to dashes.






    share|improve this answer






















    • @steeldriver, ah, true, I'd already forgotten that when I reached the end...
      – ilkkachu
      Feb 1 at 18:34














    up vote
    2
    down vote



    accepted










    find ./* -depth -type d -exec sh -c ' ... ' ;


    finds all directories (-type d) in the tree and runs that shell snippet for each of them, with $0 set to the current name. -depth makes it process the contents of each directory first, and the directory itself last. (otherwise the renaming messes things up.)



    t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");


    $0%/* removes the last slash and everything after it from $0, i.e. leaves the directory name. $0##*/ is basically the opposite. (They're types of parameter expansion) The printf | tr is used to change the final part of the name to lower case. The result is assigned to t. ($(...) is command substitution)



    [ "$t" = "$0" ] || mv -i "$0" "$t"


    Tests to see if the new name in t and the old name in $0 are the same, and if not, then calls mv on them.




    The silly parts here are that find could be called just as find . -depth ..., there's no need for the filename wildcard (find ./*) since finding the file names is what find does. If they used -execdir instead of -exec, there would be no need to deal with the directory part of the file names. And using $0 for the target file name is a bit bad form, it's meant for the name of the script itself.




    You mentioned renaming files and directories, and changing whitespace to dashes. As far as I can see, the command here does neither. find -type d only catches directories, you'd need to use -type f to catch only regular files, or leave it out to ignore the type. Also, there's nothing about whitespace in the tr, but you could change it to, say tr "[:upper:][:space:]" "[:lower:][-*]" to also change all whitespace to dashes.






    share|improve this answer






















    • @steeldriver, ah, true, I'd already forgotten that when I reached the end...
      – ilkkachu
      Feb 1 at 18:34












    up vote
    2
    down vote



    accepted







    up vote
    2
    down vote



    accepted






    find ./* -depth -type d -exec sh -c ' ... ' ;


    finds all directories (-type d) in the tree and runs that shell snippet for each of them, with $0 set to the current name. -depth makes it process the contents of each directory first, and the directory itself last. (otherwise the renaming messes things up.)



    t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");


    $0%/* removes the last slash and everything after it from $0, i.e. leaves the directory name. $0##*/ is basically the opposite. (They're types of parameter expansion) The printf | tr is used to change the final part of the name to lower case. The result is assigned to t. ($(...) is command substitution)



    [ "$t" = "$0" ] || mv -i "$0" "$t"


    Tests to see if the new name in t and the old name in $0 are the same, and if not, then calls mv on them.




    The silly parts here are that find could be called just as find . -depth ..., there's no need for the filename wildcard (find ./*) since finding the file names is what find does. If they used -execdir instead of -exec, there would be no need to deal with the directory part of the file names. And using $0 for the target file name is a bit bad form, it's meant for the name of the script itself.




    You mentioned renaming files and directories, and changing whitespace to dashes. As far as I can see, the command here does neither. find -type d only catches directories, you'd need to use -type f to catch only regular files, or leave it out to ignore the type. Also, there's nothing about whitespace in the tr, but you could change it to, say tr "[:upper:][:space:]" "[:lower:][-*]" to also change all whitespace to dashes.






    share|improve this answer














    find ./* -depth -type d -exec sh -c ' ... ' ;


    finds all directories (-type d) in the tree and runs that shell snippet for each of them, with $0 set to the current name. -depth makes it process the contents of each directory first, and the directory itself last. (otherwise the renaming messes things up.)



    t=$0%/*/$(printf %s "$0##*/" | tr "[:upper:]" "[:lower:]");


    $0%/* removes the last slash and everything after it from $0, i.e. leaves the directory name. $0##*/ is basically the opposite. (They're types of parameter expansion) The printf | tr is used to change the final part of the name to lower case. The result is assigned to t. ($(...) is command substitution)



    [ "$t" = "$0" ] || mv -i "$0" "$t"


    Tests to see if the new name in t and the old name in $0 are the same, and if not, then calls mv on them.




    The silly parts here are that find could be called just as find . -depth ..., there's no need for the filename wildcard (find ./*) since finding the file names is what find does. If they used -execdir instead of -exec, there would be no need to deal with the directory part of the file names. And using $0 for the target file name is a bit bad form, it's meant for the name of the script itself.




    You mentioned renaming files and directories, and changing whitespace to dashes. As far as I can see, the command here does neither. find -type d only catches directories, you'd need to use -type f to catch only regular files, or leave it out to ignore the type. Also, there's nothing about whitespace in the tr, but you could change it to, say tr "[:upper:][:space:]" "[:lower:][-*]" to also change all whitespace to dashes.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 1 at 18:34

























    answered Feb 1 at 17:44









    ilkkachu

    49.8k674137




    49.8k674137











    • @steeldriver, ah, true, I'd already forgotten that when I reached the end...
      – ilkkachu
      Feb 1 at 18:34
















    • @steeldriver, ah, true, I'd already forgotten that when I reached the end...
      – ilkkachu
      Feb 1 at 18:34















    @steeldriver, ah, true, I'd already forgotten that when I reached the end...
    – ilkkachu
    Feb 1 at 18:34




    @steeldriver, ah, true, I'd already forgotten that when I reached the end...
    – ilkkachu
    Feb 1 at 18:34












    up vote
    0
    down vote













    I would use larry walls rename, it is available on many distros. Including Debian, and probably derivatives.



    rename -E 's/-//g' -E 's/(.*)/L$1/g' *


    First expression search and replaces - with nothing. second expression search and replaces everything (.*) with the same thing $1 but converted to lowercase L






    share|improve this answer






















    • The main problem with rename is it's inconsistent. The default rename is different between debian and red hat variants, and even Debian has multiple providers for /usr/bin/rename.
      – jordanm
      Feb 1 at 17:34










    • ... and is not recursive ... plus I was looking for an explanation not a different method. Thank you very much for your input!
      – Alex
      Feb 1 at 17:48














    up vote
    0
    down vote













    I would use larry walls rename, it is available on many distros. Including Debian, and probably derivatives.



    rename -E 's/-//g' -E 's/(.*)/L$1/g' *


    First expression search and replaces - with nothing. second expression search and replaces everything (.*) with the same thing $1 but converted to lowercase L






    share|improve this answer






















    • The main problem with rename is it's inconsistent. The default rename is different between debian and red hat variants, and even Debian has multiple providers for /usr/bin/rename.
      – jordanm
      Feb 1 at 17:34










    • ... and is not recursive ... plus I was looking for an explanation not a different method. Thank you very much for your input!
      – Alex
      Feb 1 at 17:48












    up vote
    0
    down vote










    up vote
    0
    down vote









    I would use larry walls rename, it is available on many distros. Including Debian, and probably derivatives.



    rename -E 's/-//g' -E 's/(.*)/L$1/g' *


    First expression search and replaces - with nothing. second expression search and replaces everything (.*) with the same thing $1 but converted to lowercase L






    share|improve this answer














    I would use larry walls rename, it is available on many distros. Including Debian, and probably derivatives.



    rename -E 's/-//g' -E 's/(.*)/L$1/g' *


    First expression search and replaces - with nothing. second expression search and replaces everything (.*) with the same thing $1 but converted to lowercase L







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 1 at 17:14









    Tomasz

    8,04052560




    8,04052560










    answered Feb 1 at 17:05









    ctrl-alt-delor

    8,79031947




    8,79031947











    • The main problem with rename is it's inconsistent. The default rename is different between debian and red hat variants, and even Debian has multiple providers for /usr/bin/rename.
      – jordanm
      Feb 1 at 17:34










    • ... and is not recursive ... plus I was looking for an explanation not a different method. Thank you very much for your input!
      – Alex
      Feb 1 at 17:48
















    • The main problem with rename is it's inconsistent. The default rename is different between debian and red hat variants, and even Debian has multiple providers for /usr/bin/rename.
      – jordanm
      Feb 1 at 17:34










    • ... and is not recursive ... plus I was looking for an explanation not a different method. Thank you very much for your input!
      – Alex
      Feb 1 at 17:48















    The main problem with rename is it's inconsistent. The default rename is different between debian and red hat variants, and even Debian has multiple providers for /usr/bin/rename.
    – jordanm
    Feb 1 at 17:34




    The main problem with rename is it's inconsistent. The default rename is different between debian and red hat variants, and even Debian has multiple providers for /usr/bin/rename.
    – jordanm
    Feb 1 at 17:34












    ... and is not recursive ... plus I was looking for an explanation not a different method. Thank you very much for your input!
    – Alex
    Feb 1 at 17:48




    ... and is not recursive ... plus I was looking for an explanation not a different method. Thank you very much for your input!
    – Alex
    Feb 1 at 17:48










    up vote
    0
    down vote













    The script you present does some things to extract the directory and changes it to lowercase. There is no change of white space to -.



    To change space to - and lowercase the string, sed works fine:



    sed -e 's/[[:space:]]/-/g' -e 's/(.*)/L1/'


    So, this script should work:



    find ./* -depth -type d -execdir sh -c '
    t=$(printf %s "$1" | sed -e 's/[[:space:]]/-/g' -e "s/(.*)/L1/")
    [ "$t" = "$1" ] || echo mv -i "$1" "$t"
    ' sh ;


    Using -depth and -execdir avoids the need to extract the dir name.

    The type d limits the selected elements to only directories.






    share|improve this answer
























      up vote
      0
      down vote













      The script you present does some things to extract the directory and changes it to lowercase. There is no change of white space to -.



      To change space to - and lowercase the string, sed works fine:



      sed -e 's/[[:space:]]/-/g' -e 's/(.*)/L1/'


      So, this script should work:



      find ./* -depth -type d -execdir sh -c '
      t=$(printf %s "$1" | sed -e 's/[[:space:]]/-/g' -e "s/(.*)/L1/")
      [ "$t" = "$1" ] || echo mv -i "$1" "$t"
      ' sh ;


      Using -depth and -execdir avoids the need to extract the dir name.

      The type d limits the selected elements to only directories.






      share|improve this answer






















        up vote
        0
        down vote










        up vote
        0
        down vote









        The script you present does some things to extract the directory and changes it to lowercase. There is no change of white space to -.



        To change space to - and lowercase the string, sed works fine:



        sed -e 's/[[:space:]]/-/g' -e 's/(.*)/L1/'


        So, this script should work:



        find ./* -depth -type d -execdir sh -c '
        t=$(printf %s "$1" | sed -e 's/[[:space:]]/-/g' -e "s/(.*)/L1/")
        [ "$t" = "$1" ] || echo mv -i "$1" "$t"
        ' sh ;


        Using -depth and -execdir avoids the need to extract the dir name.

        The type d limits the selected elements to only directories.






        share|improve this answer












        The script you present does some things to extract the directory and changes it to lowercase. There is no change of white space to -.



        To change space to - and lowercase the string, sed works fine:



        sed -e 's/[[:space:]]/-/g' -e 's/(.*)/L1/'


        So, this script should work:



        find ./* -depth -type d -execdir sh -c '
        t=$(printf %s "$1" | sed -e 's/[[:space:]]/-/g' -e "s/(.*)/L1/")
        [ "$t" = "$1" ] || echo mv -i "$1" "$t"
        ' sh ;


        Using -depth and -execdir avoids the need to extract the dir name.

        The type d limits the selected elements to only directories.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Feb 1 at 18:48









        Isaac

        6,6371734




        6,6371734






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f421240%2fcan-anyone-explain-to-me-how-this-script-works%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Peggy Mitchell

            Palaiologos

            The Forum (Inglewood, California)