Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question

3 Answers 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
share|improve this answer
    
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

cut -d/ -f 2-

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

share|improve this answer

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)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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