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'm working on a website conversion. The files as they were linked and served from the web server were case insensitive. But, I've made a dump of the site on my linux system and I'm writing scripts to migrate data. The problem is that I'm running into case sensitivity problems between link strings in the pages and the actual word case on the file system.

For instance, a page might have a link like <a href='/subfolder/PageName.asp'> while the actual file is /subfolder/pagename.asp. Likewise with images — <img src='spacer_sm.gif'> might be Spacer_Sm.gif.

So my thought is to change all directory and filenames to their lower-case equivalents for the site download. How do I do this (and might there be a better way?)

Even if there are unix commands that have case-insensitve switches, I'm using php, so not all of the filesystem commands there have options for case sensitivity.

share|improve this question
2  
See a similar previous question. I've reposted a simpler answer here because the question is a bit more specific. –  Gilles Sep 7 '11 at 0:32

4 Answers 4

up vote 7 down vote accepted

I don't know whether your unix-flavor has a rename. Many Linuxes have, and it is part of a perl-package, if you search for a repository.

find ./ -depth -exec rename -n 'y/[A-Z]/[a-z]/' {} ";"

Above version with

rename -n 

doesn't really perform the action, but only print what would be done. You omit the -n to do it for real.

share|improve this answer
    
What 'language' or regex is the 'y/[A-Z]/[a-z]/' part? –  user394 Sep 7 '11 at 15:57
    
Well, since rename is part of a perl package, I guess perl, but the pattern is used in sed too, and maybe in AWK as well. I only know sed quiet well. I translate y to translate or map, but I don't know where the character origins from. –  user unknown Sep 7 '11 at 16:21
    
Must be perl regex - Gilles in his answer says rename is a perl script. –  user394 Sep 7 '11 at 16:26
    
Yes, and you may use perl regexs, to modify the filenames, which doesn't necessarily conclude from being written in perl, but which might be the more interesting question. –  user unknown Sep 7 '11 at 16:33

Zsh

zmv -o-i '(**/)(*)' '$1${2:l}'

Explanations: zmv renames files matching a pattern according to the given replacement text. -o-i passes the -i option to each mv command under the hood (see below). In the replacement text, $1, $2, etc, are the successive parenthesized groups in the pattern. ** means all (sub)*directories, recursively. The final (/) is not a parenthesized group but a glob qualifier meaning to match only directories. ${2:l} converts $2 to lowercase.

Perl rename

Here I use the Perl rename script that Debian and Ubuntu ship as /usr/bin/prename (typically available as rename as well). With bash ≥4 or zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' **/*

With other shells:

find . -depth -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +

Portable

Recursively:

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

The use of -depth ensures that deeply nested directories are processed before their ancestors.

share|improve this answer

The accepted answer didn't work for me as it tried to change all the directories at once. I found another solution on stackexchange very similar to the portable one from Gilles above: from Baramin -
http://stackoverflow.com/questions/4268591/unix-rename-files-directories-to-uppercase

I've copied it here:

find . -depth | \
while read LONG; do
   SHORT=$( basename "$LONG" | tr '[:lower:]' '[:upper:]' )
   DIR=$( dirname "$LONG" )
   if [ "${LONG}" != "${DIR}/${SHORT}"  ]; then
     mv "${LONG}" "${DIR}/${SHORT}"
   fi
done

To which I changed the tr command to i.e: sed s/cat/dog/g

Any thanks goes to Baramin at link above.i.e.

share|improve this answer

It did not work on the following directory structure :

JKL/
deF/
ABC/DEf
ABC/gHi
ghi/jkL

Here's an example that does work :

for i in `find | sort -r | sed '$d'`; do \
   b=${i%/*}; e=${i##*/}; mv $i $b'/'${e,,}; done

For an explanation on b and e vars:

man bash

Then use the following key sequence: /,,Enterbb

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.