3

I need to lower all upper-cases of file and folder names from a path, recursively inside other folders found; I need to do that with a bash script.

Here my code:

for file in $(find $1 -type f)
do
    tmp=$(echo $file | rev | cut -d/ -f1 | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
    tmp2=$(echo $file | rev | cut ????)
    tmp=$tmp$tmp2
    mv $file $(echo $tmp | rev)
done
for file in $(find $1 -type d | sort -r)
do
    tmp=$(echo $file | rev | cut -d/ -f1 | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz)
    tmp2=$(echo $file | rev | cut)
    tmp=$tmp$tmp2
    mv $file $(echo $tmp | rev)
done

The problem is at line 4, [tmp2=$(echo $file | rev | cut ????)] I don't know how I can select all the fields delimited with / after the first field.

With line 3 I can isolate the file name and with the tr command modify all upper-cases, but then comes the trouble. Same for folders t the second 'for' construct.

3

You should be using dirname and basename instead of these tricks with rev and cut

declare -l file_lower   # anything assigned to this varname will be lower-cased

find $1 -type f | while read -r file
do
    file_lower=$(basename "$file")
    dir=$(dirname "$file")
    mv "$file" "$dir/$file_lower"
done

find $1 -type d | sort -r | while read -r file
do
    file_lower=$(basename "$file")
    dir=$(dirname "$file")
    mv "$file" "$dir/$file_lower"
done
  • That assumes file names don't contain newline characters and don't end in space or tab characters. It interprets the first argument as a list of file patterns. sort -r doesn't do what you (and the OP) think it does as there are several characters that sort before / (you want -depth here). – Stéphane Chazelas Nov 29 '13 at 21:25
2

cut -d/ -f 2-

Cut supports ranges for its offset parameter, e.g. -f 2- , -c -2, -b 1-3

1

On a GNU system:

find . -depth -name '*[[:upper:]]*' -printf '%h\0%f\0' |
  awk -v RS='\0' '{getline f; printf "%s\0%s\0", $0"/"f, $0"/"tolower(f)}' |
  xargs -r0n2 echo mv

(remove echo when happy).

Or if you can use zsh:

autoload zmv
zmv -n -wQ '**/*(D)' '$1${(L)2}'

(remove -n when happy)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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