Can anyone explain to me how this script works?

Clash Royale CLAN TAG#URR8PPP
up vote
0
down vote
favorite
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"
' ;
bash find tr
add a comment |Â
up vote
0
down vote
favorite
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"
' ;
bash find tr
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
add a comment |Â
up vote
0
down vote
favorite
up vote
0
down vote
favorite
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"
' ;
bash find tr
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"
' ;
bash find tr
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
add a comment |Â
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
add a comment |Â
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.
@steeldriver, ah, true, I'd already forgotten that when I reached the end...
â ilkkachu
Feb 1 at 18:34
add a comment |Â
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
The main problem withrenameis it's inconsistent. The defaultrenameis 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
add a comment |Â
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.
add a comment |Â
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.
@steeldriver, ah, true, I'd already forgotten that when I reached the end...
â ilkkachu
Feb 1 at 18:34
add a comment |Â
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.
@steeldriver, ah, true, I'd already forgotten that when I reached the end...
â ilkkachu
Feb 1 at 18:34
add a comment |Â
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.
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.
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
add a comment |Â
@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
add a comment |Â
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
The main problem withrenameis it's inconsistent. The defaultrenameis 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
add a comment |Â
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
The main problem withrenameis it's inconsistent. The defaultrenameis 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
add a comment |Â
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
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
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 withrenameis it's inconsistent. The defaultrenameis 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
add a comment |Â
The main problem withrenameis it's inconsistent. The defaultrenameis 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
add a comment |Â
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.
add a comment |Â
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.
add a comment |Â
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.
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.
answered Feb 1 at 18:48
Isaac
6,6371734
6,6371734
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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